From 651259a80ce9f822534f05b1a1d54c038cb100a9 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Tue, 21 Jun 2011 15:03:08 +0200 Subject: [PATCH 01/16] Started to implement svg cache --- src/core/CMakeLists.txt | 1 + src/core/symbology-ng/qgssvgcache.cpp | 59 ++++++++++++++++++++++ src/core/symbology-ng/qgssvgcache.h | 73 +++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 src/core/symbology-ng/qgssvgcache.cpp create mode 100644 src/core/symbology-ng/qgssvgcache.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 202222fc94dc..a998e99a6341 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -37,6 +37,7 @@ SET(QGIS_CORE_SRCS symbology-ng/qgsvectorcolorrampv2.cpp symbology-ng/qgsstylev2.cpp symbology-ng/qgssymbologyv2conversion.cpp + symbology-ng/qgssvgcache.cpp qgis.cpp qgsapplication.cpp diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp new file mode 100644 index 000000000000..3abc59f82efe --- /dev/null +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + qgssvgcache.h + ------------------------------ + begin : 2011 + copyright : (C) 2011 by Marco Hugentobler + email : marco dot hugentobler at sourcepole dot ch + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgssvgcache.h" + +QgsSvgCache* QgsSvgCache::mInstance = 0; + +QgsSvgCache* QgsSvgCache::instance() +{ + if ( !mInstance ) + { + mInstance = new QgsSvgCache(); + } + return mInstance; +} + +QgsSvgCache::QgsSvgCache() +{ +} + +QgsSvgCache::~QgsSvgCache() +{ +} + + +const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth ) const +{ +} + +const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth ) const +{ +} + +void QgsSvgCache::insertSVG( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth ) +{ +} + +void QgsSvgCache::cacheImage( QgsSvgCacheEntry ) +{ +} + +void QgsSvgCache::cachePicture( QgsSvgCacheEntry ) +{ +} + diff --git a/src/core/symbology-ng/qgssvgcache.h b/src/core/symbology-ng/qgssvgcache.h new file mode 100644 index 000000000000..431ffd7b4049 --- /dev/null +++ b/src/core/symbology-ng/qgssvgcache.h @@ -0,0 +1,73 @@ +/*************************************************************************** + qgssvgcache.h + ------------------------------ + begin : 2011 + copyright : (C) 2011 by Marco Hugentobler + email : marco dot hugentobler at sourcepole dot ch + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSSVGCACHE_H +#define QGSSVGCACHE_H + +#include +#include +#include +#include +#include + +class QImage; +class QPicture; + +struct QgsSvgCacheEntry +{ + QString file; + double size; + double outlineWidth; + QColor fill; + QColor outline; + QImage* image; + QPicture* picture; + QDateTime lastUsed; +}; + +/**A cache for images / pictures derived from svg files. This class supports parameter replacement in svg files +according to the svg params specification (http://www.w3.org/TR/2009/WD-SVGParamPrimer-20090616/). Supported are +the parameters 'fill-color', 'pen-color', 'outline-width', 'stroke-width'. E.g. mEntries; + /**Entry pointers accessible by file name*/ + QMultiHash< QString, QgsSvgCacheEntry* > mEntryLookup; + /**Estimated total size of all images and pictures*/ + double mTotalSize; +}; + +#endif // QGSSVGCACHE_H From 48aa535a2918ec9bc409e75af904d99414669978 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Thu, 23 Jun 2011 14:22:05 +0200 Subject: [PATCH 02/16] Further work on the svg cache --- src/core/symbology-ng/qgssvgcache.cpp | 115 ++++++++++++++++++++++++-- src/core/symbology-ng/qgssvgcache.h | 29 +++++-- 2 files changed, 133 insertions(+), 11 deletions(-) diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index 3abc59f82efe..cff5b6da0362 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -16,6 +16,41 @@ ***************************************************************************/ #include "qgssvgcache.h" +#include +#include +#include +#include + +QgsSvgCacheEntry::QgsSvgCacheEntry(): file( QString() ), size( 0 ), outlineWidth( 0 ), widthScaleFactor( 1.0 ), rasterScaleFactor( 1.0 ), fill( Qt::black ), +outline( Qt::black ), image( 0 ), picture( 0 ) +{ +} + +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 ), +widthScaleFactor( wsf ), rasterScaleFactor( rsf ), fill( fi ), outline( ou ), image( 0 ), picture( 0 ) +{ +} + + +QgsSvgCacheEntry::~QgsSvgCacheEntry() +{ + delete image; + delete picture; +} + +bool QgsSvgCacheEntry::operator==( const QgsSvgCacheEntry& other ) const +{ + return ( other.file == file && other.size == size && other.outlineWidth == outlineWidth && other.widthScaleFactor == widthScaleFactor + && other.rasterScaleFactor == rasterScaleFactor && other.fill == fill && other.outline == outline ); +} + +QString file; +double size; +double outlineWidth; +double widthScaleFactor; +double rasterScaleFactor; +QColor fill; +QColor outline; QgsSvgCache* QgsSvgCache::mInstance = 0; @@ -37,23 +72,93 @@ QgsSvgCache::~QgsSvgCache() } -const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth ) const +const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, + double widthScaleFactor, double rasterScaleFactor ) +{ + +} + +const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, + double widthScaleFactor, double rasterScaleFactor ) { + //search entries in mEntryLookup + QgsSvgCacheEntry* currentEntry = 0; + QList entries = mEntryLookup.values( file ); + + QList::iterator entryIt = entries.begin(); + for(; entryIt != entries.end(); ++entryIt ) + { + QgsSvgCacheEntry* cacheEntry = *entryIt; + if( cacheEntry->file == file && cacheEntry->size == size && cacheEntry->fill == fill && cacheEntry->outline == outline && + cacheEntry->outlineWidth == outlineWidth && cacheEntry->widthScaleFactor == widthScaleFactor && cacheEntry->rasterScaleFactor == rasterScaleFactor) + { + currentEntry = cacheEntry; + break; + } + } + + + //if not found: create new entry + //cache and replace params in svg content + if( !currentEntry ) + { + currentEntry = insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); + } + + //if current entry image is 0: cache image for entry + //update stats for memory usage + if( !currentEntry->picture ) + { + cachePicture( currentEntry ); + } + + //update lastUsed with current date time + + return *( currentEntry->picture ); } -const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth ) const +QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, + double widthScaleFactor, double rasterScaleFactor ) { + QgsSvgCacheEntry* entry = new QgsSvgCacheEntry( file, size, outlineWidth, widthScaleFactor, rasterScaleFactor, fill, outline ); + entry->lastUsed = QDateTime::currentDateTime(); + + replaceParamsAndCacheSvg( entry ); + + mEntries.insert( entry->lastUsed, entry ); + mEntryLookup.insert( file, entry ); + return entry; } -void QgsSvgCache::insertSVG( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth ) +void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ) { + if( !entry ) + { + return; + } + + QFile svgFile( entry->file ); + if( !svgFile.open( QIODevice::ReadOnly ) ) + { + return; + } + + QDomDocument svgDoc; + if( !svgDoc.setContent( &svgFile ) ) + { + return; + } + + //todo: replace params here + + entry->svgContent = svgDoc.toByteArray(); } -void QgsSvgCache::cacheImage( QgsSvgCacheEntry ) +void QgsSvgCache::cacheImage( QgsSvgCacheEntry* entry ) { } -void QgsSvgCache::cachePicture( QgsSvgCacheEntry ) +void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry ) { } diff --git a/src/core/symbology-ng/qgssvgcache.h b/src/core/symbology-ng/qgssvgcache.h index 431ffd7b4049..cfe18144c584 100644 --- a/src/core/symbology-ng/qgssvgcache.h +++ b/src/core/symbology-ng/qgssvgcache.h @@ -29,14 +29,25 @@ class QPicture; struct QgsSvgCacheEntry { + QgsSvgCacheEntry(); + QgsSvgCacheEntry( const QString& file, double size, double outlineWidth, double widthScaleFactor, double rasterScaleFctor, const QColor& fill, const QColor& outline ); + ~QgsSvgCacheEntry(); + QString file; double size; double outlineWidth; + double widthScaleFactor; + double rasterScaleFactor; QColor fill; QColor outline; QImage* image; QPicture* picture; QDateTime lastUsed; + //content (with params replaced) + QByteArray svgContent; + + /**Don't consider image, picture, last used timestamp for comparison*/ + bool operator==( const QgsSvgCacheEntry& other ) const; }; /**A cache for images / pictures derived from svg files. This class supports parameter replacement in svg files @@ -49,21 +60,27 @@ class QgsSvgCache static QgsSvgCache* instance(); ~QgsSvgCache(); - const QImage& svgAsImage( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth ) const; - const QPicture& svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth ) const; + const QImage& svgAsImage( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, + double widthScaleFactor, double rasterScaleFactor ); + const QPicture& svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, + double widthScaleFactor, double rasterScaleFactor ); protected: QgsSvgCache(); - void insertSVG( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth ); - void cacheImage( QgsSvgCacheEntry ); - void cachePicture( QgsSvgCacheEntry ); + /**Creates new cache entry and returns pointer to it*/ + QgsSvgCacheEntry* insertSVG( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, + double widthScaleFactor, double rasterScaleFactor ); + + void replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ); + void cacheImage( QgsSvgCacheEntry* entry ); + void cachePicture( QgsSvgCacheEntry* entry ); private: static QgsSvgCache* mInstance; /**Entries sorted by last used time*/ - QMap< QDateTime, QgsSvgCacheEntry > mEntries; + QMap< QDateTime, QgsSvgCacheEntry* > mEntries; /**Entry pointers accessible by file name*/ QMultiHash< QString, QgsSvgCacheEntry* > mEntryLookup; /**Estimated total size of all images and pictures*/ From aa2ad452620426ab8b8441052898c65dfbccdd7c Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Thu, 23 Jun 2011 16:50:42 +0200 Subject: [PATCH 03/16] Add caching, experimental test with QPicture for svg marker --- .../symbology-ng/qgsmarkersymbollayerv2.cpp | 7 +- src/core/symbology-ng/qgssvgcache.cpp | 108 ++++++++++++++---- src/core/symbology-ng/qgssvgcache.h | 3 + 3 files changed, 94 insertions(+), 24 deletions(-) diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp index 0851edd2e548..3f67b9724207 100644 --- a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp +++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp @@ -6,6 +6,7 @@ #include "qgsapplication.h" #include "qgslogger.h" #include "qgsproject.h" +#include "qgssvgcache.h" #include #include @@ -533,9 +534,13 @@ void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2Re if ( mAngle != 0 ) p->rotate( mAngle ); - QPicture &pct = context.selected() ? mSelPicture : mPicture; + const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( mPath, mSize, QColor( Qt::black )/*const QColor& fill*/, QColor( Qt::black ) /*const QColor& outline*/, + 1.0 /*outline width*/, context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() ); p->drawPicture( 0, 0, pct ); + /*QPicture &pct = context.selected() ? mSelPicture : mPicture; + p->drawPicture( 0, 0, pct );*/ + p->restore(); } diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index cff5b6da0362..e84ce5456378 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include QgsSvgCacheEntry::QgsSvgCacheEntry(): file( QString() ), size( 0 ), outlineWidth( 0 ), widthScaleFactor( 1.0 ), rasterScaleFactor( 1.0 ), fill( Qt::black ), outline( Qt::black ), image( 0 ), picture( 0 ) @@ -69,41 +71,35 @@ QgsSvgCache::QgsSvgCache() QgsSvgCache::~QgsSvgCache() { + QMap< QDateTime, QgsSvgCacheEntry* >::iterator it = mEntries.begin(); + for(; it != mEntries.end(); ++it ) + { + delete it.value(); + } } const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor ) { + QgsSvgCacheEntry* currentEntry = this->cacheEntry( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); + + //if current entry image is 0: cache image for entry + //update stats for memory usage + if( !currentEntry->image ) + { + cacheImage( currentEntry ); + } + //update lastUsed with current date time + + return *( currentEntry->image ); } const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor ) { - //search entries in mEntryLookup - QgsSvgCacheEntry* currentEntry = 0; - QList entries = mEntryLookup.values( file ); - - QList::iterator entryIt = entries.begin(); - for(; entryIt != entries.end(); ++entryIt ) - { - QgsSvgCacheEntry* cacheEntry = *entryIt; - if( cacheEntry->file == file && cacheEntry->size == size && cacheEntry->fill == fill && cacheEntry->outline == outline && - cacheEntry->outlineWidth == outlineWidth && cacheEntry->widthScaleFactor == widthScaleFactor && cacheEntry->rasterScaleFactor == rasterScaleFactor) - { - currentEntry = cacheEntry; - break; - } - } - - - //if not found: create new entry - //cache and replace params in svg content - if( !currentEntry ) - { - currentEntry = insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); - } + QgsSvgCacheEntry* currentEntry = this->cacheEntry( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); //if current entry image is 0: cache image for entry //update stats for memory usage @@ -156,9 +152,75 @@ void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ) void QgsSvgCache::cacheImage( QgsSvgCacheEntry* entry ) { + if( !entry ) + { + return; + } + + delete entry->image; + entry->image = 0; + + double imageSize = entry->size * entry->widthScaleFactor * entry->rasterScaleFactor; + QImage* image = new QImage( imageSize, imageSize, QImage::Format_ARGB32_Premultiplied ); + image->fill( 0 ); // transparent background + + //rasterise byte array to image + QPainter p( image ); + QSvgRenderer r( entry->svgContent ); + r.render( &p ); + + entry->image = image; } void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry ) { + if( !entry ) + { + return; + } + + delete entry->picture; + entry->picture = 0; + + //correct QPictures dpi correction + QPicture* picture = new QPicture(); + double dpi = entry->widthScaleFactor * 25.4 * entry->rasterScaleFactor; + double pictureSize = entry->size * entry->widthScaleFactor / dpi * picture->logicalDpiX(); + QRectF rect( QPointF( -pictureSize / 2.0, -pictureSize / 2.0 ), QSizeF( pictureSize, pictureSize ) ); + + + QSvgRenderer renderer( entry->svgContent ); + QPainter painter( picture ); + renderer.render( &painter, rect ); + entry->picture = picture; +} + +QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, + double widthScaleFactor, double rasterScaleFactor ) +{ + //search entries in mEntryLookup + QgsSvgCacheEntry* currentEntry = 0; + QList entries = mEntryLookup.values( file ); + + QList::iterator entryIt = entries.begin(); + for(; entryIt != entries.end(); ++entryIt ) + { + QgsSvgCacheEntry* cacheEntry = *entryIt; + if( cacheEntry->file == file && cacheEntry->size == size && cacheEntry->fill == fill && cacheEntry->outline == outline && + cacheEntry->outlineWidth == outlineWidth && cacheEntry->widthScaleFactor == widthScaleFactor && cacheEntry->rasterScaleFactor == rasterScaleFactor) + { + currentEntry = cacheEntry; + break; + } + } + + + //if not found: create new entry + //cache and replace params in svg content + if( !currentEntry ) + { + currentEntry = insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); + } + return currentEntry; } diff --git a/src/core/symbology-ng/qgssvgcache.h b/src/core/symbology-ng/qgssvgcache.h index cfe18144c584..669c30a53bab 100644 --- a/src/core/symbology-ng/qgssvgcache.h +++ b/src/core/symbology-ng/qgssvgcache.h @@ -75,6 +75,9 @@ class QgsSvgCache void replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ); void cacheImage( QgsSvgCacheEntry* entry ); void cachePicture( QgsSvgCacheEntry* entry ); + /**Returns entry from cache or creates a new entry if it does not exist already*/ + QgsSvgCacheEntry* cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, + double widthScaleFactor, double rasterScaleFactor ); private: static QgsSvgCache* mInstance; From e1122045d34580b40233a086814b14bd4ece7077 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Sat, 25 Jun 2011 09:43:49 +0200 Subject: [PATCH 04/16] Use QImage for map and QPicture for composer --- .../symbology-ng/qgsmarkersymbollayerv2.cpp | 18 +++++--- src/core/symbology-ng/qgssvgcache.cpp | 43 ++++++++++++++++++- src/core/symbology-ng/qgssvgcache.h | 3 ++ 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp index 3f67b9724207..79c1e570f830 100644 --- a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp +++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp @@ -534,12 +534,18 @@ void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2Re if ( mAngle != 0 ) p->rotate( mAngle ); - const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( mPath, mSize, QColor( Qt::black )/*const QColor& fill*/, QColor( Qt::black ) /*const QColor& outline*/, - 1.0 /*outline width*/, context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() ); - p->drawPicture( 0, 0, pct ); - - /*QPicture &pct = context.selected() ? mSelPicture : mPicture; - p->drawPicture( 0, 0, pct );*/ + if( doubleNear( context.renderContext().rasterScaleFactor(), 1.0 ) ) + { + const QImage& img = QgsSvgCache::instance()->svgAsImage( mPath, mSize, QColor( Qt::black )/*const QColor& fill*/, QColor( Qt::black ) /*const QColor& outline*/, + 1.0 /*outline width*/, context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() ); + p->drawImage( -img.width() / 2.0, -img.width() / 2.0, img ); + } + else + { + const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( mPath, mSize, QColor( Qt::black )/*const QColor& fill*/, QColor( Qt::black ) /*const QColor& outline*/, + 1.0 /*outline width*/, context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() ); + p->drawPicture( 0, 0, pct ); + } p->restore(); } diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index e84ce5456378..8b440f2a4b5e 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -17,6 +17,7 @@ #include "qgssvgcache.h" #include +#include #include #include #include @@ -145,7 +146,9 @@ void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ) return; } - //todo: replace params here + //replace fill color, outline color, outline with in all nodes + QDomElement docElem = svgDoc.documentElement(); + replaceElemParams( docElem, entry->fill, entry->outline, entry->outlineWidth ); entry->svgContent = svgDoc.toByteArray(); } @@ -164,7 +167,6 @@ void QgsSvgCache::cacheImage( QgsSvgCacheEntry* entry ) QImage* image = new QImage( imageSize, imageSize, QImage::Format_ARGB32_Premultiplied ); image->fill( 0 ); // transparent background - //rasterise byte array to image QPainter p( image ); QSvgRenderer r( entry->svgContent ); r.render( &p ); @@ -224,3 +226,40 @@ QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, con return currentEntry; } +void QgsSvgCache::replaceElemParams( QDomElement& elem, const QColor& fill, const QColor& outline, double outlineWidth ) +{ + if( elem.isNull() ) + { + return; + } + + //go through attributes + QDomNamedNodeMap attributes = elem.attributes(); + int nAttributes = attributes.count(); + for( int i = 0; i < nAttributes; ++i ) + { + QDomAttr attribute = attributes.item( i ).toAttr(); + QString value = attribute.value(); + if( value.startsWith("params(fill)") ) + { + elem.setAttribute( attribute.name(), fill.name() ); + } + else if( value.startsWith("params(outline)") ) + { + elem.setAttribute( attribute.name(), outline.name() ); + } + else if( value.startsWith("params(outline-width)") ) + { + elem.setAttribute( attribute.name(), QString::number( outlineWidth ) ); + } + } + + QDomNodeList childList = elem.childNodes(); + int nChildren = childList.count(); + for( int i = 0; i < nChildren; ++i ) + { + QDomElement childElem = childList.at( i ).toElement(); + replaceElemParams( childElem, fill, outline, outlineWidth ); + } +} + diff --git a/src/core/symbology-ng/qgssvgcache.h b/src/core/symbology-ng/qgssvgcache.h index 669c30a53bab..7ec027379b72 100644 --- a/src/core/symbology-ng/qgssvgcache.h +++ b/src/core/symbology-ng/qgssvgcache.h @@ -24,6 +24,7 @@ #include #include +class QDomElement; class QImage; class QPicture; @@ -88,6 +89,8 @@ class QgsSvgCache QMultiHash< QString, QgsSvgCacheEntry* > mEntryLookup; /**Estimated total size of all images and pictures*/ double mTotalSize; + /**Replaces parameters in elements of a dom node and calls method for all child nodes*/ + void replaceElemParams( QDomElement& elem, const QColor& fill, const QColor& outline, double outlineWidth ); }; #endif // QGSSVGCACHE_H From 49d87048c27c1d1b22169d92d5a4b674b62315ee Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Sat, 25 Jun 2011 12:22:37 +0200 Subject: [PATCH 05/16] Change color through svg marker dialog --- .../symbology-ng/qgsmarkersymbollayerv2.cpp | 25 ++++++++-- .../symbology-ng/qgsmarkersymbollayerv2.h | 17 +++++++ src/core/symbology-ng/qgssvgcache.cpp | 50 +++++++++---------- .../symbology-ng/qgssymbollayerv2widget.cpp | 34 +++++++++++++ src/gui/symbology-ng/qgssymbollayerv2widget.h | 3 ++ src/ui/symbollayer/widget_svgmarker.ui | 48 ++++++++++++++++-- 6 files changed, 142 insertions(+), 35 deletions(-) diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp index 79c1e570f830..c2576d4a1d98 100644 --- a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp +++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp @@ -450,6 +450,9 @@ QgsSvgMarkerSymbolLayerV2::QgsSvgMarkerSymbolLayerV2( QString name, double size, mSize = size; mAngle = angle; mOffset = QPointF( 0, 0 ); + mOutlineWidth = 1.0; + mFillColor = QColor( Qt::black ); + mOutlineColor = QColor( Qt::black ); } @@ -469,6 +472,12 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::create( const QgsStringMap& props ) QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle ); if ( props.contains( "offset" ) ) m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) ); + if ( props.contains( "fill" ) ) + m->setFillColor( QColor( props["fill"] ) ); + if ( props.contains( "outline" ) ) + m->setOutlineColor( QColor( props["outline"] ) ); + if ( props.contains( "outline-width" ) ) + m->setOutlineWidth( props["outline-width"].toDouble() ); return m; } @@ -534,16 +543,16 @@ void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2Re if ( mAngle != 0 ) p->rotate( mAngle ); - if( doubleNear( context.renderContext().rasterScaleFactor(), 1.0 ) ) + if ( doubleNear( context.renderContext().rasterScaleFactor(), 1.0, 0.1 ) ) { - const QImage& img = QgsSvgCache::instance()->svgAsImage( mPath, mSize, QColor( Qt::black )/*const QColor& fill*/, QColor( Qt::black ) /*const QColor& outline*/, - 1.0 /*outline width*/, context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() ); + const QImage& img = QgsSvgCache::instance()->svgAsImage( mPath, mSize, mFillColor, mOutlineColor, mOutlineWidth, + context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() ); p->drawImage( -img.width() / 2.0, -img.width() / 2.0, img ); } else { - const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( mPath, mSize, QColor( Qt::black )/*const QColor& fill*/, QColor( Qt::black ) /*const QColor& outline*/, - 1.0 /*outline width*/, context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() ); + const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( mPath, mSize, mFillColor, mOutlineColor, mOutlineWidth, + context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() ); p->drawPicture( 0, 0, pct ); } @@ -558,12 +567,18 @@ QgsStringMap QgsSvgMarkerSymbolLayerV2::properties() const map["size"] = QString::number( mSize ); map["angle"] = QString::number( mAngle ); map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset ); + map["fill"] = mFillColor.name(); + map["outline"] = mOutlineColor.name(); + map["outline-width"] = QString::number( mOutlineWidth ); return map; } QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::clone() const { QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( mPath, mSize, mAngle ); + m->setFillColor( mFillColor ); + m->setOutlineColor( mOutlineColor ); + m->setOutlineWidth( 1.0 ); m->setOffset( mOffset ); return m; } diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.h b/src/core/symbology-ng/qgsmarkersymbollayerv2.h index 386a7ef763f9..4f351915ac19 100644 --- a/src/core/symbology-ng/qgsmarkersymbollayerv2.h +++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.h @@ -114,11 +114,28 @@ class CORE_EXPORT QgsSvgMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2 QString path() const { return mPath; } void setPath( QString path ) { mPath = path; } + QColor fillColor() const { return mFillColor; } + void setFillColor( const QColor& c ) { mFillColor = c; } + + QColor outlineColor() const { return mOutlineColor; } + void setOutlineColor( const QColor& c ) { mOutlineColor = c; } + + double outlineWidth() const { return mOutlineWidth; } + void setOutlineWidth( double w ) { mOutlineWidth = w; } + protected: void loadSvg(); QString mPath; + + //param(fill), param(outline), param(outline-width) are going + //to be replaced in memory + QColor mFillColor; + QColor mOutlineColor; + double mOutlineWidth; + + QPicture mPicture; QPicture mSelPicture; double mOrigSize; diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index 8b440f2a4b5e..ea523544d7a8 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -25,12 +25,12 @@ #include QgsSvgCacheEntry::QgsSvgCacheEntry(): file( QString() ), size( 0 ), outlineWidth( 0 ), widthScaleFactor( 1.0 ), rasterScaleFactor( 1.0 ), fill( Qt::black ), -outline( Qt::black ), image( 0 ), picture( 0 ) + outline( Qt::black ), image( 0 ), picture( 0 ) { } 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 ), -widthScaleFactor( wsf ), rasterScaleFactor( rsf ), fill( fi ), outline( ou ), image( 0 ), picture( 0 ) + widthScaleFactor( wsf ), rasterScaleFactor( rsf ), fill( fi ), outline( ou ), image( 0 ), picture( 0 ) { } @@ -73,7 +73,7 @@ QgsSvgCache::QgsSvgCache() QgsSvgCache::~QgsSvgCache() { QMap< QDateTime, QgsSvgCacheEntry* >::iterator it = mEntries.begin(); - for(; it != mEntries.end(); ++it ) + for ( ; it != mEntries.end(); ++it ) { delete it.value(); } @@ -83,11 +83,11 @@ QgsSvgCache::~QgsSvgCache() const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor ) { - QgsSvgCacheEntry* currentEntry = this->cacheEntry( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); + QgsSvgCacheEntry* currentEntry = cacheEntry( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); //if current entry image is 0: cache image for entry //update stats for memory usage - if( !currentEntry->image ) + if ( !currentEntry->image ) { cacheImage( currentEntry ); } @@ -98,13 +98,13 @@ const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const Q } const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, - double widthScaleFactor, double rasterScaleFactor ) + double widthScaleFactor, double rasterScaleFactor ) { - QgsSvgCacheEntry* currentEntry = this->cacheEntry( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); + QgsSvgCacheEntry* currentEntry = cacheEntry( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); //if current entry image is 0: cache image for entry //update stats for memory usage - if( !currentEntry->picture ) + if ( !currentEntry->picture ) { cachePicture( currentEntry ); } @@ -115,7 +115,7 @@ const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, con } QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, - double widthScaleFactor, double rasterScaleFactor ) + double widthScaleFactor, double rasterScaleFactor ) { QgsSvgCacheEntry* entry = new QgsSvgCacheEntry( file, size, outlineWidth, widthScaleFactor, rasterScaleFactor, fill, outline ); entry->lastUsed = QDateTime::currentDateTime(); @@ -129,19 +129,19 @@ QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, double size, cons void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ) { - if( !entry ) + if ( !entry ) { return; } QFile svgFile( entry->file ); - if( !svgFile.open( QIODevice::ReadOnly ) ) + if ( !svgFile.open( QIODevice::ReadOnly ) ) { return; } QDomDocument svgDoc; - if( !svgDoc.setContent( &svgFile ) ) + if ( !svgDoc.setContent( &svgFile ) ) { return; } @@ -155,7 +155,7 @@ void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ) void QgsSvgCache::cacheImage( QgsSvgCacheEntry* entry ) { - if( !entry ) + if ( !entry ) { return; } @@ -176,7 +176,7 @@ void QgsSvgCache::cacheImage( QgsSvgCacheEntry* entry ) void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry ) { - if( !entry ) + if ( !entry ) { return; } @@ -198,18 +198,18 @@ void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry ) } QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, - double widthScaleFactor, double rasterScaleFactor ) + double widthScaleFactor, double rasterScaleFactor ) { //search entries in mEntryLookup QgsSvgCacheEntry* currentEntry = 0; QList entries = mEntryLookup.values( file ); QList::iterator entryIt = entries.begin(); - for(; entryIt != entries.end(); ++entryIt ) + for ( ; entryIt != entries.end(); ++entryIt ) { QgsSvgCacheEntry* cacheEntry = *entryIt; - if( cacheEntry->file == file && cacheEntry->size == size && cacheEntry->fill == fill && cacheEntry->outline == outline && - cacheEntry->outlineWidth == outlineWidth && cacheEntry->widthScaleFactor == widthScaleFactor && cacheEntry->rasterScaleFactor == rasterScaleFactor) + if ( cacheEntry->file == file && cacheEntry->size == size && cacheEntry->fill == fill && cacheEntry->outline == outline && + cacheEntry->outlineWidth == outlineWidth && cacheEntry->widthScaleFactor == widthScaleFactor && cacheEntry->rasterScaleFactor == rasterScaleFactor ) { currentEntry = cacheEntry; break; @@ -219,7 +219,7 @@ QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, con //if not found: create new entry //cache and replace params in svg content - if( !currentEntry ) + if ( !currentEntry ) { currentEntry = insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); } @@ -228,7 +228,7 @@ QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, con void QgsSvgCache::replaceElemParams( QDomElement& elem, const QColor& fill, const QColor& outline, double outlineWidth ) { - if( elem.isNull() ) + if ( elem.isNull() ) { return; } @@ -236,19 +236,19 @@ void QgsSvgCache::replaceElemParams( QDomElement& elem, const QColor& fill, cons //go through attributes QDomNamedNodeMap attributes = elem.attributes(); int nAttributes = attributes.count(); - for( int i = 0; i < nAttributes; ++i ) + for ( int i = 0; i < nAttributes; ++i ) { QDomAttr attribute = attributes.item( i ).toAttr(); QString value = attribute.value(); - if( value.startsWith("params(fill)") ) + if ( value.startsWith( "param(fill)" ) ) { elem.setAttribute( attribute.name(), fill.name() ); } - else if( value.startsWith("params(outline)") ) + else if ( value.startsWith( "param(outline)" ) ) { elem.setAttribute( attribute.name(), outline.name() ); } - else if( value.startsWith("params(outline-width)") ) + else if ( value.startsWith( "param(outline-width)" ) ) { elem.setAttribute( attribute.name(), QString::number( outlineWidth ) ); } @@ -256,7 +256,7 @@ void QgsSvgCache::replaceElemParams( QDomElement& elem, const QColor& fill, cons QDomNodeList childList = elem.childNodes(); int nChildren = childList.count(); - for( int i = 0; i < nChildren; ++i ) + for ( int i = 0; i < nChildren; ++i ) { QDomElement childElem = childList.at( i ).toElement(); replaceElemParams( childElem, fill, outline, outlineWidth ); diff --git a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp index 3b263e05ee0b..ad7733c3b29d 100644 --- a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp +++ b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp @@ -669,6 +669,40 @@ void QgsSvgMarkerSymbolLayerV2Widget::on_mFileLineEdit_textEdited( const QString emit changed(); } +void QgsSvgMarkerSymbolLayerV2Widget::on_mChangeColorButton_clicked() +{ + if ( !mLayer ) + { + return; + } + QColor c = QColorDialog::getColor( mLayer->fillColor() ); + if ( c.isValid() ) + { + mLayer->setFillColor( c ); + } +} + +void QgsSvgMarkerSymbolLayerV2Widget::on_mChangeBorderColorButton_clicked() +{ + if ( !mLayer ) + { + return; + } + QColor c = QColorDialog::getColor( mLayer->outlineColor() ); + if ( c.isValid() ) + { + mLayer->setOutlineColor( c ); + } +} + +void QgsSvgMarkerSymbolLayerV2Widget::on_mBorderWidthSpinBox_valueChanged( double d ) +{ + if ( mLayer ) + { + mLayer->setOutlineWidth( d ); + } +} + /////////////// QgsLineDecorationSymbolLayerV2Widget::QgsLineDecorationSymbolLayerV2Widget( QWidget* parent ) diff --git a/src/gui/symbology-ng/qgssymbollayerv2widget.h b/src/gui/symbology-ng/qgssymbollayerv2widget.h index ba101d3eda34..a1d04e1222d1 100644 --- a/src/gui/symbology-ng/qgssymbollayerv2widget.h +++ b/src/gui/symbology-ng/qgssymbollayerv2widget.h @@ -181,6 +181,9 @@ class GUI_EXPORT QgsSvgMarkerSymbolLayerV2Widget : public QgsSymbolLayerV2Widget void setOffset(); void on_mFileToolButton_clicked(); void on_mFileLineEdit_textEdited( const QString& text ); + void on_mChangeColorButton_clicked(); + void on_mChangeBorderColorButton_clicked(); + void on_mBorderWidthSpinBox_valueChanged( double d ); protected: diff --git a/src/ui/symbollayer/widget_svgmarker.ui b/src/ui/symbollayer/widget_svgmarker.ui index 5cbe542d5a8e..9039f71f1bdd 100644 --- a/src/ui/symbollayer/widget_svgmarker.ui +++ b/src/ui/symbollayer/widget_svgmarker.ui @@ -6,8 +6,8 @@ 0 0 - 391 - 276 + 302 + 337 @@ -29,7 +29,7 @@ - + Qt::Horizontal @@ -62,7 +62,7 @@ - + @@ -92,7 +92,7 @@ - + Offset X,Y @@ -118,6 +118,44 @@ + + + + Change + + + + + + + Color + + + + + + + + + + Border width + + + + + + + Change + + + + + + + Border color + + + From bc61e9fa6ca664b468562bab9ceb6ed32a3a801f Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Sat, 25 Jun 2011 17:27:29 +0200 Subject: [PATCH 06/16] Notify dialog if svg accepts parameters --- src/core/symbology-ng/qgssvgcache.cpp | 63 +++++++++++++++++-- src/core/symbology-ng/qgssvgcache.h | 12 ++-- .../symbology-ng/qgssymbollayerv2widget.cpp | 10 +++ 3 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index ea523544d7a8..56250af094c6 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -16,6 +16,7 @@ ***************************************************************************/ #include "qgssvgcache.h" +#include "qgslogger.h" #include #include #include @@ -66,14 +67,14 @@ QgsSvgCache* QgsSvgCache::instance() return mInstance; } -QgsSvgCache::QgsSvgCache() +QgsSvgCache::QgsSvgCache(): mTotalSize( 0 ) { } QgsSvgCache::~QgsSvgCache() { - QMap< QDateTime, QgsSvgCacheEntry* >::iterator it = mEntries.begin(); - for ( ; it != mEntries.end(); ++it ) + QMultiHash< QString, QgsSvgCacheEntry* >::iterator it = mEntryLookup.begin(); + for( ; it != mEntryLookup.end(); ++it ) { delete it.value(); } @@ -92,7 +93,11 @@ const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const Q cacheImage( currentEntry ); } - //update lastUsed with current date time + //debug: display current cache usage + QgsDebugMsg("cache size: " + QString::number( mTotalSize ) ); + + //set entry timestamp to current time + currentEntry->lastUsed = QDateTime::currentDateTime(); return *( currentEntry->image ); } @@ -109,7 +114,11 @@ const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, con cachePicture( currentEntry ); } - //update lastUsed with current date time + //debug: display current cache usage + QgsDebugMsg("cache size: " + QString::number( mTotalSize ) ); + + //set entry timestamp to current time + currentEntry->lastUsed = QDateTime::currentDateTime(); return *( currentEntry->picture ); } @@ -122,11 +131,44 @@ QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, double size, cons replaceParamsAndCacheSvg( entry ); - mEntries.insert( entry->lastUsed, entry ); mEntryLookup.insert( file, entry ); return entry; } +void QgsSvgCache::containsParams( const QString& path, bool& hasFillParam, bool& hasOutlineParam, bool& hasOutlineWidthParam ) const +{ + hasFillParam = false; + hasOutlineParam = false; + hasOutlineWidthParam = false; + + QFile svgFile( path ); + if ( !svgFile.open( QIODevice::ReadOnly ) ) + { + return; + } + + QDomDocument svgDoc; + if ( !svgDoc.setContent( &svgFile ) ) + { + return; + } + + //there are surely faster ways to get this information + QString content = svgDoc.toString(); + if( content.contains("param(fill") ) + { + hasFillParam = true; + } + if( content.contains("param(outline") ) + { + hasOutlineParam = true; + } + if( content.contains("param(outline-width)" ) ) + { + hasOutlineWidthParam = true; + } +} + void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ) { if ( !entry ) @@ -151,6 +193,7 @@ void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ) replaceElemParams( docElem, entry->fill, entry->outline, entry->outlineWidth ); entry->svgContent = svgDoc.toByteArray(); + mTotalSize += entry->svgContent.size(); } void QgsSvgCache::cacheImage( QgsSvgCacheEntry* entry ) @@ -172,6 +215,7 @@ void QgsSvgCache::cacheImage( QgsSvgCacheEntry* entry ) r.render( &p ); entry->image = image; + mTotalSize += (image->width() * image->height() * 32); } void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry ) @@ -195,6 +239,7 @@ void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry ) QPainter painter( picture ); renderer.render( &painter, rect ); entry->picture = picture; + mTotalSize += entry->picture->size(); } QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, @@ -263,3 +308,9 @@ void QgsSvgCache::replaceElemParams( QDomElement& elem, const QColor& fill, cons } } +void QgsSvgCache::removeCacheEntry( QString s, QgsSvgCacheEntry* entry ) +{ + delete entry; + mEntryLookup.remove( s , entry ); +} + diff --git a/src/core/symbology-ng/qgssvgcache.h b/src/core/symbology-ng/qgssvgcache.h index 7ec027379b72..519f9c7b5d65 100644 --- a/src/core/symbology-ng/qgssvgcache.h +++ b/src/core/symbology-ng/qgssvgcache.h @@ -66,6 +66,9 @@ class QgsSvgCache const QPicture& svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor ); + /**Tests if an svg file contains parameters for fill, outline color, outline width*/ + void containsParams( const QString& path, bool& hasFillParam, bool& hasOutlineParam, bool& hasOutlineWidthParam ) const; + protected: QgsSvgCache(); @@ -83,14 +86,15 @@ class QgsSvgCache private: static QgsSvgCache* mInstance; - /**Entries sorted by last used time*/ - QMap< QDateTime, QgsSvgCacheEntry* > mEntries; /**Entry pointers accessible by file name*/ QMultiHash< QString, QgsSvgCacheEntry* > mEntryLookup; - /**Estimated total size of all images and pictures*/ - double mTotalSize; + /**Estimated total size of all images, pictures and svgContent*/ + long mTotalSize; /**Replaces parameters in elements of a dom node and calls method for all child nodes*/ void replaceElemParams( QDomElement& elem, const QColor& fill, const QColor& outline, double outlineWidth ); + + /**Release memory and remove cache entry from mEntryLookup*/ + void removeCacheEntry( QString s, QgsSvgCacheEntry* entry ); }; #endif // QGSSVGCACHE_H diff --git a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp index ad7733c3b29d..bc2ee2866078 100644 --- a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp +++ b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp @@ -8,6 +8,7 @@ #include "characterwidget.h" #include "qgsdashspacedialog.h" #include "qgssymbolv2propertiesdialog.h" +#include "qgssvgcache.h" #include "qgsapplication.h" @@ -595,6 +596,7 @@ void QgsSvgMarkerSymbolLayerV2Widget::setSymbolLayer( QgsSymbolLayerV2* layer ) { selModel->select( idx, QItemSelectionModel::SelectCurrent ); selModel->setCurrentIndex( idx, QItemSelectionModel::SelectCurrent ); + setName( idx ); break; } } @@ -623,6 +625,14 @@ void QgsSvgMarkerSymbolLayerV2Widget::setName( const QModelIndex& idx ) QString name = idx.data( Qt::UserRole ).toString(); mLayer->setPath( name ); mFileLineEdit->setText( name ); + + //activate gui for svg parameters only if supported by the svg file + bool hasFillParam, hasOutlineParam, hasOutlineWidthParam; + QgsSvgCache::instance()->containsParams( name, hasFillParam, hasOutlineParam, hasOutlineWidthParam ); + mChangeColorButton->setEnabled( hasFillParam ); + mChangeBorderColorButton->setEnabled( hasOutlineParam ); + mBorderWidthSpinBox->setEnabled( hasOutlineWidthParam ); + emit changed(); } From 718093fa6c0b348c954c7a8feaa12d70c710aacb Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Mon, 27 Jun 2011 11:27:25 +0200 Subject: [PATCH 07/16] Restore svg marker selection --- .../symbology-ng/qgsmarkersymbollayerv2.cpp | 34 ++++++------------- .../symbology-ng/qgsmarkersymbollayerv2.h | 4 --- .../symbology-ng/qgssymbollayerv2widget.cpp | 27 +++++++++++---- src/gui/symbology-ng/qgssymbollayerv2widget.h | 2 ++ 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp index c2576d4a1d98..5b13d897abdb 100644 --- a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp +++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp @@ -489,30 +489,8 @@ QString QgsSvgMarkerSymbolLayerV2::layerType() const void QgsSvgMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context ) { - double pictureSize = 0; - QgsRenderContext& rc = context.renderContext(); - - if ( rc.painter() && rc.painter()->device() ) - { - //correct QPictures DPI correction - pictureSize = context.outputLineWidth( mSize ) / rc.painter()->device()->logicalDpiX() * mPicture.logicalDpiX(); - } - else - { - pictureSize = context.outputLineWidth( mSize ); - } - QRectF rect( QPointF( -pictureSize / 2.0, -pictureSize / 2.0 ), QSizeF( pictureSize, pictureSize ) ); - QSvgRenderer renderer( mPath ); - QPainter painter( &mPicture ); - renderer.render( &painter, rect ); - QPainter selPainter( &mSelPicture ); - selPainter.setRenderHint( QPainter::Antialiasing ); - selPainter.setBrush( QBrush( context.selectionColor() ) ); - selPainter.setPen( Qt::NoPen ); - selPainter.drawEllipse( QPointF( 0, 0 ), pictureSize*0.6, pictureSize*0.6 ); - renderer.render( &selPainter, rect ); - mOrigSize = mSize; // save in case the size would be data defined + Q_UNUSED( context ); } void QgsSvgMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context ) @@ -556,6 +534,16 @@ void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2Re p->drawPicture( 0, 0, pct ); } + if( context.selected() ) + { + QPen pen( context.selectionColor() ); + pen.setWidth( 2 ); + p->setPen( pen ); + p->setBrush( Qt::NoBrush ); + double sizePixel = context.outputLineWidth( mSize ); + p->drawRect( QRectF( -sizePixel / 2.0, -sizePixel / 2.0, sizePixel, sizePixel ) ); + } + p->restore(); } diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.h b/src/core/symbology-ng/qgsmarkersymbollayerv2.h index 4f351915ac19..026918c44a26 100644 --- a/src/core/symbology-ng/qgsmarkersymbollayerv2.h +++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.h @@ -134,10 +134,6 @@ class CORE_EXPORT QgsSvgMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2 QColor mFillColor; QColor mOutlineColor; double mOutlineWidth; - - - QPicture mPicture; - QPicture mSelPicture; double mOrigSize; }; diff --git a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp index bc2ee2866078..209efc16379a 100644 --- a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp +++ b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp @@ -576,6 +576,20 @@ void QgsSvgMarkerSymbolLayerV2Widget::populateList() viewImages->setModel( m ); } +void QgsSvgMarkerSymbolLayerV2Widget::setGuiForSvg( const QString& svgPath ) +{ + //activate gui for svg parameters only if supported by the svg file + bool hasFillParam, hasOutlineParam, hasOutlineWidthParam; + QgsSvgCache::instance()->containsParams( svgPath, hasFillParam, hasOutlineParam, hasOutlineWidthParam ); + mChangeColorButton->setEnabled( hasFillParam ); + mChangeBorderColorButton->setEnabled( hasOutlineParam ); + mBorderWidthSpinBox->setEnabled( hasOutlineWidthParam ); + + mFileLineEdit->blockSignals( true ); + mFileLineEdit->setText( svgPath ); + mFileLineEdit->blockSignals( false ); +} + void QgsSvgMarkerSymbolLayerV2Widget::setSymbolLayer( QgsSymbolLayerV2* layer ) { @@ -613,6 +627,8 @@ void QgsSvgMarkerSymbolLayerV2Widget::setSymbolLayer( QgsSymbolLayerV2* layer ) spinOffsetY->blockSignals( true ); spinOffsetY->setValue( mLayer->offset().y() ); spinOffsetY->blockSignals( false ); + + setGuiForSvg( mLayer->path() ); } QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2Widget::symbolLayer() @@ -626,13 +642,7 @@ void QgsSvgMarkerSymbolLayerV2Widget::setName( const QModelIndex& idx ) mLayer->setPath( name ); mFileLineEdit->setText( name ); - //activate gui for svg parameters only if supported by the svg file - bool hasFillParam, hasOutlineParam, hasOutlineWidthParam; - QgsSvgCache::instance()->containsParams( name, hasFillParam, hasOutlineParam, hasOutlineWidthParam ); - mChangeColorButton->setEnabled( hasFillParam ); - mChangeBorderColorButton->setEnabled( hasOutlineParam ); - mBorderWidthSpinBox->setEnabled( hasOutlineWidthParam ); - + setGuiForSvg( name ); emit changed(); } @@ -689,6 +699,7 @@ void QgsSvgMarkerSymbolLayerV2Widget::on_mChangeColorButton_clicked() if ( c.isValid() ) { mLayer->setFillColor( c ); + emit changed(); } } @@ -702,6 +713,7 @@ void QgsSvgMarkerSymbolLayerV2Widget::on_mChangeBorderColorButton_clicked() if ( c.isValid() ) { mLayer->setOutlineColor( c ); + emit changed(); } } @@ -710,6 +722,7 @@ void QgsSvgMarkerSymbolLayerV2Widget::on_mBorderWidthSpinBox_valueChanged( doubl if ( mLayer ) { mLayer->setOutlineWidth( d ); + emit changed(); } } diff --git a/src/gui/symbology-ng/qgssymbollayerv2widget.h b/src/gui/symbology-ng/qgssymbollayerv2widget.h index a1d04e1222d1..e822c3b0958e 100644 --- a/src/gui/symbology-ng/qgssymbollayerv2widget.h +++ b/src/gui/symbology-ng/qgssymbollayerv2widget.h @@ -188,6 +188,8 @@ class GUI_EXPORT QgsSvgMarkerSymbolLayerV2Widget : public QgsSymbolLayerV2Widget protected: void populateList(); + //update gui for svg file (insert new path, update activation of gui elements for svg params) + void setGuiForSvg( const QString& svgPath ); QgsSvgMarkerSymbolLayerV2* mLayer; }; From 166b3d2589428f72bb642157bc1409abea38a12b Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Mon, 27 Jun 2011 13:34:47 +0200 Subject: [PATCH 08/16] Support also style-syntax for svg params --- .../symbology-ng/qgsmarkersymbollayerv2.cpp | 2 +- src/core/symbology-ng/qgssvgcache.cpp | 68 ++++++++++++++----- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp index 5b13d897abdb..adacd18f642d 100644 --- a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp +++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp @@ -537,7 +537,7 @@ void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2Re if( context.selected() ) { QPen pen( context.selectionColor() ); - pen.setWidth( 2 ); + pen.setWidth( context.outputLineWidth( 1.0 ) ); p->setPen( pen ); p->setBrush( Qt::NoBrush ); double sizePixel = context.outputLineWidth( mSize ); diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index 56250af094c6..7fdaf648adfd 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -74,7 +74,7 @@ QgsSvgCache::QgsSvgCache(): mTotalSize( 0 ) QgsSvgCache::~QgsSvgCache() { QMultiHash< QString, QgsSvgCacheEntry* >::iterator it = mEntryLookup.begin(); - for( ; it != mEntryLookup.end(); ++it ) + for ( ; it != mEntryLookup.end(); ++it ) { delete it.value(); } @@ -94,7 +94,7 @@ const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const Q } //debug: display current cache usage - QgsDebugMsg("cache size: " + QString::number( mTotalSize ) ); + QgsDebugMsg( "cache size: " + QString::number( mTotalSize ) ); //set entry timestamp to current time currentEntry->lastUsed = QDateTime::currentDateTime(); @@ -115,7 +115,7 @@ const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, con } //debug: display current cache usage - QgsDebugMsg("cache size: " + QString::number( mTotalSize ) ); + QgsDebugMsg( "cache size: " + QString::number( mTotalSize ) ); //set entry timestamp to current time currentEntry->lastUsed = QDateTime::currentDateTime(); @@ -155,15 +155,15 @@ void QgsSvgCache::containsParams( const QString& path, bool& hasFillParam, bool& //there are surely faster ways to get this information QString content = svgDoc.toString(); - if( content.contains("param(fill") ) + if ( content.contains( "param(fill" ) ) { hasFillParam = true; } - if( content.contains("param(outline") ) + if ( content.contains( "param(outline" ) ) { hasOutlineParam = true; } - if( content.contains("param(outline-width)" ) ) + if ( content.contains( "param(outline-width)" ) ) { hasOutlineWidthParam = true; } @@ -215,7 +215,7 @@ void QgsSvgCache::cacheImage( QgsSvgCacheEntry* entry ) r.render( &p ); entry->image = image; - mTotalSize += (image->width() * image->height() * 32); + mTotalSize += ( image->width() * image->height() * 32 ); } void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry ) @@ -284,18 +284,54 @@ void QgsSvgCache::replaceElemParams( QDomElement& elem, const QColor& fill, cons for ( int i = 0; i < nAttributes; ++i ) { QDomAttr attribute = attributes.item( i ).toAttr(); - QString value = attribute.value(); - if ( value.startsWith( "param(fill)" ) ) + //e.g. style="fill:param(fill);param(stroke)" + if ( attribute.name().compare( "style", Qt::CaseInsensitive ) == 0 ) { - elem.setAttribute( attribute.name(), fill.name() ); + //entries separated by ';' + QString newAttributeString; + + QStringList entryList = attribute.value().split( ';' ); + QStringList::const_iterator entryIt = entryList.constBegin(); + for ( ; entryIt != entryList.constEnd(); ++entryIt ) + { + QStringList keyValueSplit = entryIt->split( ':' ); + if ( keyValueSplit.size() < 2 ) + { + continue; + } + QString key = keyValueSplit.at( 0 ); + QString value = keyValueSplit.at( 1 ); + if ( value.startsWith( "param(fill" ) ) + { + value = fill.name(); + } + else if ( value.startsWith( "param(outline)" ) ) + { + value = outline.name(); + } + else if ( value.startsWith( "param(outline-width)" ) ) + { + value = QString::number( outlineWidth ); + } + newAttributeString.append( key + ":" + value + ";" ); + } + elem.setAttribute( attribute.name(), newAttributeString ); } - else if ( value.startsWith( "param(outline)" ) ) + else { - elem.setAttribute( attribute.name(), outline.name() ); - } - else if ( value.startsWith( "param(outline-width)" ) ) - { - elem.setAttribute( attribute.name(), QString::number( outlineWidth ) ); + QString value = attribute.value(); + if ( value.startsWith( "param(fill)" ) ) + { + elem.setAttribute( attribute.name(), fill.name() ); + } + else if ( value.startsWith( "param(outline)" ) ) + { + elem.setAttribute( attribute.name(), outline.name() ); + } + else if ( value.startsWith( "param(outline-width)" ) ) + { + elem.setAttribute( attribute.name(), QString::number( outlineWidth ) ); + } } } From 05b418317304df218fc3d8ad738a0c51db2db65a Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Tue, 28 Jun 2011 12:08:22 +0200 Subject: [PATCH 09/16] Remove oldest entries from svg cache if cache size is too large --- src/core/symbology-ng/qgssvgcache.cpp | 116 ++++++++++++++++++++++---- src/core/symbology-ng/qgssvgcache.h | 28 ++++++- 2 files changed, 127 insertions(+), 17 deletions(-) diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index 7fdaf648adfd..2cc039b6836a 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -48,6 +48,20 @@ bool QgsSvgCacheEntry::operator==( const QgsSvgCacheEntry& other ) const && other.rasterScaleFactor == rasterScaleFactor && other.fill == fill && other.outline == outline ); } +int QgsSvgCacheEntry::dataSize() const +{ + int size = svgContent.size(); + if ( picture ) + { + size += picture->size(); + } + if ( image ) + { + size += ( image->width() * image->height() * 32 ); + } + return size; +} + QString file; double size; double outlineWidth; @@ -67,7 +81,7 @@ QgsSvgCache* QgsSvgCache::instance() return mInstance; } -QgsSvgCache::QgsSvgCache(): mTotalSize( 0 ) +QgsSvgCache::QgsSvgCache(): mTotalSize( 0 ), mLeastRecentEntry( 0 ), mMostRecentEntry( 0 ) { } @@ -91,14 +105,9 @@ const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const Q if ( !currentEntry->image ) { cacheImage( currentEntry ); + trimToMaximumSize(); } - //debug: display current cache usage - QgsDebugMsg( "cache size: " + QString::number( mTotalSize ) ); - - //set entry timestamp to current time - currentEntry->lastUsed = QDateTime::currentDateTime(); - return *( currentEntry->image ); } @@ -112,14 +121,9 @@ const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, con if ( !currentEntry->picture ) { cachePicture( currentEntry ); + trimToMaximumSize(); } - //debug: display current cache usage - QgsDebugMsg( "cache size: " + QString::number( mTotalSize ) ); - - //set entry timestamp to current time - currentEntry->lastUsed = QDateTime::currentDateTime(); - return *( currentEntry->picture ); } @@ -127,11 +131,28 @@ QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, double size, cons double widthScaleFactor, double rasterScaleFactor ) { QgsSvgCacheEntry* entry = new QgsSvgCacheEntry( file, size, outlineWidth, widthScaleFactor, rasterScaleFactor, fill, outline ); - entry->lastUsed = QDateTime::currentDateTime(); replaceParamsAndCacheSvg( entry ); mEntryLookup.insert( file, entry ); + + //insert to most recent place in entry list + if ( !mMostRecentEntry ) //inserting first entry + { + mLeastRecentEntry = entry; + mMostRecentEntry = entry; + entry->previousEntry = 0; + entry->nextEntry = 0; + } + else + { + entry->previousEntry = mMostRecentEntry; + entry->nextEntry = 0; + mMostRecentEntry->nextEntry = entry; + mMostRecentEntry = entry; + } + + trimToMaximumSize(); return entry; } @@ -268,6 +289,18 @@ QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, con { currentEntry = insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); } + else + { + takeEntryFromList( currentEntry ); + mMostRecentEntry->nextEntry = currentEntry; + currentEntry->previousEntry = mMostRecentEntry; + currentEntry->nextEntry = 0; + mMostRecentEntry = currentEntry; + } + + //debugging + //printEntryList(); + return currentEntry; } @@ -350,3 +383,58 @@ void QgsSvgCache::removeCacheEntry( QString s, QgsSvgCacheEntry* entry ) mEntryLookup.remove( s , entry ); } +void QgsSvgCache::printEntryList() +{ + QgsDebugMsg( "****************svg cache entry list*************************" ); + QgsDebugMsg( "Cache size: " + QString::number( mTotalSize ) ); + QgsSvgCacheEntry* entry = mLeastRecentEntry; + while ( entry ) + { + QgsDebugMsg( "***Entry:" ); + QgsDebugMsg( "File:" + entry->file ); + QgsDebugMsg( "Size:" + QString::number( entry->size ) ); + QgsDebugMsg( "Width scale factor" + QString::number( entry->widthScaleFactor ) ); + QgsDebugMsg( "Raster scale factor" + QString::number( entry->rasterScaleFactor ) ); + entry = entry->nextEntry; + } +} + +void QgsSvgCache::trimToMaximumSize() +{ + QgsSvgCacheEntry* entry = mLeastRecentEntry; + while ( entry && ( mTotalSize > mMaximumSize ) ) + { + QgsSvgCacheEntry* bkEntry = entry; + entry = entry->nextEntry; + + takeEntryFromList( bkEntry ); + mTotalSize -= bkEntry->dataSize(); + delete bkEntry; + } +} + +void QgsSvgCache::takeEntryFromList( QgsSvgCacheEntry* entry ) +{ + if ( !entry ) + { + return; + } + + if ( entry->previousEntry ) + { + entry->previousEntry->nextEntry = entry->nextEntry; + } + else + { + mLeastRecentEntry = entry->nextEntry; + } + if ( entry->nextEntry ) + { + entry->nextEntry->previousEntry = entry->previousEntry; + } + else + { + mMostRecentEntry = entry->previousEntry; + } +} + diff --git a/src/core/symbology-ng/qgssvgcache.h b/src/core/symbology-ng/qgssvgcache.h index 519f9c7b5d65..1cf93d566178 100644 --- a/src/core/symbology-ng/qgssvgcache.h +++ b/src/core/symbology-ng/qgssvgcache.h @@ -19,7 +19,6 @@ #define QGSSVGCACHE_H #include -#include #include #include #include @@ -43,12 +42,17 @@ struct QgsSvgCacheEntry QColor outline; QImage* image; QPicture* picture; - QDateTime lastUsed; //content (with params replaced) QByteArray svgContent; + //keep entries on a least, sorted by last access + QgsSvgCacheEntry* nextEntry; + QgsSvgCacheEntry* previousEntry; + /**Don't consider image, picture, last used timestamp for comparison*/ bool operator==( const QgsSvgCacheEntry& other ) const; + /**Return memory usage in bytes*/ + int dataSize() const; }; /**A cache for images / pictures derived from svg files. This class supports parameter replacement in svg files @@ -81,7 +85,13 @@ class QgsSvgCache void cachePicture( QgsSvgCacheEntry* entry ); /**Returns entry from cache or creates a new entry if it does not exist already*/ QgsSvgCacheEntry* cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, - double widthScaleFactor, double rasterScaleFactor ); + double widthScaleFactor, double rasterScaleFactor ); + + /**Removes the least used items until the maximum size is under the limit*/ + void trimToMaximumSize(); + + //Removes entry from the ordered list (but does not delete the entry itself) + void takeEntryFromList( QgsSvgCacheEntry* entry ); private: static QgsSvgCache* mInstance; @@ -90,11 +100,23 @@ class QgsSvgCache QMultiHash< QString, QgsSvgCacheEntry* > mEntryLookup; /**Estimated total size of all images, pictures and svgContent*/ long mTotalSize; + + //The svg cache keeps the entries on a double connected list, moving the current entry to the front. + //That way, removing entries for more space can start with the least used objects. + QgsSvgCacheEntry* mLeastRecentEntry; + QgsSvgCacheEntry* mMostRecentEntry; + + //Maximum cache size + static const long mMaximumSize = 20000000; + /**Replaces parameters in elements of a dom node and calls method for all child nodes*/ void replaceElemParams( QDomElement& elem, const QColor& fill, const QColor& outline, double outlineWidth ); /**Release memory and remove cache entry from mEntryLookup*/ void removeCacheEntry( QString s, QgsSvgCacheEntry* entry ); + + /**For debugging*/ + void printEntryList(); }; #endif // QGSSVGCACHE_H From 66c009fca756a05b726a1703ae930a85a52a1ded Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Wed, 29 Jun 2011 08:21:53 +0200 Subject: [PATCH 10/16] Try to consider default parameters --- .../symbology-ng/qgsmarkersymbollayerv2.cpp | 43 +++++++ .../symbology-ng/qgsmarkersymbollayerv2.h | 2 +- src/core/symbology-ng/qgssvgcache.cpp | 121 +++++++++++++++++- src/core/symbology-ng/qgssvgcache.h | 9 +- .../symbology-ng/qgssymbollayerv2widget.cpp | 22 +++- src/gui/symbology-ng/qgssymbollayerv2widget.h | 2 +- 6 files changed, 188 insertions(+), 11 deletions(-) diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp index adacd18f642d..eb01ef345485 100644 --- a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp +++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp @@ -470,6 +470,28 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::create( const QgsStringMap& props ) angle = props["angle"].toDouble(); QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle ); + + //we only check the svg default parameters if necessary, since it could be expensive + if( !props.contains("fill") && !props.contains("outline") && !props.contains("outline-width") ) + { + QColor fillColor, outlineColor; + double outlineWidth; + bool hasFillParam, hasOutlineParam, hasOutlineWidthParam; + QgsSvgCache::instance()->containsParams( name, hasFillParam, fillColor, hasOutlineParam, outlineColor, hasOutlineWidthParam, outlineWidth ); + if( hasFillParam ) + { + m->setFillColor( fillColor ); + } + if( hasOutlineParam ) + { + m->setOutlineColor( outlineColor ); + } + if( hasOutlineWidthParam ) + { + m->setOutlineWidth( outlineWidth ); + } + } + if ( props.contains( "offset" ) ) m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) ); if ( props.contains( "fill" ) ) @@ -481,6 +503,27 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::create( const QgsStringMap& props ) return m; } +void QgsSvgMarkerSymbolLayerV2::setPath( QString path ) +{ + mPath = path; + QColor fillColor, outlineColor; + double outlineWidth; + bool hasFillParam, hasOutlineParam, hasOutlineWidthParam; + QgsSvgCache::instance()->containsParams( path, hasFillParam, fillColor, hasOutlineParam, outlineColor, hasOutlineWidthParam, outlineWidth ); + if( hasFillParam ) + { + setFillColor( fillColor ); + } + if( hasOutlineParam ) + { + setOutlineColor( outlineColor ); + } + if( hasOutlineWidthParam ) + { + setOutlineWidth( outlineWidth ); + } +} + QString QgsSvgMarkerSymbolLayerV2::layerType() const { diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.h b/src/core/symbology-ng/qgsmarkersymbollayerv2.h index 026918c44a26..705721cacc3e 100644 --- a/src/core/symbology-ng/qgsmarkersymbollayerv2.h +++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.h @@ -112,7 +112,7 @@ class CORE_EXPORT QgsSvgMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2 QgsSymbolLayerV2* clone() const; QString path() const { return mPath; } - void setPath( QString path ) { mPath = path; } + void setPath( QString path ); QColor fillColor() const { return mFillColor; } void setFillColor( const QColor& c ) { mFillColor = c; } diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index 2cc039b6836a..f90c76a31434 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -156,9 +156,10 @@ QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, double size, cons return entry; } -void QgsSvgCache::containsParams( const QString& path, bool& hasFillParam, bool& hasOutlineParam, bool& hasOutlineWidthParam ) const +void QgsSvgCache::containsParams( const QString& path, bool& hasFillParam, QColor& defaultFillColor, bool& hasOutlineParam, QColor& defaultOutlineColor, + bool& hasOutlineWidthParam, double& defaultOutlineWidth ) const { - hasFillParam = false; + /*hasFillParam = false; hasOutlineParam = false; hasOutlineWidthParam = false; @@ -187,7 +188,26 @@ void QgsSvgCache::containsParams( const QString& path, bool& hasFillParam, bool& if ( content.contains( "param(outline-width)" ) ) { hasOutlineWidthParam = true; + }*/ + + defaultFillColor = QColor( Qt::black ); + defaultOutlineColor= QColor( Qt::black ); + defaultOutlineWidth = 1.0; + + QFile svgFile( path ); + if ( !svgFile.open( QIODevice::ReadOnly ) ) + { + return; + } + + QDomDocument svgDoc; + if ( !svgDoc.setContent( &svgFile ) ) + { + return; } + + QDomElement docElem = svgDoc.documentElement(); + containsElemParams( docElem, hasFillParam, defaultFillColor, hasOutlineParam, defaultOutlineColor, hasOutlineWidthParam, defaultOutlineWidth ); } void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry* entry ) @@ -377,6 +397,103 @@ void QgsSvgCache::replaceElemParams( QDomElement& elem, const QColor& fill, cons } } +void QgsSvgCache::containsElemParams( const QDomElement& elem, bool& hasFillParam, QColor& defaultFill, bool& hasOutlineParam, QColor& defaultOutline, + bool& hasOutlineWidthParam, double& defaultOutlineWidth ) const +{ + if( elem.isNull() ) + { + return; + } + + //we already have all the information, no need to go deeper + if( hasFillParam && hasOutlineParam && hasOutlineWidthParam ) + { + return; + } + + //check this elements attribute + QDomNamedNodeMap attributes = elem.attributes(); + int nAttributes = attributes.count(); + + QStringList valueSplit; + for ( int i = 0; i < nAttributes; ++i ) + { + QDomAttr attribute = attributes.item( i ).toAttr(); + if ( attribute.name().compare( "style", Qt::CaseInsensitive ) == 0 ) + { + //entries separated by ';' + QStringList entryList = attribute.value().split( ';' ); + QStringList::const_iterator entryIt = entryList.constBegin(); + for ( ; entryIt != entryList.constEnd(); ++entryIt ) + { + valueSplit = entryIt->split(" "); + if( !hasFillParam && entryIt->startsWith( "param(fill)" ) ) + { + hasFillParam = true; + if( valueSplit.size() > 1 ) + { + defaultFill = QColor( valueSplit.at( 1 ) ); + } + } + else if( !hasOutlineParam && entryIt->startsWith( "param(outline)" ) ) + { + hasOutlineParam = true; + if( valueSplit.size() > 1 ) + { + defaultOutline = QColor( valueSplit.at( 1 ) ); + } + } + else if( !hasOutlineWidthParam && entryIt->startsWith( "param(outlineWidth)" ) ) + { + hasOutlineWidthParam = true; + if( valueSplit.size() > 1 ) + { + defaultOutlineWidth = valueSplit.at( 1 ).toDouble(); + } + } + } + } + else + { + QString value = attribute.value(); + valueSplit = value.split(" "); + if ( !hasFillParam && value.startsWith( "param(fill)" ) ) + { + hasFillParam = true; + if( valueSplit.size() > 1 ) + { + defaultFill = QColor( valueSplit.at( 1 ) ); + } + } + else if( !hasOutlineParam && value.startsWith( "param(outline)" ) ) + { + hasOutlineParam = true; + if( valueSplit.size() > 1 ) + { + defaultOutline = QColor( valueSplit.at( 1 ) ); + } + } + else if( !hasOutlineWidthParam && value.startsWith( "param(outlineWidth)" ) ) + { + hasOutlineWidthParam = true; + if( valueSplit.size() > 1 ) + { + defaultOutlineWidth = valueSplit.at( 1 ).toDouble(); + } + } + } + } + + //pass it further to child items + QDomNodeList childList = elem.childNodes(); + int nChildren = childList.count(); + for ( int i = 0; i < nChildren; ++i ) + { + QDomElement childElem = childList.at( i ).toElement(); + containsElemParams( childElem, hasFillParam, defaultFill, hasOutlineParam, defaultOutline, hasOutlineWidthParam, defaultOutlineWidth ); + } +} + void QgsSvgCache::removeCacheEntry( QString s, QgsSvgCacheEntry* entry ) { delete entry; diff --git a/src/core/symbology-ng/qgssvgcache.h b/src/core/symbology-ng/qgssvgcache.h index 1cf93d566178..81af83827c9c 100644 --- a/src/core/symbology-ng/qgssvgcache.h +++ b/src/core/symbology-ng/qgssvgcache.h @@ -70,8 +70,10 @@ class QgsSvgCache const QPicture& svgAsPicture( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor ); - /**Tests if an svg file contains parameters for fill, outline color, outline width*/ - void containsParams( const QString& path, bool& hasFillParam, bool& hasOutlineParam, bool& hasOutlineWidthParam ) const; + /**Tests if an svg file contains parameters for fill, outline color, outline width. If yes, possible default values are returned. If there are several + default values in the svg file, only the first one is considered*/ + void containsParams( const QString& path, bool& hasFillParam, QColor& defaultFillColor, bool& hasOutlineParam, QColor& defaultOutlineColor, bool& hasOutlineWidthParam, + double& defaultOutlineWidth ) const; protected: QgsSvgCache(); @@ -112,6 +114,9 @@ class QgsSvgCache /**Replaces parameters in elements of a dom node and calls method for all child nodes*/ void replaceElemParams( QDomElement& elem, const QColor& fill, const QColor& outline, double outlineWidth ); + void containsElemParams( const QDomElement& elem, bool& hasFillParam, QColor& defaultFill, bool& hasOutlineParam, QColor& defaultOutline, + bool& hasOutlineWidthParam, double& defaultOutlineWidth ) const; + /**Release memory and remove cache entry from mEntryLookup*/ void removeCacheEntry( QString s, QgsSvgCacheEntry* entry ); diff --git a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp index 209efc16379a..2f59aa3e8ce7 100644 --- a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp +++ b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp @@ -576,18 +576,29 @@ void QgsSvgMarkerSymbolLayerV2Widget::populateList() viewImages->setModel( m ); } -void QgsSvgMarkerSymbolLayerV2Widget::setGuiForSvg( const QString& svgPath ) +void QgsSvgMarkerSymbolLayerV2Widget::setGuiForSvg( const QgsSvgMarkerSymbolLayerV2* layer ) { + if( !layer ) + { + return; + } + //activate gui for svg parameters only if supported by the svg file bool hasFillParam, hasOutlineParam, hasOutlineWidthParam; - QgsSvgCache::instance()->containsParams( svgPath, hasFillParam, hasOutlineParam, hasOutlineWidthParam ); + QColor defaultFill, defaultOutline; + double defaultOutlineWidth; + QgsSvgCache::instance()->containsParams( layer->path(), hasFillParam, defaultFill, hasOutlineParam, defaultOutline, hasOutlineWidthParam, defaultOutlineWidth ); mChangeColorButton->setEnabled( hasFillParam ); mChangeBorderColorButton->setEnabled( hasOutlineParam ); mBorderWidthSpinBox->setEnabled( hasOutlineWidthParam ); mFileLineEdit->blockSignals( true ); - mFileLineEdit->setText( svgPath ); + mFileLineEdit->setText( layer->path() ); mFileLineEdit->blockSignals( false ); + + mBorderWidthSpinBox->blockSignals( true ); + mBorderWidthSpinBox->setValue( layer->outlineWidth() ); + mBorderWidthSpinBox->blockSignals( false ); } @@ -628,7 +639,8 @@ void QgsSvgMarkerSymbolLayerV2Widget::setSymbolLayer( QgsSymbolLayerV2* layer ) spinOffsetY->setValue( mLayer->offset().y() ); spinOffsetY->blockSignals( false ); - setGuiForSvg( mLayer->path() ); + setGuiForSvg( mLayer ); + } QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2Widget::symbolLayer() @@ -642,7 +654,7 @@ void QgsSvgMarkerSymbolLayerV2Widget::setName( const QModelIndex& idx ) mLayer->setPath( name ); mFileLineEdit->setText( name ); - setGuiForSvg( name ); + setGuiForSvg( mLayer ); emit changed(); } diff --git a/src/gui/symbology-ng/qgssymbollayerv2widget.h b/src/gui/symbology-ng/qgssymbollayerv2widget.h index e822c3b0958e..59fd25a4c607 100644 --- a/src/gui/symbology-ng/qgssymbollayerv2widget.h +++ b/src/gui/symbology-ng/qgssymbollayerv2widget.h @@ -189,7 +189,7 @@ class GUI_EXPORT QgsSvgMarkerSymbolLayerV2Widget : public QgsSymbolLayerV2Widget void populateList(); //update gui for svg file (insert new path, update activation of gui elements for svg params) - void setGuiForSvg( const QString& svgPath ); + void setGuiForSvg( const QgsSvgMarkerSymbolLayerV2* layer ); QgsSvgMarkerSymbolLayerV2* mLayer; }; From 7e274d81ea6c3786347b2bc714e0589c0aaab6f4 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Wed, 29 Jun 2011 09:20:15 +0200 Subject: [PATCH 11/16] Fix replacement in style attribute --- src/core/symbology-ng/qgssvgcache.cpp | 43 ++++++++++++++++----------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index f90c76a31434..32ced23df73d 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -157,7 +157,7 @@ QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, double size, cons } void QgsSvgCache::containsParams( const QString& path, bool& hasFillParam, QColor& defaultFillColor, bool& hasOutlineParam, QColor& defaultOutlineColor, - bool& hasOutlineWidthParam, double& defaultOutlineWidth ) const + bool& hasOutlineWidthParam, double& defaultOutlineWidth ) const { /*hasFillParam = false; hasOutlineParam = false; @@ -191,7 +191,7 @@ void QgsSvgCache::containsParams( const QString& path, bool& hasFillParam, QColo }*/ defaultFillColor = QColor( Qt::black ); - defaultOutlineColor= QColor( Qt::black ); + defaultOutlineColor = QColor( Qt::black ); defaultOutlineWidth = 1.0; QFile svgFile( path ); @@ -398,15 +398,15 @@ void QgsSvgCache::replaceElemParams( QDomElement& elem, const QColor& fill, cons } void QgsSvgCache::containsElemParams( const QDomElement& elem, bool& hasFillParam, QColor& defaultFill, bool& hasOutlineParam, QColor& defaultOutline, - bool& hasOutlineWidthParam, double& defaultOutlineWidth ) const + bool& hasOutlineWidthParam, double& defaultOutlineWidth ) const { - if( elem.isNull() ) + if ( elem.isNull() ) { return; } //we already have all the information, no need to go deeper - if( hasFillParam && hasOutlineParam && hasOutlineWidthParam ) + if ( hasFillParam && hasOutlineParam && hasOutlineWidthParam ) { return; } @@ -426,27 +426,34 @@ void QgsSvgCache::containsElemParams( const QDomElement& elem, bool& hasFillPara QStringList::const_iterator entryIt = entryList.constBegin(); for ( ; entryIt != entryList.constEnd(); ++entryIt ) { - valueSplit = entryIt->split(" "); - if( !hasFillParam && entryIt->startsWith( "param(fill)" ) ) + QStringList keyValueSplit = entryIt->split( ':' ); + if ( keyValueSplit.size() < 2 ) + { + continue; + } + QString key = keyValueSplit.at( 0 ); + QString value = keyValueSplit.at( 1 ); + valueSplit = value.split( " " ); + if ( !hasFillParam && value.startsWith( "param(fill)" ) ) { hasFillParam = true; - if( valueSplit.size() > 1 ) + if ( valueSplit.size() > 1 ) { defaultFill = QColor( valueSplit.at( 1 ) ); } } - else if( !hasOutlineParam && entryIt->startsWith( "param(outline)" ) ) + else if ( !hasOutlineParam && value.startsWith( "param(outline)" ) ) { hasOutlineParam = true; - if( valueSplit.size() > 1 ) + if ( valueSplit.size() > 1 ) { defaultOutline = QColor( valueSplit.at( 1 ) ); } } - else if( !hasOutlineWidthParam && entryIt->startsWith( "param(outlineWidth)" ) ) + else if ( !hasOutlineWidthParam && value.startsWith( "param(outlineWidth)" ) ) { hasOutlineWidthParam = true; - if( valueSplit.size() > 1 ) + if ( valueSplit.size() > 1 ) { defaultOutlineWidth = valueSplit.at( 1 ).toDouble(); } @@ -456,27 +463,27 @@ void QgsSvgCache::containsElemParams( const QDomElement& elem, bool& hasFillPara else { QString value = attribute.value(); - valueSplit = value.split(" "); + valueSplit = value.split( " " ); if ( !hasFillParam && value.startsWith( "param(fill)" ) ) { hasFillParam = true; - if( valueSplit.size() > 1 ) + if ( valueSplit.size() > 1 ) { defaultFill = QColor( valueSplit.at( 1 ) ); } } - else if( !hasOutlineParam && value.startsWith( "param(outline)" ) ) + else if ( !hasOutlineParam && value.startsWith( "param(outline)" ) ) { hasOutlineParam = true; - if( valueSplit.size() > 1 ) + if ( valueSplit.size() > 1 ) { defaultOutline = QColor( valueSplit.at( 1 ) ); } } - else if( !hasOutlineWidthParam && value.startsWith( "param(outlineWidth)" ) ) + else if ( !hasOutlineWidthParam && value.startsWith( "param(outlineWidth)" ) ) { hasOutlineWidthParam = true; - if( valueSplit.size() > 1 ) + if ( valueSplit.size() > 1 ) { defaultOutlineWidth = valueSplit.at( 1 ).toDouble(); } From 0a15a072ea7790af2a1b6e6f067a9fba19e2338b Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Wed, 29 Jun 2011 10:00:53 +0200 Subject: [PATCH 12/16] Replace svg params also for preview --- src/gui/symbology-ng/qgssymbollayerv2widget.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp index 2f59aa3e8ce7..8b41cd1e97ba 100644 --- a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp +++ b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp @@ -538,20 +538,17 @@ class QgsSvgListModel : public QAbstractListModel if ( role == Qt::DecorationRole ) // icon { - QPixmap pixmap; if ( !QPixmapCache::find( entry, pixmap ) ) { // render SVG file - QSvgRenderer renderer; - QPainter painter; - renderer.load( entry ); - pixmap = QPixmap( QSize( 24, 24 ) ); - pixmap.fill(); - painter.begin( &pixmap ); - renderer.render( &painter ); - painter.end(); + QColor fill, outline; + double outlineWidth; + bool fillParam, outlineParam, outlineWidthParam; + QgsSvgCache::instance()->containsParams( entry, fillParam, fill, outlineParam, outline, outlineWidthParam, outlineWidth ); + const QImage& img = QgsSvgCache::instance()->svgAsImage( entry, 8, fill, outline, outlineWidth, 3.5 /*appr. 88 dpi*/, 1.0 ); + pixmap = QPixmap::fromImage( img ); QPixmapCache::insert( entry, pixmap ); } From 3ca74587eb6dcc3e930daf9938311b685b902fc0 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Wed, 29 Jun 2011 11:42:26 +0200 Subject: [PATCH 13/16] Added svg parameters to marker files --- images/svg/geometric/Square1.svg | 4 ++-- images/svg/geometric/Square2.svg | 6 +++--- images/svg/geometric/Triangle1.svg | 4 ++-- images/svg/transport/amenity=airport.svg | 2 +- .../svg/transport/amenity=ferry_terminal.svg | 4 ++-- images/svg/transport/amenity=taxi.svg | 18 +++++++++--------- .../symbology-ng/qgsmarkersymbollayerv2.cpp | 2 +- src/core/symbology-ng/qgssvgcache.cpp | 4 ++-- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/images/svg/geometric/Square1.svg b/images/svg/geometric/Square1.svg index 56213861672f..d10de261233e 100644 --- a/images/svg/geometric/Square1.svg +++ b/images/svg/geometric/Square1.svg @@ -1,8 +1,8 @@ - + + ]> diff --git a/images/svg/geometric/Square2.svg b/images/svg/geometric/Square2.svg index cb88690dc78a..f4e3ac55ae49 100644 --- a/images/svg/geometric/Square2.svg +++ b/images/svg/geometric/Square2.svg @@ -1,9 +1,9 @@ - - + + + ]> diff --git a/images/svg/geometric/Triangle1.svg b/images/svg/geometric/Triangle1.svg index 4ba3ad2a9657..e84dc200e46c 100644 --- a/images/svg/geometric/Triangle1.svg +++ b/images/svg/geometric/Triangle1.svg @@ -1,8 +1,8 @@ - + + ]> diff --git a/images/svg/transport/amenity=airport.svg b/images/svg/transport/amenity=airport.svg index 75cb00d71478..8cc0cadec91f 100644 --- a/images/svg/transport/amenity=airport.svg +++ b/images/svg/transport/amenity=airport.svg @@ -86,7 +86,7 @@ inkscape:groupmode="layer" sodipodi:insensitive="true"> diff --git a/images/svg/transport/amenity=taxi.svg b/images/svg/transport/amenity=taxi.svg index 33bc6ae5fa43..a7bd7ac75d8d 100644 --- a/images/svg/transport/amenity=taxi.svg +++ b/images/svg/transport/amenity=taxi.svg @@ -85,7 +85,7 @@ inkscape:groupmode="layer" sodipodi:insensitive="true"> + style="fill:param(fill) #6c7be1;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="fill:param(fill) #6c7be1;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp index eb01ef345485..2adb7750ef7b 100644 --- a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp +++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp @@ -609,7 +609,7 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::clone() const QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( mPath, mSize, mAngle ); m->setFillColor( mFillColor ); m->setOutlineColor( mOutlineColor ); - m->setOutlineWidth( 1.0 ); + m->setOutlineWidth( mOutlineWidth ); m->setOffset( mOffset ); return m; } diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index 32ced23df73d..3f7cb2e93aeb 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -450,7 +450,7 @@ void QgsSvgCache::containsElemParams( const QDomElement& elem, bool& hasFillPara defaultOutline = QColor( valueSplit.at( 1 ) ); } } - else if ( !hasOutlineWidthParam && value.startsWith( "param(outlineWidth)" ) ) + else if ( !hasOutlineWidthParam && value.startsWith( "param(outline-width)" ) ) { hasOutlineWidthParam = true; if ( valueSplit.size() > 1 ) @@ -480,7 +480,7 @@ void QgsSvgCache::containsElemParams( const QDomElement& elem, bool& hasFillPara defaultOutline = QColor( valueSplit.at( 1 ) ); } } - else if ( !hasOutlineWidthParam && value.startsWith( "param(outlineWidth)" ) ) + else if ( !hasOutlineWidthParam && value.startsWith( "param(outline-width)" ) ) { hasOutlineWidthParam = true; if ( valueSplit.size() > 1 ) From 93158e78ad99e06004b466fb847e30aa8c9e5b79 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Wed, 29 Jun 2011 12:01:00 +0200 Subject: [PATCH 14/16] Small fix for svg parameter replacement --- src/core/symbology-ng/qgssvgcache.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/symbology-ng/qgssvgcache.cpp b/src/core/symbology-ng/qgssvgcache.cpp index 3f7cb2e93aeb..6c53d06f7037 100644 --- a/src/core/symbology-ng/qgssvgcache.cpp +++ b/src/core/symbology-ng/qgssvgcache.cpp @@ -366,7 +366,12 @@ void QgsSvgCache::replaceElemParams( QDomElement& elem, const QColor& fill, cons { value = QString::number( outlineWidth ); } - newAttributeString.append( key + ":" + value + ";" ); + + if( entryIt != entryList.constBegin() ) + { + newAttributeString.append(";"); + } + newAttributeString.append( key + ":" + value ); } elem.setAttribute( attribute.name(), newAttributeString ); } From ae6fb04fea1388b9c37dfde3882cace0d2496b42 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Wed, 29 Jun 2011 17:23:21 +0200 Subject: [PATCH 15/16] small tweak to svg file --- images/svg/transport/amenity=ferry_terminal.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/svg/transport/amenity=ferry_terminal.svg b/images/svg/transport/amenity=ferry_terminal.svg index 91ae59e61cc8..a21343b1e097 100644 --- a/images/svg/transport/amenity=ferry_terminal.svg +++ b/images/svg/transport/amenity=ferry_terminal.svg @@ -112,7 +112,7 @@ inkscape:radius="0.2593877" inkscape:original="M 5.6875 7.90625 C 5.5920634 7.9309548 5.5014714 7.992784 5.4375 8.0625 C 5.3834383 8.1054353 5.3452352 8.156256 5.3125 8.21875 C 5.2751819 8.2899943 5.2505865 8.358769 5.25 8.4375 C 4.8692988 9.3217403 3.8654515 9.754957 2.9375 9.4375 C 2.3600674 9.2399573 2.0133307 8.888797 1.8125 8.3125 C 1.7762243 8.1833713 1.6800247 8.064639 1.5625 8 C 1.4449753 7.9353608 1.3159791 7.930236 1.1875 7.96875 C 1.0509325 8.0042168 0.94047034 8.093761 0.875 8.21875 C 0.80952963 8.3437393 0.7951452 8.492538 0.84375 8.625 C 1.1358785 9.4632823 1.7850673 10.118904 2.625 10.40625 C 3.7925772 10.805684 5.0496938 10.384963 5.78125 9.46875 C 6.1159315 9.8869593 6.5407536 10.227757 7.0625 10.40625 C 8.2300772 10.805684 9.4871943 10.384963 10.21875 9.46875 C 10.554718 9.8945333 11.00308 10.22556 11.53125 10.40625 C 13.016117 10.914231 14.648269 10.109868 15.15625 8.625 C 15.246612 8.4497623 15.216803 8.247801 15.09375 8.09375 C 14.970696 7.9396993 14.784624 7.856841 14.59375 7.90625 C 14.402877 7.9556588 14.251603 8.118092 14.21875 8.3125 C 13.885904 9.2854333 12.816683 9.770345 11.84375 9.4375 C 11.288851 9.2476663 10.95406 8.912026 10.75 8.375 C 10.746634 8.3661403 10.753292 8.352722 10.75 8.34375 C 10.748598 8.3296273 10.721349 8.326464 10.71875 8.3125 C 10.700612 8.2479353 10.665883 8.176507 10.625 8.125 C 10.619359 8.1170203 10.631153 8.101453 10.625 8.09375 C 10.501947 7.9396993 10.315873 7.856841 10.125 7.90625 C 10.038142 7.9287338 9.9676439 8.002081 9.90625 8.0625 C 9.873203 8.0950223 9.8354674 8.11568 9.8125 8.15625 C 9.7985624 8.1755263 9.7924279 8.19741 9.78125 8.21875 C 9.7690359 8.2501023 9.7557493 8.278479 9.75 8.3125 C 9.7391707 8.3441543 9.7311091 8.375641 9.71875 8.40625 C 9.3512297 9.3164703 8.3162794 9.759516 7.375 9.4375 C 6.8292558 9.2507983 6.4864361 8.92777 6.28125 8.40625 C 6.2852911 8.2892103 6.2635036 8.188899 6.1875 8.09375 C 6.0644462 7.9396993 5.8783733 7.856841 5.6875 7.90625 z " xlink:href="#path3173" - style="opacity:1;fill:param(fill) #6c7be1;fill-opacity:1;stroke:#6c7be1;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:param(fill) #6c7be1;fill-opacity:1;stroke:param(outline) #6c7be1;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path3195" d="M 5.625,7.65625 C 5.4763275,7.6947355 5.3734452,7.7800534 5.28125,7.875 L 5.28125,7.90625 C 5.2060789,7.9712328 5.1344978,8.0159593 5.09375,8.09375 C 5.0594627,8.1592083 5.0469067,8.2556613 5.03125,8.34375 L 5,8.34375 C 4.6726226,9.1041371 3.8366127,9.4630187 3.03125,9.1875 C 2.522755,9.0135412 2.2433025,8.7502184 2.0625,8.25 C 2.0601678,8.2416982 2.0650857,8.2269203 2.0625,8.21875 L 2.03125,8.21875 C 1.9677373,8.0349231 1.8568108,7.8743715 1.6875,7.78125 C 1.5048211,7.6807757 1.3052853,7.6647061 1.125,7.71875 C 0.91856052,7.7723627 0.75373758,7.9076371 0.65625,8.09375 C 0.5587628,8.2798625 0.51780423,8.511776 0.59375,8.71875 C 0.91134529,9.630111 1.6157155,10.34304 2.53125,10.65625 C 3.7167015,11.061799 4.9677669,10.670186 5.78125,9.8125 C 6.1124315,10.170715 6.4807826,10.489313 6.96875,10.65625 C 8.1542015,11.061799 9.4052672,10.670186 10.21875,9.8125 C 10.558335,10.173453 10.951728,10.490065 11.4375,10.65625 C 13.042743,11.205412 14.805018,10.341887 15.375,8.75 C 15.379988,8.7360678 15.401445,8.7327942 15.40625,8.71875 L 15.375,8.71875 C 15.496195,8.4566291 15.454428,8.1543027 15.28125,7.9375 C 15.106922,7.7192596 14.829823,7.5789624 14.53125,7.65625 C 14.261853,7.7259852 14.070939,7.9515882 14,8.21875 L 13.96875,8.21875 C 13.682428,9.0556891 12.782362,9.4765314 11.9375,9.1875 C 11.451007,9.0210684 11.182559,8.7763651 11,8.3125 C 10.998762,8.3000327 11.002886,8.2927802 11,8.28125 C 10.996848,8.2661849 11.007106,8.2693665 11,8.25 L 10.96875,8.25 C 10.958653,8.2140592 10.920825,8.1903391 10.90625,8.15625 C 10.894022,8.1452989 10.914116,8.1304823 10.90625,8.125 C 10.896266,8.1038485 10.887167,8.0830169 10.875,8.0625 C 10.872261,8.0481204 10.874775,8.0306958 10.875,8.03125 C 10.87509,8.0314717 10.880368,8.0098028 10.875,8 C 10.868052,7.9855734 10.853037,7.9878089 10.84375,7.96875 C 10.834463,7.9496911 10.812796,7.9378703 10.8125,7.9375 C 10.638172,7.7192576 10.361073,7.5789619 10.0625,7.65625 C 9.8761163,7.7044967 9.7760966,7.818564 9.71875,7.875 C 9.7173249,7.8764025 9.6747534,7.9364188 9.625,8 C 9.6110069,8.0178822 9.6078818,8.0062873 9.59375,8.03125 C 9.5754361,8.0641374 9.5593201,8.0998207 9.5625,8.09375 C 9.5512134,8.1032588 9.5407588,8.1137134 9.53125,8.125 C 9.526121,8.1381656 9.5107896,8.1852792 9.5,8.21875 C 9.4932565,8.2396692 9.5049005,8.2522517 9.5,8.28125 C 9.4970636,8.2906039 9.4703095,8.3086377 9.46875,8.3125 C 9.1535855,9.0930532 8.2859911,9.4670819 7.46875,9.1875 C 6.9782268,9.0196897 6.7137576,8.7763783 6.53125,8.3125 L 6.5,8.3125 C 6.4889568,8.1819112 6.4681208,8.0540781 6.375,7.9375 C 6.2006717,7.7192589 5.9235731,7.5789621 5.625,7.65625 z" transform="translate(3.125e-2,3.4509804)" /> From 4546646f1dd03c899ad505df7afcea51e4e30e62 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Thu, 30 Jun 2011 09:09:18 +0200 Subject: [PATCH 16/16] Adapt svg param elements also if going via the line edit --- src/gui/symbology-ng/qgssymbollayerv2widget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp index 8b41cd1e97ba..4147de5d5ba6 100644 --- a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp +++ b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp @@ -695,6 +695,7 @@ void QgsSvgMarkerSymbolLayerV2Widget::on_mFileLineEdit_textEdited( const QString return; } mLayer->setPath( text ); + setGuiForSvg( mLayer ); emit changed(); }