Skip to content

Commit

Permalink
Fix crash when deleting multiframe item child frames
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jan 7, 2018
1 parent 3f414e2 commit 1b96926
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 19 deletions.
3 changes: 3 additions & 0 deletions python/core/layout/qgslayoutframe.sip
Expand Up @@ -43,6 +43,9 @@ Creates a new QgsLayoutFrame belonging to the specified ``layout``.
virtual QString displayName() const; virtual QString displayName() const;




virtual void cleanup();


void setContentSection( const QRectF &section ); void setContentSection( const QRectF &section );
%Docstring %Docstring
Sets the visible part of the multiframe's content which is visible within Sets the visible part of the multiframe's content which is visible within
Expand Down
14 changes: 0 additions & 14 deletions python/core/layout/qgslayoutmultiframe.sip
Expand Up @@ -383,20 +383,6 @@ in finalizeRestoreFromXml(), not readPropertiesFromElement().






protected slots:

void handlePageChange();
%Docstring
Adapts to changed number of layout pages if resize type is RepeatOnEveryPage.
%End

void handleFrameRemoval();
%Docstring
Called when a frame is removed. Updates frame list and recalculates
content of remaining frames.
%End


}; };




Expand Down
8 changes: 8 additions & 0 deletions src/core/layout/qgslayoutframe.cpp
Expand Up @@ -192,6 +192,14 @@ QString QgsLayoutFrame::displayName() const
return tr( "<Frame>" ); return tr( "<Frame>" );
} }


void QgsLayoutFrame::cleanup()
{
if ( mMultiFrame )
mMultiFrame->handleFrameRemoval( this );

QgsLayoutItem::cleanup();
}

void QgsLayoutFrame::draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle ) void QgsLayoutFrame::draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle )
{ {
if ( mMultiFrame ) if ( mMultiFrame )
Expand Down
2 changes: 2 additions & 0 deletions src/core/layout/qgslayoutframe.h
Expand Up @@ -52,6 +52,8 @@ class CORE_EXPORT QgsLayoutFrame: public QgsLayoutItem
//Overridden to allow multiframe to set display name //Overridden to allow multiframe to set display name
QString displayName() const override; QString displayName() const override;


void cleanup() override;

/** /**
* Sets the visible part of the multiframe's content which is visible within * Sets the visible part of the multiframe's content which is visible within
* this frame (relative to the total multiframe extent in layout units). * this frame (relative to the total multiframe extent in layout units).
Expand Down
8 changes: 5 additions & 3 deletions src/core/layout/qgslayoutmultiframe.cpp
Expand Up @@ -60,7 +60,10 @@ void QgsLayoutMultiFrame::addFrame( QgsLayoutFrame *frame, bool recalcFrameSizes
mFrameItems.push_back( frame ); mFrameItems.push_back( frame );
frame->mMultiFrame = this; frame->mMultiFrame = this;
connect( frame, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutMultiFrame::recalculateFrameSizes ); connect( frame, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutMultiFrame::recalculateFrameSizes );
connect( frame, &QgsLayoutFrame::destroyed, this, &QgsLayoutMultiFrame::handleFrameRemoval ); connect( frame, &QgsLayoutFrame::destroyed, this, [this, frame ]
{
handleFrameRemoval( frame );
} );
if ( mLayout ) if ( mLayout )
{ {
mLayout->addLayoutItem( frame ); mLayout->addLayoutItem( frame );
Expand Down Expand Up @@ -306,12 +309,11 @@ void QgsLayoutMultiFrame::refresh()
refreshDataDefinedProperty(); refreshDataDefinedProperty();
} }


void QgsLayoutMultiFrame::handleFrameRemoval() void QgsLayoutMultiFrame::handleFrameRemoval( QgsLayoutFrame *frame )
{ {
if ( mBlockUpdates ) if ( mBlockUpdates )
return; return;


QgsLayoutFrame *frame = qobject_cast<QgsLayoutFrame *>( sender() );
if ( !frame ) if ( !frame )
{ {
return; return;
Expand Down
5 changes: 3 additions & 2 deletions src/core/layout/qgslayoutmultiframe.h
Expand Up @@ -370,7 +370,7 @@ class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject, public QgsLayoutU


ResizeMode mResizeMode = UseExistingFrames; ResizeMode mResizeMode = UseExistingFrames;


protected slots: private slots:


/** /**
* Adapts to changed number of layout pages if resize type is RepeatOnEveryPage. * Adapts to changed number of layout pages if resize type is RepeatOnEveryPage.
Expand All @@ -381,7 +381,7 @@ class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject, public QgsLayoutU
* Called when a frame is removed. Updates frame list and recalculates * Called when a frame is removed. Updates frame list and recalculates
* content of remaining frames. * content of remaining frames.
*/ */
void handleFrameRemoval(); void handleFrameRemoval( QgsLayoutFrame *frame );




private: private:
Expand All @@ -394,6 +394,7 @@ class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject, public QgsLayoutU


//! Unique id //! Unique id
QString mUuid; QString mUuid;
friend class QgsLayoutFrame;
}; };




Expand Down
24 changes: 24 additions & 0 deletions tests/src/core/testqgslayoutmultiframe.cpp
Expand Up @@ -47,6 +47,7 @@ class TestQgsLayoutMultiFrame : public QObject
void undoRedoRemovedFrame(); //test that undo doesn't crash with removed frames void undoRedoRemovedFrame(); //test that undo doesn't crash with removed frames
void undoRedoRemovedFrame2(); void undoRedoRemovedFrame2();
void registry(); void registry();
void deleteFrame();


private: private:
QgsLayout *mLayout = nullptr; QgsLayout *mLayout = nullptr;
Expand Down Expand Up @@ -556,5 +557,28 @@ void TestQgsLayoutMultiFrame::registry()
QVERIFY( props.isEmpty() ); QVERIFY( props.isEmpty() );
} }


void TestQgsLayoutMultiFrame::deleteFrame()
{
QgsLayout l( QgsProject::instance() );
l.initializeDefaults();

QgsLayoutItemHtml *htmlItem = new QgsLayoutItemHtml( &l );
QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, htmlItem );
frame1->attemptSetSceneRect( QRectF( 0, 0, 100, 200 ) );
htmlItem->addFrame( frame1 );
QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, htmlItem );
frame2->attemptSetSceneRect( QRectF( 0, 0, 100, 200 ) );
htmlItem->addFrame( frame2 );

QCOMPARE( htmlItem->frameCount(), 2 );
QCOMPARE( htmlItem->frames(), QList< QgsLayoutFrame * >() << frame1 << frame2 );
l.removeLayoutItem( frame1 );
QCOMPARE( htmlItem->frameCount(), 1 );
QCOMPARE( htmlItem->frames(), QList< QgsLayoutFrame * >() << frame2 );
l.removeLayoutItem( frame2 );
QCOMPARE( htmlItem->frameCount(), 0 );
QVERIFY( htmlItem->frames().empty() );
}

QGSTEST_MAIN( TestQgsLayoutMultiFrame ) QGSTEST_MAIN( TestQgsLayoutMultiFrame )
#include "testqgslayoutmultiframe.moc" #include "testqgslayoutmultiframe.moc"

0 comments on commit 1b96926

Please sign in to comment.