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