Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgsprojectbadlayerguihandler.cpp - handle bad layers 00003 --------------------- 00004 begin : December 2009 00005 copyright : (C) 2009 by Martin Dobias 00006 email : wonder.sk at gmail.com 00007 *************************************************************************** 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 ***************************************************************************/ 00015 00016 #include "qgsprojectbadlayerguihandler.h" 00017 00018 #include <QApplication> 00019 #include <QDomDocument> 00020 #include <QFileInfo> 00021 #include <QMessageBox> 00022 #include <QPushButton> 00023 00024 #include "qgslogger.h" 00025 #include "qgisgui.h" 00026 #include "qgsproviderregistry.h" 00027 00028 QgsProjectBadLayerGuiHandler::QgsProjectBadLayerGuiHandler() 00029 { 00030 } 00031 00032 bool QgsProjectBadLayerGuiHandler::mIgnore = false; 00033 00034 void QgsProjectBadLayerGuiHandler::handleBadLayers( QList<QDomNode> layers, QDomDocument projectDom ) 00035 { 00036 Q_UNUSED( projectDom ); 00037 00038 QgsDebugMsg( QString( "%1 bad layers found" ).arg( layers.size() ) ); 00039 00040 // make sure we have arrow cursor (and not a wait cursor) 00041 QApplication::setOverrideCursor( Qt::ArrowCursor ); 00042 00043 QMessageBox messageBox; 00044 00045 QAbstractButton *ignoreButton = 00046 messageBox.addButton( tr( "Ignore" ), QMessageBox::ActionRole ); 00047 00048 QAbstractButton *okButton = messageBox.addButton( QMessageBox :: Ok ); 00049 00050 messageBox.addButton( QMessageBox :: Cancel ); 00051 00052 messageBox.setWindowTitle( tr( "QGIS Project Read Error" ) ); 00053 messageBox.setText( tr( "Unable to open one or more project layers.\nChoose " 00054 "ignore to continue loading without the missing layers. Choose cancel to " 00055 "return to your pre-project load state. Choose OK to try to find the " 00056 "missing layers." ) ); 00057 messageBox.setIcon( QMessageBox::Critical ); 00058 messageBox.exec(); 00059 00060 QgsProjectBadLayerGuiHandler::mIgnore = false; 00061 00062 if ( messageBox.clickedButton() == okButton ) 00063 { 00064 QgsDebugMsg( "want to find missing layers is true" ); 00065 00066 // attempt to find the new locations for missing layers 00067 // XXX vector file hard-coded -- but what if it's raster? 00068 00069 QString filter = QgsProviderRegistry::instance()->fileVectorFilters(); 00070 findLayers( filter, layers ); 00071 } 00072 else if ( messageBox.clickedButton() == ignoreButton ) 00073 { 00074 QgsProjectBadLayerGuiHandler::mIgnore = true; 00075 } 00076 else 00077 { 00078 // Do nothing 00079 } 00080 00081 QApplication::restoreOverrideCursor(); 00082 } 00083 00084 QgsProjectBadLayerGuiHandler::DataType QgsProjectBadLayerGuiHandler::dataType( QDomNode & layerNode ) 00085 { 00086 QString type = layerNode.toElement().attribute( "type" ); 00087 00088 if ( QString::null == type ) 00089 { 00090 QgsDebugMsg( "cannot find ``type'' attribute" ); 00091 00092 return IS_BOGUS; 00093 } 00094 00095 if ( "raster" == type ) 00096 { 00097 QgsDebugMsg( "is a raster" ); 00098 00099 return IS_RASTER; 00100 } 00101 else if ( "vector" == type ) 00102 { 00103 QgsDebugMsg( "is a vector" ); 00104 00105 return IS_VECTOR; 00106 } 00107 00108 QgsDebugMsg( "is unknown type " + type ); 00109 00110 return IS_BOGUS; 00111 } // dataType_( QDomNode & layerNode ) 00112 00113 00114 QString QgsProjectBadLayerGuiHandler::dataSource( QDomNode & layerNode ) 00115 { 00116 QDomNode dataSourceNode = layerNode.namedItem( "datasource" ); 00117 00118 if ( dataSourceNode.isNull() ) 00119 { 00120 QgsDebugMsg( "cannot find datasource node" ); 00121 00122 return QString::null; 00123 } 00124 00125 return dataSourceNode.toElement().text(); 00126 00127 } // dataSource( QDomNode & layerNode ) 00128 00129 00130 00131 00132 QgsProjectBadLayerGuiHandler::ProviderType QgsProjectBadLayerGuiHandler::providerType( QDomNode & layerNode ) 00133 { 00134 // XXX but what about rasters that can be URLs? _Can_ they be URLs? 00135 00136 switch ( dataType( layerNode ) ) 00137 { 00138 case IS_VECTOR: 00139 { 00140 QString ds = dataSource( layerNode ); 00141 00142 QgsDebugMsg( "datasource is " + ds ); 00143 00144 if ( ds.contains( "host=" ) ) 00145 { 00146 return IS_URL; 00147 } 00148 #ifdef HAVE_POSTGRESQL 00149 else if ( ds.contains( "dbname=" ) ) 00150 { 00151 return IS_DATABASE; 00152 } 00153 #endif 00154 // be default, then, this should be a file based layer data source 00155 // XXX is this a reasonable assumption? 00156 00157 return IS_FILE; 00158 } 00159 00160 case IS_RASTER: // rasters are currently only accessed as 00161 // physical files 00162 return IS_FILE; 00163 00164 default: 00165 QgsDebugMsg( "unknown ``type'' attribute" ); 00166 } 00167 00168 return IS_Unknown; 00169 00170 } // providerType 00171 00172 00173 00174 void QgsProjectBadLayerGuiHandler::setDataSource( QDomNode & layerNode, QString const & dataSource ) 00175 { 00176 QDomNode dataSourceNode = layerNode.namedItem( "datasource" ); 00177 QDomElement dataSourceElement = dataSourceNode.toElement(); 00178 QDomText dataSourceText = dataSourceElement.firstChild().toText(); 00179 00180 QgsDebugMsg( "datasource changed from " + dataSourceText.data() ); 00181 00182 dataSourceText.setData( dataSource ); 00183 00184 QgsDebugMsg( "to " + dataSourceText.data() ); 00185 } // setDataSource 00186 00187 00188 00189 00190 bool QgsProjectBadLayerGuiHandler::findMissingFile( QString const & fileFilters, QDomNode & layerNode ) 00191 { 00192 // Prepend that file name to the valid file format filter list since it 00193 // makes it easier for the user to not only find the original file, but to 00194 // perhaps find a similar file. 00195 00196 QFileInfo originalDataSource( dataSource( layerNode ) ); 00197 00198 QString memoryQualifier; // to differentiate between last raster and 00199 // vector directories 00200 00201 switch ( dataType( layerNode ) ) 00202 { 00203 case IS_VECTOR: 00204 { 00205 memoryQualifier = "lastVectorFileFilter"; 00206 00207 break; 00208 } 00209 case IS_RASTER: 00210 { 00211 memoryQualifier = "lastRasterFileFilter"; 00212 00213 break; 00214 } 00215 default: 00216 QgsDebugMsg( "unable to determine data type" ); 00217 return false; 00218 } 00219 00220 // Prepend the original data source base name to make it easier to pick it 00221 // out from a list of other files; however the appropriate filter strings 00222 // for the file type will also be added in case the file name itself has 00223 // changed, too. 00224 00225 QString myFileFilters = originalDataSource.fileName() + ";;" + fileFilters; 00226 00227 QStringList selectedFiles; 00228 QString enc; 00229 QString title = QObject::tr( "Where is '%1' (original location: %2)?" ) 00230 .arg( originalDataSource.fileName() ) 00231 .arg( originalDataSource.absoluteFilePath() ); 00232 00233 bool retVal = QgisGui::openFilesRememberingFilter( memoryQualifier, 00234 myFileFilters, 00235 selectedFiles, 00236 enc, 00237 title, 00238 true ); 00239 00240 if ( selectedFiles.isEmpty() ) 00241 { 00242 return retVal; 00243 } 00244 else 00245 { 00246 setDataSource( layerNode, selectedFiles.first() ); 00247 if ( ! QgsProject::instance()->read( layerNode ) ) 00248 { 00249 QgsDebugMsg( "unable to re-read layer" ); 00250 } 00251 } 00252 return retVal; 00253 } // findMissingFile 00254 00255 00256 00257 00258 bool QgsProjectBadLayerGuiHandler::findLayer( QString const & fileFilters, QDomNode const & constLayerNode ) 00259 { 00260 // XXX actually we could possibly get away with a copy of the node 00261 QDomNode & layerNode = const_cast<QDomNode&>( constLayerNode ); 00262 00263 bool retVal = false; 00264 00265 switch ( providerType( layerNode ) ) 00266 { 00267 case IS_FILE: 00268 QgsDebugMsg( "layer is file based" ); 00269 retVal = findMissingFile( fileFilters, layerNode ); 00270 break; 00271 00272 case IS_DATABASE: 00273 QgsDebugMsg( "layer is database based" ); 00274 break; 00275 00276 case IS_URL: 00277 QgsDebugMsg( "layer is URL based" ); 00278 break; 00279 00280 case IS_Unknown: 00281 QgsDebugMsg( "layer has an unknown type" ); 00282 break; 00283 } 00284 return retVal; 00285 } // findLayer 00286 00287 00288 00289 00290 void QgsProjectBadLayerGuiHandler::findLayers( QString const & fileFilters, QList<QDomNode> const & layerNodes ) 00291 { 00292 00293 for ( QList<QDomNode>::const_iterator i = layerNodes.begin(); 00294 i != layerNodes.end(); 00295 ++i ) 00296 { 00297 if ( findLayer( fileFilters, *i ) ) 00298 { 00299 // If findLayer returns true, the user hit Cancel All button 00300 break; 00301 } 00302 } 00303 00304 } // findLayers 00305