Android native message dialog

Change-Id: Ief8c3ce3b8683c6960f046245844c1835a327d51
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
This commit is contained in:
BogDan Vatra 2013-11-09 09:21:02 +02:00 committed by The Qt Project
parent 315ba388f3
commit ef6544ee27
15 changed files with 848 additions and 11 deletions

View File

@ -9,6 +9,7 @@ JAVASOURCES += \
$$PATHPREFIX/QtEditText.java \
$$PATHPREFIX/QtInputConnection.java \
$$PATHPREFIX/QtLayout.java \
$$PATHPREFIX/QtMessageDialogHelper.java \
$$PATHPREFIX/QtNative.java \
$$PATHPREFIX/QtNativeLibrariesDir.java \
$$PATHPREFIX/QtSurface.java

View File

@ -0,0 +1,425 @@
/****************************************************************************
**
** Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Android port of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
package org.qtproject.qt5.android;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.ClipboardManager;
import android.util.TypedValue;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
class QtNativeDialogHelper
{
static native void dialogResult(long handler, int buttonID);
}
class ButtonStruct implements View.OnClickListener
{
ButtonStruct(QtMessageDialogHelper dialog, int id, String text)
{
m_dialog = dialog;
m_id = id;
m_text = text;
}
QtMessageDialogHelper m_dialog;
private int m_id;
String m_text;
@Override
public void onClick(View view) {
QtNativeDialogHelper.dialogResult(m_dialog.handler(), m_id);
}
}
public class QtMessageDialogHelper
{
public QtMessageDialogHelper(Activity activity)
{
m_activity = activity;
}
public void setIcon(int icon)
{
m_icon = icon;
}
private Drawable getIconDrawable()
{
if (m_icon == 0)
return null;
if (Build.VERSION.SDK_INT > 10) {
try {
TypedValue typedValue = new TypedValue();
m_theme.resolveAttribute(Class.forName("android.R$attr").getDeclaredField("alertDialogIcon").getInt(null), typedValue, true);
return m_activity.getResources().getDrawable(typedValue.resourceId);
} catch (Exception e) {
e.printStackTrace();
}
}
// Information, Warning, Critical, Question
switch (m_icon)
{
case 1: // Information
try {
return m_activity.getResources().getDrawable(Class.forName("android.R$drawable").getDeclaredField("ic_dialog_info").getInt(null));
} catch (Exception e) {
e.printStackTrace();
}
break;
case 2: // Warning
// try {
// return Class.forName("android.R$drawable").getDeclaredField("stat_sys_warning").getInt(null);
// } catch (Exception e) {
// e.printStackTrace();
// }
// break;
case 3: // Critical
try {
return m_activity.getResources().getDrawable(Class.forName("android.R$drawable").getDeclaredField("ic_dialog_alert").getInt(null));
} catch (Exception e) {
e.printStackTrace();
}
break;
case 4: // Question
try {
return m_activity.getResources().getDrawable(Class.forName("android.R$drawable").getDeclaredField("ic_menu_help").getInt(null));
} catch (Exception e) {
e.printStackTrace();
}
break;
}
return null;
}
public void setTile(String title)
{
m_title = title;
}
public void setText(String text)
{
m_text = text;
}
public void setInformativeText(String informativeText)
{
m_informativeText = informativeText;
}
public void setDetailedText(String text)
{
m_detailedText = text;
}
public void addButton(int id, String text)
{
if (m_buttonsList == null)
m_buttonsList = new ArrayList<ButtonStruct>();
m_buttonsList.add(new ButtonStruct(this, id, text));
}
private void setTextAppearance(TextView view, String attr, String style)
{
try {
int[] attrs = (int[]) Class.forName("android.R$styleable").getDeclaredField("TextAppearance").get(null);
final TypedArray a = m_theme.obtainStyledAttributes(null,
attrs,
Class.forName("android.R$attr").getDeclaredField(attr).getInt(null),
Class.forName("android.R$style").getDeclaredField(style).getInt(null));
final int textSize = a.getDimensionPixelSize(
Class.forName("android.R$styleable").getDeclaredField("TextAppearance_textSize").getInt(null), 0);
if (textSize != 0)
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
final int textColor = a.getColor(
Class.forName("android.R$styleable").getDeclaredField("TextAppearance_textColor").getInt(null), 0x3138);
if (textColor != 0x3138)
view.setTextColor(textColor);
a.recycle();
} catch (Exception e) {
e.printStackTrace();
}
}
private Drawable getStyledDrawable(String drawable) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException
{
int[] attrs = {Class.forName("android.R$attr").getDeclaredField(drawable).getInt(null)};
final TypedArray a = m_theme.obtainStyledAttributes(attrs);
Drawable d = a.getDrawable(0);
a.recycle();
return d;
}
public void show(long handler)
{
m_handler = handler;
m_activity.runOnUiThread( new Runnable() {
@Override
public void run() {
if (m_dialog != null && m_dialog.isShowing())
m_dialog.dismiss();
m_dialog = new AlertDialog.Builder(m_activity).create();
m_theme = m_dialog.getWindow().getContext().getTheme();
if (m_title != null)
m_dialog.setTitle(m_title);
m_dialog.setOnCancelListener( new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
QtNativeDialogHelper.dialogResult(handler(), -1);
}
});
m_dialog.setCancelable(m_buttonsList == null);
m_dialog.setCanceledOnTouchOutside(m_buttonsList == null);
m_dialog.setIcon(getIconDrawable());
ScrollView scrollView = new ScrollView(m_activity);
RelativeLayout dialogLayout = new RelativeLayout(m_activity);
int id = 1;
View lastView = null;
View.OnLongClickListener copyText = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
TextView tv = (TextView)view;
if (tv != null) {
ClipboardManager cm = (android.text.ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setText(tv.getText());
}
return true;
}
};
if (m_text != null)
{
TextView view = new TextView(m_activity);
view.setId(id++);
view.setOnLongClickListener(copyText);
view.setLongClickable(true);
view.setText(m_text);
setTextAppearance(view, "textAppearanceMedium", "TextAppearance_Medium");
RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layout.setMargins(16, 8, 16, 8);
layout.addRule(RelativeLayout.ALIGN_PARENT_TOP);
dialogLayout.addView(view, layout);
lastView = view;
}
if (m_informativeText != null)
{
TextView view= new TextView(m_activity);
view.setId(id++);
view.setOnLongClickListener(copyText);
view.setLongClickable(true);
view.setText(m_informativeText);
setTextAppearance(view, "textAppearanceMedium", "TextAppearance_Medium");
RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layout.setMargins(16, 8, 16, 8);
if (lastView != null)
layout.addRule(RelativeLayout.BELOW, lastView.getId());
else
layout.addRule(RelativeLayout.ALIGN_PARENT_TOP);
dialogLayout.addView(view, layout);
lastView = view;
}
if (m_detailedText != null)
{
TextView view= new TextView(m_activity);
view.setId(id++);
view.setOnLongClickListener(copyText);
view.setLongClickable(true);
view.setText(m_detailedText);
setTextAppearance(view, "textAppearanceSmall", "TextAppearance_Small");
RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layout.setMargins(16, 8, 16, 8);
if (lastView != null)
layout.addRule(RelativeLayout.BELOW, lastView.getId());
else
layout.addRule(RelativeLayout.ALIGN_PARENT_TOP);
dialogLayout.addView(view, layout);
lastView = view;
}
if (m_buttonsList != null)
{
LinearLayout buttonsLayout = new LinearLayout(m_activity);
buttonsLayout.setOrientation(LinearLayout.HORIZONTAL);
buttonsLayout.setId(id++);
boolean firstButton = true;
for (ButtonStruct button: m_buttonsList)
{
Button bv;
if (Build.VERSION.SDK_INT > 10) {
try {
bv = new Button(m_activity, null, Class.forName("android.R$attr").getDeclaredField("borderlessButtonStyle").getInt(null));
} catch (Exception e) {
bv = new Button(m_activity);
e.printStackTrace();
}
} else {
bv = new Button(m_activity);
}
bv.setText(button.m_text);
bv.setOnClickListener(button);
if (!firstButton) // first button
{
LinearLayout.LayoutParams layout = null;
View spacer = new View(m_activity);
if (Build.VERSION.SDK_INT > 10) {
try {
layout = new LinearLayout.LayoutParams(1, RelativeLayout.LayoutParams.MATCH_PARENT);
spacer.setBackgroundDrawable(getStyledDrawable("dividerVertical"));
buttonsLayout.addView(spacer, layout);
} catch (Exception e) {
e.printStackTrace();
}
}
}
LinearLayout.LayoutParams layout = null;
layout = new LinearLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT, 1.0f);
buttonsLayout.addView(bv, layout);
firstButton = false;
}
if (Build.VERSION.SDK_INT > 10) {
try {
View horizontalDevider = new View(m_activity);
horizontalDevider.setId(id++);
horizontalDevider.setBackgroundDrawable(getStyledDrawable("dividerHorizontal"));
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 1);
relativeParams.setMargins(0, 10, 0, 0);
if (lastView != null) {
relativeParams.addRule(RelativeLayout.BELOW, lastView.getId());
}
else
relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
dialogLayout.addView(horizontalDevider, relativeParams);
lastView = horizontalDevider;
} catch (Exception e) {
e.printStackTrace();
}
}
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
if (lastView != null) {
relativeParams.addRule(RelativeLayout.BELOW, lastView.getId());
}
else
relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
if (Build.VERSION.SDK_INT < 11)
relativeParams.setMargins(2, 12, 2, 4);
else
relativeParams.setMargins(2, 0, 2, 0);
dialogLayout.addView(buttonsLayout, relativeParams);
}
scrollView.addView(dialogLayout);
m_dialog.setView(scrollView);
m_dialog.show();
}
});
}
public void hide()
{
m_activity.runOnUiThread( new Runnable() {
@Override
public void run() {
if (m_dialog != null && m_dialog.isShowing())
m_dialog.dismiss();
reset();
}
});
}
public long handler()
{
return m_handler;
}
public void reset()
{
m_icon = 0;
m_title = null;
m_text = null;
m_informativeText = null;
m_detailedText = null;
m_buttonsList = null;
m_dialog = null;
m_handler = 0;
}
private Activity m_activity;
private int m_icon = 0;
private String m_title, m_text, m_informativeText, m_detailedText;
private ArrayList<ButtonStruct> m_buttonsList;
private AlertDialog m_dialog;
private long m_handler = 0;
private Resources.Theme m_theme;
}

View File

@ -123,13 +123,13 @@ public class QtActivity extends Activity
// and must be separated with "\t"
// e.g "-param1\t-param2=value2\t-param3\tvalue3"
public String ENVIRONMENT_VARIABLES = "QT_USE_ANDROID_NATIVE_STYLE=1\t";
public String ENVIRONMENT_VARIABLES = "QT_USE_ANDROID_NATIVE_STYLE=1\tQT_USE_ANDROID_NATIVE_DIALOGS=1\t";
// use this variable to add any environment variables to your application.
// the env vars must be separated with "\t"
// e.g. "ENV_VAR1=1\tENV_VAR2=2\t"
// Currently the following vars are used by the android plugin:
// * QT_USE_ANDROID_NATIVE_STYLE - 1 to use the android widget style if available,
// note that the android style plugin in Qt 5.1 is not fully functional.
// * QT_USE_ANDROID_NATIVE_STYLE - 1 to use the android widget style if available.
// * QT_USE_ANDROID_NATIVE_DIALOGS -1 to use the android native dialogs.
public String[] QT_ANDROID_THEMES = null; // A list with all themes that your application want to use.
// The name of the theme must be the same with any theme from

View File

@ -59,6 +59,7 @@
#include "androidjniinput.h"
#include "androidjniclipboard.h"
#include "androidjnimenu.h"
#include "qandroidplatformdialoghelpers.h"
#include "qandroidplatformintegration.h"
#include <QtWidgets/QApplication>
@ -865,7 +866,8 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
|| !QtAndroidInput::registerNatives(env)
|| !QtAndroidClipboard::registerNatives(env)
|| !QtAndroidMenu::registerNatives(env)
) {
|| !QtAndroidAccessibility::registerNatives(env)
|| !QtAndroidDialogHelpers::registerNatives(env)) {
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1;
}

View File

@ -0,0 +1,223 @@
/****************************************************************************
**
** Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtWidgets/QApplication>
#include <QtWidgets/QStyle>
#include "qandroidplatformdialoghelpers.h"
#include "androidjnimain.h"
namespace QtAndroidDialogHelpers {
static jclass g_messageDialogHelperClass = 0;
QAndroidPlatformMessageDialogHelper::QAndroidPlatformMessageDialogHelper()
:m_buttonId(-1)
,m_javaMessageDialog(g_messageDialogHelperClass, "(Landroid/app/Activity;)V", QtAndroid::activity())
,m_shown(false)
{
}
void QAndroidPlatformMessageDialogHelper::exec()
{
if (!m_shown)
show(Qt::Dialog, Qt::ApplicationModal, 0);
m_loop.exec();
}
static QString standardButtonText(int sbutton)
{
QString buttonText = 0;
switch (sbutton) {
case QMessageDialogOptions::Ok:
buttonText = QObject::tr("OK");
break;
case QMessageDialogOptions::Save:
buttonText = QObject::tr("Save");
break;
case QMessageDialogOptions::Open:
buttonText = QObject::tr("Open");
break;
case QMessageDialogOptions::Cancel:
buttonText = QObject::tr("Cancel");
break;
case QMessageDialogOptions::Close:
buttonText = QObject::tr("Close");
break;
case QMessageDialogOptions::Apply:
buttonText = QObject::tr("Apply");
break;
case QMessageDialogOptions::Reset:
buttonText = QObject::tr("Reset");
break;
case QMessageDialogOptions::Help:
buttonText = QObject::tr("Help");
break;
case QMessageDialogOptions::Discard:
buttonText = QObject::tr("Discard");
break;
case QMessageDialogOptions::Yes:
buttonText = QObject::tr("Yes");
break;
case QMessageDialogOptions::YesToAll:
buttonText = QObject::tr("Yes to All");
break;
case QMessageDialogOptions::No:
buttonText = QObject::tr("No");
break;
case QMessageDialogOptions::NoToAll:
buttonText = QObject::tr("No to All");
break;
case QMessageDialogOptions::SaveAll:
buttonText = QObject::tr("Save All");
break;
case QMessageDialogOptions::Abort:
buttonText = QObject::tr("Abort");
break;
case QMessageDialogOptions::Retry:
buttonText = QObject::tr("Retry");
break;
case QMessageDialogOptions::Ignore:
buttonText = QObject::tr("Ignore");
break;
case QMessageDialogOptions::RestoreDefaults:
buttonText = QObject::tr("Restore Defaults");
break;
} // switch
return buttonText;
}
bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags
, Qt::WindowModality windowModality
, QWindow *parent)
{
Q_UNUSED(windowFlags)
Q_UNUSED(windowModality)
Q_UNUSED(parent)
QSharedPointer<QMessageDialogOptions> opt = options();
if (!opt.data())
return false;
m_javaMessageDialog.callMethod<void>("setIcon", "(I)V", opt->icon());
QString str = opt->windowTitle();
if (!str.isEmpty())
m_javaMessageDialog.callMethod<void>("setTile", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
str = opt->text();
if (!str.isEmpty())
m_javaMessageDialog.callMethod<void>("setText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
str = opt->informativeText();
if (!str.isEmpty())
m_javaMessageDialog.callMethod<void>("setInformativeText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
str = opt->detailedText();
if (!str.isEmpty())
m_javaMessageDialog.callMethod<void>("setDetailedText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
for (int i = QMessageDialogOptions::FirstButton; i < QMessageDialogOptions::LastButton; i<<=1) {
if ( opt->standardButtons() & i )
m_javaMessageDialog.callMethod<void>("addButton", "(ILjava/lang/String;)V", i, QJNIObjectPrivate::fromString(standardButtonText(i)).object());
}
m_javaMessageDialog.callMethod<void>("show", "(J)V", jlong(static_cast<QObject*>(this)));
m_shown = true;
return true;
}
void QAndroidPlatformMessageDialogHelper::hide()
{
m_javaMessageDialog.callMethod<void>("hide", "()V");
m_shown = false;
}
void QAndroidPlatformMessageDialogHelper::dialogResult(int buttonID)
{
m_buttonId = buttonID;
if (m_loop.isRunning())
m_loop.exit();
if (m_buttonId < 0) {
emit reject();
return;
}
QMessageDialogOptions::StandardButton standardButton = static_cast<QMessageDialogOptions::StandardButton>(buttonID);
QMessageDialogOptions::ButtonRole role = QMessageDialogOptions::buttonRole(standardButton);
emit clicked(standardButton, role);
}
static void dialogResult(JNIEnv * /*env*/, jobject /*thiz*/, jlong handler, int buttonID)
{
QObject *object = reinterpret_cast<QObject *>(handler);
QMetaObject::invokeMethod(object, "dialogResult", Qt::QueuedConnection, Q_ARG(int, buttonID));
}
static JNINativeMethod methods[] = {
{"dialogResult", "(JI)V", (void *)dialogResult}
};
#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
clazz = env->FindClass(CLASS_NAME); \
if (!clazz) { \
__android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::classErrorMsgFmt(), CLASS_NAME); \
return false; \
}
bool registerNatives(JNIEnv *env)
{
jclass clazz = QtAndroid::findClass("org/qtproject/qt5/android/QtMessageDialogHelper", env);
if (!clazz) {
__android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::classErrorMsgFmt()
, "org/qtproject/qt5/android/QtMessageDialogHelper");
return false;
}
g_messageDialogHelperClass = static_cast<jclass>(env->NewGlobalRef(clazz));
FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNativeDialogHelper");
jclass appClass = static_cast<jclass>(env->NewGlobalRef(clazz));
if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
__android_log_print(ANDROID_LOG_FATAL, "Qt", "RegisterNatives failed");
return false;
}
return true;
}
}

