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