QGIS API Documentation 3.41.0-Master (45a0abf3bec)
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,
45 this, [ = ] { updateDataDefinedButtons(); } );
46 }
47 if ( layoutAtlas() )
48 {
49 connect( layoutAtlas(), &QgsLayoutAtlas::toggled, this, &QgsLayoutConfigObject::updateDataDefinedButtons );
50 }
51}
52
53void QgsLayoutConfigObject::updateDataDefinedProperty()
54{
55 //match data defined button to item's data defined property
56 QgsPropertyOverrideButton *ddButton = qobject_cast<QgsPropertyOverrideButton *>( sender() );
57 if ( !ddButton )
58 {
59 return;
60 }
62
63 if ( ddButton->propertyKey() >= 0 )
64 key = static_cast< QgsLayoutObject::DataDefinedProperty >( ddButton->propertyKey() );
65
67 {
68 return;
69 }
70
71 const bool propertyAssociatesWithMultiFrame = QgsLayoutObject::propertyAssociatesWithParentMultiframe( key );
72
73 //set the data defined property and refresh the item
74 if ( propertyAssociatesWithMultiFrame )
75 {
76 if ( QgsLayoutFrame *frame = dynamic_cast< QgsLayoutFrame * >( mLayoutObject.data() ) )
77 {
78 if ( QgsLayoutMultiFrame *multiFrame = frame->multiFrame() )
79 {
80 multiFrame->dataDefinedProperties().setProperty( key, ddButton->toProperty() );
81 multiFrame->refresh();
82 }
83 }
84 else if ( QgsLayoutMultiFrame *multiFrame = dynamic_cast< QgsLayoutMultiFrame * >( mLayoutObject.data() ) )
85 {
86 multiFrame->dataDefinedProperties().setProperty( key, ddButton->toProperty() );
87 multiFrame->refresh();
88 }
89 }
90 else if ( mLayoutObject )
91 {
92 mLayoutObject->dataDefinedProperties().setProperty( key, ddButton->toProperty() );
93 mLayoutObject->refresh();
94 }
95}
96
97void QgsLayoutConfigObject::updateDataDefinedButtons()
98{
99 const QList< QgsPropertyOverrideButton * > buttons = findChildren< QgsPropertyOverrideButton * >();
100 for ( QgsPropertyOverrideButton *button : buttons )
101 {
102 button->setVectorLayer( coverageLayer() );
103 }
104}
105
107{
108 button->blockSignals( true );
109 button->init( static_cast< int >( key ), mLayoutObject->dataDefinedProperties(), QgsLayoutObject::propertyDefinitions(), coverageLayer() );
110 connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLayoutConfigObject::updateDataDefinedProperty, Qt::UniqueConnection );
111 button->registerExpressionContextGenerator( mLayoutObject );
112 button->blockSignals( false );
113}
114
116{
117 if ( !button )
118 return;
119
120 if ( button->propertyKey() < 0 || !mLayoutObject )
121 return;
122
124 const bool propertyAssociatesWithMultiFrame = QgsLayoutObject::propertyAssociatesWithParentMultiframe( key );
125
126 //set the data defined property
127 if ( propertyAssociatesWithMultiFrame )
128 {
129 if ( QgsLayoutFrame *frame = dynamic_cast< QgsLayoutFrame * >( mLayoutObject.data() ) )
130 {
131 if ( QgsLayoutMultiFrame *multiFrame = frame->multiFrame() )
132 {
133 whileBlocking( button )->setToProperty( multiFrame->dataDefinedProperties().property( key ) );
134 }
135 }
136 else if ( QgsLayoutMultiFrame *multiFrame = dynamic_cast< QgsLayoutMultiFrame * >( mLayoutObject.data() ) )
137 {
138 whileBlocking( button )->setToProperty( multiFrame->dataDefinedProperties().property( key ) );
139 }
140 }
141 else if ( mLayoutObject )
142 {
143 whileBlocking( button )->setToProperty( mLayoutObject->dataDefinedProperties().property( key ) );
144 }
145
146 // 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 )
147 connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLayoutConfigObject::updateDataDefinedProperty, Qt::UniqueConnection );
148 button->registerExpressionContextGenerator( mLayoutObject );
149}
150
152{
153 if ( !mLayoutObject )
154 {
155 return nullptr;
156 }
157
158 QgsPrintLayout *printLayout = qobject_cast< QgsPrintLayout * >( mLayoutObject->layout() );
159
160 if ( !printLayout )
161 {
162 return nullptr;
163 }
164
165 return printLayout->atlas();
166}
167
169{
170 mLayoutObject = object;
171}
172
174{
175 if ( !mLayoutObject )
176 return nullptr;
177
178 QgsLayout *layout = mLayoutObject->layout();
179 if ( !layout )
180 return nullptr;
181
182 return layout->reportContext().layer();
183}
184
185
186//
187// QgsLayoutItemBaseWidget
188//
189
191 : QgsPanelWidget( parent )
192 , mConfigObject( new QgsLayoutConfigObject( this, layoutObject ) )
193 , mObject( layoutObject )
194{
195
196}
197
202
204{
205 QgsLayoutObject *oldObject = mObject;
206 QgsLayoutConfigObject *oldConfigObject = mConfigObject;
207 // have to set new mObject/mConfigObject here, because setNewItem methods require access to them
208 mObject = item;
209 mConfigObject = new QgsLayoutConfigObject( this, mObject );
210 if ( setNewItem( item ) )
211 {
212 oldConfigObject->deleteLater();
213 return true;
214 }
215 else
216 {
217 // revert object change since it was unsuccessful
218 mObject = oldObject;
219 mConfigObject->deleteLater();
220 mConfigObject = oldConfigObject;
221 return false;
222 }
223}
224
226{
227}
228
230{
231 const auto symbolButtonWidgets = findChildren<QgsSymbolButton *>();
232 for ( QgsSymbolButton *symbolWidget : symbolButtonWidgets )
233 {
234 symbolWidget->setMessageBar( iface->messageBar() );
235 }
236 const auto fontButtonWidgets = findChildren<QgsFontButton *>();
237 for ( QgsFontButton *fontButton : fontButtonWidgets )
238 {
239 fontButton->setMessageBar( iface->messageBar() );
240 }
241}
242
247
252
257
259{
260 return mConfigObject->coverageLayer();
261}
262
264{
265 return false;
266}
267
269{
270 return mConfigObject->layoutAtlas();
271}
272
273//
274
275
276//QgsLayoutItemPropertiesWidget
277
279{
280 if ( !mItem )
281 return;
282
283 mBlockVariableUpdates = true;
284 QgsExpressionContext context = mItem->createExpressionContext();
285 mVariableEditor->setContext( &context );
286
287 // here, we prefer to make the multiframe's scope the editable one. That's because most expressions are evaluated
288 // on the multiframe subclass level, not on a frame-by-frame basis. Ideally both would be editable, but for now let's go
289 // with the most useful one.
290 const int multiFrameScopeIndex = context.indexOfScope( tr( "Multiframe Item" ) );
291 const int itemScopeIndex = context.indexOfScope( tr( "Layout Item" ) );
292 if ( multiFrameScopeIndex >= 0 )
293 mVariableEditor->setEditableScopeIndex( multiFrameScopeIndex );
294 else if ( itemScopeIndex >= 0 )
295 mVariableEditor->setEditableScopeIndex( itemScopeIndex );
296 mBlockVariableUpdates = false;
297}
298
300 : QWidget( parent )
301 , mConfigObject( new QgsLayoutConfigObject( this, item ) )
302{
303 setupUi( this );
304
305 mVariableEditor->setMinimumHeight( mVariableEditor->fontMetrics().height() * 15 );
306
307 mItemRotationSpinBox->setClearValue( 0 );
308 mStrokeUnitsComboBox->linkToWidget( mStrokeWidthSpinBox );
309 mStrokeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
310
311 QgsFilterLineEdit *exportGroupLineEdit = new QgsFilterLineEdit();
312 exportGroupLineEdit->setShowClearButton( true );
313 exportGroupLineEdit->setPlaceholderText( tr( "Not set" ) );
314 mExportGroupNameCombo->setLineEdit( exportGroupLineEdit );
315
316 mPosUnitsComboBox->linkToWidget( mXPosSpin );
317 mPosUnitsComboBox->linkToWidget( mYPosSpin );
318 mSizeUnitsComboBox->linkToWidget( mWidthSpin );
319 mSizeUnitsComboBox->linkToWidget( mHeightSpin );
320
321 mPosUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
322 mSizeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
323
324 mPosLockAspectRatio->setWidthSpinBox( mXPosSpin );
325 mPosLockAspectRatio->setHeightSpinBox( mYPosSpin );
326 mSizeLockAspectRatio->setWidthSpinBox( mWidthSpin );
327 mSizeLockAspectRatio->setHeightSpinBox( mHeightSpin );
328
329 mItemFrameColorDDBtn->registerLinkedWidget( mFrameColorButton );
330 mItemBackgroundColorDDBtn->registerLinkedWidget( mBackgroundColorButton );
331
332 connect( mFrameColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged );
333 connect( mBackgroundColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged );
334 connect( mStrokeWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged );
335 connect( mStrokeUnitsComboBox, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutItemPropertiesWidget::strokeUnitChanged );
336 connect( mFrameGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled );
337 connect( mFrameJoinStyleCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged );
338 connect( mBackgroundGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled );
339 connect( mItemIdLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished );
340 connect( mExportGroupNameCombo, &QComboBox::currentTextChanged, this, &QgsLayoutItemPropertiesWidget::exportGroupNameEditingFinished );
341 connect( mPageSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged );
342 connect( mXPosSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged );
343 connect( mYPosSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged );
344 connect( mPosUnitsComboBox, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutItemPropertiesWidget::positionUnitsChanged );
345 connect( mWidthSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged );
346 connect( mHeightSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged );
347 connect( mSizeUnitsComboBox, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutItemPropertiesWidget::sizeUnitsChanged );
348 connect( mUpperLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged );
349 connect( mUpperMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged );
350 connect( mUpperRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged );
351 connect( mMiddleLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged );
352 connect( mMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged );
353 connect( mMiddleRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged );
354 connect( mLowerLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged );
355 connect( mLowerMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged );
356 connect( mLowerRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged );
357 connect( mBlendModeCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged );
358 connect( mItemRotationSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged );
359 connect( mExcludeFromPrintsCheckBox, &QCheckBox::toggled, this, &QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled );
360
361 //make button exclusive
362 QButtonGroup *buttonGroup = new QButtonGroup( this );
363 buttonGroup->addButton( mUpperLeftRadioButton );
364 buttonGroup->addButton( mUpperMiddleRadioButton );
365 buttonGroup->addButton( mUpperRightRadioButton );
366 buttonGroup->addButton( mMiddleLeftRadioButton );
367 buttonGroup->addButton( mMiddleRadioButton );
368 buttonGroup->addButton( mMiddleRightRadioButton );
369 buttonGroup->addButton( mLowerLeftRadioButton );
370 buttonGroup->addButton( mLowerMiddleRadioButton );
371 buttonGroup->addButton( mLowerRightRadioButton );
372 buttonGroup->setExclusive( true );
373
375
376 setItem( item );
377
378 connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsLayoutItemPropertiesWidget::opacityChanged );
379
381 connect( mVariableEditor, &QgsVariableEditorWidget::scopeChanged, this, [ = ]
382 {
383 if ( !mBlockVariableUpdates )
384 QgsLayoutItemPropertiesWidget::variablesChanged();
385 } );
386 // listen out for variable edits
390
391 if ( item->layout() )
392 {
396 }
397}
398
400{
401 mBackgroundGroupBox->setVisible( showGroup );
402}
403
405{
406 mFrameGroupBox->setVisible( showGroup );
407}
408
410{
411 if ( mItem )
412 {
413 disconnect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
414 disconnect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
415 }
416 mItem = item;
417 if ( mItem )
418 {
419 connect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
420 connect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
421 }
422
423 mConfigObject->setObject( mItem );
424
425 setValuesForGuiElements();
426}
427
429{
430 if ( QgsPrintLayout *printLayout = dynamic_cast< QgsPrintLayout * >( masterLayout ) )
431 {
434 }
435}
436
437//slots
438
439void QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged( const QColor &newFrameColor )
440{
441 if ( !mItem )
442 {
443 return;
444 }
445 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Color" ), QgsLayoutItem::UndoStrokeColor );
446 mItem->setFrameStrokeColor( newFrameColor );
447 mItem->layout()->undoStack()->endCommand();
448 mItem->update();
449}
450
451void QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged( const QColor &newBackgroundColor )
452{
453 if ( !mItem )
454 {
455 return;
456 }
457 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Background Color" ), QgsLayoutItem::UndoBackgroundColor );
458 mItem->setBackgroundColor( newBackgroundColor );
459 mItem->layout()->undoStack()->endCommand();
460 mItem->invalidateCache();
461}
462
463void QgsLayoutItemPropertiesWidget::changeItemPosition()
464{
465 if ( !mItem )
466 return;
467
468 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Move Item" ), QgsLayoutItem::UndoIncrementalMove );
469
470 const QgsLayoutPoint point( mXPosSpin->value(), mYPosSpin->value(), mPosUnitsComboBox->unit() );
471 mItem->attemptMove( point, true, false, mPageSpinBox->value() - 1 );
472
473 mItem->layout()->undoStack()->endCommand();
474}
475
476void QgsLayoutItemPropertiesWidget::changeItemReference( QgsLayoutItem::ReferencePoint point )
477{
478 if ( !mItem )
479 return;
480
481 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item Reference" ) );
482 mItem->setReferencePoint( point );
483 mItem->layout()->undoStack()->endCommand();
484}
485
486void QgsLayoutItemPropertiesWidget::changeItemSize()
487{
488 if ( !mItem )
489 return;
490
491 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Resize Item" ), QgsLayoutItem::UndoIncrementalResize );
492
493 const QgsLayoutSize size( mWidthSpin->value(), mHeightSpin->value(), mSizeUnitsComboBox->unit() );
494 mItem->attemptResize( size );
495
496 mItem->layout()->undoStack()->endCommand();
497}
498
499void QgsLayoutItemPropertiesWidget::variablesChanged()
500{
501 if ( !mItem )
502 return;
503
504 if ( QgsLayoutFrame *frame = qobject_cast< QgsLayoutFrame * >( mItem ) )
505 {
506 if ( QgsLayoutMultiFrame *mf = frame->multiFrame() )
507 {
508 QgsExpressionContextUtils::setLayoutMultiFrameVariables( mf, mVariableEditor->variablesInActiveScope() );
509 }
510 }
511 else
512 {
513 QgsExpressionContextUtils::setLayoutItemVariables( mItem, mVariableEditor->variablesInActiveScope() );
514 }
515}
516
518{
519 if ( mUpperLeftRadioButton->isChecked() )
520 {
522 }
523 else if ( mUpperMiddleRadioButton->isChecked() )
524 {
526 }
527 else if ( mUpperRightRadioButton->isChecked() )
528 {
530 }
531 else if ( mMiddleLeftRadioButton->isChecked() )
532 {
534 }
535 else if ( mMiddleRadioButton->isChecked() )
536 {
538 }
539 else if ( mMiddleRightRadioButton->isChecked() )
540 {
542 }
543 else if ( mLowerLeftRadioButton->isChecked() )
544 {
546 }
547 else if ( mLowerMiddleRadioButton->isChecked() )
548 {
550 }
551 else if ( mLowerRightRadioButton->isChecked() )
552 {
554 }
556}
557
558void QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged( double d )
559{
560 if ( !mItem )
561 {
562 return;
563 }
564
565 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
566 mItem->setFrameStrokeWidth( QgsLayoutMeasurement( d, mStrokeUnitsComboBox->unit() ) );
567 mItem->layout()->undoStack()->endCommand();
568}
569
570void QgsLayoutItemPropertiesWidget::strokeUnitChanged( Qgis::LayoutUnit unit )
571{
572 if ( !mItem )
573 {
574 return;
575 }
576
577 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
578 mItem->setFrameStrokeWidth( QgsLayoutMeasurement( mStrokeWidthSpinBox->value(), unit ) );
579 mItem->layout()->undoStack()->endCommand();
580}
581
582void QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged( int index )
583{
584 Q_UNUSED( index )
585 if ( !mItem )
586 {
587 return;
588 }
589
590 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Join Style" ) );
591 mItem->setFrameJoinStyle( mFrameJoinStyleCombo->penJoinStyle() );
592 mItem->layout()->undoStack()->endCommand();
593}
594
595void QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled( bool state )
596{
597 if ( !mItem )
598 {
599 return;
600 }
601
602 mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Frame" ) : tr( "Disable Frame" ) );
603 mItem->setFrameEnabled( state );
604 mItem->update();
605 mItem->layout()->undoStack()->endCommand();
606}
607
608void QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled( bool state )
609{
610 if ( !mItem )
611 {
612 return;
613 }
614
615 mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Background" ) : tr( "Disable Background" ) );
616 mItem->setBackgroundEnabled( state );
617 mItem->layout()->undoStack()->endCommand();
618 mItem->invalidateCache();
619}
620
621
622void QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements()
623{
624 if ( !mItem )
625 {
626 return;
627 }
628
629 auto block = [ = ]( bool blocked )
630 {
631 mXPosSpin->blockSignals( blocked );
632 mYPosSpin->blockSignals( blocked );
633 mPosUnitsComboBox->blockSignals( blocked );
634 mWidthSpin->blockSignals( blocked );
635 mHeightSpin->blockSignals( blocked );
636 mSizeUnitsComboBox->blockSignals( blocked );
637 mUpperLeftRadioButton->blockSignals( blocked );
638 mUpperMiddleRadioButton->blockSignals( blocked );
639 mUpperRightRadioButton->blockSignals( blocked );
640 mMiddleLeftRadioButton->blockSignals( blocked );
641 mMiddleRadioButton->blockSignals( blocked );
642 mMiddleRightRadioButton->blockSignals( blocked );
643 mLowerLeftRadioButton->blockSignals( blocked );
644 mLowerMiddleRadioButton->blockSignals( blocked );
645 mLowerRightRadioButton->blockSignals( blocked );
646 mPageSpinBox->blockSignals( blocked );
647 };
648 block( true );
649
650 const QgsLayoutPoint point = mItem->pagePositionWithUnits();
651
652 if ( !mFreezeXPosSpin )
653 mXPosSpin->setValue( point.x() );
654 if ( !mFreezeYPosSpin )
655 mYPosSpin->setValue( point.y() );
656 mPosUnitsComboBox->setUnit( point.units() );
657
658 switch ( mItem->referencePoint() )
659 {
661 {
662 mUpperLeftRadioButton->setChecked( true );
663 break;
664 }
665
667 {
668 mUpperMiddleRadioButton->setChecked( true );
669 break;
670 }
671
673 {
674 mUpperRightRadioButton->setChecked( true );
675 break;
676 }
677
679 {
680 mMiddleLeftRadioButton->setChecked( true );
681 break;
682 }
683
685 {
686 mMiddleRadioButton->setChecked( true );
687 break;
688 }
689
691 {
692 mMiddleRightRadioButton->setChecked( true );
693 break;
694 }
695
697 {
698 mLowerLeftRadioButton->setChecked( true );
699 break;
700 }
701
703 {
704 mLowerMiddleRadioButton->setChecked( true );
705 break;
706 }
707
709 {
710 mLowerRightRadioButton->setChecked( true );
711 break;
712 }
713 }
714
715 const QgsLayoutSize size = mItem->sizeWithUnits();
716 if ( !mFreezeWidthSpin )
717 mWidthSpin->setValue( size.width() );
718 if ( !mFreezeHeightSpin )
719 mHeightSpin->setValue( size.height() );
720
721 mSizeUnitsComboBox->setUnit( size.units() );
722
723 mSizeLockAspectRatio->resetRatio();
724 mPosLockAspectRatio->resetRatio();
725
726 if ( !mFreezePageSpin )
727 mPageSpinBox->setValue( mItem->page() + 1 );
728
729 block( false );
730}
731
732void QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements()
733{
734 if ( !mItem )
735 {
736 return;
737 }
738
739 whileBlocking( mBackgroundColorButton )->setColor( mItem->backgroundColor( false ) );
740 whileBlocking( mFrameColorButton )->setColor( mItem->frameStrokeColor() );
741 whileBlocking( mStrokeUnitsComboBox )->setUnit( mItem->frameStrokeWidth().units() );
742 whileBlocking( mStrokeWidthSpinBox )->setValue( mItem->frameStrokeWidth().length() );
743 whileBlocking( mFrameJoinStyleCombo )->setPenJoinStyle( mItem->frameJoinStyle() );
744 whileBlocking( mItemIdLineEdit )->setText( mItem->id() );
745 whileBlocking( mFrameGroupBox )->setChecked( mItem->frameEnabled() );
746 whileBlocking( mBackgroundGroupBox )->setChecked( mItem->hasBackground() );
747 whileBlocking( mBlendModeCombo )->setBlendMode( mItem->blendMode() );
748 whileBlocking( mOpacityWidget )->setOpacity( mItem->itemOpacity() );
749 whileBlocking( mItemRotationSpinBox )->setValue( mItem->itemRotation() );
750 whileBlocking( mExcludeFromPrintsCheckBox )->setChecked( mItem->excludeFromExports() );
751 whileBlocking( mExportGroupNameCombo )->setCurrentText( mItem->customProperty( QStringLiteral( "pdfExportGroup" ) ).toString() );
752}
753
767
769{
770 const QList< QgsPropertyOverrideButton * > buttons = findChildren< QgsPropertyOverrideButton * >();
771 for ( QgsPropertyOverrideButton *button : buttons )
772 {
773 mConfigObject->updateDataDefinedButton( button );
774 }
775}
776
777void QgsLayoutItemPropertiesWidget::setValuesForGuiElements()
778{
779 if ( !mItem )
780 {
781 return;
782 }
783
784 mBackgroundColorButton->setColorDialogTitle( tr( "Select Background Color" ) );
785 mBackgroundColorButton->setAllowOpacity( true );
786 mBackgroundColorButton->setContext( QStringLiteral( "composer" ) );
787 mFrameColorButton->setColorDialogTitle( tr( "Select Frame Color" ) );
788 mFrameColorButton->setAllowOpacity( true );
789 mFrameColorButton->setContext( QStringLiteral( "composer" ) );
790
791 if ( QgsLayout *layout = mItem->layout() )
792 {
793 // collect export groups from layout, so that we can offer auto completion in the PDF export group combo
794 QList< QgsLayoutItem * > items;
795 layout->layoutItems( items );
796 QStringList existingGroups;
797 for ( const QgsLayoutItem *item : std::as_const( items ) )
798 {
799 const QString groupName = item->customProperty( QStringLiteral( "pdfExportGroup" ) ).toString();
800 if ( !groupName.isEmpty() && !existingGroups.contains( groupName ) )
801 existingGroups.append( groupName );
802 }
803
804 std::sort( existingGroups.begin(), existingGroups.end(), [ = ]( const QString & a, const QString & b ) -> bool
805 {
806 return a.localeAwareCompare( b ) < 0;
807 } );
808
809 whileBlocking( mExportGroupNameCombo )->clear();
810 whileBlocking( mExportGroupNameCombo )->addItems( existingGroups );
811 }
812
813 setValuesForGuiPositionElements();
814 setValuesForGuiNonPositionElements();
816
818}
819
820void QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged( int index )
821{
822 Q_UNUSED( index )
823 if ( mItem )
824 {
825 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Blend Mode" ) );
826 mItem->setBlendMode( mBlendModeCombo->blendMode() );
827 mItem->layout()->undoStack()->endCommand();
828 }
829}
830
831void QgsLayoutItemPropertiesWidget::opacityChanged( double value )
832{
833 if ( mItem )
834 {
835 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Opacity" ), QgsLayoutItem::UndoOpacity );
836 mItem->setItemOpacity( value );
837 mItem->layout()->undoStack()->endCommand();
838 }
839}
840
841void QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished()
842{
843 if ( mItem )
844 {
845 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item ID" ), QgsLayoutItem::UndoSetId );
846 mItem->setId( mItemIdLineEdit->text() );
847 mItemIdLineEdit->setText( mItem->id() );
848 mItem->layout()->undoStack()->endCommand();
849 }
850}
851
852void QgsLayoutItemPropertiesWidget::exportGroupNameEditingFinished()
853{
854 if ( mItem )
855 {
856 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Export Group Name" ), QgsLayoutItem::UndoExportLayerName );
857 mItem->setCustomProperty( QStringLiteral( "pdfExportGroup" ), mExportGroupNameCombo->currentText() );
858 mItem->layout()->undoStack()->endCommand();
859 }
860}
861
862void QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged( int )
863{
864 mFreezePageSpin = true;
865 changeItemPosition();
866 mFreezePageSpin = false;
867}
868
869void QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged( double )
870{
871 mFreezeXPosSpin = true;
872 changeItemPosition();
873 mFreezeXPosSpin = false;
874}
875
876void QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged( double )
877{
878 mFreezeYPosSpin = true;
879 changeItemPosition();
880 mFreezeYPosSpin = false;
881}
882
883void QgsLayoutItemPropertiesWidget::positionUnitsChanged( Qgis::LayoutUnit )
884{
885 changeItemPosition();
886}
887
888void QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged( double )
889{
890 mFreezeWidthSpin = true;
891 changeItemSize();
892 mFreezeWidthSpin = false;
893}
894
895void QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged( double )
896{
897 mFreezeHeightSpin = true;
898 changeItemSize();
899 mFreezeHeightSpin = false;
900}
901
902void QgsLayoutItemPropertiesWidget::sizeUnitsChanged( Qgis::LayoutUnit )
903{
904 changeItemSize();
905}
906
907void QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged( bool state )
908{
909 if ( !state )
910 return;
911
912 if ( mItem )
913 {
914 changeItemReference( QgsLayoutItem::UpperLeft );
915 }
916 setValuesForGuiPositionElements();
917}
918
919void QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged( bool state )
920{
921 if ( !state )
922 return;
923 if ( mItem )
924 {
925 changeItemReference( QgsLayoutItem::UpperMiddle );
926 }
927 setValuesForGuiPositionElements();
928}
929
930void QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged( bool state )
931{
932 if ( !state )
933 return;
934 if ( mItem )
935 {
936 changeItemReference( QgsLayoutItem::UpperRight );
937 }
938 setValuesForGuiPositionElements();
939}
940
941void QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged( bool state )
942{
943 if ( !state )
944 return;
945 if ( mItem )
946 {
947 changeItemReference( QgsLayoutItem::MiddleLeft );
948 }
949 setValuesForGuiPositionElements();
950}
951
952void QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged( bool state )
953{
954 if ( !state )
955 return;
956 if ( mItem )
957 {
958 changeItemReference( QgsLayoutItem::Middle );
959 }
960 setValuesForGuiPositionElements();
961}
962
963void QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged( bool state )
964{
965 if ( !state )
966 return;
967 if ( mItem )
968 {
969 changeItemReference( QgsLayoutItem::MiddleRight );
970 }
971 setValuesForGuiPositionElements();
972}
973
974void QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged( bool state )
975{
976 if ( !state )
977 return;
978 if ( mItem )
979 {
980 changeItemReference( QgsLayoutItem::LowerLeft );
981 }
982 setValuesForGuiPositionElements();
983}
984
985void QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged( bool state )
986{
987 if ( !state )
988 return;
989 if ( mItem )
990 {
991 changeItemReference( QgsLayoutItem::LowerMiddle );
992 }
993 setValuesForGuiPositionElements();
994}
995
996void QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged( bool state )
997{
998 if ( !state )
999 return;
1000 if ( mItem )
1001 {
1002 changeItemReference( QgsLayoutItem::LowerRight );
1003 }
1004 setValuesForGuiPositionElements();
1005}
1006
1007void QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged( double val )
1008{
1009 if ( mItem )
1010 {
1011 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Rotate" ), QgsLayoutItem::UndoRotation );
1012 mItem->setItemRotation( val, true );
1013 mItem->update();
1014 mItem->layout()->undoStack()->endCommand();
1015 }
1016}
1017
1018void QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled( bool checked )
1019{
1020 if ( mItem )
1021 {
1022 mItem->layout()->undoStack()->beginCommand( mItem, checked ? tr( "Exclude from Exports" ) : tr( "Include in Exports" ) );
1023 mItem->setExcludeFromExports( checked );
1024 mItem->layout()->undoStack()->endCommand();
1025 }
1026}
LayoutUnit
Layout measurement units.
Definition qgis.h:4867
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:5862