Skip to content

Commit

Permalink
[FEATURE] Add a button in guide manager to apply current page's guides
Browse files Browse the repository at this point in the history
to all other pages

This allows resetting all other pages to use the guide configuration
for the current page. Since guides are now single page only (required
to handle mixed page size/orientation layouts), this is a shortcut
to allow guide configuration to be setup on a single page and then
easily transferred to all other pages in the layout.
  • Loading branch information
nyalldawson committed Aug 7, 2017
1 parent c43a173 commit 98ff702
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 2 deletions.
5 changes: 5 additions & 0 deletions python/core/layout/qgslayoutguidecollection.sip
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ class QgsLayoutGuideCollection : QAbstractTableModel
.. seealso:: removeGuide()
%End

void applyGuidesToAllOtherPages( int sourcePage );
%Docstring
Resets all other pages' guides to match the guides from the specified ``sourcePage``.
%End

void update();
%Docstring
Updates the position (and visibility) of all guide line items.
Expand Down
6 changes: 6 additions & 0 deletions src/app/layout/qgslayoutguidewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ QgsLayoutGuideWidget::QgsLayoutGuideWidget( QWidget *parent, QgsLayout *layout,
connect( mDeleteVertGuideButton, &QPushButton::clicked, this, &QgsLayoutGuideWidget::deleteVerticalGuide );

connect( mClearAllButton, &QPushButton::clicked, this, &QgsLayoutGuideWidget::clearAll );
connect( mApplyToAllButton, &QPushButton::clicked, this, &QgsLayoutGuideWidget::applyToAll );

connect( layoutView, &QgsLayoutView::pageChanged, this, &QgsLayoutGuideWidget::pageChanged );
pageChanged( 0 );
Expand Down Expand Up @@ -128,6 +129,11 @@ void QgsLayoutGuideWidget::clearAll()
mHozProxyModel->removeRows( 0, mHozProxyModel->rowCount() );
}

void QgsLayoutGuideWidget::applyToAll()
{
mLayout->guides().applyGuidesToAllOtherPages( mPage );
}


QgsLayoutGuidePositionDelegate::QgsLayoutGuidePositionDelegate( QgsLayout *layout, QAbstractItemModel *model )
: mLayout( layout )
Expand Down
2 changes: 2 additions & 0 deletions src/app/layout/qgslayoutguidewidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class QgsLayoutGuideWidget: public QgsPanelWidget, private Ui::QgsLayoutGuideWid

void clearAll();

void applyToAll();

private:

QgsLayout *mLayout = nullptr;
Expand Down
29 changes: 29 additions & 0 deletions src/core/layout/qgslayoutguidecollection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,35 @@ void QgsLayoutGuideCollection::clear()
endResetModel();
}

void QgsLayoutGuideCollection::applyGuidesToAllOtherPages( int sourcePage )
{
// remove other page's guides
Q_FOREACH ( QgsLayoutGuide *guide, mGuides )
{
if ( guide->page() != sourcePage )
removeGuide( guide );
}

// remaining guides belong to source page - clone them to other pages
Q_FOREACH ( QgsLayoutGuide *guide, mGuides )
{
for ( int p = 0; p < mLayout->pageCollection()->pageCount(); ++p )
{
if ( p == sourcePage )
continue;

std::unique_ptr< QgsLayoutGuide> newGuide( new QgsLayoutGuide( guide->orientation(), guide->position() ) );
newGuide->setPage( p );
newGuide->setLayout( mLayout );
if ( newGuide->item()->isVisible() )
{
// if invisible, new guide is outside of page bounds
addGuide( newGuide.release() );
}
}
}
}

void QgsLayoutGuideCollection::update()
{
Q_FOREACH ( QgsLayoutGuide *guide, mGuides )
Expand Down
5 changes: 5 additions & 0 deletions src/core/layout/qgslayoutguidecollection.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ class CORE_EXPORT QgsLayoutGuideCollection : public QAbstractTableModel
*/
void clear();

/**
* Resets all other pages' guides to match the guides from the specified \a sourcePage.
*/
void applyGuidesToAllOtherPages( int sourcePage );

/**
* Updates the position (and visibility) of all guide line items.
*/
Expand Down
17 changes: 15 additions & 2 deletions src/ui/layout/qgslayoutguidewidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>231</width>
<height>518</height>
<width>217</width>
<height>526</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
Expand Down Expand Up @@ -192,8 +192,21 @@
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="mApplyToAllButton">
<property name="toolTip">
<string>Resets all other pages' guides to match this page</string>
</property>
<property name="text">
<string>Apply to All Pages</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mClearAllButton">
<property name="toolTip">
<string>Removes all guides from the current page</string>
</property>
<property name="text">
<string>Clear All Guides</string>
</property>
Expand Down
44 changes: 44 additions & 0 deletions tests/src/python/test_qgslayoutguides.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

from qgis.testing import start_app, unittest

import sip

start_app()


Expand Down Expand Up @@ -249,6 +251,48 @@ def testClear(self):
guides.clear()
self.assertEqual(guides.guides(QgsLayoutGuide.Horizontal), [])

def testApplyToOtherPages(self):
p = QgsProject()
l = QgsLayout(p)
l.initializeDefaults()
page2 = QgsLayoutItemPage(l)
page2.setPageSize('A6')
l.pageCollection().addPage(page2)
guides = l.guides()

# add some guides
g1 = QgsLayoutGuide(QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(5))
guides.addGuide(g1)
g2 = QgsLayoutGuide(QgsLayoutGuide.Vertical, QgsLayoutMeasurement(6))
guides.addGuide(g2)
g3 = QgsLayoutGuide(QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(190))
guides.addGuide(g3)
g4 = QgsLayoutGuide(QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(1))
g4.setPage(1)
guides.addGuide(g4)

# apply guides from page 0 - should delete g4
guides.applyGuidesToAllOtherPages(0)
self.assertEqual(guides.guides(QgsLayoutGuide.Horizontal, 0), [g1, g3])
self.assertEqual(guides.guides(QgsLayoutGuide.Vertical, 0), [g2])
self.assertTrue(sip.isdeleted(g4))

# g3 is outside of page 2 bounds - should not be copied
self.assertEqual(len(guides.guides(QgsLayoutGuide.Horizontal, 1)), 1)
self.assertEqual(guides.guides(QgsLayoutGuide.Horizontal, 1)[0].position().length(), 5)
self.assertEqual(len(guides.guides(QgsLayoutGuide.Vertical, 1)), 1)
self.assertEqual(guides.guides(QgsLayoutGuide.Vertical, 1)[0].position().length(), 6)

# apply guides from page 1 to 0
guides.applyGuidesToAllOtherPages(1)
self.assertTrue(sip.isdeleted(g1))
self.assertTrue(sip.isdeleted(g2))
self.assertTrue(sip.isdeleted(g3))
self.assertEqual(len(guides.guides(QgsLayoutGuide.Horizontal, 0)), 1)
self.assertEqual(guides.guides(QgsLayoutGuide.Horizontal, 0)[0].position().length(), 5)
self.assertEqual(len(guides.guides(QgsLayoutGuide.Vertical, 0)), 1)
self.assertEqual(guides.guides(QgsLayoutGuide.Vertical, 0)[0].position().length(), 6)


if __name__ == '__main__':
unittest.main()

0 comments on commit 98ff702

Please sign in to comment.