Goodbye SPIT plugin

This commit is contained in:
Nathan Woodrow 2015-12-04 15:37:59 +10:00
parent 9c340d7b4b
commit b39e6d1760
15 changed files with 1 additions and 2465 deletions

View File

@ -209,7 +209,7 @@ ENDIF (NOT SQLITE3_FOUND)
# optional
IF (WITH_POSTGRESQL)
FIND_PACKAGE(Postgres) # PostgreSQL provider, SPIT plugin
FIND_PACKAGE(Postgres) # PostgreSQL provider
ENDIF (WITH_POSTGRESQL)
FIND_PACKAGE(SPATIALITE REQUIRED)

View File

@ -22,10 +22,6 @@ ADD_SUBDIRECTORY(heatmap)
ADD_SUBDIRECTORY(geometry_checker)
ADD_SUBDIRECTORY(geometry_snapper)
IF (POSTGRES_FOUND)
ADD_SUBDIRECTORY(spit)
ENDIF (POSTGRES_FOUND)
IF (GRASS_FOUND)
ADD_SUBDIRECTORY(grass)
ENDIF (GRASS_FOUND)

View File

@ -1,98 +0,0 @@
########################################################
# Files
SET (SPIT_SRCS
qgsspit.cpp
../../providers/postgres/qgspgnewconnection.cpp
../../providers/postgres/qgspostgresconn.cpp
qgspgutil.cpp
qgsshapefile.cpp
)
SET (SPIT_PLUGIN_SRCS
${SPIT_SRCS}
qgsspitplugin.cpp
)
SET (SPIT_EXE_SRCS
${SPIT_SRCS}
main.cpp
)
SET (SPIT_UIS
../../ui/qgspgnewconnectionbase.ui
qgsspitbase.ui
../../ui/qgsmessageviewer.ui
../../ui/qgscredentialdialog.ui
)
SET (SPIT_EXE_MOC_HDRS
qgsspit.h
qgsshapefile.h
../../providers/postgres/qgspgnewconnection.h
../../providers/postgres/qgspostgresconn.h
)
SET (SPIT_PLUGIN_MOC_HDRS
${SPIT_EXE_MOC_HDRS}
qgsspitplugin.h
)
SET (SPIT_RCCS spit.qrc)
########################################################
# Build
QT4_WRAP_UI (SPIT_UIS_H ${SPIT_UIS})
QT4_WRAP_CPP (SPIT_PLUGIN_MOC_SRCS ${SPIT_PLUGIN_MOC_HDRS})
QT4_WRAP_CPP (SPIT_EXE_MOC_SRCS ${SPIT_EXE_MOC_HDRS})
QT4_ADD_RESOURCES(SPIT_RCC_SRCS ${SPIT_RCCS})
ADD_LIBRARY (spitplugin MODULE ${SPIT_PLUGIN_SRCS} ${SPIT_PLUGIN_MOC_SRCS} ${SPIT_RCC_SRCS} ${SPIT_UIS_H})
INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_BINARY_DIR}
../../core ../../core/auth ../../core/geometry ../../core/raster
../../gui ../../gui/auth
../../ui
${CMAKE_CURRENT_BINARY_DIR}/../../ui
../../app
../../providers/postgres
..
)
INCLUDE_DIRECTORIES(SYSTEM
${POSTGRES_INCLUDE_DIR}
${GDAL_INCLUDE_DIR}
${QCA_INCLUDE_DIR}
)
TARGET_LINK_LIBRARIES(spitplugin
${POSTGRES_LIBRARY}
qgis_core
qgis_gui
)
IF (PLUGINS_ALSO_BINARIES)
ADD_EXECUTABLE (spit ${SPIT_EXE_SRCS} ${SPIT_EXE_MOC_SRCS} ${SPIT_RCC_SRCS} ${SPIT_UIS_H})
TARGET_LINK_LIBRARIES(spit
${POSTGRES_LIBRARY}
qgis_core
qgis_gui
)
ENDIF (PLUGINS_ALSO_BINARIES)
########################################################
# Install
INSTALL(TARGETS spitplugin
RUNTIME DESTINATION ${QGIS_PLUGIN_DIR}
LIBRARY DESTINATION ${QGIS_PLUGIN_DIR})
IF (PLUGINS_ALSO_BINARIES)
INSTALL(TARGETS spit RUNTIME DESTINATION ${QGIS_BIN_DIR})
ENDIF (PLUGINS_ALSO_BINARIES)

View File

@ -1,32 +0,0 @@
/***************************************************************************
main.cpp
--------------------------------------
Date : Sun Sep 16 12:12:52 AKDT 2007
Copyright : (C) 2007 by Gary E. Sherman
Email : sherman at mrcc dot com
***************************************************************************
* *
* 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 <qapplication.h>
#include "qgsspit.h"
int main( int argc, char ** argv )
{
QApplication a( argc, argv );
// Set up the QSettings environment must be done after qapp is created
QCoreApplication::setOrganizationName( "QGIS" );
QCoreApplication::setOrganizationDomain( "qgis.org" );
QCoreApplication::setApplicationName( "QGIS2" );
QgsSpit w( 0, Qt::Window );
w.show();
a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
return a.exec();
}

View File

@ -1,56 +0,0 @@
/***************************************************************************
qgspgutil.cpp - PostgreSQL Utility Functions
--------------------------------------
Date : 2004-11-21
Copyright : (C) 2004 by Gary E.Sherman
Email : sherman at mrcc.com
***************************************************************************
* *
* 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 "qgspgutil.h"
QgsPgUtil *QgsPgUtil::instance()
{
static QgsPgUtil mInstance;
return &mInstance;
}
QgsPgUtil::QgsPgUtil()
: mPgConnection( NULL )
{
}
QgsPgUtil::~QgsPgUtil()
{
}
void QgsPgUtil::setConnection( PGconn *con )
{
mPgConnection = con;
}
PGconn *QgsPgUtil::connection()
{
return mPgConnection;
}
QString QgsPgUtil::quotedIdentifier( QString ident )
{
ident.replace( '"', "\"\"" );
return ident.prepend( '\"' ).append( '\"' );
}
QString QgsPgUtil::quotedValue( QString value )
{
if ( value.isNull() )
return "NULL";
// FIXME: use PQescapeStringConn
value.replace( '\'', "''" );
return value.prepend( '\'' ).append( '\'' );
}

View File

@ -1,68 +0,0 @@
/***************************************************************************
qgspgutil.h - PostgreSQL Utility Functions
--------------------------------------
Date : 2004-11-21
Copyright : (C) 2004 by Gary E.Sherman
Email : sherman at mrcc.com
***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifndef QGSPGUTIL_H
#define QGSPGUTIL_H
#include <map>
#include <QStringList>
extern "C"
{
#include <libpq-fe.h>
}
/*!
* \class QgsPgUtil
* \brief Class containing utility functions for working with PostgreSQL
* tables/databases
*/
class QgsPgUtil
{
public:
//! Instance function to return a pointer to the one and
//only QgsPgUtil object (QgsPgUtil is a Singleton)
static QgsPgUtil* instance();
/*!
* Set the connection to be used in database operations
* @param con Pointer to an active PostgreSQL connection
*/
void setConnection( PGconn *con );
/*!
* Get the connection currently in use for database operations
* @return Pointer to the PostgreSQL connection object
*/
PGconn *connection();
/** Double quote a PostgreSQL identifier for placement in a SQL string.
*/
static QString quotedIdentifier( QString ident );
/** Quote a value for placement in a SQL string.
*/
static QString quotedValue( QString value );
protected:
//! Protected constructor
QgsPgUtil();
//! Destructor
~QgsPgUtil();
private:
//! Initialize the list of reserved words
void initReservedWords();
//! Reserved word list
QStringList mReservedWords;
//! PostgreSQL connection
PGconn *mPgConnection;
};
#endif // QGSPGUTIL_H

View File

