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