Skip to content

Commit 3021fc8

Browse files
committedJul 25, 2017
QgsLayoutUnitComboBox can be linked to spin boxes so that their
values are automatically updated when the combo box unit changes This means that you can flip between units and things like the existing width and height are converted immediately to the new unit
1 parent 3e92e16 commit 3021fc8

8 files changed

+163
-5
lines changed
 

‎python/gui/layout/qgslayoutnewitempropertiesdialog.sip

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ class QgsLayoutItemPropertiesDialog : QDialog
6969
.. seealso:: referencePoint()
7070
%End
7171

72+
void setLayout( QgsLayout *layout );
73+
%Docstring
74+
Sets the ``layout`` associated with the dialog. This allows the dialog
75+
to retrieve properties from the layout and perform tasks like automatic
76+
conversion of units.
77+
%End
78+
7279
};
7380

7481
/************************************************************************

‎python/gui/layout/qgslayoutunitscombobox.sip

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
************************************************************************/
88

99

10+
1011
class QgsLayoutUnitsComboBox : QComboBox
1112
{
1213
%Docstring
@@ -36,6 +37,33 @@ class QgsLayoutUnitsComboBox : QComboBox
3637
%Docstring
3738
Sets the ``unit`` currently selected in the combo box.
3839
.. seealso:: unit()
40+
%End
41+
42+
void linkToWidget( QDoubleSpinBox *widget );
43+
%Docstring
44+
Registers a spin box ``widget`` as linked with the combo box.
45+
46+
Registered spin boxes will automatically be upodated whenever the unit is changed. I.e. a
47+
spin box with a value of 100 will be set to 1 when the unit is changed from centimeters to meters.
48+
49+
A measurement converter() must be set in order for the automatic unit conversion to occur.
50+
51+
.. seealso:: setConverter()
52+
%End
53+
54+
QgsLayoutMeasurementConverter *converter() const;
55+
%Docstring
56+
Returns the converter used when automatically converting units for linked widgets.
57+
.. seealso:: setConverter()
58+
:rtype: QgsLayoutMeasurementConverter
59+
%End
60+
61+
void setConverter( QgsLayoutMeasurementConverter *converter );
62+
%Docstring
63+
Sets a ``converter`` to use when automatically converting units for linked widgets.
64+
The ownership of ``converter`` is not transferred, and converter must exist for the
65+
life of the combo box.
66+
.. seealso:: converter()
3967
%End
4068

4169
signals:

‎src/gui/layout/qgslayoutnewitempropertiesdialog.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
#include "qgslayoutnewitempropertiesdialog.h"
1717
#include "qgssettings.h"
18+
#include "qgslayout.h"
19+
1820

1921
QgsLayoutItemPropertiesDialog::QgsLayoutItemPropertiesDialog( QWidget *parent, Qt::WindowFlags flags )
2022
: QDialog( parent, flags )
@@ -39,6 +41,11 @@ QgsLayoutItemPropertiesDialog::QgsLayoutItemPropertiesDialog( QWidget *parent, Q
3941
double lastHeight = settings.value( QStringLiteral( "LayoutDesigner/lastItemHeight" ), QStringLiteral( "50" ) ).toDouble();
4042
QgsUnitTypes::LayoutUnit lastSizeUnit = static_cast< QgsUnitTypes::LayoutUnit >( settings.value( QStringLiteral( "LayoutDesigner/lastSizeUnit" ) ).toInt() );
4143
setItemSize( QgsLayoutSize( lastWidth, lastHeight, lastSizeUnit ) );
44+
45+
mPosUnitsComboBox->linkToWidget( mXPosSpin );
46+
mPosUnitsComboBox->linkToWidget( mYPosSpin );
47+
mSizeUnitsComboBox->linkToWidget( mWidthSpin );
48+
mSizeUnitsComboBox->linkToWidget( mHeightSpin );
4249
}
4350

4451
void QgsLayoutItemPropertiesDialog::setItemPosition( QgsLayoutPoint position )
@@ -147,3 +154,9 @@ void QgsLayoutItemPropertiesDialog::setReferencePoint( QgsLayoutItem::ReferenceP
147154
break;
148155
}
149156
}
157+
158+
void QgsLayoutItemPropertiesDialog::setLayout( QgsLayout *layout )
159+
{
160+
mSizeUnitsComboBox->setConverter( &layout->context().measurementConverter() );
161+
mPosUnitsComboBox->setConverter( &layout->context().measurementConverter() );
162+
}

