QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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
225{
226 mInterface = iface;
228}
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 {
401 xForm.setBallparkTransformsAreAppropriate( true );
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 ), QgsBookmarkManagerModel::RoleGroup ).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 ), QgsBookmarkManagerModel::RoleName ).toString(), mBookmarkMenu );
479 const QgsReferencedRectangle extent = mBookmarkModel->data( mBookmarkModel->index( i, 0 ), QgsBookmarkManagerModel::RoleExtent ).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
949 if ( QgsWkbTypes::geometryType( layer->wkbType() ) == Qgis::GeometryType::Point )
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 const QList<QgsMapLayer *> layers = mMapCanvas->mapSettings().layers();
1536 mMapItem->setLayers( layers );
1537
1538 if ( mMapItem->keepLayerStyles() )
1539 {
1540 // also store styles associated with the layers
1541 mMapItem->storeCurrentLayerStyles();
1542 }
1543}
1544
1545QList<QgsMapLayer *> QgsLayoutMapWidget::orderedPresetVisibleLayers( const QString &name ) const
1546{
1547 const QStringList visibleIds = QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayerIds( name );
1548
1549 // also make sure to order the layers according to map canvas order
1550 QList<QgsMapLayer *> lst;
1551 const auto constLayerOrder = QgsProject::instance()->layerTreeRoot()->layerOrder();
1552 for ( QgsMapLayer *layer : constLayerOrder )
1553 {
1554 if ( visibleIds.contains( layer->id() ) )
1555 {
1556 lst << layer;
1557 }
1558 }
1559 return lst;
1560}
1561
1562QListWidgetItem *QgsLayoutMapWidget::addOverviewListItem( const QString &id, const QString &name )
1563{
1564 QListWidgetItem *item = new QListWidgetItem( name, nullptr );
1565 item->setData( Qt::UserRole, id );
1566 item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable );
1567 mOverviewListWidget->insertItem( 0, item );
1568 return item;
1569}
1570
1571void QgsLayoutMapWidget::loadOverviewEntries()
1572{
1573 //save selection
1574 QSet<QString> selectedIds;
1575 const QList<QListWidgetItem *> itemSelection = mOverviewListWidget->selectedItems();
1576 QList<QListWidgetItem *>::const_iterator sIt = itemSelection.constBegin();
1577 for ( ; sIt != itemSelection.constEnd(); ++sIt )
1578 {
1579 selectedIds.insert( ( *sIt )->data( Qt::UserRole ).toString() );
1580 }
1581
1582 mOverviewListWidget->clear();
1583 if ( !mMapItem )
1584 {
1585 return;
1586 }
1587
1588 mOverviewFrameMapComboBox->setExceptedItemList( QList< QgsLayoutItem * >() << mMapItem );
1589
1590 //load all composer overviews into list widget
1591 const QList< QgsLayoutItemMapOverview * > overviews = mMapItem->overviews()->asList();
1592 QList< QgsLayoutItemMapOverview * >::const_iterator overviewIt = overviews.constBegin();
1593 for ( ; overviewIt != overviews.constEnd(); ++overviewIt )
1594 {
1595 QListWidgetItem *item = addOverviewListItem( ( *overviewIt )->id(), ( *overviewIt )->name() );
1596 if ( selectedIds.contains( ( *overviewIt )->id() ) )
1597 {
1598 item->setSelected( true );
1599 mOverviewListWidget->setCurrentItem( item );
1600 }
1601 }
1602
1603 if ( mOverviewListWidget->currentItem() )
1604 {
1605 mOverviewListWidget_currentItemChanged( mOverviewListWidget->currentItem(), nullptr );
1606 }
1607 else
1608 {
1609 mOverviewListWidget_currentItemChanged( nullptr, nullptr );
1610 }
1611}
1612
1613void QgsLayoutMapWidget::mOverviewCheckBox_toggled( bool state )
1614{
1615 QgsLayoutItemMapOverview *overview = currentOverview();
1616 if ( !overview )
1617 {
1618 return;
1619 }
1620
1621 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Overview Display Toggled" ) );
1622 overview->setEnabled( state );
1623 mMapItem->invalidateCache();
1624 mMapItem->layout()->undoStack()->endCommand();
1625}
1626
1627void QgsLayoutMapWidget::overviewMapChanged( QgsLayoutItem *item )
1628{
1629 QgsLayoutItemMapOverview *overview = currentOverview();
1630 if ( !overview )
1631 {
1632 return;
1633 }
1634
1635 QgsLayoutItemMap *map = dynamic_cast< QgsLayoutItemMap * >( item );
1636 if ( !map )
1637 return;
1638
1639 mMapItem->beginCommand( tr( "Change Overview Map" ) );
1640 overview->setLinkedMap( map );
1641 mMapItem->invalidateCache();
1642 mMapItem->endCommand();
1643}
1644
1645void QgsLayoutMapWidget::mOverviewBlendModeComboBox_currentIndexChanged( int index )
1646{
1647 Q_UNUSED( index )
1648 QgsLayoutItemMapOverview *overview = currentOverview();
1649 if ( !overview )
1650 {
1651 return;
1652 }
1653
1654 mMapItem->beginCommand( tr( "Change Overview Blend Mode" ) );
1655 overview->setBlendMode( mOverviewBlendModeComboBox->blendMode() );
1656 mMapItem->invalidateCache();
1657 mMapItem->endCommand();
1658}
1659
1660void QgsLayoutMapWidget::mOverviewInvertCheckbox_toggled( bool state )
1661{
1662 QgsLayoutItemMapOverview *overview = currentOverview();
1663 if ( !overview )
1664 {
1665 return;
1666 }
1667
1668 mMapItem->beginCommand( tr( "Toggle Overview Inverted" ) );
1669 overview->setInverted( state );
1670 mMapItem->invalidateCache();
1671 mMapItem->endCommand();
1672}
1673
1674void QgsLayoutMapWidget::mOverviewCenterCheckbox_toggled( bool state )
1675{
1676 QgsLayoutItemMapOverview *overview = currentOverview();
1677 if ( !overview )
1678 {
1679 return;
1680 }
1681
1682 mMapItem->beginCommand( tr( "Toggle Overview Centered" ) );
1683 overview->setCentered( state );
1684 mMapItem->invalidateCache();
1685 mMapItem->endCommand();
1686}
1687
1688void QgsLayoutMapWidget::overviewStackingChanged( int )
1689{
1690 QgsLayoutItemMapOverview *overview = currentOverview();
1691 if ( !overview )
1692 {
1693 return;
1694 }
1695
1696 mMapItem->beginCommand( tr( "Change Overview Position" ) );
1697 overview->setStackingPosition( static_cast< QgsLayoutItemMapItem::StackingPosition >( mOverviewPositionComboBox->currentData().toInt() ) );
1698 mMapItem->invalidateCache();
1699 mMapItem->endCommand();
1700
1701 switch ( overview->stackingPosition() )
1702 {
1706 mOverviewStackingLayerComboBox->setEnabled( false );
1707 break;
1708
1711 mOverviewStackingLayerComboBox->setEnabled( true );
1712 break;
1713 }
1714}
1715
1716void QgsLayoutMapWidget::overviewStackingLayerChanged( QgsMapLayer *layer )
1717{
1718 QgsLayoutItemMapOverview *overview = currentOverview();
1719 if ( !overview )
1720 {
1721 return;
1722 }
1723
1724 mMapItem->beginCommand( tr( "Change Overview Position" ) );
1725 overview->setStackingLayer( layer );
1726 mMapItem->invalidateCache();
1727 mMapItem->endCommand();
1728}
1729
1730//
1731// QgsLayoutMapLabelingWidget
1732//
1733
1735 : QgsLayoutItemBaseWidget( nullptr, map )
1736 , mMapItem( map )
1737{
1738 setupUi( this );
1739 setPanelTitle( tr( "Label Settings" ) );
1740
1741 mLabelBoundarySpinBox->setClearValue( 0 );
1742 mLabelBoundarySpinBox->setShowClearButton( true );
1743
1744 mLabelBoundaryUnitsCombo->linkToWidget( mLabelBoundarySpinBox );
1745 mLabelBoundaryUnitsCombo->setConverter( &mMapItem->layout()->renderContext().measurementConverter() );
1746
1747 connect( mLabelBoundaryUnitsCombo, &QgsLayoutUnitsComboBox::unitChanged, this, &QgsLayoutMapLabelingWidget::labelMarginUnitsChanged );
1748 connect( mLabelBoundarySpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutMapLabelingWidget::labelMarginChanged );
1749 connect( mShowPartialLabelsCheckBox, &QCheckBox::toggled, this, &QgsLayoutMapLabelingWidget::showPartialsToggled );
1750 connect( mShowUnplacedCheckBox, &QCheckBox::toggled, this, &QgsLayoutMapLabelingWidget::showUnplacedToggled );
1751
1753
1754 setNewItem( map );
1755}
1756
1758{
1759 if ( item->type() != QgsLayoutItemRegistry::LayoutMap )
1760 return false;
1761
1762 if ( mMapItem )
1763 {
1764 disconnect( mMapItem, &QgsLayoutObject::changed, this, &QgsLayoutMapLabelingWidget::updateGuiElements );
1765 }
1766
1767 mMapItem = qobject_cast< QgsLayoutItemMap * >( item );
1768
1769 if ( mMapItem )
1770 {
1771 connect( mMapItem, &QgsLayoutObject::changed, this, &QgsLayoutMapLabelingWidget::updateGuiElements );
1772 }
1773
1774 updateGuiElements();
1775
1776 return true;
1777}
1778
1779void QgsLayoutMapLabelingWidget::updateGuiElements()
1780{
1781 whileBlocking( mLabelBoundarySpinBox )->setValue( mMapItem->labelMargin().length() );
1782 whileBlocking( mLabelBoundaryUnitsCombo )->setUnit( mMapItem->labelMargin().units() );
1783 whileBlocking( mShowPartialLabelsCheckBox )->setChecked( mMapItem->mapFlags() & QgsLayoutItemMap::ShowPartialLabels );
1784 whileBlocking( mShowUnplacedCheckBox )->setChecked( mMapItem->mapFlags() & QgsLayoutItemMap::ShowUnplacedLabels );
1785
1786 if ( mBlockingItemsListView->model() )
1787 {
1788 QAbstractItemModel *oldModel = mBlockingItemsListView->model();
1789 mBlockingItemsListView->setModel( nullptr );
1790 oldModel->deleteLater();
1791 }
1792
1793 QgsLayoutMapItemBlocksLabelsModel *model = new QgsLayoutMapItemBlocksLabelsModel( mMapItem, mMapItem->layout()->itemsModel(), mBlockingItemsListView );
1794 mBlockingItemsListView->setModel( model );
1795
1796 updateDataDefinedButton( mLabelMarginDDBtn );
1797}
1798
1799void QgsLayoutMapLabelingWidget::labelMarginChanged( double val )
1800{
1801 if ( !mMapItem )
1802 return;
1803
1804 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Label Margin" ), QgsLayoutItem::UndoMapLabelMargin );
1805 mMapItem->setLabelMargin( QgsLayoutMeasurement( val, mLabelBoundaryUnitsCombo->unit() ) );
1806 mMapItem->layout()->undoStack()->endCommand();
1807 mMapItem->invalidateCache();
1808}
1809
1810void QgsLayoutMapLabelingWidget::labelMarginUnitsChanged()
1811{
1812 if ( !mMapItem )
1813 return;
1814
1815 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Label Margin" ), QgsLayoutItem::UndoMapLabelMargin );
1816 mMapItem->setLabelMargin( QgsLayoutMeasurement( mLabelBoundarySpinBox->value(), mLabelBoundaryUnitsCombo->unit() ) );
1817 mMapItem->layout()->undoStack()->endCommand();
1818 mMapItem->invalidateCache();
1819}
1820
1821void QgsLayoutMapLabelingWidget::showPartialsToggled( bool checked )
1822{
1823 if ( !mMapItem )
1824 return;
1825
1826 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Label Visibility" ) );
1827 QgsLayoutItemMap::MapItemFlags flags = mMapItem->mapFlags();
1828 if ( checked )
1830 else
1831 flags &= ~QgsLayoutItemMap::ShowPartialLabels;
1832 mMapItem->setMapFlags( flags );
1833 mMapItem->layout()->undoStack()->endCommand();
1834 mMapItem->invalidateCache();
1835}
1836
1837void QgsLayoutMapLabelingWidget::showUnplacedToggled( bool checked )
1838{
1839 if ( !mMapItem )
1840 return;
1841
1842 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Label Visibility" ) );
1843 QgsLayoutItemMap::MapItemFlags flags = mMapItem->mapFlags();
1844 if ( checked )
1846 else
1847 flags &= ~QgsLayoutItemMap::ShowUnplacedLabels;
1848 mMapItem->setMapFlags( flags );
1849 mMapItem->layout()->undoStack()->endCommand();
1850 mMapItem->invalidateCache();
1851}
1852
1854 : QSortFilterProxyModel( parent )
1855 , mLayoutModel( layoutModel )
1856 , mMapItem( map )
1857{
1858 setSourceModel( layoutModel );
1859}
1860
1862{
1863 return 1;
1864}
1865
1866QVariant QgsLayoutMapItemBlocksLabelsModel::data( const QModelIndex &i, int role ) const
1867{
1868 if ( !i.isValid() )
1869 return QVariant();
1870
1871 if ( i.column() != 0 )
1872 return QVariant();
1873
1874 const QModelIndex sourceIndex = mapToSource( index( i.row(), QgsLayoutModel::ItemId, i.parent() ) );
1875
1876 QgsLayoutItem *item = mLayoutModel->itemFromIndex( mapToSource( i ) );
1877 if ( !item )
1878 {
1879 return QVariant();
1880 }
1881
1882 switch ( role )
1883 {
1884 case Qt::CheckStateRole:
1885 switch ( i.column() )
1886 {
1887 case 0:
1888 return mMapItem ? ( mMapItem->isLabelBlockingItem( item ) ? Qt::Checked : Qt::Unchecked ) : Qt::Unchecked;
1889 default:
1890 return QVariant();
1891 }
1892
1893 default:
1894 return mLayoutModel->data( sourceIndex, role );
1895 }
1896}
1897
1898bool QgsLayoutMapItemBlocksLabelsModel::setData( const QModelIndex &index, const QVariant &value, int role )
1899{
1900 Q_UNUSED( role )
1901
1902 if ( !index.isValid() )
1903 return false;
1904
1905 QgsLayoutItem *item = mLayoutModel->itemFromIndex( mapToSource( index ) );
1906 if ( !item || !mMapItem )
1907 {
1908 return false;
1909 }
1910
1911 mMapItem->layout()->undoStack()->beginCommand( mMapItem, tr( "Change Label Blocking Items" ) );
1912
1913 if ( value.toBool() )
1914 {
1915 mMapItem->addLabelBlockingItem( item );
1916 }
1917 else
1918 {
1919 mMapItem->removeLabelBlockingItem( item );
1920 }
1921 emit dataChanged( index, index, QVector<int>() << role );
1922
1923 mMapItem->layout()->undoStack()->endCommand();
1924 mMapItem->invalidateCache();
1925
1926 return true;
1927}
1928
1929Qt::ItemFlags QgsLayoutMapItemBlocksLabelsModel::flags( const QModelIndex &index ) const
1930{
1931 Qt::ItemFlags flags = QAbstractItemModel::flags( index );
1932
1933 if ( ! index.isValid() )
1934 {
1935 return flags ;
1936 }
1937
1938 switch ( index.column() )
1939 {
1940 case 0:
1941 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
1942 default:
1943 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
1944 }
1945}
1946
1947bool QgsLayoutMapItemBlocksLabelsModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
1948{
1949 QgsLayoutItem *item = mLayoutModel->itemFromIndex( mLayoutModel->index( source_row, 0, source_parent ) );
1950 if ( !item || item == mMapItem )
1951 {
1952 return false;
1953 }
1954
1955 return true;
1956}
1957
1958
1959
1960//
1961// QgsLayoutMapClippingWidget
1962//
1963
1965 : QgsLayoutItemBaseWidget( nullptr, map )
1966 , mMapItem( map )
1967{
1968 setupUi( this );
1969 setPanelTitle( tr( "Clipping Settings" ) );
1970
1971 mLayerModel = new QgsMapLayerModel( this );
1972 mLayerModel->setItemsCheckable( true );
1973 mLayersTreeView->setModel( mLayerModel );
1974
1975 mAtlasClippingTypeComboBox->addItem( tr( "Clip During Render Only" ), static_cast< int >( QgsMapClippingRegion::FeatureClippingType::ClipPainterOnly ) );
1976 mAtlasClippingTypeComboBox->addItem( tr( "Clip Feature Before Render" ), static_cast< int >( QgsMapClippingRegion::FeatureClippingType::ClipToIntersection ) );
1977 mAtlasClippingTypeComboBox->addItem( tr( "Render Intersecting Features Unchanged" ), static_cast< int >( QgsMapClippingRegion::FeatureClippingType::NoClipping ) );
1978
1979 for ( int i = 0; i < mAtlasClippingTypeComboBox->count(); ++i )
1980 {
1981 mItemClippingTypeComboBox->addItem( mAtlasClippingTypeComboBox->itemText( i ), mAtlasClippingTypeComboBox->itemData( i ) );
1982 }
1983
1984 mClipItemComboBox->setCurrentLayout( map->layout() );
1985 mClipItemComboBox->setItemFlags( QgsLayoutItem::FlagProvidesClipPath );
1986
1987 connect( mRadioClipSelectedLayers, &QRadioButton::toggled, mLayersTreeView, &QWidget::setEnabled );
1988 mLayersTreeView->setEnabled( false );
1989 mRadioClipAllLayers->setChecked( true );
1990
1991 connect( mClipToAtlasCheckBox, &QGroupBox::toggled, this, [ = ]( bool active )
1992 {
1993 if ( !mBlockUpdates )
1994 {
1995 mMapItem->beginCommand( tr( "Toggle Atlas Clipping" ) );
1996 mMapItem->atlasClippingSettings()->setEnabled( active );
1997 mMapItem->endCommand();
1998 }
1999 } );
2000 connect( mForceLabelsInsideCheckBox, &QCheckBox::toggled, this, [ = ]( bool active )
2001 {
2002 if ( !mBlockUpdates )
2003 {
2004 mMapItem->beginCommand( tr( "Change Atlas Clipping Label Behavior" ) );
2005 mMapItem->atlasClippingSettings()->setForceLabelsInsideFeature( active );
2006 mMapItem->endCommand();
2007 }
2008 } );
2009 connect( mAtlasClippingTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]
2010 {
2011 if ( !mBlockUpdates )
2012 {
2013 mMapItem->beginCommand( tr( "Change Atlas Clipping Behavior" ) );
2014 mMapItem->atlasClippingSettings()->setFeatureClippingType( static_cast< QgsMapClippingRegion::FeatureClippingType >( mAtlasClippingTypeComboBox->currentData().toInt() ) );
2015 mMapItem->endCommand();
2016 }
2017 } );
2018
2019 connect( mRadioClipSelectedLayers, &QCheckBox::toggled, this, [ = ]( bool active )
2020 {
2021 if ( active && !mBlockUpdates )
2022 {
2023 mBlockUpdates = true;
2024 mMapItem->beginCommand( tr( "Change Atlas Clipping Layers" ) );
2025 mMapItem->atlasClippingSettings()->setRestrictToLayers( true );
2026 mMapItem->endCommand();
2027 mBlockUpdates = false;
2028 }
2029 } );
2030 connect( mRadioClipAllLayers, &QCheckBox::toggled, this, [ = ]( bool active )
2031 {
2032 if ( active && !mBlockUpdates )
2033 {
2034 mBlockUpdates = true;
2035 mMapItem->beginCommand( tr( "Change Atlas Clipping Layers" ) );
2036 mMapItem->atlasClippingSettings()->setRestrictToLayers( false );
2037 mMapItem->endCommand();
2038 mBlockUpdates = false;
2039 }
2040 } );
2041 connect( mLayerModel, &QgsMapLayerModel::dataChanged, this, [ = ]( const QModelIndex &, const QModelIndex &, const QVector<int> &roles = QVector<int>() )
2042 {
2043 if ( !roles.contains( Qt::CheckStateRole ) )
2044 return;
2045
2046 if ( !mBlockUpdates )
2047 {
2048 mBlockUpdates = true;
2049 mMapItem->beginCommand( tr( "Change Atlas Clipping Layers" ) );
2050 mMapItem->atlasClippingSettings()->setLayersToClip( mLayerModel->layersChecked() );
2051 mMapItem->endCommand();
2052 mBlockUpdates = false;
2053 }
2054 } );
2055
2056 // item clipping widgets
2057
2058 connect( mClipToItemCheckBox, &QGroupBox::toggled, this, [ = ]( bool active )
2059 {
2060 if ( !mBlockUpdates )
2061 {
2062 mMapItem->beginCommand( tr( "Toggle Map Clipping" ) );
2063 mMapItem->itemClippingSettings()->setEnabled( active );
2064 mMapItem->endCommand();
2065 }
2066 } );
2067 connect( mItemClippingTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]
2068 {
2069 if ( !mBlockUpdates )
2070 {
2071 mMapItem->beginCommand( tr( "Change Map Clipping Behavior" ) );
2072 mMapItem->itemClippingSettings()->setFeatureClippingType( static_cast< QgsMapClippingRegion::FeatureClippingType >( mItemClippingTypeComboBox->currentData().toInt() ) );
2073 mMapItem->endCommand();
2074 }
2075 } );
2076 connect( mForceLabelsInsideItemCheckBox, &QCheckBox::toggled, this, [ = ]( bool active )
2077 {
2078 if ( !mBlockUpdates )
2079 {
2080 mMapItem->beginCommand( tr( "Change Map Clipping Label Behavior" ) );
2081 mMapItem->itemClippingSettings()->setForceLabelsInsideClipPath( active );
2082 mMapItem->endCommand();
2083 }
2084 } );
2085 connect( mClipItemComboBox, &QgsLayoutItemComboBox::itemChanged, this, [ = ]( QgsLayoutItem * item )
2086 {
2087 if ( !mBlockUpdates )
2088 {
2089 mMapItem->beginCommand( tr( "Change Map Clipping Item" ) );
2090 mMapItem->itemClippingSettings()->setSourceItem( item );
2091 mMapItem->endCommand();
2092 }
2093 } );
2094
2095 setNewItem( map );
2096
2098 this, &QgsLayoutMapClippingWidget::atlasLayerChanged );
2099 if ( QgsLayoutAtlas *atlas = layoutAtlas() )
2100 {
2101 connect( atlas, &QgsLayoutAtlas::toggled, this, &QgsLayoutMapClippingWidget::atlasToggled );
2102 atlasToggled( atlas->enabled() );
2103 }
2104}
2105
2107{
2108 mClipToAtlasCheckBox->setTitle( tr( "Clip to %1 feature" ).arg( string ) );
2109 mClipToAtlasLabel->setText( tr( "<b>When enabled, map layers will be automatically clipped to the boundary of the current %1 feature.</b>" ).arg( string ) );
2110 mForceLabelsInsideCheckBox->setText( tr( "Force labels inside %1 feature" ).arg( string ) );
2111}
2112
2114{
2115 if ( item->type() != QgsLayoutItemRegistry::LayoutMap )
2116 return false;
2117
2118 if ( mMapItem )
2119 {
2120 disconnect( mMapItem, &QgsLayoutObject::changed, this, &QgsLayoutMapClippingWidget::updateGuiElements );
2121 }
2122
2123 mMapItem = qobject_cast< QgsLayoutItemMap * >( item );
2124
2125 if ( mMapItem )
2126 {
2127 connect( mMapItem, &QgsLayoutObject::changed, this, &QgsLayoutMapClippingWidget::updateGuiElements );
2128 }
2129
2130 updateGuiElements();
2131
2132 return true;
2133}
2134
2135void QgsLayoutMapClippingWidget::updateGuiElements()
2136{
2137 if ( mBlockUpdates )
2138 return;
2139
2140 mBlockUpdates = true;
2141 mClipToAtlasCheckBox->setChecked( mMapItem->atlasClippingSettings()->enabled() );
2142 mAtlasClippingTypeComboBox->setCurrentIndex( mAtlasClippingTypeComboBox->findData( static_cast< int >( mMapItem->atlasClippingSettings()->featureClippingType() ) ) );
2143 mForceLabelsInsideCheckBox->setChecked( mMapItem->atlasClippingSettings()->forceLabelsInsideFeature() );
2144
2145 mRadioClipAllLayers->setChecked( !mMapItem->atlasClippingSettings()->restrictToLayers() );
2146 mRadioClipSelectedLayers->setChecked( mMapItem->atlasClippingSettings()->restrictToLayers() );
2147 mLayerModel->setLayersChecked( mMapItem->atlasClippingSettings()->layersToClip() );
2148
2149 mClipToItemCheckBox->setChecked( mMapItem->itemClippingSettings()->enabled() );
2150 mItemClippingTypeComboBox->setCurrentIndex( mItemClippingTypeComboBox->findData( static_cast< int >( mMapItem->itemClippingSettings()->featureClippingType() ) ) );
2151 mForceLabelsInsideItemCheckBox->setChecked( mMapItem->itemClippingSettings()->forceLabelsInsideClipPath() );
2152 mClipItemComboBox->setItem( mMapItem->itemClippingSettings()->sourceItem() );
2153
2154 mBlockUpdates = false;
2155}
2156
2157void QgsLayoutMapClippingWidget::atlasLayerChanged( QgsVectorLayer *layer )
2158{
2159 if ( !layer || layer->geometryType() != Qgis::GeometryType::Polygon )
2160 {
2161 //non-polygon layer, disable atlas control
2162 mClipToAtlasCheckBox->setChecked( false );
2163 mClipToAtlasCheckBox->setEnabled( false );
2164 return;
2165 }
2166 else
2167 {
2168 mClipToAtlasCheckBox->setEnabled( true );
2169 }
2170}
2171
2172void QgsLayoutMapClippingWidget::atlasToggled( bool atlasEnabled )
2173{
2174 if ( atlasEnabled &&
2175 mMapItem && mMapItem->layout() && mMapItem->layout()->reportContext().layer()
2176 && mMapItem->layout()->reportContext().layer()->geometryType() == Qgis::GeometryType::Polygon )
2177 {
2178 mClipToAtlasCheckBox->setEnabled( true );
2179 }
2180 else
2181 {
2182 mClipToAtlasCheckBox->setEnabled( false );
2183 mClipToAtlasCheckBox->setChecked( false );
2184 }
2185}
@ 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.
@ 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 unitChanged(Qgis::LayoutUnit unit)
Emitted when the unit is changed.
QgsLayoutReportContext & reportContext()
Returns a reference to the layout's report context, which stores information relating to the current ...
Definition: qgslayout.cpp:375
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:113
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:110
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.
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:63
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) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:865
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:3509
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:3435
const QgsCoordinateReferenceSystem & crs