Skip to content

Commit

Permalink
Move addFeature, startEditing and stopEditing vector layer actions
Browse files Browse the repository at this point in the history
to an abstract base class QgsVectorLayerTools in the gui library,
so these can be reimplemented for a custom app, but can also be used
from plugins or in the gui library.
  • Loading branch information
m-kuhn committed Oct 7, 2013
1 parent 331f71a commit fb32966
Show file tree
Hide file tree
Showing 14 changed files with 372 additions and 12 deletions.
1 change: 1 addition & 0 deletions python/gui/gui.sip
Expand Up @@ -69,6 +69,7 @@
%Include qgssearchquerybuilder.sip
%Include qgstextannotationitem.sip
%Include qgsvertexmarker.sip
%Include qgsvectorlayertools.sip
%Include qgssublayersdialog.sip
%Include qgscharacterselectdialog.sip
%Include qgscomposerruler.sip
Expand Down
2 changes: 2 additions & 0 deletions python/gui/qgisinterface.sip
Expand Up @@ -484,6 +484,8 @@ class QgisInterface : QObject

virtual QDialog* getFeatureForm( QgsVectorLayer *l, QgsFeature &f ) = 0;

virtual QgsVectorLayerTools* vectorLayerTools() = 0;

virtual void preloadForm( QString uifile ) = 0;

/** Return vector layers in edit mode
Expand Down
10 changes: 10 additions & 0 deletions python/gui/qgsvectorlayertools.sip
@@ -0,0 +1,10 @@
class QgsVectorLayerTools
{
%TypeHeaderCode
#include <qgsvectorlayertools.h>
%End
public:
virtual bool addFeature( QgsVectorLayer* layer, QgsAttributeMap defaultValues = QgsAttributeMap(), const QgsGeometry& = QgsGeometry() ) = 0;
virtual bool startEditing( QgsVectorLayer* layer ) = 0;
virtual bool stopEditing( QgsVectorLayer* layer, bool allowCancel = true ) = 0;
};
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -43,6 +43,7 @@ SET(QGIS_APP_SRCS
qgslabelpreview.cpp
qgsloadstylefromdbdialog.cpp
qgssavestyletodbdialog.cpp
qgsguivectorlayertools.cpp

qgsmaptooladdfeature.cpp
qgsmaptooladdpart.cpp
Expand Down Expand Up @@ -99,6 +100,7 @@ SET(QGIS_APP_SRCS
qgsrasterlayerproperties.cpp
qgstextannotationdialog.cpp
qgsshortcutsmanager.cpp
qgsguivectorlayertools.h
qgssnappingdialog.cpp
qgssvgannotationdialog.cpp
qgsundowidget.cpp
Expand Down
3 changes: 3 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -133,6 +133,7 @@
#include "qgshtmlannotationitem.h"
#include "qgsgenericprojectionselector.h"
#include "qgsgpsinformationwidget.h"
#include "qgsguivectorlayertools.h"
#include "qgslabelinggui.h"
#include "qgslegend.h"
#include "qgslayerorder.h"
Expand Down Expand Up @@ -574,6 +575,8 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, QWidget * parent,
mLogDock->setWidget( mLogViewer );
mLogDock->hide();

mVectorLayerTools = new QgsGuiVectorLayerTools();

mInternalClipboard = new QgsClipboard; // create clipboard
connect( mInternalClipboard, SIGNAL( changed() ), this, SLOT( clipboardChanged() ) );
mQgisInterface = new QgisAppInterface( this ); // create the interfce
Expand Down
10 changes: 9 additions & 1 deletion src/app/qgisapp.h
Expand Up @@ -57,9 +57,9 @@ class QgsPoint;
class QgsProviderRegistry;
class QgsPythonUtils;
class QgsRectangle;

class QgsUndoWidget;
class QgsVectorLayer;
class QgsVectorLayerTools;

class QDomDocument;
class QNetworkReply;
Expand Down Expand Up @@ -242,6 +242,13 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
/** overloaded function used to sort menu entries alphabetically */
QMenu* createPopupMenu();

/**
* Access the vector layer tools. This will be an instance of {@see QgsGuiVectorLayerTools}
* by default.
* @return The vector layer tools
*/
QgsVectorLayerTools* vectorLayerTools() { return mVectorLayerTools; }

//! Actions to be inserted in menus and toolbars
QAction *actionNewProject() { return mActionNewProject; }
QAction *actionOpenProject() { return mActionOpenProject; }
Expand Down Expand Up @@ -1518,6 +1525,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QgsMessageBar *mInfoBar;
QWidget *mMacrosWarn;