‎src/gui/layout/qgslayoutnewitempropertiesdialog.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ class GUI_EXPORT QgsLayoutItemPropertiesDialog : public QDialog, private Ui::Qgs
8080
*/
8181
void setReferencePoint( QgsLayoutItem::ReferencePoint point );
8282

83+
/**
84+
* Sets the \a layout associated with the dialog. This allows the dialog
85+
* to retrieve properties from the layout and perform tasks like automatic
86+
* conversion of units.
87+
*/
88+
void setLayout( QgsLayout *layout );
89+
8390
};
8491

8592
#endif // QGSLAYOUTNEWITEMPROPERTIESDIALOG_H

‎src/gui/layout/qgslayoutunitscombobox.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
***************************************************************************/
1515

1616
#include "qgslayoutunitscombobox.h"
17+
#include "qgslayoutmeasurementconverter.h"
1718

1819
QgsLayoutUnitsComboBox::QgsLayoutUnitsComboBox( QWidget *parent )
1920
: QComboBox( parent )
@@ -34,10 +35,7 @@ QgsLayoutUnitsComboBox::QgsLayoutUnitsComboBox( QWidget *parent )
3435
setItemData( 6, tr( "Picas" ), Qt::ToolTipRole );
3536
addItem( tr( "px" ), QgsUnitTypes::LayoutPixels );
3637
setItemData( 7, tr( "Pixels" ), Qt::ToolTipRole );
37-
connect( this, static_cast<void ( QgsLayoutUnitsComboBox::* )( int )>( &QgsLayoutUnitsComboBox::currentIndexChanged ), this, [ = ]( int )
38-
{
39-
emit changed( unit() );
40-
} );
38+
connect( this, static_cast<void ( QgsLayoutUnitsComboBox::* )( int )>( &QgsLayoutUnitsComboBox::currentIndexChanged ), this, &QgsLayoutUnitsComboBox::indexChanged );
4139
}
4240

4341
QgsUnitTypes::LayoutUnit QgsLayoutUnitsComboBox::unit() const
@@ -50,4 +48,34 @@ void QgsLayoutUnitsComboBox::setUnit( QgsUnitTypes::LayoutUnit unit )
5048
setCurrentIndex( findData( unit ) );
5149
}
5250

51+
void QgsLayoutUnitsComboBox::linkToWidget( QDoubleSpinBox *widget )
52+
{
53+
mLinkedSpinBoxes << widget;
54+
}
55+
56+
void QgsLayoutUnitsComboBox::indexChanged( int )
57+
{
58+
QgsUnitTypes::LayoutUnit newUnit = unit();
59+
if ( mConverter )
60+
{
61+
Q_FOREACH ( const QPointer< QDoubleSpinBox > &widget, mLinkedSpinBoxes )
62+
{
63+
if ( widget )
64+
widget->setValue( mConverter->convert( QgsLayoutMeasurement( widget->value(), mOldUnit ), newUnit ).length() );
65+
}
66+
}
67+
emit changed( newUnit );
68+
mOldUnit = newUnit;
69+
}
70+
71+
QgsLayoutMeasurementConverter *QgsLayoutUnitsComboBox::converter() const
72+
{
73+
return mConverter;
74+
}
75+
76+
void QgsLayoutUnitsComboBox::setConverter( QgsLayoutMeasurementConverter *converter )
77+
{
78+
mConverter = converter;
79+
}
80+
5381
#include "qgslayoutunitscombobox.h"

‎src/gui/layout/qgslayoutunitscombobox.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#include "qgis_gui.h"
2020
#include "qgis_sip.h"
2121
#include "qgsunittypes.h"
22+
#include <QDoubleSpinBox>
23+
#include <QPointer>
24+
25+
class QgsLayoutMeasurementConverter;
2226

2327
/**
2428
* \ingroup gui
@@ -50,13 +54,50 @@ class GUI_EXPORT QgsLayoutUnitsComboBox : public QComboBox
5054
*/
5155
void setUnit( QgsUnitTypes::LayoutUnit unit );
5256

