2 changes: 1 addition & 1 deletion src/core/qgsrelation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ QgsRelation QgsRelation::createFromXML( const QDomNode &node )
relation.addFieldPair( referencingField, referencedField );
}

relation.mValid = true;
relation.updateRelationStatus();

return relation;
}
Expand Down
88 changes: 62 additions & 26 deletions src/gui/attributetable/qgsdualview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ QgsDualView::QgsDualView( QWidget* parent )
, mEditorContext()
, mMasterModel( NULL )
, mAttributeDialog( NULL )
, mLayerCache( NULL )
, mProgressDlg( NULL )
, mFeatureSelectionManager( NULL )
{
Expand Down Expand Up @@ -190,14 +191,14 @@ void QgsDualView::columnBoxInit()

void QgsDualView::hideEvent( QHideEvent* event )
{
saveEditChanges();
QStackedWidget::hideEvent( event );
if ( saveEditChanges() )
QStackedWidget::hideEvent( event );
}

void QgsDualView::focusOutEvent( QFocusEvent* event )
{
saveEditChanges();
QStackedWidget::focusOutEvent( event );
if ( saveEditChanges() )
QStackedWidget::focusOutEvent( event );
}

void QgsDualView::setView( QgsDualView::ViewMode view )
Expand Down Expand Up @@ -257,35 +258,52 @@ void QgsDualView::initModels( QgsMapCanvas* mapCanvas, const QgsFeatureRequest&

void QgsDualView::on_mFeatureList_currentEditSelectionChanged( const QgsFeature &feat )
{
// Invalid feature? Strange: bail out
if ( !feat.isValid() )
return;

// We already show the feature in question: bail out
if ( mAttributeDialog && mAttributeDialog->feature()
&& mAttributeDialog->feature()->id() == feat.id() )
return;

bool dontChange = false;

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

if ( mAttributeDialog && mAttributeDialog->dialog() )
{
saveEditChanges();
mAttributeEditorLayout->removeWidget( mAttributeDialog->dialog() );
if ( saveEditChanges() )
mAttributeEditorLayout->removeWidget( mAttributeDialog->dialog() );
else
dontChange = true;
}

mAttributeDialog = new QgsAttributeDialog( mLayerCache->layer(), new QgsFeature( feat ), true, this, false, mEditorContext );
mAttributeEditorLayout->addWidget( mAttributeDialog->dialog() );
mAttributeDialog->dialog()->setVisible( true );
if ( !dontChange )
{
mAttributeDialog = new QgsAttributeDialog( mLayerCache->layer(), new QgsFeature( feat ), true, this, false, mEditorContext );
mAttributeEditorLayout->addWidget( mAttributeDialog->dialog() );
mAttributeDialog->dialog()->setVisible( true );

delete oldDialog;
delete oldDialog;
}
else
{
setCurrentEditSelection( QgsFeatureIds() << oldDialog->feature()->id() );
}
}

void QgsDualView::setCurrentEditSelection( const QgsFeatureIds& fids )
{
mFeatureList->setEditSelection( fids );
}

void QgsDualView::saveEditChanges()
bool QgsDualView::saveEditChanges()
{
if ( mAttributeDialog && mAttributeDialog->dialog() )
{
if ( mLayerCache->layer() && mLayerCache->layer()->isEditable() )
if ( mAttributeDialog->editable() )
{
// Get the current (unedited) feature
QgsFeature srcFeat;
Expand All @@ -294,29 +312,47 @@ void QgsDualView::saveEditChanges()
QgsAttributes src = srcFeat.attributes();

// Let the dialog write the edited widget values to it's feature
mAttributeDialog->accept();
// Get the edited feature
const QgsAttributes &dst = mAttributeDialog->feature()->attributes();

if ( src.count() != dst.count() )
QDialogButtonBox* buttonBox = mAttributeDialog->dialog()->findChild<QDialogButtonBox*>();
if ( buttonBox && buttonBox->button( QDialogButtonBox::Ok ) )
{
// bail out
return;
QPushButton* okBtn = buttonBox->button( QDialogButtonBox::Ok );
okBtn->click();
}
else
{
mAttributeDialog->accept();
}

mLayerCache->layer()->beginEditCommand( tr( "Attributes changed" ) );

for ( int i = 0; i < dst.count(); ++i )
if ( mAttributeDialog->dialog()->result() == QDialog::Accepted )
{
if ( dst[i] != src[i] )
// Get the edited feature
const QgsAttributes &dst = mAttributeDialog->feature()->attributes();

if ( src.count() != dst.count() )
{
mLayerCache->layer()->changeAttributeValue( fid, i, dst[i] );
// bail out
return false;
}
}

mLayerCache->layer()->endEditCommand();
mLayerCache->layer()->beginEditCommand( tr( "Attributes changed" ) );

for ( int i = 0; i < dst.count(); ++i )
{
if ( dst[i] != src[i] )
{
mLayerCache->layer()->changeAttributeValue( fid, i, dst[i] );
}
}

mLayerCache->layer()->endEditCommand();
}
else
{
return false;
}
}
}
return true;
}

void QgsDualView::previewExpressionBuilder()
Expand Down
5 changes: 4 additions & 1 deletion src/gui/attributetable/qgsdualview.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,11 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas

/**
* @brief saveEditChanges
*
* @return true if the saving was ok. false is possible due to connected
* validation logic.
*/
void saveEditChanges();
bool saveEditChanges();

/**
* Update the shown feature if an attribute changed
Expand Down
10 changes: 10 additions & 0 deletions src/gui/attributetable/qgsfeaturelistview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ QString QgsFeatureListView::parserErrorString()
return mModel->parserErrorString();
}

QgsFeatureIds QgsFeatureListView::currentEditSelection()
{
QgsFeatureIds selection;
Q_FOREACH( QModelIndex idx, mCurrentEditSelectionModel->selectedIndexes() )
{
selection << idx.data( QgsAttributeTableModel::FeatureIdRole ).value<QgsFeatureId>();
}
return selection;
}

void QgsFeatureListView::mousePressEvent( QMouseEvent *event )
{
QPoint pos = event->pos();
Expand Down
7 changes: 7 additions & 0 deletions src/gui/attributetable/qgsfeaturelistview.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ class GUI_EXPORT QgsFeatureListView : public QListView
*/
QString parserErrorString();

/**
* Get the currentEditSelection
*
* @return A list of edited feature ids
*/
QgsFeatureIds currentEditSelection();

protected:
virtual void mouseMoveEvent( QMouseEvent *event );
virtual void mousePressEvent( QMouseEvent *event );
Expand Down
106 changes: 70 additions & 36 deletions src/gui/qgsattributedialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,8 @@ void QgsAttributeDialog::init()

foreach ( const QgsRelation& relation, relations )
{
relation.id();

QWidget *myWidget = QgsRelationEditorWidget::createRelationEditor( relation, *mFeature, mContext );
QWidget *myWidget = new QWidget();
myWidget->setProperty( "qgisRelation", relation.id() );
myWidget->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
if ( !myWidget )
continue;
Expand Down Expand Up @@ -303,48 +302,71 @@ void QgsAttributeDialog::init()
myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() );
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
#endif
for ( int fldIdx = 0; fldIdx < theFields.count(); ++fldIdx )
{
QList<QWidget *> myWidgets = mDialog->findChildren<QWidget*>( theFields[fldIdx].name() );
if ( myWidgets.isEmpty() )
continue;

foreach ( QWidget *myWidget, myWidgets )
// Get all widgets on the dialog
QList<QWidget *> myWidgets = mDialog->findChildren<QWidget*>();
Q_FOREACH( QWidget* myWidget, myWidgets )
{
// Check the widget's properties for a relation definition
QVariant vRel = myWidget->property( "qgisRelation" );
if ( vRel.isValid() )
{
QgsAttributeEditor::createAttributeEditor( mDialog, myWidget, mLayer, fldIdx, mFeature->attribute( fldIdx ), mContext );

if ( mLayer->editType( fldIdx ) != QgsVectorLayer::Immutable )
QgsRelationManager* relMgr = QgsProject::instance()->relationManager();
QgsRelation relation = relMgr->relation( vRel.toString() );
if ( relation.isValid() )
{
if ( mLayer->isEditable() && mLayer->fieldEditable( fldIdx ) )
{
myWidget->setEnabled( true );
}
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::Photo )
QgsRelationEditorWidget *relWdg = QgsRelationEditorWidget::createRelationEditor( relation, *mFeature, mContext, myWidget );
if ( !myWidget->layout() )
{
foreach ( QWidget *w, myWidget->findChildren<QWidget *>() )
{
w->setEnabled( qobject_cast<QLabel *>( w ) ? true : false );
}
}
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::WebView )
{
foreach ( QWidget *w, myWidget->findChildren<QWidget *>() )
{
w->setEnabled( qobject_cast<QWebView *>( w ) ? true : false );
}
myWidget->setLayout( new QHBoxLayout() );
}
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::EditorWidgetV2 )
myWidget->layout()->addWidget( relWdg );
}
}
else
{
// No widget definition properties defined, check if the widget's
// objectName matches a field name
for ( int fldIdx = 0; fldIdx < theFields.count(); ++fldIdx )
{
if ( myWidget->objectName() == theFields[fldIdx].name() )
{
QgsEditorWidgetWrapper* ww = QgsEditorWidgetWrapper::fromWidget( myWidget );
if ( ww )
QgsAttributeEditor::createAttributeEditor( mDialog, myWidget, mLayer, fldIdx, mFeature->attribute( fldIdx ), mContext );

if ( mLayer->editType( fldIdx ) != QgsVectorLayer::Immutable )
{
ww->setEnabled( false );
if ( mLayer->isEditable() && mLayer->fieldEditable( fldIdx ) )
{
myWidget->setEnabled( true );
}
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::Photo )
{
foreach ( QWidget *w, myWidget->findChildren<QWidget *>() )
{
w->setEnabled( qobject_cast<QLabel *>( w ) ? true : false );
}
}
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::WebView )
{
foreach ( QWidget *w, myWidget->findChildren<QWidget *>() )
{
w->setEnabled( qobject_cast<QWebView *>( w ) ? true : false );
}
}
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::EditorWidgetV2 )
{
QgsEditorWidgetWrapper* ww = QgsEditorWidgetWrapper::fromWidget( myWidget );
if ( ww )
{
ww->setEnabled( false );
}
}
else
{
myWidget->setEnabled( false );
}
}
}
else
{
myWidget->setEnabled( false );
}
}
}
}
Expand Down Expand Up @@ -396,6 +418,8 @@ void QgsAttributeDialog::init()
}
}

mEditable = mLayer->isEditable();

if ( mDialog )
{
if ( mDialog->objectName().isEmpty() )
Expand Down Expand Up @@ -429,6 +453,16 @@ void QgsAttributeDialog::init()
{
if ( buttonBox )
{
// Add dummy buttons
if ( mLayer->isEditable() )
{
buttonBox->clear();

buttonBox->setStandardButtons( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
connect( buttonBox, SIGNAL( accepted() ), mDialog, SLOT( accept() ) );
connect( buttonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
}

buttonBox->setVisible( false );
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/gui/qgsattributedialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ class GUI_EXPORT QgsAttributeDialog : public QObject

QgsFeature* feature() { return mFeature; }

/**
* Is this dialog editable?
*
* @return returns true, if this dialog was created in an editable manner.
*/
bool editable() { return mEditable; }

public slots:
void accept();

Expand All @@ -106,6 +113,9 @@ class GUI_EXPORT QgsAttributeDialog : public QObject
bool mShowDialogButtons;
QString mReturnvarname;

// true if this dialog is editable
bool mEditable;

static int sFormCounter;
static QString sSettingsPath;
};
Expand Down