39
39
#include " qgstaskmanager.h"
40
40
#include " qgsproviderregistry.h"
41
41
#include " qgsproxyprogresstask.h"
42
+ #include " qgsnewnamedialog.h"
42
43
43
44
QGISEXTERN bool deleteLayer ( const QString &uri, const QString &errCause );
44
45
@@ -81,6 +82,13 @@ QList<QAction *> QgsGeoPackageAbstractLayerItem::actions( QWidget * )
81
82
QAction *actionDeleteLayer = new QAction ( tr ( " Delete Layer '%1'…" ).arg ( mName ), this );
82
83
connect ( actionDeleteLayer, &QAction::triggered, this , &QgsGeoPackageAbstractLayerItem::deleteLayer );
83
84
lst.append ( actionDeleteLayer );
85
+ // Check capabilities: for now rename is only available for vectors
86
+ if ( capabilities2 () & QgsDataItem::Capability::Rename )
87
+ {
88
+ QAction *actionRenameLayer = new QAction ( tr ( " Rename Layer '%1'…" ).arg ( mName ), this );
89
+ connect ( actionRenameLayer, &QAction::triggered, this , &QgsGeoPackageAbstractLayerItem::renameLayer );
90
+ lst.append ( actionRenameLayer );
91
+ }
84
92
return lst;
85
93
}
86
94
@@ -490,16 +498,7 @@ void QgsGeoPackageCollectionItem::vacuumGeoPackageDbAction()
490
498
void QgsGeoPackageAbstractLayerItem::deleteLayer ()
491
499
{
492
500
// Check if the layer(s) are in the registry
493
- QList<QgsMapLayer *> layersList;
494
- const auto mapLayers ( QgsProject::instance ()->mapLayers () );
495
- for ( QgsMapLayer *layer : mapLayers )
496
- {
497
- if ( layer->publicSource () == mUri )
498
- {
499
- layersList << layer;
500
- }
501
- }
502
-
501
+ const QList<QgsMapLayer *> layersList ( layersInProject ( ) );
503
502
if ( ! layersList.isEmpty ( ) )
504
503
{
505
504
if ( QMessageBox::question ( nullptr , QObject::tr ( " Delete Layer" ), QObject::tr ( " The layer <b>%1</b> exists in the current project <b>%2</b>,"
@@ -515,7 +514,7 @@ void QgsGeoPackageAbstractLayerItem::deleteLayer()
515
514
return ;
516
515
}
517
516
518
- if ( layersList.isEmpty () )
517
+ if ( ! layersList.isEmpty () )
519
518
{
520
519
QgsProject::instance ()->removeMapLayers ( layersList );
521
520
}
@@ -534,6 +533,32 @@ void QgsGeoPackageAbstractLayerItem::deleteLayer()
534
533
}
535
534
536
535
}
536
+
537
+ void QgsGeoPackageAbstractLayerItem::renameLayer ( )
538
+ {
539
+ QMessageBox::warning ( nullptr , QObject::tr ( " Rename layer" ),
540
+ QObject::tr ( " The layer <b>%1</b> cannot be renamed because this feature is not yet implemented for this kind of layers." )
541
+ .arg ( mName ) );
542
+ }
543
+
544
+ void QgsGeoPackageVectorLayerItem::renameLayer ()
545
+ {
546
+
547
+ // Get layer name from layer URI
548
+ QVariantMap pieces ( QgsProviderRegistry::instance ()->decodeUri ( providerKey (), mUri ) );
549
+ QString baseUri = pieces[QStringLiteral ( " path" )].toString ();
550
+ QString layerName = pieces[QStringLiteral ( " layerName" )].toString ();
551
+
552
+ // Collect existing table names
553
+ const QRegExp checkRe ( QStringLiteral ( R"re( [A-Za-z_][A-Za-z0-9_\s]+)re" ) );
554
+ QgsNewNameDialog dlg ( mUri , layerName, QStringList (), tableNames (), checkRe );
555
+ dlg.setOverwriteEnabled ( false );
556
+
557
+ if ( dlg.exec () != dlg.Accepted || dlg.name ().isEmpty () || dlg.name () == layerName )
558
+ return ;
559
+
560
+ rename ( dlg.name () );
561
+ }
537
562
#endif
538
563
539
564
bool QgsGeoPackageCollectionItem::vacuumGeoPackageDb ( const QString &path, const QString &name, QString &errCause )
@@ -718,11 +743,64 @@ bool QgsGeoPackageAbstractLayerItem::executeDeleteLayer( QString &errCause )
718
743
return false ;
719
744
}
720
745
746
+ QList<QString> QgsGeoPackageAbstractLayerItem::tableNames ()
747
+ {
748
+ QList<QString> names;
749
+ QString errCause;
750
+ QVariantMap pieces ( QgsProviderRegistry::instance ()->decodeUri ( providerKey (), mUri ) );
751
+ QString baseUri = pieces[QStringLiteral ( " path" )].toString ();
752
+ if ( !baseUri.isEmpty () )
753
+ {
754
+ char *errmsg = nullptr ;
755
+ sqlite3_database_unique_ptr database;
756
+ int status = database.open_v2 ( baseUri, SQLITE_OPEN_READONLY, nullptr );
757
+ if ( status == SQLITE_OK )
758
+ {
759
+ char *sql = sqlite3_mprintf ( " SELECT table_name FROM gpkg_contents;" );
760
+ status = sqlite3_exec (
761
+ database.get (), /* An open database */
762
+ sql, /* SQL to be evaluated */
763
+ +[]( void *names, int , char **argv, char ** )
764
+ {
765
+ *static_cast <QList<QString>*>( names ) << QString ( argv[ 0 ] );
766
+ return 0 ;
767
+ }, /* Callback function */
768
+ &names, /* 1st argument to callback */
769
+ &errmsg /* Error msg written here */
770
+ );
771
+ sqlite3_free ( sql );
772
+ if ( status != SQLITE_OK )
773
+ QgsDebugMsg ( QStringLiteral ( " There was an error reading tables from GPKG layer %1: %2" ).arg ( mUri , QString::fromUtf8 ( errmsg ) ) );
774
+ sqlite3_free ( errmsg );
775
+ }
776
+ else
777
+ {
778
+ QgsDebugMsg ( QStringLiteral ( " There was an error opening GPKG %1" ).arg ( mUri ) );
779
+ }
780
+ }
781
+ return names;
782
+ }
783
+
784
+ QList<QgsMapLayer *> QgsGeoPackageAbstractLayerItem::layersInProject () const
785
+ {
786
+ // Check if the layer(s) are in the registry
787
+ QList<QgsMapLayer *> layersList;
788
+ const auto mapLayers ( QgsProject::instance ()->mapLayers () );
789
+ for ( QgsMapLayer *layer : mapLayers )
790
+ {
791
+ if ( layer->publicSource () == mUri )
792
+ {
793
+ layersList << layer;
794
+ }
795
+ }
796
+ return layersList;
797
+ }
798
+
721
799
722
800
QgsGeoPackageVectorLayerItem::QgsGeoPackageVectorLayerItem ( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri, LayerType layerType )
723
801
: QgsGeoPackageAbstractLayerItem( parent, name, path, uri, layerType, QStringLiteral( " ogr" ) )
724
802
{
725
-
803
+ mCapabilities |= Rename;
726
804
}
727
805
728
806
@@ -737,9 +815,80 @@ bool QgsGeoPackageRasterLayerItem::executeDeleteLayer( QString &errCause )
737
815
return QgsGeoPackageCollectionItem::deleteGeoPackageRasterLayer ( mUri , errCause );
738
816
}
739
817
740
-
741
818
bool QgsGeoPackageVectorLayerItem::executeDeleteLayer ( QString &errCause )
742
819
{
743
820
return ::deleteLayer ( mUri , errCause );
744
821
}
745
822
823
+ bool QgsGeoPackageVectorLayerItem::rename ( const QString &name )
824
+ {
825
+ // Checks that name does not exist yet
826
+ if ( tableNames ().contains ( name ) )
827
+ {
828
+ return false ;
829
+ }
830
+ // Check if the layer(s) are in the registry
831
+ const QList<QgsMapLayer *> layersList ( layersInProject () );
832
+ if ( ! layersList.isEmpty ( ) )
833
+ {
834
+ if ( QMessageBox::question ( nullptr , QObject::tr ( " Rename Layer" ), QObject::tr ( " The layer <b>%1</b> is loaded in the current project with name <b>%2</b>,"
835
+ " do you want to remove it from the project and rename it?" ).arg ( mName , layersList.at ( 0 )->name () ), QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
836
+ {
837
+ return false ;
838
+ }
839
+ }
840
+ if ( ! layersList.isEmpty () )
841
+ {
842
+ QgsProject::instance ()->removeMapLayers ( layersList );
843
+ }
844
+
845
+ const QVariantMap parts = QgsProviderRegistry::instance ()->decodeUri ( mProviderKey , mUri );
846
+ QString errCause;
847
+ if ( parts.empty () || parts.value ( QStringLiteral ( " path" ) ).isNull () || parts.value ( " layerName" ).isNull () )
848
+ {
849
+ errCause = QObject::tr ( " Layer URI %1 is not valid!" ).arg ( mUri );
850
+ }
851
+ else
852
+ {
853
+ QString filePath = parts.value ( QStringLiteral ( " path" ) ).toString ();
854
+ const QList<QgsMapLayer *> layersList ( layersInProject () );
855
+ if ( ! layersList.isEmpty ( ) )
856
+ {
857
+ if ( QMessageBox::question ( nullptr , QObject::tr ( " Rename Layer" ), QObject::tr ( " The layer <b>%1</b> exists in the current project <b>%2</b>,"
858
+ " do you want to remove it from the project and rename it?" ).arg ( mName , layersList.at ( 0 )->name () ), QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
859
+ {
860
+ return false ;
861
+ }
862
+ }
863
+ if ( ! layersList.isEmpty () )
864
+ {
865
+ QgsProject::instance ()->removeMapLayers ( layersList );
866
+ }
867
+
868
+ // TODO: maybe an index?
869
+ QString oldName = parts.value ( QStringLiteral ( " layerName" ) ).toString ();
870
+
871
+ GDALDatasetH hDS = GDALOpenEx ( filePath.toUtf8 ().constData (), GDAL_OF_VECTOR | GDAL_OF_UPDATE, nullptr , nullptr , nullptr );
872
+ if ( hDS )
873
+ {
874
+ QString sql ( QStringLiteral ( " ALTER TABLE \" %1\" RENAME TO \" %2\" " ).arg ( oldName, name ) );
875
+ OGRLayerH ogrLayer ( GDALDatasetExecuteSQL ( hDS, sql.toUtf8 ().constData (), nullptr , nullptr ) );
876
+ if ( ogrLayer )
877
+ GDALDatasetReleaseResultSet ( hDS, ogrLayer );
878
+ GDALClose ( hDS );
879
+ errCause = CPLGetLastErrorMsg ( );
880
+ }
881
+ else
882
+ {
883
+ errCause = QObject::tr ( " There was an error opening %1!" ).arg ( filePath );
884
+ }
885
+ }
886
+
887
+ if ( ! errCause.isEmpty () )
888
+ QMessageBox::critical ( nullptr , QObject::tr ( " Error renaming layer" ), errCause );
889
+ else if ( mParent )
890
+ mParent ->refreshConnections ();
891
+
892
+ return errCause.isEmpty ();
893
+ }
894
+
0 commit comments