QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsannotationitemwidget_impl.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsannotationitemwidget_impl.cpp
3  ------------------------
4  Date : September 2021
5  Copyright : (C) 2021 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  ***************************************************************************/
16 
18 #include "qgsstyle.h"
19 #include "qgsfillsymbol.h"
20 #include "qgslinesymbol.h"
21 #include "qgsmarkersymbol.h"
23 #include "qgsannotationlineitem.h"
27 #include "qgstextformatwidget.h"
28 #include "qgsapplication.h"
29 #include "qgsrecentstylehandler.h"
30 
32 
33 QgsAnnotationPolygonItemWidget::QgsAnnotationPolygonItemWidget( QWidget *parent )
34  : QgsAnnotationItemBaseWidget( parent )
35 {
36  setupUi( this );
37 
38  mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
39  mSelector->setDockMode( dockMode() );
40  connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [ = ]
41  {
42  if ( !mBlockChangedSignal )
43  {
44  emit itemChanged();
45  QgsApplication::recentStyleHandler()->pushRecentSymbol( QStringLiteral( "polygon_annotation_item" ), qgis::down_cast< QgsFillSymbol * >( mSelector->symbol()->clone() ) );
46  }
47  } );
48  connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
49 
50  QVBoxLayout *layout = new QVBoxLayout();
51  layout->setContentsMargins( 0, 0, 0, 0 );
52  layout->addWidget( mSelector );
53  mSymbolSelectorFrame->setLayout( layout );
54 
55  connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
56  {
57  if ( !mBlockChangedSignal )
58  emit itemChanged();
59  } );
60 }
61 
62 QgsAnnotationItem *QgsAnnotationPolygonItemWidget::createItem()
63 {
64  QgsAnnotationPolygonItem *newItem = mItem->clone();
65  newItem->setSymbol( mSymbol->clone() );
66  mPropertiesWidget->updateItem( newItem );
67  return newItem;
68 }
69 
70 void QgsAnnotationPolygonItemWidget::updateItem( QgsAnnotationItem *item )
71 {
72  if ( QgsAnnotationPolygonItem *polygonItem = dynamic_cast< QgsAnnotationPolygonItem * >( item ) )
73  {
74  polygonItem->setSymbol( mSymbol->clone() );
75  mPropertiesWidget->updateItem( polygonItem );
76  }
77 }
78 
79 void QgsAnnotationPolygonItemWidget::setDockMode( bool dockMode )
80 {
82  if ( mSelector )
83  mSelector->setDockMode( dockMode );
84 }
85 
86 void QgsAnnotationPolygonItemWidget::setContext( const QgsSymbolWidgetContext &context )
87 {
89  if ( mSelector )
90  mSelector->setContext( context );
91  mPropertiesWidget->setContext( context );
92 }
93 
94 QgsAnnotationPolygonItemWidget::~QgsAnnotationPolygonItemWidget() = default;
95 
96 bool QgsAnnotationPolygonItemWidget::setNewItem( QgsAnnotationItem *item )
97 {
98  QgsAnnotationPolygonItem *polygonItem = dynamic_cast< QgsAnnotationPolygonItem * >( item );
99  if ( !polygonItem )
100  return false;
101 
102  mItem.reset( polygonItem->clone() );
103  if ( mItem->symbol() )
104  {
105  mSymbol.reset( mItem->symbol()->clone() );
106  }
107  else
108  {
109  mSymbol.reset( QgsFillSymbol::createSimple( {} ) );
110  }
111  mBlockChangedSignal = true;
112  mSelector->loadSymbol( mSymbol.get() );
113  mSelector->updatePreview();
114  mPropertiesWidget->setItem( mItem.get() );
115  mBlockChangedSignal = false;
116 
117  return true;
118 }
119 
120 
121 //
122 // QgsAnnotationLineItemWidget
123 //
124 
125 QgsAnnotationLineItemWidget::QgsAnnotationLineItemWidget( QWidget *parent )
126  : QgsAnnotationItemBaseWidget( parent )
127 {
128  setupUi( this );
129 
130  mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
131  mSelector->setDockMode( dockMode() );
132  connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [ = ]
133  {
134  if ( !mBlockChangedSignal )
135  {
136  emit itemChanged();
137  QgsApplication::recentStyleHandler()->pushRecentSymbol( QStringLiteral( "line_annotation_item" ), qgis::down_cast< QgsLineSymbol * >( mSelector->symbol()->clone() ) );
138  }
139  } );
140  connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
141 
142  QVBoxLayout *layout = new QVBoxLayout();
143  layout->setContentsMargins( 0, 0, 0, 0 );
144  layout->addWidget( mSelector );
145  mSymbolSelectorFrame->setLayout( layout );
146 
147  connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
148  {
149  if ( !mBlockChangedSignal )
150  emit itemChanged();
151  } );
152 }
153 
154 QgsAnnotationItem *QgsAnnotationLineItemWidget::createItem()
155 {
156  QgsAnnotationLineItem *newItem = mItem->clone();
157  newItem->setSymbol( mSymbol->clone() );
158  mPropertiesWidget->updateItem( newItem );
159  return newItem;
160 }
161 
162 void QgsAnnotationLineItemWidget::updateItem( QgsAnnotationItem *item )
163 {
164  if ( QgsAnnotationLineItem *lineItem = dynamic_cast< QgsAnnotationLineItem * >( item ) )
165  {
166  lineItem->setSymbol( mSymbol->clone() );
167  mPropertiesWidget->updateItem( lineItem );
168  }
169 }
170 
171 void QgsAnnotationLineItemWidget::setDockMode( bool dockMode )
172 {
174  if ( mSelector )
175  mSelector->setDockMode( dockMode );
176 }
177 
178 void QgsAnnotationLineItemWidget::setContext( const QgsSymbolWidgetContext &context )
179 {
181  if ( mSelector )
182  mSelector->setContext( context );
183  mPropertiesWidget->setContext( context );
184 }
185 
186 QgsAnnotationLineItemWidget::~QgsAnnotationLineItemWidget() = default;
187 
188 bool QgsAnnotationLineItemWidget::setNewItem( QgsAnnotationItem *item )
189 {
190  QgsAnnotationLineItem *lineItem = dynamic_cast< QgsAnnotationLineItem * >( item );
191  if ( !lineItem )
192  return false;
193 
194  mItem.reset( lineItem->clone() );
195  if ( mItem->symbol() )
196  {
197  mSymbol.reset( mItem->symbol()->clone() );
198  }
199  else
200  {
201  mSymbol.reset( QgsLineSymbol::createSimple( {} ) );
202  }
203  mBlockChangedSignal = true;
204  mSelector->loadSymbol( mSymbol.get() );
205  mSelector->updatePreview();
206  mPropertiesWidget->setItem( mItem.get() );
207  mBlockChangedSignal = false;
208 
209  return true;
210 }
211 
212 
213 //
214 // QgsAnnotationMarkerItemWidget
215 //
216 
217 QgsAnnotationMarkerItemWidget::QgsAnnotationMarkerItemWidget( QWidget *parent )
218  : QgsAnnotationItemBaseWidget( parent )
219 {
220  setupUi( this );
221 
222  mSelector = new QgsSymbolSelectorWidget( mSymbol.get(), QgsStyle::defaultStyle(), nullptr, nullptr );
223  mSelector->setDockMode( dockMode() );
224  connect( mSelector, &QgsSymbolSelectorWidget::symbolModified, this, [ = ]
225  {
226  if ( !mBlockChangedSignal )
227  {
228  emit itemChanged();
229  QgsApplication::recentStyleHandler()->pushRecentSymbol( QStringLiteral( "marker_annotation_item" ), qgis::down_cast< QgsMarkerSymbol * >( mSelector->symbol()->clone() ) );
230  }
231  } );
232  connect( mSelector, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
233 
234  QVBoxLayout *layout = new QVBoxLayout();
235  layout->setContentsMargins( 0, 0, 0, 0 );
236  layout->addWidget( mSelector );
237  mSymbolSelectorFrame->setLayout( layout );
238 
239  connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
240  {
241  if ( !mBlockChangedSignal )
242  emit itemChanged();
243  } );
244 }
245 
246 QgsAnnotationItem *QgsAnnotationMarkerItemWidget::createItem()
247 {
248  QgsAnnotationMarkerItem *newItem = mItem->clone();
249  newItem->setSymbol( mSymbol->clone() );
250  mPropertiesWidget->updateItem( newItem );
251  return newItem;
252 }
253 
254 void QgsAnnotationMarkerItemWidget::updateItem( QgsAnnotationItem *item )
255 {
256  if ( QgsAnnotationMarkerItem *markerItem = dynamic_cast< QgsAnnotationMarkerItem * >( item ) )
257  {
258  markerItem->setSymbol( mSymbol->clone() );
259  mPropertiesWidget->updateItem( markerItem );
260  }
261 }
262 
263 void QgsAnnotationMarkerItemWidget::setDockMode( bool dockMode )
264 {
266  if ( mSelector )
267  mSelector->setDockMode( dockMode );
268 }
269 
270 void QgsAnnotationMarkerItemWidget::setContext( const QgsSymbolWidgetContext &context )
271 {
273  if ( mSelector )
274  mSelector->setContext( context );
275  mPropertiesWidget->setContext( context );
276 }
277 
278 QgsAnnotationMarkerItemWidget::~QgsAnnotationMarkerItemWidget() = default;
279 
280 bool QgsAnnotationMarkerItemWidget::setNewItem( QgsAnnotationItem *item )
281 {
282  QgsAnnotationMarkerItem *markerItem = dynamic_cast< QgsAnnotationMarkerItem * >( item );
283  if ( !markerItem )
284  return false;
285 
286  mItem.reset( markerItem->clone() );
287  if ( mItem->symbol() )
288  {
289  mSymbol.reset( mItem->symbol()->clone() );
290  }
291  else
292  {
293  mSymbol.reset( QgsMarkerSymbol::createSimple( {} ) );
294  }
295  mBlockChangedSignal = true;
296  mSelector->loadSymbol( mSymbol.get() );
297  mSelector->updatePreview();
298  mPropertiesWidget->setItem( mItem.get() );
299  mBlockChangedSignal = false;
300 
301  return true;
302 }
303 
304 
305 
306 //
307 // QgsAnnotationPointTextItemWidget
308 //
309 
310 QgsAnnotationPointTextItemWidget::QgsAnnotationPointTextItemWidget( QWidget *parent )
311  : QgsAnnotationItemBaseWidget( parent )
312 {
313  setupUi( this );
314 
315  mTextFormatWidget = new QgsTextFormatWidget();
316  QVBoxLayout *vLayout = new QVBoxLayout();
317  vLayout->setContentsMargins( 0, 0, 0, 0 );
318  vLayout->addWidget( mTextFormatWidget );
319  mTextFormatWidgetContainer->setLayout( vLayout );
320 
321  mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 );
322 
323  mTextFormatWidget->setDockMode( dockMode() );
324  connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [ = ]
325  {
326  if ( !mBlockChangedSignal )
327  emit itemChanged();
328  } );
329  connect( mTextEdit, &QPlainTextEdit::textChanged, this, [ = ]
330  {
331  if ( !mBlockChangedSignal )
332  emit itemChanged();
333  } );
334  connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked );
335  connect( mPropertiesWidget, &QgsAnnotationItemCommonPropertiesWidget::itemChanged, this, [ = ]
336  {
337  if ( !mBlockChangedSignal )
338  emit itemChanged();
339  } );
340 }
341 
342 QgsAnnotationItem *QgsAnnotationPointTextItemWidget::createItem()
343 {
344  QgsAnnotationPointTextItem *newItem = mItem->clone();
345  newItem->setFormat( mTextFormatWidget->format() );
346  newItem->setText( mTextEdit->toPlainText() );
347  mPropertiesWidget->updateItem( newItem );
348  return newItem;
349 }
350 
351 void QgsAnnotationPointTextItemWidget::updateItem( QgsAnnotationItem *item )
352 {
353  if ( QgsAnnotationPointTextItem *pointTextItem = dynamic_cast< QgsAnnotationPointTextItem * >( item ) )
354  {
355  pointTextItem->setFormat( mTextFormatWidget->format() );
356  pointTextItem->setText( mTextEdit->toPlainText() );
357  mPropertiesWidget->updateItem( pointTextItem );
358  }
359 }
360 
361 void QgsAnnotationPointTextItemWidget::setDockMode( bool dockMode )
362 {
364  if ( mTextFormatWidget )
365  mTextFormatWidget->setDockMode( dockMode );
366 }
367 
368 void QgsAnnotationPointTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
369 {
371  if ( mTextFormatWidget )
372  mTextFormatWidget->setContext( context );
373  mPropertiesWidget->setContext( context );
374 }
375 
376 void QgsAnnotationPointTextItemWidget::focusDefaultWidget()
377 {
378  mTextEdit->selectAll();
379  mTextEdit->setFocus();
380 }
381 
382 QgsAnnotationPointTextItemWidget::~QgsAnnotationPointTextItemWidget() = default;
383 
384 bool QgsAnnotationPointTextItemWidget::setNewItem( QgsAnnotationItem *item )
385 {
386  QgsAnnotationPointTextItem *textItem = dynamic_cast< QgsAnnotationPointTextItem * >( item );
387  if ( !textItem )
388  return false;
389 
390  mItem.reset( textItem->clone() );
391 
392  mBlockChangedSignal = true;
393  mTextFormatWidget->setFormat( mItem->format() );
394  mTextEdit->setPlainText( mItem->text() );
395  mPropertiesWidget->setItem( mItem.get() );
396  mBlockChangedSignal = false;
397 
398  return true;
399 }
400 
401 void QgsAnnotationPointTextItemWidget::mInsertExpressionButton_clicked()
402 {
403  QString selText = mTextEdit->textCursor().selectedText();
404 
405  // html editor replaces newlines with Paragraph Separator characters - see https://github.com/qgis/QGIS/issues/27568
406  selText = selText.replace( QChar( 0x2029 ), QChar( '\n' ) );
407 
408  // edit the selected expression if there's one
409  if ( selText.startsWith( QLatin1String( "[%" ) ) && selText.endsWith( QLatin1String( "%]" ) ) )
410  selText = selText.mid( 2, selText.size() - 4 );
411 
412  QgsExpressionContext expressionContext;
413  if ( context().expressionContext() )
414  expressionContext = *( context().expressionContext() );
415  else
416  expressionContext = QgsProject::instance()->createExpressionContext();
417 
418  QgsExpressionBuilderDialog exprDlg( nullptr, selText, this, QStringLiteral( "generic" ), expressionContext );
419 
420  exprDlg.setWindowTitle( tr( "Insert Expression" ) );
421  if ( exprDlg.exec() == QDialog::Accepted )
422  {
423  QString expression = exprDlg.expressionText();
424  if ( !expression.isEmpty() )
425  {
426  mTextEdit->insertPlainText( "[%" + expression + "%]" );
427  }
428  }
429 }
430 
432 
QgsAnnotationItemBaseWidget
A base class for property widgets for annotation items.
Definition: qgsannotationitemwidget.h:35
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsAnnotationPolygonItem::clone
QgsAnnotationPolygonItem * clone() override
Returns a clone of the item.
Definition: qgsannotationpolygonitem.cpp:220
QgsApplication::recentStyleHandler
static QgsRecentStyleHandler * recentStyleHandler()
Returns the handler for recently used style items.
Definition: qgsapplication.cpp:2435
QgsPanelWidget::setDockMode
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
Definition: qgspanelwidget.cpp:44
qgsannotationpolygonitem.h
QgsSymbolWidgetContext
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
Definition: qgssymbolwidgetcontext.h:35
QgsPanelWidget::openPanel
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
Definition: qgspanelwidget.cpp:84
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:480
QgsRecentStyleHandler::pushRecentSymbol
void pushRecentSymbol(const QString &identifier, QgsSymbol *symbol)
Pushes a recently used symbol with the specified identifier.
Definition: qgsrecentstylehandler.cpp:24
QgsSymbolSelectorWidget
Symbol selector widget that can be used to select and build a symbol.
Definition: qgssymbolselectordialog.h:87
QgsSymbolSelectorWidget::symbolModified
void symbolModified()
Emitted when a symbol is modified in the widget.
QgsPanelWidget::dockMode
bool dockMode()
Returns the dock mode state.
Definition: qgspanelwidget.h:93
QgsLineSymbol::createSimple
static QgsLineSymbol * createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
Definition: qgslinesymbol.cpp:22
QgsAnnotationMarkerItem
An annotation item which renders a marker symbol at a point location.
Definition: qgsannotationmarkeritem.h:32
QgsAnnotationLineItem::clone
QgsAnnotationLineItem * clone() override
Returns a clone of the item.
Definition: qgsannotationlineitem.cpp:196
QgsAnnotationPointTextItem::clone
QgsAnnotationPointTextItem * clone() override
Returns a clone of the item.
Definition: qgsannotationpointtextitem.cpp:109
QgsPanelWidget::showPanel
void showPanel(QgsPanelWidget *panel)
Emit when you require a panel to be show in the interface.
QgsStyle::defaultStyle
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
qgsannotationlineitem.h
qgsapplication.h
QgsAnnotationItemBaseWidget::itemChanged
void itemChanged()
Emitted when the annotation item definition in the widget is changed by the user.
qgsannotationmarkeritem.h
QgsAnnotationPointTextItem::setText
void setText(const QString &text)
Sets the text rendered by the item.
Definition: qgsannotationpointtextitem.h:104
qgstextformatwidget.h
QgsAnnotationMarkerItem::clone
QgsAnnotationMarkerItem * clone() override
Returns a clone of the item.
Definition: qgsannotationmarkeritem.cpp:156
QgsAnnotationPolygonItem
An annotation item which renders a fill symbol for a polygon geometry.
Definition: qgsannotationpolygonitem.h:32
QgsAnnotationItemBaseWidget::setContext
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the widget is shown, e.g., the associated map canvas and expression context...
Definition: qgsannotationitemwidget.cpp:29
QgsExpressionBuilderDialog
A generic dialog for building expression strings.
Definition: qgsexpressionbuilderdialog.h:30
qgsannotationitemwidget_impl.h
QgsSymbolWidgetContext::expressionContext
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
Definition: qgssymbolwidgetcontext.cpp:77
QgsTextFormatWidget
A widget for customizing text formatting settings.
Definition: qgstextformatwidget.h:50
QgsFillSymbol::createSimple
static QgsFillSymbol * createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
Definition: qgsfillsymbol.cpp:20
qgssymbolselectordialog.h
qgsstyle.h
QgsAnnotationItemCommonPropertiesWidget::itemChanged
void itemChanged()
Emitted when the annotation item definition in the widget is changed by the user.
qgsannotationpointtextitem.h
qgsrecentstylehandler.h
QgsTextFormatWidget::widgetChanged
void widgetChanged()
Emitted when the text format defined by the widget changes.
QgsAnnotationLineItem::setSymbol
void setSymbol(QgsLineSymbol *symbol)
Sets the symbol used to render the marker item.
Definition: qgsannotationlineitem.cpp:209
QgsAnnotationPointTextItem::setFormat
void setFormat(const QgsTextFormat &format)
Sets the text format used to render the text.
Definition: qgsannotationpointtextitem.cpp:204
qgsmarkersymbol.h
QgsProject::createExpressionContext
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgsproject.cpp:2214
QgsAnnotationPolygonItem::setSymbol
void setSymbol(QgsFillSymbol *symbol)
Sets the symbol used to render the polygon item.
Definition: qgsannotationpolygonitem.cpp:238
QgsAnnotationLineItem
An annotation item which renders a line symbol along a line geometry.
Definition: qgsannotationlineitem.h:33
QgsMarkerSymbol::createSimple
static QgsMarkerSymbol * createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
Definition: qgsmarkersymbol.cpp:22
qgsfillsymbol.h
QgsAnnotationItem
Abstract base class for annotation items which are drawn with QgsAnnotationLayers.
Definition: qgsannotationitem.h:42
QgsAnnotationMarkerItem::setSymbol
void setSymbol(QgsMarkerSymbol *symbol)
Sets the symbol used to render the marker item.
Definition: qgsannotationmarkeritem.cpp:203
QgsAnnotationPointTextItem
An annotation item which renders a text string at a point location.
Definition: qgsannotationpointtextitem.h:33
qgslinesymbol.h
qgsexpressionbuilderdialog.h