@ -1,466 +0,0 @@
/***************************************************************************
qgsshapefile.cpp - description
-------------------
begin : Fri Dec 19 2003
copyright : (C) 2003 by Denis Antipov
email :
***************************************************************************/
/***************************************************************************
* *
* 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 <QApplication>
#include <ogr_api.h>
#include <cpl_conv.h>
#include <QFile>
#include <QProgressDialog>
#include <QString>
#include <QLabel>
#include <QTextCodec>
#include <QFileInfo>
#include <QSettings>
#include "qgsapplication.h"
#include "cpl_error.h"
#include "qgsshapefile.h"
#include "qgis.h"
#include "qgslogger.h"
#include "qgspgutil.h"
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
#define TO8F(x) (x).toUtf8().constData()
#else
#define TO8F(x) QFile::encodeName( x ).constData()
#endif
QgsShapeFile::QgsShapeFile( const QString& name, const QString& encoding )
: ogrLayer( 0 )
, import_canceled( false )
, valid( false )
, isMulti( false )
, hasMoreDimensions( false )
, features( 0 )
, fileName( name )
{
QgsApplication::registerOgrDrivers();
QSettings settings;
CPLSetConfigOption( "SHAPE_ENCODING", settings.value( "/qgis/ignoreShapeEncoding", true ).toBool() ? "" : 0 );
ogrDataSource = OGROpen( TO8F( fileName ), false, NULL );
if ( ogrDataSource != NULL )
{
valid = true;
ogrLayer = OGR_DS_GetLayer( ogrDataSource, 0 );
features = OGR_L_GetFeatureCount( ogrLayer, true );
}
setDefaultTable();
// init the geometry types
geometries << "NULL" << "POINT" << "LINESTRING" << "POLYGON" << "MULTIPOINT"
<< "MULTILINESTRING" << "MULTIPOLYGON" << "GEOMETRYCOLLECTION";
codec = QTextCodec::codecForName( encoding.toLocal8Bit().constData() );
if ( !codec )
codec = QTextCodec::codecForLocale();
Q_ASSERT( codec );
}
QgsShapeFile::~QgsShapeFile()
{
OGR_DS_Destroy( ogrDataSource );
}
int QgsShapeFile::getFeatureCount()
{
return features;
}
bool QgsShapeFile::scanGeometries()
{
QProgressDialog *sg = new QProgressDialog();
sg->setMinimum( 0 );
sg->setMaximum( 0 );
QString label = tr( "Scanning " );
label += fileName;
sg->setLabel( new QLabel( label ) );
sg->show();
qApp->processEvents();
OGRFeatureH feat;
OGRwkbGeometryType currentType = wkbUnknown;
bool multi = false;
while (( feat = OGR_L_GetNextFeature( ogrLayer ) ) )
{
qApp->processEvents();
// feat->DumpReadable(NULL);
OGRGeometryH geom = OGR_F_GetGeometryRef( feat );
if ( geom )
{
QString gml = OGR_G_ExportToGML( geom );
// QgsDebugMsg(gml);
if ( gml.indexOf( "gml:Multi" ) > -1 )
{
// QgsDebugMsg("MULTI Part Feature detected");
multi = true;
}
OGRFeatureDefnH fDef = OGR_F_GetDefnRef( feat );
OGRwkbGeometryType gType = OGR_FD_GetGeomType( fDef );
// QgsDebugMsg(gType);
if ( gType > currentType )
{
currentType = gType;
}
if ( gType < currentType )
{
QgsDebugMsg( QString( "Encountered inconsistent geometry type %1" ).arg( gType ) );
}
}
}
// a hack to support 2.5D geometries (their wkb is equivalent to 2D variants
// except that the highest bit is set also). For now we will ignore 3rd coordinate.
hasMoreDimensions = false;
if ( currentType & wkb25DBit )
{
QgsDebugMsg( "Got a shapefile with 2.5D geometry." );
currentType = wkbFlatten( currentType );
hasMoreDimensions = true;
}
OGR_L_ResetReading( ogrLayer );
geom_type = geometries[currentType];
if ( multi && ( geom_type.indexOf( "MULTI" ) == -1 ) )
{
geom_type = "MULTI" + geom_type;
}
delete sg;
// QgsDebugMsg(QString("Geometry type is %1 (%2)").arg(currentType).arg(geometries[currentType]));
return multi;
}
QString QgsShapeFile::getFeatureClass()
{
// scan the whole layer to try to determine the geometry
// type.
qApp->processEvents();
isMulti = scanGeometries();
OGRFeatureH feat;
// skip features without geometry
while (( feat = OGR_L_GetNextFeature( ogrLayer ) ) != NULL )
{
if ( OGR_F_GetGeometryRef( feat ) )
break;
}
if ( feat )
{
OGRGeometryH geom = OGR_F_GetGeometryRef( feat );
if ( geom )
{
/* OGR doesn't appear to report geometry type properly
* for a layer containing both polygon and multipolygon
* entities
*
// get the feature type from the layer
OGRFeatureDefn * gDef = ogrLayer->GetLayerDefn();
OGRwkbGeometryType gType = gDef->GetGeomType();
geom_type = QGis::qgisFeatureTypes[gType];
*/
//geom_type = QString(geom->getGeometryName());
//geom_type = "GEOMETRY";
QgsDebugMsg( "Preparing to escape " + geom_type );
char * esc_str = new char[geom_type.length()*2+1];
PQescapeString( esc_str, geom_type.toUtf8(), geom_type.length() );
geom_type = QString( esc_str );
QgsDebugMsg( "After escaping, geom_type is : " + geom_type );
delete[] esc_str;
int numFields = OGR_F_GetFieldCount( feat );
for ( int n = 0; n < numFields; n++ )
{
OGRFieldDefnH fld = OGR_F_GetFieldDefnRef( feat, n );
column_names.push_back( codec->toUnicode( OGR_Fld_GetNameRef( fld ) ) );
switch ( OGR_Fld_GetType( fld ) )
{
case OFTInteger:
column_types.push_back( "int" );
break;
case OFTReal:
column_types.push_back( "float" );
break;
case OFTString:
column_types.push_back( QString( "varchar(%1)" ).arg( OGR_Fld_GetWidth( fld ) ) );
break;
case OFTDate:
column_types.push_back( "date" );
break;
case OFTTime:
column_types.push_back( "time" );
break;
case OFTDateTime:
column_types.push_back( "timestamp" );
break;
default:
column_types.push_back( "varchar(256)" );
break;
}
}
}
else valid = false;
OGR_F_Destroy( feat );
}
else valid = false;
OGR_L_ResetReading( ogrLayer );
return valid ? geom_type : QString::null;
}
bool QgsShapeFile::is_valid()
{
return valid;
}
QString QgsShapeFile::getName()
{
return fileName;
}
QString QgsShapeFile::getTable()
{
return table_name;
}
void QgsShapeFile::setTable( QString new_table )
{
new_table.replace( '\'', "\\'" );
new_table.replace( '\\', "\\\\" );
table_name = new_table;
}
void QgsShapeFile::setDefaultTable()
{
QFileInfo fi( fileName );
table_name = fi.baseName();
}
void QgsShapeFile::setColumnNames( QStringList columns )
{
column_names.clear();
for ( QStringList::Iterator it = columns.begin(); it != columns.end(); ++it )
{
column_names.push_back( *it );
}
}
bool QgsShapeFile::insertLayer( const QString& dbname, const QString& schema, const QString& primary_key, const QString& geom_col,
const QString& srid, PGconn * conn, QProgressDialog& pro, bool &fin,
QString& errorText )
{
Q_UNUSED( dbname );
connect( &pro, SIGNAL( canceled() ), this, SLOT( cancelImport() ) );
import_canceled = false;
bool result = true;
QString query = QString( "CREATE TABLE %1.%2(%3 SERIAL PRIMARY KEY" )
.arg( QgsPgUtil::quotedIdentifier( schema ),
QgsPgUtil::quotedIdentifier( table_name ),
QgsPgUtil::quotedIdentifier( primary_key ) );
for ( int n = 0; n < column_names.size() && result; n++ )
{
query += QString( ",%1 %2" )
.arg( QgsPgUtil::quotedIdentifier( column_names[n] ),
column_types[n] );
}
query += " )";
QgsDebugMsg( "Query string is: " + query );
PGresult *res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
// flag error and send query and error message to stdout on debug
errorText += tr( "The database gave an error while executing this SQL:\n%1\nThe error was:\n%2\n" )
.arg( query, PQresultErrorMessage( res ) );
PQclear( res );
return false;
}
else
{
PQclear( res );
}
query = QString( "SELECT AddGeometryColumn(%1,%2,%3,%4,%5,2)" )
.arg( QgsPgUtil::quotedValue( schema ),
QgsPgUtil::quotedValue( table_name ),
QgsPgUtil::quotedValue( geom_col ),
srid,
QgsPgUtil::quotedValue( geom_type ) );
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_TUPLES_OK )
{
errorText += tr( "The database gave an error while executing this SQL:\n%1\nThe error was:\n%2\n" )
.arg( query, PQresultErrorMessage( res ) );
PQclear( res );
return false;
}
else
{
PQclear( res );
}
if ( isMulti )
{
query = QString( "select constraint_name from information_schema.table_constraints where table_schema=%1 and table_name=%2 and constraint_name in ('$2','enforce_geotype_the_geom')" )
.arg( QgsPgUtil::quotedValue( schema ),
QgsPgUtil::quotedValue( table_name ) );
QStringList constraints;
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) == PGRES_TUPLES_OK )
{
for ( int i = 0; i < PQntuples( res ); i++ )
constraints.append( PQgetvalue( res, i, 0 ) );
}
PQclear( res );
if ( constraints.size() > 0 )
{
// drop the check constraint
// TODO This whole concept needs to be changed to either
// convert the geometries to the same type or allow
// multiple types in the check constraint. For now, we
// just drop the constraint...
query = QString( "alter table %1 drop constraint %2" )
.arg( QgsPgUtil::quotedIdentifier( table_name ),
QgsPgUtil::quotedIdentifier( constraints[0] ) );
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
errorText += tr( "The database gave an error while executing this SQL:\n%1\nThe error was:\n%2\n" )
.arg( query, PQresultErrorMessage( res ) );
PQclear( res );
return false;
}
PQclear( res );
}
}
//adding the data into the table
for ( int m = 0; m < features && result; m++ )
{
if ( import_canceled )
{
fin = true;
break;
}
OGRFeatureH feat = OGR_L_GetNextFeature( ogrLayer );
if ( feat )
{
OGRGeometryH geom = OGR_F_GetGeometryRef( feat );
if ( geom )
{
query = QString( "INSERT INTO %1.%2(" )
.arg( QgsPgUtil::quotedIdentifier( schema ),
QgsPgUtil::quotedIdentifier( table_name ) );
QString values = " VALUES (";
char *geo_temp;
// 'GeometryFromText' supports only 2D coordinates
// TODO for proper 2.5D support we would need to use 'GeomFromEWkt'
if ( hasMoreDimensions )
OGR_G_SetCoordinateDimension( geom, 2 );
OGR_G_ExportToWkt( geom, &geo_temp );
QString geometry( geo_temp );
CPLFree( geo_temp );
for ( int n = 0; n < column_types.size(); n++ )
{
QString val;
// FIXME: OGR_F_GetFieldAsString returns junk when called with a 8.255 float field
if ( column_types[n] == "float" )
val = qgsDoubleToString( OGR_F_GetFieldAsDouble( feat, n ) );
else
val = codec->toUnicode( OGR_F_GetFieldAsString( feat, n ) );
if ( val.isEmpty() )
val = "NULL";
else
val = QgsPgUtil::quotedValue( val );
if ( n > 0 )
{
query += ',';
values += ',';
}
query += QgsPgUtil::quotedIdentifier( column_names[n] );
values += val;
}
query += ',' + QgsPgUtil::quotedIdentifier( geom_col );
values += QString( ",st_geometryfromtext(%1,%2)" )
.arg( QgsPgUtil::quotedValue( geometry ),
srid );
query += ')' + values + ')';
if ( result )
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
// flag error and send query and error message to stdout on debug
result = false;
errorText += tr( "The database gave an error while executing this SQL:" ) + '\n';
// the query string can be quite long. Trim if necessary...
if ( query.count() > 100 )
errorText += query.left( 150 ) +
tr( "... (rest of SQL trimmed)", "is appended to a truncated SQL statement" ) +
'\n';
else
errorText += query + '\n';
errorText += tr( "The error was:\n%1\n" ).arg( PQresultErrorMessage( res ) );
errorText += '\n';
}
else
{
PQclear( res );
}
pro.setValue( pro.value() + 1 );
qApp->processEvents();
}
OGR_F_Destroy( feat );
}
}
// create the GIST index if the load was successful
if ( result )
{
// prompt user to see if they want to build the index and warn
// them about the potential time-cost
}
OGR_L_ResetReading( ogrLayer );
return result;
}
void QgsShapeFile::cancelImport()
{
import_canceled = true;
}

