From 9275edbc31a0ca83740df5b4450b7776c59012dc Mon Sep 17 00:00:00 2001 From: Alexey Edelev Date: Tue, 30 Mar 2021 10:19:35 +0200 Subject: [PATCH 1/3] Remove the redundant code related to the QT_NAMESPACE variable Change-Id: Ib82b199fc7761c8b84f915c2808c7f57bf23927c Reviewed-by: Alexandru Croitor --- cmake/QtBuild.cmake | 5 ----- src/corelib/CMakeLists.txt | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake index c904743b8a4..9766e7f683f 100644 --- a/cmake/QtBuild.cmake +++ b/cmake/QtBuild.cmake @@ -367,11 +367,6 @@ set(QT_PLATFORM_DEFINITION_DIR "${QT_DEFAULT_PLATFORM_DEFINITION_DIR}" set(QT_PLATFORM_DEFINITION_DIR_ABSOLUTE "${QT_DEFAULT_PLATFORM_DEFINITION_DIR_ABSOLUTE}" CACHE INTERNAL "Path to directory that contains qplatformdefs.h") set(QT_NAMESPACE "" CACHE STRING "Qt Namespace") -if(QT_NAMESPACE STREQUAL "") - set(QT_HAS_NAMESPACE OFF) -else() - set(QT_HAS_NAMESPACE ON) -endif() include(QtGlobalStateHelpers) diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 1a9a690f427..54b756d2a60 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -273,8 +273,7 @@ add_dependencies(Core ${QT_CMAKE_EXPORT_NAMESPACE}::rcc) add_dependencies(CorePrivate ${QT_CMAKE_EXPORT_NAMESPACE}::moc) add_dependencies(CorePrivate ${QT_CMAKE_EXPORT_NAMESPACE}::rcc) -if (QT_NAMESPACE STREQUAL "") -else() +if (NOT QT_NAMESPACE STREQUAL "") target_compile_definitions(Core PUBLIC "QT_NAMESPACE=${QT_NAMESPACE}") endif() From c80f262258b7846bf199887bcfdbb6dcfda6ad6f Mon Sep 17 00:00:00 2001 From: Piotr Mikolajczyk Date: Thu, 25 Feb 2021 15:36:29 +0100 Subject: [PATCH 2/3] Android: Add select and copy capability to read-only text widgets In case of a read-only text editing widget it was imposibble to copy text from it. In QtWidgets you could not even see the selection handless. Text selection in QtWidgets module was filtered depending on readOnly property of the widget. Additionally, in InputMethod the read-only state was translated into disabled. Patch also makes the edit menu to be aware of the read-only status of the control - the menu items are different for rw and ro controls. Task-number: QTBUG-91417 Change-Id: Ic7b27f78678eeaa87a38607af787f254db1383b8 Reviewed-by: Rami Potinkara Reviewed-by: Ville Voutilainen --- .../qt/android/QtActivityDelegate.java | 4 +-- src/corelib/global/qnamespace.h | 1 + .../android/qandroidinputcontext.cpp | 31 ++++++++++--------- src/widgets/widgets/qlineedit.cpp | 16 +++++++++- src/widgets/widgets/qlineedit_p.cpp | 12 +++++++ src/widgets/widgets/qlineedit_p.h | 6 ++++ src/widgets/widgets/qplaintextedit.cpp | 11 +++++-- src/widgets/widgets/qtextbrowser.cpp | 11 ++++++- src/widgets/widgets/qtextedit.cpp | 6 ++++ src/widgets/widgets/qwidgetlinecontrol_p.h | 3 ++ src/widgets/widgets/qwidgettextcontrol.cpp | 2 +- .../widgets/qtextbrowser/tst_qtextbrowser.cpp | 18 +++++++++++ 12 files changed, 99 insertions(+), 22 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java index e9efd064975..0a60587aa8b 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -566,9 +566,7 @@ public class QtActivityDelegate break; } - if (QtNative.hasClipboardText()) - editButtons |= EditContextView.PASTE_BUTTON; - else + if (!QtNative.hasClipboardText()) editButtons &= ~EditContextView.PASTE_BUTTON; if ((mode & CursorHandleShowEdit) == CursorHandleShowEdit && editButtons != 0) { diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 4a051e8ff0e..0f5003e5931 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1394,6 +1394,7 @@ namespace Qt { ImAnchorRectangle = 0x4000, ImInputItemClipRectangle = 0x8000, + ImReadOnly = 0x10000, ImPlatformData = 0x80000000, ImQueryInput = ImCursorRectangle | ImCursorPosition | ImSurroundingText | ImCurrentSelection | ImAnchorRectangle | ImAnchorPosition, diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 9ed6dd396d8..01b8ae8deed 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -604,34 +604,34 @@ void QAndroidInputContext::updateCursorPosition() void QAndroidInputContext::updateSelectionHandles() { static bool noHandles = qEnvironmentVariableIntValue("QT_QPA_NO_TEXT_HANDLES"); - if (noHandles) + if (noHandles || !m_focusObject) return; auto im = qGuiApp->inputMethod(); - if (!m_focusObject || ((m_handleMode & 0xff) == Hidden)) { - // Hide the handles - QtAndroidInput::updateHandles(Hidden); - return; - } - QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled | Qt::ImCurrentSelection | Qt::ImHints | Qt::ImSurroundingText); + + QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled + | Qt::ImCurrentSelection | Qt::ImHints | Qt::ImSurroundingText + | Qt::ImReadOnly); QCoreApplication::sendEvent(m_focusObject, &query); int cpos = query.value(Qt::ImCursorPosition).toInt(); int anchor = query.value(Qt::ImAnchorPosition).toInt(); + const QVariant readOnlyVariant = query.value(Qt::ImReadOnly); + bool readOnly = readOnlyVariant.toBool(); + + if ( cpos == anchor && (!readOnlyVariant.isValid() || readOnly)) { + QtAndroidInput::updateHandles(Hidden); + return; + } if (cpos == anchor || im->anchorRectangle().isNull()) { - if (!query.value(Qt::ImEnabled).toBool()) { - QtAndroidInput::updateHandles(Hidden); - return; - } - auto curRect = cursorRectangle(); QPoint cursorPoint = qGuiApp->focusWindow()->handle()->mapToGlobal(QPoint(curRect.x() + (curRect.width() / 2), curRect.y() + curRect.height())); QPoint editMenuPoint(cursorPoint.x(), cursorPoint.y()); m_handleMode &= ShowEditPopup; m_handleMode |= ShowCursor; - uint32_t buttons = EditContext::PasteButton; + uint32_t buttons = readOnly ? 0 : EditContext::PasteButton; if (!query.value(Qt::ImSurroundingText).toString().isEmpty()) buttons |= EditContext::SelectAllButton; QtAndroidInput::updateHandles(m_handleMode, editMenuPoint, buttons, cursorPoint); @@ -650,7 +650,10 @@ void QAndroidInputContext::updateSelectionHandles() QPoint leftPoint(leftRect.bottomLeft().toPoint()); QPoint righPoint(rightRect.bottomRight().toPoint()); QPoint editPoint(leftRect.united(rightRect).topLeft().toPoint()); - QtAndroidInput::updateHandles(m_handleMode, editPoint, EditContext::AllButtons, leftPoint, righPoint, + uint32_t buttons = readOnly ? EditContext::CopyButton | EditContext::SelectAllButton + : EditContext::AllButtons; + + QtAndroidInput::updateHandles(m_handleMode, editPoint, buttons, leftPoint, righPoint, query.value(Qt::ImCurrentSelection).toString().isRightToLeft()); m_hideCursorHandleTimer.stop(); } diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index 9643c4db433..a308f92f9d6 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -1806,7 +1806,7 @@ QRect QLineEdit::cursorRect() const void QLineEdit::inputMethodEvent(QInputMethodEvent *e) { Q_D(QLineEdit); - if (d->control->isReadOnly()) { + if (!d->shouldEnableInputMethod()) { e->ignore(); return; } @@ -1874,6 +1874,20 @@ QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property, QVariant arg return QVariant(d->control->selectionEnd()); else return QVariant(d->control->selectionStart()); + case Qt::ImReadOnly: + return isReadOnly(); + case Qt::ImTextBeforeCursor: { + const QPointF pt = argument.toPointF(); + if (!pt.isNull()) + return d->textBeforeCursor(d->xToPos(pt.x(), QTextLine::CursorBetweenCharacters)); + else + return d->textBeforeCursor(d->control->cursor()); } + case Qt::ImTextAfterCursor: { + const QPointF pt = argument.toPointF(); + if (!pt.isNull()) + return d->textAfterCursor(d->xToPos(pt.x(), QTextLine::CursorBetweenCharacters)); + else + return d->textAfterCursor(d->control->cursor()); } default: return QWidget::inputMethodQuery(property); } diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp index 7526379f3c6..a5ac6a2211c 100644 --- a/src/widgets/widgets/qlineedit_p.cpp +++ b/src/widgets/widgets/qlineedit_p.cpp @@ -86,6 +86,18 @@ int QLineEditPrivate::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const return control->xToPos(x, betweenOrOn); } +QString QLineEditPrivate::textBeforeCursor(int curPos) const +{ + const QString &text = control->text(); + return text.mid(0, curPos); +} + +QString QLineEditPrivate::textAfterCursor(int curPos) const +{ + const QString &text = control->text(); + return text.mid(curPos); +} + bool QLineEditPrivate::inSelection(int x) const { x -= adjustedContentsRect().x() - hscroll + horizontalMargin; diff --git a/src/widgets/widgets/qlineedit_p.h b/src/widgets/widgets/qlineedit_p.h index 936cf2d088f..de9b9c16363 100644 --- a/src/widgets/widgets/qlineedit_p.h +++ b/src/widgets/widgets/qlineedit_p.h @@ -179,13 +179,19 @@ public: void setCursorVisible(bool visible); void setText(const QString& text); + QString textBeforeCursor(int curPos) const; + QString textAfterCursor(int curPos) const; void updatePasswordEchoEditing(bool); void resetInputMethod(); inline bool shouldEnableInputMethod() const { +#if defined (Q_OS_ANDROID) + return !control->isReadOnly() || control->isSelectableByMouse(); +#else return !control->isReadOnly(); +#endif } inline bool shouldShowPlaceholderText() const { diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index d2006d05628..20fdbcd6a85 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -71,9 +71,14 @@ QT_BEGIN_NAMESPACE -static inline bool shouldEnableInputMethod(QPlainTextEdit *plaintextedit) +static inline bool shouldEnableInputMethod(QPlainTextEdit *control) { - return !plaintextedit->isReadOnly(); +#if defined(Q_OS_ANDROID) + Q_UNUSED(control); + return !control->isReadOnly() || (control->textInteractionFlags() & Qt::TextSelectableByMouse); +#else + return !control->isReadOnly(); +#endif } class QPlainTextDocumentLayoutPrivate : public QAbstractTextDocumentLayoutPrivate @@ -2238,6 +2243,8 @@ QVariant QPlainTextEdit::inputMethodQuery(Qt::InputMethodQuery query, QVariant a case Qt::ImHints: case Qt::ImInputItemClipRectangle: return QWidget::inputMethodQuery(query); + case Qt::ImReadOnly: + return isReadOnly(); default: break; } diff --git a/src/widgets/widgets/qtextbrowser.cpp b/src/widgets/widgets/qtextbrowser.cpp index 99ebaa93bfa..6b05156ea3f 100644 --- a/src/widgets/widgets/qtextbrowser.cpp +++ b/src/widgets/widgets/qtextbrowser.cpp @@ -57,6 +57,15 @@ QT_BEGIN_NAMESPACE +static inline bool shouldEnableInputMethod(QTextBrowser *texbrowser) +{ +#if defined (Q_OS_ANDROID) + return !texbrowser->isReadOnly() || (texbrowser->textInteractionFlags() & Qt::TextSelectableByMouse); +#else + return !texbrowser->isReadOnly(); +#endif +} + Q_LOGGING_CATEGORY(lcBrowser, "qt.text.browser") class QTextBrowserPrivate : public QTextEditPrivate @@ -692,7 +701,7 @@ void QTextBrowserPrivate::init() #ifndef QT_NO_CURSOR viewport->setCursor(oldCursor); #endif - q->setAttribute(Qt::WA_InputMethodEnabled, !q->isReadOnly()); + q->setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(q)); q->setUndoRedoEnabled(false); viewport->setMouseTracking(true); QObject::connect(q->document(), SIGNAL(contentsChanged()), q, SLOT(_q_documentModified())); diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp index 9cdee2964fa..2d3f98b4b9e 100644 --- a/src/widgets/widgets/qtextedit.cpp +++ b/src/widgets/widgets/qtextedit.cpp @@ -79,7 +79,11 @@ QT_BEGIN_NAMESPACE static inline bool shouldEnableInputMethod(QTextEdit *textedit) { +#if defined (Q_OS_ANDROID) + return !textedit->isReadOnly() || (textedit->textInteractionFlags() & Qt::TextSelectableByMouse); +#else return !textedit->isReadOnly(); +#endif } class QTextEditControl : public QWidgetTextControl @@ -1832,6 +1836,8 @@ QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery query, QVariant argume case Qt::ImHints: case Qt::ImInputItemClipRectangle: return QWidget::inputMethodQuery(query); + case Qt::ImReadOnly: + return isReadOnly(); default: break; } diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h index f906165c203..bb24fe4d5ba 100644 --- a/src/widgets/widgets/qwidgetlinecontrol_p.h +++ b/src/widgets/widgets/qwidgetlinecontrol_p.h @@ -164,6 +164,9 @@ public: int selectionStart() const { return hasSelectedText() ? m_selstart : -1; } int selectionEnd() const { return hasSelectedText() ? m_selend : -1; } +#if defined (Q_OS_ANDROID) + bool isSelectableByMouse() const { return true; } +#endif bool inSelection(int x) const { if (m_selstart >= m_selend) diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index 1972ff366b4..c9c4c848fc6 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -2039,7 +2039,7 @@ bool QWidgetTextControlPrivate::dropEvent(const QMimeData *mimeData, const QPoin void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) { Q_Q(QWidgetTextControl); - if (!(interactionFlags & Qt::TextEditable) || cursor.isNull()) { + if (!(interactionFlags & (Qt::TextEditable | Qt::TextSelectableByMouse)) || cursor.isNull()) { e->ignore(); return; } diff --git a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp index 73266d77f3e..ec187a55b04 100644 --- a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp +++ b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp @@ -466,11 +466,29 @@ void tst_QTextBrowser::textInteractionFlags_vs_readOnly() void tst_QTextBrowser::inputMethodAttribute_vs_readOnly() { QVERIFY(browser->isReadOnly()); +#if defined(Q_OS_ANDROID) + QInputMethodQueryEvent query(Qt::ImReadOnly); + QCoreApplication::sendEvent(browser, &query); + QVERIFY(query.value(Qt::ImReadOnly).toBool()); +#else QVERIFY(!browser->testAttribute(Qt::WA_InputMethodEnabled)); +#endif + browser->setReadOnly(false); +#if defined(Q_OS_ANDROID) + QCoreApplication::sendEvent(browser, &query); + QVERIFY(!query.value(Qt::ImReadOnly).toBool()); +#else QVERIFY(browser->testAttribute(Qt::WA_InputMethodEnabled)); +#endif + browser->setReadOnly(true); +#if defined(Q_OS_ANDROID) + QCoreApplication::sendEvent(browser, &query); + QVERIFY(query.value(Qt::ImReadOnly).toBool()); +#else QVERIFY(!browser->testAttribute(Qt::WA_InputMethodEnabled)); +#endif } void tst_QTextBrowser::anchorsWithSelfBuiltHtml() From b4aac2af19690917553f93660e3ad760fc15d0b9 Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 29 Mar 2021 18:34:43 +0200 Subject: [PATCH 3/3] QAbstractItemModelTester: fix false positive when model has zero columns Regression introduced by me in commit 72e0d699cec09458ca9325035d477d4899e8e47b Fixes: QTBUG-92220 Change-Id: Ic7dd4eda0a1993f9763933882baf928bfc83b08b Pick-to: 6.1 6.0 5.15 Reviewed-by: Luca Beldi Reviewed-by: Alexandru Croitor --- src/testlib/qabstractitemmodeltester.cpp | 2 +- .../tst_qabstractitemmodeltester.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/testlib/qabstractitemmodeltester.cpp b/src/testlib/qabstractitemmodeltester.cpp index 42bac5afb2a..165baedfbe6 100644 --- a/src/testlib/qabstractitemmodeltester.cpp +++ b/src/testlib/qabstractitemmodeltester.cpp @@ -439,7 +439,7 @@ void QAbstractItemModelTesterPrivate::parent() // when asked for the parent of an invalid index. MODELTESTER_VERIFY(!model->parent(QModelIndex()).isValid()); - if (model->rowCount() == 0) + if (model->rowCount() == 0 || model->columnCount() == 0) return; // Column 0 | Column 1 | diff --git a/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp b/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp index de461dd293a..bc96cab64bd 100644 --- a/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp +++ b/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp @@ -41,6 +41,7 @@ private slots: void stringListModel(); void treeWidgetModel(); void standardItemModel(); + void standardItemModelZeroColumns(); void testInsertThroughProxy(); void moveSourceItems(); void testResetThroughProxy(); @@ -105,6 +106,15 @@ void tst_QAbstractItemModelTester::standardItemModel() model.insertColumns(0, 5, model.index(1, 3)); } +void tst_QAbstractItemModelTester::standardItemModelZeroColumns() // QTBUG-92220 +{ + QStandardItemModel model; + + QAbstractItemModelTester t1(&model); + model.insertRows(0, 5); + model.removeRows(0, 5); +} + void tst_QAbstractItemModelTester::testInsertThroughProxy() { DynamicTreeModel *model = new DynamicTreeModel(this);