QGIS API Documentation  master-6227475
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 #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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines