Skip to content

Commit 2cd4c1a

Browse files
committedApr 8, 2013
Merge pull request #508 from matthias-kuhn/dual-view-fixes
Dual view fixes
2 parents a150865 + 57c2307 commit 2cd4c1a

20 files changed

+2127
-119
lines changed
 

‎images/images.qrc‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,8 @@
545545
<file>themes/gis/mIconSelectAdd.svg</file>
546546
<file>themes/gis/mIconSelectIntersect.svg</file>
547547
<file>themes/gis/mIconSelectRemove.svg</file>
548+
<file>themes/gis/mIconSelected.svg</file>
549+
<file>themes/gis/mIconDeselected.svg</file>
548550
</qresource>
549551
<qresource prefix="/images/tips">
550552
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>

‎images/themes/gis/mIconDeselected.svg‎

Lines changed: 915 additions & 0 deletions
Loading

‎images/themes/gis/mIconSelected.svg‎

Lines changed: 915 additions & 0 deletions
Loading

‎src/app/qgsattributetabledialog.cpp‎

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
109109
connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( editingToggled() ) );
110110
connect( mLayer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) );
111111
connect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( close() ) );
112+
connect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateTitle() ) );
113+
connect( mLayer, SIGNAL( attributeAdded(int) ), this, SLOT( columnBoxInit() ) );
114+
connect( mLayer, SIGNAL( attributeDeleted(int) ), this, SLOT( columnBoxInit() ) );
115+
116+
// connect table info to window
117+
connect( mMainView, SIGNAL( filterChanged() ), this, SLOT( updateTitle() ) );
112118

113119
// info from table to application
114120
connect( this, SIGNAL( saveEdits( QgsMapLayer * ) ), QgisApp::instance(), SLOT( saveEdits( QgsMapLayer * ) ) );
@@ -193,12 +199,11 @@ QgsAttributeTableDialog::~QgsAttributeTableDialog()
193199
void QgsAttributeTableDialog::updateTitle()
194200
{
195201
QWidget *w = mDock ? qobject_cast<QWidget*>( mDock ) : qobject_cast<QWidget*>( this );
196-
w->setWindowTitle( tr( "Attribute table - %1 :: %n / %2 feature(s) filtered",
197-
"feature count",
198-
mMainView->filteredFeatureCount()
199-
)
202+
w->setWindowTitle( tr( "Attribute table - %1 :: Features total: %2, filtered: %3, selected: %4" )
200203
.arg( mLayer->name() )
201204
.arg( mMainView->featureCount() )
205+
.arg( mMainView->filteredFeatureCount() )
206+
.arg( mLayer->selectedFeatureCount() )
202207
);
203208
}
204209

@@ -219,6 +224,7 @@ void QgsAttributeTableDialog::columnBoxInit()
219224
{
220225
mFilterColumnsMenu->removeAction( a );
221226
mFilterActionMapper->removeMappings( a );
227+
mFilterButton->removeAction( a );
222228
delete a;
223229
}
224230

@@ -345,7 +351,6 @@ void QgsAttributeTableDialog::on_mOpenFieldCalculator_clicked()
345351
if ( col >= 0 )
346352
{
347353
masterModel->reload( masterModel->index( 0, col ), masterModel->index( masterModel->rowCount() - 1, col ) );
348-
columnBoxInit();
349354
}
350355
}
351356
}
@@ -610,14 +615,4 @@ void QgsAttributeTableDialog::setFilterExpression( QString filterString )
610615
QgisApp::instance()->messageBar()->pushMessage( tr( "Error filtering" ), filterExpression.evalErrorString(), QgsMessageBar::WARNING, QgisApp::instance()->messageTimeout() );
611616
return;
612617
}
613-
614-
QWidget *w = mDock ? qobject_cast<QWidget*>( mDock ) : qobject_cast<QWidget*>( this );
615-
if ( mMainView->filteredFeatureCount() )
616-
{
617-
w->setWindowTitle( tr( "Attribute table - %1 (%n matching features)", "matching features", mMainView->filteredFeatureCount() ).arg( mMainView->filteredFeatureCount() ) );
618-
}
619-
else
620-
{
621-
w->setWindowTitle( tr( "Attribute table - %1 (No matching features)" ).arg( mLayer->name() ) );
622-
}
623618
}

