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