765 changes: 390 additions & 375 deletions src/core/symbology-ng/qgscptcityarchive.cpp

Large diffs are not rendered by default.

59 changes: 27 additions & 32 deletions src/core/symbology-ng/qgscptcityarchive.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,63 +37,45 @@ class CORE_EXPORT QgsCptCityArchive
QString baseDir = QString() );
~QgsCptCityArchive();

// basic dir info
QString baseDir() const;
static QString baseDir( QString archiveName );
static QString defaultBaseDir();
void setBaseDir( QString dirName ) { mBaseDir = dirName; }
bool loadSchemes( QString rootDir = "", bool reset = false );
/** Is the minimal (free to distribute) set of schemes available?
* Currently returns hasAllSchemes, because we don't have a minimal set yet. */
/* bool hasBasicSchemes(); */
/** Is the entire archive available? Currently tests that there is at least one scheme. */
/* bool hasAllSchemes(); */
bool isEmpty();

QStringList listDirNames( QString dirName = "", bool recursive = false );
QStringList listSchemeNames( QString dirName );
QgsCptCityArchive* colorRampFromSVGFile( QString svgFile );
QgsCptCityArchive* colorRampFromSVGString( QString svgString );

// collection + selection info
QString copyingFileName( const QString& dirName ) const;
QString descFileName( const QString& dirName ) const;
static QString findFileName( const QString & target, const QString & startDir, const QString & baseDir );
static QMap< QString, QString > copyingInfo( const QString& copyingFileName );
static QMap< QString, QString > copyingInfo( const QString& fileName );
static QMap< QString, QString > description( const QString& fileName );
static QMap< double, QPair<QColor, QColor> > gradientColorMap( const QString& fileName );

// archive management
bool isEmpty();
QString archiveName() const { return mArchiveName; }
QMap< QString, QStringList > schemeMap() const { return mSchemeMap; }
QMap< QString, QStringList > schemeVariants() const { return mSchemeVariants; }
QMap< QString, QString > dirNamesMap() const { return mDirNamesMap; }
QMap< QString, QStringList > selectionsMap() const { return mSelectionsMap; }
QVector< QgsCptCityDataItem* > rootItems() const { return mRootItems; }
QVector<QgsCptCityDataItem*> selectionItems() const { return mSelectionItems; }

static void initArchives( bool loadAll = false );
static void initArchive( QString archiveName, QString archiveBaseDir );
static void clearArchives();
static QgsCptCityArchive* defaultArchive();
static QString defaultArchiveName();
static QMap< QString, QgsCptCityArchive* > archiveRegistry();

// items
QVector< QgsCptCityDataItem* > rootItems() const { return mRootItems; }
QVector<QgsCptCityDataItem*> selectionItems() const { return mSelectionItems; }

protected:

QString mArchiveName;
QString mBaseDir;
QStringList mDirNames;
QMap< QString, QStringList > mSchemeMap; //key is archive, value is schemes
QMap< QString, QStringList > mSchemeVariants; //key is scheme, value is variants
QMap< QString, QString > mDirNamesMap; //key is name, value is description
QMap< QString, QStringList > mSelectionsMap;
static QString mDefaultArchiveName;
static QMap< QString, QgsCptCityArchive* > mArchiveRegistry;
static QMap< QString, QMap< QString, QString > > mCopyingInfoMap; // mapping of copyinginfo, key is fileName

// new stuff

// root items, namely directories at root of archive
QVector< QgsCptCityDataItem* > mRootItems;
// map of selections, each one corresponds to an .xml file
/* QMap< QString, QVector<QgsCptCitySelectionItem*> > mSelections; */
QVector<QgsCptCityDataItem*> mSelectionItems;
// mapping of copyinginfo, key is fileName
static QMap< QString, QMap< QString, QString > > mCopyingInfoMap;

};

Expand All @@ -107,7 +89,7 @@ class CORE_EXPORT QgsCptCityDataItem : public QObject
ColorRamp,
Collection,
Directory,
Category
Selection
};

QgsCptCityDataItem( QgsCptCityDataItem::Type type, QgsCptCityDataItem* parent,
Expand Down Expand Up @@ -213,6 +195,10 @@ class CORE_EXPORT QgsCptCityColorRampItem : public QgsCptCityDataItem
QString name, QString path, QString info = QString(),
QString variantName = QString() );