QgsVectorLayerTools* mVectorLayerTools;
#ifdef HAVE_TOUCH
bool gestureEvent( QGestureEvent *event );
void tapAndHoldTriggered( QTapAndHoldGesture *gesture );
Expand Down
1 change: 1 addition & 0 deletions src/app/qgsattributetabledialog.cpp
Expand Up @@ -80,6 +80,7 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );

context.setDistanceArea( myDa );
context.setVectorLayerTools( QgisApp::instance()->vectorLayerTools() );

// Initialize dual view
mMainView->init( mLayer, QgisApp::instance()->mapCanvas(), QgsFeatureRequest(), context );
Expand Down
29 changes: 20 additions & 9 deletions src/app/qgsfeatureaction.cpp
Expand Up @@ -15,16 +15,17 @@
* *
***************************************************************************/

#include "qgisapp.h"
#include "qgsattributedialog.h"
#include "qgsdistancearea.h"
#include "qgsfeatureaction.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsguivectorlayertools.h"
#include "qgsidentifyresultsdialog.h"
#include "qgsattributedialog.h"
#include "qgslogger.h"
#include "qgsdistancearea.h"
#include "qgisapp.h"
#include "qgsproject.h"
#include "qgsmapcanvas.h"
#include "qgsproject.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"

#include <QPushButton>
#include <QSettings>
Expand All @@ -47,13 +48,18 @@ QgsAttributeDialog *QgsFeatureAction::newDialog( bool cloneFeature )
{
QgsFeature *f = cloneFeature ? new QgsFeature( mFeature ) : &mFeature;

QgsAttributeEditorContext context;

QgsDistanceArea myDa;

myDa.setSourceCrs( mLayer->crs() );
myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() );
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );

QgsAttributeDialog *dialog = new QgsAttributeDialog( mLayer, f, cloneFeature, myDa );
context.setDistanceArea( myDa );
context.setVectorLayerTools( QgisApp::instance()->vectorLayerTools() );

QgsAttributeDialog *dialog = new QgsAttributeDialog( mLayer, f, cloneFeature, NULL, true, context );

if ( mLayer->actions()->size() > 0 )
{
Expand Down Expand Up @@ -138,7 +144,7 @@ bool QgsFeatureAction::editFeature()
return res;
}

