QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgslayoutmapwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayoutmapwidget.cpp
3 ----------------------
4 begin : October 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
19#include "qgslayoutmapwidget.h"
21#include "qgslayoutitemmap.h"
22#include "qgsproject.h"
24#include "qgslayout.h"
25#include "qgslayertree.h"
26#include "qgsmapcanvas.h"
28#include "qgslayoutundostack.h"
29#include "qgslayoutatlas.h"
31#include "qgsguiutils.h"
32#include "qgsbookmarkmodel.h"
35#include "qgsmaplayermodel.h"
36#include "qgsfillsymbol.h"
37
38#include <QMenu>
39#include <QMessageBox>
40#include <QStringListModel>
41
43 : QgsLayoutItemBaseWidget( nullptr, item )
44 , mMapItem( item )
45 , mMapCanvas( mapCanvas )
46{
47 Q_ASSERT( mMapItem );
48
49 setupUi( this );
50 connect( mScaleLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutMapWidget::mScaleLineEdit_editingFinished );
51 connect( mActionSetToCanvasExtent, &QAction::triggered, this, &QgsLayoutMapWidget::setToMapCanvasExtent );
52 connect( mActionViewExtentInCanvas, &QAction::triggered, this, &QgsLayoutMapWidget::viewExtentInCanvas );
53 connect( mActionSetToCanvasScale, &QAction::triggered, this, &QgsLayoutMapWidget::setToMapCanvasScale );
54 connect( mActionViewScaleInCanvas, &QAction::triggered, this, &QgsLayoutMapWidget::viewScaleInCanvas );
55 connect( mActionUpdatePreview, &QAction::triggered, this, &QgsLayoutMapWidget::updatePreview );
56 connect( mFollowVisibilityPresetCheckBox, &QCheckBox::stateChanged, this, &QgsLayoutMapWidget::mFollowVisibilityPresetCheckBox_stateChanged );
57 connect( mKeepLayerListCheckBox, &QCheckBox::stateChanged, this, &QgsLayoutMapWidget::mKeepLayerListCheckBox_stateChanged );
58 connect( mKeepLayerStylesCheckBox, &QCheckBox::stateChanged, this, &QgsLayoutMapWidget::mKeepLayerStylesCheckBox_stateChanged );
59 connect( mDrawCanvasItemsCheckBox, &QCheckBox::stateChanged, this, &QgsLayoutMapWidget::mDrawCanvasItemsCheckBox_stateChanged );
60 connect( mOverviewBlendModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutMapWidget::mOverviewBlendModeComboBox_currentIndexChanged );
61 connect( mOverviewInvertCheckbox, &QCheckBox::toggled, this, &QgsLayoutMapWidget::mOverviewInvertCheckbox_toggled );
62 connect( mOverviewCenterCheckbox, &QCheckBox::toggled, this, &QgsLayoutMapWidget::mOverviewCenterCheckbox_toggled );
63 connect( mOverviewPositionComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutMapWidget::overviewStackingChanged );
64 connect( mOverviewStackingLayerComboBox, &QgsMapLayerComboBox::layerChanged, this, &QgsLayoutMapWidget::overviewStackingLayerChanged );
65 connect( mXMinLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutMapWidget::mXMinLineEdit_editingFinished );
66 connect( mXMaxLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutMapWidget::mXMaxLineEdit_editingFinished );
67 connect( mYMinLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutMapWidget::mYMinLineEdit_editingFinished );
68 connect( mYMaxLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutMapWidget::mYMaxLineEdit_editingFinished );
69 connect( mAtlasMarginRadio, &QRadioButton::toggled, this, &QgsLayoutMapWidget::mAtlasMarginRadio_toggled );
70 connect( mAtlasCheckBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutMapWidget::mAtlasCheckBox_toggled );
71 connect( mAtlasMarginSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsLayoutMapWidget::mAtlasMarginSpinBox_valueChanged );
72 connect( mAtlasFixedScaleRadio, &QRadioButton::toggled, this, &QgsLayoutMapWidget::mAtlasFixedScaleRadio_toggled );
73 connect( mAtlasPredefinedScaleRadio, &QRadioButton::toggled, this, &QgsLayoutMapWidget::mAtlasPredefinedScaleRadio_toggled );
74 connect( mAddGridPushButton, &QPushButton::clicked, this, &QgsLayoutMapWidget::mAddGridPushButton_clicked );
75 connect( mRemoveGridPushButton, &QPushButton::clicked, this, &QgsLayoutMapWidget::mRemoveGridPushButton_clicked );
76 connect( mGridUpButton, &QPushButton::clicked, this, &QgsLayoutMapWidget::mGridUpButton_clicked );
77 connect( mGridDownButton, &QPushButton::clicked, this, &QgsLayoutMapWidget::mGridDownButton_clicked );
78 connect( mGridListWidget, &QListWidget::currentItemChanged, this, &QgsLayoutMapWidget::mGridListWidget_currentItemChanged );
79 connect( mGridListWidget, &QListWidget::itemChanged, this, &QgsLayoutMapWidget::mGridListWidget_itemChanged );
80 connect( mGridPropertiesButton, &QPushButton::clicked, this, &QgsLayoutMapWidget::mGridPropertiesButton_clicked );
81 connect( mAddOverviewPushButton, &QPushButton::clicked, this, &QgsLayoutMapWidget::mAddOverviewPushButton_clicked );
82 connect( mRemoveOverviewPushButton, &QPushButton::clicked, this, &QgsLayoutMapWidget::mRemoveOverviewPushButton_clicked );
83 connect( mOverviewUpButton, &QPushButton::clicked, this, &QgsLayoutMapWidget::mOverviewUpButton_clicked );
84 connect( mOverviewDownButton, &QPushButton::clicked, this, &QgsLayoutMapWidget::mOverviewDownButton_clicked );
85 connect( mOverviewCheckBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutMapWidget::mOverviewCheckBox_toggled );
86 connect( mOverviewListWidget, &QListWidget::currentItemChanged, this, &QgsLayoutMapWidget::mOverviewListWidget_currentItemChanged );
87 connect( mOverviewListWidget, &QListWidget::itemChanged, this, &QgsLayoutMapWidget::mOverviewListWidget_itemChanged );
88 connect( mActionLabelSettings, &QAction::triggered, this, &QgsLayoutMapWidget::showLabelSettings );
89 connect( mActionClipSettings, &QAction::triggered, this, &QgsLayoutMapWidget::showClipSettings );
90
91 connect( mTemporalCheckBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutMapWidget::mTemporalCheckBox_toggled );
92 connect( mStartDateTime, &QDateTimeEdit::dateTimeChanged, this, &QgsLayoutMapWidget::updateTemporalExtent );
93 connect( mEndDateTime, &QDateTimeEdit::dateTimeChanged, this, &QgsLayoutMapWidget::updateTemporalExtent );
94
95 mZLowerSpin->setClearValueMode( QgsDoubleSpinBox::ClearValueMode::MinimumValue, tr( "Not set" ) );
96 mZUpperSpin->setClearValueMode( QgsDoubleSpinBox::ClearValueMode::MinimumValue, tr( "Not set" ) );
97 connect( mElevationRangeCheckBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutMapWidget::mElevationRangeCheckBox_toggled );
98 connect( mZLowerSpin, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, &QgsLayoutMapWidget::updateZRange );
99 connect( mZUpperSpin, qOverload< double >( &QgsDoubleSpinBox::valueChanged ), this, &QgsLayoutMapWidget::updateZRange );
100
101 mStartDateTime->setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), mStartDateTime->maximumDateTime() );
102 mEndDateTime->setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), mStartDateTime->maximumDateTime() );
103 mStartDateTime->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
104 mEndDateTime->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
105
106 connect( mActionMoveContent, &QAction::triggered, this, &QgsLayoutMapWidget::switchToMoveContentTool );
107 setPanelTitle( tr( "Map Properties" ) );
108 mMapRotationSpinBox->setClearValue( 0 );
109
110 mDockToolbar->setIconSize( QgsGuiUtils::iconSize( true ) );
111
112 mBookmarkMenu = new QMenu( this );
113 QToolButton *btnBookmarks = new QToolButton( this );
114 btnBookmarks->setAutoRaise( true );
115 btnBookmarks->setToolTip( tr( "Bookmarks" ) );
116 btnBookmarks->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowBookmarks.svg" ) ) );
117 btnBookmarks->setPopupMode( QToolButton::InstantPopup );
118 btnBookmarks->setMenu( mBookmarkMenu );
119
120 mDockToolbar->insertWidget( mActionMoveContent, btnBookmarks );
121 connect( mBookmarkMenu, &QMenu::aboutToShow, this, &QgsLayoutMapWidget::aboutToShowBookmarkMenu );
122
123 //add widget for general composer item properties
124 mItemPropertiesWidget = new QgsLayoutItemPropertiesWidget( this, item );
125 mainLayout->addWidget( mItemPropertiesWidget );
126
127 mScaleLineEdit->setValidator( new QDoubleValidator( mScaleLineEdit ) );
128
129 mXMinLineEdit->setValidator( new QDoubleValidator( mXMinLineEdit ) );
130 mXMaxLineEdit->setValidator( new QDoubleValidator( mXMaxLineEdit ) );
131 mYMinLineEdit->setValidator( new QDoubleValidator( mYMinLineEdit ) );
132 mYMaxLineEdit->setValidator( new QDoubleValidator( mYMaxLineEdit ) );
133
134 mOverviewPositionComboBox->addItem( tr( "Below Map" ), QgsLayoutItemMapItem::StackBelowMap );
135 mOverviewPositionComboBox->addItem( tr( "Below Map Layer" ), QgsLayoutItemMapItem::StackBelowMapLayer );
136 mOverviewPositionComboBox->addItem( tr( "Above Map Layer" ), QgsLayoutItemMapItem::StackAboveMapLayer );
137 mOverviewPositionComboBox->addItem( tr( "Below Map Labels" ), QgsLayoutItemMapItem::StackBelowMapLabels );
138 mOverviewPositionComboBox->addItem( tr( "Above Map Labels" ), QgsLayoutItemMapItem::StackAboveMapLabels );
139
140 blockAllSignals( true );
141
142 mCrsSelector->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
143 mCrsSelector->setNotSetText( tr( "Use Project CRS" ) );
144 mCrsSelector->setDialogTitle( tr( "Map Item CRS" ) );
145
146 mOverviewFrameStyleButton->setSymbolType( Qgis::SymbolType::Fill );
147
148 // follow preset combo
149 mFollowVisibilityPresetCombo->setModel( new QStringListModel( mFollowVisibilityPresetCombo ) );
150 connect( mFollowVisibilityPresetCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutMapWidget::followVisibilityPresetSelected );
151 connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemesChanged,
152 this, &QgsLayoutMapWidget::onMapThemesChanged );
153 onMapThemesChanged();
154
155 // keep layers from preset button
156 QMenu *menuKeepLayers = new QMenu( this );
157 mLayerListFromPresetButton->setMenu( menuKeepLayers );
158 mLayerListFromPresetButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ) );
159 mLayerListFromPresetButton->setToolTip( tr( "Set layer list from a map theme" ) );
160 connect( menuKeepLayers, &QMenu::aboutToShow, this, &QgsLayoutMapWidget::aboutToShowKeepLayersVisibilityPresetsMenu );
161
162 connect( item, &QgsLayoutObject::changed, this, &QgsLayoutMapWidget::updateGuiElements );
163
165 this, &QgsLayoutMapWidget::atlasLayerChanged );
166 if ( QgsLayoutAtlas *atlas = layoutAtlas() )
167 {
168 connect( atlas, &QgsLayoutAtlas::toggled, this, &QgsLayoutMapWidget::compositionAtlasToggled );
169 compositionAtlasToggled( atlas->enabled() );
170 }
171
172 mOverviewFrameMapComboBox->setCurrentLayout( item->layout() );
173 mOverviewFrameMapComboBox->setItemType( QgsLayoutItemRegistry::LayoutMap );
174 mOverviewFrameStyleButton->registerExpressionContextGenerator( item );
175
176 connect( mOverviewFrameMapComboBox, &QgsLayoutItemComboBox::itemChanged, this, &QgsLayoutMapWidget::overviewMapChanged );
177 connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged, this, &QgsLayoutMapWidget::mapCrsChanged );
178 connect( mOverviewFrameStyleButton, &QgsSymbolButton::changed, this, &QgsLayoutMapWidget::overviewSymbolChanged );
179
180 mOverviewFrameStyleButton->registerExpressionContextGenerator( item );
181 mOverviewFrameStyleButton->setLayer( coverageLayer() );
182 if ( item->layout() )
183 {
184 connect( &item->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, mOverviewFrameStyleButton, &QgsSymbolButton::setLayer );
185 }
186
187
202
203 updateGuiElements();
204 loadGridEntries();
205 loadOverviewEntries();
206
207 connect( mMapRotationSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsLayoutMapWidget::rotationChanged );
208 connect( mMapItem, &QgsLayoutItemMap::extentChanged, mItemPropertiesWidget, &QgsLayoutItemPropertiesWidget::updateVariables );
210
211 blockAllSignals( false );
212}
213
215{
216 if ( mItemPropertiesWidget )
217 mItemPropertiesWidget->setMasterLayout( masterLayout );
218}
219
220void QgsLayoutMapWidget::setReportTypeString( const QString &string )
221{
222 mReportTypeString = string;
223 mAtlasCheckBox->setTitle( tr( "Controlled by %1" ).arg( string == tr( "atlas" ) ? tr( "Atlas" ) : tr( "Report" ) ) );
224 mAtlasPredefinedScaleRadio->setToolTip( tr( "Use one of the predefined scales of the project where the %1 feature best fits." ).arg( string ) );
225
226 if ( mClipWidget )
227 mClipWidget->setReportTypeString( string );
228 if ( mLabelWidget )
229 mLabelWidget->setReportTypeString( string );
230}
231
233{
234 mInterface = iface;
236}
237
239{
240 if ( item->type() != QgsLayoutItemRegistry::LayoutMap )
241 return false;
242
243 if ( mMapItem )
244 {
245 disconnect( mMapItem, &QgsLayoutObject::changed, this, &QgsLayoutMapWidget::updateGuiElements );
246 disconnect( mMapItem, &QgsLayoutItemMap::extentChanged, mItemPropertiesWidget, &QgsLayoutItemPropertiesWidget::updateVariables );
247 disconnect( mMapItem, &QgsLayoutItemMap::mapRotationChanged, mItemPropertiesWidget, &QgsLayoutItemPropertiesWidget::updateVariables );
248 }
249
250 mMapItem = qobject_cast< QgsLayoutItemMap * >( item );
251 mItemPropertiesWidget->setItem( mMapItem );
252 if ( mLabelWidget )
253 mLabelWidget->setItem( mMapItem );
254 if ( mClipWidget )
255 mClipWidget->setItem( mMapItem );
256
257 if ( mMapItem )
258 {
259 connect( mMapItem, &QgsLayoutObject::changed, this, &QgsLayoutMapWidget::updateGuiElements );
260 connect( mMapItem, &QgsLayoutItemMap::extentChanged, mItemPropertiesWidget, &QgsLayoutItemPropertiesWidget::updateVariables );
262 mOverviewFrameStyleButton->registerExpressionContextGenerator( mMapItem );
263 }
264
265 updateGuiElements();
266
267 return true;
268}
269
271{
272 updateDataDefinedButton( mScaleDDBtn );
273 updateDataDefinedButton( mMapRotationDDBtn );
274 updateDataDefinedButton( mXMinDDBtn );
275 updateDataDefinedButton( mYMinDDBtn );
276 updateDataDefinedButton( mXMaxDDBtn );
277 updateDataDefinedButton( mYMaxDDBtn );
278 updateDataDefinedButton( mAtlasMarginDDBtn );
279 updateDataDefinedButton( mStylePresetsDDBtn );
280 updateDataDefinedButton( mLayersDDBtn );
281 updateDataDefinedButton( mCRSDDBtn );
282 updateDataDefinedButton( mStartDateTimeDDBtn );
283 updateDataDefinedButton( mEndDateTimeDDBtn );
284}
285
286void QgsLayoutMapWidget::compositionAtlasToggled( bool atlasEnabled )
287{
288 if ( atlasEnabled &&
289 mMapItem && mMapItem->layout() && mMapItem->layout()->reportContext().layer()
290 && mMapItem->layout()->reportContext().layer()->wkbType() != Qgis::WkbType::NoGeometry )
291 {
292 mAtlasCheckBox->setEnabled( true );
293 }
294 else
295 {
296 mAtlasCheckBox->setEnabled( false );
297 mAtlasCheckBox->setChecked( false );
298 }
299}
300
301void QgsLayoutMapWidget::aboutToShowKeepLayersVisibilityPresetsMenu()
302{
303 // this menu is for the case when setting "keep layers" and "keep layer styles"
304 // and the preset configuration is copied. The preset is not followed further.
305
306 QMenu *menu = qobject_cast<QMenu *>( sender() );
307 if ( !menu )
308 return;
309
310 menu->clear();
311 const auto constMapThemes = QgsProject::instance()->mapThemeCollection()->mapThemes();
312 for ( const QString &presetName : constMapThemes )
313 {
314 menu->addAction( presetName, this, &QgsLayoutMapWidget::keepLayersVisibilityPresetSelected );
315 }
316
317 if ( menu->actions().isEmpty() )
318 menu->addAction( tr( "No presets defined" ) )->setEnabled( false );
319}
320
321void QgsLayoutMapWidget::followVisibilityPresetSelected( int currentIndex )
322{
323 if ( !mMapItem )
324 return;
325
326 if ( mBlockThemeComboChanges != 0 )
327 return;
328
329 if ( currentIndex == -1 )
330 return; // doing combo box model reset
331
332 QString presetName;
333 if ( currentIndex != 0 )
334 {
335 presetName = mFollowVisibilityPresetCombo->currentText();
336 }
337
338 if ( presetName == mMapItem->followVisibilityPresetName() )
339 return;
340
341 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map Preset" ) );
342 mFollowVisibilityPresetCheckBox->setChecked( true );
343 mMapItem->setFollowVisibilityPresetName( presetName );
344 mMapItem->layout()->undoStack()->endCommand();
345
346 mMapItem->invalidateCache();
347}
348
349void QgsLayoutMapWidget::keepLayersVisibilityPresetSelected()
350{
351 QAction *action = qobject_cast<QAction *>( sender() );
352 if ( !action )
353 return;
354
355 const QString presetName = action->text();
356 const QList<QgsMapLayer *> lst = orderedPresetVisibleLayers( presetName );
357 if ( mMapItem )
358 {
359 mKeepLayerListCheckBox->setChecked( true );
360 mMapItem->setLayers( lst );
361
362 mKeepLayerStylesCheckBox->setChecked( true );
363
364 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map Preset" ) );
365 mMapItem->setLayerStyleOverrides( QgsProject::instance()->mapThemeCollection()->mapThemeStyleOverrides( presetName ) );
366 mMapItem->layout()->undoStack()->endCommand();
367
368 mMapItem->invalidateCache();
369 }
370}
371
372void QgsLayoutMapWidget::onMapThemesChanged()
373{
374 if ( QStringListModel *model = qobject_cast<QStringListModel *>( mFollowVisibilityPresetCombo->model() ) )
375 {
376 mBlockThemeComboChanges++;
377 QStringList lst;
378 lst.append( tr( "(none)" ) );
380 model->setStringList( lst );
381
382 // select the previously selected item again
383 const int presetModelIndex = mFollowVisibilityPresetCombo->findText( mMapItem->followVisibilityPresetName() );
384 mFollowVisibilityPresetCombo->blockSignals( true );
385 mFollowVisibilityPresetCombo->setCurrentIndex( presetModelIndex != -1 ? presetModelIndex : 0 ); // 0 == none
386 mFollowVisibilityPresetCombo->blockSignals( false );
387 mBlockThemeComboChanges--;
388 }
389}
390
391void QgsLayoutMapWidget::mapCrsChanged( const QgsCoordinateReferenceSystem &crs )
392{
393 if ( !mMapItem )
394 {
395 return;
396 }
397
398 if ( mMapItem->presetCrs() == crs )
399 return;
400
401 // try to reproject to maintain extent
402 const QgsCoordinateReferenceSystem oldCrs = mMapItem->crs();
403
404 bool updateExtent = false;
405 QgsRectangle newExtent;
406 try
407 {
409 xForm.setBallparkTransformsAreAppropriate( true );
410 const QgsRectangle prevExtent = mMapItem->extent();
411 newExtent = xForm.transformBoundingBox( prevExtent );
412 updateExtent = true;
413 }
414 catch ( QgsCsException & )
415 {
416 //transform failed, don't update extent
417 }
418
419 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map CRS" ) );
420 mMapItem->setCrs( crs );
421 if ( updateExtent )
422 mMapItem->zoomToExtent( newExtent );
423 mMapItem->layout()->undoStack()->endCommand();
424 mMapItem->invalidateCache();
425}
426
427void QgsLayoutMapWidget::overviewSymbolChanged()
428{
429 QgsLayoutItemMapOverview *overview = currentOverview();
430 if ( !overview )
431 return;
432
433 mMapItem->beginCommand( tr( "Change Overview Style" ), QgsLayoutItem::UndoOverviewStyle );
434 overview->setFrameSymbol( mOverviewFrameStyleButton->clonedSymbol<QgsFillSymbol>() );
435 mMapItem->endCommand();
436 mMapItem->invalidateCache();
437}
438
439void QgsLayoutMapWidget::showLabelSettings()
440{
441 mLabelWidget = new QgsLayoutMapLabelingWidget( mMapItem );
442
443 if ( !mReportTypeString.isEmpty() )
444 mLabelWidget->setReportTypeString( mReportTypeString );
445
446 openPanel( mLabelWidget );
447}
448
449void QgsLayoutMapWidget::showClipSettings()
450{
451 mClipWidget = new QgsLayoutMapClippingWidget( mMapItem );
452 if ( !mReportTypeString.isEmpty() )
453 mClipWidget->setReportTypeString( mReportTypeString );
454 openPanel( mClipWidget );
455}
456
457void QgsLayoutMapWidget::switchToMoveContentTool()
458{
459 if ( mInterface )
461}
462
463void QgsLayoutMapWidget::aboutToShowBookmarkMenu()
464{
465 mBookmarkMenu->clear();
466
467 // query the bookmarks now? or once during widget creation... Hmm. Either way, there's potentially a
468 // delay if there's LOTS of bookmarks. Let's avoid the cost until bookmarks are actually required.
469 if ( !mBookmarkModel )
470 mBookmarkModel = new QgsBookmarkManagerProxyModel( QgsApplication::bookmarkManager(), QgsProject::instance()->bookmarkManager(), this );
471
472 QMap< QString, QMenu * > groupMenus;
473 for ( int i = 0; i < mBookmarkModel->rowCount(); ++i )
474 {
475 const QString group = mBookmarkModel->data( mBookmarkModel->index( i, 0 ), static_cast< int >( QgsBookmarkManagerModel::CustomRole::Group ) ).toString();
476 QMenu *destMenu = mBookmarkMenu;
477 if ( !group.isEmpty() )
478 {
479 destMenu = groupMenus.value( group );
480 if ( !destMenu )
481 {
482 destMenu = new QMenu( group, mBookmarkMenu );
483 groupMenus[ group ] = destMenu;
484 }
485 }
486 QAction *action = new QAction( mBookmarkModel->data( mBookmarkModel->index( i, 0 ), static_cast< int >( QgsBookmarkManagerModel::CustomRole::Name ) ).toString(), mBookmarkMenu );
487 const QgsReferencedRectangle extent = mBookmarkModel->data( mBookmarkModel->index( i, 0 ), static_cast< int >( QgsBookmarkManagerModel::CustomRole::Extent ) ).value< QgsReferencedRectangle >();
488 connect( action, &QAction::triggered, this, [ = ]
489 {
490 if ( !mMapItem )
491 {
492 return;
493 }
494
495 QgsRectangle newExtent = extent;
496
497 //transform?
498 if ( extent.crs() != mMapItem->crs() )
499 {
500 try
501 {
502 QgsCoordinateTransform xForm( extent.crs(), mMapItem->crs(), QgsProject::instance() );
503 xForm.setBallparkTransformsAreAppropriate( true );
504 newExtent = xForm.transformBoundingBox( newExtent );
505 }
506 catch ( QgsCsException & )
507 {
508 //transform failed, better not proceed
509 return;
510 }
511 }
512
513 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map Extent" ) );
514 mMapItem->zoomToExtent( newExtent );
515 mMapItem->layout()->undoStack()->endCommand();
516 } );
517 destMenu->addAction( action );
518 }
519
520 QStringList groupKeys = groupMenus.keys();
521 groupKeys.sort( Qt::CaseInsensitive );
522 for ( int i = 0; i < groupKeys.count(); ++i )
523 {
524 if ( mBookmarkMenu->actions().value( i ) )
525 mBookmarkMenu->insertMenu( mBookmarkMenu->actions().at( i ), groupMenus.value( groupKeys.at( i ) ) );
526 else
527 mBookmarkMenu->addMenu( groupMenus.value( groupKeys.at( i ) ) );
528 }
529}
530
531void QgsLayoutMapWidget::mTemporalCheckBox_toggled( bool checked )
532{
533 if ( !mMapItem )
534 {
535 return;
536 }
537
538 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Toggle Temporal Range" ) );
539 mMapItem->setIsTemporal( checked );
540 mMapItem->layout()->undoStack()->endCommand();
541
542 if ( checked )
543 {
544 whileBlocking( mStartDateTime )->setDateTime( mMapItem->temporalRange().begin() );
545 whileBlocking( mEndDateTime )->setDateTime( mMapItem->temporalRange().end() );
546 }
547
548 updatePreview();
549}
550
551void QgsLayoutMapWidget::updateTemporalExtent()
552{
553 if ( !mMapItem )
554 {
555 return;
556 }
557
558 const QDateTime begin = mStartDateTime->dateTime();
559 const QDateTime end = mEndDateTime->dateTime();
560 const QgsDateTimeRange range = QgsDateTimeRange( begin, end, true, begin == end );
561
562 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Set Temporal Range" ) );
563 mMapItem->setTemporalRange( range );
564 mMapItem->layout()->undoStack()->endCommand();
565
566 updatePreview();
567}
568
569void QgsLayoutMapWidget::mElevationRangeCheckBox_toggled( bool checked )
570{
571 if ( !mMapItem )
572 {
573 return;
574 }
575
576 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Toggle Z Range" ) );
577 mMapItem->setZRangeEnabled( checked );
578 mMapItem->layout()->undoStack()->endCommand();
579
580 updatePreview();
581}
582
583void QgsLayoutMapWidget::updateZRange()
584{
585 if ( !mMapItem )
586 {
587 return;
588 }
589
590 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Set Z Range" ) );
591 double zLower = mZLowerSpin->value();
592 if ( zLower == mZLowerSpin->clearValue() )
593 zLower = std::numeric_limits< double >::lowest();
594 double zUpper = mZUpperSpin->value();
595 if ( zUpper == mZUpperSpin->clearValue() )
596 zUpper = std::numeric_limits< double >::max();
597
598 mMapItem->setZRange( QgsDoubleRange( zLower, zUpper ) );
599 mMapItem->layout()->undoStack()->endCommand();
600
601 updatePreview();
602}
603
604void QgsLayoutMapWidget::mAtlasCheckBox_toggled( bool checked )
605{
606 if ( !mMapItem )
607 {
608 return;
609 }
610
611 mAtlasFixedScaleRadio->setEnabled( checked );
612 mAtlasMarginRadio->setEnabled( checked );
613
614 if ( mAtlasMarginRadio->isEnabled() && mAtlasMarginRadio->isChecked() )
615 {
616 mAtlasMarginSpinBox->setEnabled( true );
617 }
618 else
619 {
620 mAtlasMarginSpinBox->setEnabled( false );
621 }
622
623 mAtlasPredefinedScaleRadio->setEnabled( checked );
624
625 if ( checked )
626 {
627 //check atlas coverage layer type
628 if ( mMapItem->layout() )
629 {
630 toggleAtlasScalingOptionsByLayerType();
631 }
632 }
633
634 // disable predefined scales if none are defined
635 if ( !hasPredefinedScales() )
636 {
637 mAtlasPredefinedScaleRadio->setEnabled( false );
638 }
639
640 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Set Atlas Driven" ) );
641 mMapItem->setAtlasDriven( checked );
642 mMapItem->layout()->undoStack()->endCommand();
643 updateMapForAtlas();
644}
645
646void QgsLayoutMapWidget::updateMapForAtlas()
647{
648 //update map if in atlas preview mode
649 if ( mMapItem->atlasDriven() )
650 {
651 mMapItem->refresh();
652 }
653 else
654 {
655 //redraw map
656 mMapItem->invalidateCache();
657 }
658}
659
660void QgsLayoutMapWidget::mAtlasMarginRadio_toggled( bool checked )
661{
662 mAtlasMarginSpinBox->setEnabled( checked );
663
664 if ( checked && mMapItem )
665 {
666 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Atlas Mode" ) );
667 mMapItem->setAtlasScalingMode( QgsLayoutItemMap::Auto );
668 mMapItem->layout()->undoStack()->endCommand();
669 updateMapForAtlas();
670 }
671}
672
673void QgsLayoutMapWidget::mAtlasMarginSpinBox_valueChanged( int value )
674{
675 if ( !mMapItem )
676 {
677 return;
678 }
679
680 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Atlas Margin" ), QgsLayoutItem::UndoAtlasMargin );
681 mMapItem->setAtlasMargin( value / 100. );
682 mMapItem->layout()->undoStack()->endCommand();
683 updateMapForAtlas();
684}
685
686void QgsLayoutMapWidget::mAtlasFixedScaleRadio_toggled( bool checked )
687{
688 if ( !mMapItem )
689 {
690 return;
691 }
692
693 if ( checked )
694 {
695 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Atlas Mode" ) );
696 mMapItem->setAtlasScalingMode( QgsLayoutItemMap::Fixed );
697 mMapItem->layout()->undoStack()->endCommand();
698 updateMapForAtlas();
699 }
700}
701
702void QgsLayoutMapWidget::mAtlasPredefinedScaleRadio_toggled( bool checked )
703{
704 if ( !mMapItem )
705 {
706 return;
707 }
708
709 if ( hasPredefinedScales() )
710 {
711 if ( checked )
712 {
713 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Atlas Scales" ) );
714 mMapItem->setAtlasScalingMode( QgsLayoutItemMap::Predefined );
715 mMapItem->layout()->undoStack()->endCommand();
716 updateMapForAtlas();
717 }
718 }
719 else
720 {
721 // restore to fixed scale if no predefined scales exist
722 whileBlocking( mAtlasFixedScaleRadio )->setChecked( true );
723 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Atlas Mode" ) );
724 mMapItem->setAtlasScalingMode( QgsLayoutItemMap::Fixed );
725 mMapItem->layout()->undoStack()->endCommand();
726 }
727}
728
729void QgsLayoutMapWidget::mScaleLineEdit_editingFinished()
730{
731 if ( !mMapItem )
732 {
733 return;
734 }
735
736 bool conversionSuccess = false;
737 const double scaleDenominator = QLocale().toDouble( mScaleLineEdit->text(), &conversionSuccess );
738 if ( !conversionSuccess )
739 {
740 return;
741 }
742
743 if ( qgsDoubleNear( scaleDenominator, mMapItem->scale() ) )
744 return;
745
746 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map Scale" ) );
747 mMapItem->setScale( scaleDenominator );
748 mMapItem->layout()->undoStack()->endCommand();
749}
750
751void QgsLayoutMapWidget::rotationChanged( double value )
752{
753 if ( !mMapItem )
754 {
755 return;
756 }
757
758 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map Rotation" ), QgsLayoutItem::UndoMapRotation );
759 mMapItem->setMapRotation( value );
760 mMapItem->layout()->undoStack()->endCommand();
761 mMapItem->invalidateCache();
762}
763
764void QgsLayoutMapWidget::setToMapCanvasExtent()
765{
766 if ( !mMapItem )
767 {
768 return;
769 }
770
771 QgsRectangle newExtent = mMapCanvas->mapSettings().visibleExtent();
772
773 //transform?
774 if ( mMapCanvas->mapSettings().destinationCrs()
775 != mMapItem->crs() )
776 {
777 try
778 {
780 mMapItem->crs(), QgsProject::instance() );
781 xForm.setBallparkTransformsAreAppropriate( true );
782 newExtent = xForm.transformBoundingBox( newExtent );
783 }
784 catch ( QgsCsException & )
785 {
786 //transform failed, better not proceed
787 return;
788 }
789 }
790
791 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map Extent" ) );
792 mMapItem->zoomToExtent( newExtent );
793 mMapItem->layout()->undoStack()->endCommand();
794}
795
796void QgsLayoutMapWidget::setToMapCanvasScale()
797{
798 if ( !mMapItem )
799 {
800 return;
801 }
802
803 const double newScale = mMapCanvas->scale();
804
805 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map Scale" ) );
806 mMapItem->setScale( newScale );
807 mMapItem->layout()->undoStack()->endCommand();
808}
809
810void QgsLayoutMapWidget::viewExtentInCanvas()
811{
812 if ( !mMapItem )
813 {
814 return;
815 }
816
817 const QgsRectangle currentMapExtent = mMapItem->extent();
818
819 if ( !currentMapExtent.isEmpty() )
820 {
821 try
822 {
823 mMapCanvas->setReferencedExtent( QgsReferencedRectangle( currentMapExtent, mMapItem->crs() ) );
824 }
825 catch ( QgsCsException & )
826 {
827 //transform failed, better not proceed
828 return;
829 }
830 mMapCanvas->refresh();
831 }
832}
833
834void QgsLayoutMapWidget::viewScaleInCanvas()
835{
836 if ( !mMapItem )
837 {
838 return;
839 }
840
841 const double currentScale = mMapItem->scale();
842 mMapCanvas->zoomScale( currentScale, true );
843}
844
845void QgsLayoutMapWidget::mXMinLineEdit_editingFinished()
846{
847 updateComposerExtentFromGui();
848}
849
850void QgsLayoutMapWidget::mXMaxLineEdit_editingFinished()
851{
852 updateComposerExtentFromGui();
853}
854
855void QgsLayoutMapWidget::mYMinLineEdit_editingFinished()
856{
857 updateComposerExtentFromGui();
858}
859
860void QgsLayoutMapWidget::mYMaxLineEdit_editingFinished()
861{
862 updateComposerExtentFromGui();
863}
864
865void QgsLayoutMapWidget::updateGuiElements()
866{
867 if ( !mMapItem )
868 {
869 return;
870 }
871
872 blockAllSignals( true );
873 mLabel->setText( mMapItem->displayName() );
874
875 whileBlocking( mCrsSelector )->setCrs( mMapItem->presetCrs() );
876
877 //width, height, scale
878 const double scale = mMapItem->scale();
879
880 //round scale to an appropriate number of decimal places
881 if ( scale >= 10000 )
882 {
883 //round scale to integer if it's greater than 10000
884 mScaleLineEdit->setText( QLocale().toString( mMapItem->scale(), 'f', 0 ) );
885 }
886 else if ( scale >= 10 )
887 {
888 mScaleLineEdit->setText( QLocale().toString( mMapItem->scale(), 'f', 3 ) );
889 }
890 else if ( scale >= 1 )
891 {
892 //don't round scale if it's less than 10, instead use 4 decimal places
893 mScaleLineEdit->setText( QLocale().toString( mMapItem->scale(), 'f', 4 ) );
894 }
895 else
896 {
897 //if scale < 1 then use 10 decimal places
898 mScaleLineEdit->setText( QLocale().toString( mMapItem->scale(), 'f', 10 ) );
899 }
900
901 //composer map extent
902 const QgsRectangle composerMapExtent = mMapItem->extent();
903 mXMinLineEdit->setText( QLocale().toString( composerMapExtent.xMinimum(), 'f', 3 ) );
904 mXMaxLineEdit->setText( QLocale().toString( composerMapExtent.xMaximum(), 'f', 3 ) );
905 mYMinLineEdit->setText( QLocale().toString( composerMapExtent.yMinimum(), 'f', 3 ) );
906 mYMaxLineEdit->setText( QLocale().toString( composerMapExtent.yMaximum(), 'f', 3 ) );
907
908 mMapRotationSpinBox->setValue( mMapItem->mapRotation( QgsLayoutObject::OriginalValue ) );
909
910 // follow preset checkbox
911 mFollowVisibilityPresetCheckBox->setCheckState(
912 mMapItem->followVisibilityPreset() ? Qt::Checked : Qt::Unchecked );
913 const int presetModelIndex = mFollowVisibilityPresetCombo->findText( mMapItem->followVisibilityPresetName() );
914 mFollowVisibilityPresetCombo->setCurrentIndex( presetModelIndex != -1 ? presetModelIndex : 0 ); // 0 == none
915
916 //keep layer list checkbox
917 if ( mMapItem->keepLayerSet() )
918 {
919 mKeepLayerListCheckBox->setCheckState( Qt::Checked );
920 }
921 else
922 {
923 mKeepLayerListCheckBox->setCheckState( Qt::Unchecked );
924 }
925
926 mKeepLayerStylesCheckBox->setEnabled( mMapItem->keepLayerSet() );
927 mKeepLayerStylesCheckBox->setCheckState( mMapItem->keepLayerStyles() ? Qt::Checked : Qt::Unchecked );
928
929 //draw canvas items
930 if ( mMapItem->drawAnnotations() )
931 {
932 mDrawCanvasItemsCheckBox->setCheckState( Qt::Checked );
933 }
934 else
935 {
936 mDrawCanvasItemsCheckBox->setCheckState( Qt::Unchecked );
937 }
938
939 //atlas controls
940 mAtlasCheckBox->setChecked( mMapItem->atlasDriven() );
941 mAtlasMarginSpinBox->setValue( static_cast<int>( mMapItem->atlasMargin( QgsLayoutObject::OriginalValue ) * 100 ) );
942
943 mAtlasFixedScaleRadio->setEnabled( mMapItem->atlasDriven() );
944 mAtlasFixedScaleRadio->setChecked( mMapItem->atlasScalingMode() == QgsLayoutItemMap::Fixed );
945 mAtlasMarginSpinBox->setEnabled( mMapItem->atlasScalingMode() == QgsLayoutItemMap::Auto );
946 mAtlasMarginRadio->setEnabled( mMapItem->atlasDriven() );
947 mAtlasMarginRadio->setChecked( mMapItem->atlasScalingMode() == QgsLayoutItemMap::Auto );
948 mAtlasPredefinedScaleRadio->setEnabled( mMapItem->atlasDriven() );
949 mAtlasPredefinedScaleRadio->setChecked( mMapItem->atlasScalingMode() == QgsLayoutItemMap::Predefined );
950
951 if ( mMapItem->atlasDriven() )
952 {
953 toggleAtlasScalingOptionsByLayerType();
954 }
955 // disable predefined scales if none are defined
956 if ( !hasPredefinedScales() )
957 {
958 mAtlasPredefinedScaleRadio->setEnabled( false );
959 }
960
961 mTemporalCheckBox->setChecked( mMapItem->isTemporal() );
962 mTemporalCheckBox->setCollapsed( !mMapItem->isTemporal() );
963 mStartDateTime->setEnabled( mMapItem->isTemporal() );
964 mEndDateTime->setEnabled( mMapItem->isTemporal() );
965 if ( mMapItem->isTemporal() )
966 {
967 mStartDateTime->setDateTime( mMapItem->temporalRange().begin() );
968 mEndDateTime->setDateTime( mMapItem->temporalRange().end() );
969 }
970
971 whileBlocking( mElevationRangeCheckBox )->setChecked( mMapItem->zRangeEnabled() );
972 mElevationRangeCheckBox->setCollapsed( !mMapItem->zRangeEnabled() );
973 if ( mMapItem->zRange().lower() != std::numeric_limits< double >::lowest() )
974 whileBlocking( mZLowerSpin )->setValue( mMapItem->zRange().lower() );
975 else
976 whileBlocking( mZLowerSpin )->clear();
977 if ( mMapItem->zRange().upper() != std::numeric_limits< double >::max() )
978 whileBlocking( mZUpperSpin )->setValue( mMapItem->zRange().upper() );
979 else
980 whileBlocking( mZUpperSpin )->clear();
981
983 loadGridEntries();
984 loadOverviewEntries();
985
986 blockAllSignals( false );
987}
988
989void QgsLayoutMapWidget::toggleAtlasScalingOptionsByLayerType()
990{
991 if ( !mMapItem )
992 {
993 return;
994 }
995
996 //get atlas coverage layer
997 QgsVectorLayer *layer = coverageLayer();
998 if ( !layer )
999 {
1000 return;
1001 }
1002
1004 {
1005 //For point layers buffer setting makes no sense, so set "fixed scale" on and disable margin control
1006 if ( mMapItem->atlasScalingMode() == QgsLayoutItemMap::Auto )
1007 mAtlasFixedScaleRadio->setChecked( true );
1008 mAtlasMarginRadio->setEnabled( false );
1009 }
1010 else
1011 {
1012 //Not a point layer, so enable changes to fixed scale control
1013 mAtlasMarginRadio->setEnabled( true );
1014 }
1015}
1016
1017void QgsLayoutMapWidget::updateComposerExtentFromGui()
1018{
1019 if ( !mMapItem )
1020 {
1021 return;
1022 }
1023
1024 double xmin, ymin, xmax, ymax;
1025 bool conversionSuccess;
1026
1027 xmin = QLocale().toDouble( mXMinLineEdit->text(), &conversionSuccess );
1028 if ( !conversionSuccess )
1029 return;
1030 xmax = QLocale().toDouble( mXMaxLineEdit->text(), &conversionSuccess );
1031 if ( !conversionSuccess )
1032 return;
1033 ymin = QLocale().toDouble( mYMinLineEdit->text(), &conversionSuccess );
1034 if ( !conversionSuccess )
1035 return;
1036 ymax = QLocale().toDouble( mYMaxLineEdit->text(), &conversionSuccess );
1037 if ( !conversionSuccess )
1038 return;
1039
1040 const QgsRectangle newExtent( xmin, ymin, xmax, ymax );
1041
1042 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map Extent" ) );
1043 mMapItem->setExtent( newExtent );
1044 mMapItem->layout()->undoStack()->endCommand();
1045}
1046
1047void QgsLayoutMapWidget::blockAllSignals( bool b )
1048{
1049 mScaleLineEdit->blockSignals( b );
1050 mXMinLineEdit->blockSignals( b );
1051 mXMaxLineEdit->blockSignals( b );
1052 mYMinLineEdit->blockSignals( b );
1053 mYMaxLineEdit->blockSignals( b );
1054 mDrawCanvasItemsCheckBox->blockSignals( b );
1055 mOverviewFrameMapComboBox->blockSignals( b );
1056 mOverviewFrameStyleButton->blockSignals( b );
1057 mOverviewBlendModeComboBox->blockSignals( b );
1058 mOverviewInvertCheckbox->blockSignals( b );
1059 mOverviewCenterCheckbox->blockSignals( b );
1060 mAtlasCheckBox->blockSignals( b );
1061 mAtlasMarginSpinBox->blockSignals( b );
1062 mAtlasFixedScaleRadio->blockSignals( b );
1063 mAtlasMarginRadio->blockSignals( b );
1064 mFollowVisibilityPresetCheckBox->blockSignals( b );
1065 mFollowVisibilityPresetCombo->blockSignals( b );
1066 mKeepLayerListCheckBox->blockSignals( b );
1067 mKeepLayerStylesCheckBox->blockSignals( b );
1068 mActionSetToCanvasExtent->blockSignals( b );
1069 mActionUpdatePreview->blockSignals( b );
1070 mTemporalCheckBox->blockSignals( b );
1071 mStartDateTime->blockSignals( b );
1072 mEndDateTime->blockSignals( b );
1073
1074 blockOverviewItemsSignals( b );
1075}
1076
1077void QgsLayoutMapWidget::updatePreview()
1078{
1079 if ( !mMapItem )
1080 {
1081 return;
1082 }
1083 mMapItem->refresh();
1084}
1085
1086void QgsLayoutMapWidget::mFollowVisibilityPresetCheckBox_stateChanged( int state )
1087{
1088 if ( !mMapItem )
1089 {
1090 return;
1091 }
1092
1093 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map Preset" ) );
1094 if ( state == Qt::Checked )
1095 {
1096 mMapItem->setFollowVisibilityPreset( true );
1097
1098 // mutually exclusive with keeping custom layer list
1099 mKeepLayerListCheckBox->setCheckState( Qt::Unchecked );
1100 mKeepLayerStylesCheckBox->setCheckState( Qt::Unchecked );
1101
1102 mMapItem->invalidateCache();
1103 }
1104 else
1105 {
1106 mMapItem->setFollowVisibilityPreset( false );
1107 }
1108 mMapItem->layout()->undoStack()->endCommand();
1109}
1110
1111void QgsLayoutMapWidget::mKeepLayerListCheckBox_stateChanged( int state )
1112{
1113 if ( !mMapItem )
1114 {
1115 return;
1116 }
1117
1118 // update map
1119 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Map Preset Changed" ) );
1120 storeCurrentLayerSet();
1121 mMapItem->setKeepLayerSet( state == Qt::Checked );
1122 if ( state == Qt::Unchecked )
1123 {
1124 mMapItem->setLayers( QList< QgsMapLayer * >() );
1125 }
1126 mMapItem->layout()->undoStack()->endCommand();
1127
1128 // update gui
1129 if ( state == Qt::Checked )
1130 {
1131 // mutually exclusive with following a preset
1132 mFollowVisibilityPresetCheckBox->setCheckState( Qt::Unchecked );
1133 }
1134 else
1135 {
1136 mKeepLayerStylesCheckBox->setChecked( Qt::Unchecked );
1137 mMapItem->invalidateCache();
1138 }
1139
1140 mKeepLayerStylesCheckBox->setEnabled( state == Qt::Checked );
1141}
1142
1143void QgsLayoutMapWidget::mKeepLayerStylesCheckBox_stateChanged( int state )
1144{
1145 if ( !mMapItem )
1146 {
1147 return;
1148 }
1149
1150 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Map Preset" ) );
1151 if ( state == Qt::Checked )
1152 {
1153 mMapItem->storeCurrentLayerStyles();
1154 mMapItem->setKeepLayerStyles( true );
1155 }
1156 else
1157 {
1158 mMapItem->setLayerStyleOverrides( QMap<QString, QString>() );
1159 mMapItem->setKeepLayerStyles( false );
1160 }
1161 mMapItem->layout()->undoStack()->endCommand();
1162}
1163
1164void QgsLayoutMapWidget::mDrawCanvasItemsCheckBox_stateChanged( int state )
1165{
1166 if ( !mMapItem )
1167 {
1168 return;
1169 }
1170
1171 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Toggle Map Item" ) );
1172 mMapItem->setDrawAnnotations( state == Qt::Checked );
1173 mMapItem->invalidateCache();
1174 mMapItem->layout()->undoStack()->endCommand();
1175}
1176
1177void QgsLayoutMapWidget::atlasLayerChanged( QgsVectorLayer *layer )
1178{
1179 if ( !layer || layer->wkbType() == Qgis::WkbType::NoGeometry )
1180 {
1181 //geometryless layer, disable atlas control
1182 mAtlasCheckBox->setChecked( false );
1183 mAtlasCheckBox->setEnabled( false );
1184 return;
1185 }
1186 else
1187 {
1188 mAtlasCheckBox->setEnabled( true );
1189 }
1190
1191 // enable or disable fixed scale control based on layer type
1192 if ( mAtlasCheckBox->isChecked() )
1193 toggleAtlasScalingOptionsByLayerType();
1194}
1195
1196bool QgsLayoutMapWidget::hasPredefinedScales() const
1197{
1198 // first look at project's scales
1199 const QVector< double > scales( QgsProject::instance()->viewSettings()->mapScales() );
1200 const bool hasProjectScales( QgsProject::instance()->viewSettings()->useProjectScales() );
1201 if ( !hasProjectScales || scales.isEmpty() )
1202 {
1203 // default to global map tool scales
1204 const QgsSettings settings;
1205 const QStringList scales = QgsSettingsRegistryCore::settingsMapScales->value();
1206 return !scales.isEmpty() && !scales[0].isEmpty();
1207 }
1208 return true;
1209}
1210
1211void QgsLayoutMapWidget::mAddGridPushButton_clicked()
1212{
1213 if ( !mMapItem )
1214 {
1215 return;
1216 }
1217
1218 const QString itemName = tr( "Grid %1" ).arg( mMapItem->grids()->size() + 1 );
1219 QgsLayoutItemMapGrid *grid = new QgsLayoutItemMapGrid( itemName, mMapItem );
1220 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Add Map Grid" ) );
1221 mMapItem->grids()->addGrid( grid );
1222 mMapItem->layout()->undoStack()->endCommand();
1223 mMapItem->updateBoundingRect();
1224 mMapItem->update();
1225
1226 addGridListItem( grid->id(), grid->name() );
1227 mGridListWidget->setCurrentRow( 0 );
1228 mGridListWidget_currentItemChanged( mGridListWidget->currentItem(), nullptr );
1229}
1230
1231void QgsLayoutMapWidget::mRemoveGridPushButton_clicked()
1232{
1233 QListWidgetItem *item = mGridListWidget->currentItem();
1234 if ( !item )
1235 {
1236 return;
1237 }
1238
1239 mMapItem->beginCommand( tr( "Remove Grid" ) );
1240 mMapItem->grids()->removeGrid( item->data( Qt::UserRole ).toString() );
1241 QListWidgetItem *delItem = mGridListWidget->takeItem( mGridListWidget->row( item ) );
1242 delete delItem;
1243 mMapItem->endCommand();
1244 mMapItem->updateBoundingRect();
1245 mMapItem->update();
1246}
1247
1248void QgsLayoutMapWidget::mGridUpButton_clicked()
1249{
1250 QListWidgetItem *item = mGridListWidget->currentItem();
1251 if ( !item )
1252 {
1253 return;
1254 }
1255
1256 const int row = mGridListWidget->row( item );
1257 if ( row < 1 )
1258 {
1259 return;
1260 }
1261 mGridListWidget->takeItem( row );
1262 mGridListWidget->insertItem( row - 1, item );
1263 mGridListWidget->setCurrentItem( item );
1264 mMapItem->beginCommand( tr( "Move Grid Up" ) );
1265 mMapItem->grids()->moveGridUp( item->data( Qt::UserRole ).toString() );
1266 mMapItem->endCommand();
1267 mMapItem->update();
1268}
1269
1270void QgsLayoutMapWidget::mGridDownButton_clicked()
1271{
1272 QListWidgetItem *item = mGridListWidget->currentItem();
1273 if ( !item )
1274 {
1275 return;
1276 }
1277
1278 const int row = mGridListWidget->row( item );
1279 if ( mGridListWidget->count() <= row )
1280 {
1281 return;
1282 }
1283 mGridListWidget->takeItem( row );
1284 mGridListWidget->insertItem( row + 1, item );
1285 mGridListWidget->setCurrentItem( item );
1286 mMapItem->beginCommand( tr( "Move Grid Down" ) );
1287 mMapItem->grids()->moveGridDown( item->data( Qt::UserRole ).toString() );
1288 mMapItem->endCommand();
1289 mMapItem->update();
1290}
1291
1292QgsLayoutItemMapGrid *QgsLayoutMapWidget::currentGrid()
1293{
1294 if ( !mMapItem )
1295 {
1296 return nullptr;
1297 }
1298
1299 QListWidgetItem *item = mGridListWidget->currentItem();
1300 if ( !item )
1301 {
1302 return nullptr;
1303 }
1304 return mMapItem->grids()->grid( item->data( Qt::UserRole ).toString() );
1305}
1306
1307void QgsLayoutMapWidget::mGridListWidget_currentItemChanged( QListWidgetItem *current, QListWidgetItem * )
1308{
1309 mGridPropertiesButton->setEnabled( static_cast< bool >( current ) );
1310}
1311
1312void QgsLayoutMapWidget::mGridListWidget_itemChanged( QListWidgetItem *item )
1313{
1314 if ( !mMapItem )
1315 {
1316 return;
1317 }
1318
1319 QgsLayoutItemMapGrid *grid = mMapItem->grids()->grid( item->data( Qt::UserRole ).toString() );
1320 if ( !grid )
1321 {
1322 return;
1323 }
1324
1325 mMapItem->beginCommand( tr( "Rename Grid" ) );
1326 grid->setName( item->text() );
1327 mMapItem->endCommand();
1328}
1329
1330void QgsLayoutMapWidget::mGridPropertiesButton_clicked()
1331{
1332 if ( !mMapItem )
1333 {
1334 return;
1335 }
1336 QgsLayoutItemMapGrid *grid = currentGrid();
1337 if ( !grid )
1338 {
1339 return;
1340 }
1341
1342 QgsLayoutMapGridWidget *w = new QgsLayoutMapGridWidget( grid, mMapItem );
1343 w->setDesignerInterface( mInterface );
1344 openPanel( w );
1345}
1346
1347QListWidgetItem *QgsLayoutMapWidget::addGridListItem( const QString &id, const QString &name )
1348{
1349 QListWidgetItem *item = new QListWidgetItem( name, nullptr );
1350 item->setData( Qt::UserRole, id );
1351 item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable );
1352 mGridListWidget->insertItem( 0, item );
1353 return item;
1354}
1355
1356void QgsLayoutMapWidget::loadGridEntries()
1357{
1358 //save selection
1359 QSet<QString> selectedIds;
1360 const QList<QListWidgetItem *> itemSelection = mGridListWidget->selectedItems();
1361 QList<QListWidgetItem *>::const_iterator sIt = itemSelection.constBegin();
1362 for ( ; sIt != itemSelection.constEnd(); ++sIt )
1363 {
1364 selectedIds.insert( ( *sIt )->data( Qt::UserRole ).toString() );
1365 }
1366
1367 mGridListWidget->clear();
1368 if ( !mMapItem )
1369 {
1370 return;
1371 }
1372 //load all composer grids into list widget
1373 const QList< QgsLayoutItemMapGrid * > grids = mMapItem->grids()->asList();
1374 QList< QgsLayoutItemMapGrid * >::const_iterator gridIt = grids.constBegin();
1375 for ( ; gridIt != grids.constEnd(); ++gridIt )
1376 {
1377 QListWidgetItem *item = addGridListItem( ( *gridIt )->id(), ( *gridIt )->name() );
1378 if ( selectedIds.contains( ( *gridIt )->id() ) )
1379 {
1380 item->setSelected( true );
1381 mGridListWidget->setCurrentItem( item );
1382 }
1383 }
1384
1385 if ( mGridListWidget->currentItem() )
1386 {
1387 mGridListWidget_currentItemChanged( mGridListWidget->currentItem(), nullptr );
1388 }
1389 else
1390 {
1391 mGridListWidget_currentItemChanged( nullptr, nullptr );
1392 }
1393}
1394
1395void QgsLayoutMapWidget::mAddOverviewPushButton_clicked()
1396{
1397 if ( !mMapItem )
1398 {
1399 return;
1400 }
1401
1402 const QString itemName = tr( "Overview %1" ).arg( mMapItem->overviews()->size() + 1 );
1403 QgsLayoutItemMapOverview *overview = new QgsLayoutItemMapOverview( itemName, mMapItem );
1404 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Add Map Overview" ) );
1405 mMapItem->overviews()->addOverview( overview );
1406 mMapItem->layout()->undoStack()->endCommand();
1407 mMapItem->invalidateCache();
1408
1409 addOverviewListItem( overview->id(), overview->name() );
1410
1411 mOverviewListWidget->setCurrentRow( 0 );
1412}
1413
1414void QgsLayoutMapWidget::mRemoveOverviewPushButton_clicked()
1415{
1416 QListWidgetItem *item = mOverviewListWidget->currentItem();
1417 if ( !item )
1418 {
1419 return;
1420 }
1421 mMapItem->beginCommand( tr( "Remove Map Overview" ) );
1422 mMapItem->overviews()->removeOverview( item->data( Qt::UserRole ).toString() );
1423 mMapItem->endCommand();
1424 QListWidgetItem *delItem = mOverviewListWidget->takeItem( mOverviewListWidget->row( item ) );
1425 delete delItem;
1426 mMapItem->invalidateCache();
1427}
1428
1429void QgsLayoutMapWidget::mOverviewUpButton_clicked()
1430{
1431 QListWidgetItem *item = mOverviewListWidget->currentItem();
1432 if ( !item )
1433 {
1434 return;
1435 }
1436
1437 const int row = mOverviewListWidget->row( item );
1438 if ( row < 1 )
1439 {
1440 return;
1441 }
1442 mOverviewListWidget->takeItem( row );
1443 mOverviewListWidget->insertItem( row - 1, item );
1444 mOverviewListWidget->setCurrentItem( item );
1445 mMapItem->beginCommand( tr( "Move Overview Up" ) );
1446 mMapItem->overviews()->moveOverviewUp( item->data( Qt::UserRole ).toString() );
1447 mMapItem->endCommand();
1448 mMapItem->invalidateCache();
1449}
1450
1451void QgsLayoutMapWidget::mOverviewDownButton_clicked()
1452{
1453 QListWidgetItem *item = mOverviewListWidget->currentItem();
1454 if ( !item )
1455 {
1456 return;
1457 }
1458
1459 const int row = mOverviewListWidget->row( item );
1460 if ( mOverviewListWidget->count() <= row )
1461 {
1462 return;
1463 }
1464 mOverviewListWidget->takeItem( row );
1465 mOverviewListWidget->insertItem( row + 1, item );
1466 mOverviewListWidget->setCurrentItem( item );
1467 mMapItem->beginCommand( tr( "Move Overview Down" ) );
1468 mMapItem->overviews()->moveOverviewDown( item->data( Qt::UserRole ).toString() );
1469 mMapItem->endCommand();
1470 mMapItem->invalidateCache();
1471}
1472
1473QgsLayoutItemMapOverview *QgsLayoutMapWidget::currentOverview()
1474{
1475 if ( !mMapItem )
1476 {
1477 return nullptr;
1478 }
1479
1480 QListWidgetItem *item = mOverviewListWidget->currentItem();
1481 if ( !item )
1482 {
1483 return nullptr;
1484 }
1485
1486 return mMapItem->overviews()->overview( item->data( Qt::UserRole ).toString() );
1487}
1488
1489void QgsLayoutMapWidget::mOverviewListWidget_currentItemChanged( QListWidgetItem *current, QListWidgetItem *previous )
1490{
1491 Q_UNUSED( previous )
1492 if ( !current )
1493 {
1494 mOverviewCheckBox->setEnabled( false );
1495 return;
1496 }
1497
1498 mOverviewCheckBox->setEnabled( true );
1499 setOverviewItems( mMapItem->overviews()->overview( current->data( Qt::UserRole ).toString() ) );
1500}
1501
1502void QgsLayoutMapWidget::mOverviewListWidget_itemChanged( QListWidgetItem *item )
1503{
1504 if ( !mMapItem )
1505 {
1506 return;
1507 }
1508
1509 QgsLayoutItemMapOverview *overview = mMapItem->overviews()->overview( item->data( Qt::UserRole ).toString() );
1510 if ( !overview )
1511 {
1512 return;
1513 }
1514
1515 mMapItem->beginCommand( QStringLiteral( "Rename Overview" ) );
1516 overview->setName( item->text() );
1517 mMapItem->endCommand();
1518 if ( item->isSelected() )
1519 {
1520 //update checkbox title if item is current item
1521 mOverviewCheckBox->setTitle( tr( "Draw \"%1\" overview" ).arg( overview->name() ) );
1522 }
1523}
1524
1525void QgsLayoutMapWidget::setOverviewItemsEnabled( bool enabled )
1526{
1527 mOverviewFrameMapLabel->setEnabled( enabled );
1528 mOverviewFrameMapComboBox->setEnabled( enabled );
1529 mOverviewFrameStyleLabel->setEnabled( enabled );
1530 mOverviewFrameStyleButton->setEnabled( enabled );
1531 mOverviewBlendModeLabel->setEnabled( enabled );
1532 mOverviewBlendModeComboBox->setEnabled( enabled );
1533 mOverviewInvertCheckbox->setEnabled( enabled );
1534 mOverviewCenterCheckbox->setEnabled( enabled );
1535 mOverviewPositionComboBox->setEnabled( enabled );
1536
1537 const QgsLayoutItemMapItem::StackingPosition currentStackingPos = static_cast< QgsLayoutItemMapItem::StackingPosition >( mOverviewPositionComboBox->currentData().toInt() );
1538 mOverviewStackingLayerComboBox->setEnabled( enabled && ( currentStackingPos == QgsLayoutItemMapItem::StackAboveMapLayer || currentStackingPos == QgsLayoutItemMapItem::StackBelowMapLayer ) );
1539}
1540
1541void QgsLayoutMapWidget::blockOverviewItemsSignals( const bool block )
1542{
1543 mOverviewFrameMapComboBox->blockSignals( block );
1544 mOverviewFrameStyleButton->blockSignals( block );
1545 mOverviewBlendModeComboBox->blockSignals( block );
1546 mOverviewInvertCheckbox->blockSignals( block );
1547 mOverviewCenterCheckbox->blockSignals( block );
1548 mOverviewPositionComboBox->blockSignals( block );
1549 mOverviewStackingLayerComboBox->blockSignals( block );
1550}
1551
1552void QgsLayoutMapWidget::setOverviewItems( QgsLayoutItemMapOverview *overview )
1553{
1554 if ( !overview )
1555 {
1556 return;
1557 }
1558
1559 blockOverviewItemsSignals( true );
1560
1561 mOverviewCheckBox->setTitle( tr( "Draw \"%1\" overview" ).arg( overview->name() ) );
1562 mOverviewCheckBox->setChecked( overview->enabled() );
1563
1564 //overview frame
1565 mOverviewFrameMapComboBox->setItem( overview->linkedMap() );
1566
1567 //overview frame blending mode
1568 mOverviewBlendModeComboBox->setBlendMode( overview->blendMode() );
1569 //overview inverted
1570 mOverviewInvertCheckbox->setChecked( overview->inverted() );
1571 //center overview
1572 mOverviewCenterCheckbox->setChecked( overview->centered() );
1573
1574 mOverviewPositionComboBox->setCurrentIndex( mOverviewPositionComboBox->findData( overview->stackingPosition() ) );
1575 mOverviewStackingLayerComboBox->setLayer( overview->stackingLayer() );
1576 mOverviewStackingLayerComboBox->setEnabled( mOverviewPositionComboBox->isEnabled() && ( overview->stackingPosition() == QgsLayoutItemMapItem::StackAboveMapLayer
1578
1579 mOverviewFrameStyleButton->setSymbol( overview->frameSymbol()->clone() );
1580
1581 blockOverviewItemsSignals( false );
1582}
1583
1584void QgsLayoutMapWidget::storeCurrentLayerSet()
1585{
1586 if ( !mMapItem )
1587 return;
1588
1589 QList<QgsMapLayer *> layers = mMapCanvas->mapSettings().layers();
1590
1591 mMapItem->setLayers( layers );
1592
1593 if ( mMapItem->keepLayerStyles() )
1594 {
1595 // also store styles associated with the layers
1596 mMapItem->storeCurrentLayerStyles();
1597 }
1598}
1599
1600QList<QgsMapLayer *> QgsLayoutMapWidget::orderedPresetVisibleLayers( const QString &name ) const
1601{
1602 const QStringList visibleIds = QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayerIds( name );
1603
1604 // also make sure to order the layers according to map canvas order
1605 QList<QgsMapLayer *> lst;
1606 const auto constLayerOrder = QgsProject::instance()->layerTreeRoot()->layerOrder();
1607 for ( QgsMapLayer *layer : constLayerOrder )
1608 {
1609 if ( visibleIds.contains( layer->id() ) )
1610 {
1611 lst << layer;
1612 }
1613 }
1614 return lst;
1615}
1616
1617QListWidgetItem *QgsLayoutMapWidget::addOverviewListItem( const QString &id, const QString &name )
1618{
1619 QListWidgetItem *item = new QListWidgetItem( name, nullptr );
1620 item->setData( Qt::UserRole, id );
1621 item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable );
1622 mOverviewListWidget->insertItem( 0, item );
1623 return item;
1624}
1625
1626void QgsLayoutMapWidget::loadOverviewEntries()
1627{
1628 //save selection
1629 QSet<QString> selectedIds;
1630 const QList<QListWidgetItem *> itemSelection = mOverviewListWidget->selectedItems();
1631 QList<QListWidgetItem *>::const_iterator sIt = itemSelection.constBegin();
1632 for ( ; sIt != itemSelection.constEnd(); ++sIt )
1633 {
1634 selectedIds.insert( ( *sIt )->data( Qt::UserRole ).toString() );
1635 }
1636
1637 mOverviewListWidget->clear();
1638 if ( !mMapItem )
1639 {
1640 return;
1641 }
1642
1643 mOverviewFrameMapComboBox->setExceptedItemList( QList< QgsLayoutItem * >() << mMapItem );
1644
1645 //load all composer overviews into list widget
1646 const QList< QgsLayoutItemMapOverview * > overviews = mMapItem->overviews()->asList();
1647 QList< QgsLayoutItemMapOverview * >::const_iterator overviewIt = overviews.constBegin();
1648 for ( ; overviewIt != overviews.constEnd(); ++overviewIt )
1649 {
1650 QListWidgetItem *item = addOverviewListItem( ( *overviewIt )->id(), ( *overviewIt )->name() );
1651 if ( selectedIds.contains( ( *overviewIt )->id() ) )
1652 {
1653 item->setSelected( true );
1654 mOverviewListWidget->setCurrentItem( item );
1655 }
1656 }
1657
1658 if ( mOverviewListWidget->currentItem() )
1659 {
1660 mOverviewListWidget_currentItemChanged( mOverviewListWidget->currentItem(), nullptr );
1661 }
1662 else
1663 {
1664 mOverviewListWidget_currentItemChanged( nullptr, nullptr );
1665 }
1666}
1667
1668void QgsLayoutMapWidget::mOverviewCheckBox_toggled( bool state )
1669{
1670 QgsLayoutItemMapOverview *overview = currentOverview();
1671 if ( !overview )
1672 {
1673 return;
1674 }
1675
1676 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Overview Display Toggled" ) );
1677 overview->setEnabled( state );
1678 mMapItem->invalidateCache();
1679 mMapItem->layout()->undoStack()->endCommand();
1680}
1681
1682void QgsLayoutMapWidget::overviewMapChanged( QgsLayoutItem *item )
1683{
1684 QgsLayoutItemMapOverview *overview = currentOverview();
1685 if ( !overview )
1686 {
1687 return;
1688 }
1689
1690 QgsLayoutItemMap *map = dynamic_cast< QgsLayoutItemMap * >( item );
1691 if ( !map )
1692 return;
1693
1694 mMapItem->beginCommand( tr( "Change Overview Map" ) );
1695 overview->setLinkedMap( map );
1696 mMapItem->invalidateCache();
1697 mMapItem->endCommand();
1698}
1699
1700void QgsLayoutMapWidget::mOverviewBlendModeComboBox_currentIndexChanged( int index )
1701{
1702 Q_UNUSED( index )
1703 QgsLayoutItemMapOverview *overview = currentOverview();
1704 if ( !overview )
1705 {
1706 return;
1707 }
1708
1709 mMapItem->beginCommand( tr( "Change Overview Blend Mode" ) );
1710 overview->setBlendMode( mOverviewBlendModeComboBox->blendMode() );
1711 mMapItem->invalidateCache();
1712 mMapItem->endCommand();
1713}
1714
1715void QgsLayoutMapWidget::mOverviewInvertCheckbox_toggled( bool state )
1716{
1717 QgsLayoutItemMapOverview *overview = currentOverview();
1718 if ( !overview )
1719 {
1720 return;
1721 }
1722
1723 mMapItem->beginCommand( tr( "Toggle Overview Inverted" ) );
1724 overview->setInverted( state );
1725 mMapItem->invalidateCache();
1726 mMapItem->endCommand();
1727}
1728
1729void QgsLayoutMapWidget::mOverviewCenterCheckbox_toggled( bool state )
1730{
1731 QgsLayoutItemMapOverview *overview = currentOverview();
1732 if ( !overview )
1733 {
1734 return;
1735 }
1736
1737 mMapItem->beginCommand( tr( "Toggle Overview Centered" ) );
1738 overview->setCentered( state );
1739 mMapItem->invalidateCache();
1740 mMapItem->endCommand();
1741}
1742
1743void QgsLayoutMapWidget::overviewStackingChanged( int )
1744{
1745 QgsLayoutItemMapOverview *overview = currentOverview();
1746 if ( !overview )
1747 {
1748 return;
1749 }
1750
1751 mMapItem->beginCommand( tr( "Change Overview Position" ) );
1752 overview->setStackingPosition( static_cast< QgsLayoutItemMapItem::StackingPosition >( mOverviewPositionComboBox->currentData().toInt() ) );
1753 mMapItem->invalidateCache();
1754 mMapItem->endCommand();
1755
1756 switch ( overview->stackingPosition() )
1757 {
1761 mOverviewStackingLayerComboBox->setEnabled( false );
1762 break;
1763
1766 mOverviewStackingLayerComboBox->setEnabled( true );
1767 break;
1768 }
1769}
1770
1771void QgsLayoutMapWidget::overviewStackingLayerChanged( QgsMapLayer *layer )
1772{
1773 QgsLayoutItemMapOverview *overview = currentOverview();
1774 if ( !overview )
1775 {
1776 return;
1777 }
1778
1779 mMapItem->beginCommand( tr( "Change Overview Position" ) );
1780 overview->setStackingLayer( layer );
1781 mMapItem->invalidateCache();
1782 mMapItem->endCommand();
1783}
1784
1785//
1786// QgsLayoutMapLabelingWidget
1787//
1788
1790 : QgsLayoutItemBaseWidget( nullptr, map )
1791 , mMapItem( map )
1792{
1793 setupUi( this );
1794 setPanelTitle( tr( "Label Settings" ) );
1795
1796 mLabelBoundarySpinBox->setClearValue( 0 );
1797 mLabelBoundarySpinBox->setShowClearButton( true );
1798
1799 mLabelBoundaryUnitsCombo->linkToWidget( mLabelBoundarySpinBox );
1800 mLabelBoundaryUnitsCombo->setConverter( &mMapItem->layout()->renderContext().measurementConverter() );
1801
1802 connect( mLabelBoundaryUnitsCombo, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutMapLabelingWidget::labelMarginUnitsChanged );
1803 connect( mLabelBoundarySpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutMapLabelingWidget::labelMarginChanged );
1804 connect( mShowPartialLabelsCheckBox, &QCheckBox::toggled, this, &QgsLayoutMapLabelingWidget::showPartialsToggled );
1805 connect( mShowUnplacedCheckBox, &QCheckBox::toggled, this, &QgsLayoutMapLabelingWidget::showUnplacedToggled );
1806
1808
1809 setNewItem( map );
1810}
1811
1813{
1814 if ( item->type() != QgsLayoutItemRegistry::LayoutMap )
1815 return false;
1816
1817 if ( mMapItem )
1818 {
1819 disconnect( mMapItem, &QgsLayoutObject::changed, this, &QgsLayoutMapLabelingWidget::updateGuiElements );
1820 }
1821
1822 mMapItem = qobject_cast< QgsLayoutItemMap * >( item );
1823
1824 if ( mMapItem )
1825 {
1826 connect( mMapItem, &QgsLayoutObject::changed, this, &QgsLayoutMapLabelingWidget::updateGuiElements );
1827 }
1828
1829 updateGuiElements();
1830
1831 return true;
1832}
1833
1834void QgsLayoutMapLabelingWidget::updateGuiElements()
1835{
1836 whileBlocking( mLabelBoundarySpinBox )->setValue( mMapItem->labelMargin().length() );
1837 whileBlocking( mLabelBoundaryUnitsCombo )->setUnit( mMapItem->labelMargin().units() );
1838 whileBlocking( mShowPartialLabelsCheckBox )->setChecked( mMapItem->mapFlags() & QgsLayoutItemMap::ShowPartialLabels );
1839 whileBlocking( mShowUnplacedCheckBox )->setChecked( mMapItem->mapFlags() & QgsLayoutItemMap::ShowUnplacedLabels );
1840
1841 if ( mBlockingItemsListView->model() )
1842 {
1843 QAbstractItemModel *oldModel = mBlockingItemsListView->model();
1844 mBlockingItemsListView->setModel( nullptr );
1845 oldModel->deleteLater();
1846 }
1847
1848 QgsLayoutMapItemBlocksLabelsModel *model = new QgsLayoutMapItemBlocksLabelsModel( mMapItem, mMapItem->layout()->itemsModel(), mBlockingItemsListView );
1849 mBlockingItemsListView->setModel( model );
1850
1851 updateDataDefinedButton( mLabelMarginDDBtn );
1852}
1853
1854void QgsLayoutMapLabelingWidget::labelMarginChanged( double val )
1855{
1856 if ( !mMapItem )
1857 return;
1858
1859 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Label Margin" ), QgsLayoutItem::UndoMapLabelMargin );
1860 mMapItem->setLabelMargin( QgsLayoutMeasurement( val, mLabelBoundaryUnitsCombo->unit() ) );
1861 mMapItem->layout()->undoStack()->endCommand();
1862 mMapItem->invalidateCache();
1863}
1864
1865void QgsLayoutMapLabelingWidget::labelMarginUnitsChanged()
1866{
1867 if ( !mMapItem )
1868 return;
1869
1870 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Label Margin" ), QgsLayoutItem::UndoMapLabelMargin );
1871 mMapItem->setLabelMargin( QgsLayoutMeasurement( mLabelBoundarySpinBox->value(), mLabelBoundaryUnitsCombo->unit() ) );
1872 mMapItem->layout()->undoStack()->endCommand();
1873 mMapItem->invalidateCache();
1874}
1875
1876void QgsLayoutMapLabelingWidget::showPartialsToggled( bool checked )
1877{
1878 if ( !mMapItem )
1879 return;
1880
1881 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Label Visibility" ) );
1882 QgsLayoutItemMap::MapItemFlags flags = mMapItem->mapFlags();
1883 if ( checked )
1885 else
1886 flags &= ~QgsLayoutItemMap::ShowPartialLabels;
1887 mMapItem->setMapFlags( flags );
1888 mMapItem->layout()->undoStack()->endCommand();
1889 mMapItem->invalidateCache();
1890}
1891
1892void QgsLayoutMapLabelingWidget::showUnplacedToggled( bool checked )
1893{
1894 if ( !mMapItem )
1895 return;
1896
1897 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Label Visibility" ) );
1898 QgsLayoutItemMap::MapItemFlags flags = mMapItem->mapFlags();
1899 if ( checked )
1901 else
1902 flags &= ~QgsLayoutItemMap::ShowUnplacedLabels;
1903 mMapItem->setMapFlags( flags );
1904 mMapItem->layout()->undoStack()->endCommand();
1905 mMapItem->invalidateCache();
1906}
1907
1909 : QSortFilterProxyModel( parent )
1910 , mLayoutModel( layoutModel )
1911 , mMapItem( map )
1912{
1913 setSourceModel( layoutModel );
1914}
1915
1917{
1918 return 1;
1919}
1920
1921QVariant QgsLayoutMapItemBlocksLabelsModel::data( const QModelIndex &i, int role ) const
1922{
1923 if ( !i.isValid() )
1924 return QVariant();
1925
1926 if ( i.column() != 0 )
1927 return QVariant();
1928
1929 const QModelIndex sourceIndex = mapToSource( index( i.row(), QgsLayoutModel::ItemId, i.parent() ) );
1930
1931 QgsLayoutItem *item = mLayoutModel->itemFromIndex( mapToSource( i ) );
1932 if ( !item )
1933 {
1934 return QVariant();
1935 }
1936
1937 switch ( role )
1938 {
1939 case Qt::CheckStateRole:
1940 switch ( i.column() )
1941 {
1942 case 0:
1943 return mMapItem ? ( mMapItem->isLabelBlockingItem( item ) ? Qt::Checked : Qt::Unchecked ) : Qt::Unchecked;
1944 default:
1945 return QVariant();
1946 }
1947
1948 default:
1949 return mLayoutModel->data( sourceIndex, role );
1950 }
1951}
1952
1953bool QgsLayoutMapItemBlocksLabelsModel::setData( const QModelIndex &index, const QVariant &value, int role )
1954{
1955 Q_UNUSED( role )
1956
1957 if ( !index.isValid() )
1958 return false;
1959
1960 QgsLayoutItem *item = mLayoutModel->itemFromIndex( mapToSource( index ) );
1961 if ( !item || !mMapItem )
1962 {
1963 return false;
1964 }
1965
1966 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Label Blocking Items" ) );
1967
1968 if ( value.toBool() )
1969 {
1970 mMapItem->addLabelBlockingItem( item );
1971 }
1972 else
1973 {
1974 mMapItem->removeLabelBlockingItem( item );
1975 }
1976 emit dataChanged( index, index, QVector<int>() << role );
1977
1978 mMapItem->layout()->undoStack()->endCommand();
1979 mMapItem->invalidateCache();
1980
1981 return true;
1982}
1983
1984Qt::ItemFlags QgsLayoutMapItemBlocksLabelsModel::flags( const QModelIndex &index ) const
1985{
1986 Qt::ItemFlags flags = QSortFilterProxyModel::flags( index );
1987
1988 if ( ! index.isValid() )
1989 {
1990 return flags ;
1991 }
1992
1993 switch ( index.column() )
1994 {
1995 case 0:
1996 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
1997 default:
1998 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
1999 }
2000}
2001
2002bool QgsLayoutMapItemBlocksLabelsModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
2003{
2004 QgsLayoutItem *item = mLayoutModel->itemFromIndex( mLayoutModel->index( source_row, 0, source_parent ) );
2005 if ( !item || item == mMapItem )
2006 {
2007 return false;
2008 }
2009
2010 return true;
2011}
2012
2013
2014
2015//
2016// QgsLayoutMapClippingWidget
2017//
2018
2020 : QgsLayoutItemBaseWidget( nullptr, map )
2021 , mMapItem( map )
2022{
2023 setupUi( this );
2024 setPanelTitle( tr( "Clipping Settings" ) );
2025
2026 mLayerModel = new QgsMapLayerModel( this );
2027 mLayerModel->setItemsCheckable( true );
2028 mLayersTreeView->setModel( mLayerModel );
2029
2030 mAtlasClippingTypeComboBox->addItem( tr( "Clip During Render Only" ), static_cast< int >( QgsMapClippingRegion::FeatureClippingType::ClipPainterOnly ) );
2031 mAtlasClippingTypeComboBox->addItem( tr( "Clip Feature Before Render" ), static_cast< int >( QgsMapClippingRegion::FeatureClippingType::ClipToIntersection ) );
2032 mAtlasClippingTypeComboBox->addItem( tr( "Render Intersecting Features Unchanged" ), static_cast< int >( QgsMapClippingRegion::FeatureClippingType::NoClipping ) );
2033
2034 for ( int i = 0; i < mAtlasClippingTypeComboBox->count(); ++i )
2035 {
2036 mItemClippingTypeComboBox->addItem( mAtlasClippingTypeComboBox->itemText( i ), mAtlasClippingTypeComboBox->itemData( i ) );
2037 }
2038
2039 mClipItemComboBox->setCurrentLayout( map->layout() );
2040 mClipItemComboBox->setItemFlags( QgsLayoutItem::FlagProvidesClipPath );
2041
2042 connect( mRadioClipSelectedLayers, &QRadioButton::toggled, this, &QgsLayoutMapClippingWidget::toggleLayersSelectionGui );
2043 mLayersTreeView->setEnabled( false );
2044 mSelectAllButton->setEnabled( false );
2045 mDeselectAllButton->setEnabled( false );
2046 mInvertSelectionButton->setEnabled( false );
2047 mRadioClipAllLayers->setChecked( true );
2048
2049 connect( mClipToAtlasCheckBox, &QGroupBox::toggled, this, [ = ]( bool active )
2050 {
2051 if ( !mBlockUpdates )
2052 {
2053 mMapItem->beginCommand( tr( "Toggle Atlas Clipping" ) );
2054 mMapItem->atlasClippingSettings()->setEnabled( active );
2055 mMapItem->endCommand();
2056 }
2057 } );
2058 connect( mForceLabelsInsideCheckBox, &QCheckBox::toggled, this, [ = ]( bool active )
2059 {
2060 if ( !mBlockUpdates )
2061 {
2062 mMapItem->beginCommand( tr( "Change Atlas Clipping Label Behavior" ) );
2063 mMapItem->atlasClippingSettings()->setForceLabelsInsideFeature( active );
2064 mMapItem->endCommand();
2065 }
2066 } );
2067 connect( mAtlasClippingTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]
2068 {
2069 if ( !mBlockUpdates )
2070 {
2071 mMapItem->beginCommand( tr( "Change Atlas Clipping Behavior" ) );
2072 mMapItem->atlasClippingSettings()->setFeatureClippingType( static_cast< QgsMapClippingRegion::FeatureClippingType >( mAtlasClippingTypeComboBox->currentData().toInt() ) );
2073 mMapItem->endCommand();
2074 }
2075 } );
2076
2077 connect( mRadioClipSelectedLayers, &QCheckBox::toggled, this, [ = ]( bool active )
2078 {
2079 if ( active && !mBlockUpdates )
2080 {
2081 mBlockUpdates = true;
2082 mMapItem->beginCommand( tr( "Change Atlas Clipping Layers" ) );
2083 mMapItem->atlasClippingSettings()->setRestrictToLayers( true );
2084 mMapItem->endCommand();
2085 mBlockUpdates = false;
2086 }
2087 } );
2088 // layers selection buttons
2089 connect( mSelectAllButton, &QPushButton::clicked, this, &QgsLayoutMapClippingWidget::selectAll );
2090 connect( mDeselectAllButton, &QPushButton::clicked, this, &QgsLayoutMapClippingWidget::deselectAll );
2091 connect( mInvertSelectionButton, &QPushButton::clicked, this, &QgsLayoutMapClippingWidget::invertSelection );
2092
2093 connect( mRadioClipAllLayers, &QCheckBox::toggled, this, [ = ]( bool active )
2094 {
2095 if ( active && !mBlockUpdates )
2096 {
2097 mBlockUpdates = true;
2098 mMapItem->beginCommand( tr( "Change Atlas Clipping Layers" ) );
2099 mMapItem->atlasClippingSettings()->setRestrictToLayers( false );
2100 mMapItem->endCommand();
2101 mBlockUpdates = false;
2102 }
2103 } );
2104 connect( mLayerModel, &QgsMapLayerModel::dataChanged, this, [ = ]( const QModelIndex &, const QModelIndex &, const QVector<int> &roles = QVector<int>() )
2105 {
2106 if ( !roles.contains( Qt::CheckStateRole ) )
2107 return;
2108
2109 if ( !mBlockUpdates )
2110 {
2111 mBlockUpdates = true;
2112 mMapItem->beginCommand( tr( "Change Atlas Clipping Layers" ) );
2113 mMapItem->atlasClippingSettings()->setLayersToClip( mLayerModel->layersChecked() );
2114 mMapItem->endCommand();
2115 mBlockUpdates = false;
2116 }
2117 } );
2118
2119 // item clipping widgets
2120
2121 connect( mClipToItemCheckBox, &QGroupBox::toggled, this, [ = ]( bool active )
2122 {
2123 if ( !mBlockUpdates )
2124 {
2125 mMapItem->beginCommand( tr( "Toggle Map Clipping" ) );
2126 mMapItem->itemClippingSettings()->setEnabled( active );
2127 mMapItem->endCommand();
2128 }
2129 } );
2130 connect( mItemClippingTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]
2131 {
2132 if ( !mBlockUpdates )
2133 {
2134 mMapItem->beginCommand( tr( "Change Map Clipping Behavior" ) );
2135 mMapItem->itemClippingSettings()->setFeatureClippingType( static_cast< QgsMapClippingRegion::FeatureClippingType >( mItemClippingTypeComboBox->currentData().toInt() ) );
2136 mMapItem->endCommand();
2137 }
2138 } );
2139 connect( mForceLabelsInsideItemCheckBox, &QCheckBox::toggled, this, [ = ]( bool active )
2140 {
2141 if ( !mBlockUpdates )
2142 {
2143 mMapItem->beginCommand( tr( "Change Map Clipping Label Behavior" ) );
2144 mMapItem->itemClippingSettings()->setForceLabelsInsideClipPath( active );
2145 mMapItem->endCommand();
2146 }
2147 } );
2148 connect( mClipItemComboBox, &QgsLayoutItemComboBox::itemChanged, this, [ = ]( QgsLayoutItem * item )
2149 {
2150 if ( !mBlockUpdates )
2151 {
2152 mMapItem->beginCommand( tr( "Change Map Clipping Item" ) );
2153 mMapItem->itemClippingSettings()->setSourceItem( item );
2154 mMapItem->endCommand();
2155 }
2156 } );
2157
2158 setNewItem( map );
2159
2161 this, &QgsLayoutMapClippingWidget::atlasLayerChanged );
2162 if ( QgsLayoutAtlas *atlas = layoutAtlas() )
2163 {
2164 connect( atlas, &QgsLayoutAtlas::toggled, this, &QgsLayoutMapClippingWidget::atlasToggled );
2165 atlasToggled( atlas->enabled() );
2166 }
2167}
2168
2170{
2171 mClipToAtlasCheckBox->setTitle( tr( "Clip to %1 feature" ).arg( string ) );
2172 mClipToAtlasLabel->setText( tr( "<b>When enabled, map layers will be automatically clipped to the boundary of the current %1 feature.</b>" ).arg( string ) );
2173 mForceLabelsInsideCheckBox->setText( tr( "Force labels inside %1 feature" ).arg( string ) );
2174}
2175
2177{
2178 if ( item->type() != QgsLayoutItemRegistry::LayoutMap )
2179 return false;
2180
2181 if ( mMapItem )
2182 {
2183 disconnect( mMapItem, &QgsLayoutObject::changed, this, &QgsLayoutMapClippingWidget::updateGuiElements );
2184 }
2185
2186 mMapItem = qobject_cast< QgsLayoutItemMap * >( item );
2187
2188 if ( mMapItem )
2189 {
2190 connect( mMapItem, &QgsLayoutObject::changed, this, &QgsLayoutMapClippingWidget::updateGuiElements );
2191 }
2192
2193 updateGuiElements();
2194
2195 return true;
2196}
2197
2198void QgsLayoutMapClippingWidget::updateGuiElements()
2199{
2200 if ( mBlockUpdates )
2201 return;
2202
2203 mBlockUpdates = true;
2204 mClipToAtlasCheckBox->setChecked( mMapItem->atlasClippingSettings()->enabled() );
2205 mAtlasClippingTypeComboBox->setCurrentIndex( mAtlasClippingTypeComboBox->findData( static_cast< int >( mMapItem->atlasClippingSettings()->featureClippingType() ) ) );
2206 mForceLabelsInsideCheckBox->setChecked( mMapItem->atlasClippingSettings()->forceLabelsInsideFeature() );
2207
2208 mRadioClipAllLayers->setChecked( !mMapItem->atlasClippingSettings()->restrictToLayers() );
2209 mRadioClipSelectedLayers->setChecked( mMapItem->atlasClippingSettings()->restrictToLayers() );
2210 mLayerModel->setLayersChecked( mMapItem->atlasClippingSettings()->layersToClip() );
2211
2212 mClipToItemCheckBox->setChecked( mMapItem->itemClippingSettings()->enabled() );
2213 mItemClippingTypeComboBox->setCurrentIndex( mItemClippingTypeComboBox->findData( static_cast< int >( mMapItem->itemClippingSettings()->featureClippingType() ) ) );
2214 mForceLabelsInsideItemCheckBox->setChecked( mMapItem->itemClippingSettings()->forceLabelsInsideClipPath() );
2215 mClipItemComboBox->setItem( mMapItem->itemClippingSettings()->sourceItem() );
2216
2217 mBlockUpdates = false;
2218}
2219
2220void QgsLayoutMapClippingWidget::atlasLayerChanged( QgsVectorLayer *layer )
2221{
2222 if ( !layer || layer->geometryType() != Qgis::GeometryType::Polygon )
2223 {
2224 //non-polygon layer, disable atlas control
2225 mClipToAtlasCheckBox->setChecked( false );
2226 mClipToAtlasCheckBox->setEnabled( false );
2227 return;
2228 }
2229 else
2230 {
2231 mClipToAtlasCheckBox->setEnabled( true );
2232 }
2233}
2234
2235void QgsLayoutMapClippingWidget::atlasToggled( bool atlasEnabled )
2236{
2237 if ( atlasEnabled &&
2238 mMapItem && mMapItem->layout() && mMapItem->layout()->reportContext().layer()
2239 && mMapItem->layout()->reportContext().layer()->geometryType() == Qgis::GeometryType::Polygon )
2240 {
2241 mClipToAtlasCheckBox->setEnabled( true );
2242 }
2243 else
2244 {
2245 mClipToAtlasCheckBox->setEnabled( false );
2246 mClipToAtlasCheckBox->setChecked( false );
2247 }
2248}
2249
2250void QgsLayoutMapClippingWidget::invertSelection()
2251{
2252 for ( int i = 0; i < mLayerModel->rowCount( QModelIndex() ); i++ )
2253 {
2254 QModelIndex index = mLayerModel->index( i, 0 );
2255 Qt::CheckState currentState = Qt::CheckState( mLayerModel->data( index, Qt::CheckStateRole ).toInt() );
2256 Qt::CheckState newState = ( currentState == Qt::Checked ) ? Qt::Unchecked : Qt::Checked;
2257 mLayerModel->setData( index, newState, Qt::CheckStateRole );
2258 }
2259}
2260
2261void QgsLayoutMapClippingWidget::selectAll()
2262{
2263 for ( int i = 0; i < mLayerModel->rowCount( QModelIndex() ); i++ )
2264 {
2265 QModelIndex index = mLayerModel->index( i, 0 );
2266 mLayerModel->setData( index, Qt::Checked, Qt::CheckStateRole );
2267 }
2268}
2269
2270void QgsLayoutMapClippingWidget::deselectAll()
2271{
2272 for ( int i = 0; i < mLayerModel->rowCount( QModelIndex() ); i++ )
2273 {
2274 QModelIndex index = mLayerModel->index( i, 0 );
2275 mLayerModel->setData( index, Qt::Unchecked, Qt::CheckStateRole );
2276 }
2277}
2278
2279void QgsLayoutMapClippingWidget::toggleLayersSelectionGui( bool toggled )
2280{
2281 mLayersTreeView->setEnabled( toggled );
2282 mSelectAllButton->setEnabled( toggled );
2283 mDeselectAllButton->setEnabled( toggled );
2284 mInvertSelectionButton->setEnabled( toggled );
2285}
@ Polygon
Polygons.
@ Fill
Fill symbol.
@ NoGeometry
No geometry.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsBookmarkManager * bookmarkManager()
Returns the application's bookmark manager, used for storing installation-wide bookmarks.
@ Extent
Bookmark extent as a QgsReferencedRectangle.
A QSortFilterProxyModel subclass for sorting the entries in a QgsBookmarkManagerModel.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:67
QgsRange which stores a range of double values.
Definition: qgsrange.h:231
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgsfillsymbol.h:30
QgsFillSymbol * clone() const override
Returns a deep copy of this symbol.
QList< QgsMapLayer * > layerOrder() const
The order in which layers will be rendered on the canvas.
Class used to render QgsLayout as an atlas, by iterating over the features from an associated vector ...
void toggled(bool)
Emitted when atlas is enabled or disabled.
A common interface for layout designer dialogs and widgets.
virtual void activateTool(StandardTool tool)=0
Activates a standard layout designer tool.
@ ToolMoveItemContent
Move item content tool.
A base class for property widgets for layout items.
void updateDataDefinedButton(QgsPropertyOverrideButton *button)
Updates a previously registered data defined button to reflect the item's current properties.
QgsVectorLayer * coverageLayer() const
Returns the current layout context coverage layer (if set).
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)
void itemChanged(QgsLayoutItem *item)
Emitted whenever the currently selected item changes.
An individual grid which is drawn above the map content in a QgsLayoutItemMap.
QString id() const
Returns the unique id for the map item.
StackingPosition
Item stacking position, specifies where the in the map's stack the item should be rendered.
@ StackBelowMapLabels
Render above all map layers, but below map labels.
@ StackAboveMapLabels
Render above all map layers and labels.
@ StackBelowMapLayer
Render below a specific map layer (see stackingLayer())
@ StackAboveMapLayer
Render above a specific map layer (see stackingLayer())
@ StackBelowMap
Render below all map layers.
void setStackingLayer(QgsMapLayer *layer)
Sets the item's stacking layer, which specifies where the in the map's stack the item should be rende...
virtual void setEnabled(bool enabled)
Controls whether the item will be drawn.
void setStackingPosition(StackingPosition position)
Sets the item's stacking position, which specifies where the in the map's stack the item should be re...
StackingPosition stackingPosition() const
Returns the item's stacking position, which specifies where the in the map's stack the item should be...
QString name() const
Returns the friendly display name for the item.
void setName(const QString &name)
Sets the friendly display name for the item.
bool enabled() const
Returns whether the item will be drawn.
QgsMapLayer * stackingLayer() const
Returns the item's stacking layer, which specifies where the in the map's stack the item should be re...
An individual overview which is drawn above the map content in a QgsLayoutItemMap,...
QgsFillSymbol * frameSymbol()
Returns the fill symbol used for drawing the overview extent.
QPainter::CompositionMode blendMode() const
Retrieves the blending mode used for drawing the overview.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the overview.
bool centered() const
Returns whether the extent of the map is forced to center on the overview.
void setLinkedMap(QgsLayoutItemMap *map)
Sets the map to show the overview extent of.
void setFrameSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used for drawing the overview extent.
bool inverted() const
Returns whether the overview frame is inverted, ie, whether the shaded area is drawn outside the exte...
void setInverted(bool inverted)
Sets whether the overview frame is inverted, ie, whether the shaded area is drawn outside the extent ...
void setCentered(bool centered)
Sets whether the extent of the map is forced to center on the overview.
QgsLayoutItemMap * linkedMap()
Returns the source map to show the overview extent of.
Layout graphical items for displaying a map.
void extentChanged()
Emitted when the map's extent changes.
@ Predefined
A scale is chosen from the predefined scales.
@ Auto
The extent is adjusted so that each feature is fully visible.
@ Fixed
The current scale of the map is used for each feature of the atlas.
void mapRotationChanged(double newRotation)
Emitted when the map's rotation changes.
QFlags< MapItemFlag > MapItemFlags
@ ShowPartialLabels
Whether to draw labels which are partially outside of the map view.
@ ShowUnplacedLabels
Whether to render unplaced labels in the map view.
A widget for controlling the common properties of layout items (e.g.
void setMasterLayout(QgsMasterLayoutInterface *masterLayout)
Sets the master layout associated with the item.
void setItem(QgsLayoutItem *item)
Sets the layout item.
void updateVariables()
Updates the variables widget, refreshing the values of variables shown.
Base class for graphical items within a QgsLayout.
@ UndoOverviewStyle
Map overview style.
@ UndoMapRotation
Map rotation changed.
@ UndoAtlasMargin
Map atlas margin changed.
@ UndoMapLabelMargin
Margin for labels from edge of map.
int type() const override
Returns a unique graphics item type identifier.
@ FlagProvidesClipPath
Item can act as a clipping path provider (see clipPath())
Allows configuration of layout map clipping settings.
QgsLayoutMapClippingWidget(QgsLayoutItemMap *map)
constructor
void setReportTypeString(const QString &string) override
Sets the string to use to describe the current report type (e.g.
bool setNewItem(QgsLayoutItem *item) final
Attempts to update the widget to show the properties for the specified item.
A widget for configuring layout map grid items.
Model for label blocking items.
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
QgsLayoutMapItemBlocksLabelsModel(QgsLayoutItemMap *map, QgsLayoutModel *layoutModel, QObject *parent=nullptr)
constructor
Qt::ItemFlags flags(const QModelIndex &index) const override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
QVariant data(const QModelIndex &index, int role) const override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Allows configuration of layout map labeling settings.
QgsLayoutMapLabelingWidget(QgsLayoutItemMap *map)
constructor
bool setNewItem(QgsLayoutItem *item) final
Attempts to update the widget to show the properties for the specified item.
void setMasterLayout(QgsMasterLayoutInterface *masterLayout) override
Sets the master layout associated with the item.
bool setNewItem(QgsLayoutItem *item) override
Attempts to update the widget to show the properties for the specified item.
void setReportTypeString(const QString &string) override
Sets the string to use to describe the current report type (e.g.
void populateDataDefinedButtons()
Initializes data defined buttons to current atlas coverage layer.
QgsLayoutMapWidget(QgsLayoutItemMap *item, QgsMapCanvas *mapCanvas)
constructor
void setDesignerInterface(QgsLayoutDesignerInterface *iface) override
Sets the the layout designer interface in which the widget is being shown.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
A model for items attached to a layout.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QVariant data(const QModelIndex &index, int role) const override
QgsLayoutItem * itemFromIndex(const QModelIndex &index) const
Returns the QgsLayoutItem corresponding to a QModelIndex index, if possible.
@ ItemId
Item ID.
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
@ MapYMin
Map extent y minimum.
@ MapZRangeUpper
Map frame Z-range lower value (since QGIS 3.38)
@ StartDateTime
Temporal range's start DateTime.
@ MapZRangeLower
Map frame Z-range lower value (since QGIS 3.38)
@ MapXMax
Map extent x maximum.
@ MapStylePreset
Layer and style map theme.
@ MapYMax
Map extent y maximum.
@ EndDateTime
Temporal range's end DateTime.
@ MapXMin
Map extent x minimum.
@ OriginalValue
Return the original, user set value.
void layerChanged(QgsVectorLayer *layer)
Emitted when the context's layer is changed.
void unitChanged(Qgis::LayoutUnit unit)
Emitted when the unit is changed.
QgsLayoutReportContext & reportContext()
Returns a reference to the layout's report context, which stores information relating to the current ...
Definition: qgslayout.cpp:386
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:93
void zoomScale(double scale, bool ignoreScaleLock=false)
Zooms the canvas to a specific scale.
bool setReferencedExtent(const QgsReferencedRectangle &extent)
Sets the canvas to the specified extent.
double scale() const
Returns the last reported scale of the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
void refresh()
Repaints the canvas map.
FeatureClippingType
Feature clipping behavior, which controls how features from vector layers will be clipped.
@ NoClipping
Only render features which intersect the clipping region, but do not clip these features to the regio...
@ ClipPainterOnly
Applying clipping on the painter only (i.e. feature boundaries will be unchanged, but may be invisibl...
@ ClipToIntersection
Clip the geometry of these features to the region prior to rendering (i.e. feature boundaries will fo...
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
The QgsMapLayerModel class is a model to display layers in widgets.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QList< QgsMapLayer * > layersChecked(Qt::CheckState checkState=Qt::Checked)
layersChecked returns the list of layers which are checked (or unchecked)
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void setItemsCheckable(bool checkable)
setItemsCheckable defines if layers should be selectable in the widget
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
void setLayersChecked(const QList< QgsMapLayer * > &layers)
Sets which layers are checked in the model.
Base class for all map layer types.
Definition: qgsmaplayer.h:75
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QList< QgsMapLayer * > layers(bool expandGroupLayers=false) const
Returns the list of layers which will be rendered in the map.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
void mapThemesChanged()
Emitted when map themes within the collection are changed.
QStringList mapThemeVisibleLayerIds(const QString &name) const
Returns the list of layer IDs that are visible for the specified map theme.
Interface for master layout type objects, such as print layouts and reports.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:481
QgsMapThemeCollection * mapThemeCollection
Definition: qgsproject.h:115
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:112
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
@ CrsNotSet
Not set (hidden by default)
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:201
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:211
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:196
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:206
bool isEmpty() const
Returns true if the rectangle has no area.
Definition: qgsrectangle.h:492
QgsCoordinateReferenceSystem crs() const
Returns the associated coordinate reference system, or an invalid CRS if no reference system is set.
A QgsRectangle with associated coordinate reference system.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
static const QgsSettingsEntryStringList * settingsMapScales
This class is a composition of two QSettings instances:
Definition: qgssettings.h:64
void setLayer(QgsVectorLayer *layer)
Sets a layer to associate with the widget.
void changed()
Emitted when the symbol's settings are changed.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:862
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:5111
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Definition: qgsrange.h:742
const QgsCoordinateReferenceSystem & crs