25 #include <QApplication>
26 #include <QCoreApplication>
28 #include <QDomDocument>
29 #include <QDomElement>
34 #include <QSvgRenderer>
36 #include <QNetworkReply>
37 #include <QNetworkRequest>
43 , widthScaleFactor( 1.0 )
44 , rasterScaleFactor( 1.0 )
46 , outline(
Qt::black )
56 , lookupKey( lk.isEmpty() ? f : lk )
59 , widthScaleFactor( wsf )
60 , rasterScaleFactor( rsf )
106 , mLeastRecentEntry( 0 )
107 , mMostRecentEntry( 0 )
109 mMissingSvg =
QString(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).
toAscii();
115 for ( ; it != mEntryLookup.end(); ++it )
123 double widthScaleFactor,
double rasterScaleFactor,
bool& fitsInCache )
133 if ( !currentEntry->
image )
136 double hwRatio = 1.0;
141 long cachedDataSize = 0;
143 cachedDataSize += ( int )( currentEntry->
size * currentEntry->
size * hwRatio * 32 );
144 if ( cachedDataSize > mMaximumSize / 2 )
147 delete currentEntry->
image;
148 currentEntry->
image = 0;
164 return *( currentEntry->
image );
168 double widthScaleFactor,
double rasterScaleFactor,
bool forceVectorOutput )
182 return *( currentEntry->
picture );
186 double widthScaleFactor,
double rasterScaleFactor )
196 double widthScaleFactor,
double rasterScaleFactor )
205 mEntryLookup.
insert( file, entry );
208 if ( !mMostRecentEntry )
210 mLeastRecentEntry = entry;
211 mMostRecentEntry = entry;
220 mMostRecentEntry = entry;
228 bool& hasOutlineWidthParam,
double& defaultOutlineWidth )
const
230 bool hasDefaultFillColor =
false;
231 bool hasDefaultOutlineColor =
false;
232 bool hasDefaultOutlineWidth =
false;
234 containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
235 hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
236 hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth );
240 bool& hasFillParam,
bool& hasDefaultFillParam,
QColor& defaultFillColor,
241 bool& hasOutlineParam,
bool& hasDefaultOutlineColor,
QColor& defaultOutlineColor,
242 bool& hasOutlineWidthParam,
bool& hasDefaultOutlineWidth,
double& defaultOutlineWidth )
const
244 hasFillParam =
false;
245 hasOutlineParam =
false;
246 hasOutlineWidthParam =
false;
247 defaultFillColor =
QColor( Qt::white );
248 defaultOutlineColor =
QColor( Qt::black );
249 defaultOutlineWidth = 0.2;
251 hasDefaultFillParam =
false;
252 hasDefaultOutlineColor =
false;
253 hasDefaultOutlineWidth =
false;
262 containsElemParams( docElem, hasFillParam, hasDefaultFillParam, defaultFillColor,
263 hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
264 hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth );
283 double sizeScaleFactor = calcSizeScaleFactor( entry, docElem );
295 if ( !entry || entry->
size == 0 )
300 if ( docElem.
tagName() ==
"svg" )
319 if ( parts.
count() != 4 )
322 bool widthOk =
false;
323 double width = parts.
at( 2 ).toDouble( &widthOk );
326 return width / entry->
size ;
335 QFile svgFile( path );
338 if ( svgFile.
open( QIODevice::ReadOnly ) )
361 if ( svgUrl.
scheme().
compare(
"file", Qt::CaseInsensitive ) == 0 )
366 if ( svgFile.
open( QIODevice::ReadOnly ) )
386 request.
setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
387 request.
setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
390 connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ),
this, SLOT( downloadProgress( qint64, qint64 ) ) );
401 if ( reply->
error() != QNetworkReply::NoError )
409 QVariant redirect = reply->
attribute( QNetworkRequest::RedirectionTargetAttribute );
418 svgUrl = redirect.
toUrl();
425 QVariant phrase = reply->
attribute( QNetworkRequest::HttpReasonPhraseAttribute );
434 if ( !contentType.
startsWith(
"image/svg+xml", Qt::CaseInsensitive ) )
458 double hwRatio = 1.0;
463 double wSize = entry->
size;
464 int wImgSize = ( int )wSize;
469 double hSize = wSize * hwRatio;
470 int hImgSize = ( int )hSize;
476 QImage* image =
new QImage( wImgSize, hImgSize, QImage::Format_ARGB32_Premultiplied );
487 s.
scale( wSize, hSize, Qt::KeepAspectRatio );
488 QRectF rect(( wImgSize - s.width() ) / 2, ( hImgSize - s.height() ) / 2, s.width(), s.height() );
492 entry->
image = image;
493 mTotalSize += ( image->
width() * image->
height() * 32 );
498 Q_UNUSED( forceVectorOutput );
511 double hwRatio = 1.0;
517 double wSize = entry->
size;
518 double hSize = wSize * hwRatio;
520 s.
scale( wSize, hSize, Qt::KeepAspectRatio );
521 rect =
QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
530 double widthScaleFactor,
double rasterScaleFactor )
537 for ( ; entryIt != entries.
end(); ++entryIt )
552 currentEntry =
insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );
557 if ( !mMostRecentEntry )
559 mMostRecentEntry = currentEntry;
560 mLeastRecentEntry = currentEntry;
564 mMostRecentEntry->
nextEntry = currentEntry;
567 mMostRecentEntry = currentEntry;
577 void QgsSvgCache::replaceElemParams(
QDomElement& elem,
const QColor& fill,
const QColor& outline,
double outlineWidth )
586 int nAttributes = attributes.
count();
587 for (
int i = 0; i < nAttributes; ++i )
591 if ( attribute.
name().
compare(
"style", Qt::CaseInsensitive ) == 0 )
598 for ( ; entryIt != entryList.
constEnd(); ++entryIt )
601 if ( keyValueSplit.
size() < 2 )
611 else if ( value.
startsWith(
"param(outline)" ) )
613 value = outline.
name();
615 else if ( value.
startsWith(
"param(outline-width)" ) )
622 newAttributeString.
append(
";" );
624 newAttributeString.
append( key +
":" + value );
635 else if ( value.
startsWith(
"param(outline)" ) )
639 else if ( value.
startsWith(
"param(outline-width)" ) )
647 int nChildren = childList.
count();
648 for (
int i = 0; i < nChildren; ++i )
651 replaceElemParams( childElem, fill, outline, outlineWidth );
655 void QgsSvgCache::containsElemParams(
const QDomElement& elem,
bool& hasFillParam,
bool& hasDefaultFill,
QColor& defaultFill,
bool& hasOutlineParam,
bool& hasDefaultOutline,
QColor& defaultOutline,
656 bool& hasOutlineWidthParam,
bool& hasDefaultOutlineWidth,
double& defaultOutlineWidth )
const
664 if ( hasFillParam && hasOutlineParam && hasOutlineWidthParam )
671 int nAttributes = attributes.
count();
674 for (
int i = 0; i < nAttributes; ++i )
677 if ( attribute.
name().
compare(
"style", Qt::CaseInsensitive ) == 0 )
682 for ( ; entryIt != entryList.
constEnd(); ++entryIt )
685 if ( keyValueSplit.
size() < 2 )
691 valueSplit = value.
split(
" " );
692 if ( !hasFillParam && value.
startsWith(
"param(fill)" ) )
695 if ( valueSplit.
size() > 1 )
697 defaultFill =
QColor( valueSplit.
at( 1 ) );
698 hasDefaultFill =
true;
701 else if ( !hasOutlineParam && value.
startsWith(
"param(outline)" ) )
703 hasOutlineParam =
true;
704 if ( valueSplit.
size() > 1 )
706 defaultOutline =
QColor( valueSplit.
at( 1 ) );
707 hasDefaultOutline =
true;
710 else if ( !hasOutlineWidthParam && value.
startsWith(
"param(outline-width)" ) )
712 hasOutlineWidthParam =
true;
713 if ( valueSplit.
size() > 1 )
715 defaultOutlineWidth = valueSplit.
at( 1 ).toDouble();
716 hasDefaultOutlineWidth =
true;
724 valueSplit = value.
split(
" " );
725 if ( !hasFillParam && value.
startsWith(
"param(fill)" ) )
728 if ( valueSplit.
size() > 1 )
730 defaultFill =
QColor( valueSplit.
at( 1 ) );
731 hasDefaultFill =
true;
734 else if ( !hasOutlineParam && value.
startsWith(
"param(outline)" ) )
736 hasOutlineParam =
true;
737 if ( valueSplit.
size() > 1 )
739 defaultOutline =
QColor( valueSplit.
at( 1 ) );
740 hasDefaultOutline =
true;
743 else if ( !hasOutlineWidthParam && value.
startsWith(
"param(outline-width)" ) )
745 hasOutlineWidthParam =
true;
746 if ( valueSplit.
size() > 1 )
748 defaultOutlineWidth = valueSplit.
at( 1 ).toDouble();
749 hasDefaultOutlineWidth =
true;
757 int nChildren = childList.
count();
758 for (
int i = 0; i < nChildren; ++i )
761 containsElemParams( childElem, hasFillParam, hasDefaultFill, defaultFill,
762 hasOutlineParam, hasDefaultOutline, defaultOutline,
763 hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth );
770 mEntryLookup.
remove( s, entry );
773 void QgsSvgCache::printEntryList()
775 QgsDebugMsg(
"****************svg cache entry list*************************" );
792 if ( mLeastRecentEntry == mMostRecentEntry )
797 while ( entry && ( mTotalSize > mMaximumSize ) )
834 void QgsSvgCache::downloadProgress( qint64 bytesReceived, qint64 bytesTotal )
QgsSvgCacheEntry * previousEntry
QString & append(QChar ch)
int dataSize() const
Return memory usage in bytes.
void scale(qreal width, qreal height, Qt::AspectRatioMode mode)
void render(QPainter *painter)
const QPicture & svgAsPicture(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool forceVectorOutput=false)
Get SVG as QPicture&.
QString attribute(const QString &name, const QString &defValue) const
QString errorString() const
QgsSvgCacheEntry * cacheEntry(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Returns entry from cache or creates a new entry if it does not exist already.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
const T & at(int i) const
A cache for images / pictures derived from svg files.
void setFileName(const QString &name)
QDomElement documentElement() const
QDomNodeList childNodes() const
QString toString(QFlags< QUrl::FormattingOption > options) const
QString tr(const char *sourceText, const char *disambiguation, int n)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasOutlineParam, QColor &defaultOutlineColor, bool &hasOutlineWidthParam, double &defaultOutlineWidth) const
Tests if an svg file contains parameters for fill, outline color, outline width.
static QgsSvgCache * instance()
QDomElement toElement() const
const QImage & svgAsImage(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool &fitsInCache)
Get SVG as QImage.
QString number(int n, int base)
int count(const T &value) const
void processEvents(QFlags< QEventLoop::ProcessEventsFlag > flags)
int toInt(bool *ok) const
void fill(uint pixelValue)
QByteArray getImageData(const QString &path) const
Get image data.
void setAttribute(const QString &name, const QString &value)
int remove(const Key &key)
static QString symbolNameToPath(QString name)
Get symbol's path from its name.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
void statusChanged(const QString &theStatusQString)
Emit a signal to be caught by qgisapp and display a msg on status bar.
const QByteArray & svgContent(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Get SVG content.
void cachePicture(QgsSvgCacheEntry *entry, bool forceVectorOutput=false)
QHash< Key, T >::iterator insert(const Key &key, const T &value)
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QString toLocalFile() const
const T value(const Key &key) const
bool contains(QChar ch, Qt::CaseSensitivity cs) const
void trimToMaximumSize()
Removes the least used items until the maximum size is under the limit.
void takeEntryFromList(QgsSvgCacheEntry *entry)
QString lookupKey
Lookup key used by QgsSvgCache's hashtable (relative or absolute path). Needed for removal from the h...
void cacheImage(QgsSvgCacheEntry *entry)
void replaceParamsAndCacheSvg(QgsSvgCacheEntry *entry)
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
QDomElement firstChildElement(const QString &tagName) const
QVariant attribute(QNetworkRequest::Attribute code) const
void setAttribute(Attribute code, const QVariant &value)
QgsSvgCache(QObject *parent=0)
protected constructor
QgsSvgCacheEntry * insertSVG(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Creates new cache entry and returns pointer to it.
NetworkError error() const
QNetworkReply * get(const QNetworkRequest &request)
const_iterator constEnd() const
const_iterator constBegin() const
QDomNode item(int index) const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int compare(const QString &other) const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString file
Absolute path to SVG file.
QByteArray toAscii() const
QByteArray toByteArray(int indent) const
QDomNode at(int index) const
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
bool operator==(const QgsSvgCacheEntry &other) const
Don't consider image, picture, last used timestamp for comparison.
QgsSvgCacheEntry * nextEntry
QDomNamedNodeMap attributes() const