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 )
206 if ( !mHasFixedOutputCrs )
213 if ( mOutputCrs == srcCrs )
222 ct.setBallparkTransformsAreAppropriate(
true );
223 extent = ct.transformBoundingBox( r );
225 catch ( QgsCsException & )
234 switch ( mOutputCrs.mapUnits() )
291 mXMinLineEdit->setText( QLocale().toString( extent.
xMinimum(),
'f', decimals ) );
292 mXMaxLineEdit->setText( QLocale().toString( extent.
xMaximum(),
'f', decimals ) );
293 mYMinLineEdit->setText( QLocale().toString( extent.
yMinimum(),
'f', decimals ) );
294 mYMaxLineEdit->setText( QLocale().toString( extent.
yMaximum(),
'f', decimals ) );
296 QString condensed = u
"%1,%2,%3,%4"_s.arg( QString::number( extent.
xMinimum(),
'f', decimals ), QString::number( extent.
xMaximum(),
'f', decimals ), QString::number( extent.
yMinimum(),
'f', decimals ), QString::number( extent.
yMaximum(),
'f', decimals ) );
298 mCondensedLineEdit->setText( condensed );
300 mExtentState = state;
308void QgsExtentWidget::setOutputExtentFromLineEdit()
314void QgsExtentWidget::setOutputExtentFromCondensedLineEdit()
316 const QString text = mCondensedLineEdit->text();
317 if ( text.isEmpty() )
323 const QRegularExpressionMatch match = mCondensedRe.match( text );
324 if ( match.hasMatch() )
327 whileBlocking( mXMinLineEdit )->setText( QLocale().toString( match.captured( 1 ).toDouble(),
'f', 10 ) );
328 whileBlocking( mXMaxLineEdit )->setText( QLocale().toString( match.captured( 2 ).toDouble(),
'f', 10 ) );
329 whileBlocking( mYMinLineEdit )->setText( QLocale().toString( match.captured( 3 ).toDouble(),
'f', 10 ) );
330 whileBlocking( mYMaxLineEdit )->setText( QLocale().toString( match.captured( 4 ).toDouble(),
'f', 10 ) );
331 if ( !match.captured( 5 ).isEmpty() )
333 mOutputCrs = QgsCoordinateReferenceSystem( match.captured( 5 ) );
345 const bool prevWasNull = mIsValid;
360 return mExtentLayerName;
370 mCondensedLineEdit->setShowClearButton( allowed );
371 mCondensedLineEdit->setNullValue( notSetText );
374void QgsExtentWidget::setValid(
bool valid )
376 if ( valid == mIsValid )
383void QgsExtentWidget::layerMenuAboutToShow()
385 qDeleteAll( mLayerMenuActions );
386 mLayerMenuActions.clear();
388 for (
int i = 0; i < mMapLayerModel->rowCount(); ++i )
390 const QModelIndex index = mMapLayerModel->index( i, 0 );
391 const QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->data( index, Qt::DecorationRole ) );
392 const QString text = mMapLayerModel->data( index, Qt::DisplayRole ).toString();
393 QAction *act =
new QAction( icon, text, mLayerMenu );
394 act->setToolTip( mMapLayerModel->data( index, Qt::ToolTipRole ).toString() );
396 if ( mExtentState ==
ProjectLayerExtent && mExtentLayer && mExtentLayer->id() == layerId )
398 act->setCheckable(
true );
399 act->setChecked(
true );
401 connect( act, &QAction::triggered,
this, [
this, layerId] {
402 setExtentToLayerExtent( layerId );
404 mLayerMenu->addAction( act );
405 mLayerMenuActions << act;
409void QgsExtentWidget::layoutMenuAboutToShow()
411 mLayoutMenu->clear();
415 const QList<QgsPrintLayout *> layouts = manager->printLayouts();
416 for (
const QgsPrintLayout *layout : layouts )
418 QList<QgsLayoutItemMap *> maps;
419 layout->layoutItems( maps );
423 QMenu *layoutMenu =
new QMenu( layout->name(), mMenu );
424 for (
const QgsLayoutItemMap *map : std::as_const( maps ) )
426 QgsRectangle extent = map->extent();
427 QgsCoordinateReferenceSystem crs = map->crs();
428 QAction *mapExtentAction =
new QAction( tr(
"%1" ).arg( map->displayName() ), mLayoutMenu );
429 connect( mapExtentAction, &QAction::triggered,
this, [
this, extent, crs] {
setOutputExtentFromUser( extent, crs ); } );
430 layoutMenu->addAction( mapExtentAction );
432 mLayoutMenu->addMenu( layoutMenu );
437void QgsExtentWidget::bookmarkMenuAboutToShow()
439 mBookmarkMenu->clear();
441 if ( !mBookmarkModel )
444 QMap<QString, QMenu *> groupMenus;
445 for (
int i = 0; i < mBookmarkModel->rowCount(); ++i )
448 QMenu *destMenu = mBookmarkMenu;
449 if ( !group.isEmpty() )
451 destMenu = groupMenus.value( group );
454 destMenu =
new QMenu( group, mBookmarkMenu );
455 groupMenus[group] = destMenu;
461 destMenu->addAction( action );
464 QStringList groupKeys = groupMenus.keys();
465 groupKeys.sort( Qt::CaseInsensitive );
466 for (
int i = 0; i < groupKeys.count(); ++i )
468 if ( mBookmarkMenu->actions().value( i ) )
469 mBookmarkMenu->insertMenu( mBookmarkMenu->actions().at( i ), groupMenus.value( groupKeys.at( i ) ) );
471 mBookmarkMenu->addMenu( groupMenus.value( groupKeys.at( i ) ) );
475void QgsExtentWidget::setExtentToLayerExtent(
const QString &layerId )
485QgsMapLayer *QgsExtentWidget::mapLayerFromMimeData(
const QMimeData *data )
const
488 for (
const QgsMimeDataUtils::Uri &u : uriList )
491 if ( QgsMapLayer *layer = u.mapLayer() )
510 setOutputExtent( mCurrentExtent, mCurrentCrs,
CurrentExtent );
530 mExtentLayer = layer;
531 mExtentLayerName = layer->
name();
540 mMapToolPrevious = mCanvas->mapTool();
541 if ( !mMapToolExtent )
543 mMapToolExtent = std::make_unique<QgsMapToolExtent>( mCanvas );
547 mMapToolExtent->setRatio( mRatio );
548 mCanvas->setMapTool( mMapToolExtent.get() );
554void QgsExtentWidget::extentDrawn(
const QgsRectangle &extent )
559 mMapToolPrevious =
nullptr;
562void QgsExtentWidget::mapToolDeactivated()
565 mMapToolPrevious =
nullptr;
592 mButtonDrawOnCanvas->setVisible( drawOnCanvasOption );
593 mCurrentExtentButton->setVisible(
true );
595 mUseCanvasExtentAction->setVisible(
true );
596 mDrawOnCanvasAction->setVisible( drawOnCanvasOption && !mBlockDrawOnCanvas );
598 mCondensedToolButton->setToolTip( tr(
"Set to current map canvas extent" ) );
601 mCondensedToolButton->setPopupMode( QToolButton::MenuButtonPopup );
605 mButtonDrawOnCanvas->setVisible(
false );
606 mCurrentExtentButton->setVisible(
false );
607 mUseCanvasExtentAction->setVisible(
false );
608 mUseCanvasExtentAction->setVisible(
false );
610 mCondensedToolButton->setToolTip( QString() );
611 mCondensedToolButton->setIcon( QIcon() );
613 mCondensedToolButton->setPopupMode( QToolButton::InstantPopup );
619 if ( !( event->possibleActions() & Qt::CopyAction ) )
625 if ( mapLayerFromMimeData( event->mimeData() ) )
628 event->setDropAction( Qt::CopyAction );
630 mCondensedLineEdit->setHighlighted(
true );
641 if ( mCondensedLineEdit->isHighlighted() )
644 mCondensedLineEdit->setHighlighted(
false );
655 if ( !( event->possibleActions() & Qt::CopyAction ) )
661 if (
QgsMapLayer *layer = mapLayerFromMimeData( event->mimeData() ) )
664 setFocus( Qt::MouseFocusReason );
665 event->setDropAction( Qt::CopyAction );
674 mCondensedLineEdit->setHighlighted(
false );
683 if ( QWidget *parentWindow = window() )
685 if ( parentWindow->isModal() )
687 mBlockDrawOnCanvas =
true;
688 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.