|
QGIS API Documentation
master-59fd5e0
|
00001 /*************************************************************************** 00002 qgsmaplayer.cpp - description 00003 ------------------- 00004 begin : Fri Jun 28 2002 00005 copyright : (C) 2002 by Gary E.Sherman 00006 email : sherman at mrcc.com 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 00019 #include <QDateTime> 00020 #include <QDomNode> 00021 #include <QFileInfo> 00022 #include <QSettings> // TODO: get rid of it [MD] 00023 #include <QDir> 00024 #include <QFile> 00025 #include <QDomDocument> 00026 #include <QDomElement> 00027 #include <QDomImplementation> 00028 #include <QTextStream> 00029 #include <QUrl> 00030 00031 #include <sqlite3.h> 00032 00033 #include "qgslogger.h" 00034 #include "qgsrectangle.h" 00035 #include "qgsmaplayer.h" 00036 #include "qgscoordinatereferencesystem.h" 00037 #include "qgsapplication.h" 00038 #include "qgsproject.h" 00039 #include "qgsprojectfiletransform.h" 00040 #include "qgsdatasourceuri.h" 00041 #include "qgsvectorlayer.h" 00042 #include "qgsproviderregistry.h" 00043 00044 QgsMapLayer::QgsMapLayer( QgsMapLayer::LayerType type, 00045 QString lyrname, 00046 QString source ) : 00047 mTransparencyLevel( 255 ), // 0 is completely transparent 00048 mValid( false ), // assume the layer is invalid 00049 mDataSource( source ), 00050 mLayerOrigName( lyrname ), // store the original name 00051 mID( "" ), 00052 mLayerType( type ), 00053 mBlendMode( QPainter::CompositionMode_SourceOver ) // Default to normal blending 00054 { 00055 mCRS = new QgsCoordinateReferenceSystem(); 00056 00057 // Set the display name = internal name 00058 QgsDebugMsg( "original name: '" + mLayerOrigName + "'" ); 00059 mLayerName = capitaliseLayerName( mLayerOrigName ); 00060 QgsDebugMsg( "display name: '" + mLayerName + "'" ); 00061 00062 // Generate the unique ID of this layer 00063 QDateTime dt = QDateTime::currentDateTime(); 00064 mID = lyrname + dt.toString( "yyyyMMddhhmmsszzz" ); 00065 // Tidy the ID up to avoid characters that may cause problems 00066 // elsewhere (e.g in some parts of XML). Replaces every non-word 00067 // character (word characters are the alphabet, numbers and 00068 // underscore) with an underscore. 00069 // Note that the first backslashe in the regular expression is 00070 // there for the compiler, so the pattern is actually \W 00071 mID.replace( QRegExp( "[\\W]" ), "_" ); 00072 00073 //set some generous defaults for scale based visibility 00074 mMinScale = 0; 00075 mMaxScale = 100000000; 00076 mScaleBasedVisibility = false; 00077 mpCacheImage = 0; 00078 } 00079 00080 QgsMapLayer::~QgsMapLayer() 00081 { 00082 delete mCRS; 00083 if ( mpCacheImage ) 00084 { 00085 delete mpCacheImage; 00086 } 00087 } 00088 00089 QgsMapLayer::LayerType QgsMapLayer::type() const 00090 { 00091 return mLayerType; 00092 } 00093 00095 QString QgsMapLayer::id() const 00096 { 00097 return mID; 00098 } 00099 00101 void QgsMapLayer::setLayerName( const QString & name ) 00102 { 00103 QgsDebugMsg( "new original name: '" + name + "'" ); 00104 QString newName = capitaliseLayerName( name ); 00105 QgsDebugMsg( "new display name: '" + name + "'" ); 00106 if ( name == mLayerOrigName && newName == mLayerName ) return; 00107 mLayerOrigName = name; // store the new original name 00108 mLayerName = newName; 00109 emit layerNameChanged(); 00110 } 00111 00113 QString const & QgsMapLayer::name() const 00114 { 00115 QgsDebugMsgLevel( "returning name '" + mLayerName + "'", 3 ); 00116 return mLayerName; 00117 } 00118 00119 QString QgsMapLayer::publicSource() const 00120 { 00121 // Redo this every time we're asked for it, as we don't know if 00122 // dataSource has changed. 00123 QString safeName = QgsDataSourceURI::removePassword( mDataSource ); 00124 return safeName; 00125 } 00126 00127 QString const & QgsMapLayer::source() const 00128 { 00129 return mDataSource; 00130 } 00131 00132 QgsRectangle QgsMapLayer::extent() 00133 { 00134 return mExtent; 00135 } 00136 00138 void QgsMapLayer::setBlendMode( const QPainter::CompositionMode blendMode ) 00139 { 00140 mBlendMode = blendMode; 00141 } 00142 00144 QPainter::CompositionMode QgsMapLayer::blendMode() const 00145 { 00146 return mBlendMode; 00147 } 00148 00149 bool QgsMapLayer::draw( QgsRenderContext& rendererContext ) 00150 { 00151 Q_UNUSED( rendererContext ); 00152 return false; 00153 } 00154 00155 void QgsMapLayer::drawLabels( QgsRenderContext& rendererContext ) 00156 { 00157 Q_UNUSED( rendererContext ); 00158 // QgsDebugMsg("entered."); 00159 } 00160 00161 bool QgsMapLayer::readLayerXML( const QDomElement& layerElement ) 00162 { 00163 QgsCoordinateReferenceSystem savedCRS; 00164 CUSTOM_CRS_VALIDATION savedValidation; 00165 bool layerError; 00166 00167 QDomNode mnl; 00168 QDomElement mne; 00169 00170 // read provider 00171 QString provider; 00172 mnl = layerElement.namedItem( "provider" ); 00173 mne = mnl.toElement(); 00174 provider = mne.text(); 00175 00176 // set data source 00177 mnl = layerElement.namedItem( "datasource" ); 00178 mne = mnl.toElement(); 00179 mDataSource = mne.text(); 00180 00181 // TODO: this should go to providers 00182 if ( provider == "spatialite" ) 00183 { 00184 QgsDataSourceURI uri( mDataSource ); 00185 uri.setDatabase( QgsProject::instance()->readPath( uri.database() ) ); 00186 mDataSource = uri.uri(); 00187 } 00188 else if ( provider == "ogr" ) 00189 { 00190 QStringList theURIParts = mDataSource.split( "|" ); 00191 theURIParts[0] = QgsProject::instance()->readPath( theURIParts[0] ); 00192 mDataSource = theURIParts.join( "|" ); 00193 } 00194 else if ( provider == "delimitedtext" ) 00195 { 00196 QUrl urlSource = QUrl::fromEncoded( mDataSource.toAscii() ); 00197 00198 if ( !mDataSource.startsWith( "file:" ) ) 00199 { 00200 QUrl file = QUrl::fromLocalFile( mDataSource.left( mDataSource.indexOf( "?" ) ) ); 00201 urlSource.setScheme( "file" ); 00202 urlSource.setPath( file.path() ); 00203 } 00204 00205 QUrl urlDest = QUrl::fromLocalFile( QgsProject::instance()->readPath( urlSource.toLocalFile() ) ); 00206 urlDest.setQueryItems( urlSource.queryItems() ); 00207 mDataSource = QString::fromAscii( urlDest.toEncoded() ); 00208 } 00209 else if ( provider == "wms" ) 00210 { 00211 // >>> BACKWARD COMPATIBILITY < 1.9 00212 // For project file backward compatibility we must support old format: 00213 // 1. mode: <url> 00214 // example: http://example.org/wms? 00215 // 2. mode: tiled=<width>;<height>;<resolution>;<resolution>...,ignoreUrl=GetMap;GetFeatureInfo,featureCount=<count>,username=<name>,password=<password>,url=<url> 00216 // example: tiled=256;256;0.703;0.351,url=http://example.org/tilecache? 00217 // example: featureCount=10,http://example.org/wms? 00218 // example: ignoreUrl=GetMap;GetFeatureInfo,username=cimrman,password=jara,url=http://example.org/wms? 00219 // This is modified version of old QgsWmsProvider::parseUri 00220 // The new format has always params crs,format,layers,styles and that params 00221 // should not appear in old format url -> use them to identify version 00222 if ( !mDataSource.contains( "crs=" ) && !mDataSource.contains( "format=" ) ) 00223 { 00224 QgsDebugMsg( "Old WMS URI format detected -> converting to new format" ); 00225 QgsDataSourceURI uri; 00226 if ( !mDataSource.startsWith( "http:" ) ) 00227 { 00228 QStringList parts = mDataSource.split( "," ); 00229 QStringListIterator iter( parts ); 00230 while ( iter.hasNext() ) 00231 { 00232 QString item = iter.next(); 00233 if ( item.startsWith( "username=" ) ) 00234 { 00235 uri.setParam( "username", item.mid( 9 ) ); 00236 } 00237 else if ( item.startsWith( "password=" ) ) 00238 { 00239 uri.setParam( "password", item.mid( 9 ) ); 00240 } 00241 else if ( item.startsWith( "tiled=" ) ) 00242 { 00243 // in < 1.9 tiled= may apper in to variants: 00244 // tiled=width;height - non tiled mode, specifies max width and max height 00245 // tiled=width;height;resolutions-1;resolution2;... - tile mode 00246 00247 QStringList params = item.mid( 6 ).split( ";" ); 00248 00249 if ( params.size() == 2 ) // non tiled mode 00250 { 00251 uri.setParam( "maxWidth", params.takeFirst() ); 00252 uri.setParam( "maxHeight", params.takeFirst() ); 00253 } 00254 else if ( params.size() > 2 ) // tiled mode 00255 { 00256 // resolutions are no more needed and size limit is not used for tiles 00257 // we have to tell to the provider however that it is tiled 00258 uri.setParam( "tileMatrixSet", "" ); 00259 } 00260 } 00261 else if ( item.startsWith( "featureCount=" ) ) 00262 { 00263 uri.setParam( "featureCount", item.mid( 13 ) ); 00264 } 00265 else if ( item.startsWith( "url=" ) ) 00266 { 00267 uri.setParam( "url", item.mid( 4 ) ); 00268 } 00269 else if ( item.startsWith( "ignoreUrl=" ) ) 00270 { 00271 uri.setParam( "ignoreUrl", item.mid( 10 ).split( ";" ) ); 00272 } 00273 } 00274 } 00275 else 00276 { 00277 uri.setParam( "url", mDataSource ); 00278 } 00279 mDataSource = uri.encodedUri(); 00280 // At this point, the URI is obviously incomplete, we add additional params 00281 // in QgsRasterLayer::readXml 00282 } 00283 // <<< BACKWARD COMPATIBILITY < 1.9 00284 } 00285 else 00286 { 00287 mDataSource = QgsProject::instance()->readPath( mDataSource ); 00288 } 00289 00290 // Set the CRS from project file, asking the user if necessary. 00291 // Make it the saved CRS to have WMS layer projected correctly. 00292 // We will still overwrite whatever GDAL etc picks up anyway 00293 // further down this function. 00294 mnl = layerElement.namedItem( "layername" ); 00295 mne = mnl.toElement(); 00296 00297 QDomNode srsNode = layerElement.namedItem( "srs" ); 00298 mCRS->readXML( srsNode ); 00299 mCRS->setValidationHint( tr( "Specify CRS for layer %1" ).arg( mne.text() ) ); 00300 mCRS->validate(); 00301 savedCRS = *mCRS; 00302 00303 // Do not validate any projections in children, they will be overwritten anyway. 00304 // No need to ask the user for a projections when it is overwritten, is there? 00305 savedValidation = QgsCoordinateReferenceSystem::customSrsValidation(); 00306 QgsCoordinateReferenceSystem::setCustomSrsValidation( NULL ); 00307 00308 // now let the children grab what they need from the Dom node. 00309 layerError = !readXml( layerElement ); 00310 00311 // overwrite CRS with what we read from project file before the raster/vector 00312 // file readnig functions changed it. They will if projections is specfied in the file. 00313 // FIXME: is this necessary? 00314 QgsCoordinateReferenceSystem::setCustomSrsValidation( savedValidation ); 00315 *mCRS = savedCRS; 00316 00317 // Abort if any error in layer, such as not found. 00318 if ( layerError ) 00319 { 00320 return false; 00321 } 00322 00323 // the internal name is just the data source basename 00324 //QFileInfo dataSourceFileInfo( mDataSource ); 00325 //internalName = dataSourceFileInfo.baseName(); 00326 00327 // set ID 00328 mnl = layerElement.namedItem( "id" ); 00329 if ( ! mnl.isNull() ) 00330 { 00331 mne = mnl.toElement(); 00332 if ( ! mne.isNull() && mne.text().length() > 10 ) // should be at least 17 (yyyyMMddhhmmsszzz) 00333 { 00334 mID = mne.text(); 00335 } 00336 } 00337 00338 // use scale dependent visibility flag 00339 toggleScaleBasedVisibility( layerElement.attribute( "hasScaleBasedVisibilityFlag" ).toInt() == 1 ); 00340 setMinimumScale( layerElement.attribute( "minimumScale" ).toFloat() ); 00341 setMaximumScale( layerElement.attribute( "maximumScale" ).toFloat() ); 00342 00343 // set name 00344 mnl = layerElement.namedItem( "layername" ); 00345 mne = mnl.toElement(); 00346 setLayerName( mne.text() ); 00347 00348 //title 00349 QDomElement titleElem = layerElement.firstChildElement( "title" ); 00350 if ( !titleElem.isNull() ) 00351 { 00352 mTitle = titleElem.text(); 00353 } 00354 00355 //abstract 00356 QDomElement abstractElem = layerElement.firstChildElement( "abstract" ); 00357 if ( !abstractElem.isNull() ) 00358 { 00359 mAbstract = abstractElem.text(); 00360 } 00361 00362 //keywordList 00363 QDomElement keywordListElem = layerElement.firstChildElement( "keywordList" ); 00364 if ( !keywordListElem.isNull() ) 00365 { 00366 QStringList kwdList; 00367 for ( QDomNode n = keywordListElem.firstChild(); !n.isNull(); n = n.nextSibling() ) 00368 { 00369 kwdList << n.toElement().text(); 00370 } 00371 mKeywordList = kwdList.join( ", " ); 00372 } 00373 00374 //metadataUrl 00375 QDomElement dataUrlElem = layerElement.firstChildElement( "dataUrl" ); 00376 if ( !dataUrlElem.isNull() ) 00377 { 00378 mDataUrl = dataUrlElem.text(); 00379 mDataUrlFormat = dataUrlElem.attribute( "format", "" ); 00380 } 00381 00382 //attribution 00383 QDomElement attribElem = layerElement.firstChildElement( "attribution" ); 00384 if ( !attribElem.isNull() ) 00385 { 00386 mAttribution = attribElem.text(); 00387 mAttributionUrl = attribElem.attribute( "href", "" ); 00388 } 00389 00390 //metadataUrl 00391 QDomElement metaUrlElem = layerElement.firstChildElement( "metadataUrl" ); 00392 if ( !metaUrlElem.isNull() ) 00393 { 00394 mMetadataUrl = metaUrlElem.text(); 00395 mMetadataUrlType = metaUrlElem.attribute( "type", "" ); 00396 mMetadataUrlFormat = metaUrlElem.attribute( "format", "" ); 00397 } 00398 00399 #if 0 00400 //read transparency level 00401 QDomNode transparencyNode = layer_node.namedItem( "transparencyLevelInt" ); 00402 if ( ! transparencyNode.isNull() ) 00403 { 00404 // set transparency level only if it's in project 00405 // (otherwise it sets the layer transparent) 00406 QDomElement myElement = transparencyNode.toElement(); 00407 setTransparency( myElement.text().toInt() ); 00408 } 00409 #endif 00410 00411 readCustomProperties( layerElement ); 00412 00413 return true; 00414 } // void QgsMapLayer::readXML 00415 00416 00417 bool QgsMapLayer::readXml( const QDomNode& layer_node ) 00418 { 00419 Q_UNUSED( layer_node ); 00420 // NOP by default; children will over-ride with behavior specific to them 00421 00422 return true; 00423 } // void QgsMapLayer::readXml 00424 00425 00426 00427 bool QgsMapLayer::writeLayerXML( QDomElement& layerElement, QDomDocument& document ) 00428 { 00429 // use scale dependent visibility flag 00430 layerElement.setAttribute( "hasScaleBasedVisibilityFlag", hasScaleBasedVisibility() ? 1 : 0 ); 00431 layerElement.setAttribute( "minimumScale", QString::number( minimumScale() ) ); 00432 layerElement.setAttribute( "maximumScale", QString::number( maximumScale() ) ); 00433 00434 // ID 00435 QDomElement layerId = document.createElement( "id" ); 00436 QDomText layerIdText = document.createTextNode( id() ); 00437 layerId.appendChild( layerIdText ); 00438 00439 layerElement.appendChild( layerId ); 00440 00441 // data source 00442 QDomElement dataSource = document.createElement( "datasource" ); 00443 00444 QString src = source(); 00445 00446 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this ); 00447 // TODO: what about postgres, mysql and others, they should not go through writePath() 00448 if ( vlayer && vlayer->providerType() == "spatialite" ) 00449 { 00450 QgsDataSourceURI uri( src ); 00451 QString database = QgsProject::instance()->writePath( uri.database() ); 00452 uri.setConnection( uri.host(), uri.port(), database, uri.username(), uri.password() ); 00453 src = uri.uri(); 00454 } 00455 else if ( vlayer && vlayer->providerType() == "ogr" ) 00456 { 00457 QStringList theURIParts = src.split( "|" ); 00458 theURIParts[0] = QgsProject::instance()->writePath( theURIParts[0] ); 00459 src = theURIParts.join( "|" ); 00460 } 00461 else if ( vlayer && vlayer->providerType() == "delimitedtext" ) 00462 { 00463 QUrl urlSource = QUrl::fromEncoded( src.toAscii() ); 00464 QUrl urlDest = QUrl::fromLocalFile( QgsProject::instance()->writePath( urlSource.toLocalFile() ) ); 00465 urlDest.setQueryItems( urlSource.queryItems() ); 00466 src = QString::fromAscii( urlDest.toEncoded() ); 00467 } 00468 else 00469 { 00470 src = QgsProject::instance()->writePath( src ); 00471 } 00472 00473 QDomText dataSourceText = document.createTextNode( src ); 00474 dataSource.appendChild( dataSourceText ); 00475 00476 layerElement.appendChild( dataSource ); 00477 00478 00479 // layer name 00480 QDomElement layerName = document.createElement( "layername" ); 00481 QDomText layerNameText = document.createTextNode( originalName() ); 00482 layerName.appendChild( layerNameText ); 00483 00484 // layer title 00485 QDomElement layerTitle = document.createElement( "title" ) ; 00486 QDomText layerTitleText = document.createTextNode( title() ); 00487 layerTitle.appendChild( layerTitleText ); 00488 00489 // layer abstract 00490 QDomElement layerAbstract = document.createElement( "abstract" ); 00491 QDomText layerAbstractText = document.createTextNode( abstract() ); 00492 layerAbstract.appendChild( layerAbstractText ); 00493 00494 layerElement.appendChild( layerName ); 00495 layerElement.appendChild( layerTitle ); 00496 layerElement.appendChild( layerAbstract ); 00497 00498 // layer keyword list 00499 QStringList keywordStringList = keywordList().split( "," ); 00500 if ( keywordStringList.size() > 0 ) 00501 { 00502 QDomElement layerKeywordList = document.createElement( "keywordList" ); 00503 for ( int i = 0; i < keywordStringList.size(); ++i ) 00504 { 00505 QDomElement layerKeywordValue = document.createElement( "value" ); 00506 QDomText layerKeywordText = document.createTextNode( keywordStringList.at( i ).trimmed() ); 00507 layerKeywordValue.appendChild( layerKeywordText ); 00508 layerKeywordList.appendChild( layerKeywordValue ); 00509 } 00510 layerElement.appendChild( layerKeywordList ); 00511 } 00512 00513 // layer metadataUrl 00514 QString aDataUrl = dataUrl(); 00515 if ( !aDataUrl.isEmpty() ) 00516 { 00517 QDomElement layerDataUrl = document.createElement( "dataUrl" ) ; 00518 QDomText layerDataUrlText = document.createTextNode( aDataUrl ); 00519 layerDataUrl.appendChild( layerDataUrlText ); 00520 layerDataUrl.setAttribute( "format", dataUrlFormat() ); 00521 layerElement.appendChild( layerDataUrl ); 00522 } 00523 00524 // layer attribution 00525 QString aAttribution = attribution(); 00526 if ( !aAttribution.isEmpty() ) 00527 { 00528 QDomElement layerAttribution = document.createElement( "attribution" ) ; 00529 QDomText layerAttributionText = document.createTextNode( aAttribution ); 00530 layerAttribution.appendChild( layerAttributionText ); 00531 layerAttribution.setAttribute( "href", attributionUrl() ); 00532 layerElement.appendChild( layerAttribution ); 00533 } 00534 00535 // layer metadataUrl 00536 QString aMetadataUrl = metadataUrl(); 00537 if ( !aMetadataUrl.isEmpty() ) 00538 { 00539 QDomElement layerMetadataUrl = document.createElement( "metadataUrl" ) ; 00540 QDomText layerMetadataUrlText = document.createTextNode( aMetadataUrl ); 00541 layerMetadataUrl.appendChild( layerMetadataUrlText ); 00542 layerMetadataUrl.setAttribute( "type", metadataUrlType() ); 00543 layerMetadataUrl.setAttribute( "format", metadataUrlFormat() ); 00544 layerElement.appendChild( layerMetadataUrl ); 00545 } 00546 00547 // timestamp if supported 00548 if ( timestamp() > QDateTime() ) 00549 { 00550 QDomElement stamp = document.createElement( "timestamp" ); 00551 QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) ); 00552 stamp.appendChild( stampText ); 00553 layerElement.appendChild( stamp ); 00554 } 00555 00556 layerElement.appendChild( layerName ); 00557 00558 // zorder 00559 // This is no longer stored in the project file. It is superfluous since the layers 00560 // are written and read in the proper order. 00561 00562 // spatial reference system id 00563 QDomElement mySrsElement = document.createElement( "srs" ); 00564 mCRS->writeXML( mySrsElement, document ); 00565 layerElement.appendChild( mySrsElement ); 00566 00567 #if 0 00568 // <transparencyLevelInt> 00569 QDomElement transparencyLevelIntElement = document.createElement( "transparencyLevelInt" ); 00570 QDomText transparencyLevelIntText = document.createTextNode( QString::number( getTransparency() ) ); 00571 transparencyLevelIntElement.appendChild( transparencyLevelIntText ); 00572 maplayer.appendChild( transparencyLevelIntElement ); 00573 #endif 00574 00575 // now append layer node to map layer node 00576 00577 writeCustomProperties( layerElement, document ); 00578 00579 return writeXml( layerElement, document ); 00580 00581 } // bool QgsMapLayer::writeXML 00582 00583 00584 bool QgsMapLayer::writeXml( QDomNode & layer_node, QDomDocument & document ) 00585 { 00586 Q_UNUSED( layer_node ); 00587 Q_UNUSED( document ); 00588 // NOP by default; children will over-ride with behavior specific to them 00589 00590 return true; 00591 } // void QgsMapLayer::writeXml 00592 00593 00594 00595 00596 bool QgsMapLayer::isValid() 00597 { 00598 return mValid; 00599 } 00600 00601 00602 void QgsMapLayer::invalidTransformInput() 00603 { 00604 QgsDebugMsg( "called" ); 00605 // TODO: emit a signal - it will be used to update legend 00606 } 00607 00608 00609 QString QgsMapLayer::lastErrorTitle() 00610 { 00611 return QString(); 00612 } 00613 00614 QString QgsMapLayer::lastError() 00615 { 00616 return QString(); 00617 } 00618 00619 void QgsMapLayer::connectNotify( const char * signal ) 00620 { 00621 Q_UNUSED( signal ); 00622 QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 ); 00623 } // QgsMapLayer::connectNotify 00624 00625 00626 00627 void QgsMapLayer::toggleScaleBasedVisibility( bool theVisibilityFlag ) 00628 { 00629 mScaleBasedVisibility = theVisibilityFlag; 00630 } 00631 00632 bool QgsMapLayer::hasScaleBasedVisibility() 00633 { 00634 return mScaleBasedVisibility; 00635 } 00636 00637 void QgsMapLayer::setMinimumScale( float theMinScale ) 00638 { 00639 mMinScale = theMinScale; 00640 } 00641 00642 float QgsMapLayer::minimumScale() 00643 { 00644 return mMinScale; 00645 } 00646 00647 00648 void QgsMapLayer::setMaximumScale( float theMaxScale ) 00649 { 00650 mMaxScale = theMaxScale; 00651 } 00652 00653 float QgsMapLayer::maximumScale() 00654 { 00655 return mMaxScale; 00656 } 00657 00658 00659 QStringList QgsMapLayer::subLayers() const 00660 { 00661 return QStringList(); // Empty 00662 } 00663 00664 void QgsMapLayer::setLayerOrder( const QStringList &layers ) 00665 { 00666 Q_UNUSED( layers ); 00667 // NOOP 00668 } 00669 00670 void QgsMapLayer::setSubLayerVisibility( QString name, bool vis ) 00671 { 00672 Q_UNUSED( name ); 00673 Q_UNUSED( vis ); 00674 // NOOP 00675 } 00676 00677 const QgsCoordinateReferenceSystem& QgsMapLayer::crs() const 00678 { 00679 return *mCRS; 00680 } 00681 00682 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem& srs, bool emitSignal ) 00683 { 00684 *mCRS = srs; 00685 00686 if ( !mCRS->isValid() ) 00687 { 00688 mCRS->setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) ); 00689 mCRS->validate(); 00690 } 00691 00692 if ( emitSignal ) 00693 emit layerCrsChanged(); 00694 } 00695 00696 #if 0 00697 unsigned int QgsMapLayer::getTransparency() 00698 { 00699 return mTransparencyLevel; 00700 } 00701 00702 void QgsMapLayer::setTransparency( unsigned int theInt ) 00703 { 00704 mTransparencyLevel = theInt; 00705 } 00706 #endif 00707 00708 QString QgsMapLayer::capitaliseLayerName( const QString& name ) 00709 { 00710 // Capitalise the first letter of the layer name if requested 00711 QSettings settings; 00712 bool capitaliseLayerName = 00713 settings.value( "/qgis/capitaliseLayerName", QVariant( false ) ).toBool(); 00714 00715 QString layerName( name ); 00716 00717 if ( capitaliseLayerName ) 00718 layerName = layerName.left( 1 ).toUpper() + layerName.mid( 1 ); 00719 00720 return layerName; 00721 } 00722 00723 QString QgsMapLayer::styleURI( ) 00724 { 00725 QString myURI = publicSource(); 00726 00727 // if file is using the VSIFILE mechanism, remove the prefix 00728 if ( myURI.startsWith( "/vsigzip/", Qt::CaseInsensitive ) ) 00729 { 00730 myURI.remove( 0, 9 ); 00731 } 00732 else if ( myURI.startsWith( "/vsizip/", Qt::CaseInsensitive ) && 00733 myURI.endsWith( ".zip", Qt::CaseInsensitive ) ) 00734 { 00735 // ideally we should look for .qml file inside zip file 00736 myURI.remove( 0, 8 ); 00737 } 00738 else if ( myURI.startsWith( "/vsitar/", Qt::CaseInsensitive ) && 00739 ( myURI.endsWith( ".tar", Qt::CaseInsensitive ) || 00740 myURI.endsWith( ".tar.gz", Qt::CaseInsensitive ) || 00741 myURI.endsWith( ".tgz", Qt::CaseInsensitive ) ) ) 00742 { 00743 // ideally we should look for .qml file inside tar file 00744 myURI.remove( 0, 8 ); 00745 } 00746 00747 QFileInfo myFileInfo( myURI ); 00748 QString key; 00749 00750 if ( myFileInfo.exists() ) 00751 { 00752 // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name 00753 if ( myURI.endsWith( ".gz", Qt::CaseInsensitive ) ) 00754 myURI.chop( 3 ); 00755 else if ( myURI.endsWith( ".zip", Qt::CaseInsensitive ) ) 00756 myURI.chop( 4 ); 00757 else if ( myURI.endsWith( ".tar", Qt::CaseInsensitive ) ) 00758 myURI.chop( 4 ); 00759 else if ( myURI.endsWith( ".tar.gz", Qt::CaseInsensitive ) ) 00760 myURI.chop( 7 ); 00761 else if ( myURI.endsWith( ".tgz", Qt::CaseInsensitive ) ) 00762 myURI.chop( 4 ); 00763 else if ( myURI.endsWith( ".gz", Qt::CaseInsensitive ) ) 00764 myURI.chop( 3 ); 00765 myFileInfo.setFile( myURI ); 00766 // get the file name for our .qml style file 00767 key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml"; 00768 } 00769 else 00770 { 00771 key = publicSource(); 00772 } 00773 00774 return key; 00775 } 00776 00777 QString QgsMapLayer::loadDefaultStyle( bool & theResultFlag ) 00778 { 00779 return loadNamedStyle( styleURI(), theResultFlag ); 00780 } 00781 00782 bool QgsMapLayer::loadNamedStyleFromDb( const QString db, const QString theURI, QString &qml ) 00783 { 00784 QgsDebugMsg( QString( "db = %1 uri = %2" ).arg( db ).arg( theURI ) ); 00785 00786 bool theResultFlag = false; 00787 00788 // read from database 00789 sqlite3 *myDatabase; 00790 sqlite3_stmt *myPreparedStatement; 00791 const char *myTail; 00792 int myResult; 00793 00794 QgsDebugMsg( QString( "Trying to load style for \"%1\" from \"%2\"" ).arg( theURI ).arg( db ) ); 00795 00796 if ( !QFile( db ).exists() ) 00797 return false; 00798 00799 myResult = sqlite3_open_v2( db.toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL ); 00800 if ( myResult != SQLITE_OK ) 00801 { 00802 return false; 00803 } 00804 00805 QString mySql = "select qml from tbl_styles where style=?"; 00806 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 00807 if ( myResult == SQLITE_OK ) 00808 { 00809 QByteArray param = theURI.toUtf8(); 00810 00811 if ( sqlite3_bind_text( myPreparedStatement, 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK && 00812 sqlite3_step( myPreparedStatement ) == SQLITE_ROW ) 00813 { 00814 qml = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) ); 00815 theResultFlag = true; 00816 } 00817 00818 sqlite3_finalize( myPreparedStatement ); 00819 } 00820 00821 sqlite3_close( myDatabase ); 00822 00823 return theResultFlag; 00824 } 00825 00826 QString QgsMapLayer::loadNamedStyle( const QString theURI, bool &theResultFlag ) 00827 { 00828 QgsDebugMsg( QString( "uri = %1 myURI = %2" ).arg( theURI ).arg( publicSource() ) ); 00829 00830 theResultFlag = false; 00831 00832 QDomDocument myDocument( "qgis" ); 00833 00834 // location of problem associated with errorMsg 00835 int line, column; 00836 QString myErrorMessage; 00837 00838 QFile myFile( theURI ); 00839 if ( myFile.open( QFile::ReadOnly ) ) 00840 { 00841 // read file 00842 theResultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column ); 00843 if ( !theResultFlag ) 00844 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column ); 00845 myFile.close(); 00846 } 00847 else 00848 { 00849 QFileInfo project( QgsProject::instance()->fileName() ); 00850 QgsDebugMsg( QString( "project fileName: %1" ).arg( project.absoluteFilePath() ) ); 00851 00852 QString qml; 00853 if ( loadNamedStyleFromDb( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( "qgis.qmldb" ), theURI, qml ) || 00854 ( project.exists() && loadNamedStyleFromDb( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), theURI, qml ) ) || 00855 loadNamedStyleFromDb( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( "resources/qgis.qmldb" ), theURI, qml ) ) 00856 { 00857 theResultFlag = myDocument.setContent( qml, &myErrorMessage, &line, &column ); 00858 if ( !theResultFlag ) 00859 { 00860 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column ); 00861 } 00862 } 00863 else 00864 { 00865 myErrorMessage = tr( "style not found in database" ); 00866 } 00867 } 00868 00869 if ( !theResultFlag ) 00870 { 00871 return myErrorMessage; 00872 } 00873 00874 // get style file version string, if any 00875 QgsProjectVersion fileVersion( myDocument.firstChildElement( "qgis" ).attribute( "version" ) ); 00876 QgsProjectVersion thisVersion( QGis::QGIS_VERSION ); 00877 00878 if ( thisVersion > fileVersion ) 00879 { 00880 QgsLogger::warning( "Loading a style file that was saved with an older " 00881 "version of qgis (saved in " + fileVersion.text() + 00882 ", loaded in " + QGis::QGIS_VERSION + 00883 "). Problems may occur." ); 00884 00885 QgsProjectFileTransform styleFile( myDocument, fileVersion ); 00886 // styleFile.dump(); 00887 styleFile.updateRevision( thisVersion ); 00888 // styleFile.dump(); 00889 } 00890 00891 // now get the layer node out and pass it over to the layer 00892 // to deserialise... 00893 QDomElement myRoot = myDocument.firstChildElement( "qgis" ); 00894 if ( myRoot.isNull() ) 00895 { 00896 myErrorMessage = tr( "Error: qgis element could not be found in %1" ).arg( theURI ); 00897 theResultFlag = false; 00898 return myErrorMessage; 00899 } 00900 00901 // use scale dependent visibility flag 00902 toggleScaleBasedVisibility( myRoot.attribute( "hasScaleBasedVisibilityFlag" ).toInt() == 1 ); 00903 setMinimumScale( myRoot.attribute( "minimumScale" ).toFloat() ); 00904 setMaximumScale( myRoot.attribute( "maximumScale" ).toFloat() ); 00905 00906 #if 0 00907 //read transparency level 00908 QDomNode transparencyNode = myRoot.namedItem( "transparencyLevelInt" ); 00909 if ( ! transparencyNode.isNull() ) 00910 { 00911 // set transparency level only if it's in project 00912 // (otherwise it sets the layer transparent) 00913 QDomElement myElement = transparencyNode.toElement(); 00914 setTransparency( myElement.text().toInt() ); 00915 } 00916 #endif 00917 00918 QString errorMsg; 00919 theResultFlag = readSymbology( myRoot, errorMsg ); 00920 if ( !theResultFlag ) 00921 { 00922 myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( errorMsg ); 00923 return myErrorMessage; 00924 } 00925 00926 return ""; 00927 } 00928 00929 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg ) 00930 { 00931 QDomImplementation DomImplementation; 00932 QDomDocumentType documentType = DomImplementation.createDocumentType( "qgis", "http://mrcc.com/qgis.dtd", "SYSTEM" ); 00933 QDomDocument myDocument( documentType ); 00934 00935 QDomElement myRootNode = myDocument.createElement( "qgis" ); 00936 myRootNode.setAttribute( "version", QString( "%1" ).arg( QGis::QGIS_VERSION ) ); 00937 myDocument.appendChild( myRootNode ); 00938 00939 myRootNode.setAttribute( "hasScaleBasedVisibilityFlag", hasScaleBasedVisibility() ? 1 : 0 ); 00940 myRootNode.setAttribute( "minimumScale", QString::number( minimumScale() ) ); 00941 myRootNode.setAttribute( "maximumScale", QString::number( maximumScale() ) ); 00942 00943 #if 0 00944 // <transparencyLevelInt> 00945 QDomElement transparencyLevelIntElement = myDocument.createElement( "transparencyLevelInt" ); 00946 QDomText transparencyLevelIntText = myDocument.createTextNode( QString::number( getTransparency() ) ); 00947 transparencyLevelIntElement.appendChild( transparencyLevelIntText ); 00948 myRootNode.appendChild( transparencyLevelIntElement ); 00949 #endif 00950 00951 if ( !writeSymbology( myRootNode, myDocument, errorMsg ) ) 00952 { 00953 errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg ); 00954 return; 00955 } 00956 doc = myDocument; 00957 } 00958 00959 QString QgsMapLayer::saveDefaultStyle( bool & theResultFlag ) 00960 { 00961 return saveNamedStyle( styleURI(), theResultFlag ); 00962 } 00963 00964 QString QgsMapLayer::saveNamedStyle( const QString theURI, bool & theResultFlag ) 00965 { 00966 QString myErrorMessage; 00967 QDomDocument myDocument; 00968 exportNamedStyle( myDocument, myErrorMessage ); 00969 00970 // check if the uri is a file or ends with .qml, 00971 // which indicates that it should become one 00972 // everything else goes to the database 00973 QString filename; 00974 00975 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this ); 00976 if ( vlayer && vlayer->providerType() == "ogr" ) 00977 { 00978 QStringList theURIParts = theURI.split( "|" ); 00979 filename = theURIParts[0]; 00980 } 00981 else if ( vlayer && vlayer->providerType() == "delimitedtext" ) 00982 { 00983 filename = QUrl::fromEncoded( theURI.toAscii() ).toLocalFile(); 00984 } 00985 else 00986 { 00987 filename = theURI; 00988 } 00989 00990 QFileInfo myFileInfo( filename ); 00991 if ( myFileInfo.exists() || filename.endsWith( ".qml", Qt::CaseInsensitive ) ) 00992 { 00993 QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name 00994 if ( !myDirInfo.isWritable() ) 00995 { 00996 return tr( "The directory containing your dataset needs to be writable!" ); 00997 } 00998 00999 // now construct the file name for our .qml style file 01000 QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml"; 01001 01002 QFile myFile( myFileName ); 01003 if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) ) 01004 { 01005 QTextStream myFileStream( &myFile ); 01006 // save as utf-8 with 2 spaces for indents 01007 myDocument.save( myFileStream, 2 ); 01008 myFile.close(); 01009 theResultFlag = true; 01010 return tr( "Created default style file as %1" ).arg( myFileName ); 01011 } 01012 else 01013 { 01014 theResultFlag = false; 01015 return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName ); 01016 } 01017 } 01018 else 01019 { 01020 QString qml = myDocument.toString(); 01021 01022 // read from database 01023 sqlite3 *myDatabase; 01024 sqlite3_stmt *myPreparedStatement; 01025 const char *myTail; 01026 int myResult; 01027 01028 myResult = sqlite3_open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( "qgis.qmldb" ).toUtf8().data(), &myDatabase ); 01029 if ( myResult != SQLITE_OK ) 01030 { 01031 return tr( "User database could not be opened." ); 01032 } 01033 01034 QByteArray param0 = theURI.toUtf8(); 01035 QByteArray param1 = qml.toUtf8(); 01036 01037 QString mySql = "create table if not exists tbl_styles(style varchar primary key,qml varchar)"; 01038 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 01039 if ( myResult == SQLITE_OK ) 01040 { 01041 if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE ) 01042 { 01043 sqlite3_finalize( myPreparedStatement ); 01044 sqlite3_close( myDatabase ); 01045 theResultFlag = false; 01046 return tr( "The style table could not be created." ); 01047 } 01048 } 01049 01050 sqlite3_finalize( myPreparedStatement ); 01051 01052 mySql = "insert into tbl_styles(style,qml) values (?,?)"; 01053 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 01054 if ( myResult == SQLITE_OK ) 01055 { 01056 if ( sqlite3_bind_text( myPreparedStatement, 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK && 01057 sqlite3_bind_text( myPreparedStatement, 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK && 01058 sqlite3_step( myPreparedStatement ) == SQLITE_DONE ) 01059 { 01060 theResultFlag = true; 01061 myErrorMessage = tr( "The style %1 was saved to database" ).arg( theURI ); 01062 } 01063 } 01064 01065 sqlite3_finalize( myPreparedStatement ); 01066 01067 if ( !theResultFlag ) 01068 { 01069 QString mySql = "update tbl_styles set qml=? where style=?"; 01070 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 01071 if ( myResult == SQLITE_OK ) 01072 { 01073 if ( sqlite3_bind_text( myPreparedStatement, 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK && 01074 sqlite3_bind_text( myPreparedStatement, 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK && 01075 sqlite3_step( myPreparedStatement ) == SQLITE_DONE ) 01076 { 01077 theResultFlag = true; 01078 myErrorMessage = tr( "The style %1 was updated in the database." ).arg( theURI ); 01079 } 01080 else 01081 { 01082 theResultFlag = false; 01083 myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( theURI ); 01084 } 01085 } 01086 else 01087 { 01088 theResultFlag = false; 01089 myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( theURI ); 01090 } 01091 01092 sqlite3_finalize( myPreparedStatement ); 01093 } 01094 01095 sqlite3_close( myDatabase ); 01096 } 01097 01098 return myErrorMessage; 01099 } 01100 01101 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) 01102 { 01103 QDomDocument myDocument = QDomDocument(); 01104 01105 QDomNode header = myDocument.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ); 01106 myDocument.appendChild( header ); 01107 01108 // Create the root element 01109 QDomElement root = myDocument.createElementNS( "http://www.opengis.net/sld", "StyledLayerDescriptor" ); 01110 root.setAttribute( "version", "1.1.0" ); 01111 root.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ); 01112 root.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" ); 01113 root.setAttribute( "xmlns:se", "http://www.opengis.net/se" ); 01114 root.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" ); 01115 root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); 01116 myDocument.appendChild( root ); 01117 01118 // Create the NamedLayer element 01119 QDomElement namedLayerNode = myDocument.createElement( "NamedLayer" ); 01120 root.appendChild( namedLayerNode ); 01121 01122 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this ); 01123 if ( !vlayer ) 01124 { 01125 errorMsg = tr( "Could not save symbology because:\n%1" ) 01126 .arg( "Non-vector layers not supported yet" ); 01127 return; 01128 } 01129 01130 if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg ) ) 01131 { 01132 errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg ); 01133 return; 01134 } 01135 01136 doc = myDocument; 01137 } 01138 01139 QString QgsMapLayer::saveSldStyle( const QString theURI, bool & theResultFlag ) 01140 { 01141 QString errorMsg; 01142 QDomDocument myDocument; 01143 exportSldStyle( myDocument, errorMsg ); 01144 if ( !errorMsg.isNull() ) 01145 { 01146 theResultFlag = false; 01147 return errorMsg; 01148 } 01149 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this ); 01150 01151 // check if the uri is a file or ends with .sld, 01152 // which indicates that it should become one 01153 QString filename; 01154 if ( vlayer->providerType() == "ogr" ) 01155 { 01156 QStringList theURIParts = theURI.split( "|" ); 01157 filename = theURIParts[0]; 01158 } 01159 else if ( vlayer->providerType() == "delimitedtext" ) 01160 { 01161 filename = QUrl::fromEncoded( theURI.toAscii() ).toLocalFile(); 01162 } 01163 else 01164 { 01165 filename = theURI; 01166 } 01167 01168 QFileInfo myFileInfo( filename ); 01169 if ( myFileInfo.exists() || filename.endsWith( ".sld", Qt::CaseInsensitive ) ) 01170 { 01171 QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name 01172 if ( !myDirInfo.isWritable() ) 01173 { 01174 return tr( "The directory containing your dataset needs to be writable!" ); 01175 } 01176 01177 // now construct the file name for our .sld style file 01178 QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld"; 01179 01180 QFile myFile( myFileName ); 01181 if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) ) 01182 { 01183 QTextStream myFileStream( &myFile ); 01184 // save as utf-8 with 2 spaces for indents 01185 myDocument.save( myFileStream, 2 ); 01186 myFile.close(); 01187 theResultFlag = true; 01188 return tr( "Created default style file as %1" ).arg( myFileName ); 01189 } 01190 } 01191 01192 theResultFlag = false; 01193 return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename ); 01194 } 01195 01196 QString QgsMapLayer::loadSldStyle( const QString theURI, bool &theResultFlag ) 01197 { 01198 QgsDebugMsg( "Entered." ); 01199 01200 theResultFlag = false; 01201 01202 QDomDocument myDocument; 01203 01204 // location of problem associated with errorMsg 01205 int line, column; 01206 QString myErrorMessage; 01207 01208 QFile myFile( theURI ); 01209 if ( myFile.open( QFile::ReadOnly ) ) 01210 { 01211 // read file 01212 theResultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column ); 01213 if ( !theResultFlag ) 01214 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column ); 01215 myFile.close(); 01216 } 01217 else 01218 { 01219 myErrorMessage = tr( "Unable to open file %1" ).arg( theURI ); 01220 } 01221 01222 if ( !theResultFlag ) 01223 { 01224 return myErrorMessage; 01225 } 01226 01227 // check for root SLD element 01228 QDomElement myRoot = myDocument.firstChildElement( "StyledLayerDescriptor" ); 01229 if ( myRoot.isNull() ) 01230 { 01231 myErrorMessage = QString( "Error: StyledLayerDescriptor element not found in %1" ).arg( theURI ); 01232 theResultFlag = false; 01233 return myErrorMessage; 01234 } 01235 01236 // now get the style node out and pass it over to the layer 01237 // to deserialise... 01238 QDomElement namedLayerElem = myRoot.firstChildElement( "NamedLayer" ); 01239 if ( namedLayerElem.isNull() ) 01240 { 01241 myErrorMessage = QString( "Info: NamedLayer element not found." ); 01242 theResultFlag = false; 01243 return myErrorMessage; 01244 } 01245 01246 QString errorMsg; 01247 theResultFlag = readSld( namedLayerElem, errorMsg ); 01248 if ( !theResultFlag ) 01249 { 01250 myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( errorMsg ); 01251 return myErrorMessage; 01252 } 01253 01254 return ""; 01255 } 01256 01257 01258 QUndoStack* QgsMapLayer::undoStack() 01259 { 01260 return &mUndoStack; 01261 } 01262 01263 01264 void QgsMapLayer::setCustomProperty( const QString& key, const QVariant& value ) 01265 { 01266 mCustomProperties[key] = value; 01267 } 01268 01269 QVariant QgsMapLayer::customProperty( const QString& value, const QVariant& defaultValue ) const 01270 { 01271 return mCustomProperties.value( value, defaultValue ); 01272 } 01273 01274 void QgsMapLayer::removeCustomProperty( const QString& key ) 01275 { 01276 mCustomProperties.remove( key ); 01277 } 01278 01279 void QgsMapLayer::readCustomProperties( const QDomNode& layerNode, const QString& keyStartsWith ) 01280 { 01281 QDomNode propsNode = layerNode.namedItem( "customproperties" ); 01282 if ( propsNode.isNull() ) // no properties stored... 01283 return; 01284 01285 if ( !keyStartsWith.isEmpty() ) 01286 { 01287 //remove old keys 01288 QStringList keysToRemove; 01289 QMap<QString, QVariant>::const_iterator pIt = mCustomProperties.constBegin(); 01290 for ( ; pIt != mCustomProperties.constEnd(); ++pIt ) 01291 { 01292 if ( pIt.key().startsWith( keyStartsWith ) ) 01293 { 01294 keysToRemove.push_back( pIt.key() ); 01295 } 01296 } 01297 01298 QStringList::const_iterator sIt = keysToRemove.constBegin(); 01299 for ( ; sIt != keysToRemove.constEnd(); ++sIt ) 01300 { 01301 mCustomProperties.remove( *sIt ); 01302 } 01303 } 01304 else 01305 { 01306 mCustomProperties.clear(); 01307 } 01308 01309 QDomNodeList nodes = propsNode.childNodes(); 01310 01311 for ( int i = 0; i < nodes.size(); i++ ) 01312 { 01313 QDomNode propNode = nodes.at( i ); 01314 if ( propNode.isNull() || propNode.nodeName() != "property" ) 01315 continue; 01316 QDomElement propElement = propNode.toElement(); 01317 01318 QString key = propElement.attribute( "key" ); 01319 if ( key.isEmpty() || key.startsWith( keyStartsWith ) ) 01320 { 01321 QString value = propElement.attribute( "value" ); 01322 mCustomProperties[key] = QVariant( value ); 01323 } 01324 } 01325 01326 } 01327 01328 void QgsMapLayer::writeCustomProperties( QDomNode & layerNode, QDomDocument & doc ) const 01329 { 01330 //remove already existing <customproperties> tags 01331 QDomNodeList propertyList = layerNode.toElement().elementsByTagName( "customproperties" ); 01332 for ( int i = 0; i < propertyList.size(); ++i ) 01333 { 01334 layerNode.removeChild( propertyList.at( i ) ); 01335 } 01336 01337 QDomElement propsElement = doc.createElement( "customproperties" ); 01338 01339 for ( QMap<QString, QVariant>::const_iterator it = mCustomProperties.constBegin(); it != mCustomProperties.constEnd(); ++it ) 01340 { 01341 QDomElement propElement = doc.createElement( "property" ); 01342 propElement.setAttribute( "key", it.key() ); 01343 propElement.setAttribute( "value", it.value().toString() ); 01344 propsElement.appendChild( propElement ); 01345 } 01346 01347 layerNode.appendChild( propsElement ); 01348 } 01349 01350 void QgsMapLayer::setCacheImage( QImage * thepImage ) 01351 { 01352 QgsDebugMsg( "cache Image set!" ); 01353 if ( mpCacheImage == thepImage ) 01354 return; 01355 01356 if ( mpCacheImage ) 01357 { 01358 onCacheImageDelete(); 01359 delete mpCacheImage; 01360 } 01361 mpCacheImage = thepImage; 01362 } 01363 01364 bool QgsMapLayer::isEditable() const 01365 { 01366 return false; 01367 } 01368 01369 void QgsMapLayer::setValid( bool valid ) 01370 { 01371 mValid = valid; 01372 } 01373 01374 void QgsMapLayer::clearCacheImage() 01375 { 01376 setCacheImage( 0 ); 01377 } 01378 01379 QString QgsMapLayer::metadata() 01380 { 01381 return QString(); 01382 } 01383 01384 void QgsMapLayer::setExtent( const QgsRectangle &r ) 01385 { 01386 mExtent = r; 01387 }