Skip to content

Commit 84dd983

Browse files
committed
Restore legend preview in symbol size assistant
1 parent 90dd988 commit 84dd983

11 files changed

+218
-80
lines changed

src/gui/qgspropertyassistantwidget.cpp

+102-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "qgsproject.h"
2121
#include "qgsmapsettings.h"
2222
#include "qgsvectorlayer.h"
23+
#include "qgslayertreelayer.h"
24+
#include "qgssymbollayerutils.h"
2325

2426
QgsPropertyAssistantWidget::QgsPropertyAssistantWidget( QWidget* parent ,
2527
const QgsPropertyDefinition& definition, const QgsProperty& initialState,
@@ -53,6 +55,16 @@ QgsPropertyAssistantWidget::QgsPropertyAssistantWidget( QWidget* parent ,
5355

5456
connect( computeValuesButton, &QPushButton::clicked, this, &QgsPropertyAssistantWidget::computeValuesFromLayer );
5557

58+
if ( mLayer )
59+
{
60+
mLayerTreeLayer = new QgsLayerTreeLayer( const_cast< QgsVectorLayer* >( mLayer ) );
61+
mRoot.addChildNode( mLayerTreeLayer ); // takes ownership
62+
}
63+
mLegendPreview->setModel( &mPreviewList );
64+
mLegendPreview->setItemDelegate( new ItemDelegate( &mPreviewList ) );
65+
mLegendPreview->setHeaderHidden( true );
66+
mLegendPreview->expandAll();
67+
5668
switch ( definition.standardTemplate() )
5769
{
5870
case QgsPropertyDefinition::Size:
@@ -72,6 +84,8 @@ QgsPropertyAssistantWidget::QgsPropertyAssistantWidget( QWidget* parent ,
7284
connect( minValueSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertyAssistantWidget::widgetChanged );
7385
connect( maxValueSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertyAssistantWidget::widgetChanged );
7486
connect( mExpressionWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString& ) > ( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsPropertyAssistantWidget::widgetChanged );
87+
connect( this, &QgsPropertyAssistantWidget::widgetChanged, this, &QgsPropertyAssistantWidget::updatePreview );
88+
updatePreview();
7589
}
7690

7791
void QgsPropertyAssistantWidget::registerExpressionContextGenerator( QgsExpressionContextGenerator* generator )
@@ -116,6 +130,55 @@ void QgsPropertyAssistantWidget::computeValuesFromLayer()
116130
emit widgetChanged();
117131
}
118132

133+
void QgsPropertyAssistantWidget::updatePreview()
134+
{
135+
if ( !mTransformerWidget || !mSymbol )
136+
return;
137+
138+
if ( dockMode() )
139+
return;
140+
141+
mLegendPreview->setIconSize( QSize( 512, 512 ) );
142+
mPreviewList.clear();
143+
144+
QList<double> breaks = QgsSymbolLayerUtils::prettyBreaks( minValueSpinBox->value(),
145+
maxValueSpinBox->value(), 4 );
146+
147+
QList< QgsSymbolLegendNode* > nodes = mTransformerWidget->generatePreviews( breaks, mLayerTreeLayer, mLayer, mSymbol.get(), minValueSpinBox->value(),
148+
maxValueSpinBox->value() );
149+
if ( nodes.isEmpty() )
150+
{
151+
mLegendPreview->show();
152+
return;
153+
}
154+
155+
int widthMax = 0;
156+
int i = 0;
157+
Q_FOREACH ( QgsSymbolLegendNode* node, nodes )
158+
{
159+
const QSize minSize( node->minimumIconSize() );
160+
node->setIconSize( minSize );
161+
widthMax = qMax( minSize.width(), widthMax );
162+
mPreviewList.appendRow( new QStandardItem( node->data( Qt::DecorationRole ).value<QPixmap>(), QString::number( breaks[i] ) ) );
163+
delete node;
164+
i++;
165+
}
166+
// center icon and align text left by giving icons the same width
167+
// @todo maybe add some space so that icons don't touch
168+
for ( int i = 0; i < breaks.length(); i++ )
169+
{
170+
QPixmap img( mPreviewList.item( i )->icon().pixmap( mPreviewList.item( i )->icon().actualSize( QSize( 512, 512 ) ) ) );
171+
QPixmap enlarged( widthMax, img.height() );
172+
// fill transparent and add original image
173+
enlarged.fill( Qt::transparent );
174+
QPainter p( &enlarged );
175+
p.drawPixmap( QPoint(( widthMax - img.width() ) / 2, 0 ), img );
176+
p.end();
177+
mPreviewList.item( i )->setIcon( enlarged );
178+
}
179+
mLegendPreview->show();
180+
}
181+
119182
bool QgsPropertyAssistantWidget::computeValuesFromExpression( const QString& expression, double& minValue, double& maxValue ) const
120183
{
121184
QgsExpression e( expression );
@@ -236,7 +299,7 @@ QgsPropertySizeAssistantWidget::QgsPropertySizeAssistantWidget( QWidget* parent,
236299
);
237300
}
238301

239-
QgsPropertyTransformer* QgsPropertySizeAssistantWidget::createTransformer( double minValue, double maxValue ) const
302+
QgsSizeScaleTransformer* QgsPropertySizeAssistantWidget::createTransformer( double minValue, double maxValue ) const
240303
{
241304
QgsSizeScaleTransformer* transformer = new QgsSizeScaleTransformer(
242305
static_cast< QgsSizeScaleTransformer::ScaleType >( scaleMethodComboBox->currentData().toInt() ),
@@ -248,3 +311,41 @@ QgsPropertyTransformer* QgsPropertySizeAssistantWidget::createTransformer( doubl
248311
exponentSpinBox->value() );
249312
return transformer;
250313
}
314+
315+
QList< QgsSymbolLegendNode* > QgsPropertySizeAssistantWidget::generatePreviews( const QList<double>& breaks, QgsLayerTreeLayer* parent, const QgsVectorLayer* layer, const QgsSymbol* symbol, double minValue, double maxValue ) const
316+
{
317+
QList< QgsSymbolLegendNode* > nodes;
318+
319+
if ( !symbol || !layer )
320+
return nodes;
321+
322+
std::unique_ptr< QgsSizeScaleTransformer > t( createTransformer( minValue, maxValue ) );
323+
324+
for ( int i = 0; i < breaks.length(); i++ )
325+
{
326+
std::unique_ptr< QgsSymbolLegendNode > node;
327+
if ( dynamic_cast<const QgsMarkerSymbol*>( symbol ) )
328+
{
329+
std::unique_ptr< QgsMarkerSymbol > symbolClone( static_cast<QgsMarkerSymbol*>( symbol->clone() ) );
330+
symbolClone->setDataDefinedSize( QgsProperty() );
331+
symbolClone->setDataDefinedAngle( QgsProperty() ); // to avoid symbol not being drawn
332+
symbolClone->setSize( t->size( breaks[i] ) );
333+
node.reset( new QgsSymbolLegendNode( parent, QgsLegendSymbolItem( symbolClone.get(), QString::number( i ), QString() ) ) );
334+
}
335+
else if ( dynamic_cast<const QgsLineSymbol*>( symbol ) )
336+
{
337+
std::unique_ptr< QgsLineSymbol > symbolClone( static_cast<QgsLineSymbol*>( symbol->clone() ) );
338+
symbolClone->setDataDefinedWidth( QgsProperty() );
339+
symbolClone->setWidth( t->size( breaks[i] ) );
340+
node.reset( new QgsSymbolLegendNode( parent, QgsLegendSymbolItem( symbolClone.get(), QString::number( i ), QString() ) ) );
341+
}
342+
if ( node )
343+
nodes << node.release();
344+
}
345+
return nodes;
346+
}
347+
348+
QList<QgsSymbolLegendNode*> QgsPropertyAbstractTransformerWidget::generatePreviews( const QList<double>& , QgsLayerTreeLayer* , const QgsVectorLayer*, const QgsSymbol*, double, double ) const
349+
{
350+
return QList< QgsSymbolLegendNode* >();
351+
}

src/gui/qgspropertyassistantwidget.h

+38-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@
2222
#include "ui_qgspropertyassistantwidgetbase.h"
2323
#include "ui_qgspropertysizeassistantwidget.h"
2424
#include "qgsproperty.h"
25+
#include "qgslayertreegroup.h"
26+
#include "qgssymbol.h"
27+
#include "qgslayertreemodellegendnode.h"
2528
#include "qgis_gui.h"
29+
#include <QStandardItemModel>
30+
#include <QItemDelegate>
2631

2732
class QgsMapCanvas;
2833

@@ -41,6 +46,8 @@ class GUI_EXPORT QgsPropertyAbstractTransformerWidget : public QWidget
4146

4247
virtual QgsPropertyTransformer* createTransformer( double minValue, double maxValue ) const = 0;
4348

49+
virtual QList< QgsSymbolLegendNode* > generatePreviews( const QList<double>& breaks, QgsLayerTreeLayer* parent, const QgsVectorLayer* layer, const QgsSymbol* symbol, double minValue, double maxValue ) const;
50+
4451
signals:
4552

4653
void widgetChanged();
@@ -59,9 +66,9 @@ class GUI_EXPORT QgsPropertySizeAssistantWidget : public QgsPropertyAbstractTran
5966

6067
QgsPropertySizeAssistantWidget( QWidget* parent = nullptr, const QgsPropertyDefinition& definition = QgsPropertyDefinition(), const QgsProperty& initialState = QgsProperty() );
6168

62-
virtual QgsPropertyTransformer* createTransformer( double minValue, double maxValue ) const override;
63-
69+
virtual QgsSizeScaleTransformer* createTransformer( double minValue, double maxValue ) const override;
6470

71+
QList< QgsSymbolLegendNode* > generatePreviews( const QList<double>& breaks, QgsLayerTreeLayer* parent, const QgsVectorLayer* layer, const QgsSymbol* symbol, double minValue, double maxValue ) const override;
6572
};
6673

6774
///@endcond PRIVATE
@@ -84,9 +91,12 @@ class GUI_EXPORT QgsPropertyAssistantWidget : public QgsPanelWidget, private Ui:
8491

8592
void updateProperty( QgsProperty& property );
8693

94+
void setSymbol( std::shared_ptr< QgsSymbol > symbol ) { mSymbol = symbol; updatePreview(); }
8795

8896
private slots:
8997
void computeValuesFromLayer();
98+
void updatePreview();
99+
90100

91101
private:
92102

@@ -95,10 +105,36 @@ class GUI_EXPORT QgsPropertyAssistantWidget : public QgsPanelWidget, private Ui:
95105
QgsExpressionContextGenerator* mExpressionContextGenerator = nullptr;
96106
QgsPropertyAbstractTransformerWidget* mTransformerWidget = nullptr;
97107

108+
QgsLayerTreeLayer* mLayerTreeLayer = nullptr;
109+
QgsLayerTreeGroup mRoot;
110+
QStandardItemModel mPreviewList;
111+
112+
std::shared_ptr< QgsSymbol > mSymbol;
113+
98114
bool computeValuesFromExpression( const QString& expression, double& minValue, double& maxValue ) const;
99115
bool computeValuesFromField( const QString& fieldName, double& minValue, double& maxValue ) const;
100116

101117
};
102118

103119

120+
/// @cond PRIVATE
121+
class ItemDelegate : public QItemDelegate
122+
{
123+
Q_OBJECT
124+
125+
public:
126+
explicit ItemDelegate( QStandardItemModel* model ) : mModel( model ) {}
127+
128+
QSize sizeHint( const QStyleOptionViewItem& /*option*/, const QModelIndex & index ) const override
129+
{
130+
return mModel->item( index.row() )->icon().actualSize( QSize( 512, 512 ) );
131+
}
132+
133+
private:
134+
QStandardItemModel* mModel = nullptr;
135+
136+
};
137+
138+
///@endcond
139+
104140
#endif // QGSPROPERTYASSISTANTWIDGET_H

src/gui/qgspropertyoverridebutton.cpp

+29-2
Original file line numberDiff line numberDiff line change
@@ -532,10 +532,13 @@ void QgsPropertyOverrideButton::showAssistant()
532532
}
533533

