QGIS API Documentation  2.99.0-Master (8ec3eaf)
qgsdualview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdualview.cpp
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 #include "qgsapplication.h"
17 #include "qgsactionmanager.h"
18 #include "qgsattributetablemodel.h"
19 #include "qgsdualview.h"
21 #include "qgsfeaturelistmodel.h"
23 #include "qgsmapcanvas.h"
25 #include "qgsmessagelog.h"
26 #include "qgsvectordataprovider.h"
27 #include "qgsvectorlayercache.h"
30 
31 #include <QClipboard>
32 #include <QDialog>
33 #include <QMenu>
34 #include <QMessageBox>
35 #include <QProgressDialog>
36 #include <QSettings>
37 #include <QGroupBox>
38 #include <QInputDialog>
39 
40 QgsDualView::QgsDualView( QWidget* parent )
41  : QStackedWidget( parent )
42  , mEditorContext()
43  , mMasterModel( nullptr )
44  , mFilterModel( nullptr )
45  , mFeatureListModel( nullptr )
46  , mAttributeForm( nullptr )
47  , mHorizontalHeaderMenu( nullptr )
48  , mLayerCache( nullptr )
49  , mProgressDlg( nullptr )
50  , mFeatureSelectionManager( nullptr )
51  , mAttributeEditorScrollArea( nullptr )
52 {
53  setupUi( this );
54 
55  mConditionalFormatWidget->hide();
56 
57  mPreviewActionMapper = new QSignalMapper( this );
58 
59  mPreviewColumnsMenu = new QMenu( this );
60  mActionPreviewColumnsMenu->setMenu( mPreviewColumnsMenu );
61 
62  // Set preview icon
63  mActionExpressionPreview->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpressionPreview.svg" ) ) );
64 
65  // Connect layer list preview signals
66  connect( mActionExpressionPreview, SIGNAL( triggered() ), SLOT( previewExpressionBuilder() ) );
67  connect( mPreviewActionMapper, SIGNAL( mapped( QObject* ) ), SLOT( previewColumnChanged( QObject* ) ) );
68  connect( mFeatureList, SIGNAL( displayExpressionChanged( QString ) ), this, SLOT( previewExpressionChanged( QString ) ) );
69 }
70 
71 void QgsDualView::init( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, const QgsFeatureRequest &request, const QgsAttributeEditorContext &context )
72 {
73  if ( !layer )
74  return;
75 
76  mEditorContext = context;
77 
78  connect( mTableView, SIGNAL( willShowContextMenu( QMenu*, QModelIndex ) ), this, SLOT( viewWillShowContextMenu( QMenu*, QModelIndex ) ) );
79  mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
80  connect( mTableView->horizontalHeader(), SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( showViewHeaderMenu( QPoint ) ) );
81  connect( mTableView, SIGNAL( columnResized( int, int ) ), this, SLOT( tableColumnResized( int, int ) ) );
82 
83  initLayerCache( layer, !request.filterRect().isNull() );
84  initModels( mapCanvas, request );
85 
86  mConditionalFormatWidget->setLayer( layer );
87 
88  mTableView->setModel( mFilterModel );
89  mFeatureList->setModel( mFeatureListModel );
90  delete mAttributeForm;
91  mAttributeForm = new QgsAttributeForm( layer, QgsFeature(), mEditorContext );
92  if ( !context.parentContext() )
93  {
94  mAttributeEditorScrollArea = new QScrollArea();
95  mAttributeEditorScrollArea->setWidgetResizable( true );
96  mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea );
97  mAttributeEditorScrollArea->setWidget( mAttributeForm );
98  }
99  else
100  {
101  mAttributeEditor->layout()->addWidget( mAttributeForm );
102  }
103 
104  connect( mAttributeForm, SIGNAL( attributeChanged( QString, QVariant ) ), this, SLOT( featureFormAttributeChanged() ) );
105  connect( mAttributeForm, SIGNAL( modeChanged( QgsAttributeForm::Mode ) ), this, SIGNAL( formModeChanged( QgsAttributeForm::Mode ) ) );
106  connect( mMasterModel, SIGNAL( modelChanged() ), mAttributeForm, SLOT( refreshFeature() ) );
107  connect( mAttributeForm, SIGNAL( filterExpressionSet( QString, QgsAttributeForm::FilterType ) ), this, SIGNAL( filterExpressionSet( QString, QgsAttributeForm::FilterType ) ) );
108  connect( mFilterModel, SIGNAL( sortColumnChanged( int, Qt::SortOrder ) ), this, SLOT( onSortColumnChanged() ) );
109  if ( mFeatureListPreviewButton->defaultAction() )
110  mFeatureList->setDisplayExpression( mDisplayExpression );
111  else
112  columnBoxInit();
113 
114  // This slows down load of the attribute table heaps and uses loads of memory.
115  //mTableView->resizeColumnsToContents();
116 
117  mFeatureList->setEditSelection( QgsFeatureIds() << mFeatureListModel->idxToFid( mFeatureListModel->index( 0, 0 ) ) );
118 }
119 
121 {
122  // load fields
123  QList<QgsField> fields = mLayerCache->layer()->fields().toList();
124 
125  QString defaultField;
126 
127  // default expression: saved value
128  QString displayExpression = mLayerCache->layer()->displayExpression();
129 
130  if ( displayExpression.isEmpty() )
131  {
132  // ... there isn't really much to display
133  displayExpression = QStringLiteral( "'[Please define preview text]'" );
134  }
135 
136  mFeatureListPreviewButton->addAction( mActionExpressionPreview );
137  mFeatureListPreviewButton->addAction( mActionPreviewColumnsMenu );
138 
139  Q_FOREACH ( const QgsField& field, fields )
140  {
141  int fieldIndex = mLayerCache->layer()->fields().lookupField( field.name() );
142  if ( fieldIndex == -1 )
143  continue;
144 
145  if ( QgsEditorWidgetRegistry::instance()->findBest( mLayerCache->layer(), field.name() ).type() != QLatin1String( "Hidden" ) )
146  {
147  QIcon icon = mLayerCache->layer()->fields().iconForField( fieldIndex );
148  QString text = field.name();
149 
150  // Generate action for the preview popup button of the feature list
151  QAction* previewAction = new QAction( icon, text, mFeatureListPreviewButton );
152  mPreviewActionMapper->setMapping( previewAction, previewAction );
153  connect( previewAction, SIGNAL( triggered() ), mPreviewActionMapper, SLOT( map() ) );
154  mPreviewColumnsMenu->addAction( previewAction );
155 
156  if ( text == defaultField )
157  {
158  mFeatureListPreviewButton->setDefaultAction( previewAction );
159  }
160  }
161  }
162 
163  // If there is no single field found as preview
164  if ( !mFeatureListPreviewButton->defaultAction() )
165  {
166  mFeatureList->setDisplayExpression( displayExpression );
167  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
168  mDisplayExpression = mFeatureList->displayExpression();
169  }
170  else
171  {
172  mFeatureListPreviewButton->defaultAction()->trigger();
173  }
174 
175  QAction* sortByPreviewExpression = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "sort.svg" ) ), tr( "Sort by preview expression" ), this );
176  connect( sortByPreviewExpression, SIGNAL( triggered( bool ) ), this, SLOT( sortByPreviewExpression() ) );
177  mFeatureListPreviewButton->addAction( sortByPreviewExpression );
178 }
179 
181 {
182  setCurrentIndex( view );
183 }
184 
186 {
187  return static_cast< QgsDualView::ViewMode >( currentIndex() );
188 }
189 
191 {
192  mFilterModel->setFilterMode( filterMode );
193  emit filterChanged();
194 }
195 
196 void QgsDualView::setSelectedOnTop( bool selectedOnTop )
197 {
198  mFilterModel->setSelectedOnTop( selectedOnTop );
199 }
200 
201 void QgsDualView::initLayerCache( QgsVectorLayer* layer, bool cacheGeometry )
202 {
203  // Initialize the cache
204  QSettings settings;
205  int cacheSize = settings.value( QStringLiteral( "/qgis/attributeTableRowCache" ), "10000" ).toInt();
206  mLayerCache = new QgsVectorLayerCache( layer, cacheSize, this );
207  mLayerCache->setCacheGeometry( cacheGeometry );
208  if ( 0 == cacheSize || 0 == ( QgsVectorDataProvider::SelectAtId & mLayerCache->layer()->dataProvider()->capabilities() ) )
209  {
210  connect( mLayerCache, SIGNAL( progress( int, bool & ) ), this, SLOT( progress( int, bool & ) ) );
211  connect( mLayerCache, SIGNAL( finished() ), this, SLOT( finished() ) );
212 
213  mLayerCache->setFullCache( true );
214  }
215 }
216 
217 void QgsDualView::initModels( QgsMapCanvas* mapCanvas, const QgsFeatureRequest& request )
218 {
219  delete mFeatureListModel;
220  delete mFilterModel;
221  delete mMasterModel;
222 
223  mMasterModel = new QgsAttributeTableModel( mLayerCache, this );
224  mMasterModel->setRequest( request );
225  mMasterModel->setEditorContext( mEditorContext );
226  mMasterModel->setExtraColumns( 1 ); // Add one extra column which we can "abuse" as an action column
227 
228  connect( mMasterModel, SIGNAL( progress( int, bool & ) ), this, SLOT( progress( int, bool & ) ) );
229  connect( mMasterModel, SIGNAL( finished() ), this, SLOT( finished() ) );
230 
231  connect( mConditionalFormatWidget, SIGNAL( rulesUpdated( QString ) ), mMasterModel, SLOT( fieldConditionalStyleChanged( QString ) ) );
232 
233  mMasterModel->loadLayer();
234 
235  mFilterModel = new QgsAttributeTableFilterModel( mapCanvas, mMasterModel, mMasterModel );
236 
237  connect( mFeatureList, SIGNAL( displayExpressionChanged( QString ) ), this, SIGNAL( displayExpressionChanged( QString ) ) );
238 
239  mFeatureListModel = new QgsFeatureListModel( mFilterModel, mFilterModel );
240 }
241 
242 void QgsDualView::on_mFeatureList_aboutToChangeEditSelection( bool& ok )
243 {
244  if ( mLayerCache->layer()->isEditable() && !mAttributeForm->save() )
245  ok = false;
246 }
247 
248 void QgsDualView::on_mFeatureList_currentEditSelectionChanged( const QgsFeature &feat )
249 {
250  if ( !mLayerCache->layer()->isEditable() || mAttributeForm->save() )
251  {
252  mAttributeForm->setFeature( feat );
254  }
255  else
256  {
257  // Couldn't save feature
258  }
259 }
260 
262 {
263  mFeatureList->setCurrentFeatureEdited( false );
264  mFeatureList->setEditSelection( fids );
265 }
266 
268 {
269  return mAttributeForm->save();
270 }
271 
273 {
274  mConditionalFormatWidget->setVisible( !mConditionalFormatWidget->isVisible() );
275  mConditionalFormatWidget->viewRules();
276 }
277 
279 {
280  if ( enabled )
282 
284 }
285 
286 void QgsDualView::toggleSearchMode( bool enabled )
287 {
288  if ( enabled )
289  {
291  mAttributeForm->setMode( QgsAttributeForm::SearchMode );
292  }
293  else
294  {
295  mAttributeForm->setMode( QgsAttributeForm::SingleEditMode );
296  }
297 }
298 
299 void QgsDualView::previewExpressionBuilder()
300 {
301  // Show expression builder
302  QgsExpressionContext context;
305  << QgsExpressionContextUtils::layerScope( mLayerCache->layer() );
306 
307  QgsExpressionBuilderDialog dlg( mLayerCache->layer(), mFeatureList->displayExpression(), this, QStringLiteral( "generic" ), context );
308  dlg.setWindowTitle( tr( "Expression based preview" ) );
309  dlg.setExpressionText( mFeatureList->displayExpression() );
310 
311  if ( dlg.exec() == QDialog::Accepted )
312  {
313  mFeatureList->setDisplayExpression( dlg.expressionText() );
314  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
315  mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
316  }
317 
318  mDisplayExpression = mFeatureList->displayExpression();
319 }
320 
321 void QgsDualView::previewColumnChanged( QObject* action )
322 {
323  QAction* previewAction = qobject_cast< QAction* >( action );
324 
325  if ( previewAction )
326  {
327  if ( !mFeatureList->setDisplayExpression( QStringLiteral( "COALESCE( \"%1\", '<NULL>' )" ).arg( previewAction->text() ) ) )
328  {
329  QMessageBox::warning( this,
330  tr( "Could not set preview column" ),
331  tr( "Could not set column '%1' as preview column.\nParser error:\n%2" )
332  .arg( previewAction->text(), mFeatureList->parserErrorString() )
333  );
334  }
335  else
336  {
337  mFeatureListPreviewButton->setDefaultAction( previewAction );
338  mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
339  }
340  }
341 
342  mDisplayExpression = mFeatureList->displayExpression();
343 
344  Q_ASSERT( previewAction );
345 }
346 
348 {
349  return mMasterModel->rowCount();
350 }
351 
353 {
354  return mFilterModel->rowCount();
355 }
356 
358 {
359  QAction* action = qobject_cast<QAction*>( sender() );
360 
361  if ( action && action->data().isValid() && action->data().canConvert<QModelIndex>() )
362  {
363  QModelIndex index = action->data().toModelIndex();
364  QVariant var = masterModel()->data( index, Qt::DisplayRole );
365  QApplication::clipboard()->setText( var.toString() );
366  }
367 }
368 
369 void QgsDualView::viewWillShowContextMenu( QMenu* menu, const QModelIndex& atIndex )
370 {
371  if ( !menu )
372  {
373  return;
374  }
375 
376 
377  QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );
378 
379  QAction *copyContentAction = new QAction( tr( "Copy cell content" ), this );
380  copyContentAction->setData( QVariant::fromValue<QModelIndex>( sourceIndex ) );
381  menu->addAction( copyContentAction );
382  connect( copyContentAction, SIGNAL( triggered() ), this, SLOT( copyCellContent() ) );
383 
384  QgsVectorLayer* vl = mFilterModel->layer();
385  QgsMapCanvas* canvas = mFilterModel->mapCanvas();
386  if ( canvas && vl && vl->geometryType() != QgsWkbTypes::NullGeometry )
387  {
388  menu->addAction( tr( "Zoom to feature" ), this, SLOT( zoomToCurrentFeature() ) );
389  menu->addAction( tr( "Pan to feature" ), this, SLOT( panToCurrentFeature() ) );
390  }
391 
392  //add user-defined actions to context menu
393  QList<QgsAction> actions = mLayerCache->layer()->actions()->actions( QStringLiteral( "Field" ) );
394  if ( !actions.isEmpty() )
395  {
396  QAction* a = menu->addAction( tr( "Run layer action" ) );
397  a->setEnabled( false );
398 
399  Q_FOREACH ( const QgsAction& action, actions )
400  {
401  if ( !action.runable() )
402  continue;
403 
404  QgsAttributeTableAction* a = new QgsAttributeTableAction( action.name(), this, action.id(), sourceIndex );
405  menu->addAction( action.name(), a, SLOT( execute() ) );
406  }
407  }
408 
409  //add actions from QgsMapLayerActionRegistry to context menu
410  QList<QgsMapLayerAction *> registeredActions = QgsMapLayerActionRegistry::instance()->mapLayerActions( mLayerCache->layer() );
411  if ( !registeredActions.isEmpty() )
412  {
413  //add a separator between user defined and standard actions
414  menu->addSeparator();
415 
416  QList<QgsMapLayerAction*>::iterator actionIt;
417  for ( actionIt = registeredActions.begin(); actionIt != registeredActions.end(); ++actionIt )
418  {
419  QgsAttributeTableMapLayerAction *a = new QgsAttributeTableMapLayerAction(( *actionIt )->text(), this, ( *actionIt ), sourceIndex );
420  menu->addAction(( *actionIt )->text(), a, SLOT( execute() ) );
421  }
422  }
423 
424  menu->addSeparator();
425  QgsAttributeTableAction* a = new QgsAttributeTableAction( tr( "Open form" ), this, QString(), sourceIndex );
426  menu->addAction( tr( "Open form" ), a, SLOT( featureForm() ) );
427 }
428 
429 void QgsDualView::showViewHeaderMenu( QPoint point )
430 {
431  int col = mTableView->columnAt( point.x() );
432 
433  delete mHorizontalHeaderMenu;
434  mHorizontalHeaderMenu = new QMenu( this );
435 
436  QAction* hide = new QAction( tr( "&Hide column" ), mHorizontalHeaderMenu );
437  connect( hide, SIGNAL( triggered( bool ) ), this, SLOT( hideColumn() ) );
438  hide->setData( col );
439  mHorizontalHeaderMenu->addAction( hide );
440  QAction* setWidth = new QAction( tr( "&Set width..." ), mHorizontalHeaderMenu );
441  connect( setWidth, SIGNAL( triggered( bool ) ), this, SLOT( resizeColumn() ) );
442  setWidth->setData( col );
443  mHorizontalHeaderMenu->addAction( setWidth );
444  QAction* optimizeWidth = new QAction( tr( "&Autosize" ), mHorizontalHeaderMenu );
445  connect( optimizeWidth, SIGNAL( triggered( bool ) ), this, SLOT( autosizeColumn() ) );
446  optimizeWidth->setData( col );
447  mHorizontalHeaderMenu->addAction( optimizeWidth );
448 
449  mHorizontalHeaderMenu->addSeparator();
450  QAction* organize = new QAction( tr( "&Organize columns..." ), mHorizontalHeaderMenu );
451  connect( organize, SIGNAL( triggered( bool ) ), this, SLOT( organizeColumns() ) );
452  mHorizontalHeaderMenu->addAction( organize );
453  QAction* sort = new QAction( tr( "&Sort..." ), mHorizontalHeaderMenu );
454  connect( sort, SIGNAL( triggered( bool ) ), this, SLOT( modifySort() ) );
455  mHorizontalHeaderMenu->addAction( sort );
456 
457  mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
458 }
459 
460 void QgsDualView::organizeColumns()
461 {
462  if ( !mLayerCache->layer() )
463  {
464  return;
465  }
466 
467  QgsOrganizeTableColumnsDialog dialog( mLayerCache->layer(), this );
468  if ( dialog.exec() == QDialog::Accepted )
469  {
470  QgsAttributeTableConfig config = dialog.config();
471  setAttributeTableConfig( config );
472  }
473 }
474 
475 void QgsDualView::tableColumnResized( int column, int width )
476 {
477  QgsAttributeTableConfig config = mConfig;
478  int sourceCol = config.mapVisibleColumnToIndex( column );
479  if ( sourceCol >= 0 )
480  {
481  config.setColumnWidth( sourceCol, width );
482  setAttributeTableConfig( config );
483  }
484 }
485 
486 void QgsDualView::hideColumn()
487 {
488  QAction* action = qobject_cast<QAction*>( sender() );
489  int col = action->data().toInt();
490  QgsAttributeTableConfig config = mConfig;
491  int sourceCol = mConfig.mapVisibleColumnToIndex( col );
492  if ( sourceCol >= 0 )
493  {
494  config.setColumnHidden( sourceCol, true );
495  setAttributeTableConfig( config );
496  }
497 }
498 
499 void QgsDualView::resizeColumn()
500 {
501  QAction* action = qobject_cast<QAction*>( sender() );
502  int col = action->data().toInt();
503  if ( col < 0 )
504  return;
505 
506  QgsAttributeTableConfig config = mConfig;
507  int sourceCol = config.mapVisibleColumnToIndex( col );
508  if ( sourceCol >= 0 )
509  {
510  bool ok = false;
511  int width = QInputDialog::getInt( this, tr( "Set column width" ), tr( "Enter column width" ),
512  mTableView->columnWidth( col ),
513  0, 1000, 10, &ok );
514  if ( ok )
515  {
516  config.setColumnWidth( sourceCol, width );
517  setAttributeTableConfig( config );
518  }
519  }
520 }
521 
522 void QgsDualView::autosizeColumn()
523 {
524  QAction* action = qobject_cast<QAction*>( sender() );
525  int col = action->data().toInt();
526  mTableView->resizeColumnToContents( col );
527 }
528 
529 void QgsDualView::modifySort()
530 {
531  QgsVectorLayer* layer = mLayerCache->layer();
532  if ( !layer )
533  return;
534 
535  QgsAttributeTableConfig config = mConfig;
536 
537  QDialog orderByDlg;
538  orderByDlg.setWindowTitle( tr( "Configure attribute table sort order" ) );
539  QDialogButtonBox* dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
540  QGridLayout* layout = new QGridLayout();
541  connect( dialogButtonBox, SIGNAL( accepted() ), &orderByDlg, SLOT( accept() ) );
542  connect( dialogButtonBox, SIGNAL( rejected() ), &orderByDlg, SLOT( reject() ) );
543  orderByDlg.setLayout( layout );
544 
545  QGroupBox* sortingGroupBox = new QGroupBox();
546  sortingGroupBox->setTitle( tr( "Defined sort order in attribute table" ) );
547  sortingGroupBox->setCheckable( true );
548  sortingGroupBox->setChecked( !sortExpression().isEmpty() );
549  layout->addWidget( sortingGroupBox );
550  sortingGroupBox->setLayout( new QGridLayout() );
551 
552  QgsExpressionBuilderWidget* expressionBuilder = new QgsExpressionBuilderWidget();
553  QgsExpressionContext context;
557  expressionBuilder->setExpressionContext( context );
558  expressionBuilder->setLayer( layer );
559  expressionBuilder->loadFieldNames();
560  expressionBuilder->loadRecent( QStringLiteral( "generic" ) );
561  expressionBuilder->setExpressionText( sortExpression().isEmpty() ? layer->displayExpression() : sortExpression() );
562 
563  sortingGroupBox->layout()->addWidget( expressionBuilder );
564 
565  QCheckBox* cbxSortAscending = new QCheckBox( tr( "Sort ascending" ) );
566  cbxSortAscending->setChecked( config.sortOrder() == Qt::AscendingOrder );
567  sortingGroupBox->layout()->addWidget( cbxSortAscending );
568 
569  layout->addWidget( dialogButtonBox );
570  if ( orderByDlg.exec() )
571  {
572  Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
573  if ( sortingGroupBox->isChecked() )
574  {
575  setSortExpression( expressionBuilder->expressionText(), sortOrder );
576  config.setSortExpression( expressionBuilder->expressionText() );
577  config.setSortOrder( sortOrder );
578  }
579  else
580  {
581  setSortExpression( QString(), sortOrder );
582  config.setSortExpression( QString() );
583  }
584 
585  setAttributeTableConfig( config );
586  }
587 }
588 
589 void QgsDualView::zoomToCurrentFeature()
590 {
591  QModelIndex currentIndex = mTableView->currentIndex();
592  if ( !currentIndex.isValid() )
593  {
594  return;
595  }
596 
597  QgsFeatureIds ids;
598  ids.insert( mFilterModel->rowToId( currentIndex ) );
599  QgsMapCanvas* canvas = mFilterModel->mapCanvas();
600  if ( canvas )
601  {
602  canvas->zoomToFeatureIds( mLayerCache->layer(), ids );
603  }
604 }
605 
606 void QgsDualView::panToCurrentFeature()
607 {
608  QModelIndex currentIndex = mTableView->currentIndex();
609  if ( !currentIndex.isValid() )
610  {
611  return;
612  }
613 
614  QgsFeatureIds ids;
615  ids.insert( mFilterModel->rowToId( currentIndex ) );
616  QgsMapCanvas* canvas = mFilterModel->mapCanvas();
617  if ( canvas )
618  {
619  canvas->panToFeatureIds( mLayerCache->layer(), ids );
620  }
621 }
622 
623 void QgsDualView::previewExpressionChanged( const QString& expression )
624 {
625  mLayerCache->layer()->setDisplayExpression( expression );
626 }
627 
628 void QgsDualView::onSortColumnChanged()
629 {
630  QgsAttributeTableConfig cfg = mLayerCache->layer()->attributeTableConfig();
631  cfg.setSortExpression( mFilterModel->sortExpression() );
632  cfg.setSortOrder( mFilterModel->sortOrder() );
634 }
635 
636 void QgsDualView::sortByPreviewExpression()
637 {
638  Qt::SortOrder sortOrder = Qt::AscendingOrder;
639  if ( mFeatureList->displayExpression() == sortExpression() )
640  {
641  sortOrder = mConfig.sortOrder() == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
642  }
643  setSortExpression( mFeatureList->displayExpression(), sortOrder );
644 }
645 
646 void QgsDualView::featureFormAttributeChanged()
647 {
648  mFeatureList->setCurrentFeatureEdited( true );
649 }
650 
652 {
653  mFilterModel->setFilteredFeatures( filteredFeatures );
654 }
655 
657 {
658  mMasterModel->setRequest( request );
659 }
660 
662 {
663  mTableView->setFeatureSelectionManager( featureSelectionManager );
664  mFeatureList->setFeatureSelectionManager( featureSelectionManager );
665 
666  if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == this )
667  delete mFeatureSelectionManager;
668 
669  mFeatureSelectionManager = featureSelectionManager;
670 }
671 
673 {
674  mLayerCache->layer()->setAttributeTableConfig( config );
675  mFilterModel->setAttributeTableConfig( config );
676  mTableView->setAttributeTableConfig( config );
677  mConfig = config;
678 }
679 
680 void QgsDualView::setSortExpression( const QString& sortExpression, Qt::SortOrder sortOrder )
681 {
682  if ( sortExpression.isNull() )
683  mFilterModel->sort( -1 );
684  else
685  mFilterModel->sort( sortExpression, sortOrder );
686 
687  mConfig.setSortExpression( sortExpression );
688  mConfig.setSortOrder( sortOrder );
689  setAttributeTableConfig( mConfig );
690 }
691 
693 {
694  return mFilterModel->sortExpression();
695 }
696 
697 void QgsDualView::progress( int i, bool& cancel )
698 {
699  if ( !mProgressDlg )
700  {
701  mProgressDlg = new QProgressDialog( tr( "Loading features..." ), tr( "Abort" ), 0, 0, this );
702  mProgressDlg->setWindowTitle( tr( "Attribute table" ) );
703  mProgressDlg->setWindowModality( Qt::WindowModal );
704  mProgressDlg->show();
705  }
706 
707  mProgressDlg->setLabelText( tr( "%1 features loaded." ).arg( i ) );
708  QCoreApplication::processEvents();
709 
710  cancel = mProgressDlg && mProgressDlg->wasCanceled();
711 }
712 
713 void QgsDualView::finished()
714 {
715  delete mProgressDlg;
716  mProgressDlg = nullptr;
717 }
718 
719 /*
720  * QgsAttributeTableAction
721  */
722 
724 {
725  mDualView->masterModel()->executeAction( mAction, mFieldIdx );
726 }
727 
729 {
730  QgsFeatureIds editedIds;
731  editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
732  mDualView->setCurrentEditSelection( editedIds );
733  mDualView->setView( QgsDualView::AttributeEditor );
734 }
735 
736 /*
737  * QgsAttributeTableMapLayerAction
738  */
739 
741 {
742  mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx );
743 }
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:291
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
QgsActionManager * actions()
Get all layer actions defined on this layer.
QgsFeatureId id
Definition: qgsfeature.h:139
QgsFeatureId rowToId(const QModelIndex &row)
Returns the feature id for a given model index.
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
static unsigned index
void setFilterMode(QgsAttributeTableFilterModel::FilterMode filterMode)
Set the filter mode.
void setSortExpression(const QString &sortExpression)
Set the sort expression used for sorting.
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
void setAttributeTableConfig(const QgsAttributeTableConfig &config)
Set the attribute table configuration to control which fields are shown, in which order they are show...
void setExpressionText(const QString &text)
virtual Capabilities capabilities() const
Returns flags containing the supported capabilities.
QgsFeatureId idxToFid(const QModelIndex &index) const
QString name
Definition: qgsfield.h:55
void setSelectedOnTop(bool selectedOnTop)
Changes the sort order of the features.
QgsAttributeTableModel * masterModel() const
Returns the model which has the information about all features (not only filtered) ...
Definition: qgsdualview.h:155
void filterExpressionSet(const QString &expression, QgsAttributeForm::FilterType type)
Is emitted when a filter expression is set using the view.
void setSortOrder(Qt::SortOrder sortOrder)
Set the sort order.
void setFilterMode(FilterMode filterMode)
Set the filter mode the filter will use.
void toggleSearchMode(bool enabled)
Toggles whether search mode should be enabled in the form.
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
Set the feature selection model.
void openConditionalStyles()
Multi edit mode, for editing fields of multiple features at once.
QIcon iconForField(int fieldIdx) const
Returns an icon corresponding to a field index, based on the field&#39;s type and source.
Definition: qgsfields.cpp:249
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:355
QString sortExpression() const
Get the expression used for sorting the table and feature list.
This class contains context information for attribute editor widgets.
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
void setLayer(QgsVectorLayer *layer)
Sets layer in order to get the fields and values.
bool save()
Save all the values from the editors to the layer.
ViewMode
The view modes, in which this widget can present information.
Definition: qgsdualview.h:52
void loadRecent(const QString &collection="generic")
Loads the recent expressions from the given collection.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
QList< QgsAction > actions(const QString &actionScope=QString()) const
Return a list of actions that are available in the given action scope.
QgsVectorLayer * layer()
Returns the layer to which this cache belongs.
int filteredFeatureCount()
Returns the number of features which are currently visible, according to the filter restrictions...
void setDisplayExpression(const QString &displayExpression)
Set the preview expression, used to create a human readable preview string.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:135
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
void setCurrentEditSelection(const QgsFeatureIds &fids)
Set the current edit selection in the AttributeEditor mode.
int mapVisibleColumnToIndex(int visibleColumn) const
Maps a visible column index to its original column index.
virtual bool isEditable() const override
Returns true if the provider is in editing mode.
static QgsEditorWidgetRegistry * instance()
This class is a singleton and has therefore to be accessed with this method instead of a constructor...
const QgsRectangle & filterRect() const
Get the rectangle from which features will be taken.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:106
void setView(ViewMode view)
Change the current view mode.
virtual void setFilteredFeatures(const QgsFeatureIds &ids)
Specify a list of features, which the filter will accept.
QgsFields fields() const
Returns the list of fields of this layer.
virtual QVariant data(const QModelIndex &index, int role) const override
Returns data on the given index.
void setAttributeTableConfig(const QgsAttributeTableConfig &config)
Set the attribute table config which should be used to control the appearance of the attribute table...
QgsDualView(QWidget *parent=nullptr)
Constructor.
Definition: qgsdualview.cpp:40
Show a list of the features, where one can be chosen and the according attribute dialog will be prese...
Definition: qgsdualview.h:65
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void setMode(Mode mode)
Sets the current mode of the form.
void setColumnWidth(int column, int width)
Sets the width of a column.
void copyCellContent() const
Copy the content of the selected cell in the clipboard.
void setSortExpression(const QString &sortExpression, Qt::SortOrder sortOrder=Qt::AscendingOrder)
Set the expression used for sorting the table and feature list.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
FilterType
Filter types.
void setExtraColumns(int extraColumns)
Empty extra columns to announce from this model.
void setFeature(const QgsFeature &feature)
Update all editors to correspond to a different feature.
FilterMode
The filter mode defines how the rows should be filtered.
Dialog for organising (hiding and reordering) columns in the attributes table.
Form values are used for searching/filtering the layer.
void setEditorContext(const QgsAttributeEditorContext &context)
Sets the context in which this table is shown.
ViewMode view() const
Returns the current view mode.
Utility class that encapsulates an action based on vector attributes.
Definition: qgsaction.h:32
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void panToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Centers canvas extent to feature ids.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void init(QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request=QgsFeatureRequest(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
Has to be called to initialize the dual view.
Definition: qgsdualview.cpp:71
bool runable() const
Checks if the action is runable on the current platform.
Definition: qgsaction.cpp:29
QgsFeatureIds filteredFeatures()
Get a list of currently visible feature ids.
Definition: qgsdualview.h:148
void filterChanged()
Is emitted, whenever the filter changes.
QString name() const
The name of the action. This may be a longer description.
Definition: qgsaction.h:91
void loadFieldNames()
Loads all the field names from the layer.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:47
Fast access to features using their ID.
QString displayExpression
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context for the widget.
QString sortExpression() const
The expression which is used to sort the attribute table.
This class caches features of a given QgsVectorLayer.
const QgsAttributeEditorContext * parentContext() const
bool saveEditChanges()
saveEditChanges
void setRequest(const QgsFeatureRequest &request)
Set the request.
QgsAttributeTableFilterModel::FilterMode filterMode()
Get the filter mode.
Definition: qgsdualview.h:112
A reusable widget that can be used to build a expression string.
QgsAttributeTableConfig attributeTableConfig() const
Get the attribute table configuration object.
void setSelectedOnTop(bool selectedOnTop)
Toggle the selectedOnTop flag.
void zoomToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Set canvas extent to the bounding box of a set of features.
static QgsMapLayerActionRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QgsEditorWidgetSetup findBest(const QgsVectorLayer *vl, const QString &fieldName) const
Find the best editor widget and its configuration for a given field.
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows.
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
void setFullCache(bool fullCache)
This enables or disables full caching.
virtual void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
Sort by the given column using the given order.
void setColumnHidden(int column, bool hidden)
Sets whether the specified column should be hidden.
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:186
bool isNull() const
test if the rectangle is null (all coordinates zero or after call to setMinimal()).
QgsMapCanvas * mapCanvas() const
Returns the map canvas.
void displayExpressionChanged(const QString &expression)
Is emitted, whenever the display expression is successfully changed.
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, QgsMapLayerAction::Targets targets=QgsMapLayerAction::AllActions)
Returns the map layer actions which can run on the specified layer.
QString expressionText()
Gets the expression string that has been set in the expression area.
void formModeChanged(QgsAttributeForm::Mode mode)
Emitted when the form changes mode.
void setExpressionText(const QString &expression)
Sets the expression string for the widget.
QUuid id() const
Returns a unique id for this action.
Definition: qgsaction.h:101
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
QgsVectorDataProvider * dataProvider()
Returns the data provider.
Single edit mode, for editing a single feature.
void setFilteredFeatures(const QgsFeatureIds &filteredFeatures)
Set a list of currently visible features.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
This is a container for configuration of the attribute table.
Qt::SortOrder sortOrder() const
Get the sort order.
void setMultiEditEnabled(bool enabled)
Sets whether multi edit mode is enabled.
Is an interface class to abstract feature selection handling.
Represents a vector layer which manages a vector based data sets.
void setAttributeTableConfig(const QgsAttributeTableConfig &attributeTableConfig)
Set the attribute table configuration object.
A generic dialog for building expression strings.
void columnBoxInit()
Initializes widgets which depend on the attributes of this layer.
int featureCount()
Returns the number of features on the layer.