From eaeea21a2d7ca230ced5f69e140ae2d97bbabd13 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Wed, 20 May 2015 12:32:27 +0200 Subject: [PATCH] [GRASS][FEATURE] rename maps in browser --- src/providers/grass/qgsgrass.cpp | 80 +++++++++++++--- src/providers/grass/qgsgrass.h | 15 +++ .../grass/qgsgrassprovidermodule.cpp | 94 ++++++++++++++++--- src/providers/grass/qgsgrassprovidermodule.h | 9 +- 4 files changed, 171 insertions(+), 27 deletions(-) diff --git a/src/providers/grass/qgsgrass.cpp b/src/providers/grass/qgsgrass.cpp index 6a5802a38b6c..9909f7c022ab 100644 --- a/src/providers/grass/qgsgrass.cpp +++ b/src/providers/grass/qgsgrass.cpp @@ -105,11 +105,42 @@ QString QgsGrassObject::elementName( Type type ) return ""; } +QString QgsGrassObject::dirName() const +{ + return dirName( mType ); +} + +QString QgsGrassObject::dirName( Type type ) +{ + if ( type == Raster ) + return "cellhd"; + else if ( type == Vector ) + return "vector"; + else if ( type == Region ) + return "windows"; + else + return ""; +} + bool QgsGrassObject::mapsetIdentical( const QgsGrassObject &other ) { return mGisdbase == other.mGisdbase && mLocation == other.mLocation && mMapset == other.mMapset; } +QRegExp QgsGrassObject::newNameRegExp( Type type ) +{ + QRegExp rx; + if ( type == QgsGrassObject::Vector ) + { + rx.setPattern( "[A-Za-z_][A-Za-z0-9_]+" ); + } + else + { + rx.setPattern( "[A-Za-z0-9_.]+" ); + } + return rx; +} + #ifdef Q_OS_WIN #include QString GRASS_LIB_EXPORT QgsGrass::shortPath( const QString &path ) @@ -1085,7 +1116,7 @@ QStringList GRASS_LIB_EXPORT QgsGrass::elements( const QString& gisdbase, const QStringList GRASS_LIB_EXPORT QgsGrass::elements( const QString& mapsetPath, const QString& element ) { - QgsDebugMsg( QString( "mapsetPath = %1" ).arg( mapsetPath ) ); + QgsDebugMsg( QString( "mapsetPath = %1 element = %2" ).arg( mapsetPath ).arg( element ) ); QStringList list; @@ -1093,7 +1124,14 @@ QStringList GRASS_LIB_EXPORT QgsGrass::elements( const QString& mapsetPath, con return list; QDir d = QDir( mapsetPath + "/" + element ); - d.setFilter( QDir::Files ); + if ( element == "vector" ) + { + d.setFilter( QDir::Dirs | QDir::NoDotAndDotDot ); + } + else + { + d.setFilter( QDir::Files ); + } for ( unsigned int i = 0; i < d.count(); i++ ) { @@ -1102,17 +1140,15 @@ QStringList GRASS_LIB_EXPORT QgsGrass::elements( const QString& mapsetPath, con return list; } -bool GRASS_LIB_EXPORT QgsGrass::objectExists( const QgsGrassObject& grassObject ) +QStringList GRASS_LIB_EXPORT QgsGrass::grassObjects( const QString& mapsetPath, QgsGrassObject::Type type ) { - QString path = grassObject.mapsetPath(); - if ( grassObject.type() == QgsGrassObject::Raster ) - path += "/cellhd"; - else if ( grassObject.type() == QgsGrassObject::Vector ) - path += "/vector"; - else if ( grassObject.type() == QgsGrassObject::Region ) - path += "/windows"; + return QgsGrass::elements( mapsetPath, QgsGrassObject::dirName( type ) ); +} - path += "/" + grassObject.name(); +bool GRASS_LIB_EXPORT QgsGrass::objectExists( const QgsGrassObject& grassObject ) +{ + QString path = grassObject.mapsetPath() + "/" + QgsGrassObject::dirName( grassObject.type() ) + + "/" + grassObject.name(); QFileInfo fi( path ); return fi.exists(); } @@ -1748,6 +1784,19 @@ QMap GRASS_LIB_EXPORT QgsGrass::query( QString gisdbase, QStri return result; } +void QgsGrass::renameObject( const QgsGrassObject & object, const QString& newName ) +{ + QgsDebugMsg( "entered" ); + QString cmd = "g.rename"; + QStringList arguments; + + arguments << object.elementShort() + "=" + object.name() + "," + newName; + + int timeout = 10000; // What timeout to use? It can take long time on network or database + // throws QgsGrass::Exception + QgsGrass::runModule( object.gisdbase(), object.location(), object.mapset(), cmd, arguments, timeout, false ); +} + bool QgsGrass::deleteObject( const QgsGrassObject & object ) { QgsDebugMsg( "entered" ); @@ -1950,6 +1999,15 @@ QString GRASS_LIB_EXPORT QgsGrass::versionString() return QString( GRASS_VERSION_STRING ); } +Qt::CaseSensitivity GRASS_LIB_EXPORT QgsGrass::caseSensitivity() +{ +#ifdef WIN32 + return Qt::CaseInsensitive; +#else + return Qt::CaseSensitive; +#endif +} + bool GRASS_LIB_EXPORT QgsGrass::isMapset( QString path ) { #if 0 diff --git a/src/providers/grass/qgsgrass.h b/src/providers/grass/qgsgrass.h index 4e3b8edd20c9..cb9964a5e798 100644 --- a/src/providers/grass/qgsgrass.h +++ b/src/providers/grass/qgsgrass.h @@ -39,6 +39,7 @@ extern "C" #include #include #include +#include #include class QgsCoordinateReferenceSystem; class QgsRectangle; @@ -93,8 +94,13 @@ class GRASS_LIB_EXPORT QgsGrassObject // descriptive full name QString elementName() const; static QString elementName( Type type ); + // name of directory in GRASS mapset to look for the object (cellhd,vector,window) + QString dirName() const; + static QString dirName( Type type ); // returns true if gisdbase, location and mapset are the same bool mapsetIdentical( const QgsGrassObject &other ); + // get regexp patter for new names, e.g. vectors should not start with number + static QRegExp newNameRegExp( Type type ); private: QString mGisdbase; QString mLocation; @@ -216,10 +222,14 @@ class QgsGrass const QString& mapset, const QString& mapName ); //! List of elements + // TODO rename elements to objects static GRASS_LIB_EXPORT QStringList elements( const QString& gisdbase, const QString& locationName, const QString& mapsetName, const QString& element ); static GRASS_LIB_EXPORT QStringList elements( const QString& mapsetPath, const QString& element ); + //! List of existing objects + static GRASS_LIB_EXPORT QStringList grassObjects( const QString& mapsetPath, QgsGrassObject::Type type ); + // returns true if object (vector, raster, region) exists static GRASS_LIB_EXPORT bool objectExists( const QgsGrassObject& grassObject ); @@ -344,6 +354,9 @@ class QgsGrass static GRASS_LIB_EXPORT QMap query( QString gisdbase, QString location, QString mapset, QString map, QgsGrassObject::Type type, double x, double y ); + // ! Rename GRASS object, throws QgsGrass::Exception + static GRASS_LIB_EXPORT void renameObject( const QgsGrassObject & object, const QString& newName ); + // ! Delete map static GRASS_LIB_EXPORT bool deleteObject( const QgsGrassObject & object ); @@ -365,6 +378,8 @@ class QgsGrass static GRASS_LIB_EXPORT int versionRelease(); static GRASS_LIB_EXPORT QString versionString(); + // files case sensitivity (insensitive on windows) + static GRASS_LIB_EXPORT Qt::CaseSensitivity caseSensitivity(); // set environment variable static GRASS_LIB_EXPORT void putEnv( QString name, QString value ); diff --git a/src/providers/grass/qgsgrassprovidermodule.cpp b/src/providers/grass/qgsgrassprovidermodule.cpp index 97e5a6f4773c..103d7128d9d5 100644 --- a/src/providers/grass/qgsgrassprovidermodule.cpp +++ b/src/providers/grass/qgsgrassprovidermodule.cpp @@ -29,6 +29,7 @@ #include #include #include +#include //----------------------- QgsGrassLocationItem ------------------------------ @@ -212,11 +213,8 @@ bool QgsGrassMapsetItem::handleDrop( const QMimeData * data, Qt::DropAction ) QStringList errors; QgsMimeDataUtils::UriList lst = QgsMimeDataUtils::decodeUriList( data ); -#ifdef WIN32 - Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; -#else - Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; -#endif + Qt::CaseSensitivity caseSensitivity = QgsGrass::caseSensitivity(); + foreach ( const QgsMimeDataUtils::Uri& u, lst ) { if ( u.layerType != "raster" && u.layerType != "vector" ) @@ -229,17 +227,20 @@ bool QgsGrassMapsetItem::handleDrop( const QMimeData * data, Qt::DropAction ) QgsDataProvider* provider = 0; QStringList extensions; QStringList existingNames; + QRegExp regExp; if ( u.layerType == "raster" ) { rasterProvider = qobject_cast( QgsProviderRegistry::instance()->provider( u.providerKey, u.uri ) ); provider = rasterProvider; existingNames = existingRasters; + regExp = QgsGrassObject::newNameRegExp( QgsGrassObject::Raster ); } else if ( u.layerType == "vector" ) { vectorProvider = qobject_cast( QgsProviderRegistry::instance()->provider( u.providerKey, u.uri ) ); provider = vectorProvider; existingNames = existingVectors; + regExp = QgsGrassObject::newNameRegExp( QgsGrassObject::Vector ); } QgsDebugMsg( "existingNames = " + existingNames.join( "," ) ); @@ -263,7 +264,7 @@ bool QgsGrassMapsetItem::handleDrop( const QMimeData * data, Qt::DropAction ) QString newName = u.name; if ( QgsNewNameDialog::exists( u.name, extensions, existingNames, caseSensitivity ) ) { - QgsNewNameDialog dialog( u.name, u.name, extensions, existingNames, QRegExp(), caseSensitivity ); + QgsNewNameDialog dialog( u.name, u.name, extensions, existingNames, regExp, caseSensitivity ); if ( dialog.exec() != QDialog::Accepted ) { delete provider; @@ -374,10 +375,9 @@ bool QgsGrassMapsetItem::handleDrop( const QMimeData * data, Qt::DropAction ) if ( !errors.isEmpty() ) { - QgsMessageOutput *output = QgsMessageOutput::createMessageOutput(); - output->setTitle( tr( "Import to GRASS mapset" ) ); - output->setMessage( tr( "Failed to import some layers!\n\n" ) + errors.join( "\n" ), QgsMessageOutput::MessageText ); - output->showMessage(); + QgsMessageOutput::showMessage( tr( "Import to GRASS mapset" ), + tr( "Failed to import some layers!\n\n" ) + errors.join( "\n" ), + QgsMessageOutput::MessageText ); } return true; @@ -407,6 +407,54 @@ QgsGrassObjectItemBase::QgsGrassObjectItemBase( QgsGrassObject grassObject ) : { } +void QgsGrassObjectItemBase::renameGrassObject( QgsDataItem* parent ) +{ + QgsDebugMsg( "Entered" ); + + QStringList existingNames = QgsGrass::grassObjects( mGrassObject.mapsetPath(), mGrassObject.type() ); + // remove current name to avoid warning that exists + existingNames.removeOne( mGrassObject.name() ); + QgsDebugMsg( "existingNames = " + existingNames.join( "," ) ); + QRegExp regExp = QgsGrassObject::newNameRegExp( mGrassObject.type() ); + Qt::CaseSensitivity caseSensitivity = QgsGrass::caseSensitivity(); + QgsNewNameDialog dialog( mGrassObject.name(), mGrassObject.name(), QStringList(), existingNames, regExp, caseSensitivity ); + + if ( dialog.exec() != QDialog::Accepted || dialog.name() == mGrassObject.name() ) + { + return; + } + + QgsDebugMsg( "rename " + mGrassObject.name() + " -> " + dialog.name() ); + + QgsGrassObject obj( mGrassObject ); + obj.setName( dialog.name() ); + QString errorTitle = QObject::tr( "Rename GRASS %1" ).arg( mGrassObject.elementName() ); + if ( QgsGrass::objectExists( obj ) ) + { + QgsDebugMsg( obj.name() + " exists -> delete" ); + if ( !QgsGrass::deleteObject( obj ) ) + { + QgsMessageOutput::showMessage( errorTitle, QObject::tr( "Cannot delete %1" ).arg( obj.name() ), QgsMessageOutput::MessageText ); + return; + } + } + + try + { + QgsGrass::renameObject( mGrassObject, obj.name() ); + if ( parent ) + { + parent->refresh(); + } + } + catch ( QgsGrass::Exception &e ) + { + QgsMessageOutput::showMessage( errorTitle, + QObject::tr( "Cannot rename %1 to %2" ).arg( mGrassObject.name() ).arg( obj.name() ) + "\n" + e.what(), + QgsMessageOutput::MessageText ); + } +} + void QgsGrassObjectItemBase::deleteGrassObject( QgsDataItem* parent ) { QgsDebugMsg( "Entered" ); @@ -426,10 +474,10 @@ void QgsGrassObjectItemBase::deleteGrassObject( QgsDataItem* parent ) QgsGrassObjectItem::QgsGrassObjectItem( QgsDataItem* parent, QgsGrassObject grassObject, QString name, QString path, QString uri, LayerType layerType, QString providerKey, - bool deleteAction ) + bool showObjectActions ) : QgsLayerItem( parent, name, path, uri, layerType, providerKey ) , QgsGrassObjectItemBase( grassObject ) - , mDeleteAction( deleteAction ) + , mShowObjectActions( showObjectActions ) { setState( Populated ); // no children, to show non expandable in browser } @@ -438,8 +486,12 @@ QList QgsGrassObjectItem::actions() { QList lst; - if ( mDeleteAction ) + if ( mShowObjectActions ) { + QAction* actionRename = new QAction( tr( "Rename" ), this ); + connect( actionRename, SIGNAL( triggered() ), this, SLOT( renameGrassObject() ) ); + lst.append( actionRename ); + QAction* actionDelete = new QAction( tr( "Delete" ), this ); connect( actionDelete, SIGNAL( triggered() ), this, SLOT( deleteGrassObject() ) ); lst.append( actionDelete ); @@ -448,6 +500,11 @@ QList QgsGrassObjectItem::actions() return lst; } +void QgsGrassObjectItem::renameGrassObject() +{ + QgsGrassObjectItemBase::renameGrassObject( parent() ); +} + void QgsGrassObjectItem::deleteGrassObject() { QgsGrassObjectItemBase::deleteGrassObject( parent() ); @@ -467,6 +524,10 @@ QList QgsGrassVectorItem::actions() { QList lst; + QAction* actionRename = new QAction( tr( "Rename" ), this ); + connect( actionRename, SIGNAL( triggered() ), this, SLOT( renameGrassObject() ) ); + lst.append( actionRename ); + QAction* actionDelete = new QAction( tr( "Delete" ), this ); connect( actionDelete, SIGNAL( triggered() ), this, SLOT( deleteGrassObject() ) ); lst.append( actionDelete ); @@ -474,6 +535,11 @@ QList QgsGrassVectorItem::actions() return lst; } +void QgsGrassVectorItem::renameGrassObject() +{ + QgsGrassObjectItemBase::renameGrassObject( parent() ); +} + void QgsGrassVectorItem::deleteGrassObject() { QgsGrassObjectItemBase::deleteGrassObject( parent() ); @@ -484,7 +550,7 @@ void QgsGrassVectorItem::deleteGrassObject() QgsGrassVectorLayerItem::QgsGrassVectorLayerItem( QgsDataItem* parent, QgsGrassObject grassObject, QString layerName, QString path, QString uri, LayerType layerType, bool singleLayer ) - : QgsGrassObjectItem( parent, grassObject, layerName, path, uri, layerType, "grass" ) + : QgsGrassObjectItem( parent, grassObject, layerName, path, uri, layerType, "grass", mSingleLayer ) , mSingleLayer( singleLayer ) { } diff --git a/src/providers/grass/qgsgrassprovidermodule.h b/src/providers/grass/qgsgrassprovidermodule.h index d6a3af01a2b1..2546048389bf 100644 --- a/src/providers/grass/qgsgrassprovidermodule.h +++ b/src/providers/grass/qgsgrassprovidermodule.h @@ -62,6 +62,7 @@ class QgsGrassObjectItemBase QgsGrassObjectItemBase( QgsGrassObject grassObject ); public: + void renameGrassObject( QgsDataItem* parent ); void deleteGrassObject( QgsDataItem* parent ); protected: @@ -75,16 +76,19 @@ class QgsGrassObjectItem : public QgsLayerItem, public QgsGrassObjectItemBase QgsGrassObjectItem( QgsDataItem* parent, QgsGrassObject grassObject, QString name, QString path, QString uri, LayerType layerType, QString providerKey, - bool deleteAction = true ); + bool showObjectActions = true ); virtual QList actions() override; public slots: + void renameGrassObject(); void deleteGrassObject(); protected: //QgsGrassObject mGrassObject; - bool mDeleteAction; + // indicates if it is really GRASS object like raster or vector map, + // for example + bool mShowObjectActions; }; // Vector is collection of layers @@ -98,6 +102,7 @@ class QgsGrassVectorItem : public QgsDataCollectionItem, public QgsGrassObjectIt virtual QList actions() override; public slots: + void renameGrassObject(); void deleteGrassObject(); private: