Skip to content
Permalink
Browse files

Restore legend preview in symbol size assistant

  • Loading branch information
nyalldawson committed Feb 14, 2017
1 parent 90dd988 commit 84dd983b797f2e56968e0f8846af50355ca47962
@@ -20,6 +20,8 @@
#include "qgsproject.h"
#include "qgsmapsettings.h"
#include "qgsvectorlayer.h"
#include "qgslayertreelayer.h"
#include "qgssymbollayerutils.h"

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

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

if ( mLayer )
{
mLayerTreeLayer = new QgsLayerTreeLayer( const_cast< QgsVectorLayer* >( mLayer ) );
mRoot.addChildNode( mLayerTreeLayer ); // takes ownership
}
mLegendPreview->setModel( &mPreviewList );
mLegendPreview->setItemDelegate( new ItemDelegate( &mPreviewList ) );
mLegendPreview->setHeaderHidden( true );
mLegendPreview->expandAll();

switch ( definition.standardTemplate() )
{
case QgsPropertyDefinition::Size:
@@ -72,6 +84,8 @@ QgsPropertyAssistantWidget::QgsPropertyAssistantWidget( QWidget* parent ,
connect( minValueSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertyAssistantWidget::widgetChanged );
connect( maxValueSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertyAssistantWidget::widgetChanged );
connect( mExpressionWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString& ) > ( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsPropertyAssistantWidget::widgetChanged );
connect( this, &QgsPropertyAssistantWidget::widgetChanged, this, &QgsPropertyAssistantWidget::updatePreview );
updatePreview();
}

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

void QgsPropertyAssistantWidget::updatePreview()
{
if ( !mTransformerWidget || !mSymbol )
return;

if ( dockMode() )
return;

mLegendPreview->setIconSize( QSize( 512, 512 ) );
mPreviewList.clear();

QList<double> breaks = QgsSymbolLayerUtils::prettyBreaks( minValueSpinBox->value(),
maxValueSpinBox->value(), 4 );

QList< QgsSymbolLegendNode* > nodes = mTransformerWidget->generatePreviews( breaks, mLayerTreeLayer, mLayer, mSymbol.get(), minValueSpinBox->value(),
maxValueSpinBox->value() );
if ( nodes.isEmpty() )
{
mLegendPreview->show();
return;
}

int widthMax = 0;
int i = 0;
Q_FOREACH ( QgsSymbolLegendNode* node, nodes )
{
const QSize minSize( node->minimumIconSize() );
node->setIconSize( minSize );
widthMax = qMax( minSize.width(), widthMax );
mPreviewList.appendRow( new QStandardItem( node->data( Qt::DecorationRole ).value<QPixmap>(), QString::number( breaks[i] ) ) );
delete node;
i++;
}
// center icon and align text left by giving icons the same width
// @todo maybe add some space so that icons don't touch
for ( int i = 0; i < breaks.length(); i++ )
{
QPixmap img( mPreviewList.item( i )->icon().pixmap( mPreviewList.item( i )->icon().actualSize( QSize( 512, 512 ) ) ) );
QPixmap enlarged( widthMax, img.height() );
// fill transparent and add original image
enlarged.fill( Qt::transparent );
QPainter p( &enlarged );
p.drawPixmap( QPoint(( widthMax - img.width() ) / 2, 0 ), img );
p.end();
mPreviewList.item( i )->setIcon( enlarged );
}
mLegendPreview->show();
}

bool QgsPropertyAssistantWidget::computeValuesFromExpression( const QString& expression, double& minValue, double& maxValue ) const
{
QgsExpression e( expression );
@@ -236,7 +299,7 @@ QgsPropertySizeAssistantWidget::QgsPropertySizeAssistantWidget( QWidget* parent,
);
}

QgsPropertyTransformer* QgsPropertySizeAssistantWidget::createTransformer( double minValue, double maxValue ) const
QgsSizeScaleTransformer* QgsPropertySizeAssistantWidget::createTransformer( double minValue, double maxValue ) const
{
QgsSizeScaleTransformer* transformer = new QgsSizeScaleTransformer(
static_cast< QgsSizeScaleTransformer::ScaleType >( scaleMethodComboBox->currentData().toInt() ),
@@ -248,3 +311,41 @@ QgsPropertyTransformer* QgsPropertySizeAssistantWidget::createTransformer( doubl
exponentSpinBox->value() );
return transformer;
}

QList< QgsSymbolLegendNode* > QgsPropertySizeAssistantWidget::generatePreviews( const QList<double>& breaks, QgsLayerTreeLayer* parent, const QgsVectorLayer* layer, const QgsSymbol* symbol, double minValue, double maxValue ) const
{
QList< QgsSymbolLegendNode* > nodes;

if ( !symbol || !layer )
return nodes;

std::unique_ptr< QgsSizeScaleTransformer > t( createTransformer( minValue, maxValue ) );

for ( int i = 0; i < breaks.length(); i++ )
{
std::unique_ptr< QgsSymbolLegendNode > node;
if ( dynamic_cast<const QgsMarkerSymbol*>( symbol ) )
{
std::unique_ptr< QgsMarkerSymbol > symbolClone( static_cast<QgsMarkerSymbol*>( symbol->clone() ) );
symbolClone->setDataDefinedSize( QgsProperty() );
symbolClone->setDataDefinedAngle( QgsProperty() ); // to avoid symbol not being drawn
symbolClone->setSize( t->size( breaks[i] ) );
node.reset( new QgsSymbolLegendNode( parent, QgsLegendSymbolItem( symbolClone.get(), QString::number( i ), QString() ) ) );
}
else if ( dynamic_cast<const QgsLineSymbol*>( symbol ) )
{
std::unique_ptr< QgsLineSymbol > symbolClone( static_cast<QgsLineSymbol*>( symbol->clone() ) );
symbolClone->setDataDefinedWidth( QgsProperty() );
symbolClone->setWidth( t->size( breaks[i] ) );
node.reset( new QgsSymbolLegendNode( parent, QgsLegendSymbolItem( symbolClone.get(), QString::number( i ), QString() ) ) );
}
if ( node )
nodes << node.release();
}
return nodes;
}

QList<QgsSymbolLegendNode*> QgsPropertyAbstractTransformerWidget::generatePreviews( const QList<double>& , QgsLayerTreeLayer* , const QgsVectorLayer*, const QgsSymbol*, double, double ) const
{
return QList< QgsSymbolLegendNode* >();
}
@@ -22,7 +22,12 @@
#include "ui_qgspropertyassistantwidgetbase.h"
#include "ui_qgspropertysizeassistantwidget.h"
#include "qgsproperty.h"
#include "qgslayertreegroup.h"
#include "qgssymbol.h"
#include "qgslayertreemodellegendnode.h"
#include "qgis_gui.h"
#include <QStandardItemModel>
#include <QItemDelegate>

class QgsMapCanvas;

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

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

virtual QList< QgsSymbolLegendNode* > generatePreviews( const QList<double>& breaks, QgsLayerTreeLayer* parent, const QgsVectorLayer* layer, const QgsSymbol* symbol, double minValue, double maxValue ) const;

signals:

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

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

virtual QgsPropertyTransformer* createTransformer( double minValue, double maxValue ) const override;

virtual QgsSizeScaleTransformer* createTransformer( double minValue, double maxValue ) const override;

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

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

void updateProperty( QgsProperty& property );

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

private slots:
void computeValuesFromLayer();
void updatePreview();


private:

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

QgsLayerTreeLayer* mLayerTreeLayer = nullptr;
QgsLayerTreeGroup mRoot;
QStandardItemModel mPreviewList;

std::shared_ptr< QgsSymbol > mSymbol;

bool computeValuesFromExpression( const QString& expression, double& minValue, double& maxValue ) const;
bool computeValuesFromField( const QString& fieldName, double& minValue, double& maxValue ) const;

};


/// @cond PRIVATE
class ItemDelegate : public QItemDelegate
{
Q_OBJECT

public:
explicit ItemDelegate( QStandardItemModel* model ) : mModel( model ) {}

QSize sizeHint( const QStyleOptionViewItem& /*option*/, const QModelIndex & index ) const override
{
return mModel->item( index.row() )->icon().actualSize( QSize( 512, 512 ) );
}

private:
QStandardItemModel* mModel = nullptr;

};

///@endcond

#endif // QGSPROPERTYASSISTANTWIDGET_H
@@ -532,10 +532,13 @@ void QgsPropertyOverrideButton::showAssistant()
}

QgsPanelWidget* panel = QgsPanelWidget::findParentPanel( this );
QgsPropertyAssistantWidget* widget = new QgsPropertyAssistantWidget( panel, mDefinition, mProperty, mVectorLayer );
widget->setDockMode( panel && panel->dockMode() );
widget->registerExpressionContextGenerator( mExpressionContextGenerator );
widget->setSymbol( mSymbol ); // we only show legend preview in dialog version

if ( panel && panel->dockMode() )
{
QgsPropertyAssistantWidget* widget = new QgsPropertyAssistantWidget( panel, mDefinition, mProperty, mVectorLayer );
widget->registerExpressionContextGenerator( mExpressionContextGenerator );
connect( widget, &QgsPropertyAssistantWidget::widgetChanged, this, [this,widget]
{
widget->updateProperty( this->mProperty );
@@ -549,6 +552,30 @@ void QgsPropertyOverrideButton::showAssistant()
panel->openPanel( widget );
return;
}
else
{
// Show the dialog version if not in a panel
QDialog* dlg = new QDialog( this );
QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( widget->panelTitle() );
QSettings settings;
dlg->restoreGeometry( settings.value( key ).toByteArray() );
dlg->setWindowTitle( widget->panelTitle() );
dlg->setLayout( new QVBoxLayout() );
dlg->layout()->addWidget( widget );
QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
connect( buttonBox, SIGNAL( accepted() ), dlg, SLOT( accept() ) );
dlg->layout()->addWidget( buttonBox );
dlg->exec();
settings.setValue( key, dlg->saveGeometry() );

widget->updateProperty( mProperty );
mExpressionString = mProperty.asExpression();
mFieldName = mProperty.field();
widget->acceptPanel();
updateGui();

emit changed();
}
}

void QgsPropertyOverrideButton::updateGui()
@@ -156,6 +156,8 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
*/
void registerExpressionContextGenerator( QgsExpressionContextGenerator* generator );

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

public slots:

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

std::shared_ptr< QgsSymbol > mSymbol;

private slots:
void aboutToShowMenu();
void menuActionTriggered( QAction* action );
@@ -127,7 +127,7 @@ QgsSizeScaleWidget::QgsSizeScaleWidget( const QgsVectorLayer * layer, const QgsS
}

treeView->setModel( &mPreviewList );
treeView->setItemDelegate( new ItemDelegate( &mPreviewList ) );
// treeView->setItemDelegate( new ItemDelegate( &mPreviewList ) );
treeView->setHeaderHidden( true );
treeView->expandAll();

@@ -110,24 +110,5 @@ class GUI_EXPORT QgsSizeScaleWidget : public QgsDataDefinedAssistant, private Ui
QgsExpressionContext createExpressionContext() const override;
};

/// @cond PRIVATE
class ItemDelegate : public QItemDelegate
{
Q_OBJECT

public:
explicit ItemDelegate( QStandardItemModel* model ) : mModel( model ) {}

QSize sizeHint( const QStyleOptionViewItem& /*option*/, const QModelIndex & index ) const override
{
return mModel->item( index.row() )->icon().actualSize( QSize( 512, 512 ) );
}

private:
QStandardItemModel* mModel;

};

///@endcond

#endif //QGSSIZESCALEWIDGET_H

0 comments on commit 84dd983

Please sign in to comment.
You can’t perform that action at this time.