Skip to content
Permalink
Browse files

[dualview] Fix add/delete crash and fieldcalc behavior of feature form

  • Loading branch information
m-kuhn committed Sep 2, 2013
1 parent ff05ee0 commit a6b52b78671dbc1ea51f456e2074f8a0a4babbd7
@@ -360,6 +360,7 @@ void QgsAttributeTableDialog::on_mOpenFieldCalculator_clicked()
if ( col >= 0 )
{
masterModel->reload( masterModel->index( 0, col ), masterModel->index( masterModel->rowCount() - 1, col ) );
mMainView->reloadAttribute( col );
}
}
}
@@ -35,7 +35,7 @@ QgsVectorLayerCache::QgsVectorLayerCache( QgsVectorLayer* layer, int cacheSize,

connect( mLayer, SIGNAL( attributeDeleted( int ) ), SLOT( attributeDeleted( int ) ) );
connect( mLayer, SIGNAL( updatedFields() ), SLOT( updatedFields() ) );
connect( mLayer, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ) );
connect( mLayer, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), SLOT( onAttributeValueChanged( QgsFeatureId, int, const QVariant& ) ) );
}

void QgsVectorLayerCache::setCacheSize( int cacheSize )
@@ -183,14 +183,16 @@ void QgsVectorLayerCache::featureRemoved( QgsFeatureId fid )
}
}

void QgsVectorLayerCache::attributeValueChanged( QgsFeatureId fid, int field, const QVariant& value )
void QgsVectorLayerCache::onAttributeValueChanged( QgsFeatureId fid, int field, const QVariant& value )
{
QgsCachedFeature* cachedFeat = mCache[ fid ];

if ( NULL != cachedFeat )
{
cachedFeat->mFeature->setAttribute( field, value );
}

emit attributeValueChanged( fid, field, value );
}

void QgsVectorLayerCache::featureDeleted( QgsFeatureId fid )
@@ -236,8 +236,14 @@ class CORE_EXPORT QgsVectorLayerCache : public QObject
*/
void cachedLayerDeleted();

/**
* @brief Is emitted when an attribute is changed. Is re-emitted after the layer itself emits this signal.
* You should connect to this signal, to be sure, to not get a cached value if querying the cache.
*/
void attributeValueChanged( const QgsFeatureId& fid, const int& field, const QVariant &value );

private slots:
void attributeValueChanged( QgsFeatureId fid, int field, const QVariant& value );
void onAttributeValueChanged( QgsFeatureId fid, int field, const QVariant& value );
void featureDeleted( QgsFeatureId fid );
void featureAdded( QgsFeatureId fid );
void attributeAdded( int field );
@@ -62,12 +62,6 @@ void QgsDualView::init( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, QgsDista

connect( mTableView, SIGNAL( willShowContextMenu( QMenu*, QModelIndex ) ), this, SLOT( viewWillShowContextMenu( QMenu*, QModelIndex ) ) );

connect( layer, SIGNAL( editingStarted() ), this, SLOT( editingToggled() ) );
connect( layer, SIGNAL( beforeCommitChanges() ), this, SLOT( editingToggled() ) );
connect( layer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) );
connect( layer, SIGNAL( attributeAdded( int ) ), this, SLOT( editingToggled() ) );
connect( layer, SIGNAL( attributeDeleted( int ) ), this, SLOT( editingToggled() ) );

initLayerCache( layer );
initModels( mapCanvas );

@@ -218,7 +212,12 @@ void QgsDualView::initLayerCache( QgsVectorLayer* layer )
mLayerCache->setFullCache( true );
}

connect( layer, SIGNAL( editingStarted() ), this, SLOT( editingToggled() ) );
connect( layer, SIGNAL( beforeCommitChanges() ), this, SLOT( editingToggled() ) );
connect( layer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) );
connect( layer, SIGNAL( attributeAdded( int ) ), this, SLOT( attributeAdded( int ) ) );
connect( layer, SIGNAL( attributeDeleted( int ) ), this, SLOT( attributeDeleted( int ) ) );
connect( mLayerCache, SIGNAL( attributeValueChanged( QgsFeatureId, int, QVariant ) ), this, SLOT( onAttributeValueChanged( QgsFeatureId, int, QVariant ) ) );
}

void QgsDualView::initModels( QgsMapCanvas* mapCanvas )
@@ -237,7 +236,7 @@ void QgsDualView::initModels( QgsMapCanvas* mapCanvas )
mFeatureListModel = new QgsFeatureListModel( mFilterModel, mFilterModel );
}