‎src/app/qgsattributetabledialog.h‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ class QgsAttributeTableDialog : public QDialog, private Ui::QgsAttributeTableDia
138138
void filterQueryChanged( const QString& query );
139139
void filterQueryAccepted();
140140

141+
/**
142+
* update window title
143+
*/
144+
void updateTitle();
145+
141146
signals:
142147
/**
143148
* Informs that editing mode has been toggled
@@ -158,17 +163,13 @@ class QgsAttributeTableDialog : public QDialog, private Ui::QgsAttributeTableDia
158163
*/
159164
void closeEvent( QCloseEvent* event );
160165

161-
private:
166+
private slots:
162167
/**
163168
* Initialize column box
164169
*/
165170
void columnBoxInit();
166171

167-
/**
168-
* update window title
169-
*/
170-
void updateTitle();
171-
172+
private:
172173
QMenu* mMenuActions;
173174
QAction* mActionToggleEditing;
174175

‎src/core/qgsvectorlayer.cpp‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,18 @@ bool QgsVectorLayer::readXml( const QDomNode& layer_node )
15111511
updateFields();
15121512
connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) );
15131513

1514+
QDomNode prevExpNode = layer_node.namedItem( "previewExpression" );
1515+
1516+
if( prevExpNode.isNull() )
1517+
{
1518+
mDisplayExpression = "";
1519+
}
1520+
else
1521+
{
1522+
QDomElement prevExpElem = prevExpNode.toElement();
1523+
mDisplayExpression = prevExpElem.text();
1524+
}
1525+
15141526
QString errorMsg;
15151527
if ( !readSymbology( layer_node, errorMsg ) )
15161528
{
@@ -1658,6 +1670,12 @@ bool QgsVectorLayer::writeXml( QDomNode & layer_node,
16581670
layer_node.appendChild( provider );
16591671
}
16601672

1673+
// save preview expression
1674+
QDomElement prevExpElem = document.createElement( "previewExpression" );
1675+
QDomText prevExpText = document.createTextNode( mDisplayExpression );
1676+
prevExpElem.appendChild( prevExpText );
1677+
layer_node.appendChild( prevExpElem );
1678+
16611679
//save joins
16621680
mJoinBuffer->writeXml( layer_node, document );
16631681

@@ -2790,6 +2808,16 @@ const QString QgsVectorLayer::displayField() const
27902808
return mDisplayField;
27912809
}
27922810

2811+
void QgsVectorLayer::setDisplayExpression( const QString displayExpression )
2812+
{
2813+
mDisplayExpression = displayExpression;
2814+
}
2815+
2816+
const QString QgsVectorLayer::displayExpression()
2817+
{
2818+
return mDisplayExpression;
2819+
}
2820+
27932821
bool QgsVectorLayer::isEditable() const
27942822
{
27952823
return ( mEditBuffer && mDataProvider );

‎src/core/qgsvectorlayer.h‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,24 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
257257
/** Returns the primary display field name used in the identify results dialog */
258258
const QString displayField() const;
259259

260+
/** Set the preview expression, used to create a human readable preview string.
261+
* Used e.g. in the attribute table feature list. Uses @link {QgsExpression}.
262+
*
263+
* @param previewExpression The expression which will be used to preview features
264+
* for this layer
265+
* @note added in 2.0
266+
*/
267+
void setDisplayExpression( const QString displayExpression );
268+
269+
/**
270+
* Get the preview expression, used to create a human readable preview string.
271+
* Uses @link {QgsExpression}.
272+
*
273+
* @return The expression which will be used to preview features for this layer
274+
* @note added in 2.0
275+
*/
276+
const QString displayExpression();
277+
260278
/** Returns the data provider */
261279
QgsVectorDataProvider* dataProvider();
262280

@@ -973,6 +991,9 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
973991
/** index of the primary label field */
974992
QString mDisplayField;
975993

994+
/** the preview expression used to generate a human readable preview string for features */
995+
QString mDisplayExpression;
996+
976997
/** Data provider key */
977998
QString mProviderKey;
978999

‎src/gui/attributetable/qgsattributetablefiltermodel.cpp‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ void QgsAttributeTableFilterModel::masterSelectionChanged( const QItemSelection
179179
}
180180

181181
// Now emit the signal
182-
layer()->setSelectedFeatures( layer()->selectedFeaturesIds() );
182+
if ( mSyncSelection )
183+
{
184+
layer()->setSelectedFeatures( layer()->selectedFeaturesIds() );
185+
}
183186

184187
connect( layer(), SIGNAL( selectionChanged() ), this, SLOT( selectionChanged() ) );
185188
}
@@ -321,6 +324,17 @@ QItemSelectionModel* QgsAttributeTableFilterModel::masterSelection()
321324
return mMasterSelection;
322325
}
323326

