QGIS API Documentation 3.31.0-Master (d2b117a3c8)
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"
27#include "qgstextformatwidget.h"
28#include "qgsapplication.h"
30
32
33QgsAnnotationPolygonItemWidget::QgsAnnotationPolygonItemWidget( QWidget *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
62QgsAnnotationItem *QgsAnnotationPolygonItemWidget::createItem()
63{
64 QgsAnnotationPolygonItem *newItem = mItem->clone();
65 newItem->setSymbol( mSymbol->clone() );
66 mPropertiesWidget->updateItem( newItem );
67 return newItem;
68}
69
70void 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
79void QgsAnnotationPolygonItemWidget::setDockMode( bool dockMode )
80{
82 if ( mSelector )
83 mSelector->setDockMode( dockMode );
84}
85
86void QgsAnnotationPolygonItemWidget::setContext( const QgsSymbolWidgetContext &context )
87{
89 if ( mSelector )
90 mSelector->setContext( context );
91 mPropertiesWidget->setContext( context );
92}
93
94QgsAnnotationPolygonItemWidget::~QgsAnnotationPolygonItemWidget() = default;
95
96bool 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
125QgsAnnotationLineItemWidget::QgsAnnotationLineItemWidget( QWidget *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
154QgsAnnotationItem *QgsAnnotationLineItemWidget::createItem()
155{
156 QgsAnnotationLineItem *newItem = mItem->clone();
157 newItem->setSymbol( mSymbol->clone() );
158 mPropertiesWidget->updateItem( newItem );
159 return newItem;
160}
161
162void 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
171void QgsAnnotationLineItemWidget::setDockMode( bool dockMode )
172{
174 if ( mSelector )
175 mSelector->setDockMode( dockMode );
176}
177
178void QgsAnnotationLineItemWidget::setContext( const QgsSymbolWidgetContext &context )
179{
181 if ( mSelector )
182 mSelector->setContext( context );
183 mPropertiesWidget->setContext( context );
184}
185
186QgsAnnotationLineItemWidget::~QgsAnnotationLineItemWidget() = default;
187
188bool 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
217QgsAnnotationMarkerItemWidget::QgsAnnotationMarkerItemWidget( QWidget *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
246QgsAnnotationItem *QgsAnnotationMarkerItemWidget::createItem()
247{
248 QgsAnnotationMarkerItem *newItem = mItem->clone();
249 newItem->setSymbol( mSymbol->clone() );
250 mPropertiesWidget->updateItem( newItem );
251 return newItem;
252}
253
254void 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
263void QgsAnnotationMarkerItemWidget::setDockMode( bool dockMode )
264{
266 if ( mSelector )
267 mSelector->setDockMode( dockMode );
268}
269
270void QgsAnnotationMarkerItemWidget::setContext( const QgsSymbolWidgetContext &context )
271{
273 if ( mSelector )
274 mSelector->setContext( context );
275 mPropertiesWidget->setContext( context );
276}
277
278QgsAnnotationMarkerItemWidget::~QgsAnnotationMarkerItemWidget() = default;
279
280bool 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
310QgsAnnotationPointTextItemWidget::QgsAnnotationPointTextItemWidget( QWidget *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
342QgsAnnotationItem *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
351void 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
361void QgsAnnotationPointTextItemWidget::setDockMode( bool dockMode )
362{
364 if ( mTextFormatWidget )
365 mTextFormatWidget->setDockMode( dockMode );
366}
367
368void QgsAnnotationPointTextItemWidget::setContext( const QgsSymbolWidgetContext &context )
369{
371 if ( mTextFormatWidget )
372 mTextFormatWidget->setContext( context );
373 mPropertiesWidget->setContext( context );
374}
375
376void QgsAnnotationPointTextItemWidget::focusDefaultWidget()
377{
378 mTextEdit->selectAll();
379 mTextEdit->setFocus();
380}
381
382QgsAnnotationPointTextItemWidget::~QgsAnnotationPointTextItemWidget() = default;
383
384bool 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
401void 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
A base class for property widgets for annotation items.
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the widget is shown, e.g., the associated map canvas and expression context...
void itemChanged()
Emitted when the annotation item definition in the widget is changed by the user.
Abstract base class for annotation items which are drawn with QgsAnnotationLayers.
An annotation item which renders a line symbol along a line geometry.
void setSymbol(QgsLineSymbol *symbol)
Sets the symbol used to render the marker item.
QgsAnnotationLineItem * clone() override
Returns a clone of the item.
An annotation item which renders a marker symbol at a point location.
QgsAnnotationMarkerItem * clone() override
Returns a clone of the item.
void setSymbol(QgsMarkerSymbol *symbol)
Sets the symbol used to render the marker item.
An annotation item which renders a text string at a point location.
void setText(const QString &text)
Sets the text rendered by the item.
void setFormat(const QgsTextFormat &format)
Sets the text format used to render the text.
QgsAnnotationPointTextItem * clone() override
Returns a clone of the item.
An annotation item which renders a fill symbol for a polygon geometry.
void setSymbol(QgsFillSymbol *symbol)
Sets the symbol used to render the polygon item.
QgsAnnotationPolygonItem * clone() override
Returns a clone of the item.
static QgsRecentStyleHandler * recentStyleHandler()
Returns the handler for recently used style items.
A generic dialog for building expression strings.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static QgsFillSymbol * createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
static QgsLineSymbol * createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
static QgsMarkerSymbol * createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
void showPanel(QgsPanelWidget *panel)
Emit when you require a panel to be show in the interface.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:479
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void pushRecentSymbol(const QString &identifier, QgsSymbol *symbol)
Pushes a recently used symbol with the specified identifier.
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
Symbol selector widget that can be used to select and build a symbol.
void symbolModified()
Emitted when a symbol is modified in the widget.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
A widget for customizing text formatting settings.
void widgetChanged()
Emitted when the text format defined by the widget changes.