|
QGIS API Documentation
master-6227475
|
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 #if 0 00363 //read transparency level 00364 QDomNode transparencyNode = layer_node.namedItem( "transparencyLevelInt" ); 00365 if ( ! transparencyNode.isNull() ) 00366 { 00367 // set transparency level only if it's in project 00368 // (otherwise it sets the layer transparent) 00369 QDomElement myElement = transparencyNode.toElement(); 00370 setTransparency( myElement.text().toInt() ); 00371 } 00372 #endif 00373 00374 readCustomProperties( layerElement ); 00375 00376 return true; 00377 } // void QgsMapLayer::readXML 00378 00379 00380 bool QgsMapLayer::readXml( const QDomNode& layer_node ) 00381 { 00382 Q_UNUSED( layer_node ); 00383 // NOP by default; children will over-ride with behavior specific to them 00384 00385 return true; 00386 } // void QgsMapLayer::readXml 00387 00388 00389 00390 bool QgsMapLayer::writeLayerXML( QDomElement& layerElement, QDomDocument& document ) 00391 { 00392 // use scale dependent visibility flag 00393 layerElement.setAttribute( "hasScaleBasedVisibilityFlag", hasScaleBasedVisibility() ? 1 : 0 ); 00394 layerElement.setAttribute( "minimumScale", QString::number( minimumScale() ) ); 00395 layerElement.setAttribute( "maximumScale", QString::number( maximumScale() ) ); 00396 00397 // ID 00398 QDomElement layerId = document.createElement( "id" ); 00399 QDomText layerIdText = document.createTextNode( id() ); 00400 layerId.appendChild( layerIdText ); 00401 00402 layerElement.appendChild( layerId ); 00403 00404 // data source 00405 QDomElement dataSource = document.createElement( "datasource" ); 00406 00407 QString src = source(); 00408 00409 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this ); 00410 // TODO: what about postgres, mysql and others, they should not go through writePath() 00411 if ( vlayer && vlayer->providerType() == "spatialite" ) 00412 { 00413 QgsDataSourceURI uri( src ); 00414 QString database = QgsProject::instance()->writePath( uri.database() ); 00415 uri.setConnection( uri.host(), uri.port(), database, uri.username(), uri.password() ); 00416 src = uri.uri(); 00417 } 00418 else if ( vlayer && vlayer->providerType() == "ogr" ) 00419 { 00420 QStringList theURIParts = src.split( "|" ); 00421 theURIParts[0] = QgsProject::instance()->writePath( theURIParts[0] ); 00422 src = theURIParts.join( "|" ); 00423 } 00424 else if ( vlayer && vlayer->providerType() == "delimitedtext" ) 00425 { 00426 QUrl urlSource = QUrl::fromEncoded( src.toAscii() ); 00427 QUrl urlDest = QUrl::fromLocalFile( QgsProject::instance()->writePath( urlSource.toLocalFile() ) ); 00428 urlDest.setQueryItems( urlSource.queryItems() ); 00429 src = QString::fromAscii( urlDest.toEncoded() ); 00430 } 00431 else 00432 { 00433 src = QgsProject::instance()->writePath( src ); 00434 } 00435 00436 QDomText dataSourceText = document.createTextNode( src ); 00437 dataSource.appendChild( dataSourceText ); 00438 00439 layerElement.appendChild( dataSource ); 00440 00441 00442 // layer name 00443 QDomElement layerName = document.createElement( "layername" ); 00444 QDomText layerNameText = document.createTextNode( originalName() ); 00445 layerName.appendChild( layerNameText ); 00446 00447 // layer title 00448 QDomElement layerTitle = document.createElement( "title" ) ; 00449 QDomText layerTitleText = document.createTextNode( title() ); 00450 layerTitle.appendChild( layerTitleText ); 00451 00452 // layer abstract 00453 QDomElement layerAbstract = document.createElement( "abstract" ); 00454 QDomText layerAbstractText = document.createTextNode( abstract() ); 00455 layerAbstract.appendChild( layerAbstractText ); 00456 00457 layerElement.appendChild( layerName ); 00458 layerElement.appendChild( layerTitle ); 00459 layerElement.appendChild( layerAbstract ); 00460 00461 // timestamp if supported 00462 if ( timestamp() > QDateTime() ) 00463 { 00464 QDomElement stamp = document.createElement( "timestamp" ); 00465 QDomText stampText = document.createTextNode( timestamp().toString( Qt::ISODate ) ); 00466 stamp.appendChild( stampText ); 00467 layerElement.appendChild( stamp ); 00468 } 00469 00470 layerElement.appendChild( layerName ); 00471 00472 // zorder 00473 // This is no longer stored in the project file. It is superfluous since the layers 00474 // are written and read in the proper order. 00475 00476 // spatial reference system id 00477 QDomElement mySrsElement = document.createElement( "srs" ); 00478 mCRS->writeXML( mySrsElement, document ); 00479 layerElement.appendChild( mySrsElement ); 00480 00481 #if 0 00482 // <transparencyLevelInt> 00483 QDomElement transparencyLevelIntElement = document.createElement( "transparencyLevelInt" ); 00484 QDomText transparencyLevelIntText = document.createTextNode( QString::number( getTransparency() ) ); 00485 transparencyLevelIntElement.appendChild( transparencyLevelIntText ); 00486 maplayer.appendChild( transparencyLevelIntElement ); 00487 #endif 00488 00489 // now append layer node to map layer node 00490 00491 writeCustomProperties( layerElement, document ); 00492 00493 return writeXml( layerElement, document ); 00494 00495 } // bool QgsMapLayer::writeXML 00496 00497 00498 bool QgsMapLayer::writeXml( QDomNode & layer_node, QDomDocument & document ) 00499 { 00500 Q_UNUSED( layer_node ); 00501 Q_UNUSED( document ); 00502 // NOP by default; children will over-ride with behavior specific to them 00503 00504 return true; 00505 } // void QgsMapLayer::writeXml 00506 00507 00508 00509 00510 bool QgsMapLayer::isValid() 00511 { 00512 return mValid; 00513 } 00514 00515 00516 void QgsMapLayer::invalidTransformInput() 00517 { 00518 QgsDebugMsg( "called" ); 00519 // TODO: emit a signal - it will be used to update legend 00520 } 00521 00522 00523 QString QgsMapLayer::lastErrorTitle() 00524 { 00525 return QString(); 00526 } 00527 00528 QString QgsMapLayer::lastError() 00529 { 00530 return QString(); 00531 } 00532 00533 void QgsMapLayer::connectNotify( const char * signal ) 00534 { 00535 Q_UNUSED( signal ); 00536 QgsDebugMsgLevel( "QgsMapLayer connected to " + QString( signal ), 3 ); 00537 } // QgsMapLayer::connectNotify 00538 00539 00540 00541 void QgsMapLayer::toggleScaleBasedVisibility( bool theVisibilityFlag ) 00542 { 00543 mScaleBasedVisibility = theVisibilityFlag; 00544 } 00545 00546 bool QgsMapLayer::hasScaleBasedVisibility() 00547 { 00548 return mScaleBasedVisibility; 00549 } 00550 00551 void QgsMapLayer::setMinimumScale( float theMinScale ) 00552 { 00553 mMinScale = theMinScale; 00554 } 00555 00556 float QgsMapLayer::minimumScale() 00557 { 00558 return mMinScale; 00559 } 00560 00561 00562 void QgsMapLayer::setMaximumScale( float theMaxScale ) 00563 { 00564 mMaxScale = theMaxScale; 00565 } 00566 00567 float QgsMapLayer::maximumScale() 00568 { 00569 return mMaxScale; 00570 } 00571 00572 00573 QStringList QgsMapLayer::subLayers() const 00574 { 00575 return QStringList(); // Empty 00576 } 00577 00578 void QgsMapLayer::setLayerOrder( const QStringList &layers ) 00579 { 00580 Q_UNUSED( layers ); 00581 // NOOP 00582 } 00583 00584 void QgsMapLayer::setSubLayerVisibility( QString name, bool vis ) 00585 { 00586 Q_UNUSED( name ); 00587 Q_UNUSED( vis ); 00588 // NOOP 00589 } 00590 00591 const QgsCoordinateReferenceSystem& QgsMapLayer::crs() const 00592 { 00593 return *mCRS; 00594 } 00595 00596 void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem& srs, bool emitSignal ) 00597 { 00598 *mCRS = srs; 00599 00600 if ( !mCRS->isValid() ) 00601 { 00602 mCRS->setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) ); 00603 mCRS->validate(); 00604 } 00605 00606 if ( emitSignal ) 00607 emit layerCrsChanged(); 00608 } 00609 00610 #if 0 00611 unsigned int QgsMapLayer::getTransparency() 00612 { 00613 return mTransparencyLevel; 00614 } 00615 00616 void QgsMapLayer::setTransparency( unsigned int theInt ) 00617 { 00618 mTransparencyLevel = theInt; 00619 } 00620 #endif 00621 00622 QString QgsMapLayer::capitaliseLayerName( const QString& name ) 00623 { 00624 // Capitalise the first letter of the layer name if requested 00625 QSettings settings; 00626 bool capitaliseLayerName = 00627 settings.value( "/qgis/capitaliseLayerName", QVariant( false ) ).toBool(); 00628 00629 QString layerName( name ); 00630 00631 if ( capitaliseLayerName ) 00632 layerName = layerName.left( 1 ).toUpper() + layerName.mid( 1 ); 00633 00634 return layerName; 00635 } 00636 00637 QString QgsMapLayer::styleURI( ) 00638 { 00639 QString myURI = publicSource(); 00640 00641 // if file is using the VSIFILE mechanism, remove the prefix 00642 if ( myURI.startsWith( "/vsigzip/", Qt::CaseInsensitive ) ) 00643 { 00644 myURI.remove( 0, 9 ); 00645 } 00646 else if ( myURI.startsWith( "/vsizip/", Qt::CaseInsensitive ) && 00647 myURI.endsWith( ".zip", Qt::CaseInsensitive ) ) 00648 { 00649 // ideally we should look for .qml file inside zip file 00650 myURI.remove( 0, 8 ); 00651 } 00652 else if ( myURI.startsWith( "/vsitar/", Qt::CaseInsensitive ) && 00653 ( myURI.endsWith( ".tar", Qt::CaseInsensitive ) || 00654 myURI.endsWith( ".tar.gz", Qt::CaseInsensitive ) || 00655 myURI.endsWith( ".tgz", Qt::CaseInsensitive ) ) ) 00656 { 00657 // ideally we should look for .qml file inside tar file 00658 myURI.remove( 0, 8 ); 00659 } 00660 00661 QFileInfo myFileInfo( myURI ); 00662 QString key; 00663 00664 if ( myFileInfo.exists() ) 00665 { 00666 // if file is using the /vsizip/ or /vsigzip/ mechanism, cleanup the name 00667 if ( myURI.endsWith( ".gz", Qt::CaseInsensitive ) ) 00668 myURI.chop( 3 ); 00669 else if ( myURI.endsWith( ".zip", Qt::CaseInsensitive ) ) 00670 myURI.chop( 4 ); 00671 else if ( myURI.endsWith( ".tar", Qt::CaseInsensitive ) ) 00672 myURI.chop( 4 ); 00673 else if ( myURI.endsWith( ".tar.gz", Qt::CaseInsensitive ) ) 00674 myURI.chop( 7 ); 00675 else if ( myURI.endsWith( ".tgz", Qt::CaseInsensitive ) ) 00676 myURI.chop( 4 ); 00677 else if ( myURI.endsWith( ".gz", Qt::CaseInsensitive ) ) 00678 myURI.chop( 3 ); 00679 myFileInfo.setFile( myURI ); 00680 // get the file name for our .qml style file 00681 key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml"; 00682 } 00683 else 00684 { 00685 key = publicSource(); 00686 } 00687 00688 return key; 00689 } 00690 00691 QString QgsMapLayer::loadDefaultStyle( bool & theResultFlag ) 00692 { 00693 return loadNamedStyle( styleURI(), theResultFlag ); 00694 } 00695 00696 bool QgsMapLayer::loadNamedStyleFromDb( const QString db, const QString theURI, QString &qml ) 00697 { 00698 QgsDebugMsg( QString( "db = %1 uri = %2" ).arg( db ).arg( theURI ) ); 00699 00700 bool theResultFlag = false; 00701 00702 // read from database 00703 sqlite3 *myDatabase; 00704 sqlite3_stmt *myPreparedStatement; 00705 const char *myTail; 00706 int myResult; 00707 00708 QgsDebugMsg( QString( "Trying to load style for \"%1\" from \"%2\"" ).arg( theURI ).arg( db ) ); 00709 00710 if ( !QFile( db ).exists() ) 00711 return false; 00712 00713 myResult = sqlite3_open_v2( db.toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL ); 00714 if ( myResult != SQLITE_OK ) 00715 { 00716 return false; 00717 } 00718 00719 QString mySql = "select qml from tbl_styles where style=?"; 00720 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 00721 if ( myResult == SQLITE_OK ) 00722 { 00723 QByteArray param = theURI.toUtf8(); 00724 00725 if ( sqlite3_bind_text( myPreparedStatement, 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK && 00726 sqlite3_step( myPreparedStatement ) == SQLITE_ROW ) 00727 { 00728 qml = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) ); 00729 theResultFlag = true; 00730 } 00731 00732 sqlite3_finalize( myPreparedStatement ); 00733 } 00734 00735 sqlite3_close( myDatabase ); 00736 00737 return theResultFlag; 00738 } 00739 00740 QString QgsMapLayer::loadNamedStyle( const QString theURI, bool &theResultFlag ) 00741 { 00742 QgsDebugMsg( QString( "uri = %1 myURI = %2" ).arg( theURI ).arg( publicSource() ) ); 00743 00744 theResultFlag = false; 00745 00746 QDomDocument myDocument( "qgis" ); 00747 00748 // location of problem associated with errorMsg 00749 int line, column; 00750 QString myErrorMessage; 00751 00752 QFile myFile( theURI ); 00753 if ( myFile.open( QFile::ReadOnly ) ) 00754 { 00755 // read file 00756 theResultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column ); 00757 if ( !theResultFlag ) 00758 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column ); 00759 myFile.close(); 00760 } 00761 else 00762 { 00763 QFileInfo project( QgsProject::instance()->fileName() ); 00764 QgsDebugMsg( QString( "project fileName: %1" ).arg( project.absoluteFilePath() ) ); 00765 00766 QString qml; 00767 if ( loadNamedStyleFromDb( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( "qgis.qmldb" ), theURI, qml ) || 00768 ( project.exists() && loadNamedStyleFromDb( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), theURI, qml ) ) || 00769 loadNamedStyleFromDb( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( "resources/qgis.qmldb" ), theURI, qml ) ) 00770 { 00771 theResultFlag = myDocument.setContent( qml, &myErrorMessage, &line, &column ); 00772 if ( !theResultFlag ) 00773 { 00774 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column ); 00775 } 00776 } 00777 else 00778 { 00779 myErrorMessage = tr( "style not found in database" ); 00780 } 00781 } 00782 00783 if ( !theResultFlag ) 00784 { 00785 return myErrorMessage; 00786 } 00787 00788 // get style file version string, if any 00789 QgsProjectVersion fileVersion( myDocument.firstChildElement( "qgis" ).attribute( "version" ) ); 00790 QgsProjectVersion thisVersion( QGis::QGIS_VERSION ); 00791 00792 if ( thisVersion > fileVersion ) 00793 { 00794 QgsLogger::warning( "Loading a style file that was saved with an older " 00795 "version of qgis (saved in " + fileVersion.text() + 00796 ", loaded in " + QGis::QGIS_VERSION + 00797 "). Problems may occur." ); 00798 00799 QgsProjectFileTransform styleFile( myDocument, fileVersion ); 00800 // styleFile.dump(); 00801 styleFile.updateRevision( thisVersion ); 00802 // styleFile.dump(); 00803 } 00804 00805 // now get the layer node out and pass it over to the layer 00806 // to deserialise... 00807 QDomElement myRoot = myDocument.firstChildElement( "qgis" ); 00808 if ( myRoot.isNull() ) 00809 { 00810 myErrorMessage = tr( "Error: qgis element could not be found in %1" ).arg( theURI ); 00811 theResultFlag = false; 00812 return myErrorMessage; 00813 } 00814 00815 // use scale dependent visibility flag 00816 toggleScaleBasedVisibility( myRoot.attribute( "hasScaleBasedVisibilityFlag" ).toInt() == 1 ); 00817 setMinimumScale( myRoot.attribute( "minimumScale" ).toFloat() ); 00818 setMaximumScale( myRoot.attribute( "maximumScale" ).toFloat() ); 00819 00820 #if 0 00821 //read transparency level 00822 QDomNode transparencyNode = myRoot.namedItem( "transparencyLevelInt" ); 00823 if ( ! transparencyNode.isNull() ) 00824 { 00825 // set transparency level only if it's in project 00826 // (otherwise it sets the layer transparent) 00827 QDomElement myElement = transparencyNode.toElement(); 00828 setTransparency( myElement.text().toInt() ); 00829 } 00830 #endif 00831 00832 QString errorMsg; 00833 theResultFlag = readSymbology( myRoot, errorMsg ); 00834 if ( !theResultFlag ) 00835 { 00836 myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( errorMsg ); 00837 return myErrorMessage; 00838 } 00839 00840 return ""; 00841 } 00842 00843 void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg ) 00844 { 00845 QDomImplementation DomImplementation; 00846 QDomDocumentType documentType = DomImplementation.createDocumentType( "qgis", "http://mrcc.com/qgis.dtd", "SYSTEM" ); 00847 QDomDocument myDocument( documentType ); 00848 00849 QDomElement myRootNode = myDocument.createElement( "qgis" ); 00850 myRootNode.setAttribute( "version", QString( "%1" ).arg( QGis::QGIS_VERSION ) ); 00851 myDocument.appendChild( myRootNode ); 00852 00853 myRootNode.setAttribute( "hasScaleBasedVisibilityFlag", hasScaleBasedVisibility() ? 1 : 0 ); 00854 myRootNode.setAttribute( "minimumScale", QString::number( minimumScale() ) ); 00855 myRootNode.setAttribute( "maximumScale", QString::number( maximumScale() ) ); 00856 00857 #if 0 00858 // <transparencyLevelInt> 00859 QDomElement transparencyLevelIntElement = myDocument.createElement( "transparencyLevelInt" ); 00860 QDomText transparencyLevelIntText = myDocument.createTextNode( QString::number( getTransparency() ) ); 00861 transparencyLevelIntElement.appendChild( transparencyLevelIntText ); 00862 myRootNode.appendChild( transparencyLevelIntElement ); 00863 #endif 00864 00865 if ( !writeSymbology( myRootNode, myDocument, errorMsg ) ) 00866 { 00867 errorMsg = QObject::tr( "Could not save symbology because:\n%1" ).arg( errorMsg ); 00868 return; 00869 } 00870 doc = myDocument; 00871 } 00872 00873 QString QgsMapLayer::saveDefaultStyle( bool & theResultFlag ) 00874 { 00875 return saveNamedStyle( styleURI(), theResultFlag ); 00876 } 00877 00878 QString QgsMapLayer::saveNamedStyle( const QString theURI, bool & theResultFlag ) 00879 { 00880 QString myErrorMessage; 00881 QDomDocument myDocument; 00882 exportNamedStyle( myDocument, myErrorMessage ); 00883 00884 // check if the uri is a file or ends with .qml, 00885 // which indicates that it should become one 00886 // everything else goes to the database 00887 QString filename; 00888 00889 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this ); 00890 if ( vlayer && vlayer->providerType() == "ogr" ) 00891 { 00892 QStringList theURIParts = theURI.split( "|" ); 00893 filename = theURIParts[0]; 00894 } 00895 else if ( vlayer && vlayer->providerType() == "delimitedtext" ) 00896 { 00897 filename = QUrl::fromEncoded( theURI.toAscii() ).toLocalFile(); 00898 } 00899 else 00900 { 00901 filename = theURI; 00902 } 00903 00904 QFileInfo myFileInfo( filename ); 00905 if ( myFileInfo.exists() || filename.endsWith( ".qml", Qt::CaseInsensitive ) ) 00906 { 00907 QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name 00908 if ( !myDirInfo.isWritable() ) 00909 { 00910 return tr( "The directory containing your dataset needs to be writable!" ); 00911 } 00912 00913 // now construct the file name for our .qml style file 00914 QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml"; 00915 00916 QFile myFile( myFileName ); 00917 if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) ) 00918 { 00919 QTextStream myFileStream( &myFile ); 00920 // save as utf-8 with 2 spaces for indents 00921 myDocument.save( myFileStream, 2 ); 00922 myFile.close(); 00923 theResultFlag = true; 00924 return tr( "Created default style file as %1" ).arg( myFileName ); 00925 } 00926 else 00927 { 00928 theResultFlag = false; 00929 return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName ); 00930 } 00931 } 00932 else 00933 { 00934 QString qml = myDocument.toString(); 00935 00936 // read from database 00937 sqlite3 *myDatabase; 00938 sqlite3_stmt *myPreparedStatement; 00939 const char *myTail; 00940 int myResult; 00941 00942 myResult = sqlite3_open( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( "qgis.qmldb" ).toUtf8().data(), &myDatabase ); 00943 if ( myResult != SQLITE_OK ) 00944 { 00945 return tr( "User database could not be opened." ); 00946 } 00947 00948 QByteArray param0 = theURI.toUtf8(); 00949 QByteArray param1 = qml.toUtf8(); 00950 00951 QString mySql = "create table if not exists tbl_styles(style varchar primary key,qml varchar)"; 00952 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 00953 if ( myResult == SQLITE_OK ) 00954 { 00955 if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE ) 00956 { 00957 sqlite3_finalize( myPreparedStatement ); 00958 sqlite3_close( myDatabase ); 00959 theResultFlag = false; 00960 return tr( "The style table could not be created." ); 00961 } 00962 } 00963 00964 sqlite3_finalize( myPreparedStatement ); 00965 00966 mySql = "insert into tbl_styles(style,qml) values (?,?)"; 00967 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 00968 if ( myResult == SQLITE_OK ) 00969 { 00970 if ( sqlite3_bind_text( myPreparedStatement, 1, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK && 00971 sqlite3_bind_text( myPreparedStatement, 2, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK && 00972 sqlite3_step( myPreparedStatement ) == SQLITE_DONE ) 00973 { 00974 theResultFlag = true; 00975 myErrorMessage = tr( "The style %1 was saved to database" ).arg( theURI ); 00976 } 00977 } 00978 00979 sqlite3_finalize( myPreparedStatement ); 00980 00981 if ( !theResultFlag ) 00982 { 00983 QString mySql = "update tbl_styles set qml=? where style=?"; 00984 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8().data(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 00985 if ( myResult == SQLITE_OK ) 00986 { 00987 if ( sqlite3_bind_text( myPreparedStatement, 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK && 00988 sqlite3_bind_text( myPreparedStatement, 1, param1.data(), param1.length(), SQLITE_STATIC ) == SQLITE_OK && 00989 sqlite3_step( myPreparedStatement ) == SQLITE_DONE ) 00990 { 00991 theResultFlag = true; 00992 myErrorMessage = tr( "The style %1 was updated in the database." ).arg( theURI ); 00993 } 00994 else 00995 { 00996 theResultFlag = false; 00997 myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( theURI ); 00998 } 00999 } 01000 else 01001 { 01002 theResultFlag = false; 01003 myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( theURI ); 01004 } 01005 01006 sqlite3_finalize( myPreparedStatement ); 01007 } 01008 01009 sqlite3_close( myDatabase ); 01010 } 01011 01012 return myErrorMessage; 01013 } 01014 01015 void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) 01016 { 01017 QDomDocument myDocument = QDomDocument(); 01018 01019 QDomNode header = myDocument.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ); 01020 myDocument.appendChild( header ); 01021 01022 // Create the root element 01023 QDomElement root = myDocument.createElementNS( "http://www.opengis.net/sld", "StyledLayerDescriptor" ); 01024 root.setAttribute( "version", "1.1.0" ); 01025 root.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" ); 01026 root.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" ); 01027 root.setAttribute( "xmlns:se", "http://www.opengis.net/se" ); 01028 root.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" ); 01029 root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); 01030 myDocument.appendChild( root ); 01031 01032 // Create the NamedLayer element 01033 QDomElement namedLayerNode = myDocument.createElement( "NamedLayer" ); 01034 root.appendChild( namedLayerNode ); 01035 01036 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this ); 01037 if ( !vlayer ) 01038 { 01039 errorMsg = tr( "Could not save symbology because:\n%1" ) 01040 .arg( "Non-vector layers not supported yet" ); 01041 return; 01042 } 01043 01044 if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg ) ) 01045 { 01046 errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg ); 01047 return; 01048 } 01049 01050 doc = myDocument; 01051 } 01052 01053 QString QgsMapLayer::saveSldStyle( const QString theURI, bool & theResultFlag ) 01054 { 01055 QString errorMsg; 01056 QDomDocument myDocument; 01057 exportSldStyle( myDocument, errorMsg ); 01058 if ( !errorMsg.isNull() ) 01059 { 01060 theResultFlag = false; 01061 return errorMsg; 01062 } 01063 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this ); 01064 01065 // check if the uri is a file or ends with .sld, 01066 // which indicates that it should become one 01067 QString filename; 01068 if ( vlayer->providerType() == "ogr" ) 01069 { 01070 QStringList theURIParts = theURI.split( "|" ); 01071 filename = theURIParts[0]; 01072 } 01073 else if ( vlayer->providerType() == "delimitedtext" ) 01074 { 01075 filename = QUrl::fromEncoded( theURI.toAscii() ).toLocalFile(); 01076 } 01077 else 01078 { 01079 filename = theURI; 01080 } 01081 01082 QFileInfo myFileInfo( filename ); 01083 if ( myFileInfo.exists() || filename.endsWith( ".sld", Qt::CaseInsensitive ) ) 01084 { 01085 QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name 01086 if ( !myDirInfo.isWritable() ) 01087 { 01088 return tr( "The directory containing your dataset needs to be writable!" ); 01089 } 01090 01091 // now construct the file name for our .sld style file 01092 QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld"; 01093 01094 QFile myFile( myFileName ); 01095 if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) ) 01096 { 01097 QTextStream myFileStream( &myFile ); 01098 // save as utf-8 with 2 spaces for indents 01099 myDocument.save( myFileStream, 2 ); 01100 myFile.close(); 01101 theResultFlag = true; 01102 return tr( "Created default style file as %1" ).arg( myFileName ); 01103 } 01104 } 01105 01106 theResultFlag = false; 01107 return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename ); 01108 } 01109 01110 QString QgsMapLayer::loadSldStyle( const QString theURI, bool &theResultFlag ) 01111 { 01112 QgsDebugMsg( "Entered." ); 01113 01114 theResultFlag = false; 01115 01116 QDomDocument myDocument; 01117 01118 // location of problem associated with errorMsg 01119 int line, column; 01120 QString myErrorMessage; 01121 01122 QFile myFile( theURI ); 01123 if ( myFile.open( QFile::ReadOnly ) ) 01124 { 01125 // read file 01126 theResultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column ); 01127 if ( !theResultFlag ) 01128 myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column ); 01129 myFile.close(); 01130 } 01131 else 01132 { 01133 myErrorMessage = tr( "Unable to open file %1" ).arg( theURI ); 01134 } 01135 01136 if ( !theResultFlag ) 01137 { 01138 return myErrorMessage; 01139 } 01140 01141 // check for root SLD element 01142 QDomElement myRoot = myDocument.firstChildElement( "StyledLayerDescriptor" ); 01143 if ( myRoot.isNull() ) 01144 { 01145 myErrorMessage = QString( "Error: StyledLayerDescriptor element not found in %1" ).arg( theURI ); 01146 theResultFlag = false; 01147 return myErrorMessage; 01148 } 01149 01150 // now get the style node out and pass it over to the layer 01151 // to deserialise... 01152 QDomElement namedLayerElem = myRoot.firstChildElement( "NamedLayer" ); 01153 if ( namedLayerElem.isNull() ) 01154 { 01155 myErrorMessage = QString( "Info: NamedLayer element not found." ); 01156 theResultFlag = false; 01157 return myErrorMessage; 01158 } 01159 01160 QString errorMsg; 01161 theResultFlag = readSld( namedLayerElem, errorMsg ); 01162 if ( !theResultFlag ) 01163 { 01164 myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( errorMsg ); 01165 return myErrorMessage; 01166 } 01167 01168 return ""; 01169 } 01170 01171 01172 QUndoStack* QgsMapLayer::undoStack() 01173 { 01174 return &mUndoStack; 01175 } 01176 01177 01178 void QgsMapLayer::setCustomProperty( const QString& key, const QVariant& value ) 01179 { 01180 mCustomProperties[key] = value; 01181 } 01182 01183 QVariant QgsMapLayer::customProperty( const QString& value, const QVariant& defaultValue ) const 01184 { 01185 return mCustomProperties.value( value, defaultValue ); 01186 } 01187 01188 void QgsMapLayer::removeCustomProperty( const QString& key ) 01189 { 01190 mCustomProperties.remove( key ); 01191 } 01192 01193 void QgsMapLayer::readCustomProperties( const QDomNode& layerNode, const QString& keyStartsWith ) 01194 { 01195 QDomNode propsNode = layerNode.namedItem( "customproperties" ); 01196 if ( propsNode.isNull() ) // no properties stored... 01197 return; 01198 01199 if ( !keyStartsWith.isEmpty() ) 01200 { 01201 //remove old keys 01202 QStringList keysToRemove; 01203 QMap<QString, QVariant>::const_iterator pIt = mCustomProperties.constBegin(); 01204 for ( ; pIt != mCustomProperties.constEnd(); ++pIt ) 01205 { 01206 if ( pIt.key().startsWith( keyStartsWith ) ) 01207 { 01208 keysToRemove.push_back( pIt.key() ); 01209 } 01210 } 01211 01212 QStringList::const_iterator sIt = keysToRemove.constBegin(); 01213 for ( ; sIt != keysToRemove.constEnd(); ++sIt ) 01214 { 01215 mCustomProperties.remove( *sIt ); 01216 } 01217 } 01218 else 01219 { 01220 mCustomProperties.clear(); 01221 } 01222 01223 QDomNodeList nodes = propsNode.childNodes(); 01224 01225 for ( int i = 0; i < nodes.size(); i++ ) 01226 { 01227 QDomNode propNode = nodes.at( i ); 01228 if ( propNode.isNull() || propNode.nodeName() != "property" ) 01229 continue; 01230 QDomElement propElement = propNode.toElement(); 01231 01232 QString key = propElement.attribute( "key" ); 01233 if ( key.isEmpty() || key.startsWith( keyStartsWith ) ) 01234 { 01235 QString value = propElement.attribute( "value" ); 01236 mCustomProperties[key] = QVariant( value ); 01237 } 01238 } 01239 01240 } 01241 01242 void QgsMapLayer::writeCustomProperties( QDomNode & layerNode, QDomDocument & doc ) const 01243 { 01244 //remove already existing <customproperties> tags 01245 QDomNodeList propertyList = layerNode.toElement().elementsByTagName( "customproperties" ); 01246 for ( int i = 0; i < propertyList.size(); ++i ) 01247 { 01248 layerNode.removeChild( propertyList.at( i ) ); 01249 } 01250 01251 QDomElement propsElement = doc.createElement( "customproperties" ); 01252 01253 for ( QMap<QString, QVariant>::const_iterator it = mCustomProperties.constBegin(); it != mCustomProperties.constEnd(); ++it ) 01254 { 01255 QDomElement propElement = doc.createElement( "property" ); 01256 propElement.setAttribute( "key", it.key() ); 01257 propElement.setAttribute( "value", it.value().toString() ); 01258 propsElement.appendChild( propElement ); 01259 } 01260 01261 layerNode.appendChild( propsElement ); 01262 } 01263 01264 void QgsMapLayer::setCacheImage( QImage * thepImage ) 01265 { 01266 QgsDebugMsg( "cache Image set!" ); 01267 if ( mpCacheImage == thepImage ) 01268 return; 01269 01270 if ( mpCacheImage ) 01271 { 01272 onCacheImageDelete(); 01273 delete mpCacheImage; 01274 } 01275 mpCacheImage = thepImage; 01276 } 01277 01278 bool QgsMapLayer::isEditable() const 01279 { 01280 return false; 01281 } 01282 01283 void QgsMapLayer::setValid( bool valid ) 01284 { 01285 mValid = valid; 01286 } 01287 01288 void QgsMapLayer::clearCacheImage() 01289 { 01290 setCacheImage( 0 ); 01291 } 01292 01293 QString QgsMapLayer::metadata() 01294 { 01295 return QString(); 01296 } 01297 01298 void QgsMapLayer::setExtent( const QgsRectangle &r ) 01299 { 01300 mExtent = r; 01301 }