Index: qgis/src/plugins/CMakeLists.txt =================================================================== --- qgis/src/plugins/CMakeLists.txt (revision 9178) +++ qgis/src/plugins/CMakeLists.txt (working copy) @@ -22,3 +22,5 @@ SUBDIRS (coordinate_capture dxf2shp_converter) + +SUBDIRS (ogr_converter) Index: qgis/src/plugins/ogr_converter/plugin.cpp =================================================================== --- qgis/src/plugins/ogr_converter/plugin.cpp (revision 0) +++ qgis/src/plugins/ogr_converter/plugin.cpp (revision 0) @@ -0,0 +1,149 @@ +// $Id$ +////////////////////////////////////////////////////////////////////////////// +// +// begin : Aug 24, 2008 +// copyright : (C) 2008 by Mateusz Loskot +// email : mateusz@loskot.net +// +////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +////////////////////////////////////////////////////////////////////////////// + +// qgis::plugin::ogrconv +#include "plugin.h" +#include "dialog.h" +// QGIS +#include +#include +#include +// Qt +#include +#include +// std +#include + +namespace qgis { namespace plugin { namespace ogrconv { + +// GDAL/OGR loaded into private namesapce +#include + +static const char * const sIdent = "$Id$"; +static const QString sName = QObject::tr("OGR Layer Converter"); +static const QString sDescription = QObject::tr("Translates vector layers between formats supported by OGR library"); +static const QString sPluginVersion = QObject::tr("Version 0.1"); +static const QgisPlugin::PLUGINTYPE sPluginType = QgisPlugin::UI; + +////////////////////////////////////////////////////////////////////////////// +// THE FOLLOWING METHODS ARE MANDATORY FOR ALL PLUGINS +////////////////////////////////////////////////////////////////////////////// + +OgrPlugin::OgrPlugin(QgisInterface * theQgisInterface) : + QgisPlugin(sName, sDescription, sPluginVersion, sPluginType), + mQGisIface(theQgisInterface), + mQActionPointer(0) +{ + assert(0 != mQGisIface); +} + +OgrPlugin::~OgrPlugin() +{ +} + +void OgrPlugin::initGui() +{ + // Create the action for tool + mQActionPointer = new QAction(QIcon(":/ogrconverter/ogrconverter.png"), tr("Run OGR Layer Converter"), this); + + // Set the what's this text + mQActionPointer->setWhatsThis(tr("Replace this with a short description of the what the plugin does")); + + // Connect the action to the run + connect(mQActionPointer, SIGNAL(triggered()), this, SLOT(run())); + + // Add the icon to the toolbar + mQGisIface->addToolBarIcon(mQActionPointer); + mQGisIface->addPluginMenu(tr("OG&R Converter"), mQActionPointer); +} + +//method defined in interface +void OgrPlugin::help() +{ + //implement me! +} + +void OgrPlugin::run() +{ + assert(0 != mQGisIface); + + Dialog* ogrDialog = new Dialog(mQGisIface->getMainWindow(), QgisGui::ModalDialogFlags); + ogrDialog->setAttribute(Qt::WA_DeleteOnClose); + ogrDialog->show(); +} + +void OgrPlugin::unload() +{ + assert(0 != mQGisIface); + + // TODO: Who is responsible for OGR cleanup? + //OGRCleanupAll(); + + // remove the GUI + mQGisIface->removePluginMenu("&OGR Layer Converter", mQActionPointer); + mQGisIface->removeToolBarIcon(mQActionPointer); + delete mQActionPointer; +} + +///////////////////////////////////////////////////////////////////////////// +// THE FOLLOWING CODE IS AUTOGENERATED BY THE PLUGIN BUILDER SCRIPT +// YOU WOULD NORMALLY NOT NEED TO MODIFY THIS, AND YOUR PLUGIN +// MAY NOT WORK PROPERLY IF YOU MODIFY THIS INCORRECTLY +///////////////////////////////////////////////////////////////////////////// + +// 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 * theQgisInterfacePointer) +{ + return new OgrPlugin(theQgisInterfacePointer); +} + +// Return the name of the plugin - note that we do not user class members as +// the class may not yet be insantiated when this method is called. +QGISEXTERN QString name() +{ + return sName; +} + +// Return the description +QGISEXTERN QString description() +{ + return sDescription; +} + +// Return the type (either UI or MapLayer plugin) +QGISEXTERN int type() +{ + return sPluginType; +} + +// Return the version number for the plugin +QGISEXTERN QString version() +{ + return sPluginVersion; +} + +// Delete ourself +QGISEXTERN void unload(QgisPlugin * thePluginPointer) +{ + delete thePluginPointer; +} + +}}} // namespace qgis::plugin::ogrconv + Index: qgis/src/plugins/ogr_converter/translator.h =================================================================== --- qgis/src/plugins/ogr_converter/translator.h (revision 0) +++ qgis/src/plugins/ogr_converter/translator.h (revision 0) @@ -0,0 +1,81 @@ +// $Id$ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2008 by Mateusz Loskot +// +// 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 QGIS_PLUGIN_OGRCONV_TRANSLATOR_H_INCLUDED +#define QGIS_PLUGIN_OGRCONV_TRANSLATOR_H_INCLUDED + +// Qt4 +#include + +namespace qgis { namespace plugin { namespace ogrconv { + +// GDAL/OGR loaded into private namespace +#include + +class Translator +{ +public: + + Translator(); + Translator(QString const& src, QString const& dst, QString const& format); + + QString const& targetFormat() const; + void setTargetFormat(QString const& format); + + QString const& targetLayer() const; + void setTargetLayer(QString const& layer); + + QString const& sourceLayer() const; + void setSourceLayer(QString const& layer); + + QString const& targetReferenceSystem() const; + void setTargetReferenceSystem(QString const& srs); + + QString const& sourceReferenceSystem() const; + void setSourceReferenceSystem(QString const& srs); + + bool isTargetUpdate() const; + void setUpdateTarget(bool update); + + bool isTargetLayerOverwrite() const; + // TODO: Implement, currently always overwrite + // void setTargetLayerOverwrite(bool overwrite); + + bool translate(); + +private: + + QString mSrcUrl; + QString mDstUrl; + QString mDstFormat; + QString mSrcLayer; + QString mDstLayer; + QString mSrcSrs; + QString mDstSrs; + bool mDstUpdate; + bool mDstLayerOverwrite; + // TODO: Append option not supported + // bool mDstLayerAppend; + + bool translateLayer(OGRDataSourceH srcDs, OGRLayerH srcLayer, OGRDataSourceH dstDs); + bool copyFields(OGRFeatureDefnH layerDefn, OGRLayerH layer); + bool copyFeatures(OGRLayerH srcLayer, OGRLayerH dstLayer); + + OGRSFDriverH findDriver(QString const& name); + OGRLayerH findLayer(OGRDataSourceH ds, QString const& name, int& index); + OGRDataSourceH openDataSource(QString const& url, bool readOnly); + OGRDataSourceH openDataTarget(QString const& url, bool update); + +}; + +}}} // namespace qgis::plugin::ogrconv + +#endif // QGIS_PLUGIN_OGRCONV_TRANSLATOR_H_INCLUDED Index: qgis/src/plugins/ogr_converter/dialog.cpp =================================================================== --- qgis/src/plugins/ogr_converter/dialog.cpp (revision 0) +++ qgis/src/plugins/ogr_converter/dialog.cpp (revision 0) @@ -0,0 +1,453 @@ +// $Id$ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2008 by Mateusz Loskot +// +// 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. +// +////////////////////////////////////////////////////////////////////////////// + +// qgis::plugin::ogrconv +#include "dialog.h" +#include "format.h" +#include "translator.h" +// QGIS includes +#include +#include +// TODO: Add support of QGIS projection selector +//#include +// Qt4 +#include +#include +#include +#include +#include +#include +#include +#include + +namespace qgis { namespace plugin { namespace ogrconv { + +// GDAL/OGR loaded into private namespace +#include +#include + +Dialog::Dialog(QWidget* parent, Qt::WFlags fl) + : QDialog(parent, fl) +{ + setupUi(this); + populateFormats(); + resetSrcUi(); + resetDstUi(); +} + +Dialog::~Dialog() +{ +} + +void Dialog::resetSrcUi() +{ + // Clear all settings and states + inputSrcDataset->clear(); + // TODO: Transformation support + //inputSrcSrs->clear(); + comboSrcLayer->clear(); + radioSrcFile->setDisabled(true); + radioSrcFile->setChecked(false); + radioSrcDirectory->setDisabled(true); + radioSrcDirectory->setChecked(false); + radioSrcProtocol->setDisabled(true); + radioSrcProtocol->setChecked(false); + + // Configure types of input sources + unsigned char const& type = mSrcFormat.type(); + + if (isFormatType(type, Format::eFile)) + { + radioSrcFile->setDisabled(false); + radioSrcFile->setChecked(true); + } + + if (isFormatType(type, Format::eDirectory)) + { + radioSrcDirectory->setDisabled(false); + if (!radioSrcFile->isEnabled()) + radioSrcDirectory->setChecked(true); + } + + if (isFormatType(type, Format::eProtocol)) + { + radioSrcProtocol->setDisabled(false); + + if (!radioSrcFile->isEnabled() && !radioSrcDirectory->isEnabled()) + { + radioSrcProtocol->setChecked(true); + inputSrcDataset->setText(mSrcFormat.protocol()); + } + } + + setButtonState(buttonSelectSrc, isFormatType(type, Format::eProtocol)); +} + +void Dialog::resetDstUi() +{ + inputDstDataset->clear(); + // TODO: Transformation support + //inputDstSrs->clear(); + + unsigned char const& type = mDstFormat.type(); + bool isProtocol = isFormatType(type, Format::eProtocol); + + if (isProtocol) + { + inputDstDataset->setText(mDstFormat.protocol()); + } + + setButtonState(buttonSelectDst, isProtocol); +} + +void Dialog::setButtonState(QPushButton* btn, bool isProtocol) +{ + Q_CHECK_PTR(btn); + + if (isProtocol) + { + btn->setText(tr("Connect")); + } + else + { + btn->setText(tr("Browse")); + } +} + +void Dialog::populateFormats() +{ + comboSrcFormats->clear(); + comboDstFormats->clear(); + + QStringList drvSrcList; + QStringList drvDstList; + QString drvName; + + if (0 >= OGRGetDriverCount()) + { + OGRRegisterAll(); + } + int const drvCount = OGRGetDriverCount(); + + for (int i = 0; i < drvCount; ++i) + { + OGRSFDriverH drv = OGRGetDriver(i); + Q_CHECK_PTR(drv); + if (0 != drv) + { + drvName = OGR_Dr_GetName(drv); + drvSrcList.append(drvName); + + if (0 != OGR_Dr_TestCapability(drv, ODrCCreateDataSource)) + { + drvDstList.append(drvName); + } + } + } + + qSort(drvSrcList.begin(), drvSrcList.end()); + qSort(drvDstList.begin(), drvDstList.end()); + comboSrcFormats->addItems(drvSrcList); + comboDstFormats->addItems(drvDstList); +} + +void Dialog::populateLayers(QString const& url) +{ + comboSrcLayer->clear(); + + OGRDataSourceH ds = OGROpen(url.toAscii().constData(), 0, 0); + if (0 != ds) + { + QString lyrName; + QString lyrType; + + int const size = OGR_DS_GetLayerCount(ds); + for (int i = 0; i < size; ++i) + { + OGRLayerH lyr = OGR_DS_GetLayer(ds, i); + if (0 != lyr) + { + OGRFeatureDefnH lyrDef = OGR_L_GetLayerDefn(lyr); + assert(0 != lyrDef); + + lyrName = OGR_FD_GetName(lyrDef); + + OGRwkbGeometryType const geomType = OGR_FD_GetGeomType(lyrDef); + lyrType = OGRGeometryTypeToName(geomType); + + // FIXME: Appending type to layer name prevents from layer finding + //comboSrcLayer->addItem(lyrName + " (" + lyrType.toUpper() + ")"); + comboSrcLayer->addItem(lyrName); + } + } + + OGR_DS_Destroy(ds); + } + else + { + QMessageBox::warning(this, + tr("OGR Converter"), + tr("Could not establish connection to: '") + url + "'", + QMessageBox::Close); + } +} + +bool Dialog::testConnection(QString const& url) +{ + bool success = false; + + OGRDataSourceH ds = OGROpen(url.toAscii().constData(), 0, 0); + if (0 != ds) + { + success = true; + OGR_DS_Destroy(ds); + } + + return success; +} + +QString Dialog::openFile() +{ + QSettings sets; + QString path = QFileDialog::getOpenFileName(this, + tr("Open OGR file"), + sets.value("/Plugin-OGR/ogr-file", "./").toString(), + tr("OGR File Data Source (*.*)")); + + return path; +} + +QString Dialog::openDirectory() +{ + QString path = QFileDialog::getExistingDirectory(this, + tr("Open Directory"), "", + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + return path; +} + +void Dialog::on_buttonBox_accepted() +{ + // Validate input settings + QString srcUrl(inputSrcDataset->text()); + QString srcLayer(comboSrcLayer->currentText()); + + if (srcUrl.isEmpty()) + { + QMessageBox::warning(this, "OGR Layer Converter", + tr("Input OGR dataset is missing!")); + return; + } + + if (srcLayer.isEmpty()) + { + QMessageBox::warning(this, "OGR Layer Converter", + tr("Input OGR layer name is missing!")); + return; + } + + // Validate output settings + QString dstFormat(comboDstFormats->currentText()); + QString dstUrl(inputDstDataset->text()); + QString dstLayer(inputDstLayer->text()); + if (dstLayer.isEmpty()) + dstLayer = srcLayer; + + if (dstFormat.isEmpty()) + { + QMessageBox::warning(this, "OGR Layer Converter", + tr("Target OGR format not selected!")); + return; + } + + if (dstUrl.isEmpty()) + { + QMessageBox::warning(this, "OGR Layer Converter", + tr("Output OGR dataset is missing!")); + return; + } + + if (dstLayer.isEmpty()) + { + QMessageBox::warning(this, "OGR Layer Converter", + tr("Output OGR layer name is missing!")); + return; + } + + // TODO: SRS transformation support + //QString srcSrs("EPSG:"); + //QString dstSrs("EPSG:"); + //srcSrs += inputSrcSrs->text(); + //dstSrs += inputDstSrs->text(); + + // Execute layer translation + bool success = false; + + // TODO: Use try-catch to display more meaningful error messages from Translator + Translator worker(srcUrl, dstUrl, dstFormat); + worker.setSourceLayer(srcLayer); + worker.setTargetLayer(dstLayer); + success = worker.translate(); + + if (success) + { + QMessageBox::information(this, "OGR Layer Converter", + tr("Successfully translated layer '") + srcLayer + "'"); + } + else + { + QMessageBox::information(this, "OGR Layer Converter", + tr("Failed to translate layer '") + srcLayer + "'"); + } + + // Close dialog box + accept(); +} + +void Dialog::on_buttonBox_rejected() +{ + reject(); +} + +void Dialog::on_buttonBox_helpRequested() +{ + QgsContextHelp::run(context_id); +} + +void Dialog::on_radioSrcFile_toggled(bool checked) +{ + if (checked) + { + unsigned char const& type = mSrcFormat.type(); + Q_ASSERT(isFormatType(type, Format::eFile)); + + inputSrcDataset->clear(); + setButtonState(buttonSelectSrc, isFormatType(type, Format::eProtocol)); + } +} + +void Dialog::on_radioSrcDirectory_toggled(bool checked) +{ + if (checked) + { + unsigned char const& type = mSrcFormat.type(); + Q_ASSERT(isFormatType(type, Format::eDirectory)); + + inputSrcDataset->clear(); + setButtonState(buttonSelectSrc, isFormatType(type, Format::eProtocol)); + } +} + +void Dialog::on_radioSrcProtocol_toggled(bool checked) +{ + if (checked) + { + unsigned char const& type = mSrcFormat.type(); + Q_ASSERT(isFormatType(type, Format::eProtocol)); + + inputSrcDataset->setText(mSrcFormat.protocol()); + setButtonState(buttonSelectSrc, isFormatType(type, Format::eProtocol)); + } +} + +void Dialog::on_comboSrcFormats_currentIndexChanged(int index) +{ + // Select source data format + QString frmtCode = comboSrcFormats->currentText(); + mSrcFormat = mFrmts.find(frmtCode); + + resetSrcUi(); +} + +void Dialog::on_comboDstFormats_currentIndexChanged(int index) +{ + // Select destination data format + QString frmtCode = comboDstFormats->currentText(); + mDstFormat = mFrmts.find(frmtCode); + + resetDstUi(); +} + +void Dialog::on_buttonSelectSrc_clicked() +{ + QSettings settings; + QString src; + + if (radioSrcFile->isChecked()) + { + src = openFile(); + } + else if (radioSrcDirectory->isChecked()) + { + src = openDirectory(); + } + else if (radioSrcProtocol->isChecked()) + { + src = inputSrcDataset->text(); + } + else + { + Q_ASSERT(!"SHOULD NEVER GET HERE"); + } + + inputSrcDataset->setText(src); + + if (!src.isEmpty()) + { + populateLayers(src); + } +} + +void Dialog::on_buttonSelectDst_clicked() +{ + QSettings settings; + QString dst; + QString msg; + + unsigned char const& type = mDstFormat.type(); + if (isFormatType(type, Format::eProtocol)) + { + dst = inputDstDataset->text(); + + if (testConnection(dst)) + { + msg = tr("Successfully connected to: '") + dst + "'"; + } + else + { + msg = tr("Could not establish connection to: '") + dst + "'"; + } + + QMessageBox::information(this, tr("OGR Converter"), + msg, QMessageBox::Close); + } + else if (isFormatType(type, Format::eDirectory)) + { + dst = openDirectory(); + } + else if (isFormatType(type, Format::eFile)) + { + dst = QFileDialog::getSaveFileName(this, + tr("Choose a file name to save to"), + "output", tr("OGR File Data Source (*.*)")); + } + else + { + Q_ASSERT(!"SHOULD NEVER GET HERE"); + } + + inputDstDataset->setText(dst); +} + + +}}} // namespace qgis::plugin::ogrconv + Index: qgis/src/plugins/ogr_converter/ogrconverter.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: qgis/src/plugins/ogr_converter/ogrconverter.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: qgis/src/plugins/ogr_converter/ogrconverter.qrc =================================================================== --- qgis/src/plugins/ogr_converter/ogrconverter.qrc (revision 0) +++ qgis/src/plugins/ogr_converter/ogrconverter.qrc (revision 0) @@ -0,0 +1,5 @@ + + + ogrconverter.png + + Index: qgis/src/plugins/ogr_converter/plugin.h =================================================================== --- qgis/src/plugins/ogr_converter/plugin.h (revision 0) +++ qgis/src/plugins/ogr_converter/plugin.h (revision 0) @@ -0,0 +1,103 @@ +// $Id$ +////////////////////////////////////////////////////////////////////////////// +// +// begin : Aug 24, 2008 +// copyright : (C) 2008 by Mateusz Loskot +// email : mateusz@loskot.net +// +////////////////////////////////////////////////////////////////////////////// +// +// 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 QGIS_PLUGIN_OGRCONV_PLUGIN_H_INCLUDED +#define QGIS_PLUGIN_OGRCONV_PLUGIN_H_INCLUDED + +// QGIS +#include "../qgisplugin.h" +// Qt4 +#include + +// Forward declarations +class QAction; +class QToolBar; +class QgisInterface; + +namespace qgis { namespace plugin { namespace ogrconv { + +/** +* \class OgrPlugin +* \brief Translates vector layers between formats supported by OGR library. +*/ +class OgrPlugin : public QObject, public QgisPlugin +{ + Q_OBJECT + +public: + + ////////////////////////////////////////////////////////////////////////// + // MANDATORY PLUGIN METHODS FOLLOW + ////////////////////////////////////////////////////////////////////////// + + /** + * Constructor for a plugin. The QgisInterface pointer is passed by + * QGIS when it attempts to instantiate the plugin. + * @param theInterface Pointer to the QgisInterface object. + */ + OgrPlugin(QgisInterface * theInterface); + + //! Destructor + virtual ~OgrPlugin(); + +public slots: + + /** + * Initialize the GUI interface for the plugin. + * This is only called once when the plugin is added to the plugin + * registry in the QGIS application. + */ + virtual void initGui(); + + /** + * Slot called when the menu item is triggered. + * If you created more menu items / toolbar buttons in initiGui, + * you should create a separate handler for each action - this + * single run() method will not be enough. + */ + void run(); + + /** + * Unload the plugin by cleaning up the GUI. + */ + void unload(); + + //! show the help document + void help(); + +private: + + ////////////////////////////////////////////////////////////////////////// + // MANDATORY PLUGIN PROPERTY DECLARATIONS + ////////////////////////////////////////////////////////////////////////// + + // FIXME: Is it used at all? + int mPluginType; + + //! Pointer to the QGIS interface object + QgisInterface *mQGisIface; + + //!pointer to the qaction for this plugin + QAction * mQActionPointer; + + ////////////////////////////////////////////////////////////////////////// + // ADD YOUR OWN PROPERTY DECLARATIONS AFTER THIS POINT..... + ////////////////////////////////////////////////////////////////////////// + +}; // OgrPlugin + +}}} // namespace qgis::plugin::ogrconv + +#endif // QGIS_PLUGIN_OGRCONV_PLUGIN_H_INCLUDED Index: qgis/src/plugins/ogr_converter/dialog.h =================================================================== --- qgis/src/plugins/ogr_converter/dialog.h (revision 0) +++ qgis/src/plugins/ogr_converter/dialog.h (revision 0) @@ -0,0 +1,69 @@ +// $Id$ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2008 by Mateusz Loskot +// +// 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 QGIS_PLUGIN_OGRCONV_DIALOG_H_INCLUDED +#define QGIS_PLUGIN_OGRCONV_DIALOG_H_INCLUDED + +// qgis::plugin::ogrconv +#include "format.h" +#include +// Qt4 +#include + +namespace qgis { namespace plugin { namespace ogrconv { + +/** +@author Mateusz Loskot +*/ +class Dialog : public QDialog, private Ui::OgrConverterGuiBase +{ + Q_OBJECT + +public: + + Dialog(QWidget* parent = 0, Qt::WFlags fl = 0); + ~Dialog(); + +private: + + static const int context_id = 0; + + FormatsRegistry mFrmts; + Format mSrcFormat; + Format mDstFormat; + + void resetSrcUi(); + void resetDstUi(); + void setButtonState(QPushButton* btn, bool isProtocol); + + void populateFormats(); + void populateLayers(QString const& url); + bool testConnection(QString const& url); + QString openFile(); + QString openDirectory(); + +private slots: + + void on_buttonBox_accepted(); + void on_buttonBox_rejected(); + void on_buttonBox_helpRequested(); + void on_radioSrcFile_toggled(bool checked); + void on_radioSrcDirectory_toggled(bool checked); + void on_radioSrcProtocol_toggled(bool checked); + void on_buttonSelectSrc_clicked(); + void on_buttonSelectDst_clicked(); + void on_comboSrcFormats_currentIndexChanged(int index); + void on_comboDstFormats_currentIndexChanged(int index); +}; + +}}} // namespace qgis::plugin::ogrconv + +#endif // QGIS_PLUGIN_OGRCONV_DIALOG_H_INCLUDED Index: qgis/src/plugins/ogr_converter/format.cpp =================================================================== --- qgis/src/plugins/ogr_converter/format.cpp (revision 0) +++ qgis/src/plugins/ogr_converter/format.cpp (revision 0) @@ -0,0 +1,117 @@ +// $Id$ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2008 by Mateusz Loskot +// +// 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. +// +////////////////////////////////////////////////////////////////////////////// + +// qgis::plugin::ogrconv +#include "format.h" +// Qt4 +#include + +namespace qgis { namespace plugin { namespace ogrconv { + +Format::Format() +{ +} + +Format::Format(QString const& c, QString const& n) + : mCode(c), mName(n), mTypeFlags(0) +{ +} + +Format::Format(QString const& c, QString const& n, unsigned char const& t) + : mCode(c), mName(n), mTypeFlags(t) +{ +} + +Format::Format(QString const& c, QString const& n, QString const& p, unsigned char const& t) + : mCode(c), mName(n), mProtocol(p), mTypeFlags(t) +{ +} + +QString const& Format::code() const +{ + return mCode; +} + +QString const& Format::name() const +{ + return mName; +} + +QString const& Format::protocol() const +{ + return mProtocol; +} + +unsigned char const& Format::type() const +{ + return mTypeFlags; +} + + +FormatsRegistry::FormatsRegistry() +{ + init(); +} + +void FormatsRegistry::add(Format const& frmt) +{ + QString code = frmt.code(); + mFrmts[code] = frmt; +} + +Format const& FormatsRegistry::find(QString const& code) +{ + mCache = mFrmts.value(code); + return mCache; +} + +void FormatsRegistry::init() +{ + add(Format("AVCBin", "Arc/Info Binary Coverage", Format::eFile)); + add(Format("AVCE00", "Arc/Info .E00 (ASCII) Coverage", Format::eFile)); + add(Format("BNA", "Atlas BNA", Format::eFile)); + add(Format("CSV", "Comma Separated Value", Format::eFile | Format::eDirectory)); + add(Format("DODS", "DODS/OPeNDAP", Format::eFile)); + add(Format("DGN", "Microstation DGN", Format::eFile)); + add(Format("ESRI Shapefile", "ESRI Shapefile", Format::eFile | Format::eDirectory)); + add(Format("FMEObjects Gateway", "FMEObjects Gateway", Format::eFile)); + add(Format("Geoconcept Text Export", "Geoconcept", Format::eFile)); + add(Format("GML", "Geography Markup Language", Format::eFile)); + add(Format("GMT", "GMT ASCII Vectors", Format::eFile)); + add(Format("GPX", "GPS Exchange Format", Format::eFile)); + add(Format("GeoJSON", "GeoJSON", Format::eFile)); // FIXME: Format::eProtocol)); + add(Format("GRASS", "GRASS", Format::eDirectory)); + add(Format("Informix DataBlade", "IDB", "IDB:", Format::eProtocol)); + add(Format("Interlis 1", "INTERLIS", Format::eFile)); + add(Format("Interlis 2", "INTERLIS", Format::eFile)); + add(Format("Ingres Database", "INGRES", "@driver=ingres,", Format::eProtocol)); + add(Format("KML", "KML", Format::eFile)); + add(Format("MapInfo", "MapInfo File", Format::eFile)); + add(Format("Memory", "Memory", Format::eFile)); + add(Format("MySQL", "MySQL", "MySQL:", Format::eProtocol)); + add(Format("ODBC", "Open DataBase Connectivity", "ODBC:", Format::eProtocol)); + add(Format("OGDI", "Open Geographic Datastore Interface Vectors", "gltp:", Format::eProtocol)); + add(Format("OCI", "Oracle Spatial", "OCI:", Format::eProtocol)); + add(Format("PGeo", "ESRI Personal GeoDatabase", "PGeo:", Format::eFile | Format::eProtocol)); + add(Format("PostgreSQL", "PostgreSQL", "PG:", Format::eProtocol)); + add(Format("S57", "IHO S-57", Format::eFile)); + add(Format("SDE", "ESRI ArcSDE", "SDE:", Format::eProtocol)); + add(Format("SDTS", "SDTS Topological Vector Profile", Format::eFile)); + add(Format("SQLite", "SQLite Database File", Format::eFile)); + add(Format("UK.NTF", "UK National Transfer Format", Format::eFile)); + add(Format("TIGER", "U.S. Census TIGER/Line", Format::eFile)); + add(Format("VRT", "Virtual Datasource", Format::eFile)); + add(Format("XPLANE", "X-Plane/Flighgear Aeronautical Data", Format::eFile)); +} + +}}} // namespace qgis::plugin::ogrconv + Index: qgis/src/plugins/ogr_converter/translator.cpp =================================================================== --- qgis/src/plugins/ogr_converter/translator.cpp (revision 0) +++ qgis/src/plugins/ogr_converter/translator.cpp (revision 0) @@ -0,0 +1,419 @@ +// $Id$ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2008 by Mateusz Loskot +// +// 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. +// +////////////////////////////////////////////////////////////////////////////// + +// qgis::plugin::ogrconv +#include "translator.h" +// QGIS +#include +// Qt4 +#include + +namespace qgis { namespace plugin { namespace ogrconv { + +// GDAL/OGR loaded into private namespace +#include + +Translator::Translator() + : mDstUpdate(false), mDstLayerOverwrite(true) +{ +} + +Translator::Translator(QString const& src, QString const& dst, QString const& format) + : mSrcUrl(src), mDstUrl(dst), mDstFormat(format), + mDstUpdate(false), mDstLayerOverwrite(true) +{ +} + +QString const& Translator::targetFormat() const +{ + return mDstFormat; +} + +void Translator::setTargetFormat(QString const& format) +{ + mDstFormat = format; +} + +QString const& Translator::targetLayer() const +{ + return mDstLayer; +} + +void Translator::setTargetLayer(QString const& layer) +{ + mDstLayer = layer; +} + +QString const& Translator::sourceLayer() const +{ + return mSrcLayer; +} + +void Translator::setSourceLayer(QString const& layer) +{ + mSrcLayer = layer; +} + +QString const& Translator::targetReferenceSystem() const +{ + return mDstSrs; +} + +void Translator::setTargetReferenceSystem(QString const& srs) +{ + mDstSrs = srs; +} + +QString const& Translator::sourceReferenceSystem() const +{ + return mSrcSrs; +} + +void Translator::setSourceReferenceSystem(QString const& srs) +{ + mSrcSrs = srs; +} + +bool Translator::isTargetUpdate() const +{ + return mDstUpdate; +} + +void Translator::setUpdateTarget(bool update) +{ + mDstUpdate = update; +} + +bool Translator::isTargetLayerOverwrite() const +{ + return mDstLayerOverwrite; +} + +bool Translator::translate() +{ + bool success = false; + + // TODO: RAII for OGR handlers!!! + + // Open input data source + OGRDataSourceH srcDs = openDataSource(mSrcUrl, true); + if (0 == srcDs) + { + QgsDebugMsg("Open source failed: " + mSrcUrl); + return false; + } + + // Open output data source + OGRDataSourceH dstDs = openDataTarget(mDstUrl, mDstUpdate); + if (0 == dstDs) + { + QgsDebugMsg("Open target failed: " + mDstUrl); + OGR_DS_Destroy(srcDs); + return false; + } + + // TODO: Support translation of all layers from input data source + //for (int i = 0; i < OGR_DS_GetLayerCount(); ++i) + + OGRLayerH srcLayer = OGR_DS_GetLayerByName(srcDs, mSrcLayer.toAscii().constData()); + if (0 == srcLayer) + { + QgsDebugMsg("Can not find layer: " + mSrcLayer); + OGR_DS_Destroy(srcDs); + OGR_DS_Destroy(dstDs); + return false; + } + + if (mDstLayer.isEmpty()) + { + QgsDebugMsg("Using source layer name: " + mDstLayer); + mDstLayer = mSrcLayer; + } + + QgsDebugMsg("START LAYER TRANSLATION ------"); + + success = translateLayer(srcDs, srcLayer, dstDs); + + QgsDebugMsg("END LAYER TRANSLATION ------"); + + OGR_DS_Destroy(dstDs); + OGR_DS_Destroy(srcDs); + + return success; +} + +bool Translator::translateLayer(OGRDataSourceH srcDs, OGRLayerH srcLayer, OGRDataSourceH dstDs) +{ + // Implementation based on TranslateLayer function from ogr2ogr.cpp, from GDAL/OGR. + Q_ASSERT(0 != srcDs); + Q_ASSERT(0 != srcLayer); + Q_ASSERT(0 != dstDs); + + bool success = false; + + // Get source layer schema + OGRFeatureDefnH srcLayerDefn = OGR_L_GetLayerDefn(srcLayer); + Q_ASSERT(0 != srcLayerDefn); + + // Find if layer exists in target data source + int dstLayerIndex = 0; + OGRLayerH dstLayer = findLayer(dstDs, mDstLayer, dstLayerIndex); + + // If the user requested overwrite, and we have the layer in question + // we need to delete it now so it will get recreated overwritten + if (0 != dstLayer && mDstLayerOverwrite + && 0 != OGR_DS_TestCapability(dstDs, ODsCDeleteLayer)) + { + if (OGRERR_NONE != OGR_DS_DeleteLayer(dstDs, dstLayerIndex)) + { + QgsDebugMsg("Delete layer failed when overwrite requested"); + return false; + } + } + + if (0 == dstLayer) + { + QgsDebugMsg("Destination layer not found, will attempt to create"); + + // If the layer does not exist, then create it + if (0 == OGR_DS_TestCapability(dstDs, ODsCCreateLayer)) + { + QgsDebugMsg("Layer " + mDstLayer + " not found, and CreateLayer not supported by driver"); + return false; + } + + // FIXME: Do we need it here? + //CPLErrorReset(); + + // TODO: -nlt option support + OGRwkbGeometryType geomType = OGR_FD_GetGeomType(srcLayerDefn); + + // TODO: Implement SRS transformation + OGRSpatialReferenceH dstLayerSrs = OGR_L_GetSpatialRef(srcLayer); + + dstLayer = OGR_DS_CreateLayer(dstDs, mDstLayer.toAscii().constData(), + dstLayerSrs, geomType, 0); + } + // TODO: Append and createion options not implemented + // else if (!mDstLayerAppend) + + Q_ASSERT(0 != dstLayer); + + // Transfer attributes schema + if (!copyFields(dstLayer, srcLayerDefn)) + { + QgsDebugMsg("Faild to copy fields from layer " + mSrcLayer); + return false; + } + + // Transfer features + success = copyFeatures(srcLayer, dstLayer); + + return success; +} + +bool Translator::copyFields(OGRFeatureDefnH layerDefn, OGRLayerH layer) +{ + Q_ASSERT(0 != layerDefn); + Q_ASSERT(0 != layer); + + int const count = OGR_FD_GetFieldCount(layerDefn); + for (int i = 0; i < count; ++i) + { + OGRFieldDefnH fieldDefn = OGR_FD_GetFieldDefn(layerDefn, i); + Q_ASSERT(0 != fieldDefn); + + if (OGRERR_NONE != OGR_L_CreateField(layer, fieldDefn, true)) + { + return false; + } + } + + return true; +} + +bool Translator::copyFeatures(OGRLayerH srcLayer, OGRLayerH dstLayer) +{ + Q_ASSERT(0 != srcLayer); + Q_ASSERT(0 != dstLayer); + + bool success = false; + OGRFeatureDefnH srcLayerDefn = OGR_L_GetLayerDefn(srcLayer); + long srcFid = 0; + long count = 0; + + // TODO: RAII for feature handlers!!! + + while (true) + { + OGRFeatureH srcFeat = OGR_L_GetNextFeature(srcLayer); + if (0 == srcFeat) + { + QgsDebugMsg("Next source feature is null, finishing"); + success = true; + break; + } + srcFid = OGR_F_GetFID(srcFeat); + + // FIXME: Do we need it here? + //CPLErrorReset(); + + OGRFeatureH dstFeat = OGR_F_Create(srcLayerDefn); + + if (OGRERR_NONE != OGR_F_SetFrom(dstFeat, srcFeat, true)) + { + QString msg = QString("Unable to translate feature %1 from layer %2").arg(srcFid).arg(mSrcLayer); + QgsDebugMsg(msg); + + OGR_F_Destroy(srcFeat); + OGR_F_Destroy(dstFeat); + success = false; + break; + } + Q_ASSERT(0 != dstFeat); + + // TODO: Transform feature geometry + + OGR_F_Destroy(srcFeat); + + // FIXME: Do we need it here? + //CPLErrorReset(); + + // TODO: Skip failures support + if (OGRERR_NONE != OGR_L_CreateFeature(dstLayer, dstFeat)) + { + QgsDebugMsg("Feature creation failed"); + OGR_F_Destroy(dstFeat); + success = false; + break; + } + + OGR_F_Destroy(dstFeat); + + count += 1; + success = true; + } + + QgsDebugMsg(QString("Number of copied features: %1").arg(count)); + + return success; +} + +OGRSFDriverH Translator::findDriver(QString const& name) +{ + if (OGRGetDriverCount() <= 0) + { + OGRRegisterAll(); + } + int const drvCount = OGRGetDriverCount(); + + OGRSFDriverH drv = 0; + QString drvName; + + for (int i = 0; i < drvCount; ++i) + { + OGRSFDriverH drvTmp = OGRGetDriver(i); + Q_CHECK_PTR(drvTmp); + if (0 != drvTmp) + { + drvName = OGR_Dr_GetName(drvTmp); + if (name == drvName + && 0 != OGR_Dr_TestCapability(drvTmp, ODrCCreateDataSource)) + { + QgsDebugMsg("Driver found: " + name); + drv = drvTmp; + break; + } + } + } + + return drv; +} + +OGRLayerH Translator::findLayer(OGRDataSourceH ds, QString const& name, int& index) +{ + if (0 == ds) + { + index = -1; + return 0; + } + + OGRLayerH lyr = 0; + int const count = OGR_DS_GetLayerCount(ds); + + for (int i = 0; i < count; ++i) + { + OGRLayerH lyrTmp = OGR_DS_GetLayer(ds, i); + if (0 != lyrTmp) + { + OGRFeatureDefnH defn = OGR_L_GetLayerDefn(lyrTmp); + Q_ASSERT(0 != defn); + + QString nameTmp(OGR_FD_GetName(defn)); + if (name == nameTmp) + { + QgsDebugMsg("Layer found: " + nameTmp); + index = i; + lyr = lyrTmp; + break; + } + } + } + + return lyr; +} + +OGRDataSourceH Translator::openDataSource(QString const& url, bool readOnly) +{ + OGRDataSourceH ds = OGROpen(url.toAscii().constData(), !readOnly, 0); + if (0 == ds) + { + QgsDebugMsg("Failed to open: " + url); + } + + return ds; +} + +OGRDataSourceH Translator::openDataTarget(QString const& url, bool update) +{ + OGRDataSourceH ds = 0; + + if (update) + { + // Try opening the output datasource as an existing, writable + ds = openDataSource(url, false); + } + else + { + // Find the output driver + OGRSFDriverH drv = findDriver(mDstFormat); + if (0 == drv) + { + QgsDebugMsg("Could not find driver: " + mDstFormat); + return 0; + } + + // Create the output data source + // + // TODO: Add support for creation options + ds = OGR_Dr_CreateDataSource(drv, url.toAscii().constData(), 0); + if (0 == ds) + { + QgsDebugMsg("Failed to open: " + url); + } + } + + return ds; +} + +}}} // namespace qgis::plugin::ogrconv + Index: qgis/src/plugins/ogr_converter/ogrconverterguibase.ui =================================================================== --- qgis/src/plugins/ogr_converter/ogrconverterguibase.ui (revision 0) +++ qgis/src/plugins/ogr_converter/ogrconverterguibase.ui (revision 0) @@ -0,0 +1,378 @@ + + OgrConverterGuiBase + + + + 0 + 0 + 521 + 450 + + + + + 0 + 0 + + + + + 520 + 450 + + + + OGR Layer Converter + + + + + + + + + + + Source + + + + + 20 + 30 + 461 + 28 + + + + + + + + 52 + 22 + + + + Format: + + + + + + + + 200 + 0 + + + + 200 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 20 + 70 + 461 + 21 + + + + + + + File + + + + + + + Directory + + + + + + + Remote source + + + + + + + + + 21 + 140 + 461 + 28 + + + + + + + + 52 + 22 + + + + Layer: + + + + + + + + 300 + 0 + + + + + + + + Qt::Horizontal + + + + 88 + 17 + + + + + + + + + + 21 + 100 + 457 + 34 + + + + + + + Dataset: + + + + + + + + 300 + 0 + + + + + + + + + 90 + 0 + + + + Browse + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Target + + + + + 22 + 33 + 454 + 28 + + + + + + + + 52 + 22 + + + + Format: + + + + + + + + 300 + 0 + + + + 200 + + + + + + + Qt::Horizontal + + + + 88 + 17 + + + + + + + + + + 20 + 71 + 457 + 34 + + + + + + + Dataset: + + + + + + + + 300 + 0 + + + + + + + + + 90 + 0 + + + + Browse + + + + + + + + + 20 + 110 + 451 + 24 + + + + + + + + 52 + 0 + + + + Layer: + + + + + + + + 300 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + inputSrcDataset + buttonSelectSrc + + + + Index: qgis/src/plugins/ogr_converter/CMakeLists.txt =================================================================== --- qgis/src/plugins/ogr_converter/CMakeLists.txt (revision 0) +++ qgis/src/plugins/ogr_converter/CMakeLists.txt (revision 0) @@ -0,0 +1,65 @@ +# $Id$ +# +# CMake configuration file for OGR Converter plugin +# Author: Mateusz Loskot +######################################################## +# Files + +SET (OGR_CONVERTER_SRCS + plugin.cpp + dialog.cpp + format.cpp + translator.cpp +) + +SET (OGR_CONVERTER_UIS ogrconverterguibase.ui) + +SET (OGR_CONVERTER_MOC_HDRS + plugin.h + dialog.h +) + +SET (OGR_CONVERTER_RCCS ogrconverter.qrc) + +SET (OGR_CONVERTER_PLUGIN ogrconverterplugin) + +######################################################## +# Build + +QT4_WRAP_UI (OGR_CONVERTER_UIS_H ${OGR_CONVERTER_UIS}) + +QT4_WRAP_CPP (OGR_CONVERTER_MOC_SRCS ${OGR_CONVERTER_MOC_HDRS}) + +QT4_ADD_RESOURCES(OGR_CONVERTER_RCC_SRCS ${OGR_CONVERTER_RCCS}) + +ADD_LIBRARY (${OGR_CONVERTER_PLUGIN} MODULE + ${OGR_CONVERTER_SRCS} + ${OGR_CONVERTER_MOC_SRCS} + ${OGR_CONVERTER_RCC_SRCS} + ${OGR_CONVERTER_UIS_H} +) + +INCLUDE_DIRECTORIES ( + ${CMAKE_CURRENT_BINARY_DIR} + ../../core + ../../core/raster + ../../core/renderer + ../../core/symbology + ../../gui + .. + ${GDAL_INCLUDE_DIR} +) + +TARGET_LINK_LIBRARIES(${OGR_CONVERTER_PLUGIN} + ${GDAL_LIBRARY} + qgis_core + qgis_gui +) + +######################################################## +# Install + +INSTALL(TARGETS ${OGR_CONVERTER_PLUGIN} + RUNTIME DESTINATION ${QGIS_PLUGIN_DIR} + LIBRARY DESTINATION ${QGIS_PLUGIN_DIR} +) Index: qgis/src/plugins/ogr_converter/README =================================================================== --- qgis/src/plugins/ogr_converter/README (revision 0) +++ qgis/src/plugins/ogr_converter/README (revision 0) @@ -0,0 +1,35 @@ +OGR Layer Converter Pluginm, Version 0.1 (Alpha) +------------------------------------------------------------------------------ +Author: Mateusz Loskot + +OGR Layer Converter aims to be a GUI-based implementation of well-known +ogr2ogr utility from GDAL/OGR package. The plugin translates layers +between OGR supported formats built-in GDAL/OGR library available for +particular QGIS installation. +Built-in formats are listed in drop-down boxes. + +Currently, it is possible to translate one selected source +layer to another OGR format. + +Testing appreciated. + +------------------------------------------------------------------------------ + TODO +------------------------------------------------------------------------------ +translator.h: // TODO: Implement, currently always overwrite +translator.h: // TODO: Append option not supported +dialog.cpp:// TODO: Add support of QGIS projection selector +dialog.cpp: // TODO: Transformation support +dialog.cpp: // TODO: Transformation support +dialog.cpp: // TODO: SRS transformation support +dialog.cpp: // TODO: Use try-catch to display more meaningful error messages from Translator +plugin.cpp: // TODO: Who is responsible for OGR cleanup? +translator.cpp: // TODO: RAII for OGR handlers!!! +translator.cpp: // TODO: Support translation of all layers from input data source +translator.cpp: // TODO: -nlt option support +translator.cpp: // TODO: Implement SRS transformation +translator.cpp: // TODO: Append and createion options not implemented +translator.cpp: // TODO: RAII for feature handlers!!! +translator.cpp: // TODO: Transform feature geometry +translator.cpp: // TODO: Skip failures support +translator.cpp: // TODO: Add support for creation options Index: qgis/src/plugins/ogr_converter/format.h =================================================================== --- qgis/src/plugins/ogr_converter/format.h (revision 0) +++ qgis/src/plugins/ogr_converter/format.h (revision 0) @@ -0,0 +1,76 @@ +// $Id$ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2008 by Mateusz Loskot +// +// 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 QGIS_PLUGIN_OGRCONV_FORMATS_H_INCLUDED +#define QGIS_PLUGIN_OGRCONV_FORMATS_H_INCLUDED + +// Qt4 +#include +#include + +namespace qgis { namespace plugin { namespace ogrconv { + +class Format +{ +public: + + enum Type + { + eUnknown = 0, + eFile = 1, + eDirectory = 2, + eProtocol = 4 + }; + + Format(); + Format(QString const& c, QString const& n); + Format(QString const& c, QString const& n, unsigned char const& t); + Format(QString const& c, QString const& n, QString const& p, unsigned char const& t); + + QString const& code() const; + QString const& name() const; + QString const& protocol() const; + unsigned char const& type() const; + +private: + + QString mCode; + QString mName; + QString mProtocol; + unsigned char mTypeFlags; +}; + +inline bool isFormatType(unsigned char const& frmt, Format::Type const& type) +{ + return ((frmt & type) == type); +} + +class FormatsRegistry +{ +public: + + FormatsRegistry(); + + void add(Format const& frmt); + Format const& find(QString const& code); + +private: + + void init(); + + QMap mFrmts; + Format mCache; +}; + + +}}} // namespace qgis::plugin::ogrconv + +#endif // QGIS_PLUGIN_OGRCONV_FORMATS_H_INCLUDED