327+
void QgsAttributeTableFilterModel::disableSelectionSync()
328+
{
329+
mSyncSelection = false;
330+
}
331+
332+
void QgsAttributeTableFilterModel::enableSelectionSync()
333+
{
334+
mSyncSelection = true;
335+
layer()->setSelectedFeatures( layer()->selectedFeaturesIds() );
336+
}
337+
324338
QModelIndex QgsAttributeTableFilterModel::mapToMaster( const QModelIndex &proxyIndex ) const
325339
{
326340
// Master is source

‎src/gui/attributetable/qgsattributetablefiltermodel.h‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel
9191
*/
9292
inline QgsVectorLayer *layer() const { return masterModel()->layer(); }
9393

94+
/**
95+
* Returns the layerCache this filter acts on.
96+
*
97+
* @return The layer cache
98+
*/
9499
inline QgsVectorLayerCache *layerCache() const { return masterModel()->layerCache(); }
95100

96101
/**
@@ -120,6 +125,21 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel
120125
*/
121126
QItemSelectionModel* masterSelection();
122127

128+
/**
129+
* Disables selection synchronisation with the map canvas. Changes to the selection in the master
130+
* model are propagated to the layer, but no redraw is requested until @link{enableSelectionSync()}
131+
* is called.
132+
*/
133+
void disableSelectionSync();
134+
135+
/**
136+
* Enables selection synchronisation with the map canvas. Changes to the selection in the master
137+
* are propagated and upon every change, a redraw will be requested. This method will update the
138+
* selection to account for any cached selection change since @link{disableSelectionSync()} was
139+
* called.
140+
*/
141+
void enableSelectionSync();
142+
123143
virtual QModelIndex mapToMaster( const QModelIndex &proxyIndex ) const;
124144

125145
virtual QModelIndex mapFromMaster( const QModelIndex &sourceIndex ) const;
@@ -194,6 +214,7 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel
194214
bool mSelectedOnTop;
195215
QItemSelectionModel* mMasterSelection;
196216
QgsAttributeTableModel* mTableModel;
217+
bool mSyncSelection;
197218
};
198219

199220
#endif

‎src/gui/attributetable/qgsattributetablemodel.cpp‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ void QgsAttributeTableModel::layerDeleted()
188188

189189
void QgsAttributeTableModel::attributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value )
190190
{
191+
if ( fid == mFeat.id() )
192+
{
193+
mFeat.setValid( false );
194+
}
191195
setData( index( idToRow( fid ), fieldCol( idx ) ), value, Qt::EditRole );
192196
}
193197

@@ -469,7 +473,7 @@ QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) cons
469473
}
470474

471475
// if we don't have the row in current cache, load it from layer first
472-
if ( mFeat.id() != rowId )
476+
if ( mFeat.id() != rowId || !mFeat.isValid() )
473477
{
474478
if ( !loadFeatureAtId( rowId ) )
475479
return QVariant( "ERROR" );

‎src/gui/attributetable/qgsattributetableview.cpp‎

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ QgsAttributeTableView::QgsAttributeTableView( QWidget *parent )
4646
setSelectionMode( QAbstractItemView::ExtendedSelection );
4747
setSortingEnabled( true );
4848

49-
connect( verticalHeader(), SIGNAL( sectionClicked( int ) ), SLOT( onVerticalHeaderSectionClicked( int ) ) );
49+
verticalHeader()->viewport()->installEventFilter( this );
5050
}
5151

