555 changes: 555 additions & 0 deletions src/providers/mssql/qgsmssqldataitems.cpp

Large diffs are not rendered by default.

117 changes: 117 additions & 0 deletions src/providers/mssql/qgsmssqldataitems.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/***************************************************************************
qgsmssqldataitems.h - description
-------------------
begin : 2011-10-08
copyright : (C) 2011 by Tamas Szekeres
email : szekerest at gmail.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 QGSMSSQLDATAITEMS_H
#define QGSMSSQLDATAITEMS_H

#include "qgsdataitem.h"

#include "qgsmssqlsourceselect.h"

class QgsMssqlRootItem;
class QgsMssqlConnectionItem;
class QgsMssqlSchemaItem;
class QgsMssqlLayerItem;

class QgsMssqlRootItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsMssqlRootItem( QgsDataItem* parent, QString name, QString path );
~QgsMssqlRootItem();

QVector<QgsDataItem*> createChildren();

virtual QWidget * paramWidget();

virtual QList<QAction*> actions();

public slots:
void connectionsChanged();
void newConnection();
};

class QgsMssqlConnectionItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsMssqlConnectionItem( QgsDataItem* parent, QString name, QString path );
~QgsMssqlConnectionItem();

QVector<QgsDataItem*> createChildren();
virtual bool equal( const QgsDataItem *other );
virtual QList<QAction*> actions();

virtual bool acceptDrop() { return true; }
virtual bool handleDrop( const QMimeData * data, Qt::DropAction action );
void refresh();

QString connInfo() const { return mConnInfo; };

signals:
void addGeometryColumn( QgsMssqlLayerProperty );

public slots:
void editConnection();
void deleteConnection();

void setLayerType( QgsMssqlLayerProperty layerProperty );

private:
QString mConnInfo;
QString mService;
QString mHost;
QString mDatabase;
QString mUsername;
QString mPassword;
bool mUseGeometryColumns;
};

class QgsMssqlSchemaItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsMssqlSchemaItem( QgsDataItem* parent, QString name, QString path );
~QgsMssqlSchemaItem();

QVector<QgsDataItem*> createChildren();

QgsMssqlLayerItem* addLayer( QgsMssqlLayerProperty layerProperty, bool refresh );
void refresh() {}; // do not refresh directly
void addLayers(QgsDataItem* newLayers);
};

class QgsMssqlLayerItem : public QgsLayerItem
{
Q_OBJECT

public:
QgsMssqlLayerItem( QgsDataItem* parent, QString name, QString path, QgsLayerItem::LayerType layerType, QgsMssqlLayerProperty layerProperties );
~QgsMssqlLayerItem();

QString createUri();

QgsMssqlLayerItem* createClone();
bool Used;

private:
QgsMssqlLayerProperty mLayerProperty;
};

#endif // QGSMSSQLDATAITEMS_H
562 changes: 562 additions & 0 deletions src/providers/mssql/qgsmssqlgeometryparser.cpp

Large diffs are not rendered by default.

176 changes: 176 additions & 0 deletions src/providers/mssql/qgsmssqlnewconnection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/***************************************************************************
qgsmssqlnewconnection.cpp - description
-------------------
begin : 2011-10-08
copyright : (C) 2011 by Tamas Szekeres
email : szekerest at gmail.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 <QSettings>
#include <QMessageBox>
#include <QInputDialog>

#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlError>

#include "qgsmssqlnewconnection.h"
#include "qgsmssqlprovider.h"
#include "qgscontexthelp.h"

QgsMssqlNewConnection::QgsMssqlNewConnection( QWidget *parent, const QString& connName, Qt::WFlags fl )
: QDialog( parent, fl ), mOriginalConnName( connName )
{
setupUi( this );

if ( !connName.isEmpty() )
{
// populate the dialog with the information stored for the connection
// populate the fields with the stored setting parameters
QSettings settings;

QString key = "/MSSQL/connections/" + connName;
txtService->setText( settings.value( key + "/service" ).toString() );
txtHost->setText( settings.value( key + "/host" ).toString() );
txtDatabase->setText( settings.value( key + "/database" ).toString() );
cb_geometryColumns->setChecked( settings.value( key + "/geometryColumns", true ).toBool() );
cb_allowGeometrylessTables->setChecked( settings.value( key + "/allowGeometrylessTables", true ).toBool() );
cb_useEstimatedMetadata->setChecked( settings.value( key + "/estimatedMetadata", false ).toBool() );

if ( settings.value( key + "/saveUsername" ).toString() == "true" )
{
txtUsername->setText( settings.value( key + "/username" ).toString() );
chkStoreUsername->setChecked( true );
}

if ( settings.value( key + "/savePassword" ).toString() == "true" )
{
txtPassword->setText( settings.value( key + "/password" ).toString() );
chkStorePassword->setChecked( true );
}

// Old save setting
if ( settings.contains( key + "/save" ) )
{
txtUsername->setText( settings.value( key + "/username" ).toString() );
chkStoreUsername->setChecked( !txtUsername->text().isEmpty() );

if ( settings.value( key + "/save" ).toString() == "true" )
txtPassword->setText( settings.value( key + "/password" ).toString() );

chkStorePassword->setChecked( true );
}

txtName->setText( connName );
}
}
/** Autoconnected SLOTS **/
void QgsMssqlNewConnection::accept()
{
QSettings settings;
QString baseKey = "/MSSQL/connections/";
settings.setValue( baseKey + "selected", txtName->text() );

if ( chkStorePassword->isChecked() &&
QMessageBox::question( this,
tr( "Saving passwords" ),
tr( "WARNING: You have opted to save your password. It will be stored in plain text in your project files and in your home directory on Unix-like systems, or in your user profile on Windows. If you do not want this to happen, please press the Cancel button.\n" ),
QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel )
{
return;
}

// warn if entry was renamed to an existing connection
if (( mOriginalConnName.isNull() || mOriginalConnName != txtName->text() ) &&
( settings.contains( baseKey + txtName->text() + "/service" ) ||
settings.contains( baseKey + txtName->text() + "/host" ) ) &&
QMessageBox::question( this,
tr( "Save connection" ),
tr( "Should the existing connection %1 be overwritten?" ).arg( txtName->text() ),
QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel )
{
return;
}

// on rename delete the original entry first
if ( !mOriginalConnName.isNull() && mOriginalConnName != txtName->text() )
{

settings.remove( baseKey + mOriginalConnName );
}

baseKey += txtName->text();
settings.setValue( baseKey + "/service", txtService->text() );
settings.setValue( baseKey + "/host", txtHost->text() );
settings.setValue( baseKey + "/database", txtDatabase->text() );
settings.setValue( baseKey + "/username", chkStoreUsername->isChecked() ? txtUsername->text() : "" );
settings.setValue( baseKey + "/password", chkStorePassword->isChecked() ? txtPassword->text() : "" );
settings.setValue( baseKey + "/saveUsername", chkStoreUsername->isChecked() ? "true" : "false" );
settings.setValue( baseKey + "/savePassword", chkStorePassword->isChecked() ? "true" : "false" );
settings.setValue( baseKey + "/geometryColumns", cb_geometryColumns->isChecked() );
settings.setValue( baseKey + "/allowGeometrylessTables", cb_allowGeometrylessTables->isChecked() );
settings.setValue( baseKey + "/estimatedMetadata", cb_useEstimatedMetadata->isChecked() );

QDialog::accept();
}

void QgsMssqlNewConnection::on_btnConnect_clicked()
{
testConnection();
}

/** end Autoconnected SLOTS **/

QgsMssqlNewConnection::~QgsMssqlNewConnection()
{
}

void QgsMssqlNewConnection::testConnection()
{
if (txtService->text().isEmpty())
{
if (txtHost->text().isEmpty())
{
QMessageBox::information( this,
tr( "Test connection" ),
tr( "Connection failed - Host name hasn't been specified.\n\n" ) );
return;
}

if (txtDatabase->text().isEmpty())
{
QMessageBox::information( this,
tr( "Test connection" ),
tr( "Connection failed - Database name hasn't been specified.\n\n" ) );
return;
}
}

QSqlDatabase db = QgsMssqlProvider::GetDatabase( txtService->text().trimmed(),
txtHost->text().trimmed(), txtDatabase->text().trimmed(),
txtUsername->text().trimmed(), txtPassword->text().trimmed() );

if ( db.isOpen() )
db.close();

if ( !db.open() )
{
QMessageBox::information( this,
tr( "Test connection" ),
db.lastError( ).text( ) );
}
else
{
QMessageBox::information( this,
tr( "Test connection" ),
tr( "Connection to %1 was successful" ).arg( txtDatabase->text() ) );
}
}
45 changes: 45 additions & 0 deletions src/providers/mssql/qgsmssqlnewconnection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/***************************************************************************
qgsmssqlnewconnection.h - description
-------------------
begin : 2011-10-08
copyright : (C) 2011 by Tamas Szekeres
email : szekerest at gmail.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 QGSMSSQLNEWCONNECTION_H
#define QGSMSSQLNEWCONNECTION_H
#include "ui_qgsmssqlnewconnectionbase.h"
#include "qgisgui.h"
#include "qgscontexthelp.h"

/*! \class QgsMssqlNewConnection
* \brief Dialog to allow the user to configure and save connection
* information for an MSSQL database
*/
class QgsMssqlNewConnection : public QDialog, private Ui::QgsMssqlNewConnectionBase
{
Q_OBJECT
public:
//! Constructor
QgsMssqlNewConnection( QWidget *parent = 0, const QString& connName = QString::null, Qt::WFlags fl = QgisGui::ModalDialogFlags );
//! Destructor
~QgsMssqlNewConnection();
//! Tests the connection using the parameters supplied
void testConnection();
public slots:
void accept();
void on_btnConnect_clicked();
void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }
private:
QString mOriginalConnName; //store initial name to delete entry in case of rename
};

#endif // QGSMSSQLNEWCONNECTION_H
1,541 changes: 1,541 additions & 0 deletions src/providers/mssql/qgsmssqlprovider.cpp

Large diffs are not rendered by default.

348 changes: 348 additions & 0 deletions src/providers/mssql/qgsmssqlprovider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,348 @@
/***************************************************************************
qgsmssqlprovider.h - Data provider for mssql server
-------------------
begin : 2011-10-08
copyright : (C) 2011 by Tamas Szekeres
email : szekerest at gmail.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 "qgsvectordataprovider.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsvectorlayerimport.h"

#include <QStringList>
#include <QFile>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>

class QgsFeature;
class QgsField;
class QFile;
class QTextStream;

#include "qgsdatasourceuri.h"
#include "qgsgeometry.h"


/**
\class QgsMssqlGeometryParser
\brief Geometry parser for SqlGeometry/SqlGeography.
*
*/

class QgsMssqlGeometryParser
{

protected:
unsigned char* pszData;
unsigned char* pszWkb;
int nWkbLen;
int nWkbMaxLen;
/* byte order */
char chByteOrder;
/* serialization properties */
char chProps;
/* point array */
int nPointSize;
int nPointPos;
int nNumPoints;
/* figure array */
int nFigurePos;
int nNumFigures;
/* shape array */
int nShapePos;
int nNumShapes;
int nSRSId;

protected:
void CopyBytes(void* src, int len);
void CopyPoint(int iPoint);
void ReadPoint(int iShape);
void ReadMultiPoint(int iShape);
void ReadLineString(int iShape);
void ReadMultiLineString(int iShape);
void ReadPolygon(int iShape);
void ReadMultiPolygon(int iShape);
void ReadGeometryCollection(int iShape);

public:
QgsMssqlGeometryParser();
unsigned char* ParseSqlGeometry(unsigned char* pszInput, int nLen);
int GetSRSId() { return nSRSId; };
int GetWkbLen() { return nWkbLen; };
void DumpMemoryToLog(char* pszMsg, unsigned char* pszInput, int nLen);
};


/**
\class QgsMssqlProvider
\brief Data provider for mssql server.
*
*/
class QgsMssqlProvider : public QgsVectorDataProvider
{
Q_OBJECT

public:

QgsMssqlProvider( QString uri = QString() );

virtual ~QgsMssqlProvider();

static QSqlDatabase GetDatabase(QString driver, QString host, QString database, QString username, QString password);
static bool OpenDatabase(QSqlDatabase db);

/* Implementation of functions from QgsVectorDataProvider */

/**
* Returns the permanent storage type for this layer as a friendly name.
*/
virtual QString storageType() const;

/**
* Sub-layers handled by this provider, in order from bottom to top
*
* Sub-layers are used when the provider's source can combine layers
* it knows about in some way before it hands them off to the provider.
*/
virtual QStringList subLayers() const;

/** Select features based on a bounding rectangle. Features can be retrieved with calls to nextFeature.
* @param fetchAttributes list of attributes which should be fetched
* @param rect spatial filter
* @param fetchGeometry true if the feature geometry should be fetched
* @param useIntersect true if an accurate intersection test should be used,
* false if a test based on bounding box is sufficient
*/
virtual void select( QgsAttributeList fetchAttributes = QgsAttributeList(),
QgsRectangle rect = QgsRectangle(),
bool fetchGeometry = true,
bool useIntersect = false );

/**
* Get the next feature resulting from a select operation.
* @param feature feature which will receive data from the provider
* @return true when there was a feature to fetch, false when end was hit
*
* mFile should be open with the file pointer at the record of the next
* feature, or EOF. The feature found on the current line is parsed.
*/
virtual bool nextFeature( QgsFeature& feature );

/**
* Gets the feature at the given feature ID.
* @param featureId id of the feature
* @param feature feature which will receive the data
* @param fetchGeoemtry if true, geometry will be fetched from the provider
* @param fetchAttributes a list containing the indexes of the attribute fields to copy
* @return True when feature was found, otherwise false
*/
virtual bool featureAtId( QgsFeatureId featureId,
QgsFeature& feature,
bool fetchGeometry = true,
QgsAttributeList fetchAttributes = QgsAttributeList() );

/**
* Get feature type.
* @return int representing the feature type
*/
virtual QGis::WkbType geometryType() const;

/**
* Number of features in the layer
* @return long containing number of features
*/
virtual long featureCount() const;

/**
* Number of attribute fields for a feature in the layer
*/
virtual uint fieldCount() const;

/** update the extent, feature count, wkb type and srid for this layer */
void UpdateStatistics();

/**
* Return a map of indexes with field names for this layer
* @return map of fields
*/
virtual const QgsFieldMap & fields() const;

/** Restart reading features from previous select operation */
virtual void rewind();

/** Returns a bitmask containing the supported capabilities
Note, some capabilities may change depending on whether
a spatial filter is active on this provider, so it may
be prudent to check this value per intended operation.
*/
virtual int capabilities() const;


/* Implementation of functions from QgsDataProvider */

/** return a provider name
Essentially just returns the provider key. Should be used to build file
dialogs so that providers can be shown with their supported types. Thus
if more than one provider supports a given format, the user is able to
select a specific provider to open that file.
@note
Instead of being pure virtual, might be better to generalize this
behavior and presume that none of the sub-classes are going to do
anything strange with regards to their name or description?
*/
QString name() const;

/** return description
Return a terse string describing what the provider is.
@note
Instead of being pure virtual, might be better to generalize this
behavior and presume that none of the sub-classes are going to do
anything strange with regards to their name or description?
*/
QString description() const;

/**
* Return the extent for this data layer
*/
virtual QgsRectangle extent();

/**
* Returns true if this is a valid data source
*/
bool isValid();

/**Writes a list of features to the database*/
virtual bool addFeatures( QgsFeatureList & flist );

/**Deletes a feature*/
virtual bool deleteFeatures( const QgsFeatureIds & id );

/**
* Adds new attributes
* @param attributes list of new attributes
* @return true in case of success and false in case of failure
* @note added in 1.2
*/
virtual bool addAttributes( const QList<QgsField> &attributes );

/**
* Deletes existing attributes
* @param attributes a set containing names of attributes
* @return true in case of success and false in case of failure
*/
virtual bool deleteAttributes( const QgsAttributeIds &attributes );

/**Changes attribute values of existing features */
virtual bool changeAttributeValues( const QgsChangedAttributesMap & attr_map );

/**Changes existing geometries*/
virtual bool changeGeometryValues( QgsGeometryMap & geometry_map );

/**
* Create a spatial index for the current layer
*/
virtual bool createSpatialIndex();

/**Create an attribute index on the datasource*/
virtual bool createAttributeIndex( int field );

/** convert a QgsField to work with MSSQL */
static bool convertField( QgsField &field );

/** Import a vector layer into the database */
static QgsVectorLayerImport::ImportError createEmptyLayer(
const QString& uri,
const QgsFieldMap &fields,
QGis::WkbType wkbType,
const QgsCoordinateReferenceSystem *srs,
bool overwrite,
QMap<int, int> *oldToNewAttrIdxMap,
QString *errorMessage = 0,
const QMap<QString, QVariant> *options = 0
);

virtual QgsCoordinateReferenceSystem crs();

protected:
/** loads fields from input file to member attributeFields */
QVariant::Type DecodeODBCType(int sqltype);
void loadFields();
void loadMetadata();

private:

//! Fields
QgsFieldMap mAttributeFields;

QgsMssqlGeometryParser parser;

int mFieldCount; // Note: this includes field count for wkt field

//! Layer extent
QgsRectangle mExtent;

bool mValid;

bool mUseWkb;
bool mSkipFailures;

int mGeomType;

long mNumberFeatures;
long mFidCol;
QString mFidColName;
long mSRId;
long mGeometryCol;
QString mGeometryColName;
QString mGeometryColType;

// QString containing the last reported error message
QString mLastError;

// Coordinate reference sytem
QgsCoordinateReferenceSystem mCrs;

QGis::WkbType mWkbType;

// The database object
QSqlDatabase mDatabase;

// The current sql query
QSqlQuery mQuery;

// The current sql statement
QString mStatement;

// current layer name
QString mSchemaName;
QString mTableName;
// available tables
QStringList mTables;

// Sets the error messages
void setLastError( QString error )
{
mLastError = error;
}

static void mssqlWkbTypeAndDimension( QGis::WkbType wkbType, QString &geometryType, int &dim );
static QGis::WkbType getWkbType( QString geometryType, int dim );
};
814 changes: 814 additions & 0 deletions src/providers/mssql/qgsmssqlsourceselect.cpp

Large diffs are not rendered by default.

189 changes: 189 additions & 0 deletions src/providers/mssql/qgsmssqlsourceselect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/***************************************************************************
qgmssqlsourceselect.h - description
-------------------
begin : 2011-10-08
copyright : (C) 2011 by Tamas Szekeres
email : szekerest at gmail.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 QGSMSSQLSOURCESELECT_H
#define QGSMSSQLSOURCESELECT_H

#include "ui_qgsdbsourceselectbase.h"
#include "qgisgui.h"
#include "qgsdbfilterproxymodel.h"
#include "qgsmssqltablemodel.h"
#include "qgscontexthelp.h"

#include <QMap>
#include <QPair>
#include <QIcon>
#include <QItemDelegate>
#include <QThread>

class QPushButton;
class QStringList;
class QgsGeomColumnTypeThread;
class QgisApp;
class QgsPgSourceSelect;

class QgsMssqlSourceSelectDelegate : public QItemDelegate
{
Q_OBJECT;

public:
QgsMssqlSourceSelectDelegate( QObject *parent = NULL )
: QItemDelegate( parent )
{}

QWidget *createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const;
void setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const;
};

// A class that determines the geometry type of a given database
// schema.table.column, with the option of doing so in a separate
// thread.

class QgsMssqlGeomColumnTypeThread : public QThread
{
Q_OBJECT
public:
QgsMssqlGeomColumnTypeThread( QString connectionName, bool useEstimatedMetadata );

// These functions get the layer types and pass that information out
// by emitting the setLayerType() signal.
virtual void run();

signals:
void setLayerType( QgsMssqlLayerProperty layerProperty );

public slots:
void addGeometryColumn( QgsMssqlLayerProperty layerProperty );
void stop();

private:
QgsMssqlGeomColumnTypeThread() {}

QString mConnectionName;
bool mUseEstimatedMetadata;
bool mStopped;
QList<QgsMssqlLayerProperty> layerProperties;
};


/*! \class QgsMssqlSourceSelect
* \brief Dialog to create connections and add tables from MS SQL.
*
* This dialog allows the user to define and save connection information
* for MS SQL databases. The user can then connect and add
* tables from the database to the map canvas.
*/
class QgsMssqlSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
{
Q_OBJECT

public:

//! static function to delete a connection
static void deleteConnection( QString key );

//! Constructor
QgsMssqlSourceSelect( QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags, bool managerMode = false, bool embeddedMode = false );
//! Destructor
~QgsMssqlSourceSelect();
//! Populate the connection list combo box
void populateConnectionList();
//! String list containing the selected tables
QStringList selectedTables();
//! Connection info (database, host, user, password)
QString connectionInfo();

signals:
void addDatabaseLayers( QStringList const & layerPathList, QString const & providerKey );
void connectionsChanged();
void addGeometryColumn( QgsMssqlLayerProperty );

public slots:
//! Determines the tables the user selected and closes the dialog
void addTables();
void buildQuery();

/*! Connects to the database using the stored connection parameters.
* Once connected, available layers are displayed.
*/
void on_btnConnect_clicked();
void on_cbxAllowGeometrylessTables_stateChanged( int );
//! Opens the create connection dialog to build a new connection
void on_btnNew_clicked();
//! Opens a dialog to edit an existing connection
void on_btnEdit_clicked();
//! Deletes the selected connection
void on_btnDelete_clicked();
//! Saves the selected connections to file
void on_btnSave_clicked();
//! Loads the selected connections from file
void on_btnLoad_clicked();
void on_mSearchTableEdit_textChanged( const QString & text );
void on_mSearchColumnComboBox_currentIndexChanged( const QString & text );
void on_mSearchModeComboBox_currentIndexChanged( const QString & text );
void setSql( const QModelIndex& index );
//! Store the selected database
void on_cmbConnections_activated( int );
void setLayerType( QgsMssqlLayerProperty layerProperty );
void on_mTablesTreeView_clicked( const QModelIndex &index );
void on_mTablesTreeView_doubleClicked( const QModelIndex &index );
//!Sets a new regular expression to the model
void setSearchExpression( const QString& regexp );

void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }

void columnThreadFinished();

private:
typedef QPair<QString, QString> geomPair;
typedef QList<geomPair> geomCol;

//! Connections manager mode
bool mManagerMode;

//! Embedded mode, without 'Close'
bool mEmbeddedMode;

// queue another query for the thread
void addSearchGeometryColumn( QString connectionName, QgsMssqlLayerProperty layerProperty );

// Set the position of the database connection list to the last
// used one.
void setConnectionListPosition();
// Combine the schema, table and column data into a single string
// useful for display to the user
QString fullDescription( QString schema, QString table, QString column, QString type );
// The column labels
QStringList mColumnLabels;
// Our thread for doing long running queries
QgsMssqlGeomColumnTypeThread* mColumnTypeThread;
QString mConnInfo;
QStringList mSelectedTables;
bool mUseEstimatedMetadata;
// Storage for the range of layer type icons
QMap<QString, QPair<QString, QIcon> > mLayerIcons;

//! Model that acts as datasource for mTableTreeWidget
QgsMssqlTableModel mTableModel;
QgsDbFilterProxyModel mProxyModel;

QPushButton *mBuildQueryButton;
QPushButton *mAddButton;

void finishList();
};

