QGIS API Documentation  master-59fd5e0
src/core/qgsmaplayer.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines