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