#endif // QGSMSSQLSOURCESELECT_H
431 changes: 431 additions & 0 deletions src/providers/mssql/qgsmssqltablemodel.cpp

Large diffs are not rendered by default.

89 changes: 89 additions & 0 deletions src/providers/mssql/qgsmssqltablemodel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/***************************************************************************
qgsmssqltablemodel.h - description
-------------------
begin : 2011-10-08
copyright : (C) 2011 by Tamas Szekeres
email : szekerest at gmail.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 <QStandardItemModel>

#include "qgis.h"

/** Layer Property structure */
struct QgsMssqlLayerProperty
{
// MSSQL layer properties
QString type;
QString schemaName;
QString tableName;
QString geometryColName;
QStringList pkCols;
QString srid;
bool isGeography;
QString sql;
};


class QIcon;

/**A model that holds the tables of a database in a hierarchy where the
schemas are the root elements that contain the individual tables as children.
The tables have the following columns: Type, Schema, Tablename, Geometry Column, Sql*/
class QgsMssqlTableModel : public QStandardItemModel
{
Q_OBJECT
public:
QgsMssqlTableModel();
~QgsMssqlTableModel();

/**Adds entry for one database table to the model*/
void addTableEntry( QgsMssqlLayerProperty property );

/**Sets an sql statement that belongs to a cell specified by a model index*/
void setSql( const QModelIndex& index, const QString& sql );

/**Sets one or more geometry types to a row. In case of several types, additional rows are inserted.
This is for tables where the type is dectected later by thread*/
void setGeometryTypesForTable( QgsMssqlLayerProperty layerProperty );

/**Returns the number of tables in the model*/
int tableCount() const { return mTableCount; }

enum columns
{
dbtmSchema = 0,
dbtmTable,
dbtmType,
dbtmGeomCol,
dbtmSrid,
dbtmPkCol,
dbtmSelectAtId,
dbtmSql,
dbtmColumns
};

bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole );

