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