1 /***************************************************************************
2 qgsannotationitempropertieswidget.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
16 #include "qgsannotationitempropertieswidget.h"
17 #include "qgsstyle.h"
18 #include "qgsapplication.h"
19 #include "qgsmaplayer.h"
20 #include "qgsannotationlayer.h"
21 #include "qgsannotationitemwidget.h"
22 #include "qgsannotationitem.h"
23 #include "qgsgui.h"
24 #include "qgsannotationitemguiregistry.h"
25 #include "qgspainteffect.h"
26
27 #include <QStackedWidget>
28 #include <QHBoxLayout>
29 #include <QLabel>
30
QgsAnnotationItemPropertiesWidget(QgsAnnotationLayer * layer,QgsMapCanvas * canvas,QWidget * parent)31 QgsAnnotationItemPropertiesWidget::QgsAnnotationItemPropertiesWidget( QgsAnnotationLayer *layer, QgsMapCanvas *canvas, QWidget *parent )
32 : QgsMapLayerConfigWidget( layer, canvas, parent )
33 {
34 setupUi( this );
35
36 mPageNoItem = new QWidget();
37 QSizePolicy sizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
38 sizePolicy.setHorizontalStretch( 0 );
39 sizePolicy.setVerticalStretch( 0 );
40 sizePolicy.setHeightForWidth( mPageNoItem->sizePolicy().hasHeightForWidth() );
41 mPageNoItem->setSizePolicy( sizePolicy );
42 QVBoxLayout *verticalLayout = new QVBoxLayout();
43 verticalLayout->setContentsMargins( 0, 0, 0, 0 );
44 QLabel *label = new QLabel();
45 label->setText( tr( "No item selected." ) );
46 verticalLayout->addWidget( label );
47 mPageNoItem->setLayout( verticalLayout );
48 mStack->addWidget( mPageNoItem );
49 mStack->setCurrentWidget( mPageNoItem );
50
51 connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsAnnotationItemPropertiesWidget::onLayerPropertyChanged );
52 connect( mBlendModeComboBox, qOverload< int >( &QgsBlendModeComboBox::currentIndexChanged ), this, &QgsAnnotationItemPropertiesWidget::onLayerPropertyChanged );
53 connect( mEffectWidget, &QgsEffectStackCompactWidget::changed, this, &QgsAnnotationItemPropertiesWidget::onLayerPropertyChanged );
54
55 setDockMode( true );
56
57 syncToLayer( layer );
58 }
59
60 QgsAnnotationItemPropertiesWidget::~QgsAnnotationItemPropertiesWidget() = default;
61
syncToLayer(QgsMapLayer * layer)62 void QgsAnnotationItemPropertiesWidget::syncToLayer( QgsMapLayer *layer )
63 {
64 if ( layer == mLayer )
65 return;
66
67 mLayer = qobject_cast< QgsAnnotationLayer * >( layer );
68 if ( !mLayer )
69 return;
70
71 // opacity and blend modes
72 mBlockLayerUpdates = true;
73 mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
74 mOpacityWidget->setOpacity( mLayer->opacity() );
75 if ( mLayer->paintEffect() )
76 {
77 mPaintEffect.reset( mLayer->paintEffect()->clone() );
78 mEffectWidget->setPaintEffect( mPaintEffect.get() );
79 }
80 mBlockLayerUpdates = false;
81
82 // check context
83 setItemId( mMapLayerConfigWidgetContext.annotationId() );
84 }
85
setMapLayerConfigWidgetContext(const QgsMapLayerConfigWidgetContext & context)86 void QgsAnnotationItemPropertiesWidget::setMapLayerConfigWidgetContext( const QgsMapLayerConfigWidgetContext &context )
87 {
88 QgsMapLayerConfigWidget::setMapLayerConfigWidgetContext( context );
89 setItemId( context.annotationId() );
90
91 if ( mItemWidget )
92 {
93 QgsSymbolWidgetContext symbolWidgetContext;
94 symbolWidgetContext.setMapCanvas( context.mapCanvas() );
95 symbolWidgetContext.setMessageBar( context.messageBar() );
96 mItemWidget->setContext( symbolWidgetContext );
97 }
98 }
99
setDockMode(bool dockMode)100 void QgsAnnotationItemPropertiesWidget::setDockMode( bool dockMode )
101 {
102 QgsMapLayerConfigWidget::setDockMode( dockMode );
103 if ( mItemWidget )
104 mItemWidget->setDockMode( dockMode );
105 }
106
apply()107 void QgsAnnotationItemPropertiesWidget::apply()
108 {
109 if ( !mLayer )
110 return;
111
112 // set the blend mode and opacity for the layer
113 mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
114 mLayer->setOpacity( mOpacityWidget->opacity() );
115
116 if ( mPaintEffect )
117 mLayer->setPaintEffect( mPaintEffect->clone() );
118
119 mLayer->triggerRepaint();
120 }
121
focusDefaultWidget()122 void QgsAnnotationItemPropertiesWidget::focusDefaultWidget()
123 {
124 if ( mItemWidget )
125 mItemWidget->focusDefaultWidget();
126 }
127
onChanged()128 void QgsAnnotationItemPropertiesWidget::onChanged()
129 {
130 if ( !mLayer )
131 return;
132
133 // we refetch the item from the layer and update it, as the item's geometry (or some other property)
134 // may have changed and we always want to use the current properties
135
136 if ( QgsAnnotationItem *existingItem = mLayer->item( mMapLayerConfigWidgetContext.annotationId() ) )
137 {
138 std::unique_ptr< QgsAnnotationItem > newItem( existingItem->clone() );
139 mItemWidget->updateItem( newItem.get() );
140
141 mLayer->replaceItem( mMapLayerConfigWidgetContext.annotationId(), newItem.release() );
142 }
143 }
144
onLayerPropertyChanged()145 void QgsAnnotationItemPropertiesWidget::onLayerPropertyChanged()
146 {
147 if ( mBlockLayerUpdates )
148 return;
149
150 emit widgetChanged();
151 }
152
setItemId(const QString & itemId)153 void QgsAnnotationItemPropertiesWidget::setItemId( const QString &itemId )
154 {
155 if ( !mLayer )
156 return;
157
158 // try to retrieve matching item
159 bool setItem = false;
160 QgsAnnotationItem *item = !itemId.isEmpty() ? mLayer->item( itemId ) : nullptr;
161 if ( item )
162 {
163 if ( mItemWidget )
164 {
165 setItem = mItemWidget->setItem( item );
166 }
167
168 if ( !setItem )
169 {
170 // create new item
171 mItemWidget = QgsGui::annotationItemGuiRegistry()->createItemWidget( item );
172
173 if ( mItemWidget )
174 {
175 setItem = true;
176
177 QWidget *prevWidget = mStack->currentWidget();
178 if ( prevWidget != mPageNoItem )
179 {
180 mStack->removeWidget( prevWidget );
181 delete prevWidget;
182 }
183
184 mStack->addWidget( mItemWidget );
185 mStack->setCurrentWidget( mItemWidget );
186 connect( mItemWidget, &QgsAnnotationItemBaseWidget::itemChanged, this, &QgsAnnotationItemPropertiesWidget::onChanged );
187 mItemWidget->setDockMode( dockMode() );
188 connect( mItemWidget, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
189
190 QgsSymbolWidgetContext symbolWidgetContext;
191 symbolWidgetContext.setMapCanvas( mMapLayerConfigWidgetContext.mapCanvas() );
192 symbolWidgetContext.setMessageBar( mMapLayerConfigWidgetContext.messageBar() );
193 mItemWidget->setContext( symbolWidgetContext );
194 }
195 }
196 }
197
198 if ( !setItem )
199 {
200 // show the "no item" widget
201 QWidget *prevWidget = mStack->currentWidget();
202 if ( prevWidget != mPageNoItem )
203 {
204 mStack->removeWidget( prevWidget );
205 delete prevWidget;
206 }
207 mStack->setCurrentWidget( mPageNoItem );
208 }
209 }
210
211 //
212 // QgsAnnotationItemPropertiesWidgetFactory
213 //
214
QgsAnnotationItemPropertiesWidgetFactory(QObject * parent)215 QgsAnnotationItemPropertiesWidgetFactory::QgsAnnotationItemPropertiesWidgetFactory( QObject *parent )
216 : QObject( parent )
217 {
218 setIcon( QgsApplication::getThemeIcon( QStringLiteral( "propertyicons/symbology.svg" ) ) );
219 setTitle( tr( "Annotation" ) );
220 }
221
createWidget(QgsMapLayer * layer,QgsMapCanvas * canvas,bool,QWidget * parent) const222 QgsMapLayerConfigWidget *QgsAnnotationItemPropertiesWidgetFactory::createWidget( QgsMapLayer *layer, QgsMapCanvas *canvas, bool, QWidget *parent ) const
223 {
224 return new QgsAnnotationItemPropertiesWidget( qobject_cast< QgsAnnotationLayer * >( layer ), canvas, parent );
225 }
226
supportLayerPropertiesDialog() const227 bool QgsAnnotationItemPropertiesWidgetFactory::supportLayerPropertiesDialog() const
228 {
229 return false;
230 }
231
supportsStyleDock() const232 bool QgsAnnotationItemPropertiesWidgetFactory::supportsStyleDock() const
233 {
234 return true;
235 }
236
supportsLayer(QgsMapLayer * layer) const237 bool QgsAnnotationItemPropertiesWidgetFactory::supportsLayer( QgsMapLayer *layer ) const
238 {
239 return layer->type() == QgsMapLayerType::AnnotationLayer;
240 }
241
242