Use PopupMenu when possible.
On API-11+ we are going to use PopupMenu instead of ContextMenu to show context menus. A PopupMenu displays a Menu in a modal popup window anchored to a View. The popup will appear below the anchor view if there is room, or above it if there is not. Task-number: QTBUG-39736 Change-Id: Ie412ab0935b868348ce5c8bb0bf53571ffefd582 Reviewed-by: J-P Nurmi <jpnurmi@digia.com> Reviewed-by: Paul Olav Tvete <paul.tvete@digia.com>bb10
parent
8ee9774e67
commit
3b577dfe79
|
|
@ -1,5 +1,6 @@
|
|||
CONFIG += java
|
||||
DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar
|
||||
API_VERSION = android-16
|
||||
|
||||
PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/
|
||||
|
||||
|
|
@ -13,7 +14,9 @@ JAVASOURCES += \
|
|||
$$PATHPREFIX/QtNative.java \
|
||||
$$PATHPREFIX/QtNativeLibrariesDir.java \
|
||||
$$PATHPREFIX/QtSurface.java \
|
||||
$$PATHPREFIX/ExtractStyle.java
|
||||
$$PATHPREFIX/ExtractStyle.java \
|
||||
$$PATHPREFIX/QtPopupMenu.java \
|
||||
$$PATHPREFIX/QtPopupMenu14.java
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_PREFIX]/jar
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ import android.content.pm.PackageManager;
|
|||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
|
|
@ -76,7 +75,6 @@ import java.io.File;
|
|||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.System;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
|
@ -122,7 +120,6 @@ public class QtActivityDelegate
|
|||
private boolean m_quitApp = true;
|
||||
private Process m_debuggerProcess = null; // debugger process
|
||||
private View m_dummyView = null;
|
||||
|
||||
private boolean m_keyboardIsVisible = false;
|
||||
public boolean m_backKeyPressedSent = false;
|
||||
private long m_showHideTimeStamp = System.nanoTime();
|
||||
|
|
@ -482,7 +479,7 @@ public class QtActivityDelegate
|
|||
return true;
|
||||
}
|
||||
|
||||
public void debugLog(String msg)
|
||||
public static void debugLog(String msg)
|
||||
{
|
||||
Log.i(QtNative.QtTAG, "DEBUGGER: " + msg);
|
||||
}
|
||||
|
|
@ -939,6 +936,12 @@ public class QtActivityDelegate
|
|||
m_contextMenuVisible = true;
|
||||
}
|
||||
|
||||
public void onCreatePopupMenu(Menu menu)
|
||||
{
|
||||
QtNative.fillContextMenu(menu);
|
||||
m_contextMenuVisible = true;
|
||||
}
|
||||
|
||||
public void onContextMenuClosed(Menu menu)
|
||||
{
|
||||
if (!m_contextMenuVisible)
|
||||
|
|
@ -949,17 +952,28 @@ public class QtActivityDelegate
|
|||
|
||||
public boolean onContextItemSelected(MenuItem item)
|
||||
{
|
||||
m_contextMenuVisible = false;
|
||||
return QtNative.onContextItemSelected(item.getItemId(), item.isChecked());
|
||||
}
|
||||
|
||||
public void openContextMenu()
|
||||
public void openContextMenu(final int x, final int y, final int w, final int h)
|
||||
{
|
||||
m_layout.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activity.openContextMenu(m_layout);
|
||||
if (Build.VERSION.SDK_INT < 11 || w <= 0 || h <= 0) {
|
||||
m_activity.openContextMenu(m_layout);
|
||||
} else if (Build.VERSION.SDK_INT < 14) {
|
||||
m_layout.removeView(m_editText);
|
||||
m_layout.addView(m_editText, new QtLayout.LayoutParams(w, h, x, y));
|
||||
QtPopupMenu.getInstance().showMenu(m_editText);
|
||||
} else {
|
||||
m_layout.removeView(m_editText);
|
||||
m_layout.addView(m_editText, new QtLayout.LayoutParams(w, h, x, y));
|
||||
QtPopupMenu14.getInstance().showMenu(m_editText);
|
||||
}
|
||||
}
|
||||
}, 10);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
public void closeContextMenu()
|
||||
|
|
|
|||
|
|
@ -440,12 +440,12 @@ public class QtNative
|
|||
return m_clipboardManager.getText().toString();
|
||||
}
|
||||
|
||||
private static void openContextMenu()
|
||||
private static void openContextMenu(final int x, final int y, final int w, final int h)
|
||||
{
|
||||
runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_activityDelegate.openContextMenu();
|
||||
m_activityDelegate.openContextMenu(x, y, w, h);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -611,6 +611,7 @@ public class QtNative
|
|||
public static native void onOptionsMenuClosed(Menu menu);
|
||||
|
||||
public static native void onCreateContextMenu(ContextMenu menu);
|
||||
public static native void fillContextMenu(Menu menu);
|
||||
public static native boolean onContextItemSelected(int itemId, boolean checked);
|
||||
public static native void onContextMenuClosed(Menu menu);
|
||||
// menu methods
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014 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.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
public class QtPopupMenu {
|
||||
private QtPopupMenu() { }
|
||||
|
||||
private static class QtPopupMenuHolder {
|
||||
private static final QtPopupMenu INSTANCE = new QtPopupMenu();
|
||||
}
|
||||
|
||||
public static QtPopupMenu getInstance() {
|
||||
return QtPopupMenuHolder.INSTANCE;
|
||||
}
|
||||
|
||||
public void showMenu(View anchor)
|
||||
{
|
||||
PopupMenu popup = new PopupMenu(QtNative.activity(), anchor);
|
||||
QtNative.activityDelegate().onCreatePopupMenu(popup.getMenu());
|
||||
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
boolean res = QtNative.onContextItemSelected(menuItem.getItemId(), menuItem.isChecked());
|
||||
if (res)
|
||||
QtNative.activityDelegate().onContextMenuClosed(null);
|
||||
return res;
|
||||
}
|
||||
});
|
||||
popup.show();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014 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.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
public class QtPopupMenu14 {
|
||||
private QtPopupMenu14() { }
|
||||
|
||||
private static class QtPopupMenu14Holder {
|
||||
private static final QtPopupMenu14 INSTANCE = new QtPopupMenu14();
|
||||
}
|
||||
|
||||
public static QtPopupMenu14 getInstance() {
|
||||
return QtPopupMenu14Holder.INSTANCE;
|
||||
}
|
||||
|
||||
public void showMenu(View anchor)
|
||||
{
|
||||
PopupMenu popup = new PopupMenu(QtNative.activity(), anchor);
|
||||
QtNative.activityDelegate().onCreatePopupMenu(popup.getMenu());
|
||||
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
return QtNative.activityDelegate().onContextItemSelected(menuItem);
|
||||
}
|
||||
});
|
||||
popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(PopupMenu popupMenu) {
|
||||
QtNative.activityDelegate().onContextMenuClosed(popupMenu.getMenu());
|
||||
}
|
||||
});
|
||||
popup.show();
|
||||
}
|
||||
}
|
||||
|
|
@ -38,9 +38,12 @@
|
|||
#include "qandroidplatformmenuitem.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QSet>
|
||||
#include <QPoint>
|
||||
#include <QQueue>
|
||||
#include <QRect>
|
||||
#include <QSet>
|
||||
#include <QWindow>
|
||||
#include <QtCore/private/qjnihelpers_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
|
@ -48,7 +51,7 @@ using namespace QtAndroid;
|
|||
|
||||
namespace QtAndroidMenu
|
||||
{
|
||||
static QQueue<QAndroidPlatformMenu *> pendingContextMenus;
|
||||
static QList<QAndroidPlatformMenu *> pendingContextMenus;
|
||||
static QAndroidPlatformMenu *visibleMenu = 0;
|
||||
static QMutex visibleMenuMutex(QMutex::Recursive);
|
||||
|
||||
|
|
@ -87,21 +90,25 @@ namespace QtAndroidMenu
|
|||
env.jniEnv->CallStaticVoidMethod(applicationClass(), openOptionsMenuMethodID);
|
||||
}
|
||||
|
||||
void showContextMenu(QAndroidPlatformMenu *menu, JNIEnv *env)
|
||||
void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env)
|
||||
{
|
||||
QMutexLocker lock(&visibleMenuMutex);
|
||||
if (visibleMenu) {
|
||||
pendingContextMenus.enqueue(menu);
|
||||
if (QtAndroidPrivate::androidSdkVersion() > 10 &&
|
||||
QtAndroidPrivate::androidSdkVersion() < 14 &&
|
||||
anchorRect.isValid()) {
|
||||
pendingContextMenus.clear();
|
||||
} else if (visibleMenu) {
|
||||
pendingContextMenus.append(visibleMenu);
|
||||
}
|
||||
|
||||
visibleMenu = menu;
|
||||
menu->aboutToShow();
|
||||
if (env) {
|
||||
env->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height());
|
||||
} else {
|
||||
visibleMenu = menu;
|
||||
menu->aboutToShow();
|
||||
if (env) {
|
||||
env->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
|
||||
} else {
|
||||
AttachedJNIEnv aenv;
|
||||
if (aenv.jniEnv)
|
||||
aenv.jniEnv->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
|
||||
}
|
||||
AttachedJNIEnv aenv;
|
||||
if (aenv.jniEnv)
|
||||
aenv.jniEnv->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +118,8 @@ namespace QtAndroidMenu
|
|||
if (visibleMenu == menu) {
|
||||
AttachedJNIEnv env;
|
||||
if (env.jniEnv)
|
||||
env.jniEnv->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
|
||||
env.jniEnv->CallStaticVoidMethod(applicationClass(), closeContextMenuMethodID);
|
||||
pendingContextMenus.clear();
|
||||
} else {
|
||||
pendingContextMenus.removeOne(menu);
|
||||
}
|
||||
|
|
@ -298,7 +306,7 @@ namespace QtAndroidMenu
|
|||
QAndroidPlatformMenuItem *item = static_cast<QAndroidPlatformMenuItem *>(menus.front()->menuItemForTag(menuId));
|
||||
if (item) {
|
||||
if (item->menu()) {
|
||||
showContextMenu(item->menu(), env);
|
||||
showContextMenu(item->menu(), QRect(), env);
|
||||
} else {
|
||||
if (item->isCheckable())
|
||||
item->setChecked(checked);
|
||||
|
|
@ -308,7 +316,7 @@ namespace QtAndroidMenu
|
|||
} else {
|
||||
QAndroidPlatformMenu *menu = static_cast<QAndroidPlatformMenu *>(visibleMenuBar->menuForTag(menuId));
|
||||
if (menu)
|
||||
showContextMenu(menu, env);
|
||||
showContextMenu(menu, QRect(), env);
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
|
|
@ -333,17 +341,30 @@ namespace QtAndroidMenu
|
|||
addAllMenuItemsToMenu(env, menu, visibleMenu);
|
||||
}
|
||||
|
||||
static void fillContextMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
|
||||
{
|
||||
env->CallVoidMethod(menu, clearMenuMethodID);
|
||||
QMutexLocker lock(&visibleMenuMutex);
|
||||
if (!visibleMenu)
|
||||
return;
|
||||
|
||||
addAllMenuItemsToMenu(env, menu, visibleMenu);
|
||||
}
|
||||
|
||||
static jboolean onContextItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
|
||||
{
|
||||
QMutexLocker lock(&visibleMenuMutex);
|
||||
QAndroidPlatformMenuItem * item = static_cast<QAndroidPlatformMenuItem *>(visibleMenu->menuItemForTag(menuId));
|
||||
if (item) {
|
||||
if (item->menu()) {
|
||||
showContextMenu(item->menu(), env);
|
||||
showContextMenu(item->menu(), QRect(), env);
|
||||
} else {
|
||||
if (item->isCheckable())
|
||||
item->setChecked(checked);
|
||||
item->activated();
|
||||
visibleMenu->aboutToHide();
|
||||
visibleMenu = 0;
|
||||
pendingContextMenus.clear();
|
||||
}
|
||||
}
|
||||
return JNI_TRUE;
|
||||
|
|
@ -354,10 +375,11 @@ namespace QtAndroidMenu
|
|||
QMutexLocker lock(&visibleMenuMutex);
|
||||
if (!visibleMenu)
|
||||
return;
|
||||
|
||||
visibleMenu->aboutToHide();
|
||||
visibleMenu = 0;
|
||||
if (!pendingContextMenus.empty())
|
||||
showContextMenu(pendingContextMenus.dequeue(), env);
|
||||
showContextMenu(pendingContextMenus.takeLast(), QRect(), env);
|
||||
}
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
|
|
@ -365,6 +387,7 @@ namespace QtAndroidMenu
|
|||
{"onOptionsItemSelected", "(IZ)Z", (void *)onOptionsItemSelected},
|
||||
{"onOptionsMenuClosed", "(Landroid/view/Menu;)V", (void*)onOptionsMenuClosed},
|
||||
{"onCreateContextMenu", "(Landroid/view/ContextMenu;)V", (void *)onCreateContextMenu},
|
||||
{"fillContextMenu", "(Landroid/view/Menu;)V", (void *)fillContextMenu},
|
||||
{"onContextItemSelected", "(IZ)Z", (void *)onContextItemSelected},
|
||||
{"onContextMenuClosed", "(Landroid/view/Menu;)V", (void*)onContextMenuClosed},
|
||||
};
|
||||
|
|
@ -406,7 +429,7 @@ namespace QtAndroidMenu
|
|||
return false;
|
||||
}
|
||||
|
||||
GET_AND_CHECK_STATIC_METHOD(openContextMenuMethodID, appClass, "openContextMenu", "()V");
|
||||
GET_AND_CHECK_STATIC_METHOD(openContextMenuMethodID, appClass, "openContextMenu", "(IIII)V");
|
||||
GET_AND_CHECK_STATIC_METHOD(closeContextMenuMethodID, appClass, "closeContextMenu", "()V");
|
||||
GET_AND_CHECK_STATIC_METHOD(resetOptionsMenuMethodID, appClass, "resetOptionsMenu", "()V");
|
||||
GET_AND_CHECK_STATIC_METHOD(openOptionsMenuMethodID, appClass, "openOptionsMenu", "()V");
|
||||
|
|
|
|||
|
|
@ -43,12 +43,14 @@ class QAndroidPlatformMenuBar;
|
|||
class QAndroidPlatformMenu;
|
||||
class QAndroidPlatformMenuItem;
|
||||
class QWindow;
|
||||
class QRect;
|
||||
class QPoint;
|
||||
|
||||
namespace QtAndroidMenu
|
||||
{
|
||||
// Menu support
|
||||
void openOptionsMenu();
|
||||
void showContextMenu(QAndroidPlatformMenu *menu, JNIEnv *env = 0);
|
||||
void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env = 0);
|
||||
void hideContextMenu(QAndroidPlatformMenu *menu);
|
||||
void syncMenu(QAndroidPlatformMenu *menu);
|
||||
void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu);
|
||||
|
|
|
|||
|
|
@ -135,13 +135,12 @@ bool QAndroidPlatformMenu::isVisible() const
|
|||
return m_isVisible;
|
||||
}
|
||||
|
||||
void QAndroidPlatformMenu::showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item)
|
||||
void QAndroidPlatformMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item)
|
||||
{
|
||||
Q_UNUSED(parentWindow);
|
||||
Q_UNUSED(pos);
|
||||
Q_UNUSED(item);
|
||||
setVisible(true);
|
||||
QtAndroidMenu::showContextMenu(this);
|
||||
QtAndroidMenu::showContextMenu(this, targetRect);
|
||||
}
|
||||
|
||||
QPlatformMenuItem *QAndroidPlatformMenu::menuItemAt(int position) const
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public:
|
|||
bool isEnabled() const;
|
||||
void setVisible(bool visible);
|
||||
bool isVisible() const;
|
||||
void showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item);
|
||||
void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item);
|
||||
|
||||
QPlatformMenuItem *menuItemAt(int position) const;
|
||||
QPlatformMenuItem *menuItemForTag(quintptr tag) const;
|
||||
|
|
|
|||
Loading…
Reference in New Issue