Skip to content

Commit

Permalink
GUI implementation to load/save projects in PostgreSQL
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Apr 7, 2018
1 parent ab83455 commit 0c701fb
Show file tree
Hide file tree
Showing 9 changed files with 378 additions and 2 deletions.
40 changes: 40 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -250,6 +250,8 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgsproject.h" #include "qgsproject.h"
#include "qgsprojectlayergroupdialog.h" #include "qgsprojectlayergroupdialog.h"
#include "qgsprojectproperties.h" #include "qgsprojectproperties.h"
#include "qgsprojectstorage.h"
#include "qgsprojectstorageregistry.h"
#include "qgsproviderregistry.h" #include "qgsproviderregistry.h"
#include "qgspythonrunner.h" #include "qgspythonrunner.h"
#include "qgsquerybuilder.h" #include "qgsquerybuilder.h"
Expand Down Expand Up @@ -1292,6 +1294,10 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh


setupDuplicateFeaturesAction(); setupDuplicateFeaturesAction();


// support for project storage
connect( mProjectFromStorageMenu, &QMenu::aboutToShow, [this] { populateProjectStorageMenu( mProjectFromStorageMenu, false ); } );
connect( mProjectToStorageMenu, &QMenu::aboutToShow, [this] { populateProjectStorageMenu( mProjectToStorageMenu, true ); } );

QList<QAction *> actions = mPanelMenu->actions(); QList<QAction *> actions = mPanelMenu->actions();
std::sort( actions.begin(), actions.end(), cmpByText_ ); std::sort( actions.begin(), actions.end(), cmpByText_ );
mPanelMenu->insertActions( nullptr, actions ); mPanelMenu->insertActions( nullptr, actions );
Expand Down Expand Up @@ -13549,3 +13555,37 @@ QgsFeature QgisApp::duplicateFeatureDigitized( QgsMapLayer *mlayer, const QgsFea
return QgsFeature(); return QgsFeature();
} }



void QgisApp::populateProjectStorageMenu( QMenu *menu, bool saving )
{
menu->clear();
for ( QgsProjectStorage *storage : QgsApplication::projectStorageRegistry()->projectStorages() )
{
QString name = storage->visibleName();
if ( name.isEmpty() )
continue;
QAction *action = menu->addAction( name );
if ( saving )
{
connect( action, &QAction::triggered, [storage]
{
QString uri = storage->showSaveGui();
if ( !uri.isEmpty() )
{
// TODO: merge with QgisApp::fileSaveAs()
QgsProject::instance()->setFileName( uri );
QgsProject::instance()->write();
}
} );
}
else
{
connect( action, &QAction::triggered, [this, storage]
{
QString uri = storage->showLoadGui();
if ( !uri.isEmpty() )
addProject( uri );
} );
}
}
}
3 changes: 3 additions & 0 deletions src/app/qgisapp.h
Expand Up @@ -1880,6 +1880,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
*/ */
int dockedToolbarIconSize( int standardToolbarIconSize ) const; int dockedToolbarIconSize( int standardToolbarIconSize ) const;


//! Populates project "load from" / "save to" menu based on project storages (when the menu is about to be shown)
void populateProjectStorageMenu( QMenu *menu, bool saving );

QgisAppStyleSheet *mStyleSheetBuilder = nullptr; QgisAppStyleSheet *mStyleSheetBuilder = nullptr;


// actions for menus and toolbars ----------------- // actions for menus and toolbars -----------------
Expand Down
2 changes: 2 additions & 0 deletions src/providers/postgres/CMakeLists.txt
Expand Up @@ -30,10 +30,12 @@ IF (WITH_GUI)
SET(PG_SRCS ${PG_SRCS} SET(PG_SRCS ${PG_SRCS}
qgspgsourceselect.cpp qgspgsourceselect.cpp
qgspgnewconnection.cpp qgspgnewconnection.cpp
qgspostgresprojectstoragedialog.cpp
) )
SET(PG_MOC_HDRS ${PG_MOC_HDRS} SET(PG_MOC_HDRS ${PG_MOC_HDRS}
qgspgnewconnection.h qgspgnewconnection.h
qgspgsourceselect.h qgspgsourceselect.h
qgspostgresprojectstoragedialog.h
) )
ENDIF () ENDIF ()


Expand Down
63 changes: 63 additions & 0 deletions src/providers/postgres/qgspostgresprojectstorage.cpp
Expand Up @@ -220,6 +220,69 @@ bool QgsPostgresProjectStorage::readProjectMetadata( const QString &uri, QgsProj
} }




#ifdef HAVE_GUI

#include "qgspostgresprojectstoragedialog.h"

QString QgsPostgresProjectStorage::visibleName()
{
return QObject::tr( "PostgreSQL" );
}

QString QgsPostgresProjectStorage::showLoadGui()
{
QgsPostgresProjectStorageDialog dlg( false );
if ( !dlg.exec() )
return QString();

QgsPostgresProjectUri postUri;
postUri.connInfo = QgsPostgresConn::connUri( dlg.connectionName() );
postUri.schemaName = dlg.schemaName();
postUri.projectName = dlg.projectName();
return makeUri( postUri );
}

