QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgslayoutpolylinewidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutpolylinewidget.cpp
3  begin : March 2016
4  copyright : (C) 2016 Paul Blottiere, Oslandia
5  email : paul dot blottiere at oslandia dot com
6  ***************************************************************************/
7 
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
19 #include "qgsstyle.h"
20 #include "qgssymbollayerutils.h"
21 #include "qgslayoutitemregistry.h"
22 #include "qgslayout.h"
23 #include "qgslayoutundostack.h"
24 #include "qgsvectorlayer.h"
25 #include "qgslinesymbol.h"
26 
27 #include <QButtonGroup>
28 #include <QFileDialog>
29 
31  : QgsLayoutItemBaseWidget( nullptr, polyline )
32  , mPolyline( polyline )
33 {
34  setupUi( this );
35  setPanelTitle( tr( "Polyline Properties" ) );
36 
37  connect( mStrokeWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPolylineWidget::arrowStrokeWidthChanged );
38  connect( mArrowHeadWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPolylineWidget::arrowHeadWidthChanged );
39  connect( mArrowHeadFillColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutPolylineWidget::arrowHeadFillColorChanged );
40  connect( mArrowHeadStrokeColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutPolylineWidget::arrowHeadStrokeColorChanged );
41  connect( mRadioStartArrow, &QRadioButton::toggled, this, &QgsLayoutPolylineWidget::startArrowHeadToggled );
42  connect( mRadioStartNoMarker, &QRadioButton::toggled, this, &QgsLayoutPolylineWidget::startNoMarkerToggled );
43  connect( mRadioStartSVG, &QRadioButton::toggled, this, &QgsLayoutPolylineWidget::startSvgMarkerToggled );
44  connect( mRadioEndArrow, &QRadioButton::toggled, this, &QgsLayoutPolylineWidget::endArrowHeadToggled );
45  connect( mRadioEndNoMarker, &QRadioButton::toggled, this, &QgsLayoutPolylineWidget::endNoMarkerToggled );
46  connect( mRadioEndSvg, &QRadioButton::toggled, this, &QgsLayoutPolylineWidget::endSvgMarkerToggled );
47  connect( mStartMarkerLineEdit, &QLineEdit::textChanged, this, &QgsLayoutPolylineWidget::mStartMarkerLineEdit_textChanged );
48  connect( mEndMarkerLineEdit, &QLineEdit::textChanged, this, &QgsLayoutPolylineWidget::mEndMarkerLineEdit_textChanged );
49  connect( mStartMarkerToolButton, &QToolButton::clicked, this, &QgsLayoutPolylineWidget::mStartMarkerToolButton_clicked );
50  connect( mEndMarkerToolButton, &QToolButton::clicked, this, &QgsLayoutPolylineWidget::mEndMarkerToolButton_clicked );
51  setPanelTitle( tr( "Arrow Properties" ) );
52  QButtonGroup *startMarkerGroup = new QButtonGroup( this );
53  startMarkerGroup->addButton( mRadioStartNoMarker );
54  startMarkerGroup->addButton( mRadioStartArrow );
55  startMarkerGroup->addButton( mRadioStartSVG );
56  startMarkerGroup->setExclusive( true );
57  QButtonGroup *endMarkerGroup = new QButtonGroup( this );
58  endMarkerGroup->addButton( mRadioEndNoMarker );
59  endMarkerGroup->addButton( mRadioEndArrow );
60  endMarkerGroup->addButton( mRadioEndSvg );
61  endMarkerGroup->setExclusive( true );
62 
63  //disable the svg related gui elements by default
64  enableStartSvgInputElements( false );
65  enableEndSvgInputElements( false );
66 
67  mArrowHeadStrokeColorButton->setColorDialogTitle( tr( "Select Arrow Head Stroke Color" ) );
68  mArrowHeadStrokeColorButton->setAllowOpacity( true );
69  mArrowHeadStrokeColorButton->setContext( QStringLiteral( "composer" ) );
70  mArrowHeadStrokeColorButton->setNoColorString( tr( "Transparent Stroke" ) );
71  mArrowHeadStrokeColorButton->setShowNoColor( true );
72  mArrowHeadFillColorButton->setColorDialogTitle( tr( "Select Arrow Head Fill Color" ) );
73  mArrowHeadFillColorButton->setAllowOpacity( true );
74  mArrowHeadFillColorButton->setContext( QStringLiteral( "composer" ) );
75  mArrowHeadFillColorButton->setNoColorString( tr( "Transparent Fill" ) );
76  mArrowHeadFillColorButton->setShowNoColor( true );
77 
78  //add widget for general composer item properties
79  mItemPropertiesWidget = new QgsLayoutItemPropertiesWidget( this, polyline );
80  //shapes don't use background or frame, since the symbol style is set through a QgsSymbolSelectorWidget
81  mItemPropertiesWidget->showBackgroundGroup( false );
82  mItemPropertiesWidget->showFrameGroup( false );
83  mainLayout->addWidget( mItemPropertiesWidget );
84 
85  mLineStyleButton->setSymbolType( Qgis::SymbolType::Line );
86  connect( mLineStyleButton, &QgsSymbolButton::changed, this, &QgsLayoutPolylineWidget::symbolChanged );
87 
88  if ( mPolyline )
89  {
90  connect( mPolyline, &QgsLayoutObject::changed, this, &QgsLayoutPolylineWidget::setGuiElementValues );
91  mLineStyleButton->registerExpressionContextGenerator( mPolyline );
92  }
93  setGuiElementValues();
94 
95  mLineStyleButton->registerExpressionContextGenerator( mPolyline );
96  mLineStyleButton->setLayer( coverageLayer() );
97  if ( mPolyline->layout() )
98  {
99  connect( &mPolyline->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, mLineStyleButton, &QgsSymbolButton::setLayer );
100  }
101 }
102 
104 {
105  if ( mItemPropertiesWidget )
106  mItemPropertiesWidget->setMasterLayout( masterLayout );
107 }
108 
110 {
112  return false;
113 
114  if ( mPolyline )
115  {
116  disconnect( mPolyline, &QgsLayoutObject::changed, this, &QgsLayoutPolylineWidget::setGuiElementValues );
117  }
118 
119  mPolyline = qobject_cast< QgsLayoutItemPolyline * >( item );
120  mItemPropertiesWidget->setItem( mPolyline );
121 
122  if ( mPolyline )
123  {
124  connect( mPolyline, &QgsLayoutObject::changed, this, &QgsLayoutPolylineWidget::setGuiElementValues );
125  mLineStyleButton->registerExpressionContextGenerator( mPolyline );
126  }
127 
128  setGuiElementValues();
129 
130  return true;
131 }
132 
133 
134 void QgsLayoutPolylineWidget::setGuiElementValues()
135 {
136  if ( !mPolyline )
137  return;
138 
139  whileBlocking( mLineStyleButton )->setSymbol( mPolyline->symbol()->clone() );
140 
141  whileBlocking( mArrowHeadFillColorButton )->setColor( mPolyline->arrowHeadFillColor() );
142  whileBlocking( mArrowHeadStrokeColorButton )->setColor( mPolyline->arrowHeadStrokeColor() );
143  whileBlocking( mStrokeWidthSpinBox )->setValue( mPolyline->arrowHeadStrokeWidth() );
144  whileBlocking( mArrowHeadWidthSpinBox )->setValue( mPolyline->arrowHeadWidth() );
145 
146  mRadioStartNoMarker->blockSignals( true );
147  mRadioStartArrow->blockSignals( true );
148  mRadioStartSVG->blockSignals( true );
149  mRadioEndArrow->blockSignals( true );
150  mRadioEndNoMarker->blockSignals( true );
151  mRadioEndSvg->blockSignals( true );
152  switch ( mPolyline->startMarker() )
153  {
155  mRadioStartNoMarker->setChecked( true );
156  break;
158  mRadioStartArrow->setChecked( true );
159  break;
161  mRadioStartSVG->setChecked( true );
162  enableStartSvgInputElements( true );
163  break;
164  }
165  switch ( mPolyline->endMarker() )
166  {
168  mRadioEndNoMarker->setChecked( true );
169  break;
171  mRadioEndArrow->setChecked( true );
172  break;
174  mRadioEndSvg->setChecked( true );
175  enableEndSvgInputElements( true );
176  break;
177  }
178  mRadioStartNoMarker->blockSignals( false );
179  mRadioStartArrow->blockSignals( false );
180  mRadioStartSVG->blockSignals( false );
181  mRadioEndArrow->blockSignals( false );
182  mRadioEndNoMarker->blockSignals( false );
183  mRadioEndSvg->blockSignals( false );
184 
185  mStartMarkerLineEdit->setText( mPolyline->startSvgMarkerPath() );
186  mEndMarkerLineEdit->setText( mPolyline->endSvgMarkerPath() );
187 }
188 
189 void QgsLayoutPolylineWidget::symbolChanged()
190 {
191  if ( !mPolyline )
192  return;
193 
194  mPolyline->layout()->undoStack()->beginCommand( mPolyline, tr( "Change Shape Style" ), QgsLayoutItem::UndoShapeStyle );
195  mPolyline->setSymbol( mLineStyleButton->clonedSymbol<QgsLineSymbol>() );
196  mPolyline->layout()->undoStack()->endCommand();
197 }
198 
199 void QgsLayoutPolylineWidget::arrowStrokeWidthChanged( double d )
200 {
201  if ( !mPolyline )
202  return;
203 
204  mPolyline->beginCommand( tr( "Change Arrow Head" ), QgsLayoutItem::UndoArrowStrokeWidth );
205  mPolyline->setArrowHeadStrokeWidth( d );
206  mPolyline->endCommand();
207 }
208 
209 void QgsLayoutPolylineWidget::arrowHeadWidthChanged( double d )
210 {
211  if ( !mPolyline )
212  return;
213 
214  mPolyline->beginCommand( tr( "Change Arrow Width" ), QgsLayoutItem::UndoArrowHeadWidth );
215  mPolyline->setArrowHeadWidth( d );
216  mPolyline->endCommand();
217 }
218 
219 
220 void QgsLayoutPolylineWidget::arrowHeadFillColorChanged( const QColor &newColor )
221 {
222  if ( !mPolyline )
223  return;
224 
225  mPolyline->beginCommand( tr( "Change Arrow Fill Color" ), QgsLayoutItem::UndoArrowHeadFillColor );
226  mPolyline->setArrowHeadFillColor( newColor );
227  mPolyline->endCommand();
228 }
229 
230 
231 void QgsLayoutPolylineWidget::arrowHeadStrokeColorChanged( const QColor &newColor )
232 {
233  if ( !mPolyline )
234  return;
235 
236  mPolyline->beginCommand( tr( "Change Arrow Stroke Color" ), QgsLayoutItem::UndoArrowHeadStrokeColor );
237  mPolyline->setArrowHeadStrokeColor( newColor );
238  mPolyline->endCommand();
239 }
240 
241 
242 void QgsLayoutPolylineWidget::startArrowHeadToggled( bool toggled )
243 {
244  if ( !mPolyline || !toggled )
245  return;
246 
247  mPolyline->beginCommand( tr( "Set Arrow Marker" ) );
248  mPolyline->setStartMarker( QgsLayoutItemPolyline::ArrowHead );
249  mPolyline->endCommand();
250 }
251 
252 void QgsLayoutPolylineWidget::endArrowHeadToggled( bool toggled )
253 {
254  if ( !mPolyline || !toggled )
255  return;
256 
257  mPolyline->beginCommand( tr( "Set Arrow Marker" ) );
258  mPolyline->setEndMarker( QgsLayoutItemPolyline::ArrowHead );
259  mPolyline->endCommand();
260 }
261 
262 void QgsLayoutPolylineWidget::startNoMarkerToggled( bool toggled )
263 {
264  if ( !mPolyline || !toggled )
265  return;
266 
267  mPolyline->beginCommand( tr( "Set Line Marker" ) );
268  mPolyline->setStartMarker( QgsLayoutItemPolyline::NoMarker );
269  mPolyline->endCommand();
270 }
271 
272 void QgsLayoutPolylineWidget::endNoMarkerToggled( bool toggled )
273 {
274  if ( !mPolyline || !toggled )
275  return;
276 
277  mPolyline->beginCommand( tr( "Set Line Marker" ) );
278  mPolyline->setEndMarker( QgsLayoutItemPolyline::NoMarker );
279  mPolyline->endCommand();
280 }
281 
282 void QgsLayoutPolylineWidget::startSvgMarkerToggled( bool toggled )
283 {
284  enableStartSvgInputElements( toggled );
285  if ( !mPolyline || !toggled )
286  return;
287 
288  mPolyline->beginCommand( tr( "Set SVG Marker" ) );
289  mPolyline->setStartMarker( QgsLayoutItemPolyline::SvgMarker );
290  mPolyline->endCommand();
291 }
292 
293 void QgsLayoutPolylineWidget::endSvgMarkerToggled( bool toggled )
294 {
295  enableEndSvgInputElements( toggled );
296  if ( !mPolyline || !toggled )
297  return;
298 
299  mPolyline->beginCommand( tr( "Set SVG Marker" ) );
300  mPolyline->setEndMarker( QgsLayoutItemPolyline::SvgMarker );
301  mPolyline->endCommand();
302 }
303 
304 void QgsLayoutPolylineWidget::enableStartSvgInputElements( bool enable )
305 {
306  mStartMarkerLineEdit->setEnabled( enable );
307  mStartMarkerToolButton->setEnabled( enable );
308 }
309 
310 void QgsLayoutPolylineWidget::enableEndSvgInputElements( bool enable )
311 {
312  mEndMarkerLineEdit->setEnabled( enable );
313  mEndMarkerToolButton->setEnabled( enable );
314 }
315 
316 void QgsLayoutPolylineWidget::mStartMarkerLineEdit_textChanged( const QString &text )
317 {
318  if ( !mPolyline )
319  return;
320 
321  mPolyline->beginCommand( tr( "Change Start Marker File" ) );
322  const QFileInfo fi( text );
323  if ( fi.exists() && fi.isFile() )
324  {
325  mPolyline->setStartSvgMarkerPath( text );
326  }
327  else
328  {
329  mPolyline->setStartSvgMarkerPath( QString() );
330  }
331  mPolyline->endCommand();
332 }
333 
334 void QgsLayoutPolylineWidget::mEndMarkerLineEdit_textChanged( const QString &text )
335 {
336  if ( !mPolyline )
337  return;
338 
339  mPolyline->beginCommand( tr( "Change End Marker File" ) );
340  const QFileInfo fi( text );
341  if ( fi.exists() && fi.isFile() )
342  {
343  mPolyline->setEndSvgMarkerPath( text );
344  }
345  else
346  {
347  mPolyline->setEndSvgMarkerPath( QString() );
348  }
349  mPolyline->endCommand();
350 }
351 
352 void QgsLayoutPolylineWidget::mStartMarkerToolButton_clicked()
353 {
354  QgsSettings s;
355  QString openDir;
356 
357  if ( !mStartMarkerLineEdit->text().isEmpty() )
358  {
359  const QFileInfo fi( mStartMarkerLineEdit->text() );
360  openDir = fi.dir().absolutePath();
361  }
362 
363  if ( openDir.isEmpty() )
364  {
365  openDir = s.value( QStringLiteral( "/UI/lastComposerMarkerDir" ), QDir::homePath() ).toString();
366  }
367 
368  const QString svgFileName = QFileDialog::getOpenFileName( this, tr( "Start marker svg file" ), openDir );
369  if ( !svgFileName.isNull() )
370  {
371  const QFileInfo fileInfo( svgFileName );
372  s.setValue( QStringLiteral( "/UI/lastComposerMarkerDir" ), fileInfo.absolutePath() );
373  mPolyline->beginCommand( tr( "Change Start Marker File" ) );
374  mStartMarkerLineEdit->setText( svgFileName );
375  mPolyline->endCommand();
376  }
377 }
378 
379 void QgsLayoutPolylineWidget::mEndMarkerToolButton_clicked()
380 {
381  QgsSettings s;
382  QString openDir;
383 
384  if ( !mEndMarkerLineEdit->text().isEmpty() )
385  {
386  const QFileInfo fi( mEndMarkerLineEdit->text() );
387  openDir = fi.dir().absolutePath();
388  }
389 
390  if ( openDir.isEmpty() )
391  {
392  openDir = s.value( QStringLiteral( "/UI/lastComposerMarkerDir" ), QDir::homePath() ).toString();
393  }
394 
395  const QString svgFileName = QFileDialog::getOpenFileName( this, tr( "End marker svg file" ), openDir );
396  if ( !svgFileName.isNull() )
397  {
398  const QFileInfo fileInfo( svgFileName );
399  s.setValue( QStringLiteral( "/UI/lastComposerMarkerDir" ), fileInfo.absolutePath() );
400  mPolyline->beginCommand( tr( "Change End Marker File" ) );
401  mEndMarkerLineEdit->setText( svgFileName );
402  mPolyline->endCommand();
403  }
404 }
@ Line
Line symbol.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
A base class for property widgets for layout items.
QgsVectorLayer * coverageLayer() const
Returns the current layout context coverage layer (if set).
Layout item for node based polyline shapes.
@ ArrowHead
Show arrow marker.
@ SvgMarker
Show SVG marker.
@ NoMarker
Don't show marker.
A widget for controlling the common properties of layout items (e.g.
void setMasterLayout(QgsMasterLayoutInterface *masterLayout)
Sets the master layout associated with the item.
void showFrameGroup(bool showGroup)
Determines if the frame of the group box shall be shown.
void setItem(QgsLayoutItem *item)
Sets the layout item.
void showBackgroundGroup(bool showGroup)
Determines if the background of the group box shall be shown.
@ LayoutPolyline
Polyline shape item.
Base class for graphical items within a QgsLayout.
@ UndoArrowHeadStrokeColor
Arrow head stroke color.
@ UndoArrowHeadFillColor
Arrow head fill color.
@ UndoArrowHeadWidth
Arrow head width.
@ UndoArrowStrokeWidth
Arrow stroke width.
@ UndoShapeStyle
Shape symbol style.
int type() const override
Returns a unique graphics item type identifier.
void changed()
Emitted when the object's properties change.
bool setNewItem(QgsLayoutItem *item) override
Attempts to update the widget to show the properties for the specified item.
QgsLayoutPolylineWidget(QgsLayoutItemPolyline *polyline)
constructor
void setMasterLayout(QgsMasterLayoutInterface *masterLayout) override
Sets the master layout associated with the item.
void layerChanged(QgsVectorLayer *layer)
Emitted when the context's layer is changed.
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:30
Interface for master layout type objects, such as print layouts and reports.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void setLayer(QgsVectorLayer *layer)
Sets a layer to associate with the widget.
void changed()
Emitted when the symbol's settings are changed.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:1517