View File

@ -1,81 +0,0 @@
/***************************************************************************
qgsshapefile.h - description
-------------------
begin : Fri Dec 19 2003
copyright : (C) 2003 by Denis Antipov
email :
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifndef QGSSHAPEFILE_H
#define QGSSHAPEFILE_H
#include <vector>
#include <QString>
#include <QStringList>
#include <QObject>
#include <ogr_api.h>
class QProgressDialog;
class QTextCodec;
class OGRLayer;
class OGRDataSource;
extern "C"
{
#include <libpq-fe.h>
}
class QgsShapeFile : public QObject
{
Q_OBJECT
public:
QgsShapeFile( const QString& fileName, const QString& encoding = QString() );
~QgsShapeFile();
int getFeatureCount();
QString getFeatureClass();
bool insertLayer( const QString& dbname, const QString& schema, const QString& primary_key, const QString& geom_col,
const QString& srid, PGconn * conn, QProgressDialog& pro,
bool &fin, QString& errorText );
bool is_valid();
QString getName();
QString getTable();
void setTable( QString new_table );
void setDefaultTable();
QStringList column_names;
QStringList column_types;
void setColumnNames( QStringList );
bool scanGeometries();
private:
QString table_name;
OGRDataSourceH ogrDataSource;
OGRLayerH ogrLayer;
bool import_canceled;
bool valid;
//! Flag to indicate the file contains multiple geometry types
bool isMulti;
bool hasMoreDimensions;
int features;
QString fileName;
QString geom_type;
QStringList geometries;
QTextCodec* codec;
public slots:
void cancelImport();
};
#endif

View File

@ -1,927 +0,0 @@
/***************************************************************************
qgsspit.cpp - description
-------------------
begin : Fri Dec 19 2003
copyright : (C) 2003 by Denis Antipov
email :
***************************************************************************/
/***************************************************************************
* *
* 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 <QComboBox>
#include <QFileDialog>
#include <QProgressDialog>
#include <QRegExp>
#include <QFile>
#include <QSettings>
#include <QPixmap>
#include <QHeaderView>
#include <QTextCodec>
#include <QList>
#include <QTableWidgetItem>
#include <QInputDialog>
#include "qgsencodingfiledialog.h"
#include "qgspgutil.h"
#include "qgsspit.h"
#include "qgspgnewconnection.h"
#include "qgsdatasourceuri.h"
#include "qgsmessageviewer.h"
#include "qgslogger.h"
QgsSpit::QgsSpit( QWidget *parent, Qt::WindowFlags fl ) : QDialog( parent, fl )
{
setupUi( this );
// Set up the table column headers
tblShapefiles->setColumnCount( 5 );
QStringList headerText;
headerText << tr( "File Name" ) << tr( "Feature Class" ) << tr( "Features" )
<< tr( "DB Relation Name" ) << tr( "Schema" );
tblShapefiles->setHorizontalHeaderLabels( headerText );
tblShapefiles->verticalHeader()->hide();
tblShapefiles->horizontalHeader()->setStretchLastSection( true );
populateConnectionList();
restoreState();
defSrid = -1;
defGeom = "the_geom";
total_features = 0;
chkUseDefaultSrid->setChecked( true );
chkUseDefaultGeom->setChecked( true );
useDefaultSrid();
useDefaultGeom();
txtPrimaryKeyName->setText( "gid" );
schema_list << "public";
conn = NULL;
// Install a delegate that provides the combo box widget for
// changing the schema (but there can only be one delegate per
// table, so it also provides edit widgets for the textual columns).
// This needs to be done after the call to getSchema() so that
// schema_list is populated.
ShapefileTableDelegate* delegate = new ShapefileTableDelegate( tblShapefiles, schema_list );
tblShapefiles->setItemDelegate( delegate );
// Now that everything is in the table, adjust the column sizes
tblShapefiles->resizeColumnsToContents();
}
QgsSpit::~QgsSpit()
{
QSettings settings;
settings.setValue( "/Plugin-Spit/geometry", saveGeometry() );
settings.setValue( "/Plugin-Spit/lastDatabase", cmbConnections->currentText() );
if ( conn )
PQfinish( conn );
}
void QgsSpit::populateConnectionList()
{
QSettings settings;
settings.beginGroup( "/PostgreSQL/connections" );
QStringList keys = settings.childGroups();
QStringList::Iterator it = keys.begin();
cmbConnections->clear();
while ( it != keys.end() )
{
cmbConnections->addItem( *it );
++it;
}
settings.endGroup();
btnConnect->setDisabled( cmbConnections->count() == 0 );
btnEdit->setDisabled( cmbConnections->count() == 0 );
btnRemove->setDisabled( cmbConnections->count() == 0 );
cmbConnections->setDisabled( cmbConnections->count() == 0 );
}
void QgsSpit::newConnection()
{
QgsPgNewConnection *nc = new QgsPgNewConnection( this );
nc->exec();
delete nc;
populateConnectionList();
}
void QgsSpit::editConnection()
{
QgsPgNewConnection *nc = new QgsPgNewConnection( this, cmbConnections->currentText() );
nc->exec();
delete nc;
populateConnectionList();
}
void QgsSpit::removeConnection()
{
QSettings settings;
QString key = "/PostgreSQL/connections/" + cmbConnections->currentText();
QString msg = tr( "Are you sure you want to remove the [%1] connection and all associated settings?" ).arg( cmbConnections->currentText() );
QMessageBox::StandardButton result = QMessageBox::information( this, tr( "Confirm Delete" ), msg, QMessageBox::Ok | QMessageBox::Cancel );
if ( result != QMessageBox::Ok )
return;
settings.remove( key + "/host" );
settings.remove( key + "/database" );
settings.remove( key + "/port" );
settings.remove( key + "/username" );
settings.remove( key + "/password" );
settings.remove( key + "/sslmode" );
settings.remove( key + "/publicOnly" );
settings.remove( key + "/geometryColumnsOnly" );
settings.remove( key + "/save" );
settings.remove( key + "/authcfg" );
settings.remove( key );
populateConnectionList();
}
void QgsSpit::addFile()
{
QString error1 = "";
QString error2 = "";
bool exist;
bool is_error = false;
QSettings settings;
QgsEncodingFileDialog dlg( this,
tr( "Add Shapefiles" ),
settings.value( "/Plugin-Spit/last_directory" ).toString(),
tr( "Shapefiles" ) + " (*.shp);;" + tr( "All files" ) + " (*)",
settings.value( "/Plugin-Spit/last_encoding" ).toString() );
dlg.setFileMode( QFileDialog::ExistingFiles );
if ( dlg.exec() != QDialog::Accepted )
return;
QStringList files = dlg.selectedFiles();
if ( files.size() > 0 )
{
// Save the directory for future use
QFileInfo fi( files[ 0 ] );
settings.setValue( "/Plugin-Spit/last_directory", fi.absolutePath() );
settings.setValue( "/Plugin-Spit/last_encoding", dlg.encoding() );
}
// Process the files
for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it )
{
exist = false;
is_error = false;
// Check to ensure that we don't insert the same file twice
QList<QTableWidgetItem*> items = tblShapefiles->findItems( *it,
Qt::MatchExactly );
if ( items.count() > 0 )
{
exist = true;
}
if ( !exist )
{
// check other files: file.dbf and file.shx
QString name = *it;
if ( !QFile::exists( name.left( name.length() - 3 ) + "dbf" ) )
{
is_error = true;
}
else if ( !QFile::exists( name.left( name.length() - 3 ) + "shx" ) )
{
is_error = true;
}
if ( !is_error )
{
QgsShapeFile * file = new QgsShapeFile( name, dlg.encoding() );
if ( file->is_valid() )
{
/* XXX getFeatureClass actually does a whole bunch
* of things and is probably better named
* something else
*/
QString featureClass = file->getFeatureClass();
fileList.push_back( file );
QTableWidgetItem *fileNameItem = new QTableWidgetItem( name );
QTableWidgetItem *featureClassItem = new QTableWidgetItem( featureClass );
QTableWidgetItem *featureCountItem = new QTableWidgetItem( QString( "%1" ).arg( file->getFeatureCount() ) );
// Sanitize the relation name to make it pg friendly
QString relName = file->getTable().replace( QRegExp( "\\s" ), "_" );
QTableWidgetItem *dbRelationNameItem = new QTableWidgetItem( relName );
QTableWidgetItem *dbSchemaNameItem = new QTableWidgetItem( cmbSchema->currentText() );
// All items are editable except for these two
fileNameItem->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
featureCountItem->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
int row = tblShapefiles->rowCount();
tblShapefiles->insertRow( row );
tblShapefiles->setItem( row, ColFILENAME, fileNameItem );
tblShapefiles->setItem( row, ColFEATURECLASS, featureClassItem );
tblShapefiles->setItem( row, ColFEATURECOUNT, featureCountItem );
tblShapefiles->setItem( row, ColDBRELATIONNAME, dbRelationNameItem );
tblShapefiles->setItem( row, ColDBSCHEMA, dbSchemaNameItem );
total_features += file->getFeatureCount();
}
else
{
error1 += name + '\n';
delete file;
}
}
else
{
error2 += name + '\n';
}
}
}
tblShapefiles->resizeColumnsToContents();
if ( error1 != "" || error2 != "" )
{
QString message = tr( "The following Shapefile(s) could not be loaded:\n\n" );
if ( error1 != "" )
{
error1 += "----------------------------------------------------------------------------------------";
error1 += '\n' + tr( "REASON: File cannot be opened" ) + "\n\n";
}
if ( error2 != "" )
{
error2 += "----------------------------------------------------------------------------------------";
error2 += '\n' + tr( "REASON: One or both of the Shapefile files (*.dbf, *.shx) missing" ) + "\n\n";
}
QgsMessageViewer * e = new QgsMessageViewer( this );
e->setMessageAsPlainText( message + error1 + error2 );
e->exec(); // deletes itself on close
}
}
void QgsSpit::removeFile()
{
QVector<int> temp;
for ( int n = 0; n < tblShapefiles->rowCount(); n++ )
if ( tblShapefiles->isItemSelected( tblShapefiles->item( n, 0 ) ) )
{
for ( QVector<QgsShapeFile *>::iterator vit = fileList.begin(); vit != fileList.end(); ++vit )
{
if (( *vit ) ->getName() == tblShapefiles->item( n, 0 )->text() )
{
total_features -= ( *vit ) ->getFeatureCount();
fileList.erase( vit );
temp.push_back( n );
break;
}
}
}
for ( int i = temp.size() - 1; i >= 0; --i )
tblShapefiles->removeRow( temp[ i ] );
QList<QTableWidgetItem*> selected = tblShapefiles->selectedItems();
for ( int i = 0; i < selected.count(); ++i )
selected[i]->setSelected( false );
}
void QgsSpit::removeAllFiles()
{
int i = tblShapefiles->rowCount() - 1;
for ( ; i >= 0; --i )
tblShapefiles->removeRow( i );
fileList.clear();
total_features = 0;
}
void QgsSpit::useDefaultSrid()
{
if ( chkUseDefaultSrid->isChecked() )
{
defaultSridValue = spinSrid->value();
spinSrid->setValue( defSrid );
spinSrid->setEnabled( false );
}
else
{
spinSrid->setEnabled( true );
spinSrid->setValue( defaultSridValue );
}
}
void QgsSpit::useDefaultGeom()
{
if ( chkUseDefaultGeom->isChecked() )
{
defaultGeomValue = txtGeomName->text();
txtGeomName->setText( defGeom );
txtGeomName->setEnabled( false );
}
else
{
txtGeomName->setEnabled( true );
txtGeomName->setText( defaultGeomValue );
}
}
// TODO: make translation of helpinfo
void QgsSpit::helpInfo()
{
QString message = tr( "General Interface Help:" ) + "\n\n";
message += tr( "PostgreSQL Connections:" ) + '\n'
+ "----------------------------------------------------------------------------------------\n"
+ tr( "[New ...] - create a new connection" ) + '\n'
+ tr( "[Edit ...] - edit the currently selected connection" ) + '\n'
+ tr( "[Remove] - remove the currently selected connection" ) + '\n'
+ tr( "-you need to select a connection that works (connects properly) in order to import files" ) + '\n'
+ tr( "-when changing connections Global Schema also changes accordingly" ) + "\n\n"
+ tr( "Shapefile List:" ) + '\n'
+ "----------------------------------------------------------------------------------------\n"
+ tr( "[Add ...] - open a File dialog and browse to the desired file(s) to import" ) + '\n'
+ tr( "[Remove] - remove the currently selected file(s) from the list" ) + '\n'
+ tr( "[Remove All] - remove all the files in the list" ) + '\n'
+ tr( "[SRID] - Reference ID for the shapefiles to be imported" ) + '\n'
+ tr( "[Use Default (SRID)] - set SRID to -1" ) + '\n'
+ tr( "[Geometry Column Name] - name of the geometry column in the database" ) + '\n'
+ tr( "[Use Default (Geometry Column Name)] - set column name to \'the_geom\'" ) + '\n'
+ tr( "[Global Schema] - set the schema for all files to be imported into" ) + "\n\n"
+ "----------------------------------------------------------------------------------------\n"
+ tr( "[Import] - import the current shapefiles in the list" ) + '\n'
+ tr( "[Quit] - quit the program\n" )
+ tr( "[Help] - display this help dialog" ) + "\n\n";
QgsMessageViewer * e = new QgsMessageViewer( this );
e->setMessageAsPlainText( message );
e->exec(); // deletes itself on close
}
void QgsSpit::dbConnect()
{
if ( conn )
{
PQfinish( conn );
conn = NULL;
}
QSettings settings;
QString connName = cmbConnections->currentText();
if ( connName.isEmpty() )
{
QMessageBox::warning( this, tr( "Import Shapefiles" ), tr( "You need to specify a Connection first" ) );
return;
}
QString key = "/PostgreSQL/connections/" + connName;
QString database = settings.value( key + "/database" ).toString();
QString username = settings.value( key + "/username" ).toString();
QString password = settings.value( key + "/password" ).toString();
QString authcfg = settings.value( key + "/authcfg" ).toString();
bool makeConnection = true;
if ( authcfg.isEmpty() && password.isEmpty() )
{
// get password from user
password = QInputDialog::getText( this, tr( "Password for %1" ).arg( username ),
tr( "Please enter your password:" ),
QLineEdit::Password, QString::null, &makeConnection );
}
if ( makeConnection )
{
// allow null password entry in case its valid for the database
QgsDataSourceURI uri;
uri.setConnection( settings.value( key + "/host" ).toString(),
settings.value( key + "/port" ).toString(),
database,
settings.value( key + "/username" ).toString(),
password,
( QgsDataSourceURI::SSLmode ) settings.value( key + "/sslmode", QgsDataSourceURI::SSLprefer ).toInt(),
authcfg );
conn = PQconnectdb( uri.connectionInfo().toUtf8() );
}
if ( conn == NULL || PQstatus( conn ) != CONNECTION_OK )
{
QMessageBox::warning( this, tr( "Import Shapefiles" ), tr( "Connection failed - Check settings and try again" ) );
if ( conn )
{
PQfinish( conn );
conn = 0;
}
}
if ( conn )
{
PGresult *res = PQexec( conn, "SET application_name='QGIS'" );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
PQclear( res );
res = PQexec( conn, "ROLLBACK" );
}
PQclear( res );
}
schema_list.clear();
schema_list << "public";
if ( conn )
{
int errcode = PQsetClientEncoding( conn, QString( "UNICODE" ).toLocal8Bit() );
if ( errcode == 0 )
{
QgsDebugMsg( "encoding successfully set" );
}
else if ( errcode == -1 )
{
QgsDebugMsg( "error in setting encoding" );
}
else
{
QgsDebugMsg( "undefined return value from encoding setting" );
}
// Check that the database actually has postgis in it.
QString sql1 = "SELECT postgis_lib_version()"; // available from v 0.9.0 onwards
QString sql2 = "SELECT postgis_version()"; // depreciated
PGresult* ver = PQexec( conn, sql1.toUtf8() );
if ( PQresultStatus( ver ) != PGRES_TUPLES_OK )
{
// In case the version of postgis is older than 0.9.0, try the
// depreciated call before erroring out.
PQclear( ver );
ver = PQexec( conn, sql2.toUtf8() );
if ( PQresultStatus( ver ) != PGRES_TUPLES_OK )
{
QMessageBox::warning( this, tr( "PostGIS not available" ),
tr( "<p>The chosen database does not have PostGIS installed, "
"but this is required for storage of spatial data.</p>" ) );
}
}
QString schemaSql = "select nspname from pg_namespace where has_schema_privilege(nspname, 'CREATE') order by nspname";
PGresult *schemas = PQexec( conn, schemaSql.toUtf8() );
// get the schema names
if ( PQresultStatus( schemas ) == PGRES_TUPLES_OK )
{
for ( int i = 0; i < PQntuples( schemas ); i++ )
{
if ( QString( PQgetvalue( schemas, i, 0 ) ) != "public" )
schema_list << QString( PQgetvalue( schemas, i, 0 ) );
}
}
PQclear( schemas );
}
// install a new delegate with an updated schema list (rather than
// update the existing delegate because delegates don't seem able to
// store modifiable data).
ShapefileTableDelegate* delegate = new ShapefileTableDelegate( tblShapefiles, schema_list );
tblShapefiles->setItemDelegate( delegate );
cmbSchema->clear();
cmbSchema->insertItems( 0, schema_list );
cmbSchema->setCurrentIndex( 0 ); // index 0 is always "public"
}
void QgsSpit::import()
{
QList<QTableWidgetItem*> selected = tblShapefiles->selectedItems();
for ( int i = 0; i < selected.count(); ++i )
selected[i]->setSelected( false );
QString connName = cmbConnections->currentText();
QSettings settings;
bool canceled = false;
QString query;
if ( total_features == 0 )
{
QMessageBox::warning( this, tr( "Import Shapefiles" ),
tr( "You need to add shapefiles to the list first" ) );
}
else if ( conn != NULL )
{
PGresult * res;
QProgressDialog pro( tr( "Importing files" ), tr( "Cancel" ),
0, total_features, this );
pro.setValue( 0 );
pro.setLabelText( tr( "Progress" ) );
pro.setAutoClose( true );
//pro->show();
qApp->processEvents();
int count = fileList.size(), successes = 0;
for ( QVector<QgsShapeFile*>::size_type i = 0; i < fileList.size() ; i++ )
{
QString error = tr( "Problem inserting features from file:" ) + '\n' +
tblShapefiles->item( i, ColFILENAME )->text();
// if a name starts with invalid character
if ( ! tblShapefiles->item( i, ColDBRELATIONNAME )->text()[ 0 ].isLetter() )
{
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\nInvalid table name." ).arg( error ) );
pro.setValue( pro.value()
+ tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
continue;
}
// if no fields detected
if (( fileList[ i ] ->column_names ).size() == 0 )
{
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\nNo fields detected." ).arg( error ) );
pro.setValue( pro.value() +
tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
continue;
}
// duplicate field check
QStringList names_copy = fileList[ i ] ->column_names;
names_copy.push_back( txtPrimaryKeyName->text() );
names_copy.push_back( txtGeomName->text() );
QString dupl = "";
qSort( names_copy.begin(), names_copy.end() );
for ( int k = 1; k < names_copy.size(); k++ )
{
QgsDebugMsg( QString( "Checking to see if %1 == %2" ).arg( names_copy[ k ], names_copy[ k - 1 ] ) );
if ( names_copy[ k ] == names_copy[ k - 1 ] )
dupl += names_copy[ k ] + '\n';
}
// if duplicate field names exist
if ( dupl != "" )
{
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\nThe following fields are duplicates:\n%2" )
.arg( error, dupl ) );
pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
continue;
}
// Check and set destination table
fileList[ i ] ->setTable( tblShapefiles->item( i, ColDBRELATIONNAME )->text() );
pro.setLabelText( tr( "Importing files\n%1" ).arg( tblShapefiles->item( i, ColFILENAME )->text() ) );
query = QString( "SELECT f_table_name FROM geometry_columns WHERE f_table_name=%1 AND f_table_schema=%2" )
.arg( QgsPgUtil::quotedValue( tblShapefiles->item( i, ColDBRELATIONNAME )->text() ),
QgsPgUtil::quotedValue( tblShapefiles->item( i, ColDBSCHEMA )->text() ) );
res = PQexec( conn, query.toUtf8() );
bool rel_exists1 = ( PQntuples( res ) > 0 );
if ( PQresultStatus( res ) != PGRES_TUPLES_OK )
{
QString err = PQresultErrorMessage( res );
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\n<p>Error while executing the SQL:</p><p>%2</p><p>The database said:%3</p>" )
.arg( error, query, err ) );
pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
PQclear( res );
continue;
}
PQclear( res );
query = QString( "SELECT tablename FROM pg_tables WHERE tablename=%1 AND schemaname=%2" )
.arg( QgsPgUtil::quotedValue( tblShapefiles->item( i, ColDBRELATIONNAME )->text() ),
QgsPgUtil::quotedValue( tblShapefiles->item( i, ColDBSCHEMA )->text() ) );
res = PQexec( conn, query.toUtf8() );
bool rel_exists2 = ( PQntuples( res ) > 0 );
if ( PQresultStatus( res ) != PGRES_TUPLES_OK )
{
QString err = PQresultErrorMessage( res );
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\n<p>Error while executing the SQL:</p><p>%2</p><p>The database said:%3</p>" )
.arg( error, query, err ) );
pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
PQclear( res );
continue;
}
else
{
PQclear( res );
}
// begin session
query = "BEGIN";
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
QString err = PQresultErrorMessage( res );
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\n<p>Error while executing the SQL:</p><p>%2</p><p>The database said:%3</p>" )
.arg( error, query, err ) );
pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
PQclear( res );
continue;
}
else
{
PQclear( res );
}
query = "SET SEARCH_PATH TO ";
if ( !tblShapefiles->item( i, ColDBSCHEMA )->text().isEmpty() &&
tblShapefiles->item( i, ColDBSCHEMA )->text() != "public" )
query += QgsPgUtil::quotedValue( tblShapefiles->item( i, ColDBSCHEMA )->text() ) + ',';
query += QgsPgUtil::quotedValue( "public" );
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
QString err = PQresultErrorMessage( res );
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
error + '\n' +
tr( "%1\n<p>Error while executing the SQL:</p><p>%2</p><p>The database said:%3</p>" )
.arg( error, query, err ) );
pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
PQclear( res );
continue;
}
else
{
PQclear( res );
}
if ( rel_exists1 || rel_exists2 )
{
QMessageBox::StandardButton del_confirm = QMessageBox::warning( this,
tr( "Import Shapefiles - Relation Exists" ),
tr( "The Shapefile:\n%1\nwill use [%2] relation for its data,\n"
"which already exists and possibly contains data.\n"
"To avoid data loss change the \"DB Relation Name\"\n"
"for this Shapefile in the main dialog file list.\n\n"
"Do you want to overwrite the [%2] relation?" )
.arg( tblShapefiles->item( i, 0 )->text(),
tblShapefiles->item( i, ColDBRELATIONNAME )->text() ),
QMessageBox::Ok | QMessageBox::Cancel );
if ( del_confirm == QMessageBox::Ok )
{
if ( rel_exists2 )
{
query = QString( "DROP TABLE %1" )
.arg( QgsPgUtil::quotedIdentifier( tblShapefiles->item( i, ColDBRELATIONNAME )->text() ) );
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
QString err = PQresultErrorMessage( res );
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\n<p>Error while executing the SQL:</p><p>%2</p><p>The database said:%3</p>" )
.arg( error, query, err ) );
pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
PQclear( res );
continue;
}
else
{
PQclear( res );
}
}
if ( rel_exists1 )
{
query = QString( "SELECT f_geometry_column FROM geometry_columns WHERE f_table_schema=%1 AND f_table_name=%2" )
.arg( QgsPgUtil::quotedValue( tblShapefiles->item( i, ColDBSCHEMA )->text() ),
QgsPgUtil::quotedValue( tblShapefiles->item( i, ColDBRELATIONNAME )->text() ) );
QStringList columns;
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_TUPLES_OK )
{
for ( int i = 0; i < PQntuples( res ); i++ )
columns.append( PQgetvalue( res, i, 0 ) );
}
PQclear( res );
for ( int i = 0; i < columns.size(); i++ )
{
query = QString( "SELECT DropGeometryColumn(%1,%2,%3)" )
.arg( QgsPgUtil::quotedValue( tblShapefiles->item( i, ColDBSCHEMA )->text() ),
QgsPgUtil::quotedValue( tblShapefiles->item( i, ColDBRELATIONNAME )->text() ),
QgsPgUtil::quotedValue( columns[i] ) );
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
QString err = PQresultErrorMessage( res );
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\n<p>Error while executing the SQL:</p><p>%2</p><p>The database said:%3</p>" )
.arg( error, query, err ) );
pro.setValue( pro.value() + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
}
PQclear( res );
}
}
}
else
{
query = "ROLLBACK";
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
QString err = PQresultErrorMessage( res );
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\n<p>Error while executing the SQL:</p><p>%2</p><p>The database said:%3</p>" )
.arg( error, query, err ) );
}
PQclear( res );
pro.setValue( pro.value() + tblShapefiles->item( i, 2 )->text().toInt() );
continue;
}
}
// importing file here
int temp_progress = pro.value();
canceled = false;
QString key = "/PostgreSQL/connections/" + connName;
QString dbname = settings.value( key + "/database" ).toString();
QString schema = tblShapefiles->item( i, ColDBSCHEMA )->text();
QString srid = QString( "%1" ).arg( spinSrid->value() );
QString errorText;
bool layerInserted = fileList[i]->insertLayer( dbname, schema, txtPrimaryKeyName->text(), txtGeomName->text(), srid, conn, pro, canceled, errorText );
if ( layerInserted && !canceled )
{ // if file has been imported successfully
query = "COMMIT";
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
QString err = PQresultErrorMessage( res );
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\n<p>Error while executing the SQL:</p><p>%2</p><p>The database said:%3</p>" )
.arg( error, query, err ) );
PQclear( res );
continue;
}
PQclear( res );
// remove file
for ( int j = 0; j < tblShapefiles->rowCount(); j++ )
{
if ( tblShapefiles->item( j, ColFILENAME )->text() == QString( fileList[ i ] ->getName() ) )
{
tblShapefiles->selectRow( j );
removeFile();
i--;
break;
}
}
successes++;
}
else if ( !canceled )
{ // if problem importing file occured
pro.setValue( temp_progress + tblShapefiles->item( i, ColFEATURECOUNT )->text().toInt() );
QString errTxt = "<pre>" + error + "\n\n" + errorText + "</pre>";
QMessageBox::warning( this, tr( "Import Shapefiles" ), errTxt );
query = "ROLLBACK";
res = PQexec( conn, query.toUtf8() );
if ( PQresultStatus( res ) != PGRES_COMMAND_OK )
{
QString err = PQresultErrorMessage( res );
QMessageBox::warning( &pro, tr( "Import Shapefiles" ),
tr( "%1\n<p>Error while executing the SQL:</p><p>%2</p><p>The database said:%3</p>" )
.arg( error, query, err ) );
}
PQclear( res );
}
else
{ // if import was actually canceled
break;
}
}
if ( successes == count )
accept();
else
QMessageBox::information( &pro, tr( "Import Shapefiles" ),
tr( "%1 of %2 shapefiles could not be imported." ).arg( count - successes ).arg( count ) );
}
else
{
QMessageBox::warning( this, tr( "Import Shapefiles" ), tr( "You need to specify a Connection first" ) );
}
}
void QgsSpit::restoreState()
{
QSettings settings;
restoreGeometry( settings.value( "/Plugin-Spit/geometry" ).toByteArray() );
cmbConnections->setCurrentIndex( cmbConnections->findText( settings.value( "/Plugin-Spit/lastDatabase" ).toString() ) );
}
QWidget *ShapefileTableDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &,
const QModelIndex & index ) const
{
switch ( index.column() )
{
case 4:
{
QComboBox* editor = new QComboBox( parent );
editor->setSizeAdjustPolicy( QComboBox::AdjustToContents );
editor->installEventFilter( const_cast<ShapefileTableDelegate*>( this ) );
return editor;
}
case 1:
case 3:
{
QLineEdit* editor = new QLineEdit( parent );
editor->installEventFilter( const_cast<ShapefileTableDelegate*>( this ) );
return editor;
}
}
return NULL;
}
void ShapefileTableDelegate::setEditorData( QWidget *editor,
const QModelIndex &index ) const
{
switch ( index.column() )
{
case 4:
{
// Create a combobox and populate with the list of schemas
QComboBox *comboBox = static_cast<QComboBox*>( editor );
comboBox->insertItems( 0, mSchemaList );
// Get the text from the table and use to set the selected text
// in the combo box.
QString text = index.model()->data( index, Qt::DisplayRole ).toString();
comboBox->setCurrentIndex( mSchemaList.indexOf( text ) );
break;
}
case 1:
case 3:
{
QString text = index.model()->data( index, Qt::DisplayRole ).toString();
QLineEdit *lineEdit = static_cast<QLineEdit*>( editor );
lineEdit->setText( text );
break;
}
}
}
void ShapefileTableDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index ) const
{
switch ( index.column() )
{
case 4:
{
QComboBox *comboBox = static_cast<QComboBox*>( editor );
QString text = comboBox->currentText();
model->setData( index, text );
break;
}
case 1:
case 3:
{
QLineEdit *lineEdit = static_cast<QLineEdit*>( editor );
QString text = lineEdit->text();
model->setData( index, text );
break;
}
}
}
void ShapefileTableDelegate::updateEditorGeometry( QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */ ) const
{
editor->setGeometry( option.rect );
}