5252
QgsAttributeTableView::~QgsAttributeTableView()
@@ -75,6 +75,27 @@ void QgsAttributeTableView::setCanvasAndLayerCache( QgsMapCanvas *canvas, QgsVec
7575
delete filterModel;
7676
}
7777

78+
bool QgsAttributeTableView::eventFilter(QObject *object, QEvent *event)
79+
{
80+
if ( object == verticalHeader()->viewport() )
81+
{
82+
switch ( event->type() )
83+
{
84+
case QEvent::MouseButtonPress:
85+
mFilterModel->disableSelectionSync();
86+
break;
87+
88+
case QEvent::MouseButtonRelease:
89+
mFilterModel->enableSelectionSync();
90+
break;
91+
92+
default:
93+
break;
94+
}
95+
}
96+
return false;
97+
}
98+
7899
void QgsAttributeTableView::setModel( QgsAttributeTableFilterModel* filterModel )
79100
{
80101
if ( mFilterModel )
@@ -158,22 +179,6 @@ void QgsAttributeTableView::keyPressEvent( QKeyEvent *event )
158179
}
159180
}
160181

161-
void QgsAttributeTableView::onVerticalHeaderSectionClicked( int logicalIndex )
162-
{
163-
Q_UNUSED( logicalIndex )
164-
165-
QgsFeatureIds selectedFeatures;
166-
167-
QModelIndexList selectedRows = selectionModel()->selectedRows();
168-
169-
foreach ( QModelIndex row, selectedRows )
170-
{
171-
selectedFeatures.insert( mFilterModel->rowToId( row ) );
172-
}
173-
174-
emit selectionChangeFinished( selectedFeatures );
175-
}
176-
177182
void QgsAttributeTableView::onFilterAboutToBeInvalidated()
178183
{
179184
disconnect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SLOT( onSelectionChanged( QItemSelection, QItemSelection ) ) );

‎src/gui/attributetable/qgsattributetableview.h‎

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView
6363
*/
6464
void setCanvasAndLayerCache( QgsMapCanvas *canvas, QgsVectorLayerCache *layerCache );
6565

66+
/**
67+
* This event filter is installed on the verticalHeader to intercept mouse press and release
68+
* events. These are used to disable / enable live synchronisation with the map canvas selection
69+
* which can be slow due to recurring canvas repaints. Updating the
70+
*
71+
* @param object The object which is the target of the event.
72+
* @param event The intercepted event
73+
*
74+
* @return Returns always false, so the event gets processed
75+
*/
76+
virtual bool eventFilter( QObject* object, QEvent* event );
77+
6678
protected:
6779
/**
6880
* Called for mouse press events on a table cell.
@@ -124,23 +136,7 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView
124136

125137
void finished();
126138

127-
/**
128-
* @brief
129-
* Is emitted, after the selection has been changed.
130-
*
131-
* @param selectedFeatures A list of currently selected features.
132-
*/
133-
void selectionChangeFinished( const QgsFeatureIds &selectedFeatures );
134-
135139
public slots:
136-
/**
137-
* Is triggered after a mouse release event on the vertical header.
138-
* Emits a selectionChangeFinished() signal, so the underlying sort filter
139-
* can adapt to the current selection without disturbing the users current interaction.
140-
*
141-
* @param logicalIndex The section's logical index
142-
*/
143-
void onVerticalHeaderSectionClicked( int logicalIndex );
144140
void onFilterAboutToBeInvalidated();
145141
void onFilterInvalidated();
146142
void onSelectionChanged( const QItemSelection& selected, const QItemSelection& deselected );