bool QgsFeatureAction::addFeature()
bool QgsFeatureAction::addFeature( const QgsAttributeMap& defaultAttributes )
{
if ( !mLayer || !mLayer->isEditable() )
return false;
Expand All @@ -154,7 +160,12 @@ bool QgsFeatureAction::addFeature()
mFeature.initAttributes( fields.count() );
for ( int idx = 0; idx < fields.count(); ++idx )
{
if ( reuseLastValues && mLastUsedValues.contains( mLayer ) && mLastUsedValues[ mLayer ].contains( idx ) )
if ( defaultAttributes.contains( idx ) )
{
QgsDebugMsg( QString( "Using specified default %1 for %2" ).arg( defaultAttributes.value( idx ).toString() ).arg( idx ) );
mFeature.setAttribute( idx, defaultAttributes.value( idx ) );
}
else if ( reuseLastValues && mLastUsedValues.contains( mLayer ) && mLastUsedValues[ mLayer ].contains( idx ) )
{
QgsDebugMsg( QString( "reusing %1 for %2" ).arg( mLastUsedValues[ mLayer ][idx].toString() ).arg( idx ) );
mFeature.setAttribute( idx, mLastUsedValues[ mLayer ][idx] );
Expand Down
15 changes: 13 additions & 2 deletions src/app/qgsfeatureaction.h
Expand Up @@ -18,6 +18,7 @@
#define QGSFEATUREACTION_H

#include "qgsfeature.h"
#include "qgsvectorlayertools.h"

#include <QList>
#include <QPair>
Expand All @@ -33,13 +34,23 @@ class APP_EXPORT QgsFeatureAction : public QAction
Q_OBJECT

public:
QgsFeatureAction( const QString &name, QgsFeature &f, QgsVectorLayer *vl, int action, int defaultAttr, QObject *parent );
QgsFeatureAction( const QString &name, QgsFeature &f, QgsVectorLayer *vl, int action = -1, int defaultAttr = -1, QObject *parent = NULL );

public slots:
void execute();
bool viewFeatureForm( QgsHighlight *h = 0 );
bool editFeature();
bool addFeature();

/**
* Add a new feature to the layer.
* Will set the default values to recently used or provider defaults based on settings
* and override with values in defaultAttributes if provided.
*
* @param defaultAttributes Provide some default attributes here if desired.
*
* @return true if feature was added
*/
bool addFeature( const QgsAttributeMap& defaultAttributes = QgsAttributeMap() );

private:
QgsAttributeDialog *newDialog( bool cloneFeature );
Expand Down
162 changes: 162 additions & 0 deletions src/app/qgsguivectorlayertools.cpp
@@ -0,0 +1,162 @@
/***************************************************************************
qgsfeaturefactory.cpp
--------------------------------------
Date : 30.5.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include <QMessageBox>
#include <QToolButton>

#include "qgsguivectorlayertools.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsmessagebar.h"
#include "qgisapp.h"
#include "qgsapplication.h"
#include "qgsmessageviewer.h"
#include "qgsfeatureaction.h"
#include "qgsmapcanvas.h"
#include "qgsmessagebaritem.h"


QgsGuiVectorLayerTools::QgsGuiVectorLayerTools()
: QObject( NULL )
{}

bool QgsGuiVectorLayerTools::addFeature( QgsVectorLayer* layer, QgsAttributeMap defaultValues, const QgsGeometry& defaultGeometry )
{
QgsFeature f;
f.setGeometry( defaultGeometry );
QgsFeatureAction a( tr( "Add feature" ), f, layer );
return a.addFeature( defaultValues );
}

bool QgsGuiVectorLayerTools::startEditing( QgsVectorLayer* layer )
{
if ( !layer )
{
return false;
}

bool res = true;

if ( !layer->isEditable() && !layer->isReadOnly() )
{
if ( !( layer->dataProvider()->capabilities() & QgsVectorDataProvider::EditingCapabilities ) )
{
QgisApp::instance()->messageBar()->pushMessage( tr( "Start editing failed" ),
tr( "Provider cannot be opened for editing" ),
QgsMessageBar::INFO, QgisApp::instance()->messageTimeout() );
return false;
}

layer->startEditing();
}

return res;
}

bool QgsGuiVectorLayerTools::stopEditing( QgsVectorLayer* layer, bool allowCancel )
{
bool res = true;

if ( layer->isModified() )
{
QMessageBox::StandardButtons buttons = QMessageBox::Save | QMessageBox::Discard;
if ( allowCancel )
buttons |= QMessageBox::Cancel;

switch ( QMessageBox::information( 0,
tr( "Stop editing" ),
tr( "Do you want to save the changes to layer %1?" ).arg( layer->name() ),
buttons ) )
{
case QMessageBox::Cancel:
res = false;
break;

case QMessageBox::Save:
if ( !layer->commitChanges() )
{
commitError( layer );
// Leave the in-memory editing state alone,
// to give the user a chance to enter different values
// and try the commit again later
res = false;
}

layer->triggerRepaint();
break;

case QMessageBox::Discard:
QgisApp::instance()->mapCanvas()->freeze( true );
if ( !layer->rollBack() )
{
QgisApp::instance()->messageBar()->pushMessage( tr( "Error" ),
tr( "Problems during roll back" ),
QgsMessageBar::CRITICAL );
res = false;
}
QgisApp::instance()->mapCanvas()->freeze( false );

layer->triggerRepaint();
break;

default:
break;
}
}
else //layer not modified
{
QgisApp::instance()->mapCanvas()->freeze( true );
layer->rollBack();
QgisApp::instance()->mapCanvas()->freeze( false );
res = true;
layer->triggerRepaint();
}

return res;
}

void QgsGuiVectorLayerTools::commitError( QgsVectorLayer* vlayer )
{
QgsMessageViewer *mv = new QgsMessageViewer();
mv->setWindowTitle( tr( "Commit errors" ) );
mv->setMessageAsPlainText( tr( "Could not commit changes to layer %1" ).arg( vlayer->name() )
+ "\n\n"
+ tr( "Errors: %1\n" ).arg( vlayer->commitErrors().join( "\n " ) )
);

QToolButton *showMore = new QToolButton();
// store pointer to vlayer in data of QAction
QAction *act = new QAction( showMore );
act->setData( QVariant( QMetaType::QObjectStar, &vlayer ) );
act->setText( tr( "Show more" ) );
showMore->setStyleSheet( "background-color: rgba(255, 255, 255, 0); color: black; text-decoration: underline;" );
showMore->setCursor( Qt::PointingHandCursor );
showMore->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );
showMore->addAction( act );
showMore->setDefaultAction( act );
connect( showMore, SIGNAL( triggered( QAction* ) ), mv, SLOT( exec() ) );
connect( showMore, SIGNAL( triggered( QAction* ) ), showMore, SLOT( deleteLater() ) );

// no timeout set, since notice needs attention and is only shown first time layer is labeled
QgsMessageBarItem *errorMsg = new QgsMessageBarItem(
tr( "Commit errors" ),
tr( "Could not commit changes to layer %1" ).arg( vlayer->name() ),
showMore,
QgsMessageBar::WARNING,
0,
QgisApp::instance()->messageBar() );
QgisApp::instance()->messageBar()->pushItem( errorMsg );

}

0 comments on commit fb32966

Please sign in to comment.