From 756a169e2530987f1b875589d196877e93704858 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 19 Jul 2016 13:17:29 +0200 Subject: texteditor example: check if document is null before using it This hasn't been an issue so far probably because those properties were accessed after m_doc had been set. However, adding some debug text can trigger a crash: Text { text: "document.cursorPosition=" + document.cursorPosition } Change-Id: Ib468815cdc0b103a2384457ab937cc3b764b96c8 Reviewed-by: Friedemann Kleint --- examples/quickcontrols/controls/texteditor/src/documenthandler.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/quickcontrols/controls/texteditor/src/documenthandler.cpp b/examples/quickcontrols/controls/texteditor/src/documenthandler.cpp index 2e03f7471..b07099e26 100644 --- a/examples/quickcontrols/controls/texteditor/src/documenthandler.cpp +++ b/examples/quickcontrols/controls/texteditor/src/documenthandler.cpp @@ -169,6 +169,9 @@ void DocumentHandler::reset() QTextCursor DocumentHandler::textCursor() const { + if (!m_doc) + return QTextCursor(); + QTextCursor cursor = QTextCursor(m_doc); if (m_selectionStart != m_selectionEnd) { cursor.setPosition(m_selectionStart); @@ -199,6 +202,9 @@ void DocumentHandler::setSelectionEnd(int position) void DocumentHandler::setAlignment(Qt::Alignment a) { + if (!m_doc) + return; + QTextBlockFormat fmt; fmt.setAlignment((Qt::Alignment) a); QTextCursor cursor = QTextCursor(m_doc); -- cgit v1.2.3 From 56d711667f4601016b474b3d463ce07659c42b9a Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Tue, 26 Jul 2016 15:34:48 +0100 Subject: Don't activate transient parent if it was closed meanwhile Closing a window while a popup is open should not trigger an activation event when the popup is closed. Prevents QGuiApplicationPrivate::focus_window from being changed to a stale window, which happens inside QGuiApplicationPrivate::processActivatedEvent(). Change-Id: I3145b3d191abb20d56fa9acbec8a0776a6bf8526 Reviewed-by: Laszlo Agocs Reviewed-by: Gabriel de Dietrich --- src/controls/qquickpopupwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controls/qquickpopupwindow.cpp b/src/controls/qquickpopupwindow.cpp index 88d91137e..ac9617091 100644 --- a/src/controls/qquickpopupwindow.cpp +++ b/src/controls/qquickpopupwindow.cpp @@ -224,7 +224,8 @@ void QQuickPopupWindow::hideEvent(QHideEvent *e) { if (QWindow *tp = !m_needsActivatedEvent ? transientParent() : 0) { m_needsActivatedEvent = true; - QWindowSystemInterface::handleWindowActivated(tp); + if (tp->isVisible()) + QWindowSystemInterface::handleWindowActivated(tp); } QQuickWindow::hideEvent(e); -- cgit v1.2.3 From c0f58d5283ce981b8cfbc43f602a3b6553e26ce2 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Fri, 12 Aug 2016 11:12:22 +0200 Subject: Doc: Change instances of 'OS X' to 'macOS' As of version 10.12 (Sierra), the name of Apple's desktop operating system will be macOS. Change all occurrences where the platform is discussed to use the macro \macos (defined in the documentation configuration in qtbase). Change-Id: I5ca47e4d830c12df297ee298ed22fd2d41dee739 Reviewed-by: Leena Miettinen --- src/controls/Private/qquickstyleitem.cpp | 2 +- src/controls/doc/src/qtquickcontrols-examples.qdoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controls/Private/qquickstyleitem.cpp b/src/controls/Private/qquickstyleitem.cpp index d7d2d4c3f..7b0446db5 100644 --- a/src/controls/Private/qquickstyleitem.cpp +++ b/src/controls/Private/qquickstyleitem.cpp @@ -67,7 +67,7 @@ static inline HIRect qt_hirectForQRect(const QRect &convertRect, const QRect &re returned if it can't be obtained. It is the caller's responsibility to CGContextRelease the context when finished using it. - \warning This function is only available on Mac OS X. + \warning This function is only available on \macos. \warning This function is duplicated in qmacstyle_mac.mm */ CGContextRef qt_mac_cg_context(const QPaintDevice *pdev) diff --git a/src/controls/doc/src/qtquickcontrols-examples.qdoc b/src/controls/doc/src/qtquickcontrols-examples.qdoc index 7ad34a303..0e0e1ee24 100644 --- a/src/controls/doc/src/qtquickcontrols-examples.qdoc +++ b/src/controls/doc/src/qtquickcontrols-examples.qdoc @@ -46,7 +46,7 @@ \endraw \image qtquickcontrols-example-gallery-osx.png - \caption OS X + \caption \macos \raw HTML \endraw -- cgit v1.2.3 From efdd81ce80b018b7b5779876e94f1b722af7fb9a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 13 Aug 2016 16:58:44 +0200 Subject: Fix ColorDialog.color and FontDialog.font update on accept When using native dialogs, ColorDialog.color was not updated at all, and FontDialog.font was incorrectly following FontDialog.currentFont. Promote the overridden accept() methods to the abstract base classes so the native dialogs get the appropriate property updates on accept the same way compared to the non-native dialogs. Task-number: QTBUG-55298 Change-Id: I9ac8f5ecc60884cd98b58d09ef3dcb4baf47772d Reviewed-by: Mitch Curtis --- src/dialogs/qquickabstractcolordialog.cpp | 6 ++++++ src/dialogs/qquickabstractcolordialog_p.h | 3 +++ src/dialogs/qquickabstractfontdialog.cpp | 6 ++++++ src/dialogs/qquickabstractfontdialog_p.h | 3 +++ src/dialogs/qquickcolordialog.cpp | 6 ------ src/dialogs/qquickcolordialog_p.h | 3 --- src/dialogs/qquickfontdialog.cpp | 6 ------ src/dialogs/qquickfontdialog_p.h | 3 --- src/dialogs/qquickplatformfontdialog.cpp | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/dialogs/qquickabstractcolordialog.cpp b/src/dialogs/qquickabstractcolordialog.cpp index 2101fe0ec..44c203df9 100644 --- a/src/dialogs/qquickabstractcolordialog.cpp +++ b/src/dialogs/qquickabstractcolordialog.cpp @@ -124,4 +124,10 @@ void QQuickAbstractColorDialog::setShowAlphaChannel(bool arg) emit showAlphaChannelChanged(); } +void QQuickAbstractColorDialog::accept() +{ + setColor(m_currentColor); + QQuickAbstractDialog::accept(); +} + QT_END_NAMESPACE diff --git a/src/dialogs/qquickabstractcolordialog_p.h b/src/dialogs/qquickabstractcolordialog_p.h index 99be766ca..16b39c267 100644 --- a/src/dialogs/qquickabstractcolordialog_p.h +++ b/src/dialogs/qquickabstractcolordialog_p.h @@ -96,6 +96,9 @@ Q_SIGNALS: void currentColorChanged(); void selectionAccepted(); +protected Q_SLOTS: + virtual void accept(); + protected: QPlatformColorDialogHelper *m_dlgHelper; QSharedPointer m_options; diff --git a/src/dialogs/qquickabstractfontdialog.cpp b/src/dialogs/qquickabstractfontdialog.cpp index fb715c358..0886449bb 100644 --- a/src/dialogs/qquickabstractfontdialog.cpp +++ b/src/dialogs/qquickabstractfontdialog.cpp @@ -154,4 +154,10 @@ void QQuickAbstractFontDialog::setProportionalFonts(bool arg) emit proportionalFontsChanged(); } +void QQuickAbstractFontDialog::accept() +{ + setFont(m_currentFont); + QQuickAbstractDialog::accept(); +} + QT_END_NAMESPACE diff --git a/src/dialogs/qquickabstractfontdialog_p.h b/src/dialogs/qquickabstractfontdialog_p.h index 3162be2ad..f60c4ddb8 100644 --- a/src/dialogs/qquickabstractfontdialog_p.h +++ b/src/dialogs/qquickabstractfontdialog_p.h @@ -101,6 +101,9 @@ Q_SIGNALS: void currentFontChanged(); void selectionAccepted(); +protected Q_SLOTS: + virtual void accept(); + protected: QPlatformFontDialogHelper *m_dlgHelper; QSharedPointer m_options; diff --git a/src/dialogs/qquickcolordialog.cpp b/src/dialogs/qquickcolordialog.cpp index 875c67403..686bd850d 100644 --- a/src/dialogs/qquickcolordialog.cpp +++ b/src/dialogs/qquickcolordialog.cpp @@ -118,10 +118,4 @@ QQuickColorDialog::~QQuickColorDialog() \l Window or an \l Item. */ -void QQuickColorDialog::accept() -{ - setColor(m_currentColor); - QQuickAbstractColorDialog::accept(); -} - QT_END_NAMESPACE diff --git a/src/dialogs/qquickcolordialog_p.h b/src/dialogs/qquickcolordialog_p.h index d3c3463bb..619b7b100 100644 --- a/src/dialogs/qquickcolordialog_p.h +++ b/src/dialogs/qquickcolordialog_p.h @@ -65,9 +65,6 @@ public: explicit QQuickColorDialog(QObject *parent = 0); ~QQuickColorDialog(); -protected Q_SLOTS: - virtual void accept(); - protected: virtual QPlatformColorDialogHelper *helper() { return 0; } diff --git a/src/dialogs/qquickfontdialog.cpp b/src/dialogs/qquickfontdialog.cpp index 0e27d29a9..00acf238e 100644 --- a/src/dialogs/qquickfontdialog.cpp +++ b/src/dialogs/qquickfontdialog.cpp @@ -119,10 +119,4 @@ QQuickFontDialog::~QQuickFontDialog() \l Window or an \l Item. */ -void QQuickFontDialog::accept() -{ - setFont(m_currentFont); - QQuickAbstractFontDialog::accept(); -} - QT_END_NAMESPACE diff --git a/src/dialogs/qquickfontdialog_p.h b/src/dialogs/qquickfontdialog_p.h index 71301a761..bd04f5361 100644 --- a/src/dialogs/qquickfontdialog_p.h +++ b/src/dialogs/qquickfontdialog_p.h @@ -65,9 +65,6 @@ public: explicit QQuickFontDialog(QObject *parent = 0); ~QQuickFontDialog(); -protected Q_SLOTS: - virtual void accept(); - protected: virtual QPlatformFontDialogHelper *helper() { return 0; } diff --git a/src/dialogs/qquickplatformfontdialog.cpp b/src/dialogs/qquickplatformfontdialog.cpp index 247e869e2..2c501a1c6 100644 --- a/src/dialogs/qquickplatformfontdialog.cpp +++ b/src/dialogs/qquickplatformfontdialog.cpp @@ -170,7 +170,7 @@ QPlatformFontDialogHelper *QQuickPlatformFontDialog::helper() return m_dlgHelper; connect(m_dlgHelper, SIGNAL(accept()), this, SLOT(accept())); connect(m_dlgHelper, SIGNAL(reject()), this, SLOT(reject())); - connect(m_dlgHelper, SIGNAL(currentFontChanged(QFont)), this, SLOT(setFont(QFont))); + connect(m_dlgHelper, SIGNAL(currentFontChanged(QFont)), this, SLOT(setCurrentFont(QFont))); connect(m_dlgHelper, SIGNAL(fontSelected(QFont)), this, SLOT(setFont(QFont))); } -- cgit v1.2.3 From 69af774a54198a83f774c89b5d5d7135b8fb1f7a Mon Sep 17 00:00:00 2001 From: Nikita Krupenko Date: Sun, 31 Jan 2016 23:38:55 +0200 Subject: Update scroll indicator position on content size change If scroll indicator is at the beginning and data prepended to contentItem, scroll indicator should change position to previous content beginning. This is especially important with so-called "infinite scrolling", when scrolling goes upwards and new content added at the top of the view. Task-number: QTBUG-50795 Change-Id: I250d6535b1146a54c6a70062b659cc49ed43709f Reviewed-by: Mitch Curtis --- src/controls/Private/ScrollViewHelper.qml | 10 +++++ tests/auto/controls/data/tst_scrollview.qml | 63 +++++++++++++++++++++++++++++ tests/auto/testplugin/testcppmodels.h | 52 ++++++++++++++++++++++++ tests/auto/testplugin/testplugin.cpp | 1 + 4 files changed, 126 insertions(+) diff --git a/src/controls/Private/ScrollViewHelper.qml b/src/controls/Private/ScrollViewHelper.qml index b4a589bf7..bc3d9eb83 100644 --- a/src/controls/Private/ScrollViewHelper.qml +++ b/src/controls/Private/ScrollViewHelper.qml @@ -131,6 +131,11 @@ Item { anchors.right: cornerFill.left anchors.leftMargin: leftMargin anchors.bottomMargin: bottomMargin + onScrollAmountChanged: { + if (flickableItem && (flickableItem.atXBeginning || flickableItem.atXEnd)) { + value = flickableItem.contentX - flickableItem.originX + } + } onValueChanged: { if (!blockUpdates) { flickableItem.contentX = value + flickableItem.originX @@ -180,6 +185,11 @@ Item { anchors.top: parent.top anchors.topMargin: __scrollBarTopMargin + topMargin anchors.rightMargin: rightMargin + onScrollAmountChanged: { + if (flickableItem && (flickableItem.atYBeginning || flickableItem.atYEnd)) { + value = flickableItem.contentY - flickableItem.originY + } + } onValueChanged: { if (flickableItem && !blockUpdates && enabled) { flickableItem.contentY = value + flickableItem.originY diff --git a/tests/auto/controls/data/tst_scrollview.qml b/tests/auto/controls/data/tst_scrollview.qml index e687c9bcc..cb96c3db6 100644 --- a/tests/auto/controls/data/tst_scrollview.qml +++ b/tests/auto/controls/data/tst_scrollview.qml @@ -41,6 +41,7 @@ import QtQuick 2.2 import QtTest 1.0 import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.1 import QtQuickControlsTests 1.0 Item { @@ -90,6 +91,68 @@ TestCase { scrollView.destroy() } + Component { + id: dragFetchAppendComponent + + ScrollView { + width: 400; height: 400 + frameVisible: false + style: ScrollViewStyle { + transientScrollBars: false + handle: Rectangle { + implicitWidth: 16; implicitHeight: 16 + color: "red" + } + scrollBarBackground: Item {width: 16 ; height: 16} + incrementControl: Rectangle { + width: 16; height: 16 + color: "blue" + } + decrementControl: Rectangle { + width: 16; height: 16 + color: "blue" + } + } + ListView { + id: view + + verticalLayoutDirection: ListView.BottomToTop + model: TestFetchAppendModel { } + delegate: Text { + width: view.width + height: 60 + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: "Item %1".arg(model.index) + } + } + } + } + + function test_dragFetchAppend() { // QTBUG-50795 + var scrollView = dragFetchAppendComponent.createObject(container) + verify(scrollView !== null, "view created is null") + waitForRendering(scrollView) + verify(scrollView.flickableItem.contentHeight === 60 * 20) + + // After scrolling to the end, view should ask the model to fetch more + // data, content height should increase and scrollbar handle should move + // to the center. + mouseDrag(scrollView, scrollView.width - 2, scrollView.height - 8 - 16, 0, -scrollView.height + 8 + 16) + waitForRendering(scrollView) + + // Move it again to fetch more data from the model. + mouseDrag(scrollView, scrollView.width - 2, scrollView.height / 2, 0, -scrollView.height / 2 + 8 + 16) + waitForRendering(scrollView) + + mouseRelease(scrollView, scrollView.width - 2, 8 + 16) + waitForRendering(scrollView) + + verify(Math.round(scrollView.flickableItem.contentHeight) > 60 * 20) + verify(Math.round(scrollView.flickableItem.contentY) < -(60 * 20)) + + scrollView.destroy() + } function test_scrollbars() { var component = scrollViewComponent diff --git a/tests/auto/testplugin/testcppmodels.h b/tests/auto/testplugin/testcppmodels.h index f5cc62986..6298bd13b 100644 --- a/tests/auto/testplugin/testcppmodels.h +++ b/tests/auto/testplugin/testcppmodels.h @@ -96,6 +96,58 @@ private: QList m_testobject; }; +class TestFetchAppendModel : public QAbstractListModel +{ + Q_OBJECT +public: + explicit TestFetchAppendModel(QObject *parent = 0) + : QAbstractListModel(parent) { } + + virtual int rowCount(const QModelIndex &parent) const + { + if (parent.isValid()) { + return 0; + } + + return m_data.size(); + } + virtual QVariant data(const QModelIndex &index, int role) const + { + if (!index.isValid() || role != Qt::DisplayRole) { + return QVariant(); + } + + return QVariant::fromValue(index.row()); + } + + virtual bool canFetchMore(const QModelIndex &parent) const + { + Q_UNUSED(parent) + + return true; + } + virtual void fetchMore(const QModelIndex & parent) + { + Q_UNUSED(parent) + + addMoreData(); + } + +private: + void addMoreData() + { + static const int insertCount = 20; + + beginInsertRows(QModelIndex(), m_data.size(), m_data.size() + insertCount - 1); + for (int i = 0; i < insertCount; i++) { + m_data.append(int()); + } + endInsertRows(); + } + + QList m_data; +}; + #endif // TESTCPPMODELS_H diff --git a/tests/auto/testplugin/testplugin.cpp b/tests/auto/testplugin/testplugin.cpp index 0f23f0b4e..ee6a97111 100644 --- a/tests/auto/testplugin/testplugin.cpp +++ b/tests/auto/testplugin/testplugin.cpp @@ -48,6 +48,7 @@ void TestPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 1, 0, "TestObject"); qmlRegisterType(uri, 1, 0, "TestItemModel"); qmlRegisterType(uri, 1, 0, "TreeModel"); + qmlRegisterType(uri, 1, 0, "TestFetchAppendModel"); } void TestPlugin::initializeEngine(QQmlEngine *engine, const char * /*uri*/) -- cgit v1.2.3 From c0be938232f4f44e064546cbf365314c07f2c35a Mon Sep 17 00:00:00 2001 From: Frederik Schwarzer Date: Thu, 11 Aug 2016 17:58:35 +0200 Subject: Fix typo in documentation Change-Id: Ibd33614206e8d770bd7ee0888a8806662e3a1a73 Reviewed-by: J-P Nurmi --- src/controls/doc/src/qtquickcontrols-examples.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controls/doc/src/qtquickcontrols-examples.qdoc b/src/controls/doc/src/qtquickcontrols-examples.qdoc index 0e0e1ee24..fb674bc81 100644 --- a/src/controls/doc/src/qtquickcontrols-examples.qdoc +++ b/src/controls/doc/src/qtquickcontrols-examples.qdoc @@ -171,7 +171,7 @@ import org.qtproject.example 1.0 \endcode - For more information about registering C++ classses as QML types, see + For more information about registering C++ classes as QML types, see \l {Defining QML Types from C++}. \include examples-run.qdocinc @@ -212,7 +212,7 @@ import org.qtproject.example 1.0 \endcode - For more information about registering C++ classses as QML types, see + For more information about registering C++ classes as QML types, see \l {Defining QML Types from C++}. \include examples-run.qdocinc -- cgit v1.2.3 From 5bd57528b5cf7b22a81b1195d90b0a364c0428aa Mon Sep 17 00:00:00 2001 From: Frederik Schwarzer Date: Fri, 12 Aug 2016 12:07:51 +0200 Subject: Fix typo (word repetition) in documentation Change-Id: I6242fa1ab805d13753678feb5929da67ae0f4385 Reviewed-by: J-P Nurmi --- src/controls/doc/src/qtquickcontrols-tableview.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controls/doc/src/qtquickcontrols-tableview.qdoc b/src/controls/doc/src/qtquickcontrols-tableview.qdoc index e188ac9ed..92efcff77 100644 --- a/src/controls/doc/src/qtquickcontrols-tableview.qdoc +++ b/src/controls/doc/src/qtquickcontrols-tableview.qdoc @@ -243,7 +243,7 @@ \endcode \b Example: To iterate over selected indexes, you can pass a callback function. - \a rowIndex is passed as as an argument to the callback function. + \a rowIndex is passed as an argument to the callback function. \code tableview.selection.forEach( function(rowIndex) {console.log(rowIndex)} ) \endcode -- cgit v1.2.3 From f44ef9daf9f0f9db6775fdb6d3fc8703b6ce77e4 Mon Sep 17 00:00:00 2001 From: Filipe Azevedo Date: Mon, 1 Aug 2016 19:01:03 +0200 Subject: macOS: Fix native dangling menu still visible on screen and crash If the parent window gets destroyed while a QtQuick Controls menu is open the macOS native platform menu is not dismissed and you see a blank gray rectangle without any text. Also, at this point the QQmlEngine was already destroyed but it's still present on the call stack, so you get a crash when the stack unwinds to the original right mouse click that created the context menu. Change-Id: I638b0de13734815995d2994e6dd6603bcb0ebefc Reviewed-by: Gabriel de Dietrich --- src/controls/qquickmenu.cpp | 17 +++++++++++++++++ src/controls/qquickmenu_p.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/src/controls/qquickmenu.cpp b/src/controls/qquickmenu.cpp index b725bbbfc..3c243ba36 100644 --- a/src/controls/qquickmenu.cpp +++ b/src/controls/qquickmenu.cpp @@ -436,6 +436,10 @@ void QQuickMenu1::__popup(const QRectF &targetRect, int atItemIndex, MenuType me // parentWindow may not be a QQuickWindow (happens when using QQuickWidget) if (m_platformMenu) { + if (m_windowConnection) + QObject::disconnect(m_windowConnection); + m_windowConnection = connect(parentWindow, &QWindow::visibleChanged, this, + &QQuickMenu1::platformMenuWindowVisibleChanged, Qt::UniqueConnection); QRectF globalTargetRect = targetRect.translated(m_xOffset, m_yOffset); if (visualItem()) { if (qGuiApp->isRightToLeft()) { @@ -565,6 +569,19 @@ void QQuickMenu1::windowVisibleChanged(bool v) } } +void QQuickMenu1::platformMenuWindowVisibleChanged(bool visible) +{ + if (!visible) { + if (m_windowConnection) { + QObject::disconnect(m_windowConnection); + m_windowConnection = QMetaObject::Connection(); + } + if (m_platformMenu) { + m_platformMenu->dismiss(); + } + } +} + void QQuickMenu1::clearPopupWindow() { m_popupWindow = 0; diff --git a/src/controls/qquickmenu_p.h b/src/controls/qquickmenu_p.h index 576ae5fd5..8510efbef 100644 --- a/src/controls/qquickmenu_p.h +++ b/src/controls/qquickmenu_p.h @@ -165,6 +165,7 @@ protected Q_SLOTS: void updateText(); void windowVisibleChanged(bool); + void platformMenuWindowVisibleChanged(bool); private: QQuickWindow *findParentWindow(); @@ -205,6 +206,7 @@ private: QFont m_font; int m_triggerCount; bool m_proxy; + QMetaObject::Connection m_windowConnection; }; QT_END_NAMESPACE -- cgit v1.2.3 From 69b3136bae16897492d27558c5909cd61a5e598e Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Wed, 6 Apr 2016 13:50:08 +0300 Subject: Fix moving of TreeView items Property binding for row property in styleData causes an update which tries to read new value for the index property, but index is changed afterwards which causes old value to be read. This may lead to crashes and other unwanted behavior. Depth changes are now delivered to update item depths in visible items and model index changes though role instead of looking for a row change. Task-number: QTBUG-47523 Change-Id: I540cd06a25281f18e4628f4b030cf969dc8e0a7f Reviewed-by: Alex Blasche --- .../Private/TreeViewItemDelegateLoader.qml | 2 +- src/controls/Private/qquicktreemodeladaptor.cpp | 51 ++++++++++++++++++++-- src/controls/Private/qquicktreemodeladaptor_p.h | 5 ++- .../tst_qquicktreemodeladaptor.cpp | 51 ++++++++++++++++++++++ tests/auto/shared/testmodel.h | 2 +- 5 files changed, 103 insertions(+), 8 deletions(-) diff --git a/src/controls/Private/TreeViewItemDelegateLoader.qml b/src/controls/Private/TreeViewItemDelegateLoader.qml index 8b8801fc9..01492eda8 100644 --- a/src/controls/Private/TreeViewItemDelegateLoader.qml +++ b/src/controls/Private/TreeViewItemDelegateLoader.qml @@ -78,7 +78,7 @@ TableViewItemDelegateLoader { readonly property color textColor: __rowItem ? __rowItem.itemTextColor : "black" readonly property string role: __column ? __column.role : "" readonly property var value: model && model.hasOwnProperty(role) ? model[role] : "" - readonly property var index: __treeModel.mapRowToModelIndex(row) + readonly property var index: model ? model["_q_TreeView_ModelIndex"] : __treeModel.index(-1,-1,null) readonly property int depth: model && column === 0 ? model["_q_TreeView_ItemDepth"] : 0 readonly property bool hasChildren: model ? model["_q_TreeView_HasChildren"] : false readonly property bool hasSibling: model ? model["_q_TreeView_HasSibling"] : false diff --git a/src/controls/Private/qquicktreemodeladaptor.cpp b/src/controls/Private/qquicktreemodeladaptor.cpp index 666fafc9d..52b231d0a 100644 --- a/src/controls/Private/qquicktreemodeladaptor.cpp +++ b/src/controls/Private/qquicktreemodeladaptor.cpp @@ -153,6 +153,7 @@ QHash QQuickTreeModelAdaptor::roleNames() const modelRoleNames.insert(ExpandedRole, "_q_TreeView_ItemExpanded"); modelRoleNames.insert(HasChildrenRole, "_q_TreeView_HasChildren"); modelRoleNames.insert(HasSiblingRole, "_q_TreeView_HasSibling"); + modelRoleNames.insert(ModelIndexRole, "_q_TreeView_ModelIndex"); return modelRoleNames; } @@ -177,6 +178,8 @@ QVariant QQuickTreeModelAdaptor::data(const QModelIndex &index, int role) const return !(modelIndex.flags() & Qt::ItemNeverHasChildren) && m_model->hasChildren(modelIndex); case HasSiblingRole: return modelIndex.row() != m_model->rowCount(modelIndex.parent()) - 1; + case ModelIndexRole: + return modelIndex; default: return m_model->data(modelIndex, role); } @@ -192,6 +195,7 @@ bool QQuickTreeModelAdaptor::setData(const QModelIndex &index, const QVariant &v case ExpandedRole: case HasChildrenRole: case HasSiblingRole: + case ModelIndexRole: return false; default: { const QModelIndex &pmi = mapToModel(index); @@ -716,8 +720,11 @@ void QQuickTreeModelAdaptor::modelRowsAboutToBeMoved(const QModelIndex & sourceP destIndex = itemIndex(m_model->index(destinationRow, 0, destinationParent)); } - beginMoveRows(QModelIndex(), startIndex, endIndex, QModelIndex(), destIndex); int totalMovedCount = endIndex - startIndex + 1; + + const bool visibleRowsMoved = startIndex != destIndex && + beginMoveRows(QModelIndex(), startIndex, endIndex, QModelIndex(), destIndex); + const QList &buffer = m_items.mid(startIndex, totalMovedCount); int bufferCopyOffset; if (destIndex > endIndex) { @@ -726,6 +733,7 @@ void QQuickTreeModelAdaptor::modelRowsAboutToBeMoved(const QModelIndex & sourceP } bufferCopyOffset = destIndex - totalMovedCount; } else { + // NOTE: we will not enter this loop if startIndex == destIndex for (int i = startIndex - 1; i >= destIndex; i--) { m_items.swap(i, i + totalMovedCount); // Fast move from 1st to 2nd position } @@ -736,14 +744,49 @@ void QQuickTreeModelAdaptor::modelRowsAboutToBeMoved(const QModelIndex & sourceP item.depth += depthDifference; m_items.replace(bufferCopyOffset + i, item); } - endMoveRows(); + + if (visibleRowsMoved) + endMoveRows(); + + if (depthDifference != 0) { + const QModelIndex &topLeft = index(bufferCopyOffset, 0, QModelIndex()); + const QModelIndex &bottomRight = index(bufferCopyOffset + totalMovedCount - 1, 0, QModelIndex()); + const QVector changedRole(1, DepthRole); + emit dataChanged(topLeft, bottomRight, changedRole); + } } } void QQuickTreeModelAdaptor::modelRowsMoved(const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow) { - if (!childrenVisible(sourceParent) && childrenVisible(destinationParent)) - modelRowsInserted(destinationParent, destinationRow, destinationRow + sourceEnd - sourceStart); + if (childrenVisible(destinationParent)) { + if (!childrenVisible(sourceParent)) + modelRowsInserted(destinationParent, destinationRow, destinationRow + sourceEnd - sourceStart); + else { + int destIndex = -1; + if (destinationRow == m_model->rowCount(destinationParent)) { + const QModelIndex &emi = m_model->index(destinationRow - 1, 0, destinationParent); + destIndex = lastChildIndex(emi) + 1; + } else { + destIndex = itemIndex(m_model->index(destinationRow, 0, destinationParent)); + } + + const QModelIndex &emi = m_model->index(destinationRow + sourceEnd - sourceStart, 0, destinationParent); + int endIndex = -1; + if (isExpanded(emi)) { + int rowCount = m_model->rowCount(emi); + if (rowCount > 0) + endIndex = lastChildIndex(m_model->index(rowCount - 1, 0, emi)); + } + if (endIndex == -1) + endIndex = itemIndex(emi); + + const QModelIndex &topLeft = index(destIndex, 0, QModelIndex()); + const QModelIndex &bottomRight = index(endIndex, 0, QModelIndex()); + const QVector changedRole(1, ModelIndexRole); + emit dataChanged(topLeft, bottomRight, changedRole); + } + } ASSERT_CONSISTENCY(); } diff --git a/src/controls/Private/qquicktreemodeladaptor_p.h b/src/controls/Private/qquicktreemodeladaptor_p.h index 3eefbe776..56c6ea08f 100644 --- a/src/controls/Private/qquicktreemodeladaptor_p.h +++ b/src/controls/Private/qquicktreemodeladaptor_p.h @@ -74,10 +74,11 @@ public: void resetRootIndex(); enum { - DepthRole = Qt::UserRole - 4, + DepthRole = Qt::UserRole - 5, ExpandedRole, HasChildrenRole, - HasSiblingRole + HasSiblingRole, + ModelIndexRole }; QHash roleNames() const; diff --git a/tests/auto/qquicktreemodeladaptor/tst_qquicktreemodeladaptor.cpp b/tests/auto/qquicktreemodeladaptor/tst_qquicktreemodeladaptor.cpp index 13a92ea78..34c8f7cc2 100644 --- a/tests/auto/qquicktreemodeladaptor/tst_qquicktreemodeladaptor.cpp +++ b/tests/auto/qquicktreemodeladaptor/tst_qquicktreemodeladaptor.cpp @@ -81,6 +81,7 @@ private slots: void moveRows_data(); void moveRows(); + void reparentOnSameRow(); void selectionForRowRange(); @@ -1160,6 +1161,56 @@ void tst_QQuickTreeModelAdaptor::moveRows() compareModels(tma, model); } +void tst_QQuickTreeModelAdaptor::reparentOnSameRow() +{ + TestModel model(2, 1); + model.alternateChildlessRows = false; + QQuickTreeModelAdaptor tma; + tma.setModel(&model); + + const QModelIndex &destParent = model.index(0, 0); + const QModelIndex &sourceParent = QModelIndex(); + QVERIFY(destParent.isValid()); + tma.expand(destParent); + QVERIFY(tma.isExpanded(destParent)); + + QSignalSpy dataChangedSpy(&tma, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector))); + QSignalSpy rowsMovedSpy(&tma, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int))); + QVERIFY(rowsMovedSpy.isValid()); + QVERIFY(dataChangedSpy.isValid()); + + QVERIFY(model.moveRows(sourceParent, 1, 1, destParent, 2)); + + QModelIndex movedIndex = tma.index(3, 0, QModelIndex()); + QVERIFY(movedIndex.isValid()); + QCOMPARE(movedIndex.data(QQuickTreeModelAdaptor::DepthRole).toInt(), 1); + QCOMPARE(tma.data(movedIndex, QQuickTreeModelAdaptor::ModelIndexRole).toModelIndex(), model.index(2, 0, destParent)); + + // at least DepthRole and ModeIndexRole changes should have happened for the affected row + bool depthChanged = false; + bool modelIndexChanged = false; + QList > &changes = dataChangedSpy; + foreach (QList change, changes) { + if (change.at(0) == movedIndex) { + if (change.at(2).value >().contains(QQuickTreeModelAdaptor::DepthRole)) + depthChanged = true; + if (change.at(2).value >().contains(QQuickTreeModelAdaptor::ModelIndexRole)) + modelIndexChanged = true; + } + } + + QCOMPARE(depthChanged, true); + QCOMPARE(modelIndexChanged, true); + + QCOMPARE(rowsMovedSpy.count(), 0); + + model.moveRow(destParent, 2, QModelIndex(), 1); + + QCOMPARE(rowsMovedSpy.count(), 0); + QVERIFY(tma.testConsistency()); + compareModels(tma, model); +} + void tst_QQuickTreeModelAdaptor::selectionForRowRange() { const int ModelRowCount = 9; diff --git a/tests/auto/shared/testmodel.h b/tests/auto/shared/testmodel.h index 00e741292..d1f49a4d9 100644 --- a/tests/auto/shared/testmodel.h +++ b/tests/auto/shared/testmodel.h @@ -238,7 +238,7 @@ public: bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) { Q_ASSERT_X(sourceRow >= 0 && sourceRow < rowCount(sourceParent) - && count > 0 && sourceRow + count < rowCount(sourceParent) + && count > 0 && sourceRow + count - 1 < rowCount(sourceParent) && destinationChild >= 0 && destinationChild <= rowCount(destinationParent), Q_FUNC_INFO, "Rows out of range."); Q_ASSERT_X(!(sourceParent == destinationParent && destinationChild >= sourceRow && destinationChild < sourceRow + count), -- cgit v1.2.3