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 defaultFillColor =
QColor( Qt::black );
231 defaultOutlineColor =
QColor( Qt::black );
232 defaultOutlineWidth = 1.0;
241 containsElemParams( docElem, hasFillParam, defaultFillColor, hasOutlineParam, defaultOutlineColor, hasOutlineWidthParam, defaultOutlineWidth );
268 QFile svgFile( path );
271 if ( svgFile.
open( QIODevice::ReadOnly ) )
294 if ( svgUrl.
scheme().
compare(
"file", Qt::CaseInsensitive ) == 0 )
299 if ( svgFile.
open( QIODevice::ReadOnly ) )
319 request.
setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
320 request.
setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
323 connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ),
this, SLOT( downloadProgress( qint64, qint64 ) ) );
334 if ( reply->
error() != QNetworkReply::NoError )
342 QVariant redirect = reply->
attribute( QNetworkRequest::RedirectionTargetAttribute );
351 svgUrl = redirect.
toUrl();
358 QVariant phrase = reply->
attribute( QNetworkRequest::HttpReasonPhraseAttribute );
367 if ( !contentType.
startsWith(
"image/svg+xml", Qt::CaseInsensitive ) )
391 double hwRatio = 1.0;
396 double wSize = entry->
size;
397 int wImgSize = ( int )wSize;
402 double hSize = wSize * hwRatio;
403 int hImgSize = ( int )hSize;
409 QImage* image =
new QImage( wImgSize, hImgSize, QImage::Format_ARGB32_Premultiplied );
420 s.
scale( wSize, hSize, Qt::KeepAspectRatio );
421 QRectF rect(( wImgSize - s.width() ) / 2, ( hImgSize - s.height() ) / 2, s.width(), s.height() );
425 entry->
image = image;
426 mTotalSize += ( image->
width() * image->
height() * 32 );
431 Q_UNUSED( forceVectorOutput );
444 double hwRatio = 1.0;
450 double wSize = entry->
size;
451 double hSize = wSize * hwRatio;
453 s.
scale( wSize, hSize, Qt::KeepAspectRatio );
454 rect =
QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
463 double widthScaleFactor,
double rasterScaleFactor )
470 for ( ; entryIt != entries.
end(); ++entryIt )
485 currentEntry =
insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );
490 if ( !mMostRecentEntry )
492 mMostRecentEntry = currentEntry;
493 mLeastRecentEntry = currentEntry;
497 mMostRecentEntry->
nextEntry = currentEntry;
500 mMostRecentEntry = currentEntry;
510 void QgsSvgCache::replaceElemParams(
QDomElement& elem,
const QColor& fill,
const QColor& outline,
double outlineWidth )
519 int nAttributes = attributes.
count();
520 for (
int i = 0; i < nAttributes; ++i )
524 if ( attribute.
name().
compare(
"style", Qt::CaseInsensitive ) == 0 )
531 for ( ; entryIt != entryList.
constEnd(); ++entryIt )
534 if ( keyValueSplit.
size() < 2 )
544 else if ( value.
startsWith(
"param(outline)" ) )
546 value = outline.
name();
548 else if ( value.
startsWith(
"param(outline-width)" ) )
555 newAttributeString.
append(
";" );
557 newAttributeString.
append( key +
":" + value );
568 else if ( value.
startsWith(
"param(outline)" ) )
572 else if ( value.
startsWith(
"param(outline-width)" ) )
580 int nChildren = childList.
count();
581 for (
int i = 0; i < nChildren; ++i )
584 replaceElemParams( childElem, fill, outline, outlineWidth );
588 void QgsSvgCache::containsElemParams(
const QDomElement& elem,
bool& hasFillParam,
QColor& defaultFill,
bool& hasOutlineParam,
QColor& defaultOutline,
589 bool& hasOutlineWidthParam,
double& defaultOutlineWidth )
const
597 if ( hasFillParam && hasOutlineParam && hasOutlineWidthParam )
604 int nAttributes = attributes.
count();
607 for (
int i = 0; i < nAttributes; ++i )
610 if ( attribute.
name().
compare(
"style", Qt::CaseInsensitive ) == 0 )
615 for ( ; entryIt != entryList.
constEnd(); ++entryIt )
618 if ( keyValueSplit.
size() < 2 )
624 valueSplit = value.
split(
" " );
625 if ( !hasFillParam && value.
startsWith(
"param(fill)" ) )
628 if ( valueSplit.
size() > 1 )
630 defaultFill =
QColor( valueSplit.
at( 1 ) );
633 else if ( !hasOutlineParam && value.
startsWith(
"param(outline)" ) )
635 hasOutlineParam =
true;
636 if ( valueSplit.
size() > 1 )
638 defaultOutline =
QColor( valueSplit.
at( 1 ) );
641 else if ( !hasOutlineWidthParam && value.
startsWith(
"param(outline-width)" ) )
643 hasOutlineWidthParam =
true;
644 if ( valueSplit.
size() > 1 )
646 defaultOutlineWidth = valueSplit.
at( 1 ).toDouble();
654 valueSplit = value.
split(
" " );
655 if ( !hasFillParam && value.
startsWith(
"param(fill)" ) )
658 if ( valueSplit.
size() > 1 )
660 defaultFill =
QColor( valueSplit.
at( 1 ) );
663 else if ( !hasOutlineParam && value.
startsWith(
"param(outline)" ) )
665 hasOutlineParam =
true;
666 if ( valueSplit.
size() > 1 )
668 defaultOutline =
QColor( valueSplit.
at( 1 ) );
671 else if ( !hasOutlineWidthParam && value.
startsWith(
"param(outline-width)" ) )
673 hasOutlineWidthParam =
true;
674 if ( valueSplit.
size() > 1 )
676 defaultOutlineWidth = valueSplit.
at( 1 ).toDouble();
684 int nChildren = childList.
count();
685 for (
int i = 0; i < nChildren; ++i )
688 containsElemParams( childElem, hasFillParam, defaultFill, hasOutlineParam, defaultOutline, hasOutlineWidthParam, defaultOutlineWidth );
695 mEntryLookup.
remove( s, entry );
698 void QgsSvgCache::printEntryList()
700 QgsDebugMsg(
"****************svg cache entry list*************************" );
717 if ( mLeastRecentEntry == mMostRecentEntry )
722 while ( entry && ( mTotalSize > mMaximumSize ) )
759 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 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)
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
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)
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
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
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