QString layerURI( const QModelIndex &index, QString connInfo, bool useEstimatedMetadata );

static QIcon iconForGeomType( QGis::GeometryType type );

static QGis::GeometryType geomTypeFromMssql( QString dbType );

static QString displayStringForGeomType( QGis::GeometryType type );

private:
/**Number of tables in the model*/
int mTableCount;
};

16 changes: 15 additions & 1 deletion src/ui/qgisapp.ui
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<x>0</x>
<y>0</y>
<width>1052</width>
<height>20</height>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="mEditMenu">
Expand Down Expand Up @@ -147,6 +147,7 @@
<addaction name="mActionAddRasterLayer"/>
<addaction name="mActionAddPgLayer"/>
<addaction name="mActionAddSpatiaLiteLayer"/>
<addaction name="mActionAddMssqlLayer"/>
<addaction name="mActionAddWmsLayer"/>
<addaction name="mActionAddLayerSeparator"/>
<addaction name="mActionAddWfsLayer"/>
Expand Down Expand Up @@ -250,6 +251,7 @@
<addaction name="mActionAddRasterLayer"/>
<addaction name="mActionAddPgLayer"/>
<addaction name="mActionAddSpatiaLiteLayer"/>
<addaction name="mActionAddMssqlLayer"/>
<addaction name="mActionAddWmsLayer"/>
<addaction name="mActionAddWfsLayer"/>
<addaction name="mActionNewVectorLayer"/>
Expand Down Expand Up @@ -1146,6 +1148,18 @@
<string>Ctrl+Shift+L</string>
</property>
</action>
<action name="mActionAddMssqlLayer">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionAddMssqlLayer.png</normaloff>:/images/themes/default/mActionAddMssqlLayer.png</iconset>
</property>
<property name="text">
<string>Add MSSQL Spatial Layer...</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+M</string>
</property>
</action>
<action name="mActionAddWmsLayer">
<property name="icon">
<iconset resource="../../images/images.qrc">
Expand Down
295 changes: 295 additions & 0 deletions src/ui/qgsmssqlnewconnectionbase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsMssqlNewConnectionBase</class>
<widget class="QDialog" name="QgsMssqlNewConnectionBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>311</width>
<height>352</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Create a New MS SQL connection</string>
</property>
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QGridLayout">
<property name="margin">
<number>9</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="QGroupBox" name="GroupBox1">
<property name="title">
<string>Connection Information</string>
</property>
<layout class="QGridLayout">
<property name="margin">
<number>0</number>
</property>
<property name="spacing">
<number>5</number>
</property>
<item row="0" column="0">
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="TextLabel1_2">
<property name="text">
<string>Name</string>
</property>
<property name="buddy">
<cstring>txtName</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Provider/DSN</string>
</property>
<property name="buddy">
<cstring>txtService</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="TextLabel1">
<property name="text">
<string>Host</string>
</property>
<property name="buddy">
<cstring>txtHost</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="TextLabel2">
<property name="text">
<string>Database</string>
</property>
<property name="buddy">
<cstring>txtDatabase</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="TextLabel3">
<property name="text">
<string>Username</string>
</property>
<property name="buddy">
<cstring>txtUsername</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="TextLabel3_2">
<property name="text">
<string>Password</string>
</property>
<property name="buddy">
<cstring>txtPassword</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="txtName">
<property name="toolTip">
<string>Name of the new connection</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txtService"/>
</item>
<item>
<widget class="QLineEdit" name="txtHost"/>
</item>
<item>
<widget class="QLineEdit" name="txtDatabase"/>
</item>
<item>
<widget class="QCheckBox" name="cb_trustedConnection">
<property name="text">
<string>Trusted Connection</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txtUsername"/>
</item>
<item>
<widget class="QLineEdit" name="txtPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout_1">
<property name="margin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="chkStoreUsername">
<property name="text">
<string>Save Username</string>
</property>
</widget>
</item>
<item row="0" column="1" rowspan="2">
<widget class="QPushButton" name="btnConnect">
<property name="text">
<string>&amp;Test Connect</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="chkStorePassword">
<property name="text">
<string>Save Password</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="cb_geometryColumns">
<property name="text">
<string>Only look in the geometry_columns metadata table</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="cb_allowGeometrylessTables">
<property name="text">
<string>Also list tables with no geometry</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="cb_useEstimatedMetadata">
<property name="text">
<string>Use estimated table parameters</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<tabstops>
<tabstop>txtName</tabstop>
<tabstop>txtService</tabstop>
<tabstop>txtHost</tabstop>
<tabstop>txtDatabase</tabstop>
<tabstop>txtUsername</tabstop>
<tabstop>txtPassword</tabstop>
<tabstop>chkStoreUsername</tabstop>
<tabstop>chkStorePassword</tabstop>
<tabstop>btnConnect</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QgsMssqlNewConnectionBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>313</x>
<y>501</y>
</hint>
<hint type="destinationlabel">
<x>451</x>
<y>312</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QgsMssqlNewConnectionBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>395</x>
<y>501</y>
</hint>
<hint type="destinationlabel">
<x>450</x>
<y>287</y>
</hint>
</hints>
</connection>
</connections>
</ui>