‎src/gui/attributetable/qgsdualview.cpp‎

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ QgsDualView::QgsDualView( QWidget* parent )
4646
// Connect layer list preview signals
4747
connect( mActionExpressionPreview, SIGNAL( triggered() ), SLOT( previewExpressionBuilder() ) );
4848
connect( mPreviewActionMapper, SIGNAL( mapped( QObject* ) ), SLOT( previewColumnChanged( QObject* ) ) );
49+
connect( mFeatureList, SIGNAL( displayExpressionChanged(QString) ), this, SLOT( previewExpressionChanged(QString) ) );
4950
}
5051

5152
QgsDualView::~QgsDualView()
@@ -76,6 +77,54 @@ void QgsDualView::init( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, QgsDista
7677

7778
void QgsDualView::columnBoxInit()
7879
{
80+
// load fields
81+
QList<QgsField> fields = mLayerCache->layer()->pendingFields().toList();
82+
83+
// default expression: saved value
84+
QString displayExpression = mLayerCache->layer()->displayExpression();
85+
86+
// if no display expression is saved: use display field instead
87+
if ( displayExpression == "" )
88+
{
89+
displayExpression = mLayerCache->layer()->displayField();
90+
}
91+
92+
// if neither diaplay expression nor display field is saved...
93+
if ( displayExpression == "" )
94+
{
95+
QgsAttributeList pkAttrs = mLayerCache->layer()->pendingPkAttributesList();
96+
97+
if ( pkAttrs.size() > 0 )
98+
{
99+
// ... If there are primary key(s) defined
100+
QStringList pkFields;
101+
102+
foreach ( int attr, pkAttrs )
103+
{
104+
pkFields.append( "\"" + fields[attr].name() + "\"" );
105+
}
106+
107+
displayExpression = pkFields.join( "||', '||" );
108+
}
109+
else if ( fields.size() > 0 )
110+
{
111+
// ... concat all fields
112+
QStringList fieldNames;
113+
foreach ( QgsField field, fields )
114+
{
115+
fieldNames.append( "\"" + field.name() + "\"" );
116+
}
117+
118+
displayExpression = fieldNames.join( "||', '||" );
119+
}
120+
else
121+
{
122+
// ... there isn't really much to display
123+
displayExpression = "[Please define preview text]";
124+
}
125+
}
126+
127+
// now initialise the menu
79128
QList< QAction* > previewActions = mFeatureListPreviewButton->actions();
80129
foreach ( QAction* a, previewActions )
81130
{
@@ -89,8 +138,6 @@ void QgsDualView::columnBoxInit()
89138
mFeatureListPreviewButton->addAction( mActionExpressionPreview );
90139
mFeatureListPreviewButton->addAction( mActionPreviewColumnsMenu );
91140

92-
QList<QgsField> fields = mLayerCache->layer()->pendingFields().toList();
93-
94141
foreach ( const QgsField field, fields )
95142
{
96143
if ( mLayerCache->layer()->editType( mLayerCache->layer()->fieldNameIndex( field.name() ) ) != QgsVectorLayer::Hidden )
@@ -104,45 +151,18 @@ void QgsDualView::columnBoxInit()
104151
connect( previewAction, SIGNAL( triggered() ), mPreviewActionMapper, SLOT( map() ) );
105152
mPreviewColumnsMenu->addAction( previewAction );
106153

107-
if ( text == mLayerCache->layer()->displayField() )
154+
if ( text == displayExpression )
108155
{
109156
mFeatureListPreviewButton->setDefaultAction( previewAction );
110157
}
111158
}
112159
}
113160

114-
// Most likely no displayField is defined
115-
// Join primary key fields
161+
// If there is no single field found as preview
116162
if ( !mFeatureListPreviewButton->defaultAction() )
117163
{
164+
mFeatureList->setDisplayExpression( displayExpression );
118165
mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
119-
QgsAttributeList pkAttrs = mLayerCache->layer()->pendingPkAttributesList();
120-
// If there is a primary key defined
121-
if ( pkAttrs.size() > 0 )
122-
{
123-
QStringList pkFields;
124-
125-
foreach ( int attr, pkAttrs )
126-
{
127-
pkFields.append( "\"" + fields[attr].name() + "\"" );
128-
}
129-
130-
mFeatureList->setDisplayExpression( pkFields.join( "||', '||" ) );
131-
}
132-
else if ( fields.size() > 0 )
133-
{
134-
QStringList fieldNames;
135-
foreach ( QgsField field, fields )
136-
{
137-
fieldNames.append( "\"" + field.name() + "\"" );
138-
}
139-
140-
mFeatureList->setDisplayExpression( fieldNames.join( "||', '||" ) );
141-
}
142-
else
143-
{
144-
mFeatureList->setDisplayExpression( "[Please define preview text]" );
145-
}
146166
}
147167
else
148168
{
@@ -191,6 +211,10 @@ void QgsDualView::initModels( QgsMapCanvas* mapCanvas )
191211
mMasterModel->loadLayer();
192212

193213
mFilterModel = new QgsAttributeTableFilterModel( mapCanvas, mMasterModel, mMasterModel );
214+
215+
connect( mFilterModel, SIGNAL( filterInvalidated() ), this, SIGNAL( filterChanged() ) );
216+
connect( mFeatureList, SIGNAL( displayExpressionChanged(QString) ), this, SIGNAL( displayExpressionChanged(QString) ) );
217+
194218
mFeatureListModel = new QgsFeatureListModel( mFilterModel, mFilterModel );
195219
}
196220

@@ -272,9 +296,11 @@ void QgsDualView::previewColumnChanged( QObject* action )
272296
.arg( mFeatureList->parserErrorString() )
273297
);
274298
}
275-
276-
mFeatureListPreviewButton->setDefaultAction( previewAction );
277-
mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
299+
else
300+
{
301+
mFeatureListPreviewButton->setDefaultAction( previewAction );
302+
mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
303+
}
278304
}
279305