View File

@ -0,0 +1,77 @@
/****************************************************************************
**
** Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QANDROIDPLATFORMDIALOGHELPERS_H
#define QANDROIDPLATFORMDIALOGHELPERS_H
#include <jni.h>
#include <qpa/qplatformdialoghelper.h>
#include <QEventLoop>
#include <private/qjni_p.h>
namespace QtAndroidDialogHelpers {
class QAndroidPlatformMessageDialogHelper: public QPlatformMessageDialogHelper
{
Q_OBJECT
public:
QAndroidPlatformMessageDialogHelper();
void exec();
bool show(Qt::WindowFlags windowFlags,
Qt::WindowModality windowModality,
QWindow *parent);
void hide();
public slots:
void dialogResult(int buttonID);
private:
int m_buttonId;
QEventLoop m_loop;
QJNIObjectPrivate m_javaMessageDialog;
bool m_shown;
};
bool registerNatives(JNIEnv *env);
}
#endif // QANDROIDPLATFORMDIALOGHELPERS_H

View File

@ -43,6 +43,7 @@
#include "qandroidplatformmenubar.h"
#include "qandroidplatformmenu.h"
#include "qandroidplatformmenuitem.h"
#include "qandroidplatformdialoghelpers.h"
#include <QVariant>
#include <QFileInfo>
#include <qandroidplatformintegration.h>
@ -150,3 +151,20 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
return QPlatformTheme::themeHint(hint);
}
}
bool QAndroidPlatformTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const
{
if (type == MessageDialog)
return qgetenv("QT_USE_ANDROID_NATIVE_DIALOGS").toInt() == 1;
return false;
}
QPlatformDialogHelper *QAndroidPlatformTheme::createPlatformDialogHelper(QPlatformTheme::DialogType type) const
{
switch (type) {
case MessageDialog:
return new QtAndroidDialogHelpers::QAndroidPlatformMessageDialogHelper;
default:
return 0;
}
}

View File

@ -54,6 +54,9 @@ public:
virtual const QPalette *palette(Palette type = SystemPalette) const;
virtual const QFont *font(Font type = SystemFont) const;
virtual QVariant themeHint(ThemeHint hint) const;
virtual bool usePlatformNativeDialog(DialogType type) const;
virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const;
private:
QAndroidPlatformNativeInterface * m_androidPlatformNativeInterface;

View File

@ -21,6 +21,7 @@ SOURCES += $$PWD/androidplatformplugin.cpp \
$$PWD/qandroidinputcontext.cpp \
$$PWD/qandroidplatformaccessibility.cpp \
$$PWD/qandroidplatformfontdatabase.cpp \
$$PWD/qandroidplatformdialoghelpers.cpp \
$$PWD/qandroidplatformclipboard.cpp \
$$PWD/qandroidplatformtheme.cpp \
$$PWD/qandroidplatformmenubar.cpp \
@ -41,6 +42,7 @@ HEADERS += $$PWD/qandroidplatformintegration.h \
$$PWD/qandroidplatformaccessibility.h \
$$PWD/qandroidplatformfontdatabase.h \
$$PWD/qandroidplatformclipboard.h \
$$PWD/qandroidplatformdialoghelpers.h \
$$PWD/qandroidplatformtheme.h \
$$PWD/qandroidplatformmenubar.h \
$$PWD/qandroidplatformmenu.h \

View File

@ -52,6 +52,8 @@
#include "qwhatsthis.h"
#include "qmenu.h"
#include "qcursor.h"
#include "qmessagebox.h"
#include "qerrormessage.h"
#include <qpa/qplatformtheme.h>
#include "private/qdialog_p.h"
#include "private/qguiapplication_p.h"
@ -74,6 +76,14 @@ static inline int themeDialogType(const QDialog *dialog)
#ifndef QT_NO_FONTDIALOG
if (qobject_cast<const QFontDialog *>(dialog))
return QPlatformTheme::FontDialog;
#endif
#ifndef QT_NO_MESSAGEBOX
if (qobject_cast<const QMessageBox *>(dialog))
return QPlatformTheme::MessageDialog;
#endif
#ifndef QT_NO_ERRORMESSAGE
if (qobject_cast<const QErrorMessage *>(dialog))
return QPlatformTheme::MessageDialog;
#endif
return -1;
}
@ -100,6 +110,17 @@ QPlatformDialogHelper *QDialogPrivate::platformHelper() const
return m_platformHelper;
}
bool QDialogPrivate::canBeNativeDialog() const
{
QDialogPrivate *ncThis = const_cast<QDialogPrivate *>(this);
QDialog *dialog = ncThis->q_func();
const int type = themeDialogType(dialog);
if (type >= 0)
return QGuiApplicationPrivate::platformTheme()
->usePlatformNativeDialog(static_cast<QPlatformTheme::DialogType>(type));
return false;
}
QWindow *QDialogPrivate::parentWindow() const
{
if (const QWidget *parent = q_func()->nativeParentWidget())
@ -697,6 +718,9 @@ void QDialog::closeEvent(QCloseEvent *e)
void QDialog::setVisible(bool visible)
{
Q_D(QDialog);
if (!testAttribute(Qt::WA_DontShowOnScreen) && d->canBeNativeDialog() && d->setNativeDialogVisible(visible))
return;
if (visible) {
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
return;

View File

@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE
class QSizeGrip;
class QDialogPrivate : public QWidgetPrivate
class Q_WIDGETS_EXPORT QDialogPrivate : public QWidgetPrivate
{
Q_DECLARE_PUBLIC(QDialog)
public:
@ -113,6 +113,7 @@ public:
bool nativeDialogInUse;
QPlatformDialogHelper *platformHelper() const;
virtual bool canBeNativeDialog() const;
private:
virtual void initHelper(QPlatformDialogHelper *) {}

View File

@ -764,9 +764,9 @@ void QFileDialogPrivate::emitFilesSelected(const QStringList &files)
emit q->fileSelected(files.first());
}
bool QFileDialogPrivate::canBeNativeDialog()
bool QFileDialogPrivate::canBeNativeDialog() const
{
Q_Q(QFileDialog);
Q_Q(const QFileDialog);
if (nativeDialogInUse)
return true;
if (q->testAttribute(Qt::WA_DontShowOnScreen))

View File

@ -251,7 +251,7 @@ public:
// setVisible_sys returns true if it ends up showing a native
// dialog. Returning false means that a non-native dialog must be
// used instead.
bool canBeNativeDialog();
bool canBeNativeDialog() const;
inline bool usingWidgets() const;
void setDirectory_sys(const QUrl &directory);

View File

@ -193,7 +193,6 @@ public:
}
};
class QMessageBoxPrivate : public QDialogPrivate
{
Q_DECLARE_PUBLIC(QMessageBox)
@ -204,11 +203,13 @@ public:
detailsText(0),
#endif
compatMode(false), autoAddOkButton(true),
detectedEscapeButton(0), informativeLabel(0) { }
detectedEscapeButton(0), informativeLabel(0),
options(new QMessageDialogOptions) { }
void init(const QString &title = QString(), const QString &text = QString());
void setupLayout();
void _q_buttonClicked(QAbstractButton *);
void _q_clicked(QMessageDialogOptions::StandardButton button, QMessageDialogOptions::ButtonRole role);
QAbstractButton *findButton(int button0, int button1, int button2, int flags);
void addOldButtons(int button0, int button1, int button2);
@ -224,7 +225,6 @@ public:
#ifdef Q_OS_WINCE
void hideSpecial();
#endif
static int showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
const QString &title, const QString &text,
int button0, int button1, int button2);
@ -262,6 +262,11 @@ public:
QPointer<QObject> receiverToDisconnectOnClose;
QByteArray memberToDisconnectOnClose;
QByteArray signalToDisconnectOnClose;
QSharedPointer<QMessageDialogOptions> options;
private:
void initHelper(QPlatformDialogHelper *);
void helperPrepareShow(QPlatformDialogHelper *);
void helperDone(QDialog::DialogCode, QPlatformDialogHelper *);
};
void QMessageBoxPrivate::init(const QString &title, const QString &text)
@ -519,6 +524,13 @@ void QMessageBoxPrivate::_q_buttonClicked(QAbstractButton *button)
}
}
void QMessageBoxPrivate::_q_clicked(QMessageDialogOptions::StandardButton button, QMessageDialogOptions::ButtonRole role)
{
Q_UNUSED(role);
Q_Q(QMessageBox);
q->done(button);
}
/*!
\class QMessageBox
@ -2682,6 +2694,54 @@ QPixmap QMessageBoxPrivate::standardIcon(QMessageBox::Icon icon, QMessageBox *mb
return QPixmap();
}
void QMessageBoxPrivate::initHelper(QPlatformDialogHelper *h)
{
Q_Q(QMessageBox);
QObject::connect(h, SIGNAL(clicked(QMessageDialogOptions::StandardButton, QMessageDialogOptions::ButtonRole)),
q, SLOT(_q_clicked(QMessageDialogOptions::StandardButton, QMessageDialogOptions::ButtonRole)));
static_cast<QPlatformMessageDialogHelper *>(h)->setOptions(options);
}
static QMessageDialogOptions::Icon helperIcon(QMessageBox::Icon i)
{
switch (i) {
case QMessageBox::NoIcon:
return QMessageDialogOptions::NoIcon;
case QMessageBox::Information:
return QMessageDialogOptions::Information;
case QMessageBox::Warning:
return QMessageDialogOptions::Warning;
case QMessageBox::Critical:
return QMessageDialogOptions::Critical;
case QMessageBox::Question:
return QMessageDialogOptions::Question;
}
return QMessageDialogOptions::NoIcon;
}
static QMessageDialogOptions::StandardButtons helperStandardButtons(QMessageBox * q)
{
QMessageDialogOptions::StandardButtons buttons(int(q->standardButtons()));
return buttons;
}
void QMessageBoxPrivate::helperPrepareShow(QPlatformDialogHelper *)
{
Q_Q(QMessageBox);
options->setWindowTitle(q->windowTitle());
options->setText(q->text());
options->setInformativeText(q->informativeText());
options->setDetailedText(q->detailedText());
options->setIcon(helperIcon(q->icon()));
options->setStandardButtons(helperStandardButtons(q));
}
void QMessageBoxPrivate::helperDone(QDialog::DialogCode code, QPlatformDialogHelper *)
{
Q_Q(QMessageBox);
clickedButton = q->button(QMessageBox::StandardButton(code));
}
/*!
\obsolete

View File

@ -309,6 +309,7 @@ protected:
private:
Q_PRIVATE_SLOT(d_func(), void _q_buttonClicked(QAbstractButton *))
Q_PRIVATE_SLOT(d_func(), void _q_clicked(QMessageDialogOptions::StandardButton, QMessageDialogOptions::ButtonRole))
Q_DISABLE_COPY(QMessageBox)
Q_DECLARE_PRIVATE(QMessageBox)