QString QgsPostgresProjectStorage::showSaveGui()
{
QgsPostgresProjectStorageDialog dlg( true );
if ( !dlg.exec() )
return QString();

QgsPostgresProjectUri postUri;
postUri.connInfo = QgsPostgresConn::connUri( dlg.connectionName() );
postUri.schemaName = dlg.schemaName();
postUri.projectName = dlg.projectName();
return makeUri( postUri );
}

#endif


QString QgsPostgresProjectStorage::makeUri( const QgsPostgresProjectUri &postUri )
{
QUrl u;
QUrlQuery urlQuery;

u.setScheme( "postgresql" );
u.setHost( postUri.connInfo.host() );
if ( !postUri.connInfo.port().isEmpty() )
u.setPort( postUri.connInfo.port().toInt() );
u.setUserName( postUri.connInfo.username() );
u.setPassword( postUri.connInfo.password() );
// TODO: sslmode, authcfg, service

urlQuery.addQueryItem( "dbname", postUri.connInfo.database() );

urlQuery.addQueryItem( "schema", postUri.schemaName );
if ( !postUri.projectName.isEmpty() )
urlQuery.addQueryItem( "project", postUri.projectName );

u.setQuery( urlQuery );

return QString::fromUtf8( u.toEncoded() );
}


QgsPostgresProjectUri QgsPostgresProjectStorage::parseUri( const QString &uri ) QgsPostgresProjectUri QgsPostgresProjectStorage::parseUri( const QString &uri )
{ {
QUrl u = QUrl::fromEncoded( uri.toUtf8() ); QUrl u = QUrl::fromEncoded( uri.toUtf8() );
Expand Down
11 changes: 9 additions & 2 deletions src/providers/postgres/qgspostgresprojectstorage.h
@@ -1,6 +1,7 @@
#ifndef QGSPOSTGRESPROJECTSTORAGE_H #ifndef QGSPOSTGRESPROJECTSTORAGE_H
#define QGSPOSTGRESPROJECTSTORAGE_H #define QGSPOSTGRESPROJECTSTORAGE_H


#include "qgsconfig.h"
#include "qgsprojectstorage.h" #include "qgsprojectstorage.h"


#include "qgsdatasourceuri.h" #include "qgsdatasourceuri.h"
Expand All @@ -12,7 +13,6 @@ typedef struct


QgsDataSourceUri connInfo; // using only the bits about connection info (server, port, username, password, service, ssl mode) QgsDataSourceUri connInfo; // using only the bits about connection info (server, port, username, password, service, ssl mode)


QString dbName;
QString schemaName; QString schemaName;
QString projectName; QString projectName;


Expand All @@ -37,7 +37,14 @@ class QgsPostgresProjectStorage : public QgsProjectStorage


virtual bool readProjectMetadata( const QString &uri, QgsProjectStorage::Metadata &metadata ) override; virtual bool readProjectMetadata( const QString &uri, QgsProjectStorage::Metadata &metadata ) override;


private: #ifdef HAVE_GUI
// GUI support
virtual QString visibleName() override;
virtual QString showLoadGui() override;
virtual QString showSaveGui() override;
#endif

static QString makeUri( const QgsPostgresProjectUri &postUri );
static QgsPostgresProjectUri parseUri( const QString &uri ); static QgsPostgresProjectUri parseUri( const QString &uri );
}; };


Expand Down
127 changes: 127 additions & 0 deletions src/providers/postgres/qgspostgresprojectstoragedialog.cpp
@@ -0,0 +1,127 @@
#include "qgspostgresprojectstoragedialog.h"

#include "qgspostgresconn.h"
#include "qgspostgresconnpool.h"
#include "qgspostgresprojectstorage.h"

#include "qgsapplication.h"
#include "qgsprojectstorage.h"
#include "qgsprojectstorageregistry.h"

#include <QMessageBox>

QgsPostgresProjectStorageDialog::QgsPostgresProjectStorageDialog( bool saving, QWidget *parent )
: QDialog( parent )
, mSaving( saving )
{
setupUi( this );

connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsPostgresProjectStorageDialog::onOK );

if ( saving )
{
setWindowTitle( tr( "Save project to PostgreSQL" ) );
mCboProject->setEditable( true );
}
else
{
setWindowTitle( tr( "Load project from PostgreSQL" ) );
}

connect( mCboConnection, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPostgresProjectStorageDialog::populateSchemas );

// populate connections
mCboConnection->addItems( QgsPostgresConn::connectionList() );

// If possible, set the item currently displayed database
QString toSelect = QgsPostgresConn::selectedConnection();
mCboConnection->setCurrentIndex( mCboConnection->findText( toSelect ) );

connect( mCboSchema, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPostgresProjectStorageDialog::populateProjects );
}

QString QgsPostgresProjectStorageDialog::connectionName() const
{
return mCboConnection->currentText();
}

QString QgsPostgresProjectStorageDialog::schemaName() const
{
return mCboSchema->currentText();
}