View File

@ -1,150 +0,0 @@
#ifndef QGSSPIT_H
#define QGSSPIT_H
/***************************************************************************
qgsspit.h - description
-------------------
begin : Fri Dec 19 2003
copyright : (C) 2003 by Denis Antipov
: (C) 2004 by Gary Sherman
email :
***************************************************************************/
/***************************************************************************
* *
* 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 <vector>
#include <algorithm>
#include <QStringList>
#include <QString>
#include <QItemDelegate>
#include "qgsshapefile.h"
#include "ui_qgsspitbase.h"
class QTableWidgetItem;
extern "C"
{
#include <libpq-fe.h>
}
class QgsSpit : public QDialog, private Ui::QgsSpitBase
{
Q_OBJECT
public:
QgsSpit( QWidget *parent = 0, Qt::WindowFlags fl = 0 );
~QgsSpit();
//! Populate the list of available database connections
void populateConnectionList();
//! Connect to the selected database
void dbConnect();
//! Return a list of selected tables
QStringList selectedTables();
//! Return the connection info
QString connectionInfo();
//! Create a new PostgreSQL connection
void newConnection();
//! Edit a PostgreSQL connection
void editConnection();
//! Remove a PostgreSQL connection
void removeConnection();
//! Add file to the queue
void addFile();
//! Remove selected file from the queue
void removeFile();
//! Remove all files from the queue
void removeAllFiles();
//! Use the default SRID (Spatial Reference ID)
void useDefaultSrid();
//! Use the default geometry field name (the_geom)
void useDefaultGeom();
//! Show brief help
void helpInfo();
//! Import shapefiles into PostgreSQL
void import();
public slots:
// In porting from Qt3 to Qt4 it was easier to have these small
// redirects for the widget signals rather than rename the existing
// functions (which would be been connected to the widgets using the
// Qt3 designer signal/slot connection mechanism), in case you were
// wondering.
void on_btnConnect_clicked() { dbConnect(); }
void on_btnEdit_clicked() { editConnection(); }
void on_btnNew_clicked() { newConnection(); }
void on_btnRemove_clicked() { removeConnection(); }
void on_buttonBox_accepted() { import(); }
void on_buttonBox_helpRequested() { helpInfo(); }
void on_buttonBox_rejected() { reject(); }
void on_btnAddFile_clicked() { addFile(); }
void on_btnRemoveAll_clicked() { removeAllFiles(); }
void on_btnRemoveFile_clicked() { removeFile(); }
void on_tblShapefiles_itemClicked( QTableWidgetItem* item )
{ tblShapefiles->editItem( item ); }
// When the user changes the selected connection, update the schema list
void on_chkUseDefaultSrid_toggled( bool ) { useDefaultSrid(); }
void on_chkUseDefaultGeom_toggled( bool ) { useDefaultGeom(); }
private:
void restoreState();
// Enum of table columns indexes
enum ShpTableColumns
{
ColFILENAME = 0,
ColFEATURECLASS = 1, // is editable
ColFEATURECOUNT = 2,
ColDBRELATIONNAME = 3, // is editable
ColDBSCHEMA = 4 // is editable
};
PGconn* checkConnection();
QStringList schema_list;
QStringList geometry_list;
int total_features;
QVector<QgsShapeFile *> fileList;
int defSrid;
QString defGeom;
int defaultSridValue;
QString defaultGeomValue;
PGconn *conn;
};
// We want to provide combo boxes in the table of shape files to
// load. Qt4 doesn't provide an 'out-of-the-box' way to do this
// (unlike Qt3), so we have to use the Qt4 delegate technique to
// provide combo boxes for the table, hence this class...
class ShapefileTableDelegate : public QItemDelegate
{
Q_OBJECT
public:
ShapefileTableDelegate( QObject *parent, QStringList& schema_list )
: mSchemaList( schema_list )
{ Q_UNUSED( parent ); }
QWidget *createEditor( QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index ) const override;
void setEditorData( QWidget *editor, const QModelIndex &index ) const override;
void setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index ) const override;
void updateEditorGeometry( QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index ) const override;
void updateSchemaList( QStringList& schema_list, QString currentSchema );
private:
QStringList mSchemaList;
};
#endif

View File

@ -1,322 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsSpitBase</class>
<widget class="QDialog" name="QgsSpitBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>695</width>
<height>520</height>
</rect>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>SPIT - Shapefile to PostGIS Import Tool</string>
</property>
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<layout class="QGridLayout">
<property name="margin">
<number>9</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>PostgreSQL connections</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QComboBox" name="cmbConnections">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="btnConnect">
<property name="toolTip">
<string>Connect to PostGIS</string>
</property>
<property name="whatsThis">
<string>Connect to PostGIS</string>
</property>
<property name="text">
<string>Connect</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnNew">
<property name="toolTip">
<string>Create a new PostGIS connection</string>
</property>
<property name="whatsThis">
<string>Create a new PostGIS connection</string>
</property>
<property name="text">
<string>New</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnEdit">
<property name="toolTip">
<string>Edit the current PostGIS connection</string>
</property>
<property name="whatsThis">
<string>Edit the current PostGIS connection</string>
</property>
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRemove">
<property name="toolTip">
<string>Remove the current PostGIS connection</string>
</property>
<property name="whatsThis">
<string>Remove the current PostGIS connection</string>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Import options and shapefile list</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_1">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Geometry column name</string>
</property>
<property name="buddy">
<cstring>txtGeomName</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtGeomName"/>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="chkUseDefaultGeom">
<property name="toolTip">
<string>Set the geometry column name to the default value</string>
</property>
<property name="whatsThis">
<string>Set the geometry column name to the default value</string>
</property>
<property name="text">
<string>Use default geometry column name</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>SRID</string>
</property>
<property name="buddy">
<cstring>spinSrid</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinSrid">
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>1000000000</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="chkUseDefaultSrid">
<property name="toolTip">
<string>Set the SRID to the default value</string>
</property>
<property name="whatsThis">
<string>Set the SRID to the default value</string>
</property>
<property name="text">
<string>Use default SRID</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Primary key column name</string>
</property>
<property name="buddy">
<cstring>txtPrimaryKeyName</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="txtPrimaryKeyName"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="textLabel1_4">
<property name="text">
<string>Global schema</string>
</property>
<property name="buddy">
<cstring>cmbSchema</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="cmbSchema">
<property name="minimumSize">
<size>
<width>200</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string/>
</property>
<property name="duplicatesEnabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="tblShapefiles">
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="btnAddFile">
<property name="toolTip">
<string>Add a shapefile to the list of files to be imported</string>
</property>
<property name="whatsThis">
<string>Add a shapefile to the list of files to be imported</string>
</property>
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="btnRemoveFile">
<property name="toolTip">
<string>Remove the selected shapefile from the import list</string>
</property>
<property name="whatsThis">
<string>Remove the selected shapefile from the import list</string>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="btnRemoveAll">
<property name="toolTip">
<string>Remove all the shapefiles from the import list</string>
</property>
<property name="whatsThis">
<string>Remove all the shapefiles from the import list</string>
</property>
<property name="text">
<string>Remove All</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<tabstops>
<tabstop>cmbConnections</tabstop>
<tabstop>btnConnect</tabstop>
<tabstop>btnNew</tabstop>
<tabstop>btnEdit</tabstop>
<tabstop>btnRemove</tabstop>
<tabstop>txtGeomName</tabstop>
<tabstop>chkUseDefaultGeom</tabstop>
<tabstop>spinSrid</tabstop>
<tabstop>chkUseDefaultSrid</tabstop>
<tabstop>txtPrimaryKeyName</tabstop>
<tabstop>cmbSchema</tabstop>
<tabstop>tblShapefiles</tabstop>
<tabstop>btnAddFile</tabstop>
<tabstop>btnRemoveFile</tabstop>
<tabstop>btnRemoveAll</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources>
<include location="spit.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -1,182 +0,0 @@
/***************************************************************************
qgsspitplugin.cpp
Shapefile to PostgreSQL Import Tool plugin
-------------------
begin : Jan 30, 2004
copyright : (C) 2004 by Gary E.Sherman
email : sherman at mrcc.com
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
// includes
#include <vector>
#include <QAction>
#include <QFile>
#include <QMenu>
#include "qgisinterface.h"
#include "qgsapplication.h"
#include "qgsspitplugin.h"
#include "qgsspit.h"
static const QString name_ = QObject::tr( "SPIT" );
static const QString description_ = QObject::tr( "Shapefile to PostgreSQL/PostGIS Import Tool" );
static const QString category_ = QObject::tr( "Database" );
static const QString version_ = QObject::tr( "Version 0.1" );
static const QgisPlugin::PLUGINTYPE type_ = QgisPlugin::UI;
static const QString icon_ = ":/spit.png";
/**
* Constructor for the plugin. The plugin is passed a pointer to the main app
* and an interface object that provides access to exposed functions in QGIS.
* @param qgis Pointer to the QGIS main window
* @parma _qI Pointer to the QGIS interface object
*/
QgsSpitPlugin::QgsSpitPlugin( QgisInterface * _qI )
: QgisPlugin( name_, description_, category_, version_, type_ )
, qgisMainWindow( _qI->mainWindow() )
, qI( _qI )
, spitAction( 0 )
{
}
QgsSpitPlugin::~QgsSpitPlugin()
{
}
/*
* Initialize the GUI interface for the plugin
*/
void QgsSpitPlugin::initGui()
{
delete spitAction;
// Create the action for tool
spitAction = new QAction( QIcon(), tr( "&Import Shapefiles to PostgreSQL" ), this );
spitAction->setObjectName( "spitAction" );
setCurrentTheme( "" );
spitAction->setWhatsThis( tr( "Import shapefiles into a PostGIS-enabled PostgreSQL database. "
"The schema and field names can be customized on import" ) );
// Connect the action to the spit slot
connect( spitAction, SIGNAL( triggered() ), this, SLOT( spit() ) );
// Add the icon to the toolbar and to the plugin menu
qI->addDatabaseToolBarIcon( spitAction );
qI->addPluginToDatabaseMenu( tr( "&Spit" ), spitAction );
// this is called when the icon theme is changed
connect( qI, SIGNAL( currentThemeChanged( QString ) ), this, SLOT( setCurrentTheme( QString ) ) );
}
// Slot called when the shapefile to postgres menu item is triggered
void QgsSpitPlugin::spit()
{
QgsSpit *spitDlg = new QgsSpit( qgisMainWindow, Qt::Window );
spitDlg->setAttribute( Qt::WA_DeleteOnClose );
spitDlg->show();
}
// Unload the plugin by cleaning up the GUI
void QgsSpitPlugin::unload()
{
// remove the GUI
qI->removeDatabaseToolBarIcon( spitAction );
qI->removePluginDatabaseMenu( tr( "&Spit" ), spitAction );
delete spitAction;
spitAction = 0;
}
//! Set icons to the current theme
void QgsSpitPlugin::setCurrentTheme( const QString& theThemeName )
{
Q_UNUSED( theThemeName );
QString myCurThemePath = QgsApplication::activeThemePath() + "/plugins/spit.png";
QString myDefThemePath = QgsApplication::defaultThemePath() + "/plugins/spit.png";
QString myQrcPath = ":/spit.png";
if ( spitAction )
{
if ( QFile::exists( myCurThemePath ) )
{
spitAction->setIcon( QIcon( myCurThemePath ) );
}
else if ( QFile::exists( myDefThemePath ) )
{
spitAction->setIcon( QIcon( myDefThemePath ) );
}
else if ( QFile::exists( myQrcPath ) )
{
spitAction->setIcon( QIcon( myQrcPath ) );
}
else
{
spitAction->setIcon( QIcon() );
}
}
}
/**
* Required extern functions needed for every plugin
* These functions can be called prior to creating an instance
* of the plugin class
*/
// Class factory to return a new instance of the plugin class
QGISEXTERN QgisPlugin * classFactory( QgisInterface * qI )
{
return new QgsSpitPlugin( qI );
}
// Return the name of the plugin
QGISEXTERN QString name()
{
return name_;
}
// Return the description
QGISEXTERN QString description()
{
return description_;
}
// Return the category
QGISEXTERN QString category()
{
return category_;
}
// Return the type (either UI or MapLayer plugin)
QGISEXTERN int type()
{
return type_;
}
// Return the version
QGISEXTERN QString version()
{
return version_;
}
QGISEXTERN QString icon()
{
return icon_;
}
// Delete ourself
QGISEXTERN void unload( QgisPlugin * p )
{
delete p;
}

