QGIS API Documentation  master-59fd5e0
src/core/symbology-ng/qgssvgcache.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                               qgssvgcache.h
00003                             ------------------------------
00004   begin                :  2011
00005   copyright            : (C) 2011 by Marco Hugentobler
00006   email                : marco dot hugentobler at sourcepole dot ch
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 #include "qgssvgcache.h"
00019 #include "qgis.h"
00020 #include "qgslogger.h"
00021 #include "qgsnetworkaccessmanager.h"
00022 #include "qgsmessagelog.h"
00023 #include <QApplication>
00024 #include <QCoreApplication>
00025 #include <QCursor>
00026 #include <QDomDocument>
00027 #include <QDomElement>
00028 #include <QFile>
00029 #include <QImage>
00030 #include <QPainter>
00031 #include <QPicture>
00032 #include <QSvgRenderer>
00033 #include <QFileInfo>
00034 #include <QNetworkReply>
00035 #include <QNetworkRequest>
00036 
00037 QgsSvgCacheEntry::QgsSvgCacheEntry(): file( QString() ), size( 0.0 ), outlineWidth( 0 ), widthScaleFactor( 1.0 ), rasterScaleFactor( 1.0 ), fill( Qt::black ),
00038     outline( Qt::black ), image( 0 ), picture( 0 )
00039 {
00040 }
00041 
00042 QgsSvgCacheEntry::QgsSvgCacheEntry( const QString& f, double s, double ow, double wsf, double rsf, const QColor& fi, const QColor& ou ): file( f ), size( s ), outlineWidth( ow ),
00043     widthScaleFactor( wsf ), rasterScaleFactor( rsf ), fill( fi ), outline( ou ), image( 0 ), picture( 0 )
00044 {
00045 }
00046 
00047 
00048 QgsSvgCacheEntry::~QgsSvgCacheEntry()
00049 {
00050   delete image;
00051   delete picture;
00052 }
00053 
00054 bool QgsSvgCacheEntry::operator==( const QgsSvgCacheEntry& other ) const
00055 {
00056   return ( other.file == file && other.size == size && other.outlineWidth == outlineWidth && other.widthScaleFactor == widthScaleFactor
00057            && other.rasterScaleFactor == rasterScaleFactor && other.fill == fill && other.outline == outline );
00058 }
00059 
00060 int QgsSvgCacheEntry::dataSize() const
00061 {
00062   int size = svgContent.size();
00063   if ( picture )
00064   {
00065     size += picture->size();
00066   }
00067   if ( image )
00068   {
00069     size += ( image->width() * image->height() * 32 );
00070   }
00071   return size;
00072 }
00073 
00074 QString file;
00075 double size;
00076 double outlineWidth;
00077 double widthScaleFactor;
00078 double rasterScaleFactor;
00079 QColor fill;
00080 QColor outline;
00081 
00082 QgsSvgCache* QgsSvgCache::mInstance = 0;
00083 
00084 QgsSvgCache* QgsSvgCache::instance()
00085 {
00086   if ( !mInstance )
00087   {
00088     mInstance = new QgsSvgCache();
00089   }
00090   return mInstance;
00091 }
00092 
00093 QgsSvgCache::QgsSvgCache( QObject *parent )
00094     : QObject( parent )
00095     , mTotalSize( 0 )
00096     , mLeastRecentEntry( 0 )
00097     , mMostRecentEntry( 0 )
00098 {
00099 }
00100 
00101 QgsSvgCache::~QgsSvgCache()
00102 {
00103   QMultiHash< QString, QgsSvgCacheEntry* >::iterator it = mEntryLookup.begin();
00104   for ( ; it != mEntryLookup.end(); ++it )
00105   {
00106     delete it.value();
00107   }
00108 }
00109 
00110 
00111 const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
00112                                        double widthScaleFactor, double rasterScaleFactor, bool& fitsInCache )
00113 {
00114   fitsInCache = true;
00115   QgsSvgCacheEntry* currentEntry = cacheEntry( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );
00116 
00117   //if current entry image is 0: cache image for entry
00118   // checks to see if image will fit into cache
00119   //update stats for memory usage
00120   if ( !currentEntry->image )
00121   {
00122     QSvgRenderer r( currentEntry->svgContent );
00123     double hwRatio = 1.0;
00124     if ( r.viewBoxF().width() > 0 )
00125     {
00126       hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
00127     }
00128     long cachedDataSize = 0;
00129     cachedDataSize += currentEntry->svgContent.size();
00130     cachedDataSize += ( int )( currentEntry->size * currentEntry->size * hwRatio * 32 );
00131     if ( cachedDataSize > mMaximumSize / 2 )
00132     {
00133       fitsInCache = false;
00134       delete currentEntry->image;
00135       currentEntry->image = 0;
00136       //currentEntry->image = new QImage( 0, 0 );
00137 
00138       // instead cache picture
00139       cachePicture( currentEntry );
00140     }
00141     else
00142     {
00143       cacheImage( currentEntry );
00144     }
00145     trimToMaximumSize();
00146   }
00147 
00148   return *( currentEntry->image );
00149 }
00150 
00151 const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
00152     double widthScaleFactor, double rasterScaleFactor )
00153 {
00154   QgsSvgCacheEntry* currentEntry = cacheEntry( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );
00155 
00156   //if current entry picture is 0: cache picture for entry
00157   //update stats for memory usage
00158   if ( !currentEntry->picture )
00159   {
00160     cachePicture( currentEntry );
00161     trimToMaximumSize();
00162   }
00163 
00164   return *( currentEntry->picture );
00165 }
00166 
00167 QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
00168     double widthScaleFactor, double rasterScaleFactor )
00169 {
00170   QgsSvgCacheEntry* entry = new QgsSvgCacheEntry( file, size, outlineWidth, widthScaleFactor, rasterScaleFactor, fill, outline );
00171 
00172   replaceParamsAndCacheSvg( entry );
00173 
00174   mEntryLookup.insert( file, entry );
00175 
00176   //insert to most recent place in entry list
00177   if ( !mMostRecentEntry ) //inserting first entry
00178   {
00179     mLeastRecentEntry = entry;
00180     mMostRecentEntry = entry;
00181     entry->previousEntry = 0;
00182     entry->nextEntry = 0;
00183   }
00184   else
00185   {
00186     entry->previousEntry = mMostRecentEntry;
00187     entry->nextEntry = 0;
00188     mMostRecentEntry->nextEntry = entry;
00189     mMostRecentEntry = entry;
00190   }
00191 
00192   trimToMaximumSize();
00193   return entry;
00194 }
00195 
00196 void QgsSvgCache::containsParams( const QString& path, bool& hasFillParam, QColor& defaultFillColor, bool& hasOutlineParam, QColor& defaultOutlineColor,
00197                                   bool& hasOutlineWidthParam, double& defaultOutlineWidth ) const
00198 {
00199   defaultFillColor = QColor( Qt::black );
00200   defaultOutlineColor = QColor( Qt::black );
00201   defaultOutlineWidth = 1.0;
00202 
00203   QDomDocument svgDoc;
00204   if ( !svgDoc.setContent( getImageData( path ) ) )
00205   {
00206     return;
00207   }
00208 
00209   QDomElement docElem = svgDoc.documentElement();
00210   containsElemParams( docElem, hasFillParam, defaultFillColor, hasOutlineParam, defaultOutlineColor, hasOutlineWidthParam, defaultOutlineWidth );
00211 }
00212 
00213 void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry )
00214 {
00215   if ( !entry )
00216   {
00217     return;
00218   }
00219 
00220   QDomDocument svgDoc;
00221   if ( !svgDoc.setContent( getImageData( entry->file ) ) )
00222   {
00223     return;
00224   }
00225 
00226   //replace fill color, outline color, outline with in all nodes
00227   QDomElement docElem = svgDoc.documentElement();
00228   replaceElemParams( docElem, entry->fill, entry->outline, entry->outlineWidth );
00229 
00230   entry->svgContent = svgDoc.toByteArray();
00231   mTotalSize += entry->svgContent.size();
00232 }
00233 
00234 QByteArray QgsSvgCache::getImageData( const QString &path ) const
00235 {
00236   // is it a path to local file?
00237   QFile svgFile( path );
00238   if ( svgFile.exists() )
00239   {
00240     if ( svgFile.open( QIODevice::ReadOnly ) )
00241     {
00242       return svgFile.readAll();
00243     }
00244     else
00245     {
00246       return QByteArray();
00247     }
00248   }
00249 
00250   // maybe it's a url...
00251   if ( !path.contains( "://" ) ) // otherwise short, relative SVG paths might be considered URLs
00252   {
00253     return QByteArray();
00254   }
00255 
00256   QUrl svgUrl( path );
00257   if ( !svgUrl.isValid() )
00258   {
00259     return QByteArray();
00260   }
00261 
00262   // check whether it's a url pointing to a local file
00263   if ( svgUrl.scheme().compare( "file", Qt::CaseInsensitive ) == 0 )
00264   {
00265     svgFile.setFileName( svgUrl.toLocalFile() );
00266     if ( svgFile.exists() )
00267     {
00268       if ( svgFile.open( QIODevice::ReadOnly ) )
00269       {
00270         return svgFile.readAll();
00271       }
00272     }
00273 
00274     // not found...
00275     return QByteArray();
00276   }
00277 
00278   // the url points to a remote resource, download it!
00279   QNetworkReply *reply = 0;
00280 
00281   // The following code blocks until the file is downloaded...
00282   // TODO: use signals to get reply finished notification, in this moment
00283   // it's executed while rendering.
00284   while ( 1 )
00285   {
00286     QgsDebugMsg( QString( "get svg: %1" ).arg( svgUrl.toString() ) );
00287     QNetworkRequest request( svgUrl );
00288     request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
00289     request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
00290 
00291     reply = QgsNetworkAccessManager::instance()->get( request );
00292     connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( downloadProgress( qint64, qint64 ) ) );
00293 
00294     //emit statusChanged( tr( "Downloading svg." ) );
00295 
00296     // wait until the image download finished
00297     // TODO: connect to the reply->finished() signal
00298     while ( !reply->isFinished() )
00299     {
00300       QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents, 500 );
00301     }
00302 
00303     if ( reply->error() != QNetworkReply::NoError )
00304     {
00305       QgsMessageLog::logMessage( tr( "SVG request failed [error: %1 - url: %2]" ).arg( reply->errorString() ).arg( reply->url().toString() ), tr( "SVG" ) );
00306 
00307       reply->deleteLater();
00308       return QByteArray();
00309     }
00310 
00311     QVariant redirect = reply->attribute( QNetworkRequest::RedirectionTargetAttribute );
00312     if ( redirect.isNull() )
00313     {
00314       // neither network error nor redirection
00315       // TODO: cache the image
00316       break;
00317     }
00318 
00319     // do a new request to the redirect url
00320     svgUrl = redirect.toUrl();
00321     reply->deleteLater();
00322   }
00323 
00324   QVariant status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute );
00325   if ( !status.isNull() && status.toInt() >= 400 )
00326   {
00327     QVariant phrase = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute );
00328     QgsMessageLog::logMessage( tr( "SVG request error [status: %1 - reason phrase: %2]" ).arg( status.toInt() ).arg( phrase.toString() ), tr( "SVG" ) );
00329 
00330     reply->deleteLater();
00331     return QByteArray();
00332   }
00333 
00334   QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
00335   QgsDebugMsg( "contentType: " + contentType );
00336   if ( !contentType.startsWith( "image/svg+xml", Qt::CaseInsensitive ) )
00337   {
00338     reply->deleteLater();
00339     return QByteArray();
00340   }
00341 
00342   // read the image data
00343   QByteArray ba = reply->readAll();
00344   reply->deleteLater();
00345 
00346   return ba;
00347 }
00348 
00349 void QgsSvgCache::cacheImage( QgsSvgCacheEntry* entry )
00350 {
00351   if ( !entry )
00352   {
00353     return;
00354   }
00355 
00356   delete entry->image;
00357   entry->image = 0;
00358 
00359   QSvgRenderer r( entry->svgContent );
00360   double hwRatio = 1.0;
00361   if ( r.viewBoxF().width() > 0 )
00362   {
00363     hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
00364   }
00365   double wSize = entry->size;
00366   int wImgSize = ( int )wSize;
00367   if ( wImgSize < 1 )
00368   {
00369     wImgSize = 1;
00370   }
00371   double hSize = wSize * hwRatio;
00372   int hImgSize = ( int )hSize;
00373   if ( hImgSize < 1 )
00374   {
00375     hImgSize = 1;
00376   }
00377   // cast double image sizes to int for QImage
00378   QImage* image = new QImage( wImgSize, hImgSize, QImage::Format_ARGB32_Premultiplied );
00379   image->fill( 0 ); // transparent background
00380 
00381   QPainter p( image );
00382   if ( r.viewBoxF().width() == r.viewBoxF().height() )
00383   {
00384     r.render( &p );
00385   }
00386   else
00387   {
00388     QSizeF s( r.viewBoxF().size() );
00389     s.scale( wSize, hSize, Qt::KeepAspectRatio );
00390     QRectF rect(( wImgSize - s.width() ) / 2, ( hImgSize - s.height() ) / 2, s.width(), s.height() );
00391     r.render( &p, rect );
00392   }
00393 
00394   entry->image = image;
00395   mTotalSize += ( image->width() * image->height() * 32 );
00396 }
00397 
00398 void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry )
00399 {
00400   if ( !entry )
00401   {
00402     return;
00403   }
00404 
00405   delete entry->picture;
00406   entry->picture = 0;
00407 
00408   //correct QPictures dpi correction
00409   QPicture* picture = new QPicture();
00410   QRectF rect;
00411   QSvgRenderer r( entry->svgContent );
00412   double hwRatio = 1.0;
00413   if ( r.viewBoxF().width() > 0 )
00414   {
00415     hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
00416   }
00417   bool drawOnScreen = qgsDoubleNear( entry->rasterScaleFactor, 1.0, 0.1 );
00418   if ( drawOnScreen )
00419   {
00420     // fix to ensure rotated symbols scale with composer page (i.e. not map item) zoom
00421     double wSize = entry->size;
00422     double hSize = wSize * hwRatio;
00423     QSizeF s( r.viewBoxF().size() );
00424     s.scale( wSize, hSize, Qt::KeepAspectRatio );
00425     rect = QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
00426   }
00427   else
00428   {
00429     // output for print or image saving @ specific dpi
00430     double scaledSize = entry->size / 25.4 / ( entry->rasterScaleFactor * entry->widthScaleFactor );
00431     double wSize = scaledSize * picture->logicalDpiX();
00432     double hSize = scaledSize * picture->logicalDpiY() * r.viewBoxF().height() / r.viewBoxF().width();
00433     rect = QRectF( QPointF( -wSize / 2.0, -hSize / 2.0 ), QSizeF( wSize, hSize ) );
00434   }
00435 
00436   QPainter p( picture );
00437   r.render( &p, rect );
00438   entry->picture = picture;
00439   mTotalSize += entry->picture->size();
00440 }
00441 
00442 QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
00443     double widthScaleFactor, double rasterScaleFactor )
00444 {
00445   //search entries in mEntryLookup
00446   QgsSvgCacheEntry* currentEntry = 0;
00447   QList<QgsSvgCacheEntry*> entries = mEntryLookup.values( file );
00448 
00449   QList<QgsSvgCacheEntry*>::iterator entryIt = entries.begin();
00450   for ( ; entryIt != entries.end(); ++entryIt )
00451   {
00452     QgsSvgCacheEntry* cacheEntry = *entryIt;
00453     if ( cacheEntry->file == file && qgsDoubleNear( cacheEntry->size, size ) && cacheEntry->fill == fill && cacheEntry->outline == outline &&
00454          cacheEntry->outlineWidth == outlineWidth && cacheEntry->widthScaleFactor == widthScaleFactor && cacheEntry->rasterScaleFactor == rasterScaleFactor )
00455     {
00456       currentEntry = cacheEntry;
00457       break;
00458     }
00459   }
00460 
00461   //if not found: create new entry
00462   //cache and replace params in svg content
00463   if ( !currentEntry )
00464   {
00465     currentEntry = insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );
00466   }
00467   else
00468   {
00469     takeEntryFromList( currentEntry );
00470     if ( !mMostRecentEntry ) //list is empty
00471     {
00472       mMostRecentEntry = currentEntry;
00473       mLeastRecentEntry = currentEntry;
00474     }
00475     else
00476     {
00477       mMostRecentEntry->nextEntry = currentEntry;
00478       currentEntry->previousEntry = mMostRecentEntry;
00479       currentEntry->nextEntry = 0;
00480       mMostRecentEntry = currentEntry;
00481     }
00482   }
00483 
00484   //debugging
00485   //printEntryList();
00486 
00487   return currentEntry;
00488 }
00489 
00490 void QgsSvgCache::replaceElemParams( QDomElement& elem, const QColor& fill, const QColor& outline, double outlineWidth )
00491 {
00492   if ( elem.isNull() )
00493   {
00494     return;
00495   }
00496 
00497   //go through attributes
00498   QDomNamedNodeMap attributes = elem.attributes();
00499   int nAttributes = attributes.count();
00500   for ( int i = 0; i < nAttributes; ++i )
00501   {
00502     QDomAttr attribute = attributes.item( i ).toAttr();
00503     //e.g. style="fill:param(fill);param(stroke)"
00504     if ( attribute.name().compare( "style", Qt::CaseInsensitive ) == 0 )
00505     {
00506       //entries separated by ';'
00507       QString newAttributeString;
00508 
00509       QStringList entryList = attribute.value().split( ';' );
00510       QStringList::const_iterator entryIt = entryList.constBegin();
00511       for ( ; entryIt != entryList.constEnd(); ++entryIt )
00512       {
00513         QStringList keyValueSplit = entryIt->split( ':' );
00514         if ( keyValueSplit.size() < 2 )
00515         {
00516           continue;
00517         }
00518         QString key = keyValueSplit.at( 0 );
00519         QString value = keyValueSplit.at( 1 );
00520         if ( value.startsWith( "param(fill" ) )
00521         {
00522           value = fill.name();
00523         }
00524         else if ( value.startsWith( "param(outline)" ) )
00525         {
00526           value = outline.name();
00527         }
00528         else if ( value.startsWith( "param(outline-width)" ) )
00529         {
00530           value = QString::number( outlineWidth );
00531         }
00532 
00533         if ( entryIt != entryList.constBegin() )
00534         {
00535           newAttributeString.append( ";" );
00536         }
00537         newAttributeString.append( key + ":" + value );
00538       }
00539       elem.setAttribute( attribute.name(), newAttributeString );
00540     }
00541     else
00542     {
00543       QString value = attribute.value();
00544       if ( value.startsWith( "param(fill)" ) )
00545       {
00546         elem.setAttribute( attribute.name(), fill.name() );
00547       }
00548       else if ( value.startsWith( "param(outline)" ) )
00549       {
00550         elem.setAttribute( attribute.name(), outline.name() );
00551       }
00552       else if ( value.startsWith( "param(outline-width)" ) )
00553       {
00554         elem.setAttribute( attribute.name(), QString::number( outlineWidth ) );
00555       }
00556     }
00557   }
00558 
00559   QDomNodeList childList = elem.childNodes();
00560   int nChildren = childList.count();
00561   for ( int i = 0; i < nChildren; ++i )
00562   {
00563     QDomElement childElem = childList.at( i ).toElement();
00564     replaceElemParams( childElem, fill, outline, outlineWidth );
00565   }
00566 }
00567 
00568 void QgsSvgCache::containsElemParams( const QDomElement& elem, bool& hasFillParam, QColor& defaultFill, bool& hasOutlineParam, QColor& defaultOutline,
00569                                       bool& hasOutlineWidthParam, double& defaultOutlineWidth ) const
00570 {
00571   if ( elem.isNull() )
00572   {
00573     return;
00574   }
00575 
00576   //we already have all the information, no need to go deeper
00577   if ( hasFillParam && hasOutlineParam && hasOutlineWidthParam )
00578   {
00579     return;
00580   }
00581 
00582   //check this elements attribute
00583   QDomNamedNodeMap attributes = elem.attributes();
00584   int nAttributes = attributes.count();
00585 
00586   QStringList valueSplit;
00587   for ( int i = 0; i < nAttributes; ++i )
00588   {
00589     QDomAttr attribute = attributes.item( i ).toAttr();
00590     if ( attribute.name().compare( "style", Qt::CaseInsensitive ) == 0 )
00591     {
00592       //entries separated by ';'
00593       QStringList entryList = attribute.value().split( ';' );
00594       QStringList::const_iterator entryIt = entryList.constBegin();
00595       for ( ; entryIt != entryList.constEnd(); ++entryIt )
00596       {
00597         QStringList keyValueSplit = entryIt->split( ':' );
00598         if ( keyValueSplit.size() < 2 )
00599         {
00600           continue;
00601         }
00602         QString key = keyValueSplit.at( 0 );
00603         QString value = keyValueSplit.at( 1 );
00604         valueSplit = value.split( " " );
00605         if ( !hasFillParam && value.startsWith( "param(fill)" ) )
00606         {
00607           hasFillParam = true;
00608           if ( valueSplit.size() > 1 )
00609           {
00610             defaultFill = QColor( valueSplit.at( 1 ) );
00611           }
00612         }
00613         else if ( !hasOutlineParam && value.startsWith( "param(outline)" ) )
00614         {
00615           hasOutlineParam = true;
00616           if ( valueSplit.size() > 1 )
00617           {
00618             defaultOutline = QColor( valueSplit.at( 1 ) );
00619           }
00620         }
00621         else if ( !hasOutlineWidthParam && value.startsWith( "param(outline-width)" ) )
00622         {
00623           hasOutlineWidthParam = true;
00624           if ( valueSplit.size() > 1 )
00625           {
00626             defaultOutlineWidth = valueSplit.at( 1 ).toDouble();
00627           }
00628         }
00629       }
00630     }
00631     else
00632     {
00633       QString value = attribute.value();
00634       valueSplit = value.split( " " );
00635       if ( !hasFillParam && value.startsWith( "param(fill)" ) )
00636       {
00637         hasFillParam = true;
00638         if ( valueSplit.size() > 1 )
00639         {
00640           defaultFill = QColor( valueSplit.at( 1 ) );
00641         }
00642       }
00643       else if ( !hasOutlineParam && value.startsWith( "param(outline)" ) )
00644       {
00645         hasOutlineParam = true;
00646         if ( valueSplit.size() > 1 )
00647         {
00648           defaultOutline = QColor( valueSplit.at( 1 ) );
00649         }
00650       }
00651       else if ( !hasOutlineWidthParam && value.startsWith( "param(outline-width)" ) )
00652       {
00653         hasOutlineWidthParam = true;
00654         if ( valueSplit.size() > 1 )
00655         {
00656           defaultOutlineWidth = valueSplit.at( 1 ).toDouble();
00657         }
00658       }
00659     }
00660   }
00661 
00662   //pass it further to child items
00663   QDomNodeList childList = elem.childNodes();
00664   int nChildren = childList.count();
00665   for ( int i = 0; i < nChildren; ++i )
00666   {
00667     QDomElement childElem = childList.at( i ).toElement();
00668     containsElemParams( childElem, hasFillParam, defaultFill, hasOutlineParam, defaultOutline, hasOutlineWidthParam, defaultOutlineWidth );
00669   }
00670 }
00671 
00672 void QgsSvgCache::removeCacheEntry( QString s, QgsSvgCacheEntry* entry )
00673 {
00674   delete entry;
00675   mEntryLookup.remove( s , entry );
00676 }
00677 
00678 void QgsSvgCache::printEntryList()
00679 {
00680   QgsDebugMsg( "****************svg cache entry list*************************" );
00681   QgsDebugMsg( "Cache size: " + QString::number( mTotalSize ) );
00682   QgsSvgCacheEntry* entry = mLeastRecentEntry;
00683   while ( entry )
00684   {
00685     QgsDebugMsg( "***Entry:" );
00686     QgsDebugMsg( "File:" + entry->file );
00687     QgsDebugMsg( "Size:" + QString::number( entry->size ) );
00688     QgsDebugMsg( "Width scale factor" + QString::number( entry->widthScaleFactor ) );
00689     QgsDebugMsg( "Raster scale factor" + QString::number( entry->rasterScaleFactor ) );
00690     entry = entry->nextEntry;
00691   }
00692 }
00693 
00694 void QgsSvgCache::trimToMaximumSize()
00695 {
00696   QgsSvgCacheEntry* entry = mLeastRecentEntry;
00697   while ( entry && ( mTotalSize > mMaximumSize ) )
00698   {
00699     QgsSvgCacheEntry* bkEntry = entry;
00700     entry = entry->nextEntry;
00701 
00702     takeEntryFromList( bkEntry );
00703     mEntryLookup.remove( bkEntry->file, bkEntry );
00704     mTotalSize -= bkEntry->dataSize();
00705     delete bkEntry;
00706   }
00707 }
00708 
00709 void QgsSvgCache::takeEntryFromList( QgsSvgCacheEntry* entry )
00710 {
00711   if ( !entry )
00712   {
00713     return;
00714   }
00715 
00716   if ( entry->previousEntry )
00717   {
00718     entry->previousEntry->nextEntry = entry->nextEntry;
00719   }
00720   else
00721   {
00722     mLeastRecentEntry = entry->nextEntry;
00723   }
00724   if ( entry->nextEntry )
00725   {
00726     entry->nextEntry->previousEntry = entry->previousEntry;
00727   }
00728   else
00729   {
00730     mMostRecentEntry = entry->previousEntry;
00731   }
00732 }
00733 
00734 void QgsSvgCache::downloadProgress( qint64 bytesReceived, qint64 bytesTotal )
00735 {
00736   QString msg = tr( "%1 of %2 bytes of svg image downloaded." ).arg( bytesReceived ).arg( bytesTotal < 0 ? QString( "unknown number of" ) : QString::number( bytesTotal ) );
00737   QgsDebugMsg( msg );
00738   emit statusChanged( msg );
00739 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines