1 /***************************************************************************
2     qgsmergedfeaturerendererwidget.cpp
3     ---------------------
4     begin                : December 2020
5     copyright            : (C) 2020 by Nyall Dawson
6     email                : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 #include "qgsmergedfeaturerendererwidget.h"
16 #include "qgsmergedfeaturerenderer.h"
17 #include "qgsrendererregistry.h"
18 
19 #include "qgssymbol.h"
20 
21 #include "qgslogger.h"
22 #include "qgsvectorlayer.h"
23 #include "qgsapplication.h"
24 
create(QgsVectorLayer * layer,QgsStyle * style,QgsFeatureRenderer * renderer)25 QgsRendererWidget *QgsMergedFeatureRendererWidget::create( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer )
26 {
27   return new QgsMergedFeatureRendererWidget( layer, style, renderer );
28 }
29 
QgsMergedFeatureRendererWidget(QgsVectorLayer * layer,QgsStyle * style,QgsFeatureRenderer * renderer)30 QgsMergedFeatureRendererWidget::QgsMergedFeatureRendererWidget( QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer )
31   : QgsRendererWidget( layer, style )
32 {
33   if ( !layer )
34   {
35     return;
36   }
37 
38   const QgsWkbTypes::GeometryType type = QgsWkbTypes::geometryType( layer->wkbType() );
39 
40   // the renderer only applies to line or polygon vector layers
41   if ( type != QgsWkbTypes::PolygonGeometry && type != QgsWkbTypes::LineGeometry )
42   {
43     //setup blank dialog
44     mRenderer.reset( nullptr );
45     QGridLayout *layout = new QGridLayout( this );
46     QLabel *label = new QLabel( tr( "The merged feature renderer only applies to line and polygon layers. \n"
47                                     "'%1' is not a line or polygon layer and then cannot be displayed" )
48                                 .arg( layer->name() ), this );
49     this->setLayout( layout );
50     layout->addWidget( label );
51     return;
52   }
53   setupUi( this );
54   connect( mRendererComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsMergedFeatureRendererWidget::mRendererComboBox_currentIndexChanged );
55 
56   // try to recognize the previous renderer
57   // (null renderer means "no previous renderer")
58   if ( renderer )
59   {
60     mRenderer.reset( QgsMergedFeatureRenderer::convertFromRenderer( renderer ) );
61   }
62   if ( ! mRenderer )
63   {
64     // use default embedded renderer
65     mRenderer.reset( new QgsMergedFeatureRenderer( QgsFeatureRenderer::defaultRenderer( type ) ) );
66     if ( renderer )
67       renderer->copyRendererData( mRenderer.get() );
68   }
69 
70   int currentEmbeddedIdx = 0;
71   //insert possible renderer types
72   const QStringList rendererList = QgsApplication::rendererRegistry()->renderersList( type == QgsWkbTypes::PolygonGeometry ? QgsRendererAbstractMetadata::PolygonLayer :  QgsRendererAbstractMetadata::LineLayer );
73   QStringList::const_iterator it = rendererList.constBegin();
74   int idx = 0;
75   mRendererComboBox->blockSignals( true );
76   for ( ; it != rendererList.constEnd(); ++it, ++idx )
77   {
78     if ( *it != QLatin1String( "mergedFeatureRenderer" )
79          && *it != QLatin1String( "invertedPolygonRenderer" ) ) //< an merged renderer cannot contain another merged or inverted renderer
80     {
81       QgsRendererAbstractMetadata *m = QgsApplication::rendererRegistry()->rendererMetadata( *it );
82       mRendererComboBox->addItem( m->icon(), m->visibleName(), /* data */ *it );
83       const QgsFeatureRenderer *embeddedRenderer = mRenderer->embeddedRenderer();
84       if ( embeddedRenderer && embeddedRenderer->type() == m->name() )
85       {
86         // store the combo box index of the current renderer
87         currentEmbeddedIdx = idx;
88       }
89     }
90   }
91   mRendererComboBox->blockSignals( false );
92 
93   const int oldIdx = mRendererComboBox->currentIndex();
94   mRendererComboBox->setCurrentIndex( currentEmbeddedIdx );
95   if ( oldIdx == currentEmbeddedIdx )
96   {
97     // force update
98     mRendererComboBox_currentIndexChanged( currentEmbeddedIdx );
99   }
100 }
101 
102 QgsMergedFeatureRendererWidget::~QgsMergedFeatureRendererWidget() = default;
103 
renderer()104 QgsFeatureRenderer *QgsMergedFeatureRendererWidget::renderer()
105 {
106   if ( mRenderer && mEmbeddedRendererWidget )
107   {
108     QgsFeatureRenderer *embeddedRenderer = mEmbeddedRendererWidget->renderer();
109     if ( embeddedRenderer )
110     {
111       mRenderer->setEmbeddedRenderer( embeddedRenderer->clone() );
112     }
113   }
114   return mRenderer.get();
115 }
116 
setContext(const QgsSymbolWidgetContext & context)117 void QgsMergedFeatureRendererWidget::setContext( const QgsSymbolWidgetContext &context )
118 {
119   QgsRendererWidget::setContext( context );
120   if ( mEmbeddedRendererWidget )
121     mEmbeddedRendererWidget->setContext( context );
122 }
123 
setDockMode(bool dockMode)124 void QgsMergedFeatureRendererWidget::setDockMode( bool dockMode )
125 {
126   QgsRendererWidget::setDockMode( dockMode );
127   if ( mEmbeddedRendererWidget )
128     mEmbeddedRendererWidget->setDockMode( dockMode );
129 }
130 
mRendererComboBox_currentIndexChanged(int index)131 void QgsMergedFeatureRendererWidget::mRendererComboBox_currentIndexChanged( int index )
132 {
133   const QString rendererId = mRendererComboBox->itemData( index ).toString();
134   QgsRendererAbstractMetadata *m = QgsApplication::rendererRegistry()->rendererMetadata( rendererId );
135   if ( m )
136   {
137     const std::unique_ptr< QgsFeatureRenderer > oldRenderer( mRenderer->embeddedRenderer()->clone() );
138     mEmbeddedRendererWidget.reset( m->createRendererWidget( mLayer, mStyle, oldRenderer.get() ) );
139     connect( mEmbeddedRendererWidget.get(), &QgsRendererWidget::widgetChanged, this, &QgsMergedFeatureRendererWidget::widgetChanged );
140     mEmbeddedRendererWidget->setContext( mContext );
141     mEmbeddedRendererWidget->disableSymbolLevels();
142     mEmbeddedRendererWidget->setDockMode( this->dockMode() );
143     connect( mEmbeddedRendererWidget.get(), &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
144 
145     if ( layout()->count() > 2 )
146     {
147       // remove the current renderer widget
148       layout()->takeAt( 2 );
149     }
150     layout()->addWidget( mEmbeddedRendererWidget.get() );
151   }
152 }
153