36#include <QRegularExpression>
39#include "moc_qgsextentwidget.cpp"
41using namespace Qt::StringLiterals;
47 connect( mXMinLineEdit, &QLineEdit::textEdited,
this, &QgsExtentWidget::setOutputExtentFromLineEdit );
48 connect( mXMaxLineEdit, &QLineEdit::textEdited,
this, &QgsExtentWidget::setOutputExtentFromLineEdit );
49 connect( mYMinLineEdit, &QLineEdit::textEdited,
this, &QgsExtentWidget::setOutputExtentFromLineEdit );
50 connect( mYMaxLineEdit, &QLineEdit::textEdited,
this, &QgsExtentWidget::setOutputExtentFromLineEdit );
52 mCondensedRe = QRegularExpression( u
"\\s*([\\d\\.\\-]+)\\s*,\\s*([\\d\\.\\-]+)\\s*,\\s*([\\d\\.\\-]+)\\s*,\\s*([\\d\\.\\-]+)\\s*(?:\\[(.*?)\\])?"_s );
53 mCondensedLineEdit->setValidator(
new QRegularExpressionValidator( mCondensedRe,
this ) );
54 mCondensedLineEdit->setShowClearButton(
false );
56 connect( mCondensedLineEdit, &QLineEdit::textEdited,
this, &QgsExtentWidget::setOutputExtentFromCondensedLineEdit );
58 mLayerMenu =
new QMenu( tr(
"Calculate from Layer" ),
this );
59 mButtonCalcFromLayer->setMenu( mLayerMenu );
60 connect( mLayerMenu, &QMenu::aboutToShow,
this, &QgsExtentWidget::layerMenuAboutToShow );
64 mLayoutMenu =
new QMenu( tr(
"Calculate from Layout Map" ),
this );
65 mButtonCalcFromLayout->setMenu( mLayoutMenu );
66 connect( mLayoutMenu, &QMenu::aboutToShow,
this, &QgsExtentWidget::layoutMenuAboutToShow );
68 mBookmarkMenu =
new QMenu( tr(
"Calculate from Bookmark" ),
this );
69 mButtonCalcFromBookmark->setMenu( mBookmarkMenu );
70 connect( mBookmarkMenu, &QMenu::aboutToShow,
this, &QgsExtentWidget::bookmarkMenuAboutToShow );
72 mMenu =
new QMenu(
this );
73 mUseCanvasExtentAction =
new QAction( tr(
"Use Current Map Canvas Extent" ),
this );
75 mUseCanvasExtentAction->setVisible(
false );
78 mUseCurrentExtentAction =
new QAction( tr(
"Use Current Layer/Default Extent" ),
this );
79 mUseCurrentExtentAction->setVisible(
false );
82 mDrawOnCanvasAction =
new QAction( tr(
"Draw on Map Canvas" ),
this );
83 mDrawOnCanvasAction->setVisible(
false );
86 mMenu->addMenu( mLayerMenu );
87 mMenu->addMenu( mLayoutMenu );
88 mMenu->addMenu( mBookmarkMenu );
89 mMenu->addSeparator();
90 mMenu->addAction( mUseCanvasExtentAction );
91 mMenu->addAction( mDrawOnCanvasAction );
92 mMenu->addAction( mUseCurrentExtentAction );
94 mCondensedToolButton->setMenu( mMenu );
95 mCondensedToolButton->setPopupMode( QToolButton::InstantPopup );
102 mOriginalExtentButton->setVisible(
false );
103 mButtonDrawOnCanvas->setVisible(
false );
104 mCurrentExtentButton->setVisible(
false );
113 mExpandedWidget->hide();
117 mCondensedFrame->hide();
121 setAcceptDrops(
true );
126 if ( mMapToolExtent )
140 mOriginalExtentButton->setVisible(
true );
149 mCurrentExtentButton->setVisible(
true );
150 mUseCurrentExtentAction->setVisible(
true );
155 mHasFixedOutputCrs =
true;
158 const bool prevExtentEnabled = mIsValid;
159 switch ( mExtentState )
198 if ( !prevExtentEnabled )
205 if ( !mHasFixedOutputCrs )
212 if ( mOutputCrs == srcCrs )
221 ct.setBallparkTransformsAreAppropriate(
true );
222 mOutputExtent = ct.transformBoundingBox( r );
224 catch ( QgsCsException & )
233 switch ( mOutputCrs.mapUnits() )
290 mXMinLineEdit->setText( QLocale().toString( mOutputExtent.xMinimum(),
'f', decimals ) );
291 mXMaxLineEdit->setText( QLocale().toString( mOutputExtent.xMaximum(),
'f', decimals ) );
292 mYMinLineEdit->setText( QLocale().toString( mOutputExtent.yMinimum(),
'f', decimals ) );
293 mYMaxLineEdit->setText( QLocale().toString( mOutputExtent.yMaximum(),
'f', decimals ) );
295 QString condensed = u
"%1,%2,%3,%4"_s.arg(
296 QString::number( mOutputExtent.xMinimum(),
'f', decimals ),
297 QString::number( mOutputExtent.xMaximum(),
'f', decimals ),
298 QString::number( mOutputExtent.yMinimum(),
'f', decimals ),
299 QString::number( mOutputExtent.yMaximum(),
'f', decimals )
302 mCondensedLineEdit->setText( condensed );
304 mExtentState = state;
312void QgsExtentWidget::setOutputExtentFromLineEdit()
314 bool ok1, ok2, ok3, ok4;
319 if ( ok1 && ok2 && ok3 && ok4 )
321 mOutputExtent = QgsRectangle( xmin, ymin, xmax, ymax );
325 mOutputExtent.setNull();
332void QgsExtentWidget::setOutputExtentFromCondensedLineEdit()
334 const QString text = mCondensedLineEdit->text();
335 if ( text.isEmpty() )
341 const QRegularExpressionMatch match = mCondensedRe.match( text );
342 if ( match.hasMatch() )
344 const double xMin = match.captured( 1 ).toDouble();
345 const double xMax = match.captured( 2 ).toDouble();
346 const double yMin = match.captured( 3 ).toDouble();
347 const double yMax = match.captured( 4 ).toDouble();
348 mOutputExtent = QgsRectangle( xMin, yMin, xMax, yMax );
350 whileBlocking( mXMinLineEdit )->setText( QLocale().toString( xMin,
'f', 10 ) );
351 whileBlocking( mXMaxLineEdit )->setText( QLocale().toString( xMax,
'f', 10 ) );
352 whileBlocking( mYMinLineEdit )->setText( QLocale().toString( yMin,
'f', 10 ) );
353 whileBlocking( mYMaxLineEdit )->setText( QLocale().toString( yMax,
'f', 10 ) );
354 if ( !match.captured( 5 ).isEmpty() )
356 mOutputCrs = QgsCoordinateReferenceSystem( match.captured( 5 ) );
368 const bool prevWasNull = mIsValid;
369 mOutputExtent.setNull();
384 return mExtentLayerName;
394 mCondensedLineEdit->setShowClearButton( allowed );
395 mCondensedLineEdit->setNullValue( notSetText );
398void QgsExtentWidget::setValid(
bool valid )
400 if ( valid == mIsValid )
407void QgsExtentWidget::layerMenuAboutToShow()
409 qDeleteAll( mLayerMenuActions );
410 mLayerMenuActions.clear();
412 for (
int i = 0; i < mMapLayerModel->rowCount(); ++i )
414 const QModelIndex index = mMapLayerModel->index( i, 0 );
415 const QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->data( index, Qt::DecorationRole ) );
416 const QString text = mMapLayerModel->data( index, Qt::DisplayRole ).toString();
417 QAction *act =
new QAction( icon, text, mLayerMenu );
418 act->setToolTip( mMapLayerModel->data( index, Qt::ToolTipRole ).toString() );
420 if ( mExtentState ==
ProjectLayerExtent && mExtentLayer && mExtentLayer->id() == layerId )
422 act->setCheckable(
true );
423 act->setChecked(
true );
425 connect( act, &QAction::triggered,
this, [
this, layerId] { setExtentToLayerExtent( layerId ); } );
426 mLayerMenu->addAction( act );
427 mLayerMenuActions << act;
431void QgsExtentWidget::layoutMenuAboutToShow()
433 mLayoutMenu->clear();
437 const QList<QgsPrintLayout *> layouts = manager->printLayouts();
438 for (
const QgsPrintLayout *layout : layouts )
440 QList<QgsLayoutItemMap *> maps;
441 layout->layoutItems( maps );
445 QMenu *layoutMenu =
new QMenu( layout->name(), mMenu );
446 for (
const QgsLayoutItemMap *map : std::as_const( maps ) )
448 QgsRectangle extent = map->extent();
449 QgsCoordinateReferenceSystem crs = map->crs();
450 QAction *mapExtentAction =
new QAction( tr(
"%1" ).arg( map->displayName() ), mLayoutMenu );
451 connect( mapExtentAction, &QAction::triggered,
this, [
this, extent, crs] {
setOutputExtentFromUser( extent, crs ); } );
452 layoutMenu->addAction( mapExtentAction );
454 mLayoutMenu->addMenu( layoutMenu );
459void QgsExtentWidget::bookmarkMenuAboutToShow()
461 mBookmarkMenu->clear();
463 if ( !mBookmarkModel )
466 QMap<QString, QMenu *> groupMenus;
467 for (
int i = 0; i < mBookmarkModel->rowCount(); ++i )
470 QMenu *destMenu = mBookmarkMenu;
471 if ( !group.isEmpty() )
473 destMenu = groupMenus.value( group );
476 destMenu =
new QMenu( group, mBookmarkMenu );
477 groupMenus[group] = destMenu;
483 destMenu->addAction( action );
486 QStringList groupKeys = groupMenus.keys();
487 groupKeys.sort( Qt::CaseInsensitive );
488 for (
int i = 0; i < groupKeys.count(); ++i )
490 if ( mBookmarkMenu->actions().value( i ) )
491 mBookmarkMenu->insertMenu( mBookmarkMenu->actions().at( i ), groupMenus.value( groupKeys.at( i ) ) );
493 mBookmarkMenu->addMenu( groupMenus.value( groupKeys.at( i ) ) );
497void QgsExtentWidget::setExtentToLayerExtent(
const QString &layerId )
507QgsMapLayer *QgsExtentWidget::mapLayerFromMimeData(
const QMimeData *data )
const
510 for (
const QgsMimeDataUtils::Uri &u : uriList )
513 if ( QgsMapLayer *layer = u.mapLayer() )
532 setOutputExtent( mCurrentExtent, mCurrentCrs,
CurrentExtent );
552 mExtentLayer = layer;
553 mExtentLayerName = layer->
name();
562 mMapToolPrevious = mCanvas->mapTool();
563 if ( !mMapToolExtent )
565 mMapToolExtent = std::make_unique<QgsMapToolExtent>( mCanvas );
569 mMapToolExtent->setRatio( mRatio );
570 mCanvas->setMapTool( mMapToolExtent.get() );
576void QgsExtentWidget::extentDrawn(
const QgsRectangle &extent )
581 mMapToolPrevious =
nullptr;
584void QgsExtentWidget::mapToolDeactivated()
587 mMapToolPrevious =
nullptr;
592 return mOutputExtent;
600 mButtonDrawOnCanvas->setVisible( drawOnCanvasOption );
601 mCurrentExtentButton->setVisible(
true );
603 mUseCanvasExtentAction->setVisible(
true );
604 mDrawOnCanvasAction->setVisible( drawOnCanvasOption && !mBlockDrawOnCanvas );
606 mCondensedToolButton->setToolTip( tr(
"Set to current map canvas extent" ) );
609 mCondensedToolButton->setPopupMode( QToolButton::MenuButtonPopup );
613 mButtonDrawOnCanvas->setVisible(
false );
614 mCurrentExtentButton->setVisible(
false );
615 mUseCanvasExtentAction->setVisible(
false );
616 mUseCanvasExtentAction->setVisible(
false );
618 mCondensedToolButton->setToolTip( QString() );
619 mCondensedToolButton->setIcon( QIcon() );
621 mCondensedToolButton->setPopupMode( QToolButton::InstantPopup );
627 if ( !( event->possibleActions() & Qt::CopyAction ) )
633 if ( mapLayerFromMimeData( event->mimeData() ) )
636 event->setDropAction( Qt::CopyAction );
638 mCondensedLineEdit->setHighlighted(
true );
649 if ( mCondensedLineEdit->isHighlighted() )
652 mCondensedLineEdit->setHighlighted(
false );
663 if ( !( event->possibleActions() & Qt::CopyAction ) )
669 if (
QgsMapLayer *layer = mapLayerFromMimeData( event->mimeData() ) )
672 setFocus( Qt::MouseFocusReason );
673 event->setDropAction( Qt::CopyAction );
682 mCondensedLineEdit->setHighlighted(
false );
691 if ( QWidget *parentWindow = window() )
693 if ( parentWindow->isModal() )
695 mBlockDrawOnCanvas =
true;
696 mDrawOnCanvasAction->setVisible(
false );
@ ShortString
A heavily abbreviated string, for use when a compact representation is required.
@ YardsBritishSears1922Truncated
British yards (Sears 1922 truncated).
@ MilesUSSurvey
US Survey miles.
@ LinksBritishSears1922
British links (Sears 1922).
@ YardsBritishBenoit1895A
British yards (Benoit 1895 A).
@ LinksBritishBenoit1895A
British links (Benoit 1895 A).
@ Centimeters
Centimeters.
@ YardsIndian1975
Indian yards (1975).
@ FeetUSSurvey
US Survey feet.
@ Millimeters
Millimeters.
@ FeetBritishSears1922
British feet (Sears 1922).
@ YardsClarkes
Clarke's yards.
@ YardsIndian
Indian yards.
@ FeetBritishBenoit1895B
British feet (Benoit 1895 B).
@ Miles
Terrestrial miles.
@ LinksUSSurvey
US Survey links.
@ ChainsUSSurvey
US Survey chains.
@ FeetClarkes
Clarke's feet.
@ Unknown
Unknown distance unit.
@ FeetBritish1936
British feet (1936).
@ FeetIndian1962
Indian feet (1962).
@ YardsBritishSears1922
British yards (Sears 1922).
@ FeetIndian1937
Indian feet (1937).
@ YardsIndian1937
Indian yards (1937).
@ Degrees
Degrees, for planar geographic CRS distance measurements.
@ ChainsBritishBenoit1895B
British chains (Benoit 1895 B).
@ LinksBritishSears1922Truncated
British links (Sears 1922 truncated).
@ ChainsBritishBenoit1895A
British chains (Benoit 1895 A).
@ YardsBritishBenoit1895B
British yards (Benoit 1895 B).
@ FeetBritish1865
British feet (1865).
@ YardsIndian1962
Indian yards (1962).
@ FeetBritishSears1922Truncated
British feet (Sears 1922 truncated).
@ MetersGermanLegal
German legal meter.
@ LinksBritishBenoit1895B
British links (Benoit 1895 B).
@ ChainsInternational
International chains.
@ LinksInternational
International links.
@ ChainsBritishSears1922Truncated
British chains (Sears 1922 truncated).
@ FeetIndian
Indian (geodetic) feet.
@ NauticalMiles
Nautical miles.
@ ChainsClarkes
Clarke's chains.
@ LinksClarkes
Clarke's links.
@ ChainsBritishSears1922
British chains (Sears 1922).
@ FeetIndian1975
Indian feet (1975).
@ FeetGoldCoast
Gold Coast feet.
@ FeetBritishBenoit1895A
British feet (Benoit 1895 A).
@ SpatialLayer
All spatial layers.
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.
@ Extent
Bookmark extent as a QgsReferencedRectangle.
Represents a coordinate reference system (CRS).
Custom exception class for Coordinate Reference System related exceptions.
A custom validator which allows entry of doubles in a locale-tolerant way.
static double toDouble(const QString &input, bool *ok)
Converts input string to double value.
void cleared()
Emitted when the widget is cleared.
Map canvas is a class for displaying all GIS data types on a canvas.
void setMapTool(QgsMapTool *mapTool, bool clean=false)
Sets the map tool currently being used on the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
@ LayerId
Stores the map layer ID.
A proxy model which provides an easy to use model to display the list of layers in widgets.
Base class for all map layer types.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Contains configuration for rendering maps.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
void setRotation(double rotation)
Sets the rotation of the resulting map image, in degrees clockwise.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
QList< QgsMimeDataUtils::Uri > UriList
static UriList decodeUriList(const QMimeData *data)
static QgsProject * instance()
Returns the QgsProject singleton instance.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
A rectangle specified with double values.
QgsCoordinateReferenceSystem crs() const
Returns the associated coordinate reference system, or an invalid CRS if no reference system is set.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.