280306
Q_ASSERT( previewAction );
@@ -325,6 +351,11 @@ void QgsDualView::viewWillShowContextMenu( QMenu* menu, QModelIndex atIndex )
325351
menu->addAction( tr( "Open form" ), a, SLOT( featureForm() ) );
326352
}
327353

354+
void QgsDualView::previewExpressionChanged( const QString expression )
355+
{
356+
mLayerCache->layer()->setDisplayExpression( expression );
357+
}
358+
328359
void QgsDualView::setFilteredFeatures( QgsFeatureIds filteredFeatures )
329360
{
330361
mFilterModel->setFilteredFeatures( filteredFeatures );

‎src/gui/attributetable/qgsdualview.h‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
9898
void setCurrentEditSelection( const QgsFeatureIds& fids );
9999

100100
signals:
101+
/**
102+
* Is emitted, whenever the display expression is successfully changed
103+
* @param The expression that was applied
104+
*/
105+
void displayExpressionChanged( const QString expression );
106+
107+
/**
108+
* Is emitted, whenever the filter changes
109+
*/
110+
void filterChanged();
101111

102112
private slots:
103113
/**
@@ -113,6 +123,8 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
113123

114124
void viewWillShowContextMenu( QMenu* menu, QModelIndex atIndex );
115125

126+
void previewExpressionChanged( const QString expression );
127+
116128
/**
117129
* Will be called periodically, when loading layers from slow data providers.
118130
*

‎src/gui/attributetable/qgsfeaturelistmodel.cpp‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,13 @@ int QgsFeatureListModel::rowCount( const QModelIndex& parent ) const
238238
Q_UNUSED( parent )
239239
return sourceModel()->rowCount();
240240
}
241+
242+
void QgsFeatureListModel::disableSelectionSync()
243+
{
244+
mFilterModel->disableSelectionSync();
245+
}
246+
247+
void QgsFeatureListModel::enableSelectionSync()
248+
{
249+
mFilterModel->enableSelectionSync();
250+
}

‎src/gui/attributetable/qgsfeaturelistmodel.h‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,21 @@ class QgsFeatureListModel : public QAbstractProxyModel
8585
virtual int columnCount( const QModelIndex&parent = QModelIndex() ) const;
8686
virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
8787

88+
/**
89+
* Disables selection synchronisation with the map canvas. Changes to the selection in the master
90+
* model are propagated to the layer, but no redraw is requested until @link{enableSelectionSync()}
91+
* is called.
92+
*/
93+
void disableSelectionSync();
94+
95+
/**
96+
* Enables selection synchronisation with the map canvas. Changes to the selection in the master
97+
* are propagated and upon every change, a redraw will be requested. This method will update the
98+
* selection to account for any cached selection change since @link{disableSelectionSync()} was
99+
* called.
100+
*/
101+
void enableSelectionSync();
102+
88103
public slots:
89104
void onBeginRemoveRows( const QModelIndex& parent, int first, int last );
90105
void onEndRemoveRows( const QModelIndex& parent, int first, int last );

‎src/gui/attributetable/qgsfeaturelistview.cpp‎

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,15 @@ void QgsFeatureListView::setModel( QgsFeatureListModel* featureListModel )
7373

7474
bool QgsFeatureListView::setDisplayExpression( const QString expression )
7575
{
76-
return mModel->setDisplayExpression( expression );
76+
if ( mModel->setDisplayExpression( expression ) )
77+
{
78+
emit displayExpressionChanged( expression );
79+
return true;
80+
}
81+
else
82+
{
83+
return false;
84+
}
7785
}
7886

7987
const QString& QgsFeatureListView::displayExpression() const
@@ -106,7 +114,7 @@ void QgsFeatureListView::mousePressEvent( QMouseEvent *event )
106114
{
107115
QPoint pos = event->pos();
108116

109-
if ( QgsFeatureListViewDelegate::EditButtonElement == mItemDelegate->positionToElement( event->pos() ) )
117+
if ( QgsFeatureListViewDelegate::EditElement == mItemDelegate->positionToElement( event->pos() ) )
110118
{
111119
mEditSelectionDrag = true;
112120
QModelIndex index = mModel->mapToMaster( indexAt( pos ) );
@@ -115,15 +123,22 @@ void QgsFeatureListView::mousePressEvent( QMouseEvent *event )
115123
}
116124
else
117125
{
126+
mModel->disableSelectionSync();
118127
QListView::mousePressEvent( event );
119128
}
120129
}
121130

122131
void QgsFeatureListView::mouseReleaseEvent( QMouseEvent *event )
123132
{
124-
mEditSelectionDrag = false;
125-
126-
QListView::mouseReleaseEvent( event );
133+
if ( mEditSelectionDrag )
134+
{
135+
mEditSelectionDrag = false;
136+
}
137+
else
138+
{
139+
QListView::mouseReleaseEvent( event );
140+
mModel->enableSelectionSync();
141+
}
127142
}
128143

129144
void QgsFeatureListView::editSelectionChanged( QItemSelection deselected, QItemSelection selected )

‎src/gui/attributetable/qgsfeaturelistview.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ class GUI_EXPORT QgsFeatureListView : public QListView
111111
*/
112112
void currentEditSelectionChanged( QgsFeature &feat );
113113

114+
/**
115+
* Is emitted, whenever the display expression is successfully changed
116+
* @param The expression that was applied
117+
*/
118+
void displayExpressionChanged( const QString expression );
119+
114120
public slots:
115121
/**
116122
* Set the feature(s) to be edited

‎src/gui/attributetable/qgsfeaturelistviewdelegate.cpp‎

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ QgsFeatureListViewDelegate::QgsFeatureListViewDelegate( QgsFeatureListModel *lis
2020

2121
QgsFeatureListViewDelegate::Element QgsFeatureListViewDelegate::positionToElement( const QPoint &pos )
2222
{
23-
if ( pos.x() < sIconSize )
23+
if ( pos.x() > sIconSize )
2424
{
25-
return EditButtonElement;
25+
return EditElement;
2626
}
2727
else
2828
{
29-
return TextElement;
29+
return SelectionElement;
3030
}
3131
}
3232

@@ -45,46 +45,48 @@ void QgsFeatureListViewDelegate::paint( QPainter *painter, const QStyleOptionVie
4545
{
4646
QString text = index.model()->data( index, Qt::EditRole ).toString();
4747
QgsFeatureListModel::FeatureInfo featInfo = index.model()->data( index, Qt::UserRole ).value<QgsFeatureListModel::FeatureInfo>();
48+
bool isEdited = mEditSelectionModel->isSelected( mListModel->mapToMaster( index ) );
4849

49-
// Edit button state
50-
bool checked = mEditSelectionModel->isSelected( mListModel->mapToMaster( index ) );
50+
// Icon layout options
51+
QStyleOptionViewItem iconOption;
5152

52-
QStyleOptionButton pbn1Opts;
53+
QRect iconLayoutBounds( option.rect.x(), option.rect.y(), option.rect.height(), option.rect.height() );
5354

54-
pbn1Opts.iconSize = QSize( sIconSize, sIconSize );
55+
QPixmap icon;
5556

56-
pbn1Opts.state |= QStyle::State_Enabled;
57-
if ( checked )
57+
if ( option.state.testFlag( QStyle::State_Selected ) )
5858
{
59-
pbn1Opts.icon = QgsApplication::getThemeIcon( "/mIconEditableEdits.png" );
60-
pbn1Opts.state |= QStyle::State_On;
59+
// Item is selected
60+
icon = QgsApplication::getThemePixmap( "/mIconSelected.svg" );
6161
}
6262
else
6363
{
64-
pbn1Opts.icon = QgsApplication::getThemeIcon( "/mIconEditable.png" );
65-
pbn1Opts.state |= QStyle::State_Off;
64+
icon = QgsApplication::getThemePixmap( "/mIconDeselected.svg" );
6665
}
6766

68-
QRect pbn1Rect( option.rect.x(), option.rect.y(), option.rect.height(), option.rect.height() );
69-
pbn1Opts.rect = pbn1Rect;
67+
// Text layout options
68+
QRect textLayoutBounds( iconLayoutBounds.x() + iconLayoutBounds.width(), option.rect.y(), option.rect.width() - ( iconLayoutBounds.x() + iconLayoutBounds.width() ), option.rect.height() );
7069

71-
QApplication::style()->drawControl( QStyle::CE_PushButton, &pbn1Opts, painter );
72-
73-
QRect textLayoutBounds( pbn1Rect.x() + pbn1Rect.width(), option.rect.y(), option.rect.width() - ( pbn1Rect.x() + pbn1Rect.width() ), option.rect.height() );
74-
75-
QStyleOptionViewItem textOption = option;
70+
QStyleOptionViewItem textOption;
71+
textOption.state |= QStyle::State_Enabled;
72+
if ( isEdited )
73+
{
74+
textOption.state |= QStyle::State_Selected;
75+
}
7676

7777
if ( featInfo.isNew )
7878
{
7979
textOption.font.setStyle( QFont::StyleItalic );
8080
textOption.palette.setColor( QPalette::Text, Qt::darkGreen );
8181
textOption.palette.setColor( QPalette::HighlightedText, Qt::darkGreen );
8282
}
83-
else if ( featInfo.isEdited || checked )
83+
else if ( featInfo.isEdited || isEdited )
8484
{
8585
textOption.font.setStyle( QFont::StyleItalic );
8686
textOption.palette.setColor( QPalette::Text, Qt::red );
8787
textOption.palette.setColor( QPalette::HighlightedText, Qt::red );
8888
}
89+
8990
drawDisplay( painter, textOption, textLayoutBounds, text );
91+
drawDecoration( painter, iconOption, iconLayoutBounds, icon );
9092
}

‎src/gui/attributetable/qgsfeaturelistviewdelegate.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ class QgsFeatureListViewDelegate : public QItemDelegate
1919

2020
enum Element
2121
{
22-
EditButtonElement,
23-
TextElement
22+
EditElement,
23+
SelectionElement
2424
};
2525

2626
explicit QgsFeatureListViewDelegate( QgsFeatureListModel* listModel, QObject *parent = 0 );

0 commit comments

Comments
 (0)
Please sign in to comment.