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