1 /*************************************************************************** 2 qgsextentwidget.h 3 --------------------- 4 begin : March 2020 5 copyright : (C) 2020 by Nyall Dawson 6 email : nyall dot dawson at gmail dot com 7 *************************************************************************** 8 * * 9 * This program is free software; you can redistribute it and/or modify * 10 * it under the terms of the GNU General Public License as published by * 11 * the Free Software Foundation; either version 2 of the License, or * 12 * (at your option) any later version. * 13 * * 14 ***************************************************************************/ 15 16 #ifndef QGSEXTENTWIDGET_H 17 #define QGSEXTENTWIDGET_H 18 19 #include "qgscollapsiblegroupbox.h" 20 #include "qgsmaptool.h" 21 #include "qgsmaptoolextent.h" 22 #include "qgis_sip.h" 23 24 #include "ui_qgsextentgroupboxwidget.h" 25 26 #include "qgscoordinatereferencesystem.h" 27 #include "qgsrectangle.h" 28 #include "qgis_gui.h" 29 30 #include <memory> 31 #include <QRegularExpression> 32 33 class QgsCoordinateReferenceSystem; 34 class QgsMapLayerModel; 35 class QgsMapLayer; 36 37 /** 38 * \ingroup gui 39 * \brief A widget for configuration of a map extent. 40 * 41 * Besides allowing the user to enter the extent manually, it comes with options to use 42 * original extent or extent defined by the current view in map canvas. 43 * 44 * When using the widget, make sure to call setOriginalExtent(), setCurrentExtent() and setOutputCrs() during initialization. 45 * 46 * \see QgsExtentGroupBox 47 * 48 * \since QGIS 3.14 49 */ 50 class GUI_EXPORT QgsExtentWidget : public QWidget, private Ui::QgsExtentGroupBoxWidget 51 { 52 Q_OBJECT 53 54 public: 55 56 //! Available states for the current extent selection in the widget 57 enum ExtentState 58 { 59 OriginalExtent, //!< Layer's extent 60 CurrentExtent, //!< Map canvas extent 61 UserExtent, //!< Extent manually entered/modified by the user 62 ProjectLayerExtent, //!< Extent taken from a layer within the project 63 DrawOnCanvas, //!< Extent taken from a rectangled drawn onto the map canvas 64 }; 65 66 //! Widget styles 67 enum WidgetStyle 68 { 69 CondensedStyle, //!< Shows a compressed widget, for use when available space is minimal 70 ExpandedStyle, //!< Shows an expanded widget, for use when space is not constrained 71 }; 72 73 /** 74 * Constructor for QgsExtentWidget. 75 */ 76 explicit QgsExtentWidget( QWidget *parent SIP_TRANSFERTHIS = nullptr, WidgetStyle style = CondensedStyle ); 77 78 ~QgsExtentWidget() override; 79 80 /** 81 * Sets the original extent and coordinate reference system for the widget. This should be called as part of initialization. 82 * \see originalExtent() 83 * \see originalCrs() 84 */ 85 void setOriginalExtent( const QgsRectangle &originalExtent, const QgsCoordinateReferenceSystem &originalCrs ); 86 87 /** 88 * Returns the original extent set for the widget. 89 * \see setOriginalExtent() 90 * \see originalCrs() 91 */ originalExtent()92 QgsRectangle originalExtent() const { return mOriginalExtent; } 93 94 /** 95 * Returns the original coordinate reference system set for the widget. 96 * \see originalExtent() 97 * \see setOriginalExtent() 98 */ originalCrs()99 QgsCoordinateReferenceSystem originalCrs() const { return mOriginalCrs; } 100 101 /** 102 * Sets the current extent to show in the widget - should be called as part of initialization (or whenever current extent changes). 103 * The current extent is usually set to match the current map canvas extent. 104 * \see currentExtent() 105 * \see currentCrs() 106 */ 107 void setCurrentExtent( const QgsRectangle ¤tExtent, const QgsCoordinateReferenceSystem ¤tCrs ); 108 109 /** 110 * Returns the current extent set for the widget. The current extent is usually set to match the 111 * current map canvas extent. 112 * \see setCurrentExtent() 113 * \see currentCrs() 114 */ currentExtent()115 QgsRectangle currentExtent() const { return mCurrentExtent; } 116 117 /** 118 * Returns the coordinate reference system for the current extent set for the widget. The current 119 * extent and CRS usually reflects the map canvas extent and CRS. 120 * \see setCurrentExtent() 121 * \see currentExtent() 122 */ currentCrs()123 QgsCoordinateReferenceSystem currentCrs() const { return mCurrentCrs; } 124 125 /** 126 * Sets the output CRS - may need to be used for transformation from original/current extent. 127 * Should be called as part of initialization and whenever the the output CRS is changed. 128 * The current extent will be reprojected into the new output CRS. 129 */ 130 void setOutputCrs( const QgsCoordinateReferenceSystem &outputCrs ); 131 132 /** 133 * Returns the extent shown in the widget - in output CRS coordinates. 134 * \see outputCrs 135 */ 136 QgsRectangle outputExtent() const; 137 138 /** 139 * Returns the current output CRS, used in the display. 140 * \see outputExtent 141 */ outputCrs()142 QgsCoordinateReferenceSystem outputCrs() const { return mOutputCrs; } 143 144 /** 145 * Returns the currently selected state for the widget's extent. 146 */ extentState()147 QgsExtentWidget::ExtentState extentState() const { return mExtentState; } 148 149 /** 150 * Sets the map canvas to enable dragging of extent on a canvas. 151 * \param canvas the map canvas 152 */ 153 void setMapCanvas( QgsMapCanvas *canvas ); 154 155 /** 156 * Returns the current fixed aspect ratio to be used when dragging extent onto the canvas. 157 * If the aspect ratio isn't fixed, the width and height will be set to zero. 158 */ ratio()159 QSize ratio() const { return mRatio; } 160 161 /** 162 * Returns the name of the extent layer. 163 */ 164 QString extentLayerName() const; 165 166 /** 167 * Returns TRUE if the widget is in a valid state, i.e. has an extent set. 168 */ 169 bool isValid() const; 170 171 /** 172 * Sets whether the widget can be set to a "not set" (null) state. 173 * 174 * The specified \a notSetText will be used for showing null values. 175 * 176 * \note This mode only applies to widgets in the condensed state! 177 */ 178 void setNullValueAllowed( bool allowed, const QString ¬SetText = QString() ); 179 180 public slots: 181 182 /** 183 * Sets the output extent to be the same as original extent (may be transformed to output CRS). 184 */ 185 void setOutputExtentFromOriginal(); 186 187 /** 188 * Sets the output extent to be the same as current extent (may be transformed to output CRS). 189 */ 190 void setOutputExtentFromCurrent(); 191 192 /** 193 * Sets the output extent to a custom extent (may be transformed to output CRS). 194 */ 195 void setOutputExtentFromUser( const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs ); 196 197 /** 198 * Sets the output extent to match a \a layer's extent (may be transformed to output CRS). 199 */ 200 void setOutputExtentFromLayer( const QgsMapLayer *layer ); 201 202 /** 203 * Sets the output extent by dragging on the canvas. 204 */ 205 void setOutputExtentFromDrawOnCanvas(); 206 207 /** 208 * Sets a fixed aspect ratio to be used when dragging extent onto the canvas. 209 * To unset a fixed aspect ratio, set the width and height to zero. 210 * \param ratio aspect ratio's width and height 211 */ setRatio(QSize ratio)212 void setRatio( QSize ratio ) { mRatio = ratio; } 213 214 /** 215 * Clears the widget, setting it to a null value. 216 */ 217 void clear(); 218 219 signals: 220 221 /** 222 * Emitted when the widget's extent is changed. 223 */ 224 void extentChanged( const QgsRectangle &r ); 225 226 /** 227 * Emitted when the widget's validation state changes. 228 */ 229 void validationChanged( bool valid ); 230 231 /** 232 * Emitted when the parent dialog visibility must be changed (e.g. 233 * to permit access to the map canvas) 234 */ 235 void toggleDialogVisibility( bool visible ); 236 237 protected: 238 239 void dragEnterEvent( QDragEnterEvent *event ) override; 240 void dragLeaveEvent( QDragLeaveEvent *event ) override; 241 void dropEvent( QDropEvent *event ) override; 242 243 private slots: 244 245 void layerMenuAboutToShow(); 246 247 void extentDrawn( const QgsRectangle &extent ); 248 void mapToolDeactivated(); 249 250 private: 251 void setOutputExtent( const QgsRectangle &r, const QgsCoordinateReferenceSystem &srcCrs, QgsExtentWidget::ExtentState state ); 252 void setOutputExtentFromLineEdit(); 253 void setOutputExtentFromCondensedLineEdit(); 254 255 ExtentState mExtentState = OriginalExtent; 256 257 QgsCoordinateReferenceSystem mOutputCrs; 258 259 QgsRectangle mCurrentExtent; 260 QgsCoordinateReferenceSystem mCurrentCrs; 261 262 QgsRectangle mOriginalExtent; 263 QgsCoordinateReferenceSystem mOriginalCrs; 264 265 QMenu *mMenu = nullptr; 266 QMenu *mLayerMenu = nullptr; 267 QgsMapLayerModel *mMapLayerModel = nullptr; 268 QList< QAction * > mLayerMenuActions; 269 QAction *mUseCanvasExtentAction = nullptr; 270 QAction *mUseCurrentExtentAction = nullptr; 271 QAction *mDrawOnCanvasAction = nullptr; 272 273 QPointer< const QgsMapLayer > mExtentLayer; 274 QString mExtentLayerName; 275 276 std::unique_ptr< QgsMapToolExtent > mMapToolExtent; 277 QPointer< QgsMapTool > mMapToolPrevious = nullptr; 278 QgsMapCanvas *mCanvas = nullptr; 279 QSize mRatio; 280 281 bool mIsValid = false; 282 bool mHasFixedOutputCrs = false; 283 284 QRegularExpression mCondensedRe; 285 void setValid( bool valid ); 286 287 void setExtentToLayerExtent( const QString &layerId ); 288 289 QgsMapLayer *mapLayerFromMimeData( const QMimeData *data ) const; 290 291 292 }; 293 294 #endif // QGSEXTENTWIDGET_H 295