Skip to content

Commit 8bd4238

Browse files
authored
Merge pull request #4640 from nyalldawson/fix_drag_crash
Fix crash when reordering composer items via drag and drop
2 parents 3a16a4e + cb33c0d commit 8bd4238

5 files changed

Lines changed: 149 additions & 0 deletions

File tree

‎src/core/composer/qgscomposermodel.cpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,10 +958,15 @@ QgsComposerProxyModel::QgsComposerProxyModel( QgsComposition *composition, QObje
958958
if ( mComposition )
959959
setSourceModel( mComposition->itemsModel() );
960960

961+
// WARNING: the below code triggers a Qt bug (tested on Qt 4.8, can't reproduce on Qt5) whenever the QgsComposerModel source model
962+
// calls beginInsertRows - since it's non functional anyway it's now disabled
963+
// PLEASE verify that the Qt issue is fixed before reenabling
964+
#if 0
961965
// TODO doesn't seem to work correctly - not updated when item changes
962966
setDynamicSortFilter( true );
963967
setSortLocaleAware( true );
964968
sort( QgsComposerModel::ItemId );
969+
#endif
965970
}
966971

967972
bool QgsComposerProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const

‎src/core/composer/qgscomposermodel.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ class CORE_EXPORT QgsComposerModel: public QAbstractItemModel
289289
void rebuildSceneItemList();
290290

291291
friend class TestQgsComposerModel;
292+
friend class TestQgsComposerGui;
292293
};
293294

294295

‎tests/src/core/testqgscomposermodel.cpp‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ class TestQgsComposerModel : public QObject
6262
void reorderToTopWithRemoved(); //test reordering to top with removed items
6363
void reorderToBottomWithRemoved(); //test reordering to bottom with removed items
6464

65+
void proxyCrash();
66+
6567
private:
6668
QgsComposition *mComposition;
6769
QgsMapSettings *mMapSettings;
@@ -610,5 +612,27 @@ void TestQgsComposerModel::reorderToBottomWithRemoved()
610612
QCOMPARE( mComposition->itemsModel()->mItemsInScene.at( 1 ), mItem2 );
611613
}
612614

615+
void TestQgsComposerModel::proxyCrash()
616+
{
617+
// test for a possible crash when using QgsComposerProxyModel and reordering items
618+
QgsMapSettings ms;
619+
QgsComposition* composition = new QgsComposition( ms );
620+
621+
// create a proxy - it's not used, but will be watching...
622+
QgsComposerProxyModel* proxy = new QgsComposerProxyModel( composition );
623+
Q_UNUSED( proxy );
624+
625+
// add some items to composition
626+
QgsComposerLabel* item1 = new QgsComposerLabel( composition );
627+
composition->addItem( item1 );
628+
QgsComposerLabel* item2 = new QgsComposerLabel( composition );
629+
composition->addItem( item2 );
630+
QgsComposerLabel* item3 = new QgsComposerLabel( composition );
631+
composition->addItem( item3 );
632+
633+
// reorder items - expect no crash!
634+
composition->itemsModel()->reorderItemUp( item1 );
635+
}
636+
613637
QTEST_MAIN( TestQgsComposerModel )
614638
#include "testqgscomposermodel.moc"

‎tests/src/gui/CMakeLists.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
1616
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/raster
1717
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core
1818
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/auth
19+
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/composer
1920
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/geometry
2021
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/raster
2122
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/symbology-ng
@@ -142,4 +143,5 @@ ADD_QGIS_TEST(scalerangewidget testqgsscalerangewidget.cpp)
142143
ADD_QGIS_TEST(spinbox testqgsspinbox.cpp)
143144
ADD_QGIS_TEST(sqlcomposerdialog testqgssqlcomposerdialog.cpp)
144145
ADD_QGIS_TEST(filedownloader testqgsfiledownloader.cpp)
146+
ADD_QGIS_TEST(composergui testqgscomposergui.cpp)
145147

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/***************************************************************************
2+
testqgscomposergui.cpp
3+
----------------------
4+
Date : May 2017
5+
Copyright : (C) 2017 Nyall Dawson
6+
Email : nyall dot dawson at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
17+
18+
19+
#include <QtTest/QtTest>
20+
21+
#include "qgsmapsettings.h"
22+
#include "qgscomposition.h"
23+
#include "qgscomposerlabel.h"
24+
#include "qgscomposermap.h"
25+
#include "qgscomposermodel.h"
26+
#include "qgscomposeritemcombobox.h"
27+
28+
#include <QApplication>
29+
#include <QMainWindow>
30+
31+
class TestQgsComposerGui: public QObject
32+
{
33+
Q_OBJECT
34+
private slots:
35+
void initTestCase(); // will be called before the first testfunction is executed.
36+
void cleanupTestCase(); // will be called after the last testfunction was executed.
37+
void init(); // will be called before each testfunction is executed.
38+
void cleanup(); // will be called after every testfunction.
39+
40+
void testProxyCrash();
41+
42+
private:
43+
44+
};
45+
46+
void TestQgsComposerGui::initTestCase()
47+
{
48+
}
49+
50+
void TestQgsComposerGui::cleanupTestCase()
51+
{
52+
}
53+
54+
void TestQgsComposerGui::init()
55+
{
56+
}
57+
58+
void TestQgsComposerGui::cleanup()
59+
{
60+
}
61+
62+
void TestQgsComposerGui::testProxyCrash()
63+
{
64+
// test for a possible crash when using QgsComposerProxyModel and reordering items
65+
QgsMapSettings ms;
66+
QgsComposition* composition = new QgsComposition( ms );
67+
68+
// create a composer item combobox
69+
QgsComposerItemComboBox* cb = new QgsComposerItemComboBox( nullptr, composition );
70+
QgsComposerItemComboBox* cb2 = new QgsComposerItemComboBox( nullptr, composition );
71+
QgsComposerItemComboBox* cb3 = new QgsComposerItemComboBox( nullptr, composition );
72+
QgsComposerItemComboBox* cb4 = new QgsComposerItemComboBox( nullptr, composition );
73+
74+
cb->show();
75+
cb2->show();
76+
77+
// add some items to composition
78+
QgsComposerMap* item1 = new QgsComposerMap( composition );
79+
composition->addItem( item1 );
80+
QgsComposerLabel* item2 = new QgsComposerLabel( composition );
81+
composition->addItem( item2 );
82+
QgsComposerMap* item3 = new QgsComposerMap( composition );
83+
composition->addItem( item3 );
84+
85+
QCOMPARE( cb->count(), 3 );
86+
cb->setItemType( QgsComposerItem::ComposerMap );
87+
QCOMPARE( cb->count(), 2 );
88+
89+
cb4->setItemType( QgsComposerItem::ComposerLabel );
90+
91+
cb->setItem( item1 );
92+
QCOMPARE( cb->currentItem(), item1 );
93+
cb2->setItem( item3 );
94+
QCOMPARE( cb2->currentItem(), item3 );
95+
cb3->setItem( item2 );
96+
QCOMPARE( cb3->currentItem(), item2 );
97+
98+
// reorder items - expect no crash!
99+
// we do this by calling the private members, in order to simulate what
100+
// happens when a drag and drop reorder occurs
101+
composition->itemsModel()->mItemZList.removeOne( item1 );
102+
composition->itemsModel()->mItemZList.insert( 1, item1 );
103+
composition->itemsModel()->rebuildSceneItemList();
104+
105+
QCOMPARE( cb->currentItem(), item1 );
106+
QCOMPARE( cb2->currentItem(), item3 );
107+
108+
composition->itemsModel()->mItemZList.removeOne( item1 );
109+
composition->itemsModel()->mItemZList.insert( 0, item1 );
110+
composition->itemsModel()->rebuildSceneItemList();
111+
112+
delete composition;
113+
}
114+
115+
116+
QTEST_MAIN( TestQgsComposerGui )
117+
#include "testqgscomposergui.moc"

0 commit comments

Comments
 (0)