void QgsDualView::on_mFeatureList_currentEditSelectionChanged( QgsFeature &feat )
void QgsDualView::on_mFeatureList_currentEditSelectionChanged( const QgsFeature &feat )
{
if ( !feat.isValid() )
return;
@@ -251,9 +250,6 @@ void QgsDualView::on_mFeatureList_currentEditSelectionChanged( QgsFeature &feat
mAttributeEditorLayout->removeWidget( mAttributeDialog->dialog() );
}

if ( feat.attributes().count() != mLayerCache->layer()->pendingFields().count() )
mLayerCache->featureAtId( feat.id(), feat );

mAttributeDialog = new QgsAttributeDialog( mLayerCache->layer(), new QgsFeature( feat ), true, mDistanceArea, this, false );
mAttributeEditorLayout->addWidget( mAttributeDialog->dialog() );
mAttributeDialog->dialog()->setVisible( true );
@@ -410,6 +406,74 @@ void QgsDualView::attributeDeleted( int attribute )
}
}

void QgsDualView::attributeAdded( int attribute )
{
if ( mAttributeDialog && mAttributeDialog->dialog() )
{
// Let the dialog write the edited widget values to it's feature
mAttributeDialog->accept();
// Get the edited feature
QgsFeature* feat = mAttributeDialog->feature();

// Get the feature including the newly added attribute
QgsFeature newFeat;
mLayerCache->featureAtId( feat->id(), newFeat );

int offset = 0;
for ( int idx = 0; idx < newFeat.attributes().count(); ++idx )
{
if ( idx == attribute )
{
offset = 1;
}
else
{
newFeat.setAttribute( idx, feat->attribute( idx - offset ) );
}
}

*feat = newFeat;

// Backup old dialog and delete only after creating the new dialog, so we can "hot-swap" the contained QgsFeature
QgsAttributeDialog* oldDialog = mAttributeDialog;

mAttributeEditorLayout->removeWidget( mAttributeDialog->dialog() );

mAttributeDialog = new QgsAttributeDialog( mLayerCache->layer(), new QgsFeature( *feat ), true, mDistanceArea, this, false );
mAttributeEditorLayout->addWidget( mAttributeDialog->dialog() );

delete oldDialog;
}
}

void QgsDualView::reloadAttribute( const int& idx )
{
if ( mAttributeDialog && mAttributeDialog->dialog() )
{
// Let the dialog write the edited widget values to it's feature
mAttributeDialog->accept();
// Get the edited feature
QgsFeature* feat = mAttributeDialog->feature();

// Get the feature including the changed attribute
QgsFeature newFeat;
mLayerCache->featureAtId( feat->id(), newFeat );

// Update the attribute
feat->setAttribute( idx, newFeat.attribute( idx ) );

// Backup old dialog and delete only after creating the new dialog, so we can "hot-swap" the contained QgsFeature
QgsAttributeDialog* oldDialog = mAttributeDialog;

mAttributeEditorLayout->removeWidget( mAttributeDialog->dialog() );

mAttributeDialog = new QgsAttributeDialog( mLayerCache->layer(), new QgsFeature( *feat ), true, mDistanceArea, this, false );
mAttributeEditorLayout->addWidget( mAttributeDialog->dialog() );

delete oldDialog;
}
}

void QgsDualView::setFilteredFeatures( QgsFeatureIds filteredFeatures )
{
mFilterModel->setFilteredFeatures( filteredFeatures );
@@ -150,9 +150,14 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
/**
* @brief saveEditChanges
*/

void saveEditChanges();

/**
* Update the shown feature if an attribute changed
*/
void reloadAttribute( const int& attribute );


signals:
/**
* Is emitted, whenever the display expression is successfully changed
@@ -171,7 +176,7 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
*
* @param feat The newly visible feature
*/
void on_mFeatureList_currentEditSelectionChanged( QgsFeature& feat );
void on_mFeatureList_currentEditSelectionChanged( const QgsFeature& feat );

void previewExpressionBuilder();

@@ -192,6 +197,15 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
*/
void attributeDeleted( int attribute );

/**
* If an attribute on this layer is added, add the field also for open
* attribute dialogs.
* (as long as the attribute dialog is not able to handle this problem)
*
* @param attribute The attribute being added
*/
void attributeAdded( int attribute );

/**
* Will be called periodically, when loading layers from slow data providers.
*

0 comments on commit a6b52b7

Please sign in to comment.
You can’t perform that action at this time.