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