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