QGIS API Documentation  2.99.0-Master (0a63d1f)
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
303 
304  QgsExpressionBuilderDialog dlg( mLayerCache->layer(), mFeatureList->displayExpression(), this, QStringLiteral( "generic" ), context );
305  dlg.setWindowTitle( tr( "Expression based preview" ) );
306  dlg.setExpressionText( mFeatureList->displayExpression() );
307 
308  if ( dlg.exec() == QDialog::Accepted )
309  {
310  mFeatureList->setDisplayExpression( dlg.expressionText() );
311  mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
312  mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
313  }
314 
315  mDisplayExpression = mFeatureList->displayExpression();
316 }
317 
318 void QgsDualView::previewColumnChanged( QObject* action )
319 {
320  QAction* previewAction = qobject_cast< QAction* >( action );
321 
322  if ( previewAction )
323  {
324  if ( !mFeatureList->setDisplayExpression( QStringLiteral( "COALESCE( \"%1\", '<NULL>' )" ).arg( previewAction->text() ) ) )
325  {
326  QMessageBox::warning( this,
327  tr( "Could not set preview column" ),
328  tr( "Could not set column '%1' as preview column.\nParser error:\n%2" )
329  .arg( previewAction->text(), mFeatureList->parserErrorString() )
330  );
331  }
332  else
333  {
334  mFeatureListPreviewButton->setDefaultAction( previewAction );
335  mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
336  }
337  }
338 
339  mDisplayExpression = mFeatureList->displayExpression();
340 
341  Q_ASSERT( previewAction );
342 }
343 
345 {
346  return mMasterModel->rowCount();
347 }
348 
350 {
351  return mFilterModel->rowCount();
352 }
353 
355 {
356  QAction* action = qobject_cast<QAction*>( sender() );
357 
358  if ( action && action->data().isValid() && action->data().canConvert<QModelIndex>() )
359  {
360  QModelIndex index = action->data().toModelIndex();
361  QVariant var = masterModel()->data( index, Qt::DisplayRole );
362  QApplication::clipboard()->setText( var.toString() );
363  }
364 }
365 
366 void QgsDualView::viewWillShowContextMenu( QMenu* menu, const QModelIndex& atIndex )
367 {
368  if ( !menu )
369  {
370  return;
371  }
372 
373 
374  QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );
375 
376  QAction *copyContentAction = new QAction( tr( "Copy cell content" ), this );
377  copyContentAction->setData( QVariant::fromValue<QModelIndex>( sourceIndex ) );
378  menu->addAction( copyContentAction );
379  connect( copyContentAction, SIGNAL( triggered() ), this, SLOT( copyCellContent() ) );
380 
381  QgsVectorLayer* vl = mFilterModel->layer();
382  QgsMapCanvas* canvas = mFilterModel->mapCanvas();
383  if ( canvas && vl && vl->geometryType() != QgsWkbTypes::NullGeometry )
384  {
385  menu->addAction( tr( "Zoom to feature" ), this, SLOT( zoomToCurrentFeature() ) );
386  menu->addAction( tr( "Pan to feature" ), this, SLOT( panToCurrentFeature() ) );
387  }
388 
389  //add user-defined actions to context menu
390  QList<QgsAction> actions = mLayerCache->layer()->actions()->actions( QStringLiteral( "Field" ) );
391  if ( !actions.isEmpty() )
392  {
393  QAction* a = menu->addAction( tr( "Run layer action" ) );
394  a->setEnabled( false );
395 
396  Q_FOREACH ( const QgsAction& action, actions )
397  {
398  if ( !action.runable() )
399  continue;
400 
401  QgsAttributeTableAction* a = new QgsAttributeTableAction( action.name(), this, action.id(), sourceIndex );
402  menu->addAction( action.name(), a, SLOT( execute() ) );
403  }
404  }
405 
406  //add actions from QgsMapLayerActionRegistry to context menu
407  QList<QgsMapLayerAction *> registeredActions = QgsMapLayerActionRegistry::instance()->mapLayerActions( mLayerCache->layer() );
408  if ( !registeredActions.isEmpty() )
409  {
410  //add a separator between user defined and standard actions
411  menu->addSeparator();
412 
413  QList<QgsMapLayerAction*>::iterator actionIt;
414  for ( actionIt = registeredActions.begin(); actionIt != registeredActions.end(); ++actionIt )
415  {
416  QgsAttributeTableMapLayerAction *a = new QgsAttributeTableMapLayerAction(( *actionIt )->text(), this, ( *actionIt ), sourceIndex );
417  menu->addAction(( *actionIt )->text(), a, SLOT( execute() ) );
418  }
419  }
420 
421  menu->addSeparator();
422  QgsAttributeTableAction* a = new QgsAttributeTableAction( tr( "Open form" ), this, QString(), sourceIndex );
423  menu->addAction( tr( "Open form" ), a, SLOT( featureForm() ) );
424 }
425 
426 void QgsDualView::showViewHeaderMenu( QPoint point )
427 {
428  int col = mTableView->columnAt( point.x() );
429 
430  delete mHorizontalHeaderMenu;
431  mHorizontalHeaderMenu = new QMenu( this );
432 
433  QAction* hide = new QAction( tr( "&Hide column" ), mHorizontalHeaderMenu );
434  connect( hide, SIGNAL( triggered( bool ) ), this, SLOT( hideColumn() ) );
435  hide->setData( col );
436  mHorizontalHeaderMenu->addAction( hide );
437  QAction* setWidth = new QAction( tr( "&Set width..." ), mHorizontalHeaderMenu );
438  connect( setWidth, SIGNAL( triggered( bool ) ), this, SLOT( resizeColumn() ) );
439  setWidth->setData( col );
440  mHorizontalHeaderMenu->addAction( setWidth );
441  QAction* optimizeWidth = new QAction( tr( "&Autosize" ), mHorizontalHeaderMenu );
442  connect( optimizeWidth, SIGNAL( triggered( bool ) ), this, SLOT( autosizeColumn() ) );
443  optimizeWidth->setData( col );
444  mHorizontalHeaderMenu->addAction( optimizeWidth );
445 
446  mHorizontalHeaderMenu->addSeparator();
447  QAction* organize = new QAction( tr( "&Organize columns..." ), mHorizontalHeaderMenu );
448  connect( organize, SIGNAL( triggered( bool ) ), this, SLOT( organizeColumns() ) );
449  mHorizontalHeaderMenu->addAction( organize );
450  QAction* sort = new QAction( tr( "&Sort..." ), mHorizontalHeaderMenu );
451  connect( sort, SIGNAL( triggered( bool ) ), this, SLOT( modifySort() ) );
452  mHorizontalHeaderMenu->addAction( sort );
453 
454  mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
455 }
456 
457 void QgsDualView::organizeColumns()
458 {
459  if ( !mLayerCache->layer() )
460  {
461  return;
462  }
463 
464  QgsOrganizeTableColumnsDialog dialog( mLayerCache->layer(), this );
465  if ( dialog.exec() == QDialog::Accepted )
466  {
467  QgsAttributeTableConfig config = dialog.config();
468  setAttributeTableConfig( config );
469  }
470 }
471 
472 void QgsDualView::tableColumnResized( int column, int width )
473 {
474  QgsAttributeTableConfig config = mConfig;
475  int sourceCol = config.mapVisibleColumnToIndex( column );
476  if ( sourceCol >= 0 )
477  {
478  config.setColumnWidth( sourceCol, width );
479  setAttributeTableConfig( config );
480  }
481 }
482 
483 void QgsDualView::hideColumn()
484 {
485  QAction* action = qobject_cast<QAction*>( sender() );
486  int col = action->data().toInt();
487  QgsAttributeTableConfig config = mConfig;
488  int sourceCol = mConfig.mapVisibleColumnToIndex( col );
489  if ( sourceCol >= 0 )
490  {
491  config.setColumnHidden( sourceCol, true );
492  setAttributeTableConfig( config );
493  }
494 }
495 
496 void QgsDualView::resizeColumn()
497 {
498  QAction* action = qobject_cast<QAction*>( sender() );
499  int col = action->data().toInt();
500  if ( col < 0 )
501  return;
502 
503  QgsAttributeTableConfig config = mConfig;
504  int sourceCol = config.mapVisibleColumnToIndex( col );
505  if ( sourceCol >= 0 )
506  {
507  bool ok = false;
508  int width = QInputDialog::getInt( this, tr( "Set column width" ), tr( "Enter column width" ),
509  mTableView->columnWidth( col ),
510  0, 1000, 10, &ok );
511  if ( ok )
512  {
513  config.setColumnWidth( sourceCol, width );
514  setAttributeTableConfig( config );
515  }
516  }
517 }
518 
519 void QgsDualView::autosizeColumn()
520 {
521  QAction* action = qobject_cast<QAction*>( sender() );
522  int col = action->data().toInt();
523  mTableView->resizeColumnToContents( col );
524 }
525 
526 void QgsDualView::modifySort()
527 {
528  QgsVectorLayer* layer = mLayerCache->layer();
529  if ( !layer )
530  return;
531 
532  QgsAttributeTableConfig config = mConfig;
533 
534  QDialog orderByDlg;
535  orderByDlg.setWindowTitle( tr( "Configure attribute table sort order" ) );
536  QDialogButtonBox* dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
537  QGridLayout* layout = new QGridLayout();
538  connect( dialogButtonBox, SIGNAL( accepted() ), &orderByDlg, SLOT( accept() ) );
539  connect( dialogButtonBox, SIGNAL( rejected() ), &orderByDlg, SLOT( reject() ) );
540  orderByDlg.setLayout( layout );
541 
542  QGroupBox* sortingGroupBox = new QGroupBox();
543  sortingGroupBox->setTitle( tr( "Defined sort order in attribute table" ) );
544  sortingGroupBox->setCheckable( true );
545  sortingGroupBox->setChecked( !sortExpression().isEmpty() );
546  layout->addWidget( sortingGroupBox );
547  sortingGroupBox->setLayout( new QGridLayout() );
548 
549  QgsExpressionBuilderWidget* expressionBuilder = new QgsExpressionBuilderWidget();
551  expressionBuilder->setExpressionContext( context );
552  expressionBuilder->setLayer( layer );
553  expressionBuilder->loadFieldNames();
554  expressionBuilder->loadRecent( QStringLiteral( "generic" ) );
555  expressionBuilder->setExpressionText( sortExpression().isEmpty() ? layer->displayExpression() : sortExpression() );
556 
557  sortingGroupBox->layout()->addWidget( expressionBuilder );
558 
559  QCheckBox* cbxSortAscending = new QCheckBox( tr( "Sort ascending" ) );
560  cbxSortAscending->setChecked( config.sortOrder() == Qt::AscendingOrder );
561  sortingGroupBox->layout()->addWidget( cbxSortAscending );
562 
563  layout->addWidget( dialogButtonBox );
564  if ( orderByDlg.exec() )
565  {
566  Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
567  if ( sortingGroupBox->isChecked() )
568  {
569  setSortExpression( expressionBuilder->expressionText(), sortOrder );
570  config.setSortExpression( expressionBuilder->expressionText() );
571  config.setSortOrder( sortOrder );
572  }
573  else
574  {
575  setSortExpression( QString(), sortOrder );
576  config.setSortExpression( QString() );
577  }
578 
579  setAttributeTableConfig( config );
580  }
581 }
582 
583 void QgsDualView::zoomToCurrentFeature()
584 {
585  QModelIndex currentIndex = mTableView->currentIndex();
586  if ( !currentIndex.isValid() )
587  {
588  return;
589  }
590 
591  QgsFeatureIds ids;
592  ids.insert( mFilterModel->rowToId( currentIndex ) );
593  QgsMapCanvas* canvas = mFilterModel->mapCanvas();
594  if ( canvas )
595  {
596  canvas->zoomToFeatureIds( mLayerCache->layer(), ids );
597  }
598 }
599 
600 void QgsDualView::panToCurrentFeature()
601 {
602  QModelIndex currentIndex = mTableView->currentIndex();
603  if ( !currentIndex.isValid() )
604  {
605  return;
606  }
607 
608  QgsFeatureIds ids;
609  ids.insert( mFilterModel->rowToId( currentIndex ) );
610  QgsMapCanvas* canvas = mFilterModel->mapCanvas();
611  if ( canvas )
612  {
613  canvas->panToFeatureIds( mLayerCache->layer(), ids );
614  }
615 }
616 
617 void QgsDualView::previewExpressionChanged( const QString& expression )
618 {
619  mLayerCache->layer()->setDisplayExpression( expression );
620 }
621 
622 void QgsDualView::onSortColumnChanged()
623 {
624  QgsAttributeTableConfig cfg = mLayerCache->layer()->attributeTableConfig();
625  cfg.setSortExpression( mFilterModel->sortExpression() );
626  cfg.setSortOrder( mFilterModel->sortOrder() );
628 }
629 
630 void QgsDualView::sortByPreviewExpression()
631 {
632  Qt::SortOrder sortOrder = Qt::AscendingOrder;
633  if ( mFeatureList->displayExpression() == sortExpression() )
634  {
635  sortOrder = mConfig.sortOrder() == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
636  }
637  setSortExpression( mFeatureList->displayExpression(), sortOrder );
638 }
639 
640 void QgsDualView::featureFormAttributeChanged()
641 {
642  mFeatureList->setCurrentFeatureEdited( true );
643 }
644 
646 {
647  mFilterModel->setFilteredFeatures( filteredFeatures );
648 }
649 
651 {
652  mMasterModel->setRequest( request );
653 }
654 
656 {
657  mTableView->setFeatureSelectionManager( featureSelectionManager );
658  mFeatureList->setFeatureSelectionManager( featureSelectionManager );
659 
660  if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == this )
661  delete mFeatureSelectionManager;
662 
663  mFeatureSelectionManager = featureSelectionManager;
664 }
665 
667 {
668  mLayerCache->layer()->setAttributeTableConfig( config );
669  mFilterModel->setAttributeTableConfig( config );
670  mTableView->setAttributeTableConfig( config );
671  mConfig = config;
672 }
673 
674 void QgsDualView::setSortExpression( const QString& sortExpression, Qt::SortOrder sortOrder )
675 {
676  if ( sortExpression.isNull() )
677  mFilterModel->sort( -1 );
678  else
679  mFilterModel->sort( sortExpression, sortOrder );
680 
681  mConfig.setSortExpression( sortExpression );
682  mConfig.setSortOrder( sortOrder );
683  setAttributeTableConfig( mConfig );
684 }
685 
687 {
688  return mFilterModel->sortExpression();
689 }
690 
691 void QgsDualView::progress( int i, bool& cancel )
692 {
693  if ( !mProgressDlg )
694  {
695  mProgressDlg = new QProgressDialog( tr( "Loading features..." ), tr( "Abort" ), 0, 0, this );
696  mProgressDlg->setWindowTitle( tr( "Attribute table" ) );
697  mProgressDlg->setWindowModality( Qt::WindowModal );
698  mProgressDlg->show();
699  }
700 
701  mProgressDlg->setLabelText( tr( "%1 features loaded." ).arg( i ) );
702  QCoreApplication::processEvents();
703 
704  cancel = mProgressDlg && mProgressDlg->wasCanceled();
705 }
706 
707 void QgsDualView::finished()
708 {
709  delete mProgressDlg;
710  mProgressDlg = nullptr;
711 }
712 
713 /*
714  * QgsAttributeTableAction
715  */
716 
718 {
719  mDualView->masterModel()->executeAction( mAction, mFieldIdx );
720 }
721 
723 {
724  QgsFeatureIds editedIds;
725  editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
726  mDualView->setCurrentEditSelection( editedIds );
727  mDualView->setView( QgsDualView::AttributeEditor );
728 }
729 
730 /*
731  * QgsAttributeTableMapLayerAction
732  */
733 
735 {
736  mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx );
737 }
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:289
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:140
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:53
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:156
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:247
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:348
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:53
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:136
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:74
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:66
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.
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:33
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:149
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:92
void loadFieldNames()
Loads all the field names from the layer.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:45
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:113
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:184
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:102
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.
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.