View File

@ -1,73 +0,0 @@
/***************************************************************************
qgsspitplugin.h
Shapefile to PostgreSQL Import Tool plugin
-------------------
begin : Jan 30, 2004
copyright : (C) 2004 by Gary E.Sherman
email : sherman at mrcc.com
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifndef QGSSPITPLUGIN_H
#define QGSSPITPLUGIN_H
#include "../qgisplugin.h"
extern "C"
{
#include <libpq-fe.h>
}
class QAction;
#include <QObject>
/**
* \class QgsSpitPlugin
* \brief SPIT PostgreSQL/PostGIS plugin for QGIS
*
*/
class QgsSpitPlugin: public QObject, public QgisPlugin
{
Q_OBJECT public:
/**
* Constructor for a plugin. The QgisInterface pointer is passed by
* QGIS when it attempts to instantiate the plugin.
* @param qI Pointer to the QgisInterface object.
*/
explicit QgsSpitPlugin( QgisInterface * qI );
//! Destructor
virtual ~ QgsSpitPlugin();
public slots:
//! init the gui
virtual void initGui() override;
void spit();
//! unload the plugin
void unload() override;
//! update the plugins theme when the app tells us its theme is changed
void setCurrentTheme( const QString& theThemeName );
private:
//! Name of the plugin
QString pName;
//! Version
QString pVersion;
//! Descrption of the plugin
QString pDescription;
//! Category of the plugin
QString pCategory;
//! Pionter to QGIS main application object
QWidget *qgisMainWindow;
//! Pointer to the QGIS interface object
QgisInterface *qI;
//! Pointer to the QAction used in the menu and on the toolbar
QAction *spitAction;
};
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/" >
<file>spit.png</file>
</qresource>
</RCC>