57+
/**
58+
* Registers a spin box \a widget as linked with the combo box.
59+
*
60+
* Registered spin boxes will automatically be upodated whenever the unit is changed. I.e. a
61+
* spin box with a value of 100 will be set to 1 when the unit is changed from centimeters to meters.
62+
*
63+
* A measurement converter() must be set in order for the automatic unit conversion to occur.
64+
*
65+
* \see setConverter()
66+
*/
67+
void linkToWidget( QDoubleSpinBox *widget );
68+
69+
/**
70+
* Returns the converter used when automatically converting units for linked widgets.
71+
* \see setConverter()
72+
*/
73+
QgsLayoutMeasurementConverter *converter() const;
74+
75+
/**
76+
* Sets a \a converter to use when automatically converting units for linked widgets.
77+
* The ownership of \a converter is not transferred, and converter must exist for the
78+
* life of the combo box.
79+
* \see converter()
80+
*/
81+
void setConverter( QgsLayoutMeasurementConverter *converter );
82+
5383
signals:
5484

5585
/**
5686
* Emitted when the \a unit is changed.
5787
*/
5888
void changed( QgsUnitTypes::LayoutUnit unit );
5989

90+
private slots:
91+
92+
void indexChanged( int index );
93+
94+
private:
95+
96+
QgsLayoutMeasurementConverter *mConverter = nullptr;
97+
98+
QgsUnitTypes::LayoutUnit mOldUnit = QgsUnitTypes::LayoutMillimeters;
99+
100+
QList< QPointer< QDoubleSpinBox > > mLinkedSpinBoxes;
60101
};
61102

62103
#endif // QGSLAYOUTUNITSCOMBOBOX_H

‎src/gui/layout/qgslayoutviewtooladditem.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *even
9090
if ( clickOnly )
9191
{
9292
QgsLayoutItemPropertiesDialog dlg( view() );
93+
dlg.setLayout( layout() );
9394
dlg.setItemPosition( QgsLayoutPoint( event->layoutPoint(), layout()->units() ) );
9495
if ( dlg.exec() )
9596
{

‎tests/src/python/test_qgslayoutunitscombobox.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414

1515
import qgis # NOQA
1616

17-
from qgis.core import QgsUnitTypes
17+
from qgis.core import QgsUnitTypes, QgsLayoutMeasurementConverter
1818
from qgis.gui import QgsLayoutUnitsComboBox
1919

20+
from qgis.PyQt.QtWidgets import QDoubleSpinBox
21+
2022
from qgis.PyQt.QtTest import QSignalSpy
2123
from qgis.testing import start_app, unittest
2224

@@ -42,6 +44,37 @@ def test_ChangedSignals(self):
4244
self.assertEqual(len(spy), 1)
4345
self.assertEqual(spy[0][0], QgsUnitTypes.LayoutPixels)
4446

47+
def testLinkedWidgets(self):
48+
""" test linking spin boxes to combobox"""
49+
w = qgis.gui.QgsLayoutUnitsComboBox()
50+
self.assertFalse(w.converter())
51+
c = QgsLayoutMeasurementConverter()
52+
w.setConverter(c)
53+
self.assertEqual(w.converter(), c)
54+
55+
spin = QDoubleSpinBox()
56+
spin.setMaximum(1000000)
57+
spin.setValue(100)
58+
w.setUnit(QgsUnitTypes.LayoutCentimeters)
59+
w.linkToWidget(spin)
60+
w.setUnit(QgsUnitTypes.LayoutMeters)
61+
self.assertAlmostEqual(spin.value(), 1.0, 2)
62+
w.setUnit(QgsUnitTypes.LayoutMillimeters)
63+
self.assertAlmostEqual(spin.value(), 1000.0, 2)
64+
65+
spin2 = QDoubleSpinBox()
66+
spin2.setValue(50)
67+
spin2.setMaximum(1000000)
68+
w.linkToWidget(spin2)
69+
w.setUnit(QgsUnitTypes.LayoutCentimeters)
70+
self.assertAlmostEqual(spin.value(), 100.0, 2)
71+
self.assertAlmostEqual(spin2.value(), 5.0, 2)
72+
73+
# no crash!
74+
del spin
75+
w.setUnit(QgsUnitTypes.LayoutMeters)
76+
self.assertAlmostEqual(spin2.value(), 0.05, 2)
77+
4578

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

0 commit comments

Comments
 (0)
Please sign in to comment.