Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgsprojectbadlayerguihandler.cpp
Go to the documentation of this file.
2 
3 #include <QApplication>
4 #include <QDomDocument>
5 #include <QFileInfo>
6 #include <QMessageBox>
7 #include <QPushButton>
8 
9 #include "qgslogger.h"
10 #include "qgisgui.h"
11 #include "qgsproviderregistry.h"
12 
14 {
15 }
16 
18 
19 void QgsProjectBadLayerGuiHandler::handleBadLayers( QList<QDomNode> layers, QDomDocument projectDom )
20 {
21  QgsDebugMsg( QString( "%1 bad layers found" ).arg( layers.size() ) );
22 
23  // make sure we have arrow cursor (and not a wait cursor)
24  QApplication::setOverrideCursor( Qt::ArrowCursor );
25 
26  QMessageBox messageBox;
27 
28  QAbstractButton *ignoreButton =
29  messageBox.addButton( tr( "Ignore" ), QMessageBox::ActionRole );
30 
31  QAbstractButton *okButton = messageBox.addButton( QMessageBox :: Ok );
32 
33  messageBox.addButton( QMessageBox :: Cancel );
34 
35  messageBox.setWindowTitle( tr( "QGIS Project Read Error" ) );
36  messageBox.setText( tr( "Unable to open one or more project layers.\nChoose "
37  "ignore to continue loading without the missing layers. Choose cancel to "
38  "return to your pre-project load state. Choose OK to try to find the "
39  "missing layers." ) );
40  messageBox.setIcon( QMessageBox::Critical );
41  messageBox.exec();
42 
44 
45  if ( messageBox.clickedButton() == okButton )
46  {
47  QgsDebugMsg( "want to find missing layers is true" );
48 
49  // attempt to find the new locations for missing layers
50  // XXX vector file hard-coded -- but what if it's raster?
51 
53  findLayers( filter, layers );
54  }
55  else if ( messageBox.clickedButton() == ignoreButton )
56  {
58  }
59  else
60  {
61  // Do nothing
62  }
63 
64  QApplication::restoreOverrideCursor();
65 }
66 
68 {
69  QString type = layerNode.toElement().attribute( "type" );
70 
71  if ( QString::null == type )
72  {
73  QgsDebugMsg( "cannot find ``type'' attribute" );
74 
75  return IS_BOGUS;
76  }
77 
78  if ( "raster" == type )
79  {
80  QgsDebugMsg( "is a raster" );
81 
82  return IS_RASTER;
83  }
84  else if ( "vector" == type )
85  {
86  QgsDebugMsg( "is a vector" );
87 
88  return IS_VECTOR;
89  }
90 
91  QgsDebugMsg( "is unknown type " + type );
92 
93  return IS_BOGUS;
94 } // dataType_( QDomNode & layerNode )
95 
96 
97 QString QgsProjectBadLayerGuiHandler::dataSource( QDomNode & layerNode )
98 {
99  QDomNode dataSourceNode = layerNode.namedItem( "datasource" );
100 
101  if ( dataSourceNode.isNull() )
102  {
103  QgsDebugMsg( "cannot find datasource node" );
104 
105  return QString::null;
106  }
107 
108  return dataSourceNode.toElement().text();
109 
110 } // dataSource( QDomNode & layerNode )
111 
112 
113 
114 
116 {
117  // XXX but what about rasters that can be URLs? _Can_ they be URLs?
118 
119  switch ( dataType( layerNode ) )
120  {
121  case IS_VECTOR:
122  {
123  QString ds = dataSource( layerNode );
124 
125  QgsDebugMsg( "datasource is " + ds );
126 
127  if ( ds.contains( "host=" ) )
128  {
129  return IS_URL;
130  }
131 #ifdef HAVE_POSTGRESQL
132  else if ( ds.contains( "dbname=" ) )
133  {
134  return IS_DATABASE;
135  }
136 #endif
137  // be default, then, this should be a file based layer data source
138  // XXX is this a reasonable assumption?
139 
140  return IS_FILE;
141  }
142 
143  case IS_RASTER: // rasters are currently only accessed as
144  // physical files
145  return IS_FILE;
146 
147  default:
148  QgsDebugMsg( "unknown ``type'' attribute" );
149  }
150 
151  return IS_Unknown;
152 
153 } // providerType
154 
155 
156 
157 void QgsProjectBadLayerGuiHandler::setDataSource( QDomNode & layerNode, QString const & dataSource )
158 {
159  QDomNode dataSourceNode = layerNode.namedItem( "datasource" );
160  QDomElement dataSourceElement = dataSourceNode.toElement();
161  QDomText dataSourceText = dataSourceElement.firstChild().toText();
162 
163  QgsDebugMsg( "datasource changed from " + dataSourceText.data() );
164 
165  dataSourceText.setData( dataSource );
166 
167  QgsDebugMsg( "to " + dataSourceText.data() );
168 } // setDataSource
169 
170 
171 
172 
173 bool QgsProjectBadLayerGuiHandler::findMissingFile( QString const & fileFilters, QDomNode & layerNode )
174 {
175  // Prepend that file name to the valid file format filter list since it
176  // makes it easier for the user to not only find the original file, but to
177  // perhaps find a similar file.
178 
179  QFileInfo originalDataSource( dataSource( layerNode ) );
180 
181  QString memoryQualifier; // to differentiate between last raster and
182  // vector directories
183 
184  switch ( dataType( layerNode ) )
185  {
186  case IS_VECTOR:
187  {
188  memoryQualifier = "lastVectorFileFilter";
189 
190  break;
191  }
192  case IS_RASTER:
193  {
194  memoryQualifier = "lastRasterFileFilter";
195 
196  break;
197  }
198  default:
199  QgsDebugMsg( "unable to determine data type" );
200  return false;
201  }
202 
203  // Prepend the original data source base name to make it easier to pick it
204  // out from a list of other files; however the appropriate filter strings
205  // for the file type will also be added in case the file name itself has
206  // changed, too.
207 
208  QString myFileFilters = originalDataSource.fileName() + ";;" + fileFilters;
209 
210  QStringList selectedFiles;
211  QString enc;
212  QString title = QObject::tr( "Where is '%1' (original location: %2)?" )
213  .arg( originalDataSource.fileName() )
214  .arg( originalDataSource.absoluteFilePath() );
215 
216  bool retVal = QgisGui::openFilesRememberingFilter( memoryQualifier,
217  myFileFilters,
218  selectedFiles,
219  enc,
220  title,
221  true );
222 
223  if ( selectedFiles.isEmpty() )
224  {
225  return retVal;
226  }
227  else
228  {
229  setDataSource( layerNode, selectedFiles.first() );
230  if ( ! QgsProject::instance()->read( layerNode ) )
231  {
232  QgsDebugMsg( "unable to re-read layer" );
233  }
234  }
235  return retVal;
236 } // findMissingFile
237 
238 
239 
240 
241 bool QgsProjectBadLayerGuiHandler::findLayer( QString const & fileFilters, QDomNode const & constLayerNode )
242 {
243  // XXX actually we could possibly get away with a copy of the node
244  QDomNode & layerNode = const_cast<QDomNode&>( constLayerNode );
245 
246  bool retVal = false;
247 
248  switch ( providerType( layerNode ) )
249  {
250  case IS_FILE:
251  QgsDebugMsg( "layer is file based" );
252  retVal = findMissingFile( fileFilters, layerNode );
253  break;
254 
255  case IS_DATABASE:
256  QgsDebugMsg( "layer is database based" );
257  break;
258 
259  case IS_URL:
260  QgsDebugMsg( "layer is URL based" );
261  break;
262 
263  case IS_Unknown:
264  QgsDebugMsg( "layer has an unknown type" );
265  break;
266  }
267  return retVal;
268 } // findLayer
269 
270 
271 
272 
273 void QgsProjectBadLayerGuiHandler::findLayers( QString const & fileFilters, QList<QDomNode> const & layerNodes )
274 {
275 
276  for ( QList<QDomNode>::const_iterator i = layerNodes.begin();
277  i != layerNodes.end();
278  ++i )
279  {
280  if ( findLayer( fileFilters, *i ) )
281  {
282  // If findLayer returns true, the user hit Cancel All button
283  break;
284  }
285  }
286 
287 } // findLayers
288