534534
QgsPanelWidget* panel = QgsPanelWidget::findParentPanel( this );
535+
QgsPropertyAssistantWidget* widget = new QgsPropertyAssistantWidget( panel, mDefinition, mProperty, mVectorLayer );
536+
widget->setDockMode( panel && panel->dockMode() );
537+
widget->registerExpressionContextGenerator( mExpressionContextGenerator );
538+
widget->setSymbol( mSymbol ); // we only show legend preview in dialog version
539+
535540
if ( panel && panel->dockMode() )
536541
{
537-
QgsPropertyAssistantWidget* widget = new QgsPropertyAssistantWidget( panel, mDefinition, mProperty, mVectorLayer );
538-
widget->registerExpressionContextGenerator( mExpressionContextGenerator );
539542
connect( widget, &QgsPropertyAssistantWidget::widgetChanged, this, [this,widget]
540543
{
541544
widget->updateProperty( this->mProperty );
@@ -549,6 +552,30 @@ void QgsPropertyOverrideButton::showAssistant()
549552
panel->openPanel( widget );
550553
return;
551554
}
555+
else
556+
{
557+
// Show the dialog version if not in a panel
558+
QDialog* dlg = new QDialog( this );
559+
QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( widget->panelTitle() );
560+
QSettings settings;
561+
dlg->restoreGeometry( settings.value( key ).toByteArray() );
562+
dlg->setWindowTitle( widget->panelTitle() );
563+
dlg->setLayout( new QVBoxLayout() );
564+
dlg->layout()->addWidget( widget );
565+
QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
566+
connect( buttonBox, SIGNAL( accepted() ), dlg, SLOT( accept() ) );
567+
dlg->layout()->addWidget( buttonBox );
568+
dlg->exec();
569+
settings.setValue( key, dlg->saveGeometry() );
570+
571+
widget->updateProperty( mProperty );
572+
mExpressionString = mProperty.asExpression();
573+
mFieldName = mProperty.field();
574+
widget->acceptPanel();
575+
updateGui();
576+
577+
emit changed();
578+
}
552579
}
553580

554581
void QgsPropertyOverrideButton::updateGui()

src/gui/qgspropertyoverridebutton.h

+4
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
156156
*/
157157
void registerExpressionContextGenerator( QgsExpressionContextGenerator* generator );
158158

159+
void setSymbol( std::shared_ptr< QgsSymbol > symbol ) { mSymbol = symbol; }
160+
159161
public slots:
160162

161163
/**
@@ -230,6 +232,8 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
230232
//! Internal property used for storing state of widget
231233
QgsProperty mProperty;
232234

235+
std::shared_ptr< QgsSymbol > mSymbol;
236+
233237
private slots:
234238
void aboutToShowMenu();
235239
void menuActionTriggered( QAction* action );

src/gui/symbology-ng/qgssizescalewidget.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ QgsSizeScaleWidget::QgsSizeScaleWidget( const QgsVectorLayer * layer, const QgsS
127127
}
128128

129129
treeView->setModel( &mPreviewList );
130-
treeView->setItemDelegate( new ItemDelegate( &mPreviewList ) );
130+
// treeView->setItemDelegate( new ItemDelegate( &mPreviewList ) );
131131
treeView->setHeaderHidden( true );
132132
treeView->expandAll();
133133

src/gui/symbology-ng/qgssizescalewidget.h

-19
Original file line numberDiff line numberDiff line change
@@ -110,24 +110,5 @@ class GUI_EXPORT QgsSizeScaleWidget : public QgsDataDefinedAssistant, private Ui
110110
QgsExpressionContext createExpressionContext() const override;
111111
};
112112

113-
/// @cond PRIVATE
114-
class ItemDelegate : public QItemDelegate
115-
{
116-
Q_OBJECT
117-
118-
public:
119-
explicit ItemDelegate( QStandardItemModel* model ) : mModel( model ) {}
120-
121-
QSize sizeHint( const QStyleOptionViewItem& /*option*/, const QModelIndex & index ) const override
122-
{
123-
return mModel->item( index.row() )->icon().actualSize( QSize( 512, 512 ) );
124-
}
125-
126-
private:
127-
QStandardItemModel* mModel;
128-
129-
};
130-
131-
///@endcond
132113

133114
#endif //QGSSIZESCALEWIDGET_H

0 commit comments

Comments
 (0)