1 /*************************************************************************** 2 qgsdualview.h 3 -------------------------------------- 4 Date : 10.2.2013 5 Copyright : (C) 2013 Matthias Kuhn 6 Email : matthias at opengis dot ch 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 QGSDUALVIEW_H 17 #define QGSDUALVIEW_H 18 19 #include <QStackedWidget> 20 21 #include "ui_qgsdualviewbase.h" 22 23 #include "qgsattributeeditorcontext.h" 24 #include "qgsattributetablefiltermodel.h" 25 #include "qgsattributeform.h" 26 #include "qgis_gui.h" 27 28 class QgsFeatureRequest; 29 class QgsMapLayerAction; 30 class QgsScrollArea; 31 class QgsFieldConditionalFormatWidget; 32 33 /** 34 * \ingroup gui 35 * \brief This widget is used to show the attributes of a set of features of a QgsVectorLayer. 36 * The attributes can be edited. 37 * It supports two different layouts: the table layout, in which the attributes for the features 38 * are shown in a table and the editor layout, where the features are shown as a selectable list 39 * and the attributes for the currently selected feature are shown in a form. 40 */ 41 class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBase 42 { 43 Q_OBJECT 44 45 public: 46 47 /** 48 * The view modes, in which this widget can present information. 49 * Relates to the QStackedWidget stacks. 50 * 51 */ 52 enum ViewMode 53 { 54 55 /** 56 * Shows the features and attributes in a table layout 57 */ 58 AttributeTable = 0, 59 60 /** 61 * Show a list of the features, where one can be chosen 62 * and the according attribute dialog will be presented 63 * in the neighbouring frame. 64 */ 65 AttributeEditor = 1 66 }; 67 Q_ENUM( ViewMode ) 68 69 70 //! Action on the map canvas when browsing the list of features 71 enum FeatureListBrowsingAction 72 { 73 NoAction = 0, //!< No action is done 74 PanToFeature, //!< The map is panned to the center of the feature bounding-box 75 ZoomToFeature, //!< The map is zoomed to contained the feature bounding-box 76 }; 77 Q_ENUM( FeatureListBrowsingAction ) 78 79 /** 80 * \brief Constructor 81 * \param parent The parent widget 82 */ 83 explicit QgsDualView( QWidget *parent SIP_TRANSFERTHIS = nullptr ); 84 ~QgsDualView() override; 85 86 /** 87 * Has to be called to initialize the dual view. 88 * 89 * \param layer The layer which should be used to fetch features 90 * \param mapCanvas The mapCanvas (used for the FilterMode 91 * QgsAttributeTableFilterModel::ShowVisible) 92 * \param request Use a modified request to limit the shown features 93 * \param context The context in which this view is shown 94 * \param loadFeatures whether to initially load all features into the view. If set to 95 * FALSE, limited features can later be loaded using setFilterMode() 96 */ 97 void init( QgsVectorLayer *layer, 98 QgsMapCanvas *mapCanvas, 99 const QgsFeatureRequest &request = QgsFeatureRequest(), 100 const QgsAttributeEditorContext &context = QgsAttributeEditorContext(), 101 bool loadFeatures = true ); 102 103 /** 104 * Change the current view mode. 105 * 106 * \param view The view mode to set 107 * \see view() 108 */ 109 void setView( ViewMode view ); 110 111 /** 112 * Returns the current view mode. 113 * \see setView() 114 * \since QGIS 2.16 115 */ 116 ViewMode view() const; 117 118 /** 119 * Set the filter mode 120 * 121 * \param filterMode 122 */ 123 void setFilterMode( QgsAttributeTableFilterModel::FilterMode filterMode ); 124 125 /** 126 * Gets the filter mode 127 * 128 * \returns the filter mode 129 */ filterMode()130 QgsAttributeTableFilterModel::FilterMode filterMode() { return mFilterModel->filterMode(); } 131 132 /** 133 * Toggle the selectedOnTop flag. If enabled, selected features will be moved to top. 134 * 135 * \param selectedOnTop TRUE: Show selected features on top. 136 * FALSE: Use defined sorting column. 137 */ 138 void setSelectedOnTop( bool selectedOnTop ); 139 140 /** 141 * Returns the number of features on the layer. 142 * 143 * \returns Number of features 144 */ 145 int featureCount(); 146 147 /** 148 * Returns the number of features which are currently visible, according to the 149 * filter restrictions 150 * 151 * \returns Number of features 152 */ 153 int filteredFeatureCount(); 154 155 /** 156 * Set a list of currently visible features 157 * 158 * \param filteredFeatures A list of feature ids 159 * 160 * \deprecated since filterFeatures is handled in the attribute filter model itself 161 */ 162 Q_DECL_DEPRECATED void setFilteredFeatures( const QgsFeatureIds &filteredFeatures ); 163 164 /** 165 * Sets the expression and Updates the filtered features in the filter model. 166 * It is called when the filter expression changed. 167 * 168 * \since QGIS 3.10.3 169 */ 170 void filterFeatures( const QgsExpression &filterExpression, const QgsExpressionContext &context ); 171 172 /** 173 * Gets a list of currently visible feature ids. 174 */ filteredFeatures()175 QgsFeatureIds filteredFeatures() { return mFilterModel->filteredFeatures(); } 176 177 /** 178 * Returns the model which has the information about all features (not only filtered) 179 * 180 * \returns The master model 181 */ masterModel()182 QgsAttributeTableModel *masterModel() const { return mMasterModel; } 183 184 /** 185 * Set the request 186 * 187 * \param request The request 188 */ 189 void setRequest( const QgsFeatureRequest &request ); 190 191 /** 192 * Set the feature selection model 193 * 194 * \param featureSelectionManager the feature selection model 195 */ 196 void setFeatureSelectionManager( QgsIFeatureSelectionManager *featureSelectionManager ); 197 198 /** 199 * Returns the table view 200 * 201 * \returns The table view 202 */ tableView()203 QgsAttributeTableView *tableView() { return mTableView; } 204 205 /** 206 * Set the attribute table config which should be used to control 207 * the appearance of the attribute table. 208 */ 209 void setAttributeTableConfig( const QgsAttributeTableConfig &config ); 210 211 /** 212 * Set the expression used for sorting the table and feature list. 213 */ 214 void setSortExpression( const QString &sortExpression, Qt::SortOrder sortOrder = Qt::AscendingOrder ); 215 216 /** 217 * Gets the expression used for sorting the table and feature list. 218 */ 219 QString sortExpression() const; 220 221 /** 222 * The config used for the attribute table. 223 * \returns The config used for the attribute table. 224 */ 225 QgsAttributeTableConfig attributeTableConfig() const; 226 227 public slots: 228 229 /** 230 * \brief Set the current edit selection in the AttributeEditor mode. 231 * 232 * \param fids A list of edited features (Currently only one at a time is supported) 233 */ 234 void setCurrentEditSelection( const QgsFeatureIds &fids ); 235 236 /** 237 * \brief saveEditChanges 238 * 239 * \returns TRUE if the saving was OK. FALSE is possible due to connected 240 * validation logic. 241 */ 242 bool saveEditChanges(); 243 244 void openConditionalStyles(); 245 246 /** 247 * Sets whether multi edit mode is enabled. 248 * \since QGIS 2.16 249 */ 250 void setMultiEditEnabled( bool enabled ); 251 252 /** 253 * Toggles whether search mode should be enabled in the form. 254 * \param enabled set to TRUE to switch on search mode 255 * \since QGIS 2.16 256 */ 257 void toggleSearchMode( bool enabled ); 258 259 /** 260 * Copy the content of the selected cell in the clipboard. 261 * \since QGIS 1.16 262 */ 263 void copyCellContent() const; 264 265 /** 266 * Cancel the progress dialog (if any) 267 * \since QGIS 3.0 268 */ 269 void cancelProgress( ); 270 271 /** 272 * Called in embedded forms when an \a attribute \a value in the parent form has changed. 273 * 274 * Notify the form widgets that something has changed in case they 275 * have filter expression that depend on the parent form scope. 276 * 277 * \since QGIS 3.14 278 */ 279 void parentFormValueChanged( const QString &attribute, const QVariant &value ); 280 281 signals: 282 283 /** 284 * Emitted whenever the display expression is successfully changed 285 * \param expression The expression that was applied 286 */ 287 void displayExpressionChanged( const QString &expression ); 288 289 /** 290 * Emitted whenever the filter changes 291 */ 292 void filterChanged(); 293 294 /** 295 * Emitted when a filter expression is set using the view. 296 * \param expression filter expression 297 * \param type filter type 298 * \since QGIS 2.16 299 */ 300 void filterExpressionSet( const QString &expression, QgsAttributeForm::FilterType type ); 301 302 /** 303 * Emitted when the form changes mode. 304 * \param mode new mode 305 */ 306 void formModeChanged( QgsAttributeEditorContext::Mode mode ); 307 308 /** 309 * Emitted when selecting context menu on the feature list to create the context menu individually 310 * \param menu context menu 311 * \param fid feature id of the selected feature 312 */ 313 void showContextMenuExternally( QgsActionMenu *menu, QgsFeatureId fid ); 314 315 protected: 316 void hideEvent( QHideEvent *event ) override; 317 318 private slots: 319 320 void featureListAboutToChangeEditSelection( bool &ok ); 321 322 /** 323 * Changes the currently visible feature within the attribute editor 324 * 325 * \param feat The newly visible feature 326 */ 327 void featureListCurrentEditSelectionChanged( const QgsFeature &feat ); 328 329 void previewExpressionBuilder(); 330 331 void previewColumnChanged( QAction *previewAction, const QString &expression ); 332 333 void viewWillShowContextMenu( QMenu *menu, const QModelIndex &atIndex ); 334 335 void widgetWillShowContextMenu( QgsActionMenu *menu, const QModelIndex &atIndex ); 336 337 void showViewHeaderMenu( QPoint point ); 338 339 void organizeColumns(); 340 341 void tableColumnResized( int column, int width ); 342 343 void hideColumn(); 344 345 void resizeColumn(); 346 347 void autosizeColumn(); 348 349 void previewExpressionChanged( const QString &expression ); 350 351 void onSortColumnChanged(); 352 353 void updateSelectedFeatures(); 354 355 void extentChanged(); 356 357 /** 358 * Will be called whenever the currently shown feature form changes. 359 * Will forward this signal to the feature list to visually represent 360 * that there has been an edit event. 361 */ 362 void featureFormAttributeChanged( const QString &attribute, const QVariant &value, bool attributeChanged ); 363 364 /** 365 * Will be called periodically, when loading layers from slow data providers. 366 * 367 * \param i The number of features already loaded 368 * \param cancel Set to TRUE to cancel 369 */ 370 virtual void progress( int i, bool &cancel ); 371 372 /** 373 * Will be called, once all the features are loaded. 374 * Use e.g. to close a dialog created from progress( int i, bool &cancel ) 375 */ 376 virtual void finished(); 377 378 //! Zooms to the active feature 379 void zoomToCurrentFeature(); 380 //! Pans to the active feature 381 void panToCurrentFeature(); 382 383 void flashCurrentFeature(); 384 385 void rebuildFullLayerCache(); 386 387 void panZoomGroupButtonToggled( QAbstractButton *button, bool checked ); 388 389 void flashButtonClicked( bool clicked ); 390 391 void filterError( const QString &errorMessage ); 392 393 private: 394 395 /** 396 * Initializes widgets which depend on the attributes of this layer 397 */ 398 void columnBoxInit(); 399 void initLayerCache( bool cacheGeometry ); 400 void initModels( QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, bool loadFeatures ); 401 void restoreRecentDisplayExpressions(); 402 void saveRecentDisplayExpressions() const; 403 void setDisplayExpression( const QString &expression ); 404 void insertRecentlyUsedDisplayExpression( const QString &expression ); 405 void updateEditSelectionProgress( int progress, int count ); 406 void panOrZoomToFeature( const QgsFeatureIds &featureset ); 407 //! disable/enable the buttons of the browsing toolbar (feature list view) 408 void setBrowsingAutoPanScaleAllowed( bool allowed ); 409 410 //! Returns TRUE if the expression dialog has been accepted 411 bool modifySort(); 412 413 414 QgsFieldConditionalFormatWidget *mConditionalFormatWidget = nullptr; 415 QgsAttributeEditorContext mEditorContext; 416 QgsAttributeTableModel *mMasterModel = nullptr; 417 QgsAttributeTableFilterModel *mFilterModel = nullptr; 418 QgsFeatureListModel *mFeatureListModel = nullptr; 419 QgsAttributeForm *mAttributeForm = nullptr; 420 QMenu *mPreviewColumnsMenu = nullptr; 421 QMenu *mPreviewActionMenu = nullptr; 422 QAction *mLastDisplayExpressionAction = nullptr; 423 QMenu *mHorizontalHeaderMenu = nullptr; 424 QgsVectorLayerCache *mLayerCache = nullptr; 425 QPointer< QgsVectorLayer > mLayer = nullptr; 426 QProgressDialog *mProgressDlg = nullptr; 427 QgsIFeatureSelectionManager *mFeatureSelectionManager = nullptr; 428 QString mDisplayExpression; 429 QgsAttributeTableConfig mConfig; 430 QgsScrollArea *mAttributeEditorScrollArea = nullptr; 431 // If the current feature is set, while the form is still not initialized 432 // we will temporarily save it in here and set it on init 433 QgsFeature mTempAttributeFormFeature; 434 QgsFeatureIds mLastFeatureSet; 435 bool mBrowsingAutoPanScaleAllowed = true; 436 ViewMode mPreviousView = AttributeTable; 437 438 friend class TestQgsDualView; 439 friend class TestQgsAttributeTable; 440 }; 441 442 /** 443 * \ingroup gui 444 * \class QgsAttributeTableAction 445 */ 446 class GUI_EXPORT QgsAttributeTableAction : public QAction 447 { 448 Q_OBJECT 449 450 public: 451 452 /** 453 * Create a new attribute table action. 454 * 455 * \since QGIS 3.0 456 */ QgsAttributeTableAction(const QString & name,QgsDualView * dualView,QUuid action,const QModelIndex & fieldIdx)457 QgsAttributeTableAction( const QString &name, QgsDualView *dualView, QUuid action, const QModelIndex &fieldIdx ) 458 : QAction( name, dualView ) 459 , mDualView( dualView ) 460 , mAction( action ) 461 , mFieldIdx( fieldIdx ) 462 {} 463 464 public slots: 465 void execute(); 466 void featureForm(); 467 468 private: 469 QgsDualView *mDualView = nullptr; 470 QUuid mAction; 471 QModelIndex mFieldIdx; 472 }; 473 474 /** 475 * \ingroup gui 476 * \class QgsAttributeTableMapLayerAction 477 */ 478 class GUI_EXPORT QgsAttributeTableMapLayerAction : public QAction 479 { 480 Q_OBJECT 481 482 public: QgsAttributeTableMapLayerAction(const QString & name,QgsDualView * dualView,QgsMapLayerAction * action,const QModelIndex & fieldIdx)483 QgsAttributeTableMapLayerAction( const QString &name, QgsDualView *dualView, QgsMapLayerAction *action, const QModelIndex &fieldIdx ) 484 : QAction( name, dualView ) 485 , mDualView( dualView ) 486 , mAction( action ) 487 , mFieldIdx( fieldIdx ) 488 {} 489 490 public slots: 491 void execute(); 492 493 private: 494 QgsDualView *mDualView = nullptr; 495 QgsMapLayerAction *mAction = nullptr; 496 QModelIndex mFieldIdx; 497 }; 498 499 Q_DECLARE_METATYPE( QModelIndex ); 500 501 #endif // QGSDUALVIEW_H 502