QString QgsPostgresProjectStorageDialog::projectName() const
{
return mCboProject->currentText();
}

void QgsPostgresProjectStorageDialog::populateSchemas()
{
mCboSchema->clear();
mCboProject->clear();

QString name = mCboConnection->currentText();
QgsDataSourceUri uri = QgsPostgresConn::connUri( name );

QApplication::setOverrideCursor( Qt::WaitCursor );

QgsPostgresConn *conn = QgsPostgresConnPool::instance()->acquireConnection( uri.connectionInfo( false ) );
if ( !conn )
{
QApplication::restoreOverrideCursor();
QMessageBox::critical( this, tr( "Error" ), tr( "Connection failed" ) + "\n" + uri.connectionInfo( false ) );
return;
}

QList<QgsPostgresSchemaProperty> schemas;
bool ok = conn->getSchemas( schemas );
QgsPostgresConnPool::instance()->releaseConnection( conn );

QApplication::restoreOverrideCursor();

if ( !ok )
{
QMessageBox::critical( this, tr( "Error" ), tr( "Failed to get schemas" ) );
return;
}

for ( const QgsPostgresSchemaProperty &schema : qAsConst( schemas ) )
{
mCboSchema->addItem( schema.name );
}
}

void QgsPostgresProjectStorageDialog::populateProjects()
{
mCboProject->clear();

QgsPostgresProjectUri postUri;
postUri.connInfo = QgsPostgresConn::connUri( mCboConnection->currentText() );
postUri.schemaName = mCboSchema->currentText();
QString uri = QgsPostgresProjectStorage::makeUri( postUri );

QgsProjectStorage *storage = QgsApplication::projectStorageRegistry()->projectStorageFromType( "postgresql" );
Q_ASSERT( storage );
mCboProject->addItems( storage->listProjects( uri ) );
}

void QgsPostgresProjectStorageDialog::onOK()
{
// check that the fields are filled in
if ( mCboProject->currentText().isEmpty() )
return;

if ( mSaving )
{
if ( mCboProject->findText( mCboProject->currentText() ) != -1 )
{
int res = QMessageBox::question( this, tr( "Overwrite project" ),
tr( "A project with the same name already exists. Would you like to overwrite it?" ),
QMessageBox::Yes | QMessageBox::No );
if ( res != QMessageBox::Yes )
return;
}
}

accept();
}
30 changes: 30 additions & 0 deletions src/providers/postgres/qgspostgresprojectstoragedialog.h
@@ -0,0 +1,30 @@
#ifndef QGSPOSTGRESPROJECTSTORAGEDIALOG_H
#define QGSPOSTGRESPROJECTSTORAGEDIALOG_H

#include <QDialog>

#include "ui_qgspostgresprojectstoragedialog.h"


class QgsPostgresProjectStorageDialog : public QDialog, private Ui::QgsPostgresProjectStorageDialog
{
Q_OBJECT
public:
explicit QgsPostgresProjectStorageDialog( bool saving, QWidget *parent = nullptr );

QString connectionName() const;
QString schemaName() const;
QString projectName() const;

signals:

private slots:
void populateSchemas();
void populateProjects();
void onOK();

private:
bool mSaving; //!< Whether using this dialog for loading or saving a project
};

#endif // QGSPOSTGRESPROJECTSTORAGEDIALOG_H
12 changes: 12 additions & 0 deletions src/ui/qgisapp.ui
Expand Up @@ -42,15 +42,27 @@
<string>New From Template</string> <string>New From Template</string>
</property> </property>
</widget> </widget>
<widget class="QMenu" name="mProjectToStorageMenu">
<property name="title">
<string>Save To</string>
</property>
</widget>
<widget class="QMenu" name="mProjectFromStorageMenu">
<property name="title">
<string>Open From</string>
</property>
</widget>
<addaction name="mActionNewProject"/> <addaction name="mActionNewProject"/>
<addaction name="mActionOpenProject"/> <addaction name="mActionOpenProject"/>
<addaction name="mProjectFromStorageMenu"/>
<addaction name="mProjectFromTemplateMenu"/> <addaction name="mProjectFromTemplateMenu"/>
<addaction name="mRecentProjectsMenu"/> <addaction name="mRecentProjectsMenu"/>
<addaction name="mActionRevertProject"/> <addaction name="mActionRevertProject"/>
<addaction name="mActionCloseProject"/> <addaction name="mActionCloseProject"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="mActionSaveProject"/> <addaction name="mActionSaveProject"/>
<addaction name="mActionSaveProjectAs"/> <addaction name="mActionSaveProjectAs"/>
<addaction name="mProjectToStorageMenu"/>
<addaction name="mActionSaveMapAsImage"/> <addaction name="mActionSaveMapAsImage"/>
<addaction name="mActionSaveMapAsPdf"/> <addaction name="mActionSaveMapAsPdf"/>
<addaction name="mActionDxfExport"/> <addaction name="mActionDxfExport"/>
Expand Down

0 comments on commit 0c701fb

Please sign in to comment.