QGIS API Documentation  2.17.0-Master (0497e4a)
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  setAttributeTableConfig( config );
528  }
529 }
530 
531 void QgsDualView::hideColumn()
532 {
533  QAction* action = qobject_cast<QAction*>( sender() );
534  int col = action->data().toInt();
535  QgsAttributeTableConfig config = mConfig;
536  int sourceCol = mConfig.mapVisibleColumnToIndex( col );
537  if ( sourceCol >= 0 )
538  {
539  config.setColumnHidden( sourceCol, true );
540  setAttributeTableConfig( config );
541  }
542 }
543 
544 void QgsDualView::resizeColumn()
545 {
546  QAction* action = qobject_cast<QAction*>( sender() );
547  int col = action->data().toInt();
548  if ( col < 0 )
549  return;
550 
551  QgsAttributeTableConfig config = mConfig;
552  int sourceCol = config.mapVisibleColumnToIndex( col );
553  if ( sourceCol >= 0 )
554  {
555  bool ok = false;
556  int width = QInputDialog::getInt( this, tr( "Set column width" ), tr( "Enter column width" ),
557  mTableView->columnWidth( col ),
558  0, 1000, 10, &ok );
559  if ( ok )
560  {
561  config.setColumnWidth( sourceCol, width );
562  setAttributeTableConfig( config );
563  }
564  }
565 }
566 
567 void QgsDualView::autosizeColumn()
568 {
569  QAction* action = qobject_cast<QAction*>( sender() );
570  int col = action->data().toInt();
571  mTableView->resizeColumnToContents( col );
572 }
573 
574 void QgsDualView::modifySort()
575 {
576  QgsVectorLayer* layer = mLayerCache->layer();
577  if ( !layer )
578  return;
579 
580  QgsAttributeTableConfig config = mConfig;
581 
582  QDialog orderByDlg;
583  orderByDlg.setWindowTitle( tr( "Configure attribute table sort order" ) );
584  QDialogButtonBox* dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
585  QGridLayout* layout = new QGridLayout();
586  connect( dialogButtonBox, SIGNAL( accepted() ), &orderByDlg, SLOT( accept() ) );
587  connect( dialogButtonBox, SIGNAL( rejected() ), &orderByDlg, SLOT( reject() ) );
588  orderByDlg.setLayout( layout );
589 
590  QGroupBox* sortingGroupBox = new QGroupBox();
591  sortingGroupBox->setTitle( tr( "Defined sort order in attribute table" ) );
592  sortingGroupBox->setCheckable( true );
593  sortingGroupBox->setChecked( !sortExpression().isEmpty() );
594  layout->addWidget( sortingGroupBox );
595  sortingGroupBox->setLayout( new QGridLayout() );
596 
597  QgsExpressionBuilderWidget* expressionBuilder = new QgsExpressionBuilderWidget();
598  QgsExpressionContext context;
602  expressionBuilder->setExpressionContext( context );
603  expressionBuilder->setLayer( layer );
604  expressionBuilder->loadFieldNames();
605  expressionBuilder->loadRecent( "generic" );
606  expressionBuilder->setExpressionText( sortExpression().isEmpty() ? layer->displayExpression() : sortExpression() );
607 
608  sortingGroupBox->layout()->addWidget( expressionBuilder );
609 
610  QCheckBox* cbxSortAscending = new QCheckBox( tr( "Sort ascending" ) );
611  cbxSortAscending->setChecked( config.sortOrder() == Qt::AscendingOrder );
612  sortingGroupBox->layout()->addWidget( cbxSortAscending );
613 
614  layout->addWidget( dialogButtonBox );
615  if ( orderByDlg.exec() )
616  {
617  Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
618  if ( sortingGroupBox->isChecked() )
619  {
620  setSortExpression( expressionBuilder->expressionText(), sortOrder );
621  config.setSortExpression( expressionBuilder->expressionText() );
622  config.setSortOrder( sortOrder );
623  }
624  else
625  {
626  setSortExpression( QString(), sortOrder );
627  config.setSortExpression( QString() );
628  }
629 
630  setAttributeTableConfig( config );
631  }
632 }
633 
634 void QgsDualView::zoomToCurrentFeature()
635 {
636  QModelIndex currentIndex = mTableView->currentIndex();
637  if ( !currentIndex.isValid() )
638  {
639  return;
640  }
641 
642  QgsFeatureIds ids;
643  ids.insert( mFilterModel->rowToId( currentIndex ) );
644  QgsMapCanvas* canvas = mFilterModel->mapCanvas();
645  if ( canvas )
646  {
647  canvas->zoomToFeatureIds( mLayerCache->layer(), ids );
648  }
649 }
650 
651 void QgsDualView::previewExpressionChanged( const QString& expression )
652 {
653  mLayerCache->layer()->setDisplayExpression( expression );
654 }
655 
656 void QgsDualView::onSortColumnChanged()
657 {
658  QgsAttributeTableConfig cfg = mLayerCache->layer()->attributeTableConfig();
659  cfg.setSortExpression( mFilterModel->sortExpression() );
660  cfg.setSortOrder( mFilterModel->sortOrder() );
662 }
663 
664 void QgsDualView::sortByPreviewExpression()
665 {
666  Qt::SortOrder sortOrder = Qt::AscendingOrder;
667  if ( mFeatureList->displayExpression() == sortExpression() )
668  {
669  sortOrder = mConfig.sortOrder() == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
670  }
671  setSortExpression( mFeatureList->displayExpression(), sortOrder );
672 }
673 
674 void QgsDualView::featureFormAttributeChanged()
675 {
676  mFeatureList->setCurrentFeatureEdited( true );
677 }
678 
680 {
681  mFilterModel->setFilteredFeatures( filteredFeatures );
682 }
683 
685 {
686  mMasterModel->setRequest( request );
687 }
688 
690 {
691  mTableView->setFeatureSelectionManager( featureSelectionManager );
692  mFeatureList->setFeatureSelectionManager( featureSelectionManager );
693 
694  if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == this )
695  delete mFeatureSelectionManager;
696 
697  mFeatureSelectionManager = featureSelectionManager;
698 }
699 
701 {
702  mLayerCache->layer()->setAttributeTableConfig( config );
703  mFilterModel->setAttributeTableConfig( config );
704  mTableView->setAttributeTableConfig( config );
705  mConfig = config;
706 }
707 
708 void QgsDualView::setSortExpression( const QString& sortExpression, Qt::SortOrder sortOrder )
709 {
710  if ( sortExpression.isNull() )
711  mFilterModel->sort( -1 );
712  else
713  mFilterModel->sort( sortExpression, sortOrder );
714 
715  mConfig.setSortExpression( sortExpression );
716  mConfig.setSortOrder( sortOrder );
717  setAttributeTableConfig( mConfig );
718 }
719 
721 {
722  return mFilterModel->sortExpression();
723 }
724 
725 void QgsDualView::progress( int i, bool& cancel )
726 {
727  if ( !mProgressDlg )
728  {
729  mProgressDlg = new QProgressDialog( tr( "Loading features..." ), tr( "Abort" ), 0, 0, this );
730  mProgressDlg->setWindowTitle( tr( "Attribute table" ) );
731  mProgressDlg->setWindowModality( Qt::WindowModal );
732  mProgressDlg->show();
733  }
734 
735  mProgressDlg->setValue( i );
736  mProgressDlg->setLabelText( tr( "%1 features loaded." ).arg( i ) );
737 
739 
740  cancel = mProgressDlg && mProgressDlg->wasCanceled();
741 }
742 
743 void QgsDualView::finished()
744 {
745  delete mProgressDlg;
746  mProgressDlg = nullptr;
747 }
748 
749 /*
750  * QgsAttributeTableAction
751  */
752 
754 {
755  mDualView->masterModel()->executeAction( mAction, mFieldIdx );
756 }
757 
759 {
760  QgsFeatureIds editedIds;
761  editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
762  mDualView->setCurrentEditSelection( editedIds );
763  mDualView->setView( QgsDualView::AttributeEditor );
764 }
765 
766 /*
767  * QgsAttributeTableMapLayerAction
768  */
769 
771 {
772  mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx );
773 }
QLayout * layout() const
void customContextMenuRequested(const QPoint &pos)
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.
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.
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...
QgsFeatureId idxToFid(const QModelIndex &index) const
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.
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 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()
void setWindowModality(Qt::WindowModality windowModality)
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:529
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:439
QString sortExpression() const
Get the expression used for sorting the table and feature list.
This class contains context information for attribute editor widgets.
QObject * sender() const
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)
T value() const
int exec()
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
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
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.
const QgsRectangle & filterRect() const
Get the rectangle from which features will be taken.
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
const QgsAction & at(int idx) const
Get the action at the specified index.
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
QgsEditFormConfig * editFormConfig() const
Get the configuration of the form used to represent this vector layer.
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: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
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 copyCellContent() const
Copy the content of the selected cell in the clipboard.
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.
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.
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:25
bool isEmpty() const
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool isEmpty() const
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
bool runable() const
Checks if the action is runable on the current platform.
Definition: qgsaction.cpp:19
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:97
void loadFieldNames()
Loads all the field names from the layer.
QGis::GeometryType geometryType() const
Returns point, line or polygon.
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.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities Note, some capabilities may change depending ...
void addWidget(QWidget *w)
QgsAttributeList pkAttributeList() const
Returns list of attributes making up the primary key.
QString displayField() const
Returns the primary display field name used in the identify results dialog.
void setData(const QVariant &userData)
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context for the widget.
iterator end()
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
void setWidgetResizable(bool resizable)
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
void setChecked(bool)
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.
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.
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 &)
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfield.cpp:466
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.
QString expressionText()
Gets the expression string that has been set in the expression area.
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, const QgsMapLayerAction::Targets &targets=QgsMapLayerAction::AllActions)
Returns the map layer actions which can run on the specified layer.
void formModeChanged(QgsAttributeForm::Mode mode)
Emitted when the form changes mode.
void setExpressionText(const QString &expression)
Sets the expression string for the widget.
bool isValid() const
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.
Qt::SortOrder sortOrder() const
Get the sort order.
QString widgetType(int fieldIdx) const
Get the id for the editor widget used to represent the field at the given index.
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.
QObject * parent() const
QString displayExpression() const
Get the preview expression, used to create a human readable preview string.
Represents a vector layer which manages a vector based data sets.
int size() const
Get the number of actions managed by this.
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)
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
void columnBoxInit()
Initializes widgets which depend on the attributes of this layer.
int featureCount()
Returns the number of features on the layer.