QGIS API Documentation 3.41.0-Master (d5b93354e9c)
Loading...
Searching...
No Matches
qgslayoutitemwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayoutitemwidget.cpp
3 ------------------------
4 Date : July 2017
5 Copyright : (C) 2017 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 "qgslayoutitemwidget.h"
17#include "moc_qgslayoutitemwidget.cpp"
19#include "qgslayout.h"
20#include "qgsproject.h"
21#include "qgslayoutundostack.h"
22#include "qgsprintlayout.h"
23#include "qgslayoutatlas.h"
25#include "qgslayoutframe.h"
26#include "qgssymbolbutton.h"
27#include "qgsfontbutton.h"
30#include "qgslayoutmultiframe.h"
31#include "qgsfilterlineedit.h"
32#include <QButtonGroup>
33
34//
35// QgsLayoutConfigObject
36//
37
39 : QObject( parent )
40 , mLayoutObject( layoutObject )
41{
42 if ( mLayoutObject->layout() )
43 {
44 connect( &mLayoutObject->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, this, [=] { updateDataDefinedButtons(); } );
45 }
46 if ( layoutAtlas() )
47 {
48 connect( layoutAtlas(), &QgsLayoutAtlas::toggled, this, &QgsLayoutConfigObject::updateDataDefinedButtons );
49 }
50}
51
52void QgsLayoutConfigObject::updateDataDefinedProperty()
53{
54 //match data defined button to item's data defined property
55 QgsPropertyOverrideButton *ddButton = qobject_cast<QgsPropertyOverrideButton *>( sender() );
56 if ( !ddButton )
57 {
58 return;
59 }
61
62 if ( ddButton->propertyKey() >= 0 )
63 key = static_cast<QgsLayoutObject::DataDefinedProperty>( ddButton->propertyKey() );
64
66 {
67 return;
68 }
69
70 const bool propertyAssociatesWithMultiFrame = QgsLayoutObject::propertyAssociatesWithParentMultiframe( key );
71
72 //set the data defined property and refresh the item
73 if ( propertyAssociatesWithMultiFrame )
74 {
75 if ( QgsLayoutFrame *frame = dynamic_cast<QgsLayoutFrame *>( mLayoutObject.data() ) )
76 {
77 if ( QgsLayoutMultiFrame *multiFrame = frame->multiFrame() )
78 {
79 multiFrame->dataDefinedProperties().setProperty( key, ddButton->toProperty() );
80 multiFrame->refresh();
81 }
82 }
83 else if ( QgsLayoutMultiFrame *multiFrame = dynamic_cast<QgsLayoutMultiFrame *>( mLayoutObject.data() ) )
84 {
85 multiFrame->dataDefinedProperties().setProperty( key, ddButton->toProperty() );
86 multiFrame->refresh();
87 }
88 }
89 else if ( mLayoutObject )
90 {
91 mLayoutObject->dataDefinedProperties().setProperty( key, ddButton->toProperty() );
92 mLayoutObject->refresh();
93 }
94}
95
96void QgsLayoutConfigObject::updateDataDefinedButtons()
97{
98 const QList<QgsPropertyOverrideButton *> buttons = findChildren<QgsPropertyOverrideButton *>();
99 for ( QgsPropertyOverrideButton *button : buttons )
100 {
101 button->setVectorLayer( coverageLayer() );
102 }
103}
104
106{
107 button->blockSignals( true );
108 button->init( static_cast<int>( key ), mLayoutObject->dataDefinedProperties(), QgsLayoutObject::propertyDefinitions(), coverageLayer() );
109 connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLayoutConfigObject::updateDataDefinedProperty, Qt::UniqueConnection );
110 button->registerExpressionContextGenerator( mLayoutObject );
111 button->blockSignals( false );
112}
113
115{
116 if ( !button )
117 return;
118
119 if ( button->propertyKey() < 0 || !mLayoutObject )
120 return;
121
123 const bool propertyAssociatesWithMultiFrame = QgsLayoutObject::propertyAssociatesWithParentMultiframe( key );
124
125 //set the data defined property
126 if ( propertyAssociatesWithMultiFrame )
127 {
128 if ( QgsLayoutFrame *frame = dynamic_cast<QgsLayoutFrame *>( mLayoutObject.data() ) )
129 {
130 if ( QgsLayoutMultiFrame *multiFrame = frame->multiFrame() )
131 {
132 whileBlocking( button )->setToProperty( multiFrame->dataDefinedProperties().property( key ) );
133 }
134 }
135 else if ( QgsLayoutMultiFrame *multiFrame = dynamic_cast<QgsLayoutMultiFrame *>( mLayoutObject.data() ) )
136 {
137 whileBlocking( button )->setToProperty( multiFrame->dataDefinedProperties().property( key ) );
138 }
139 }
140 else if ( mLayoutObject )
141 {
142 whileBlocking( button )->setToProperty( mLayoutObject->dataDefinedProperties().property( key ) );
143 }
144
145 // In case the button was initialized to a different config object, we need to reconnect to it here (see https://github.com/qgis/QGIS/issues/26582 )
146 connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLayoutConfigObject::updateDataDefinedProperty, Qt::UniqueConnection );
147 button->registerExpressionContextGenerator( mLayoutObject );
148}
149
151{
152 if ( !mLayoutObject )
153 {
154 return nullptr;
155 }
156
157 QgsPrintLayout *printLayout = qobject_cast<QgsPrintLayout *>( mLayoutObject->layout() );
158
159 if ( !printLayout )
160 {
161 return nullptr;
162 }
163
164 return printLayout->atlas();
165}
166
168{
169 mLayoutObject = object;
170}
171
173{
174 if ( !mLayoutObject )
175 return nullptr;
176
177 QgsLayout *layout = mLayoutObject->layout();
178 if ( !layout )
179 return nullptr;
180
181 return layout->reportContext().layer();
182}
183
184
185//
186// QgsLayoutItemBaseWidget
187//
188
190 : QgsPanelWidget( parent )
191 , mConfigObject( new QgsLayoutConfigObject( this, layoutObject ) )
192 , mObject( layoutObject )
193{
194}
195
200
202{
203 QgsLayoutObject *oldObject = mObject;
204 QgsLayoutConfigObject *oldConfigObject = mConfigObject;
205 // have to set new mObject/mConfigObject here, because setNewItem methods require access to them
206 mObject = item;
207 mConfigObject = new QgsLayoutConfigObject( this, mObject );
208 if ( setNewItem( item ) )
209 {
210 oldConfigObject->deleteLater();
211 return true;
212 }
213 else
214 {
215 // revert object change since it was unsuccessful
216 mObject = oldObject;
217 mConfigObject->deleteLater();
218 mConfigObject = oldConfigObject;
219 return false;
220 }
221}
222
224{
225}
226
228{
229 const auto symbolButtonWidgets = findChildren<QgsSymbolButton *>();
230 for ( QgsSymbolButton *symbolWidget : symbolButtonWidgets )
231 {
232 symbolWidget->setMessageBar( iface->messageBar() );
233 }
234 const auto fontButtonWidgets = findChildren<QgsFontButton *>();
235 for ( QgsFontButton *fontButton : fontButtonWidgets )
236 {
237 fontButton->setMessageBar( iface->messageBar() );
238 }
239}
240
244
249
254
256{
257 return mConfigObject->coverageLayer();
258}
259
261{
262 return false;
263}
264
266{
267 return mConfigObject->layoutAtlas();
268}
269
270//
271
272
273//QgsLayoutItemPropertiesWidget
274
276{
277 if ( !mItem )
278 return;
279
280 mBlockVariableUpdates = true;
281 QgsExpressionContext context = mItem->createExpressionContext();
282 mVariableEditor->setContext( &context );
283
284 // here, we prefer to make the multiframe's scope the editable one. That's because most expressions are evaluated
285 // on the multiframe subclass level, not on a frame-by-frame basis. Ideally both would be editable, but for now let's go
286 // with the most useful one.
287 const int multiFrameScopeIndex = context.indexOfScope( tr( "Multiframe Item" ) );
288 const int itemScopeIndex = context.indexOfScope( tr( "Layout Item" ) );
289 if ( multiFrameScopeIndex >= 0 )
290 mVariableEditor->setEditableScopeIndex( multiFrameScopeIndex );
291 else if ( itemScopeIndex >= 0 )
292 mVariableEditor->setEditableScopeIndex( itemScopeIndex );
293 mBlockVariableUpdates = false;
294}
295
297 : QWidget( parent )
298 , mConfigObject( new QgsLayoutConfigObject( this, item ) )
299{
300 setupUi( this );
301
302 mVariableEditor->setMinimumHeight( mVariableEditor->fontMetrics().height() * 15 );
303
304 mItemRotationSpinBox->setClearValue( 0 );
305 mStrokeUnitsComboBox->linkToWidget( mStrokeWidthSpinBox );
306 mStrokeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
307
308 QgsFilterLineEdit *exportGroupLineEdit = new QgsFilterLineEdit();
309 exportGroupLineEdit->setShowClearButton( true );
310 exportGroupLineEdit->setPlaceholderText( tr( "Not set" ) );
311 mExportGroupNameCombo->setLineEdit( exportGroupLineEdit );
312
313 mPosUnitsComboBox->linkToWidget( mXPosSpin );
314 mPosUnitsComboBox->linkToWidget( mYPosSpin );
315 mSizeUnitsComboBox->linkToWidget( mWidthSpin );
316 mSizeUnitsComboBox->linkToWidget( mHeightSpin );
317
318 mPosUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
319 mSizeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
320
321 mPosLockAspectRatio->setWidthSpinBox( mXPosSpin );
322 mPosLockAspectRatio->setHeightSpinBox( mYPosSpin );
323 mSizeLockAspectRatio->setWidthSpinBox( mWidthSpin );
324 mSizeLockAspectRatio->setHeightSpinBox( mHeightSpin );
325
326 mItemFrameColorDDBtn->registerLinkedWidget( mFrameColorButton );
327 mItemBackgroundColorDDBtn->registerLinkedWidget( mBackgroundColorButton );
328
329 connect( mFrameColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged );
330 connect( mBackgroundColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged );
331 connect( mStrokeWidthSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged );
332 connect( mStrokeUnitsComboBox, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutItemPropertiesWidget::strokeUnitChanged );
333 connect( mFrameGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled );
334 connect( mFrameJoinStyleCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged );
335 connect( mBackgroundGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled );
336 connect( mItemIdLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished );
337 connect( mExportGroupNameCombo, &QComboBox::currentTextChanged, this, &QgsLayoutItemPropertiesWidget::exportGroupNameEditingFinished );
338 connect( mPageSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged );
339 connect( mXPosSpin, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged );
340 connect( mYPosSpin, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged );
341 connect( mPosUnitsComboBox, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutItemPropertiesWidget::positionUnitsChanged );
342 connect( mWidthSpin, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged );
343 connect( mHeightSpin, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged );
344 connect( mSizeUnitsComboBox, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutItemPropertiesWidget::sizeUnitsChanged );
345 connect( mUpperLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged );
346 connect( mUpperMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged );
347 connect( mUpperRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged );
348 connect( mMiddleLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged );
349 connect( mMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged );
350 connect( mMiddleRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged );
351 connect( mLowerLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged );
352 connect( mLowerMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged );
353 connect( mLowerRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged );
354 connect( mBlendModeCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged );
355 connect( mItemRotationSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged );
356 connect( mExcludeFromPrintsCheckBox, &QCheckBox::toggled, this, &QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled );
357
358 //make button exclusive
359 QButtonGroup *buttonGroup = new QButtonGroup( this );
360 buttonGroup->addButton( mUpperLeftRadioButton );
361 buttonGroup->addButton( mUpperMiddleRadioButton );
362 buttonGroup->addButton( mUpperRightRadioButton );
363 buttonGroup->addButton( mMiddleLeftRadioButton );
364 buttonGroup->addButton( mMiddleRadioButton );
365 buttonGroup->addButton( mMiddleRightRadioButton );
366 buttonGroup->addButton( mLowerLeftRadioButton );
367 buttonGroup->addButton( mLowerMiddleRadioButton );
368 buttonGroup->addButton( mLowerRightRadioButton );
369 buttonGroup->setExclusive( true );
370
372
373 setItem( item );
374
375 connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsLayoutItemPropertiesWidget::opacityChanged );
376
378 connect( mVariableEditor, &QgsVariableEditorWidget::scopeChanged, this, [=] {
379 if ( !mBlockVariableUpdates )
380 QgsLayoutItemPropertiesWidget::variablesChanged();
381 } );
382 // listen out for variable edits
386
387 if ( item->layout() )
388 {
392 }
393}
394
396{
397 mBackgroundGroupBox->setVisible( showGroup );
398}
399
401{
402 mFrameGroupBox->setVisible( showGroup );
403}
404
406{
407 if ( mItem )
408 {
409 disconnect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
410 disconnect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
411 }
412 mItem = item;
413 if ( mItem )
414 {
415 connect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
416 connect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
417 }
418
419 mConfigObject->setObject( mItem );
420
421 setValuesForGuiElements();
422}
423
425{
426 if ( QgsPrintLayout *printLayout = dynamic_cast<QgsPrintLayout *>( masterLayout ) )
427 {
430 }
431}
432
433//slots
434
435void QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged( const QColor &newFrameColor )
436{
437 if ( !mItem )
438 {
439 return;
440 }
441 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Color" ), QgsLayoutItem::UndoStrokeColor );
442 mItem->setFrameStrokeColor( newFrameColor );
443 mItem->layout()->undoStack()->endCommand();
444 mItem->update();
445}
446
447void QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged( const QColor &newBackgroundColor )
448{
449 if ( !mItem )
450 {
451 return;
452 }
453 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Background Color" ), QgsLayoutItem::UndoBackgroundColor );
454 mItem->setBackgroundColor( newBackgroundColor );
455 mItem->layout()->undoStack()->endCommand();
456 mItem->invalidateCache();
457}
458
459void QgsLayoutItemPropertiesWidget::changeItemPosition()
460{
461 if ( !mItem )
462 return;
463
464 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Move Item" ), QgsLayoutItem::UndoIncrementalMove );
465
466 const QgsLayoutPoint point( mXPosSpin->value(), mYPosSpin->value(), mPosUnitsComboBox->unit() );
467 mItem->attemptMove( point, true, false, mPageSpinBox->value() - 1 );
468
469 mItem->layout()->undoStack()->endCommand();
470}
471
472void QgsLayoutItemPropertiesWidget::changeItemReference( QgsLayoutItem::ReferencePoint point )
473{
474 if ( !mItem )
475 return;
476
477 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item Reference" ) );
478 mItem->setReferencePoint( point );
479 mItem->layout()->undoStack()->endCommand();
480}
481
482void QgsLayoutItemPropertiesWidget::changeItemSize()
483{
484 if ( !mItem )
485 return;
486
487 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Resize Item" ), QgsLayoutItem::UndoIncrementalResize );
488
489 const QgsLayoutSize size( mWidthSpin->value(), mHeightSpin->value(), mSizeUnitsComboBox->unit() );
490 mItem->attemptResize( size );
491
492 mItem->layout()->undoStack()->endCommand();
493}
494
495void QgsLayoutItemPropertiesWidget::variablesChanged()
496{
497 if ( !mItem )
498 return;
499
500 if ( QgsLayoutFrame *frame = qobject_cast<QgsLayoutFrame *>( mItem ) )
501 {
502 if ( QgsLayoutMultiFrame *mf = frame->multiFrame() )
503 {
504 QgsExpressionContextUtils::setLayoutMultiFrameVariables( mf, mVariableEditor->variablesInActiveScope() );
505 }
506 }
507 else
508 {
509 QgsExpressionContextUtils::setLayoutItemVariables( mItem, mVariableEditor->variablesInActiveScope() );
510 }
511}
512
514{
515 if ( mUpperLeftRadioButton->isChecked() )
516 {
518 }
519 else if ( mUpperMiddleRadioButton->isChecked() )
520 {
522 }
523 else if ( mUpperRightRadioButton->isChecked() )
524 {
526 }
527 else if ( mMiddleLeftRadioButton->isChecked() )
528 {
530 }
531 else if ( mMiddleRadioButton->isChecked() )
532 {
534 }
535 else if ( mMiddleRightRadioButton->isChecked() )
536 {
538 }
539 else if ( mLowerLeftRadioButton->isChecked() )
540 {
542 }
543 else if ( mLowerMiddleRadioButton->isChecked() )
544 {
546 }
547 else if ( mLowerRightRadioButton->isChecked() )
548 {
550 }
552}
553
554void QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged( double d )
555{
556 if ( !mItem )
557 {
558 return;
559 }
560
561 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
562 mItem->setFrameStrokeWidth( QgsLayoutMeasurement( d, mStrokeUnitsComboBox->unit() ) );
563 mItem->layout()->undoStack()->endCommand();
564}
565
566void QgsLayoutItemPropertiesWidget::strokeUnitChanged( Qgis::LayoutUnit unit )
567{
568 if ( !mItem )
569 {
570 return;
571 }
572
573 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
574 mItem->setFrameStrokeWidth( QgsLayoutMeasurement( mStrokeWidthSpinBox->value(), unit ) );
575 mItem->layout()->undoStack()->endCommand();
576}
577
578void QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged( int index )
579{
580 Q_UNUSED( index )
581 if ( !mItem )
582 {
583 return;
584 }
585
586 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Join Style" ) );
587 mItem->setFrameJoinStyle( mFrameJoinStyleCombo->penJoinStyle() );
588 mItem->layout()->undoStack()->endCommand();
589}
590
591void QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled( bool state )
592{
593 if ( !mItem )
594 {
595 return;
596 }
597
598 mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Frame" ) : tr( "Disable Frame" ) );
599 mItem->setFrameEnabled( state );
600 mItem->update();
601 mItem->layout()->undoStack()->endCommand();
602}
603
604void QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled( bool state )
605{
606 if ( !mItem )
607 {
608 return;
609 }
610
611 mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Background" ) : tr( "Disable Background" ) );
612 mItem->setBackgroundEnabled( state );
613 mItem->layout()->undoStack()->endCommand();
614 mItem->invalidateCache();
615}
616
617
618void QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements()
619{
620 if ( !mItem )
621 {
622 return;
623 }
624
625 auto block = [=]( bool blocked ) {
626 mXPosSpin->blockSignals( blocked );
627 mYPosSpin->blockSignals( blocked );
628 mPosUnitsComboBox->blockSignals( blocked );
629 mWidthSpin->blockSignals( blocked );
630 mHeightSpin->blockSignals( blocked );
631 mSizeUnitsComboBox->blockSignals( blocked );
632 mUpperLeftRadioButton->blockSignals( blocked );
633 mUpperMiddleRadioButton->blockSignals( blocked );
634 mUpperRightRadioButton->blockSignals( blocked );
635 mMiddleLeftRadioButton->blockSignals( blocked );
636 mMiddleRadioButton->blockSignals( blocked );
637 mMiddleRightRadioButton->blockSignals( blocked );
638 mLowerLeftRadioButton->blockSignals( blocked );
639 mLowerMiddleRadioButton->blockSignals( blocked );
640 mLowerRightRadioButton->blockSignals( blocked );
641 mPageSpinBox->blockSignals( blocked );
642 };
643 block( true );
644
645 const QgsLayoutPoint point = mItem->pagePositionWithUnits();
646
647 if ( !mFreezeXPosSpin )
648 mXPosSpin->setValue( point.x() );
649 if ( !mFreezeYPosSpin )
650 mYPosSpin->setValue( point.y() );
651 mPosUnitsComboBox->setUnit( point.units() );
652
653 switch ( mItem->referencePoint() )
654 {
656 {
657 mUpperLeftRadioButton->setChecked( true );
658 break;
659 }
660
662 {
663 mUpperMiddleRadioButton->setChecked( true );
664 break;
665 }
666
668 {
669 mUpperRightRadioButton->setChecked( true );
670 break;
671 }
672
674 {
675 mMiddleLeftRadioButton->setChecked( true );
676 break;
677 }
678
680 {
681 mMiddleRadioButton->setChecked( true );
682 break;
683 }
684
686 {
687 mMiddleRightRadioButton->setChecked( true );
688 break;
689 }
690
692 {
693 mLowerLeftRadioButton->setChecked( true );
694 break;
695 }
696
698 {
699 mLowerMiddleRadioButton->setChecked( true );
700 break;
701 }
702
704 {
705 mLowerRightRadioButton->setChecked( true );
706 break;
707 }
708 }
709
710 const QgsLayoutSize size = mItem->sizeWithUnits();
711 if ( !mFreezeWidthSpin )
712 mWidthSpin->setValue( size.width() );
713 if ( !mFreezeHeightSpin )
714 mHeightSpin->setValue( size.height() );
715
716 mSizeUnitsComboBox->setUnit( size.units() );
717
718 mSizeLockAspectRatio->resetRatio();
719 mPosLockAspectRatio->resetRatio();
720
721 if ( !mFreezePageSpin )
722 mPageSpinBox->setValue( mItem->page() + 1 );
723
724 block( false );
725}
726
727void QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements()
728{
729 if ( !mItem )
730 {
731 return;
732 }
733
734 whileBlocking( mBackgroundColorButton )->setColor( mItem->backgroundColor( false ) );
735 whileBlocking( mFrameColorButton )->setColor( mItem->frameStrokeColor() );
736 whileBlocking( mStrokeUnitsComboBox )->setUnit( mItem->frameStrokeWidth().units() );
737 whileBlocking( mStrokeWidthSpinBox )->setValue( mItem->frameStrokeWidth().length() );
738 whileBlocking( mFrameJoinStyleCombo )->setPenJoinStyle( mItem->frameJoinStyle() );
739 whileBlocking( mItemIdLineEdit )->setText( mItem->id() );
740 whileBlocking( mFrameGroupBox )->setChecked( mItem->frameEnabled() );
741 whileBlocking( mBackgroundGroupBox )->setChecked( mItem->hasBackground() );
742 whileBlocking( mBlendModeCombo )->setBlendMode( mItem->blendMode() );
743 whileBlocking( mOpacityWidget )->setOpacity( mItem->itemOpacity() );
744 whileBlocking( mItemRotationSpinBox )->setValue( mItem->itemRotation() );
745 whileBlocking( mExcludeFromPrintsCheckBox )->setChecked( mItem->excludeFromExports() );
746 whileBlocking( mExportGroupNameCombo )->setCurrentText( mItem->customProperty( QStringLiteral( "pdfExportGroup" ) ).toString() );
747}
748
762
764{
765 const QList<QgsPropertyOverrideButton *> buttons = findChildren<QgsPropertyOverrideButton *>();
766 for ( QgsPropertyOverrideButton *button : buttons )
767 {
768 mConfigObject->updateDataDefinedButton( button );
769 }
770}
771
772void QgsLayoutItemPropertiesWidget::setValuesForGuiElements()
773{
774 if ( !mItem )
775 {
776 return;
777 }
778
779 mBackgroundColorButton->setColorDialogTitle( tr( "Select Background Color" ) );
780 mBackgroundColorButton->setAllowOpacity( true );
781 mBackgroundColorButton->setContext( QStringLiteral( "composer" ) );
782 mFrameColorButton->setColorDialogTitle( tr( "Select Frame Color" ) );
783 mFrameColorButton->setAllowOpacity( true );
784 mFrameColorButton->setContext( QStringLiteral( "composer" ) );
785
786 if ( QgsLayout *layout = mItem->layout() )
787 {
788 // collect export groups from layout, so that we can offer auto completion in the PDF export group combo
789 QList<QgsLayoutItem *> items;
790 layout->layoutItems( items );
791 QStringList existingGroups;
792 for ( const QgsLayoutItem *item : std::as_const( items ) )
793 {
794 const QString groupName = item->customProperty( QStringLiteral( "pdfExportGroup" ) ).toString();
795 if ( !groupName.isEmpty() && !existingGroups.contains( groupName ) )
796 existingGroups.append( groupName );
797 }
798
799 std::sort( existingGroups.begin(), existingGroups.end(), [=]( const QString &a, const QString &b ) -> bool {
800 return a.localeAwareCompare( b ) < 0;
801 } );
802
803 whileBlocking( mExportGroupNameCombo )->clear();
804 whileBlocking( mExportGroupNameCombo )->addItems( existingGroups );
805 }
806
807 setValuesForGuiPositionElements();
808 setValuesForGuiNonPositionElements();
810
812}
813
814void QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged( int index )
815{
816 Q_UNUSED( index )
817 if ( mItem )
818 {
819 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Blend Mode" ) );
820 mItem->setBlendMode( mBlendModeCombo->blendMode() );
821 mItem->layout()->undoStack()->endCommand();
822 }
823}
824
825void QgsLayoutItemPropertiesWidget::opacityChanged( double value )
826{
827 if ( mItem )
828 {
829 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Opacity" ), QgsLayoutItem::UndoOpacity );
830 mItem->setItemOpacity( value );
831 mItem->layout()->undoStack()->endCommand();
832 }
833}
834
835void QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished()
836{
837 if ( mItem )
838 {
839 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item ID" ), QgsLayoutItem::UndoSetId );
840 mItem->setId( mItemIdLineEdit->text() );
841 mItemIdLineEdit->setText( mItem->id() );
842 mItem->layout()->undoStack()->endCommand();
843 }
844}
845
846void QgsLayoutItemPropertiesWidget::exportGroupNameEditingFinished()
847{
848 if ( mItem )
849 {
850 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Export Group Name" ), QgsLayoutItem::UndoExportLayerName );
851 mItem->setCustomProperty( QStringLiteral( "pdfExportGroup" ), mExportGroupNameCombo->currentText() );
852 mItem->layout()->undoStack()->endCommand();
853 }
854}
855
856void QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged( int )
857{
858 mFreezePageSpin = true;
859 changeItemPosition();
860 mFreezePageSpin = false;
861}
862
863void QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged( double )
864{
865 mFreezeXPosSpin = true;
866 changeItemPosition();
867 mFreezeXPosSpin = false;
868}
869
870void QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged( double )
871{
872 mFreezeYPosSpin = true;
873 changeItemPosition();
874 mFreezeYPosSpin = false;
875}
876
877void QgsLayoutItemPropertiesWidget::positionUnitsChanged( Qgis::LayoutUnit )
878{
879 changeItemPosition();
880}
881
882void QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged( double )
883{
884 mFreezeWidthSpin = true;
885 changeItemSize();
886 mFreezeWidthSpin = false;
887}
888
889void QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged( double )
890{
891 mFreezeHeightSpin = true;
892 changeItemSize();
893 mFreezeHeightSpin = false;
894}
895
896void QgsLayoutItemPropertiesWidget::sizeUnitsChanged( Qgis::LayoutUnit )
897{
898 changeItemSize();
899}
900
901void QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged( bool state )
902{
903 if ( !state )
904 return;
905
906 if ( mItem )
907 {
908 changeItemReference( QgsLayoutItem::UpperLeft );
909 }
910 setValuesForGuiPositionElements();
911}
912
913void QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged( bool state )
914{
915 if ( !state )
916 return;
917 if ( mItem )
918 {
919 changeItemReference( QgsLayoutItem::UpperMiddle );
920 }
921 setValuesForGuiPositionElements();
922}
923
924void QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged( bool state )
925{
926 if ( !state )
927 return;
928 if ( mItem )
929 {
930 changeItemReference( QgsLayoutItem::UpperRight );
931 }
932 setValuesForGuiPositionElements();
933}
934
935void QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged( bool state )
936{
937 if ( !state )
938 return;
939 if ( mItem )
940 {
941 changeItemReference( QgsLayoutItem::MiddleLeft );
942 }
943 setValuesForGuiPositionElements();
944}
945
946void QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged( bool state )
947{
948 if ( !state )
949 return;
950 if ( mItem )
951 {
952 changeItemReference( QgsLayoutItem::Middle );
953 }
954 setValuesForGuiPositionElements();
955}
956
957void QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged( bool state )
958{
959 if ( !state )
960 return;
961 if ( mItem )
962 {
963 changeItemReference( QgsLayoutItem::MiddleRight );
964 }
965 setValuesForGuiPositionElements();
966}
967
968void QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged( bool state )
969{
970 if ( !state )
971 return;
972 if ( mItem )
973 {
974 changeItemReference( QgsLayoutItem::LowerLeft );
975 }
976 setValuesForGuiPositionElements();
977}
978
979void QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged( bool state )
980{
981 if ( !state )
982 return;
983 if ( mItem )
984 {
985 changeItemReference( QgsLayoutItem::LowerMiddle );
986 }
987 setValuesForGuiPositionElements();
988}
989
990void QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged( bool state )
991{
992 if ( !state )
993 return;
994 if ( mItem )
995 {
996 changeItemReference( QgsLayoutItem::LowerRight );
997 }
998 setValuesForGuiPositionElements();
999}
1000
1001void QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged( double val )
1002{
1003 if ( mItem )
1004 {
1005 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Rotate" ), QgsLayoutItem::UndoRotation );
1006 mItem->setItemRotation( val, true );
1007 mItem->update();
1008 mItem->layout()->undoStack()->endCommand();
1009 }
1010}
1011
1012void QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled( bool checked )
1013{
1014 if ( mItem )
1015 {
1016 mItem->layout()->undoStack()->beginCommand( mItem, checked ? tr( "Exclude from Exports" ) : tr( "Include in Exports" ) );
1017 mItem->setExcludeFromExports( checked );
1018 mItem->layout()->undoStack()->endCommand();
1019 }
1020}
LayoutUnit
Layout measurement units.
Definition qgis.h:4912
void customVariablesChanged()
Emitted whenever a custom global variable changes.
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
static void setLayoutItemVariables(QgsLayoutItem *item, const QVariantMap &variables)
Sets all layout item context variables for an item.
static void setLayoutMultiFrameVariables(QgsLayoutMultiFrame *frame, const QVariantMap &variables)
Sets all layout multiframe context variables for an frame.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
int indexOfScope(QgsExpressionContextScope *scope) const
Returns the index of the specified scope if it exists within the context.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
void setShowClearButton(bool visible)
Sets whether the widget's clear button is visible.
A button for customizing QgsTextFormat settings.
Class used to render QgsLayout as an atlas, by iterating over the features from an associated vector ...
void toggled(bool enabled)
Emitted when atlas is enabled or disabled.
void coverageLayerChanged(QgsVectorLayer *layer)
Emitted when the coverage layer for the atlas changes.
An object for property widgets for layout items.
QgsLayoutAtlas * layoutAtlas() const
Returns the atlas for the layout, if available.
void setObject(QgsLayoutObject *object) SIP_SKIP
Links a new layout object to this QgsLayoutConfigObject.
void initializeDataDefinedButton(QgsPropertyOverrideButton *button, QgsLayoutObject::DataDefinedProperty key)
Registers a data defined button, setting up its initial value, connections and description.
QgsVectorLayer * coverageLayer() const
Returns the current layout context coverage layer (if set).
void updateDataDefinedButton(QgsPropertyOverrideButton *button)
Updates a data defined button to reflect the item's current properties.
QgsLayoutConfigObject(QWidget *parent SIP_TRANSFERTHIS, QgsLayoutObject *layoutObject)
Constructor for QgsLayoutConfigObject, linked with the specified layoutObject.
A common interface for layout designer dialogs and widgets.
virtual QgsMessageBar * messageBar()=0
Returns the designer's message bar.
Base class for frame items, which form a layout multiframe item.
QgsLayoutObject * layoutObject()
Returns the layout object associated with this widget.
void updateDataDefinedButton(QgsPropertyOverrideButton *button)
Updates a previously registered data defined button to reflect the item's current properties.
bool setItem(QgsLayoutItem *item)
Sets the current item to show in the widget.
QgsVectorLayer * coverageLayer() const
Returns the current layout context coverage layer (if set).
virtual bool setNewItem(QgsLayoutItem *item)
Attempts to update the widget to show the properties for the specified item.
void registerDataDefinedButton(QgsPropertyOverrideButton *button, QgsLayoutObject::DataDefinedProperty property)
Registers a data defined button, setting up its initial value, connections and description.
virtual void setDesignerInterface(QgsLayoutDesignerInterface *iface)
Sets the the layout designer interface in which the widget is being shown.
QgsLayoutAtlas * layoutAtlas() const
Returns the atlas for the layout (if available)
virtual void setMasterLayout(QgsMasterLayoutInterface *masterLayout)
Sets the master layout associated with the item.
QgsLayoutItemBaseWidget(QWidget *parent SIP_TRANSFERTHIS, QgsLayoutObject *layoutObject)
Constructor for QgsLayoutItemBaseWidget, linked with the specified layoutObject.
virtual void setReportTypeString(const QString &string)
Sets the string to use to describe the current report type (e.g.
void setMasterLayout(QgsMasterLayoutInterface *masterLayout)
Sets the master layout associated with the item.
void populateDataDefinedButtons()
Sets data defined button state to match item.
QgsLayoutItemPropertiesWidget(QWidget *parent, QgsLayoutItem *item)
Constructs a QgsLayoutItemPropertiesWidget with a parent and for the given layout item.
void initializeDataDefinedButtons()
Initializes data defined buttons to current atlas coverage layer.
void showFrameGroup(bool showGroup)
Determines if the frame of the group box shall be shown.
void setItem(QgsLayoutItem *item)
Sets the layout item.
QgsLayoutItem::ReferencePoint positionMode() const
Returns the position mode.
void updateVariables()
Updates the variables widget, refreshing the values of variables shown.
void showBackgroundGroup(bool showGroup)
Determines if the background of the group box shall be shown.
Base class for graphical items within a QgsLayout.
@ UndoIncrementalMove
Layout item incremental movement, e.g. as a result of a keypress.
@ UndoBackgroundColor
Background color adjustment.
@ UndoOpacity
Opacity adjustment.
@ UndoIncrementalResize
Incremental resize.
@ UndoRotation
Rotation adjustment.
@ UndoStrokeWidth
Stroke width adjustment.
@ UndoExportLayerName
Export layer name.
@ UndoSetId
Change item ID.
@ UndoStrokeColor
Stroke color adjustment.
ReferencePoint
Fixed position reference point.
@ LowerMiddle
Lower center of item.
@ MiddleLeft
Middle left of item.
@ Middle
Center of item.
@ UpperRight
Upper right corner of item.
@ LowerLeft
Lower left corner of item.
@ UpperLeft
Upper left corner of item.
@ UpperMiddle
Upper center of item.
@ MiddleRight
Middle right of item.
@ LowerRight
Lower right corner of item.
void sizePositionChanged()
Emitted when the item's size or position changes.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
Abstract base class for layout items with the ability to distribute the content to several frames (Qg...
A base class for objects which belong to a layout.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the layout object property definitions.
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
DataDefinedProperty
Data defined properties for different item types.
@ ExcludeFromExports
Exclude item from exports.
@ BackgroundColor
Item background color.
static bool propertyAssociatesWithParentMultiframe(DataDefinedProperty property)
Returns true if the specified property key is normally associated with the parent QgsLayoutMultiFrame...
void changed()
Emitted when pages are added or removed from the collection.
This class provides a method of storing points, consisting of an x and y coordinate,...
double x() const
Returns x coordinate of point.
double y() const
Returns y coordinate of point.
Qgis::LayoutUnit units() const
Returns the units for the point.
void dpiChanged()
Emitted when the context's DPI is changed.
const QgsLayoutMeasurementConverter & measurementConverter() const
Returns the layout measurement converter to be used in the layout.
void layerChanged(QgsVectorLayer *layer)
Emitted when the context's layer is changed.
QgsVectorLayer * layer() const
Returns the vector layer associated with the layout's context.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
double height() const
Returns the height of the size.
Qgis::LayoutUnit units() const
Returns the units for the size.
double width() const
Returns the width of the size.
void unitChanged(Qgis::LayoutUnit unit)
Emitted when the unit is changed.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition qgslayout.h:49
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout's render context, which stores information relating to the current ...
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout's page collection, which stores and manages page items in the layout.
void variablesChanged()
Emitted whenever the expression variables stored in the layout have been changed.
QgsLayoutReportContext & reportContext()
Returns a reference to the layout's report context, which stores information relating to the current ...
QgsProject * project() const
The project associated with the layout.
Interface for master layout type objects, such as print layouts and reports.
void opacityChanged(double opacity)
Emitted when the opacity is changed in the widget, where opacity ranges from 0.0 (transparent) to 1....
Base class for any widget that can be shown as a inline panel.
Print layout, a QgsLayout subclass for static or atlas-based layouts.
QgsLayoutAtlas * atlas()
Returns the print layout's atlas.
void nameChanged(const QString &name)
Emitted when the layout's name is changed.
void metadataChanged()
Emitted when the project's metadata is changed.
void customVariablesChanged()
Emitted whenever the expression variables stored in the project have been changed.
A button for controlling property overrides which may apply to a widget.
QgsProperty toProperty() const
Returns a QgsProperty object encapsulating the current state of the widget.
void changed()
Emitted when property definition changes.
void init(int propertyKey, const QgsProperty &property, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer=nullptr, bool auxiliaryStorageEnabled=false)
Initialize a newly constructed property button (useful if button was included in a UI layout).
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
int propertyKey() const
Returns the property key linked to the button.
A button for creating and modifying QgsSymbol settings.
void scopeChanged()
Emitted when the user has modified a scope using the widget.
Represents a vector layer which manages a vector based data sets.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:5928