QGIS API Documentation 3.40.0-Bratislava (b56115d8743)
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"
18#include "qgslayout.h"
19#include "qgsproject.h"
20#include "qgslayoutundostack.h"
21#include "qgsprintlayout.h"
22#include "qgslayoutatlas.h"
24#include "qgslayoutframe.h"
25#include "qgssymbolbutton.h"
26#include "qgsfontbutton.h"
29#include "qgslayoutmultiframe.h"
30#include "qgsfilterlineedit.h"
31#include <QButtonGroup>
32
33//
34// QgsLayoutConfigObject
35//
36
38 : QObject( parent )
39 , mLayoutObject( layoutObject )
40{
41 if ( mLayoutObject->layout() )
42 {
43 connect( &mLayoutObject->layout()->reportContext(), &QgsLayoutReportContext::layerChanged,
44 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}
196
201
203{
204 QgsLayoutObject *oldObject = mObject;
205 QgsLayoutConfigObject *oldConfigObject = mConfigObject;
206 // have to set new mObject/mConfigObject here, because setNewItem methods require access to them
207 mObject = item;
208 mConfigObject = new QgsLayoutConfigObject( this, mObject );
209 if ( setNewItem( item ) )
210 {
211 oldConfigObject->deleteLater();
212 return true;
213 }
214 else
215 {
216 // revert object change since it was unsuccessful
217 mObject = oldObject;
218 mConfigObject->deleteLater();
219 mConfigObject = oldConfigObject;
220 return false;
221 }
222}
223
225{
226}
227
229{
230 const auto symbolButtonWidgets = findChildren<QgsSymbolButton *>();
231 for ( QgsSymbolButton *symbolWidget : symbolButtonWidgets )
232 {
233 symbolWidget->setMessageBar( iface->messageBar() );
234 }
235 const auto fontButtonWidgets = findChildren<QgsFontButton *>();
236 for ( QgsFontButton *fontButton : fontButtonWidgets )
237 {
238 fontButton->setMessageBar( iface->messageBar() );
239 }
240}
241
246
251
256
258{
259 return mConfigObject->coverageLayer();
260}
261
263{
264 return false;
265}
266
268{
269 return mConfigObject->layoutAtlas();
270}
271
272//
273
274
275//QgsLayoutItemPropertiesWidget
276
278{
279 if ( !mItem )
280 return;
281
282 mBlockVariableUpdates = true;
283 QgsExpressionContext context = mItem->createExpressionContext();
284 mVariableEditor->setContext( &context );
285
286 // here, we prefer to make the multiframe's scope the editable one. That's because most expressions are evaluated
287 // on the multiframe subclass level, not on a frame-by-frame basis. Ideally both would be editable, but for now let's go
288 // with the most useful one.
289 const int multiFrameScopeIndex = context.indexOfScope( tr( "Multiframe Item" ) );
290 const int itemScopeIndex = context.indexOfScope( tr( "Layout Item" ) );
291 if ( multiFrameScopeIndex >= 0 )
292 mVariableEditor->setEditableScopeIndex( multiFrameScopeIndex );
293 else if ( itemScopeIndex >= 0 )
294 mVariableEditor->setEditableScopeIndex( itemScopeIndex );
295 mBlockVariableUpdates = false;
296}
297
299 : QWidget( parent )
300 , mConfigObject( new QgsLayoutConfigObject( this, item ) )
301{
302 setupUi( this );
303
304 mVariableEditor->setMinimumHeight( mVariableEditor->fontMetrics().height() * 15 );
305
306 mItemRotationSpinBox->setClearValue( 0 );
307 mStrokeUnitsComboBox->linkToWidget( mStrokeWidthSpinBox );
308 mStrokeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
309
310 QgsFilterLineEdit *exportGroupLineEdit = new QgsFilterLineEdit();
311 exportGroupLineEdit->setShowClearButton( true );
312 exportGroupLineEdit->setPlaceholderText( tr( "Not set" ) );
313 mExportGroupNameCombo->setLineEdit( exportGroupLineEdit );
314
315 mPosUnitsComboBox->linkToWidget( mXPosSpin );
316 mPosUnitsComboBox->linkToWidget( mYPosSpin );
317 mSizeUnitsComboBox->linkToWidget( mWidthSpin );
318 mSizeUnitsComboBox->linkToWidget( mHeightSpin );
319
320 mPosUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
321 mSizeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
322
323 mPosLockAspectRatio->setWidthSpinBox( mXPosSpin );
324 mPosLockAspectRatio->setHeightSpinBox( mYPosSpin );
325 mSizeLockAspectRatio->setWidthSpinBox( mWidthSpin );
326 mSizeLockAspectRatio->setHeightSpinBox( mHeightSpin );
327
328 mItemFrameColorDDBtn->registerLinkedWidget( mFrameColorButton );
329 mItemBackgroundColorDDBtn->registerLinkedWidget( mBackgroundColorButton );
330
331 connect( mFrameColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged );
332 connect( mBackgroundColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged );
333 connect( mStrokeWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged );
334 connect( mStrokeUnitsComboBox, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutItemPropertiesWidget::strokeUnitChanged );
335 connect( mFrameGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled );
336 connect( mFrameJoinStyleCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged );
337 connect( mBackgroundGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled );
338 connect( mItemIdLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished );
339 connect( mExportGroupNameCombo, &QComboBox::currentTextChanged, this, &QgsLayoutItemPropertiesWidget::exportGroupNameEditingFinished );
340 connect( mPageSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged );
341 connect( mXPosSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged );
342 connect( mYPosSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged );
343 connect( mPosUnitsComboBox, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutItemPropertiesWidget::positionUnitsChanged );
344 connect( mWidthSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged );
345 connect( mHeightSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged );
346 connect( mSizeUnitsComboBox, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutItemPropertiesWidget::sizeUnitsChanged );
347 connect( mUpperLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged );
348 connect( mUpperMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged );
349 connect( mUpperRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged );
350 connect( mMiddleLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged );
351 connect( mMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged );
352 connect( mMiddleRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged );
353 connect( mLowerLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged );
354 connect( mLowerMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged );
355 connect( mLowerRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged );
356 connect( mBlendModeCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged );
357 connect( mItemRotationSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged );
358 connect( mExcludeFromPrintsCheckBox, &QCheckBox::toggled, this, &QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled );
359
360 //make button exclusive
361 QButtonGroup *buttonGroup = new QButtonGroup( this );
362 buttonGroup->addButton( mUpperLeftRadioButton );
363 buttonGroup->addButton( mUpperMiddleRadioButton );
364 buttonGroup->addButton( mUpperRightRadioButton );
365 buttonGroup->addButton( mMiddleLeftRadioButton );
366 buttonGroup->addButton( mMiddleRadioButton );
367 buttonGroup->addButton( mMiddleRightRadioButton );
368 buttonGroup->addButton( mLowerLeftRadioButton );
369 buttonGroup->addButton( mLowerMiddleRadioButton );
370 buttonGroup->addButton( mLowerRightRadioButton );
371 buttonGroup->setExclusive( true );
372
374
375 setItem( item );
376
377 connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsLayoutItemPropertiesWidget::opacityChanged );
378
380 connect( mVariableEditor, &QgsVariableEditorWidget::scopeChanged, this, [ = ]
381 {
382 if ( !mBlockVariableUpdates )
383 QgsLayoutItemPropertiesWidget::variablesChanged();
384 } );
385 // listen out for variable edits
389
390 if ( item->layout() )
391 {
395 }
396}
397
399{
400 mBackgroundGroupBox->setVisible( showGroup );
401}
402
404{
405 mFrameGroupBox->setVisible( showGroup );
406}
407
409{
410 if ( mItem )
411 {
412 disconnect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
413 disconnect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
414 }
415 mItem = item;
416 if ( mItem )
417 {
418 connect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
419 connect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
420 }
421
422 mConfigObject->setObject( mItem );
423
424 setValuesForGuiElements();
425}
426
428{
429 if ( QgsPrintLayout *printLayout = dynamic_cast< QgsPrintLayout * >( masterLayout ) )
430 {
433 }
434}
435
436//slots
437
438void QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged( const QColor &newFrameColor )
439{
440 if ( !mItem )
441 {
442 return;
443 }
444 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Color" ), QgsLayoutItem::UndoStrokeColor );
445 mItem->setFrameStrokeColor( newFrameColor );
446 mItem->layout()->undoStack()->endCommand();
447 mItem->update();
448}
449
450void QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged( const QColor &newBackgroundColor )
451{
452 if ( !mItem )
453 {
454 return;
455 }
456 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Background Color" ), QgsLayoutItem::UndoBackgroundColor );
457 mItem->setBackgroundColor( newBackgroundColor );
458 mItem->layout()->undoStack()->endCommand();
459 mItem->invalidateCache();
460}
461
462void QgsLayoutItemPropertiesWidget::changeItemPosition()
463{
464 if ( !mItem )
465 return;
466
467 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Move Item" ), QgsLayoutItem::UndoIncrementalMove );
468
469 const QgsLayoutPoint point( mXPosSpin->value(), mYPosSpin->value(), mPosUnitsComboBox->unit() );
470 mItem->attemptMove( point, true, false, mPageSpinBox->value() - 1 );
471
472 mItem->layout()->undoStack()->endCommand();
473}
474
475void QgsLayoutItemPropertiesWidget::changeItemReference( QgsLayoutItem::ReferencePoint point )
476{
477 if ( !mItem )
478 return;
479
480 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item Reference" ) );
481 mItem->setReferencePoint( point );
482 mItem->layout()->undoStack()->endCommand();
483}
484
485void QgsLayoutItemPropertiesWidget::changeItemSize()
486{
487 if ( !mItem )
488 return;
489
490 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Resize Item" ), QgsLayoutItem::UndoIncrementalResize );
491
492 const QgsLayoutSize size( mWidthSpin->value(), mHeightSpin->value(), mSizeUnitsComboBox->unit() );
493 mItem->attemptResize( size );
494
495 mItem->layout()->undoStack()->endCommand();
496}
497
498void QgsLayoutItemPropertiesWidget::variablesChanged()
499{
500 if ( !mItem )
501 return;
502
503 if ( QgsLayoutFrame *frame = qobject_cast< QgsLayoutFrame * >( mItem ) )
504 {
505 if ( QgsLayoutMultiFrame *mf = frame->multiFrame() )
506 {
507 QgsExpressionContextUtils::setLayoutMultiFrameVariables( mf, mVariableEditor->variablesInActiveScope() );
508 }
509 }
510 else
511 {
512 QgsExpressionContextUtils::setLayoutItemVariables( mItem, mVariableEditor->variablesInActiveScope() );
513 }
514}
515
517{
518 if ( mUpperLeftRadioButton->isChecked() )
519 {
521 }
522 else if ( mUpperMiddleRadioButton->isChecked() )
523 {
525 }
526 else if ( mUpperRightRadioButton->isChecked() )
527 {
529 }
530 else if ( mMiddleLeftRadioButton->isChecked() )
531 {
533 }
534 else if ( mMiddleRadioButton->isChecked() )
535 {
537 }
538 else if ( mMiddleRightRadioButton->isChecked() )
539 {
541 }
542 else if ( mLowerLeftRadioButton->isChecked() )
543 {
545 }
546 else if ( mLowerMiddleRadioButton->isChecked() )
547 {
549 }
550 else if ( mLowerRightRadioButton->isChecked() )
551 {
553 }
555}
556
557void QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged( double d )
558{
559 if ( !mItem )
560 {
561 return;
562 }
563
564 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
565 mItem->setFrameStrokeWidth( QgsLayoutMeasurement( d, mStrokeUnitsComboBox->unit() ) );
566 mItem->layout()->undoStack()->endCommand();
567}
568
569void QgsLayoutItemPropertiesWidget::strokeUnitChanged( Qgis::LayoutUnit unit )
570{
571 if ( !mItem )
572 {
573 return;
574 }
575
576 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
577 mItem->setFrameStrokeWidth( QgsLayoutMeasurement( mStrokeWidthSpinBox->value(), unit ) );
578 mItem->layout()->undoStack()->endCommand();
579}
580
581void QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged( int index )
582{
583 Q_UNUSED( index )
584 if ( !mItem )
585 {
586 return;
587 }
588
589 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Join Style" ) );
590 mItem->setFrameJoinStyle( mFrameJoinStyleCombo->penJoinStyle() );
591 mItem->layout()->undoStack()->endCommand();
592}
593
594void QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled( bool state )
595{
596 if ( !mItem )
597 {
598 return;
599 }
600
601 mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Frame" ) : tr( "Disable Frame" ) );
602 mItem->setFrameEnabled( state );
603 mItem->update();
604 mItem->layout()->undoStack()->endCommand();
605}
606
607void QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled( bool state )
608{
609 if ( !mItem )
610 {
611 return;
612 }
613
614 mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Background" ) : tr( "Disable Background" ) );
615 mItem->setBackgroundEnabled( state );
616 mItem->layout()->undoStack()->endCommand();
617 mItem->invalidateCache();
618}
619
620
621void QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements()
622{
623 if ( !mItem )
624 {
625 return;
626 }
627
628 auto block = [ = ]( bool blocked )
629 {
630 mXPosSpin->blockSignals( blocked );
631 mYPosSpin->blockSignals( blocked );
632 mPosUnitsComboBox->blockSignals( blocked );
633 mWidthSpin->blockSignals( blocked );
634 mHeightSpin->blockSignals( blocked );
635 mSizeUnitsComboBox->blockSignals( blocked );
636 mUpperLeftRadioButton->blockSignals( blocked );
637 mUpperMiddleRadioButton->blockSignals( blocked );
638 mUpperRightRadioButton->blockSignals( blocked );
639 mMiddleLeftRadioButton->blockSignals( blocked );
640 mMiddleRadioButton->blockSignals( blocked );
641 mMiddleRightRadioButton->blockSignals( blocked );
642 mLowerLeftRadioButton->blockSignals( blocked );
643 mLowerMiddleRadioButton->blockSignals( blocked );
644 mLowerRightRadioButton->blockSignals( blocked );
645 mPageSpinBox->blockSignals( blocked );
646 };
647 block( true );
648
649 const QgsLayoutPoint point = mItem->pagePositionWithUnits();
650
651 if ( !mFreezeXPosSpin )
652 mXPosSpin->setValue( point.x() );
653 if ( !mFreezeYPosSpin )
654 mYPosSpin->setValue( point.y() );
655 mPosUnitsComboBox->setUnit( point.units() );
656
657 switch ( mItem->referencePoint() )
658 {
660 {
661 mUpperLeftRadioButton->setChecked( true );
662 break;
663 }
664
666 {
667 mUpperMiddleRadioButton->setChecked( true );
668 break;
669 }
670
672 {
673 mUpperRightRadioButton->setChecked( true );
674 break;
675 }
676
678 {
679 mMiddleLeftRadioButton->setChecked( true );
680 break;
681 }
682
684 {
685 mMiddleRadioButton->setChecked( true );
686 break;
687 }
688
690 {
691 mMiddleRightRadioButton->setChecked( true );
692 break;
693 }
694
696 {
697 mLowerLeftRadioButton->setChecked( true );
698 break;
699 }
700
702 {
703 mLowerMiddleRadioButton->setChecked( true );
704 break;
705 }
706
708 {
709 mLowerRightRadioButton->setChecked( true );
710 break;
711 }
712 }
713
714 const QgsLayoutSize size = mItem->sizeWithUnits();
715 if ( !mFreezeWidthSpin )
716 mWidthSpin->setValue( size.width() );
717 if ( !mFreezeHeightSpin )
718 mHeightSpin->setValue( size.height() );
719
720 mSizeUnitsComboBox->setUnit( size.units() );
721
722 mSizeLockAspectRatio->resetRatio();
723 mPosLockAspectRatio->resetRatio();
724
725 if ( !mFreezePageSpin )
726 mPageSpinBox->setValue( mItem->page() + 1 );
727
728 block( false );
729}
730
731void QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements()
732{
733 if ( !mItem )
734 {
735 return;
736 }
737
738 whileBlocking( mBackgroundColorButton )->setColor( mItem->backgroundColor( false ) );
739 whileBlocking( mFrameColorButton )->setColor( mItem->frameStrokeColor() );
740 whileBlocking( mStrokeUnitsComboBox )->setUnit( mItem->frameStrokeWidth().units() );
741 whileBlocking( mStrokeWidthSpinBox )->setValue( mItem->frameStrokeWidth().length() );
742 whileBlocking( mFrameJoinStyleCombo )->setPenJoinStyle( mItem->frameJoinStyle() );
743 whileBlocking( mItemIdLineEdit )->setText( mItem->id() );
744 whileBlocking( mFrameGroupBox )->setChecked( mItem->frameEnabled() );
745 whileBlocking( mBackgroundGroupBox )->setChecked( mItem->hasBackground() );
746 whileBlocking( mBlendModeCombo )->setBlendMode( mItem->blendMode() );
747 whileBlocking( mOpacityWidget )->setOpacity( mItem->itemOpacity() );
748 whileBlocking( mItemRotationSpinBox )->setValue( mItem->itemRotation() );
749 whileBlocking( mExcludeFromPrintsCheckBox )->setChecked( mItem->excludeFromExports() );
750 whileBlocking( mExportGroupNameCombo )->setCurrentText( mItem->customProperty( QStringLiteral( "pdfExportGroup" ) ).toString() );
751}
752
766
768{
769 const QList< QgsPropertyOverrideButton * > buttons = findChildren< QgsPropertyOverrideButton * >();
770 for ( QgsPropertyOverrideButton *button : buttons )
771 {
772 mConfigObject->updateDataDefinedButton( button );
773 }
774}
775
776void QgsLayoutItemPropertiesWidget::setValuesForGuiElements()
777{
778 if ( !mItem )
779 {
780 return;
781 }
782
783 mBackgroundColorButton->setColorDialogTitle( tr( "Select Background Color" ) );
784 mBackgroundColorButton->setAllowOpacity( true );
785 mBackgroundColorButton->setContext( QStringLiteral( "composer" ) );
786 mFrameColorButton->setColorDialogTitle( tr( "Select Frame Color" ) );
787 mFrameColorButton->setAllowOpacity( true );
788 mFrameColorButton->setContext( QStringLiteral( "composer" ) );
789
790 if ( QgsLayout *layout = mItem->layout() )
791 {
792 // collect export groups from layout, so that we can offer auto completion in the PDF export group combo
793 QList< QgsLayoutItem * > items;
794 layout->layoutItems( items );
795 QStringList existingGroups;
796 for ( const QgsLayoutItem *item : std::as_const( items ) )
797 {
798 const QString groupName = item->customProperty( QStringLiteral( "pdfExportGroup" ) ).toString();
799 if ( !groupName.isEmpty() && !existingGroups.contains( groupName ) )
800 existingGroups.append( groupName );
801 }
802
803 std::sort( existingGroups.begin(), existingGroups.end(), [ = ]( const QString & a, const QString & b ) -> bool
804 {
805 return a.localeAwareCompare( b ) < 0;
806 } );
807
808 whileBlocking( mExportGroupNameCombo )->clear();
809 whileBlocking( mExportGroupNameCombo )->addItems( existingGroups );
810 }
811
812 setValuesForGuiPositionElements();
813 setValuesForGuiNonPositionElements();
815
817}
818
819void QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged( int index )
820{
821 Q_UNUSED( index )
822 if ( mItem )
823 {
824 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Blend Mode" ) );
825 mItem->setBlendMode( mBlendModeCombo->blendMode() );
826 mItem->layout()->undoStack()->endCommand();
827 }
828}
829
830void QgsLayoutItemPropertiesWidget::opacityChanged( double value )
831{
832 if ( mItem )
833 {
834 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Opacity" ), QgsLayoutItem::UndoOpacity );
835 mItem->setItemOpacity( value );
836 mItem->layout()->undoStack()->endCommand();
837 }
838}
839
840void QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished()
841{
842 if ( mItem )
843 {
844 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item ID" ), QgsLayoutItem::UndoSetId );
845 mItem->setId( mItemIdLineEdit->text() );
846 mItemIdLineEdit->setText( mItem->id() );
847 mItem->layout()->undoStack()->endCommand();
848 }
849}
850
851void QgsLayoutItemPropertiesWidget::exportGroupNameEditingFinished()
852{
853 if ( mItem )
854 {
855 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Export Group Name" ), QgsLayoutItem::UndoExportLayerName );
856 mItem->setCustomProperty( QStringLiteral( "pdfExportGroup" ), mExportGroupNameCombo->currentText() );
857 mItem->layout()->undoStack()->endCommand();
858 }
859}
860
861void QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged( int )
862{
863 mFreezePageSpin = true;
864 changeItemPosition();
865 mFreezePageSpin = false;
866}
867
868void QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged( double )
869{
870 mFreezeXPosSpin = true;
871 changeItemPosition();
872 mFreezeXPosSpin = false;
873}
874
875void QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged( double )
876{
877 mFreezeYPosSpin = true;
878 changeItemPosition();
879 mFreezeYPosSpin = false;
880}
881
882void QgsLayoutItemPropertiesWidget::positionUnitsChanged( Qgis::LayoutUnit )
883{
884 changeItemPosition();
885}
886
887void QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged( double )
888{
889 mFreezeWidthSpin = true;
890 changeItemSize();
891 mFreezeWidthSpin = false;
892}
893
894void QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged( double )
895{
896 mFreezeHeightSpin = true;
897 changeItemSize();
898 mFreezeHeightSpin = false;
899}
900
901void QgsLayoutItemPropertiesWidget::sizeUnitsChanged( Qgis::LayoutUnit )
902{
903 changeItemSize();
904}
905
906void QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged( bool state )
907{
908 if ( !state )
909 return;
910
911 if ( mItem )
912 {
913 changeItemReference( QgsLayoutItem::UpperLeft );
914 }
915 setValuesForGuiPositionElements();
916}
917
918void QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged( bool state )
919{
920 if ( !state )
921 return;
922 if ( mItem )
923 {
924 changeItemReference( QgsLayoutItem::UpperMiddle );
925 }
926 setValuesForGuiPositionElements();
927}
928
929void QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged( bool state )
930{
931 if ( !state )
932 return;
933 if ( mItem )
934 {
935 changeItemReference( QgsLayoutItem::UpperRight );
936 }
937 setValuesForGuiPositionElements();
938}
939
940void QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged( bool state )
941{
942 if ( !state )
943 return;
944 if ( mItem )
945 {
946 changeItemReference( QgsLayoutItem::MiddleLeft );
947 }
948 setValuesForGuiPositionElements();
949}
950
951void QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged( bool state )
952{
953 if ( !state )
954 return;
955 if ( mItem )
956 {
957 changeItemReference( QgsLayoutItem::Middle );
958 }
959 setValuesForGuiPositionElements();
960}
961
962void QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged( bool state )
963{
964 if ( !state )
965 return;
966 if ( mItem )
967 {
968 changeItemReference( QgsLayoutItem::MiddleRight );
969 }
970 setValuesForGuiPositionElements();
971}
972
973void QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged( bool state )
974{
975 if ( !state )
976 return;
977 if ( mItem )
978 {
979 changeItemReference( QgsLayoutItem::LowerLeft );
980 }
981 setValuesForGuiPositionElements();
982}
983
984void QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged( bool state )
985{
986 if ( !state )
987 return;
988 if ( mItem )
989 {
990 changeItemReference( QgsLayoutItem::LowerMiddle );
991 }
992 setValuesForGuiPositionElements();
993}
994
995void QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged( bool state )
996{
997 if ( !state )
998 return;
999 if ( mItem )
1000 {
1001 changeItemReference( QgsLayoutItem::LowerRight );
1002 }
1003 setValuesForGuiPositionElements();
1004}
1005
1006void QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged( double val )
1007{
1008 if ( mItem )
1009 {
1010 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Rotate" ), QgsLayoutItem::UndoRotation );
1011 mItem->setItemRotation( val, true );
1012 mItem->update();
1013 mItem->layout()->undoStack()->endCommand();
1014 }
1015}
1016
1017void QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled( bool checked )
1018{
1019 if ( mItem )
1020 {
1021 mItem->layout()->undoStack()->beginCommand( mItem, checked ? tr( "Exclude from Exports" ) : tr( "Include in Exports" ) );
1022 mItem->setExcludeFromExports( checked );
1023 mItem->layout()->undoStack()->endCommand();
1024 }
1025}
LayoutUnit
Layout measurement units.
Definition qgis.h:4859
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:5821