QgsCptCityColorRampItem( QgsCptCityDataItem* parent,
QString name, QString path, QString info,
QStringList variantList );

// --- reimplemented from QgsCptCityDataItem ---

virtual bool equal( const QgsCptCityDataItem *other );
Expand All @@ -222,6 +208,7 @@ class CORE_EXPORT QgsCptCityColorRampItem : public QgsCptCityDataItem

protected:

void init();
QgsCptCityColorRampV2 mRamp;
QIcon mIcon;
};
Expand Down Expand Up @@ -254,6 +241,8 @@ class CORE_EXPORT QgsCptCityDirectoryItem : public QgsCptCityCollectionItem

virtual bool equal( const QgsCptCityDataItem *other );

protected:
QMap< QString, QStringList > gradientsMap();
};

/** A selection: contains subdirectories and color ramps */
Expand All @@ -267,6 +256,12 @@ class CORE_EXPORT QgsCptCitySelectionItem : public QgsCptCityCollectionItem
QVector<QgsCptCityDataItem*> createChildren();

virtual bool equal( const QgsCptCityDataItem *other );

QStringList selectionsList() const { return mSelectionsList; }

protected:
void parseXML();
QStringList mSelectionsList;
};


Expand Down
159 changes: 21 additions & 138 deletions src/core/symbology-ng/qgsvectorcolorrampv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,18 @@ QgsCptCityColorRampV2::QgsCptCityColorRampV2( QString schemeName, QString varian
: mSchemeName( schemeName ), mVariantName( variantName ),
mGradientType( Continuous ), mFileLoaded( false )
{
QgsCptCityArchive* archive = QgsCptCityArchive::defaultArchive();
if ( archive )
mVariantList = archive->schemeVariants().value( schemeName );
// TODO replace this with hard-coded data in the default case
// don't load file if variant is missing
if ( variantName != QString() || mVariantList.isEmpty() )
loadFile();
}

QgsCptCityColorRampV2::QgsCptCityColorRampV2( QString schemeName, QStringList variantList,
QString variantName )
: mSchemeName( schemeName ), mVariantName( variantName ),
mGradientType( Continuous ), mFileLoaded( false )
{
mVariantList = variantList;

// TODO replace this with hard-coded data in the default case
// don't load file if variant is missing
Expand All @@ -305,53 +314,6 @@ QgsVectorColorRampV2* QgsCptCityColorRampV2::create( const QgsStringMap& props )
return new QgsCptCityColorRampV2( schemeName, variantName );
}


#if 0
QColor QgsCptCityColorRampV2::color( double value ) const
{
if ( mPalette.isEmpty() || value < 0 || value > 1 )
return QColor( 255, 0, 0 ); // red color as a warning :)

if ( ! mContinuous )
{
int paletteEntry = ( int )( value * mPalette.count() );
if ( paletteEntry >= mPalette.count() )
paletteEntry = mPalette.count() - 1;

return mPalette.at( paletteEntry );
}
else
{
int numStops = mPalette.count();
if ( numStops < 2 )
return QColor( 255, 0, 0 ); // red color as a warning :)

StopsMap mStops; // TODO integrate in main class
for ( int i = 0; i < numStops; i++ )
mStops[ mPaletteStops[i] ] = mPalette[i];

double lower = 0, upper;
QColor c1 = mPalette[1], c2;
for ( StopsMap::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
{
if ( it.key() >= value )
{
upper = it.key();
c2 = it.value();

return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
}
lower = it.key();
c1 = it.value();
}

upper = 1;
c2 = mPalette[ numStops - 1 ];
return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
}
}
#endif

QColor QgsCptCityColorRampV2::color( double value ) const
{
int numStops = mPalette.count();
Expand Down Expand Up @@ -446,102 +408,23 @@ bool QgsCptCityColorRampV2::loadFile()

QgsDebugMsg( QString( "filename= %1 loaded=%2" ).arg( filename ).arg( mFileLoaded ) );

mFileLoaded = false;
mPalette.clear();

// import xml file
QFile f( filename );
if ( !f.open( QFile::ReadOnly ) )
{
QgsDebugMsg( "Couldn't open SVG file: " + filename );
return false;
}

// parse the document
QDomDocument doc( "gradient" );
if ( !doc.setContent( &f ) )
{
f.close();
QgsDebugMsg( "Couldn't parse SVG file: " + filename );
return false;
}
f.close();

QDomElement docElem = doc.documentElement();

if ( docElem.tagName() != "svg" )
{
QgsDebugMsg( "Incorrect root tag: " + docElem.tagName() );
return false;
}

// load color ramp from first linearGradient node
QDomElement rampsElement = docElem.firstChildElement( "linearGradient" );
if ( rampsElement.isNull() )
{
QDomNodeList nodeList = docElem.elementsByTagName( "linearGradient" );
if ( ! nodeList.isEmpty() )
rampsElement = nodeList.at( 0 ).toElement();
}
if ( rampsElement.isNull() )
{
QgsDebugMsg( "linearGradient tag missing" );
return false;
}

// loop for all stop tags
QDomElement e = rampsElement.firstChildElement();
QMap< double, QPair<QColor, QColor> > map;

QColor prevColor;
while ( !e.isNull() )
{
if ( e.tagName() == "stop" )
{
//todo integrate this into symbollayerutils, keep here for now...
double offset;
QString offsetStr = e.attribute( "offset" ); // offset="50.00%" | offset="0.5"
QString colorStr = e.attribute( "stop-color", "" ); // stop-color="rgb(222,235,247)"
QString opacityStr = e.attribute( "stop-opacity", "1.0" ); // stop-opacity="1.0000"
if ( offsetStr.endsWith( "%" ) )
offset = offsetStr.remove( offsetStr.size() - 1, 1 ).toDouble() / 100.0;
else
offset = offsetStr.toDouble();

// QColor color( 255, 0, 0 ); // red color as a warning :)
QColor color = QgsSymbolLayerV2Utils::parseColor( colorStr );
if ( color != QColor() )
{
int alpha = opacityStr.toDouble() * 255; // test
color.setAlpha( alpha );
if ( map.contains( offset ) )
map[offset].second = color;
else
map[offset] = qMakePair( color, color );
}
else
QgsDebugMsg( QString( "at offset=%1 invalid color" ).arg( offset ) );
}
else
{
QgsDebugMsg( "unknown tag: " + e.tagName() );
}

e = e.nextSiblingElement();
}
// get color ramp from svg file
QMap< double, QPair<QColor, QColor> > colorMap =
QgsCptCityArchive::gradientColorMap( filename );

// add colors to palette
mFileLoaded = false;
mPalette.clear();
QMap<double, QPair<QColor, QColor> >::const_iterator it, prev;
// first detect if file is gradient is continuous or dicrete
// discrete: stop contains 2 colors and first color is identical to previous second
// multi: stop contains 2 colors and no relation with previous stop
mGradientType = Continuous;
it = prev = map.constBegin();
while ( it != map.constEnd() )
it = prev = colorMap.constBegin();
while ( it != colorMap.constEnd() )
{
// look for stops that contain multiple values
if ( it != map.constBegin() && ( it.value().first != it.value().second ) )
if ( it != colorMap.constBegin() && ( it.value().first != it.value().second ) )
{
if ( it.value().first == prev.value().second )
{
Expand All @@ -558,8 +441,8 @@ bool QgsCptCityColorRampV2::loadFile()
++it;
}

it = prev = map.constBegin();
while ( it != map.constEnd() )
it = prev = colorMap.constBegin();
while ( it != colorMap.constEnd() )
{
if ( mGradientType == Discrete )
{
Expand Down
5 changes: 3 additions & 2 deletions src/core/symbology-ng/qgsvectorcolorrampv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ class CORE_EXPORT QgsCptCityColorRampV2 : public QgsVectorColorRampV2
public:
QgsCptCityColorRampV2( QString schemeName = DEFAULT_CPTCITY_SCHEMENAME,
QString variantName = DEFAULT_CPTCITY_VARIANTNAME );
QgsCptCityColorRampV2( QString schemeName, QStringList variantList, QString variantName = QString() );


enum GradientType
Expand Down Expand Up @@ -202,8 +203,8 @@ class CORE_EXPORT QgsCptCityColorRampV2 : public QgsVectorColorRampV2
/* lazy loading - have to call loadPalette() explicitly */
void setSchemeName( QString schemeName ) { mSchemeName = schemeName; mFileLoaded = false; }
void setVariantName( QString variantName ) { mVariantName = variantName; mFileLoaded = false; }
void setName( QString schemeName, QString variantName = "" )
{ mSchemeName = schemeName; mVariantName = variantName; mFileLoaded = false; }
void setName( QString schemeName, QString variantName = "", QStringList variantList = QStringList() )
{ mSchemeName = schemeName; mVariantName = variantName; mVariantList = variantList; mFileLoaded = false; }

void loadPalette() { loadFile(); }
/* bool isContinuous() const { return mContinuous; } */
Expand Down
17 changes: 7 additions & 10 deletions src/gui/symbology-ng/qgscptcitycolorrampv2dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ TODO
- try to keep file reads at a minimum -> when selecting an item in the browser copy its ramp over to mRamp
- collapse all button
- show information from dir when selected
- when browsing by selections, remove dir from scheme name
- show type when there are variants - based on the first file
Expand All @@ -42,14 +41,14 @@ TODO
- when collection has only 1 item (e.g. es_skywalker), bring up one level
*/

QgsCptCityColorRampV2Dialog::QgsCptCityColorRampV2Dialog( QgsCptCityColorRampV2* ramp, QWidget* parent )
: QDialog( parent ), mRamp( ramp )
{
setupUi( this );
mAuthorsModel = mSelectionsModel = 0;
}


void QgsCptCityColorRampV2Dialog::populateVariants( QString newVariant )
{
QStringList variantList;
Expand All @@ -70,7 +69,7 @@ void QgsCptCityColorRampV2Dialog::populateVariants( QString newVariant )
else
{
QString oldVariant = cboVariantName->currentText();
QgsCptCityColorRampV2 ramp( mRamp->schemeName(), QString() );
QgsCptCityColorRampV2 ramp( mRamp->schemeName(), mRamp->variantList(), QString() );
QPixmap blankPixmap( cboVariantName->iconSize() );
blankPixmap.fill( Qt::white );
QIcon blankIcon( blankPixmap );
Expand Down Expand Up @@ -129,7 +128,7 @@ void QgsCptCityColorRampV2Dialog::on_mBrowserView_clicked( const QModelIndex &in
if ( item->type() == QgsCptCityDataItem::ColorRamp )
{
lblSchemeName->setText( item->name() );
mRamp->setSchemeName( item->path() );
mRamp->setName( item->path() );
populateVariants();
}
else if ( item->type() == QgsCptCityDataItem::Directory )
Expand All @@ -139,6 +138,7 @@ void QgsCptCityColorRampV2Dialog::on_mBrowserView_clicked( const QModelIndex &in
populateVariants();
lblSchemePath->setText( item->path() );
updateCopyingInfo( mArchive->copyingInfo( mArchive->copyingFileName( item->path() ) ) );
// updateCopyingInfo( item->copyingInfo() );
}
}

Expand Down Expand Up @@ -183,24 +183,21 @@ void QgsCptCityColorRampV2Dialog::on_pbtnLicenseDetails_pressed()
// get basic information, depending on if is color ramp or directory
QgsCptCityDataItem *item =
dynamic_cast< QgsCptCityDataItem* >( mModel->dataItem( mBrowserView->currentIndex() ) );
path = item->path();
if ( item && item->type() == QgsCptCityDataItem::Directory )
{
path = item->path();
title = tr( "%1 directory details" ).arg( item->name() );
copyFile = mArchive->copyingFileName( path );
descFile = mArchive->descFileName( path );
}
else if ( item )
{
path = mRamp->schemeName() + mRamp->variantName();
title = tr( "%1 gradient details" ).arg( path );
copyFile = mRamp->copyingFileName();
descFile = mRamp->descFileName();
}
else
{
return;
}
copyFile = mArchive->copyingFileName( path );
descFile = mArchive->descFileName( path );

// prepare dialog
QgsDialog dlg( this, 0, QDialogButtonBox::Close );
Expand Down