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