[QGIS Commit] r12350 - in trunk/qgis: python/core python/gui
src/app src/app/ogr src/core src/gui
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Mon Dec 7 12:14:42 EST 2009
Author: wonder
Date: 2009-12-07 12:14:41 -0500 (Mon, 07 Dec 2009)
New Revision: 12350
Added:
trunk/qgis/python/gui/qgsprojectbadlayerguihandler.sip
trunk/qgis/src/gui/qgsprojectbadlayerguihandler.cpp
trunk/qgis/src/gui/qgsprojectbadlayerguihandler.h
Removed:
trunk/qgis/src/core/qgsexception.cpp
Modified:
trunk/qgis/python/core/qgsproject.sip
trunk/qgis/python/gui/gui.sip
trunk/qgis/src/app/ogr/qgsopenvectorlayerdialog.cpp
trunk/qgis/src/app/ogr/qgsopenvectorlayerdialog.h
trunk/qgis/src/app/qgisapp.cpp
trunk/qgis/src/core/CMakeLists.txt
trunk/qgis/src/core/qgsexception.h
trunk/qgis/src/core/qgsproject.cpp
trunk/qgis/src/core/qgsproject.h
trunk/qgis/src/gui/CMakeLists.txt
trunk/qgis/src/gui/qgisgui.cpp
trunk/qgis/src/gui/qgisgui.h
Log:
Change in handling of missing layers within QgsProject. Instead of throwing an exception, now a custom handler is called
that might try to fix the missing layers. There's a default handler (QgsProjectBadLayerDefaultHandler) which simply ignores
all missing layers. Then there's a GUI handler (QgsProjectBadLayerGuiHandler) in GUI library which asks user about
the path for missing layers. QGIS application automatically installs the GUI handler on startup.
This should allow python plugins/applications to work with QgsProject without a fear of a segfault as there are no more
exceptions thrown during load/save of the project files.
Some further notes:
- removed QgsProjectBadLayerException class and (now empty) qgsexception.cpp file
- openFilesRememberingFilter() moved to QgisGui namespace (was duplicated: QgisApp vs QgsOpenVectorLayerDialog)
- removed deprecated buildVectorFilters_ methods
- added python bindings for new classes/methods
Modified: trunk/qgis/python/core/qgsproject.sip
===================================================================
--- trunk/qgis/python/core/qgsproject.sip 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/python/core/qgsproject.sip 2009-12-07 17:14:41 UTC (rev 12350)
@@ -235,6 +235,11 @@
@note added in 1.4 */
QString error() const;
+ /** Change handler for missing layers.
+ Deletes old handler and takes ownership of the new one.
+ @note added in 1.4 */
+ void setBadLayerHandler( QgsProjectBadLayerHandler* handler );
+
protected:
/** Set error message from read/write operation
@@ -259,3 +264,30 @@
}; // QgsProject
+
+/** Interface for classes that handle missing layer files when reading project file.
+ @note added in 1.4 */
+class QgsProjectBadLayerHandler
+{
+%TypeHeaderCode
+#include <qgsproject.h>
+%End
+
+public:
+ virtual void handleBadLayers( QList<QDomNode> layers, QDomDocument projectDom ) = 0;
+ virtual ~QgsProjectBadLayerHandler();
+};
+
+
+/** Default bad layer handler which ignores any missing layers.
+ @note added in 1.4 */
+class QgsProjectBadLayerDefaultHandler : QgsProjectBadLayerHandler
+{
+%TypeHeaderCode
+#include <qgsproject.h>
+%End
+
+public:
+ virtual void handleBadLayers( QList<QDomNode> layers, QDomDocument projectDom );
+
+};
Modified: trunk/qgis/python/gui/gui.sip
===================================================================
--- trunk/qgis/python/gui/gui.sip 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/python/gui/gui.sip 2009-12-07 17:14:41 UTC (rev 12350)
@@ -22,6 +22,7 @@
%Include qgsmaptoolzoom.sip
%Include qgsmapoverviewcanvas.sip
%Include qgsmessageviewer.sip
+%Include qgsprojectbadlayerguihandler.sip
%Include qgsprojectionselector.sip
%Include qgsquickprint.sip
%Include qgsrubberband.sip
Added: trunk/qgis/python/gui/qgsprojectbadlayerguihandler.sip
===================================================================
--- trunk/qgis/python/gui/qgsprojectbadlayerguihandler.sip (rev 0)
+++ trunk/qgis/python/gui/qgsprojectbadlayerguihandler.sip 2009-12-07 17:14:41 UTC (rev 12350)
@@ -0,0 +1,21 @@
+
+/** \ingroup gui
+ Handler for missing layers within project.
+
+ Gives user a chance to select path to the missing layers.
+
+ @note added in 1.4
+ */
+class QgsProjectBadLayerGuiHandler : QObject, QgsProjectBadLayerHandler
+{
+%TypeHeaderCode
+#include <qgsprojectbadlayerguihandler.h>
+%End
+
+ public:
+ QgsProjectBadLayerGuiHandler();
+
+ /** implementation of the handler */
+ virtual void handleBadLayers( QList<QDomNode> layers, QDomDocument projectDom );
+
+};
Modified: trunk/qgis/src/app/ogr/qgsopenvectorlayerdialog.cpp
===================================================================
--- trunk/qgis/src/app/ogr/qgsopenvectorlayerdialog.cpp 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/app/ogr/qgsopenvectorlayerdialog.cpp 2009-12-07 17:14:41 UTC (rev 12350)
@@ -97,11 +97,11 @@
QStringList selectedFiles;
QgsDebugMsg( "Vector file filters: " + mVectorFileFilter );
- QString enc;
+ QString enc = encoding();
QString title = tr( "Open an OGR Supported Vector Layer" );
- openFilesRememberingFilter( "lastVectorFileFilter", mVectorFileFilter, selectedFiles,
- title );
- mEnc = enc;
+ QgisGui::openFilesRememberingFilter( "lastVectorFileFilter", mVectorFileFilter, selectedFiles, enc,
+ title );
+
return selectedFiles;
}
@@ -306,70 +306,8 @@
}
-/**
- Open files, preferring to have the default file selector be the
- last one used, if any; also, prefer to start in the last directory
- associated with filterName.
- @param filterName the name of the filter; used for persistent store
- key
- @param filters the file filters used for QFileDialog
- @param selectedFiles string list of selected files; will be empty
- if none selected
- @param title the title for the dialog
- @note
-
- Stores persistent settings under /UI/. The sub-keys will be
- filterName and filterName + "Dir".
-
- Opens dialog on last directory associated with the filter name, or
- the current working directory if this is the first time invoked
- with the current filter name.
-
-*/
-void QgsOpenVectorLayerDialog::openFilesRememberingFilter( QString const &filterName,
- QString const &filters, QStringList & selectedFiles, QString &title )
-{
-
- bool haveLastUsedFilter = false; // by default, there is no last
- // used filter
-
- QSettings settings; // where we keep last used filter in
-
- // persistant state
-
- haveLastUsedFilter = settings.contains( "/UI/" + filterName );
- QString lastUsedFilter = settings.value( "/UI/" + filterName,
- QVariant( QString::null ) ).toString();
-
- QString lastUsedDir = settings.value( "/UI/" + filterName + "Dir", "." ).toString();
- QgsDebugMsg( "Opening file dialog with filters: " + filters );
-
- if ( haveLastUsedFilter )
- {
- selectedFiles = QFileDialog::getOpenFileNames( 0, title, lastUsedDir, filters, &lastUsedFilter );
- }
- else
- {
- selectedFiles = QFileDialog::getOpenFileNames( 0, title, lastUsedDir, filters );
- }
-
- if ( !selectedFiles.isEmpty() )
- {
- QString myFirstFileName = selectedFiles.first();
- QFileInfo myFI( myFirstFileName );
- QString myPath = myFI.path();
-
- QgsDebugMsg( "Writing last used dir: " + myPath );
-
- settings.setValue( "/UI/" + filterName, lastUsedFilter );
- settings.setValue( "/UI/" + filterName + "Dir", myPath );
- }
-} // openFilesRememberingFilter_
-
-
-
//********************auto connected slots *****************/
void QgsOpenVectorLayerDialog::on_buttonBox_accepted()
{
Modified: trunk/qgis/src/app/ogr/qgsopenvectorlayerdialog.h
===================================================================
--- trunk/qgis/src/app/ogr/qgsopenvectorlayerdialog.h 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/app/ogr/qgsopenvectorlayerdialog.h 2009-12-07 17:14:41 UTC (rev 12350)
@@ -46,9 +46,6 @@
//! Returns the connection type
QString dataSourceType();
private:
- //! Shows a dialog remembering the last directory and filter selected */
- void openFilesRememberingFilter( QString const &filterName,
- QString const &filters, QStringList & selectedFiles, QString &title );
//! Stores the file vector filters */
QString mVectorFileFilter;
//! Stores the selected datasources */
Modified: trunk/qgis/src/app/qgisapp.cpp
===================================================================
--- trunk/qgis/src/app/qgisapp.cpp 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/app/qgisapp.cpp 2009-12-07 17:14:41 UTC (rev 12350)
@@ -126,6 +126,7 @@
#include "qgspluginregistry.h"
#include "qgspoint.h"
#include "qgsproject.h"
+#include "qgsprojectbadlayerguihandler.h"
#include "qgsprojectproperties.h"
#include "qgsproviderregistry.h"
#include "qgsrasterlayer.h"
@@ -211,13 +212,7 @@
const int AFTER_RECENT_PATHS = 321;
-/// build the vector file filter string for a QFileDialog
-/*
- called in ctor for initializing mVectorFileFilter
- */
-static void buildSupportedVectorFileFilter_( QString & fileFilters );
-
/** set the application title bar text
If the current project title is null
@@ -426,10 +421,13 @@
mSplash->showMessage( tr( "Initializing file filters" ), Qt::AlignHCenter | Qt::AlignBottom );
qApp->processEvents();
// now build vector file filter
- buildSupportedVectorFileFilter_( mVectorFileFilter );
-
+ mVectorFileFilter = QgsProviderRegistry::instance()->fileVectorFilters();
// now build raster file filter
QgsRasterLayer::buildSupportedRasterFileFilter( mRasterFileFilter );
+
+ // set handler for missing layers (will be owned by QgsProject)
+ QgsProject::instance()->setBadLayerHandler( new QgsProjectBadLayerGuiHandler() );
+
#if 0
// Set the background colour for toolbox and overview as they default to
// white instead of the window color
@@ -2203,238 +2201,8 @@
-/**
- Builds the list of file filter strings to later be used by
- QgisApp::addVectorLayer()
- We query OGR for a list of supported vector formats; we then build a list
- of file filter strings from that list. We return a string that contains
- this list that is suitable for use in a a QFileDialog::getOpenFileNames()
- call.
-
- XXX Most of the file name filters need to be filled in; however we
- XXX may want to wait until we've tested each format before committing
- XXX them permanently instead of blindly relying on OGR to properly
- XXX supply all needed spatial data.
-
-*/
-static void buildSupportedVectorFileFilter_( QString & fileFilters )
-{
-
-#ifdef DEPRECATED
- static QString myFileFilters;
-
- // if we've already built the supported vector string, just return what
- // we've already built
- if ( !( myFileFilters.isEmpty() || myFileFilters.isNull() ) )
- {
- fileFilters = myFileFilters;
-
- return;
- }
-
- // then iterate through all of the supported drivers, adding the
- // corresponding file filter
-
- OGRSFDriverH driver; // current driver
-
- QString driverName; // current driver name
-
- // Grind through all the drivers and their respective metadata.
- // We'll add a file filter for those drivers that have a file
- // extension defined for them; the others, welll, even though
- // theoreticaly we can open those files because there exists a
- // driver for them, the user will have to use the "All Files" to
- // open datasets with no explicitly defined file name extension.
- QgsDebugMsg( "Driver count: " + QString::number( driverRegistrar->GetDriverCount() ) );
-
- for ( int i = 0; i < OGRGetDriverCount(); ++i )
- {
- driver = OGRGetDriver( i );
-
- Q_CHECK_PTR( driver );
-
- if ( !driver )
- {
- QgsDebugMsg( QString( "unable to get driver %1" ).arg( i ) );
- continue;
- }
-
- driverName = OGR_Dr_GetName( driver );
-
- if ( driverName.startsWith( "ESRI" ) )
- {
- myFileFilters += createFileFilter_( "ESRI Shapefiles", "*.shp" );
- }
- else if ( driverName.startsWith( "UK" ) )
- {
- // XXX needs file filter extension
- }
- else if ( driverName.startsWith( "SDTS" ) )
- {
- myFileFilters += createFileFilter_( "Spatial Data Transfer Standard",
- "*catd.ddf" );
- }
- else if ( driverName.startsWith( "TIGER" ) )
- {
- // XXX needs file filter extension
- }
- else if ( driverName.startsWith( "S57" ) )
- {
- // XXX needs file filter extension
- }
- else if ( driverName.startsWith( "MapInfo" ) )
- {
- myFileFilters += createFileFilter_( "MapInfo", "*.mif *.tab" );
- // XXX needs file filter extension
- }
- else if ( driverName.startsWith( "DGN" ) )
- {
- // XXX needs file filter extension
- }
- else if ( driverName.startsWith( "VRT" ) )
- {
- // XXX needs file filter extension
- }
- else if ( driverName.startsWith( "AVCBin" ) )
- {
- // XXX needs file filter extension
- }
- else if ( driverName.startsWith( "REC" ) )
- {
- // XXX needs file filter extension
- }
- else if ( driverName.startsWith( "Memory" ) )
- {
- // XXX needs file filter extension
- }
- else if ( driverName.startsWith( "Jis" ) )
- {
- // XXX needs file filter extension
- }
- else if ( driverName.startsWith( "GML" ) )
- {
- // XXX not yet supported; post 0.1 release task
- myFileFilters += createFileFilter_( "Geography Markup Language",
- "*.gml" );
- }
- else
- {
- // NOP, we don't know anything about the current driver
- // with regards to a proper file filter string
- QgsDebugMsg( "unknown driver " + driverName );
- }
-
- } // each loaded GDAL driver
-
- QgsDebugMsg( myFileFilters );
-
- // can't forget the default case
-
- myFileFilters += "All files (*.*)";
- fileFilters = myFileFilters;
-
-#endif // DEPRECATED
-
- fileFilters = QgsProviderRegistry::instance()->fileVectorFilters();
- //QgsDebugMsg("Vector file filters: " + fileFilters);
-
-} // buildSupportedVectorFileFilter_()
-
-
-
-
/**
- Open files, preferring to have the default file selector be the
- last one used, if any; also, prefer to start in the last directory
- associated with filterName.
-
- @param filterName the name of the filter; used for persistent store
- key
- @param filters the file filters used for QFileDialog
-
- @param selectedFiles string list of selected files; will be empty
- if none selected
- @param enc encoding?
- @param title the title for the dialog
- @note
-
- Stores persistent settings under /UI/. The sub-keys will be
- filterName and filterName + "Dir".
-
- Opens dialog on last directory associated with the filter name, or
- the current working directory if this is the first time invoked
- with the current filter name.
-
- This method returns true if cancel all was clicked, otherwise false
-
-*/
-
-static bool openFilesRememberingFilter_( QString const &filterName,
- QString const &filters, QStringList & selectedFiles, QString& enc, QString &title,
- bool cancelAll = false )
-{
-
- bool haveLastUsedFilter = false; // by default, there is no last
- // used filter
-
- QSettings settings; // where we keep last used filter in
- // persistant state
-
- haveLastUsedFilter = settings.contains( "/UI/" + filterName );
- QString lastUsedFilter = settings.value( "/UI/" + filterName,
- QVariant( QString::null ) ).toString();
-
- QString lastUsedDir = settings.value( "/UI/" + filterName + "Dir", "." ).toString();
-
- QgsDebugMsg( "Opening file dialog with filters: " + filters );
- if ( !cancelAll )
- {
- selectedFiles = QFileDialog::getOpenFileNames( 0, title, lastUsedDir, filters, &lastUsedFilter );
- }
- else //we have to use non-native dialog to add cancel all button
- {
- QgsEncodingFileDialog* openFileDialog = new QgsEncodingFileDialog( 0, title, lastUsedDir, filters, QString( "" ) );
- // allow for selection of more than one file
- openFileDialog->setFileMode( QFileDialog::ExistingFiles );
- if ( haveLastUsedFilter ) // set the filter to the last one used
- {
- openFileDialog->selectFilter( lastUsedFilter );
- }
- openFileDialog->addCancelAll();
- if ( openFileDialog->exec() == QDialog::Accepted )
- {
- selectedFiles = openFileDialog->selectedFiles();
- }
- else
- {
- //cancel or cancel all?
- if ( openFileDialog->cancelAll() )
- {
- return true;
- }
- }
- }
-
- if ( !selectedFiles.isEmpty() )
- {
- // Fix by Tim - getting the dirPath from the dialog
- // directly truncates the last node in the dir path.
- // This is a workaround for that
- QString myFirstFileName = selectedFiles.first();
- QFileInfo myFI( myFirstFileName );
- QString myPath = myFI.path();
-
- QgsDebugMsg( "Writing last used dir: " + myPath );
-
- settings.setValue( "/UI/" + filterName, lastUsedFilter );
- settings.setValue( "/UI/" + filterName + "Dir", myPath );
- }
- return false;
-} // openFilesRememberingFilter_
-
-
-/**
This method prompts the user for a list of vector file names with a dialog.
*/
void QgisApp::addVectorLayer()
@@ -2819,300 +2587,6 @@
-/// file data representation
-enum dataType { IS_VECTOR, IS_RASTER, IS_BOGUS };
-
-
-
-/** returns data type associated with the given QgsProject file Dom node
-
- The Dom node should represent the state associated with a specific layer.
- */
-static
-dataType
-dataType_( QDomNode & layerNode )
-{
- QString type = layerNode.toElement().attribute( "type" );
-
- if ( QString::null == type )
- {
- QgsDebugMsg( "cannot find ``type'' attribute" );
-
- return IS_BOGUS;
- }
-
- if ( "raster" == type )
- {
- QgsDebugMsg( "is a raster" );
-
- return IS_RASTER;
- }
- else if ( "vector" == type )
- {
- QgsDebugMsg( "is a vector" );
-
- return IS_VECTOR;
- }
-
- QgsDebugMsg( "is unknown type " + type );
-
- return IS_BOGUS;
-} // dataType_( QDomNode & layerNode )
-
-
-/** return the data source for the given layer
-
- The QDomNode is a QgsProject Dom node corresponding to a map layer state.
-
- Essentially dumps <datasource> tag.
-
-*/
-static
-QString
-dataSource_( QDomNode & layerNode )
-{
- QDomNode dataSourceNode = layerNode.namedItem( "datasource" );
-
- if ( dataSourceNode.isNull() )
- {
- QgsDebugMsg( "cannot find datasource node" );
-
- return QString::null;
- }
-
- return dataSourceNode.toElement().text();
-
-} // dataSource_( QDomNode & layerNode )
-
-
-
-/// the three flavors for data
-typedef enum { IS_FILE, IS_DATABASE, IS_URL, IS_Unknown } providerType;
-
-
-/** return the physical storage type associated with the given layer
-
- The QDomNode is a QgsProject Dom node corresponding to a map layer state.
-
- If the <provider> is "ogr", then it's a file type.
-
- However, if the layer is a raster, then there won't be a <provider> tag. It
- will always have an associated file.
-
- If the layer doesn't fall into either of the previous two categories, then
- it's either a database or URL. If the <datasource> tag has "url=", then
- it's URL based. If the <datasource> tag has "dbname=">, then the layer data
- is in a database.
-
-*/
-static
-providerType
-providerType_( QDomNode & layerNode )
-{
- // XXX but what about rasters that can be URLs? _Can_ they be URLs?
-
- switch ( dataType_( layerNode ) )
- {
- case IS_VECTOR:
- {
- QString dataSource = dataSource_( layerNode );
-
- QgsDebugMsg( "datasource is " + dataSource );
-
- if ( dataSource.contains( "host=" ) )
- {
- return IS_URL;
- }
-#ifdef HAVE_POSTGRESQL
- else if ( dataSource.contains( "dbname=" ) )
- {
- return IS_DATABASE;
- }
-#endif
- // be default, then, this should be a file based layer data source
- // XXX is this a reasonable assumption?
-
- return IS_FILE;
- }
-
- case IS_RASTER: // rasters are currently only accessed as
- // physical files
- return IS_FILE;
-
- default:
- QgsDebugMsg( "unknown ``type'' attribute" );
- }
-
- return IS_Unknown;
-
-} // providerType_
-
-
-
-/** set the <datasource> to the new value
-*/
-static
-void
-setDataSource_( QDomNode & layerNode, QString const & dataSource )
-{
- QDomNode dataSourceNode = layerNode.namedItem( "datasource" );
- QDomElement dataSourceElement = dataSourceNode.toElement();
- QDomText dataSourceText = dataSourceElement.firstChild().toText();
-
- QgsDebugMsg( "datasource changed from " + dataSourceText.data() );
-
- dataSourceText.setData( dataSource );
-
- QgsDebugMsg( "to " + dataSourceText.data() );
-} // setDataSource_
-
-
-
-
-/** this is used to locate files that have moved or otherwise are missing
-
-*/
-static
-bool
-findMissingFile_( QString const & fileFilters, QDomNode & layerNode )
-{
- // Prepend that file name to the valid file format filter list since it
- // makes it easier for the user to not only find the original file, but to
- // perhaps find a similar file.
-
- QFileInfo originalDataSource( dataSource_( layerNode ) );
-
- QString memoryQualifier; // to differentiate between last raster and
- // vector directories
-
- switch ( dataType_( layerNode ) )
- {
- case IS_VECTOR:
- {
- memoryQualifier = "lastVectorFileFilter";
-
- break;
- }
- case IS_RASTER:
- {
- memoryQualifier = "lastRasterFileFilter";
-
- break;
- }
- default:
- QgsDebugMsg( "unable to determine data type" );
- return false;
- }
-
- // Prepend the original data source base name to make it easier to pick it
- // out from a list of other files; however the appropriate filter strings
- // for the file type will also be added in case the file name itself has
- // changed, too.
-
- QString myFileFilters = originalDataSource.fileName() + ";;" + fileFilters;
-
- QStringList selectedFiles;
- QString enc;
- QString title = QObject::tr( "Where is '%1' (original location: %2)?" )
- .arg( originalDataSource.fileName() )
- .arg( originalDataSource.absoluteFilePath() );
-
- bool retVal = openFilesRememberingFilter_( memoryQualifier,
- myFileFilters,
- selectedFiles,
- enc,
- title,
- true );
-
- if ( selectedFiles.isEmpty() )
- {
- return retVal;
- }
- else
- {
- setDataSource_( layerNode, selectedFiles.first() );
- if ( ! QgsProject::instance()->read( layerNode ) )
- {
- QgsDebugMsg( "unable to re-read layer" );
- }
- }
- return retVal;
-} // findMissingFile_
-
-
-
-
-/** find relocated data source for the given layer
-
- This QDom object represents a QgsProject node that maps to a specific layer.
-
- @param layerNode QDom node containing layer project information
-
- @todo
-
- XXX Only implemented for file based layers. It will need to be extended for
- XXX other data source types such as databases.
-
-*/
-static
-bool
-findLayer_( QString const & fileFilters, QDomNode const & constLayerNode )
-{
- // XXX actually we could possibly get away with a copy of the node
- QDomNode & layerNode = const_cast<QDomNode&>( constLayerNode );
-
- bool retVal = false;
-
- switch ( providerType_( layerNode ) )
- {
- case IS_FILE:
- QgsDebugMsg( "layer is file based" );
- retVal = findMissingFile_( fileFilters, layerNode );
- break;
-
- case IS_DATABASE:
- QgsDebugMsg( "layer is database based" );
- break;
-
- case IS_URL:
- QgsDebugMsg( "layer is URL based" );
- break;
-
- case IS_Unknown:
- QgsDebugMsg( "layer has an unkown type" );
- break;
- }
- return retVal;
-} // findLayer_
-
-
-
-
-/** find relocated data sources for given layers
-
- These QDom objects represent QgsProject nodes that map to specific layers.
-
-*/
-static
-void
-findLayers_( QString const & fileFilters, std::list<QDomNode> const & layerNodes )
-{
-
- for ( std::list<QDomNode>::const_iterator i = layerNodes.begin();
- i != layerNodes.end();
- ++i )
- {
- if ( findLayer_( fileFilters, *i ) )
- {
- // If findLayer returns true, the user hit Cancel All button
- break;
- }
- }
-
-} // findLayers_
-
-
-
void QgisApp::fileExit()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
@@ -3366,31 +2840,14 @@
QgsProject::instance()->setFileName( fullPath );
- try
+ if ( ! QgsProject::instance()->read() )
{
- if ( ! QgsProject::instance()->read() )
- {
- QMessageBox::critical( this,
- tr( "QGIS Project Read Error" ),
- QgsProject::instance()->error() );
- mMapCanvas->freeze( false );
- mMapCanvas->refresh();
- return;
- }
- }
- catch ( QgsProjectBadLayerException & e )
- {
QMessageBox::critical( this,
tr( "QGIS Project Read Error" ),
- QString::fromLocal8Bit( e.what() ) );
- QgsDebugMsg( QString( "%1 bad layers found" ).arg( e.layers().size() ) );
-
- // attempt to find the new locations for missing layers
- // XXX vector file hard-coded -- but what if it's raster?
- findLayers_( mVectorFileFilter, e.layers() );
-
- // Tell the legend to update the ordering
- mMapLegend->readProject( e.document() );
+ QgsProject::instance()->error() );
+ mMapCanvas->freeze( false );
+ mMapCanvas->refresh();
+ return;
}
setTitleBarText_( *this );
@@ -3425,51 +2882,19 @@
// clear the map canvas
removeAllLayers();
- try
+ if ( ! QgsProject::instance()->read( projectFile ) )
{
- if ( ! QgsProject::instance()->read( projectFile ) )
- {
- QMessageBox::critical( this,
- tr( "Unable to open project" ),
- QgsProject::instance()->error() );
+ QMessageBox::critical( this,
+ tr( "Unable to open project" ),
+ QgsProject::instance()->error() );
- QApplication::restoreOverrideCursor();
+ QApplication::restoreOverrideCursor();
- mMapCanvas->freeze( false );
- mMapCanvas->refresh();
- return false;
- }
- // Continue after last catch statement
-
+ mMapCanvas->freeze( false );
+ mMapCanvas->refresh();
+ return false;
}
- catch ( QgsProjectBadLayerException & e )
- {
- QgsDebugMsg( QString( "%1 bad layers found" ).arg( e.layers().size() ) );
- if ( QMessageBox::Ok == QMessageBox::critical( this,
- tr( "QGIS Project Read Error" ),
- tr( "%1\nTry to find missing layers?" ).arg( QString::fromLocal8Bit( e.what() ) ),
- QMessageBox::Ok | QMessageBox::Cancel ) )
- {
- QgsDebugMsg( "want to find missing layers is true" );
-
- // attempt to find the new locations for missing layers
- // XXX vector file hard-coded -- but what if it's raster?
- QApplication::restoreOverrideCursor();
-
- findLayers_( mVectorFileFilter, e.layers() );
-
- QApplication::setOverrideCursor( Qt::WaitCursor );
-
- // Tell the legend to update the ordering
- mMapLegend->readProject( e.document() );
- }
- // Continue after last catch statement
-
- }
-
- // Continue, now with layers found (hopefully)
-
setTitleBarText_( *this );
int myRedInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorRedPart", 255 );
int myGreenInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorGreenPart", 255 );
@@ -5973,8 +5398,8 @@
QStringList selectedFiles;
QString e;//only for parameter correctness
QString title = tr( "Open a GDAL Supported Raster Data Source" );
- openFilesRememberingFilter_( "lastRasterFileFilter", mRasterFileFilter, selectedFiles, e,
- title );
+ QgisGui::openFilesRememberingFilter( "lastRasterFileFilter", mRasterFileFilter, selectedFiles, e,
+ title );
if ( selectedFiles.isEmpty() )
{
Modified: trunk/qgis/src/core/CMakeLists.txt
===================================================================
--- trunk/qgis/src/core/CMakeLists.txt 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/core/CMakeLists.txt 2009-12-07 17:14:41 UTC (rev 12350)
@@ -29,7 +29,6 @@
qgscoordinatetransform.cpp
qgsdatasourceuri.cpp
qgsdistancearea.cpp
- qgsexception.cpp
qgsfeature.cpp
qgsfield.cpp
qgsgeometry.cpp
Deleted: trunk/qgis/src/core/qgsexception.cpp
===================================================================
--- trunk/qgis/src/core/qgsexception.cpp 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/core/qgsexception.cpp 2009-12-07 17:14:41 UTC (rev 12350)
@@ -1,27 +0,0 @@
-/***************************************************************************
- qgsexception.cpp - description
- -------------------
- begin : Time-stamp: <2005-04-28 14:30:58 mcoletti>
- copyright : (C) 2002 by Mark Coletti
- email : mcoletti 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 <QObject>
-#include "qgsexception.h"
-
-
-const char * const ident_ = "$Id$";
-
-
-
-
-const char * QgsProjectBadLayerException::msg_ = "Unable to open one or more project layers";
Modified: trunk/qgis/src/core/qgsexception.h
===================================================================
--- trunk/qgis/src/core/qgsexception.h 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/core/qgsexception.h 2009-12-07 17:14:41 UTC (rev 12350)
@@ -56,49 +56,4 @@
}; // class QgsException
-
-/** for files missing from layers while reading project files
-
-*/
-class QgsProjectBadLayerException : public QgsException
-{
- public:
-
- QgsProjectBadLayerException( std::list<QDomNode> const & layers, QDomDocument const & doc = QDomDocument() )
- : QgsException( std::string( msg_ ) ),
- mBrokenLayers( layers ),
- mProjectDom( doc )
- {}
-
- ~QgsProjectBadLayerException() throw()
- {}
-
- std::list<QDomNode> const & layers() const
- {
- return mBrokenLayers;
- }
-
- QDomDocument const & document() const
- {
- return mProjectDom;
- }
- private:
-
- /** QDomNodes representing the state of a layer that couldn't be loaded
-
- The layer data was either relocated or deleted. The Dom node also
- contains ancillary data such as line widths and the like.
-
- */
- std::list<QDomNode> mBrokenLayers;
-
- // A default empty document does not contain any extra information
- QDomDocument mProjectDom;
-
- static const char * msg_;
-
-}; // class QgsProjectBadLayerException
-
-
-
#endif
Modified: trunk/qgis/src/core/qgsproject.cpp
===================================================================
--- trunk/qgis/src/core/qgsproject.cpp 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/core/qgsproject.cpp 2009-12-07 17:14:41 UTC (rev 12350)
@@ -340,7 +340,7 @@
QgsProject::QgsProject()
- : imp_( new QgsProject::Imp )
+ : imp_( new QgsProject::Imp ), mBadLayerHandler( new QgsProjectBadLayerDefaultHandler() )
{
// Set some default project properties
// XXX THESE SHOULD BE MOVED TO STATUSBAR RELATED SOURCE
@@ -355,6 +355,8 @@
QgsProject::~QgsProject()
{
+ delete mBadLayerHandler;
+
// note that std::auto_ptr automatically deletes imp_ when it's destroyed
} // QgsProject dtor
@@ -642,7 +644,7 @@
</maplayer>
*/
-std::pair< bool, std::list<QDomNode> > QgsProject::_getMapLayers( QDomDocument const &doc )
+QPair< bool, QList<QDomNode> > QgsProject::_getMapLayers( QDomDocument const &doc )
{
// Layer order is set by the restoring the legend settings from project file.
// This is done on the 'readProject( ... ) signal
@@ -653,7 +655,7 @@
QString wk;
- std::list<QDomNode> brokenNodes; // a list of Dom nodes corresponding to layers
+ QList<QDomNode> brokenNodes; // a list of Dom nodes corresponding to layers
// that we were unable to load; this could be
// because the layers were removed or
// re-located after the project was last saved
@@ -662,7 +664,7 @@
if ( 0 == nl.count() ) // if we have no layers to process, bail
{
- return make_pair( true, brokenNodes ); // Decided to return "true" since it's
+ return qMakePair( true, brokenNodes ); // Decided to return "true" since it's
// possible for there to be a project with no
// layers; but also, more imporantly, this
// would cause the tests/qgsproject to fail
@@ -700,7 +702,7 @@
{
QgsDebugMsg( "Unable to create layer" );
- return make_pair( false, brokenNodes );
+ return qMakePair( false, brokenNodes );
}
// have the layer restore state that is stored in Dom node
@@ -722,7 +724,7 @@
emit layerLoaded( i + 1, nl.count() );
}
- return make_pair( returnStatus, brokenNodes );
+ return qMakePair( returnStatus, brokenNodes );
} // _getMapLayers
@@ -835,7 +837,7 @@
// get the map layers
- std::pair< bool, std::list<QDomNode> > getMapLayersResults = _getMapLayers( *doc );
+ QPair< bool, QList<QDomNode> > getMapLayersResults = _getMapLayers( *doc );
// review the integrity of the retrieved map layers
@@ -843,18 +845,14 @@
{
QgsDebugMsg( "Unable to get map layers from project file." );
- if ( ! getMapLayersResults.second.empty() )
+ if ( ! getMapLayersResults.second.isEmpty() )
{
QgsDebugMsg( "there are " + QString::number( getMapLayersResults.second.size() ) + " broken layers" );
}
- // Since we could be executing this from the test harness which
- // doesn't *have* layers -- nor a GUI for that matter -- we'll just
- // leave in the whining and boldly stomp on.
- emit readProject( *doc );
- throw QgsProjectBadLayerException( getMapLayersResults.second, *doc );
-
-// return false;
+ // we let a custom handler to decide what to do with missing layers
+ // (default implementation ignores them, there's also a GUI handler that lets user choose correct path)
+ mBadLayerHandler->handleBadLayers( getMapLayersResults.second, *doc );
}
// read the project: used by map canvas and legend
@@ -1480,3 +1478,14 @@
{
setError( QString() );
}
+
+void QgsProject::setBadLayerHandler( QgsProjectBadLayerHandler* handler )
+{
+ delete mBadLayerHandler;
+ mBadLayerHandler = handler;
+}
+
+void QgsProjectBadLayerDefaultHandler::handleBadLayers( QList<QDomNode> /*layers*/, QDomDocument /*projectDom*/ )
+{
+ // just ignore any bad layers
+}
Modified: trunk/qgis/src/core/qgsproject.h
===================================================================
--- trunk/qgis/src/core/qgsproject.h 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/core/qgsproject.h 2009-12-07 17:14:41 UTC (rev 12350)
@@ -25,6 +25,8 @@
#include <memory>
#include "qgsprojectversion.h"
#include <QObject>
+#include <QList>
+#include <QPair>
//#include <QDomDocument>
@@ -32,6 +34,7 @@
class QDomDocument;
class QDomNode;
+class QgsProjectBadLayerHandler;
/** \ingroup core
* Reads and writes project states.
@@ -268,6 +271,11 @@
@note added in 1.4 */
QString error() const;
+ /** Change handler for missing layers.
+ Deletes old handler and takes ownership of the new one.
+ @note added in 1.4 */
+ void setBadLayerHandler( QgsProjectBadLayerHandler* handler );
+
protected:
/** Set error message from read/write operation
@@ -307,10 +315,32 @@
static QgsProject * theProject_;
- std::pair< bool, std::list<QDomNode> > _getMapLayers( QDomDocument const &doc );
+ QPair< bool, QList<QDomNode> > _getMapLayers( QDomDocument const &doc );
QString mErrorMessage;
+ QgsProjectBadLayerHandler* mBadLayerHandler;
+
}; // QgsProject
+
+/** Interface for classes that handle missing layer files when reading project file.
+ @note added in 1.4 */
+class CORE_EXPORT QgsProjectBadLayerHandler
+{
+ public:
+ virtual void handleBadLayers( QList<QDomNode> layers, QDomDocument projectDom ) = 0;
+ virtual ~QgsProjectBadLayerHandler() {}
+};
+
+
+/** Default bad layer handler which ignores any missing layers.
+ @note added in 1.4 */
+class CORE_EXPORT QgsProjectBadLayerDefaultHandler : public QgsProjectBadLayerHandler
+{
+ public:
+ virtual void handleBadLayers( QList<QDomNode> layers, QDomDocument projectDom );
+
+};
+
#endif
Modified: trunk/qgis/src/gui/CMakeLists.txt
===================================================================
--- trunk/qgis/src/gui/CMakeLists.txt 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/gui/CMakeLists.txt 2009-12-07 17:14:41 UTC (rev 12350)
@@ -39,6 +39,7 @@
qgsmaptoolpan.cpp
qgsmaptoolzoom.cpp
qgsmessageviewer.cpp
+qgsprojectbadlayerguihandler.cpp
qgsprojectionselector.cpp
qgsquickprint.cpp
qgsrubberband.cpp
Modified: trunk/qgis/src/gui/qgisgui.cpp
===================================================================
--- trunk/qgis/src/gui/qgisgui.cpp 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/gui/qgisgui.cpp 2009-12-07 17:14:41 UTC (rev 12350)
@@ -14,3 +14,75 @@
***************************************************************************/
#include "qgisgui.h"
+#include <QSettings>
+#include "qgsencodingfiledialog.h"
+#include "qgslogger.h"
+
+namespace QgisGui
+{
+
+ bool openFilesRememberingFilter( QString const &filterName,
+ QString const &filters, QStringList & selectedFiles, QString& enc, QString &title,
+ bool cancelAll )
+ {
+
+ bool haveLastUsedFilter = false; // by default, there is no last
+ // used filter
+
+ QSettings settings; // where we keep last used filter in
+ // persistant state
+
+ haveLastUsedFilter = settings.contains( "/UI/" + filterName );
+ QString lastUsedFilter = settings.value( "/UI/" + filterName,
+ QVariant( QString::null ) ).toString();
+
+ QString lastUsedDir = settings.value( "/UI/" + filterName + "Dir", "." ).toString();
+
+ QgsDebugMsg( "Opening file dialog with filters: " + filters );
+ if ( !cancelAll )
+ {
+ selectedFiles = QFileDialog::getOpenFileNames( 0, title, lastUsedDir, filters, &lastUsedFilter );
+ }
+ else //we have to use non-native dialog to add cancel all button
+ {
+ QgsEncodingFileDialog* openFileDialog = new QgsEncodingFileDialog( 0, title, lastUsedDir, filters, QString( "" ) );
+ // allow for selection of more than one file
+ openFileDialog->setFileMode( QFileDialog::ExistingFiles );
+ if ( haveLastUsedFilter ) // set the filter to the last one used
+ {
+ openFileDialog->selectFilter( lastUsedFilter );
+ }
+ openFileDialog->addCancelAll();
+ if ( openFileDialog->exec() == QDialog::Accepted )
+ {
+ selectedFiles = openFileDialog->selectedFiles();
+ }
+ else
+ {
+ //cancel or cancel all?
+ if ( openFileDialog->cancelAll() )
+ {
+ return true;
+ }
+ }
+ }
+
+ if ( !selectedFiles.isEmpty() )
+ {
+ // Fix by Tim - getting the dirPath from the dialog
+ // directly truncates the last node in the dir path.
+ // This is a workaround for that
+ QString myFirstFileName = selectedFiles.first();
+ QFileInfo myFI( myFirstFileName );
+ QString myPath = myFI.path();
+
+ QgsDebugMsg( "Writing last used dir: " + myPath );
+
+ settings.setValue( "/UI/" + filterName, lastUsedFilter );
+ settings.setValue( "/UI/" + filterName + "Dir", myPath );
+ }
+ return false;
+ }
+
+
+} // end of QgisGui namespace
Modified: trunk/qgis/src/gui/qgisgui.h
===================================================================
--- trunk/qgis/src/gui/qgisgui.h 2009-12-07 14:22:37 UTC (rev 12349)
+++ trunk/qgis/src/gui/qgisgui.h 2009-12-07 17:14:41 UTC (rev 12350)
@@ -18,9 +18,11 @@
#include <Qt>
+class QStringList;
+
/** \ingroup gui
* /namespace QgisGui
- * The QgisGui namespace contains constants used throughout the QGIS GUI.
+ * The QgisGui namespace contains constants and helper functions used throughout the QGIS GUI.
*/
namespace QgisGui
{
@@ -49,6 +51,34 @@
0;
#endif
+ /**
+ Open files, preferring to have the default file selector be the
+ last one used, if any; also, prefer to start in the last directory
+ associated with filterName.
+
+ @param filterName the name of the filter; used for persistent store key
+ @param filters the file filters used for QFileDialog
+ @param selectedFiles string list of selected files; will be empty if none selected
+ @param enc encoding?
+ @param title the title for the dialog
+ @note
+
+ Stores persistent settings under /UI/. The sub-keys will be
+ filterName and filterName + "Dir".
+
+ Opens dialog on last directory associated with the filter name, or
+ the current working directory if this is the first time invoked
+ with the current filter name.
+
+ This method returns true if cancel all was clicked, otherwise false
+
+ @note added in 1.4
+ */
+
+ bool openFilesRememberingFilter( QString const &filterName,
+ QString const &filters, QStringList & selectedFiles, QString& enc, QString &title,
+ bool cancelAll = false );
+
}
#endif
Added: trunk/qgis/src/gui/qgsprojectbadlayerguihandler.cpp
===================================================================
--- trunk/qgis/src/gui/qgsprojectbadlayerguihandler.cpp (rev 0)
+++ trunk/qgis/src/gui/qgsprojectbadlayerguihandler.cpp 2009-12-07 17:14:41 UTC (rev 12350)
@@ -0,0 +1,264 @@
+#include "qgsprojectbadlayerguihandler.h"
+
+#include <QApplication>
+#include <QDomDocument>
+#include <QFileInfo>
+#include <QMessageBox>
+
+#include "qgslogger.h"
+#include "qgisgui.h"
+#include "qgsproviderregistry.h"
+
+QgsProjectBadLayerGuiHandler::QgsProjectBadLayerGuiHandler()
+{
+}
+
+
+void QgsProjectBadLayerGuiHandler::handleBadLayers( QList<QDomNode> layers, QDomDocument projectDom )
+{
+
+ QgsDebugMsg( QString( "%1 bad layers found" ).arg( layers.size() ) );
+
+ // make sure we have arrow cursor (and not a wait cursor)
+ QApplication::setOverrideCursor( Qt::ArrowCursor );
+
+ if ( QMessageBox::Ok == QMessageBox::critical( NULL,
+ tr( "QGIS Project Read Error" ),
+ tr( "Unable to open one or more project layers\nTry to find missing layers?" ),
+ QMessageBox::Ok | QMessageBox::Cancel ) )
+ {
+ QgsDebugMsg( "want to find missing layers is true" );
+
+ // attempt to find the new locations for missing layers
+ // XXX vector file hard-coded -- but what if it's raster?
+
+ QString filter = QgsProviderRegistry::instance()->fileVectorFilters();
+ findLayers( filter, layers );
+ }
+
+ QApplication::restoreOverrideCursor();
+}
+
+
+QgsProjectBadLayerGuiHandler::DataType QgsProjectBadLayerGuiHandler::dataType( QDomNode & layerNode )
+{
+ QString type = layerNode.toElement().attribute( "type" );
+
+ if ( QString::null == type )
+ {
+ QgsDebugMsg( "cannot find ``type'' attribute" );
+
+ return IS_BOGUS;
+ }
+
+ if ( "raster" == type )
+ {
+ QgsDebugMsg( "is a raster" );
+
+ return IS_RASTER;
+ }
+ else if ( "vector" == type )
+ {
+ QgsDebugMsg( "is a vector" );
+
+ return IS_VECTOR;
+ }
+
+ QgsDebugMsg( "is unknown type " + type );
+
+ return IS_BOGUS;
+} // dataType_( QDomNode & layerNode )
+
+
+QString QgsProjectBadLayerGuiHandler::dataSource( QDomNode & layerNode )
+{
+ QDomNode dataSourceNode = layerNode.namedItem( "datasource" );
+
+ if ( dataSourceNode.isNull() )
+ {
+ QgsDebugMsg( "cannot find datasource node" );
+
+ return QString::null;
+ }
+
+ return dataSourceNode.toElement().text();
+
+} // dataSource( QDomNode & layerNode )
+
+
+
+
+QgsProjectBadLayerGuiHandler::ProviderType QgsProjectBadLayerGuiHandler::providerType( QDomNode & layerNode )
+{
+ // XXX but what about rasters that can be URLs? _Can_ they be URLs?
+
+ switch ( dataType( layerNode ) )
+ {
+ case IS_VECTOR:
+ {
+ QString ds = dataSource( layerNode );
+
+ QgsDebugMsg( "datasource is " + ds );
+
+ if ( ds.contains( "host=" ) )
+ {
+ return IS_URL;
+ }
+#ifdef HAVE_POSTGRESQL
+ else if ( ds.contains( "dbname=" ) )
+ {
+ return IS_DATABASE;
+ }
+#endif
+ // be default, then, this should be a file based layer data source
+ // XXX is this a reasonable assumption?
+
+ return IS_FILE;
+ }
+
+ case IS_RASTER: // rasters are currently only accessed as
+ // physical files
+ return IS_FILE;
+
+ default:
+ QgsDebugMsg( "unknown ``type'' attribute" );
+ }
+
+ return IS_Unknown;
+
+} // providerType
+
+
+
+void QgsProjectBadLayerGuiHandler::setDataSource( QDomNode & layerNode, QString const & dataSource )
+{
+ QDomNode dataSourceNode = layerNode.namedItem( "datasource" );
+ QDomElement dataSourceElement = dataSourceNode.toElement();
+ QDomText dataSourceText = dataSourceElement.firstChild().toText();
+
+ QgsDebugMsg( "datasource changed from " + dataSourceText.data() );
+
+ dataSourceText.setData( dataSource );
+
+ QgsDebugMsg( "to " + dataSourceText.data() );
+} // setDataSource
+
+
+
+
+bool QgsProjectBadLayerGuiHandler::findMissingFile( QString const & fileFilters, QDomNode & layerNode )
+{
+ // Prepend that file name to the valid file format filter list since it
+ // makes it easier for the user to not only find the original file, but to
+ // perhaps find a similar file.
+
+ QFileInfo originalDataSource( dataSource( layerNode ) );
+
+ QString memoryQualifier; // to differentiate between last raster and
+ // vector directories
+
+ switch ( dataType( layerNode ) )
+ {
+ case IS_VECTOR:
+ {
+ memoryQualifier = "lastVectorFileFilter";
+
+ break;
+ }
+ case IS_RASTER:
+ {
+ memoryQualifier = "lastRasterFileFilter";
+
+ break;
+ }
+ default:
+ QgsDebugMsg( "unable to determine data type" );
+ return false;
+ }
+
+ // Prepend the original data source base name to make it easier to pick it
+ // out from a list of other files; however the appropriate filter strings
+ // for the file type will also be added in case the file name itself has
+ // changed, too.
+
+ QString myFileFilters = originalDataSource.fileName() + ";;" + fileFilters;
+
+ QStringList selectedFiles;
+ QString enc;
+ QString title = QObject::tr( "Where is '%1' (original location: %2)?" )
+ .arg( originalDataSource.fileName() )
+ .arg( originalDataSource.absoluteFilePath() );
+
+ bool retVal = QgisGui::openFilesRememberingFilter( memoryQualifier,
+ myFileFilters,
+ selectedFiles,
+ enc,
+ title,
+ true );
+
+ if ( selectedFiles.isEmpty() )
+ {
+ return retVal;
+ }
+ else
+ {
+ setDataSource( layerNode, selectedFiles.first() );
+ if ( ! QgsProject::instance()->read( layerNode ) )
+ {
+ QgsDebugMsg( "unable to re-read layer" );
+ }
+ }
+ return retVal;
+} // findMissingFile
+
+
+
+
+bool QgsProjectBadLayerGuiHandler::findLayer( QString const & fileFilters, QDomNode const & constLayerNode )
+{
+ // XXX actually we could possibly get away with a copy of the node
+ QDomNode & layerNode = const_cast<QDomNode&>( constLayerNode );
+
+ bool retVal = false;
+
+ switch ( providerType( layerNode ) )
+ {
+ case IS_FILE:
+ QgsDebugMsg( "layer is file based" );
+ retVal = findMissingFile( fileFilters, layerNode );
+ break;
+
+ case IS_DATABASE:
+ QgsDebugMsg( "layer is database based" );
+ break;
+
+ case IS_URL:
+ QgsDebugMsg( "layer is URL based" );
+ break;
+
+ case IS_Unknown:
+ QgsDebugMsg( "layer has an unkown type" );
+ break;
+ }
+ return retVal;
+} // findLayer
+
+
+
+
+void QgsProjectBadLayerGuiHandler::findLayers( QString const & fileFilters, QList<QDomNode> const & layerNodes )
+{
+
+ for ( QList<QDomNode>::const_iterator i = layerNodes.begin();
+ i != layerNodes.end();
+ ++i )
+ {
+ if ( findLayer( fileFilters, *i ) )
+ {
+ // If findLayer returns true, the user hit Cancel All button
+ break;
+ }
+ }
+
+} // findLayers
+
Added: trunk/qgis/src/gui/qgsprojectbadlayerguihandler.h
===================================================================
--- trunk/qgis/src/gui/qgsprojectbadlayerguihandler.h (rev 0)
+++ trunk/qgis/src/gui/qgsprojectbadlayerguihandler.h 2009-12-07 17:14:41 UTC (rev 12350)
@@ -0,0 +1,87 @@
+#ifndef QGSPROJECTBADLAYERGUIHANDLER_H
+#define QGSPROJECTBADLAYERGUIHANDLER_H
+
+#include "qgsproject.h"
+
+/** \ingroup gui
+ Handler for missing layers within project.
+
+ Gives user a chance to select path to the missing layers.
+
+ @note added in 1.4
+ */
+class GUI_EXPORT QgsProjectBadLayerGuiHandler : public QObject, public QgsProjectBadLayerHandler
+{
+ public:
+ QgsProjectBadLayerGuiHandler();
+
+ /** implementation of the handler */
+ virtual void handleBadLayers( QList<QDomNode> layers, QDomDocument projectDom );
+
+ protected:
+
+ //! file data representation
+ enum DataType { IS_VECTOR, IS_RASTER, IS_BOGUS };
+
+ //! the three flavors for data
+ enum ProviderType { IS_FILE, IS_DATABASE, IS_URL, IS_Unknown };
+
+
+ /** returns data type associated with the given QgsProject file Dom node
+
+ The Dom node should represent the state associated with a specific layer.
+ */
+ DataType dataType( QDomNode & layerNode );
+
+ /** return the data source for the given layer
+
+ The QDomNode is a QgsProject Dom node corresponding to a map layer state.
+
+ Essentially dumps <datasource> tag.
+ */
+ QString dataSource( QDomNode & layerNode );
+
+ /** return the physical storage type associated with the given layer
+
+ The QDomNode is a QgsProject Dom node corresponding to a map layer state.
+
+ If the <provider> is "ogr", then it's a file type.
+
+ However, if the layer is a raster, then there won't be a <provider> tag. It
+ will always have an associated file.
+
+ If the layer doesn't fall into either of the previous two categories, then
+ it's either a database or URL. If the <datasource> tag has "url=", then
+ it's URL based. If the <datasource> tag has "dbname=">, then the layer data
+ is in a database.
+ */
+ ProviderType providerType( QDomNode & layerNode );
+
+ /** set the <datasource> to the new value */
+ void setDataSource( QDomNode & layerNode, QString const & dataSource );
+
+ /** this is used to locate files that have moved or otherwise are missing */
+ bool findMissingFile( QString const & fileFilters, QDomNode & layerNode );
+
+ /** find relocated data source for the given layer
+
+ This QDom object represents a QgsProject node that maps to a specific layer.
+
+ @param layerNode QDom node containing layer project information
+
+ @todo
+
+ XXX Only implemented for file based layers. It will need to be extended for
+ XXX other data source types such as databases.
+ */
+ bool findLayer( QString const & fileFilters, QDomNode const & constLayerNode );
+
+ /** find relocated data sources for given layers
+
+ These QDom objects represent QgsProject nodes that map to specific layers.
+ */
+ void findLayers( QString const & fileFilters, QList<QDomNode> const & layerNodes );
+
+};
+
+#endif // QGSPROJECTBADLAYERGUIHANDLER_H
More information about the QGIS-commit
mailing list