Skip to content

Commit

Permalink
Support dropping multiple colors into a color list widget
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Aug 17, 2014
1 parent ea75259 commit 6d10ff3
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 27 deletions.
15 changes: 13 additions & 2 deletions python/core/symbology-ng/qgssymbollayerv2utils.sip
Expand Up @@ -191,24 +191,35 @@ class QgsSymbolLayerV2Utils
static QgsVectorColorRampV2* loadColorRamp( QDomElement& element ) /Factory/;
static QDomElement saveColorRamp( QString name, QgsVectorColorRampV2* ramp, QDomDocument& doc );

/**
* Attempts to parse a string as a list of colors using a variety of common formats, including hex
* codes, rgb and rgba strings.
* @param colorStr string representing the color list
* @returns list of parsed colors
* @note added in 2.5
*/
static QList< QColor > parseColorList( const QString colorStr );

/**
* Attempts to parse a string as a color using a variety of common formats, including hex
* codes, rgb and rgba strings.
* @param colorStr string representing the color
* @param strictEval set to true for stricter color parsing rules
* @returns parsed color
* @note added in 2.3
*/
static QColor parseColor( QString colorStr );
static QColor parseColor( QString colorStr, bool strictEval = false );

/**
* Attempts to parse a string as a color using a variety of common formats, including hex
* codes, rgb and rgba strings.
* @param colorStr string representing the color
* @param containsAlpha if colorStr contains an explicit alpha value then containsAlpha will be set to true
* @param strictEval set to true for stricter color parsing rules
* @returns parsed color
* @note added in 2.3
*/
static QColor parseColorWithAlpha( const QString colorStr, bool &containsAlpha );
static QColor parseColorWithAlpha( const QString colorStr, bool &containsAlpha, bool strictEval = false );

/**Returns the line width scale factor depending on the unit and the paint device*/
static double lineWidthScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale& scale = QgsMapUnitScale() );
Expand Down
1 change: 0 additions & 1 deletion src/core/qgscolorscheme.cpp
Expand Up @@ -213,7 +213,6 @@ bool QgsProjectColorScheme::setColors( const QgsNamedColorList colors, const QSt
Q_UNUSED( baseColor );

// save colors to project
QSettings settings;
QStringList customColors;
QStringList customColorLabels;

Expand Down
76 changes: 65 additions & 11 deletions src/core/symbology-ng/qgssymbollayerv2utils.cpp
Expand Up @@ -2732,13 +2732,64 @@ QDomElement QgsSymbolLayerV2Utils::saveColorRamp( QString name, QgsVectorColorRa
return rampEl;
}

QColor QgsSymbolLayerV2Utils::parseColor( QString colorStr )
QList<QColor> QgsSymbolLayerV2Utils::parseColorList( const QString colorStr )
{
QList<QColor> colors;

//try splitting string at newlines
QStringList components = colorStr.split( QRegExp( "\n" ) );
QStringList::iterator it = components.begin();
for ( ; it != components.end(); ++it )
{
QColor result = parseColor( *it, true );
if ( result.isValid() )
{
colors << result;
}
}
if ( colors.length() > 0 )
{
return colors;
}

//try splitting string at whitespace
components = colorStr.simplified().split( QString( " " ) );
it = components.begin();
for ( ; it != components.end(); ++it )
{
QColor result = parseColor( *it, true );
if ( result.isValid() )
{
colors << result;
}
}
if ( colors.length() > 0 )
{
return colors;
}

//try splitting string at commas
components = colorStr.split( QString( "," ) );
it = components.begin();
for ( ; it != components.end(); ++it )
{
QColor result = parseColor( *it, true );
if ( result.isValid() )
{
colors << result;
}
}

return colors;
}

QColor QgsSymbolLayerV2Utils::parseColor( QString colorStr , bool strictEval )
{
bool hasAlpha;
return parseColorWithAlpha( colorStr, hasAlpha );
return parseColorWithAlpha( colorStr, hasAlpha, strictEval );
}

QColor QgsSymbolLayerV2Utils::parseColorWithAlpha( const QString colorStr, bool &containsAlpha )
QColor QgsSymbolLayerV2Utils::parseColorWithAlpha( const QString colorStr, bool &containsAlpha, bool strictEval )
{
QColor parsedColor;

Expand All @@ -2754,16 +2805,19 @@ QColor QgsSymbolLayerV2Utils::parseColorWithAlpha( const QString colorStr, bool
}
}

//color in hex format, without #
QRegExp hexColorRx2( "^\\s*(?:[0-9a-fA-F]{3}){1,2}\\s*$" );
if ( hexColorRx2.indexIn( colorStr ) != -1 )
if ( !strictEval )
{
//add "#" and parse
parsedColor.setNamedColor( QString( "#" ) + colorStr );
if ( parsedColor.isValid() )
//color in hex format, without #
QRegExp hexColorRx2( "^\\s*(?:[0-9a-fA-F]{3}){1,2}\\s*$" );
if ( hexColorRx2.indexIn( colorStr ) != -1 )
{
containsAlpha = false;
return parsedColor;
//add "#" and parse
parsedColor.setNamedColor( QString( "#" ) + colorStr );
if ( parsedColor.isValid() )
{
containsAlpha = false;
return parsedColor;
}
}
}

Expand Down
15 changes: 13 additions & 2 deletions src/core/symbology-ng/qgssymbollayerv2utils.h
Expand Up @@ -228,24 +228,35 @@ class CORE_EXPORT QgsSymbolLayerV2Utils
static QgsVectorColorRampV2* loadColorRamp( QDomElement& element );
static QDomElement saveColorRamp( QString name, QgsVectorColorRampV2* ramp, QDomDocument& doc );

/**
* Attempts to parse a string as a list of colors using a variety of common formats, including hex
* codes, rgb and rgba strings.
* @param colorStr string representing the color list
* @returns list of parsed colors
* @note added in 2.5
*/
static QList< QColor > parseColorList( const QString colorStr );

/**
* Attempts to parse a string as a color using a variety of common formats, including hex
* codes, rgb and rgba strings.
* @param colorStr string representing the color
* @param strictEval set to true for stricter color parsing rules
* @returns parsed color
* @note added in 2.3
*/
static QColor parseColor( QString colorStr );
static QColor parseColor( QString colorStr, bool strictEval = false );

/**
* Attempts to parse a string as a color using a variety of common formats, including hex
* codes, rgb and rgba strings.
* @param colorStr string representing the color
* @param containsAlpha if colorStr contains an explicit alpha value then containsAlpha will be set to true
* @param strictEval set to true for stricter color parsing rules
* @returns parsed color
* @note added in 2.3
*/
static QColor parseColorWithAlpha( const QString colorStr, bool &containsAlpha );
static QColor parseColorWithAlpha( const QString colorStr, bool &containsAlpha, bool strictEval = false );

/**Returns the line width scale factor depending on the unit and the paint device*/
static double lineWidthScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale& scale = QgsMapUnitScale() );
Expand Down
23 changes: 12 additions & 11 deletions src/gui/qgscolorschemelist.cpp
Expand Up @@ -266,7 +266,7 @@ QVariant QgsColorSchemeModel::headerData( int section, Qt::Orientation orientati

Qt::DropActions QgsColorSchemeModel::supportedDropActions() const
{
return Qt::MoveAction | Qt::CopyAction;;
return Qt::MoveAction | Qt::CopyAction;
}

QStringList QgsColorSchemeModel::mimeTypes() const
Expand Down Expand Up @@ -352,23 +352,24 @@ bool QgsColorSchemeModel::dropMimeData( const QMimeData *data, Qt::DropAction ac
}
}

if ( droppedColors.length() == 0 && data->hasColor() )
if ( droppedColors.length() == 0 && data->hasText() )
{
//attempt to read color data directly from mime
QColor mimeColor = data->colorData().value<QColor>();
if ( mimeColor.isValid() )
//attempt to read color data from mime text
QList< QColor > parsedColors = QgsSymbolLayerV2Utils::parseColorList( data->text() );
QList< QColor >::iterator it = parsedColors.begin();
for ( ; it != parsedColors.end(); ++it )
{
droppedColors << qMakePair( mimeColor, QString() );
droppedColors << qMakePair( *it, QString() );
}
}

if ( droppedColors.length() == 0 && data->hasText() )
if ( droppedColors.length() == 0 && data->hasColor() )
{
//attempt to read color data from mime text
QColor textColor = QgsSymbolLayerV2Utils::parseColor( data->text() );
if ( textColor.isValid() )
//attempt to read color data directly from mime
QColor mimeColor = data->colorData().value<QColor>();
if ( mimeColor.isValid() )
{
droppedColors << qMakePair( textColor, QString() );
droppedColors << qMakePair( mimeColor, QString() );
}
}

Expand Down
117 changes: 117 additions & 0 deletions tests/src/core/testqgsstylev2.cpp
Expand Up @@ -55,6 +55,7 @@ class TestStyleV2: public QObject
void testLoadColorRamps();
void testSaveLoad();
void testParseColor();
void testParseColorList();
};


Expand Down Expand Up @@ -284,6 +285,122 @@ void TestStyleV2::testParseColor()
}
}

void TestStyleV2::testParseColorList()
{
//ensure that majority of single parseColor tests work for lists
//note that some are not possible, as the colors may be ambiguous when treated as a list
QMap< QString, QColor > colorTests;
colorTests.insert( "bad color", QColor( ) );
colorTests.insert( "red", QColor( 255, 0, 0 ) );
colorTests.insert( "#ff00ff", QColor( 255, 0, 255 ) );
colorTests.insert( "#99AA00", QColor( 153, 170, 0 ) );
colorTests.insert( "#GG0000", QColor() );
//colorTests.insert( "000000", QColor( 0, 0, 0 ) );
//colorTests.insert( "00ff00", QColor( 0, 255, 0 ) );
//colorTests.insert( "00gg00", QColor() );
colorTests.insert( "00ff000", QColor() );
//colorTests.insert( "fff", QColor( 255, 255, 255 ) );
colorTests.insert( "fff0", QColor() );
colorTests.insert( "0,0,0", QColor( 0, 0, 0 ) );
colorTests.insert( "127,60,0", QColor( 127, 60, 0 ) );
colorTests.insert( "255,255,255", QColor( 255, 255, 255 ) );
//colorTests.insert( "256,60,0", QColor() );
colorTests.insert( "rgb(127,60,0)", QColor( 127, 60, 0 ) );
colorTests.insert( "rgb(255,255,255)", QColor( 255, 255, 255 ) );
colorTests.insert( "rgb(256,60,0)", QColor() );
colorTests.insert( " rgb( 127, 60 , 0 ) ", QColor( 127, 60, 0 ) );
colorTests.insert( "rgb(127,60,0);", QColor( 127, 60, 0 ) );
colorTests.insert( "(127,60,0);", QColor( 127, 60, 0 ) );
colorTests.insert( "(127,60,0)", QColor( 127, 60, 0 ) );
colorTests.insert( "127,060,000", QColor( 127, 60, 0 ) );
colorTests.insert( "0,0,0,0", QColor( 0, 0, 0, 0 ) );
colorTests.insert( "127,60,0,0.5", QColor( 127, 60, 0, 128 ) );
colorTests.insert( "255,255,255,0.1", QColor( 255, 255, 255, 26 ) );
colorTests.insert( "rgba(127,60,0,1.0)", QColor( 127, 60, 0, 255 ) );
colorTests.insert( "rgba(255,255,255,0.0)", QColor( 255, 255, 255, 0 ) );
colorTests.insert( " rgba( 127, 60 , 0 , 0.2 ) ", QColor( 127, 60, 0, 51 ) );
colorTests.insert( "rgba(127,60,0,0.1);", QColor( 127, 60, 0, 26 ) );
colorTests.insert( "(127,60,0,1);", QColor( 127, 60, 0, 255 ) );
colorTests.insert( "(127,60,0,1.0)", QColor( 127, 60, 0, 255 ) );
colorTests.insert( "127,060,000,1", QColor( 127, 60, 0, 255 ) );
colorTests.insert( "0%,0%,0%", QColor( 0, 0, 0 ) );
colorTests.insert( "50 %,60 %,0 %", QColor( 127, 153, 0 ) );
colorTests.insert( "100%, 100%, 100%", QColor( 255, 255, 255 ) );
colorTests.insert( "rgb(50%,60%,0%)", QColor( 127, 153, 0 ) );
colorTests.insert( "rgb(100%, 100%, 100%)", QColor( 255, 255, 255 ) );
colorTests.insert( " rgb( 50 % , 60 % , 0 % ) ", QColor( 127, 153, 0 ) );
colorTests.insert( "rgb(50%,60%,0%);", QColor( 127, 153, 0 ) );
colorTests.insert( "(50%,60%,0%);", QColor( 127, 153, 0 ) );
colorTests.insert( "(50%,60%,0%)", QColor( 127, 153, 0 ) );
colorTests.insert( "050%,060%,000%", QColor( 127, 153, 0 ) );
colorTests.insert( "0%,0%,0%,0", QColor( 0, 0, 0, 0 ) );
colorTests.insert( "50 %,60 %,0 %,0.5", QColor( 127, 153, 0, 128 ) );
colorTests.insert( "100%, 100%, 100%, 1.0", QColor( 255, 255, 255, 255 ) );
colorTests.insert( "rgba(50%,60%,0%, 1.0)", QColor( 127, 153, 0, 255 ) );
colorTests.insert( "rgba(100%, 100%, 100%, 0.0)", QColor( 255, 255, 255, 0 ) );
colorTests.insert( " rgba( 50 % , 60 % , 0 %, 0.5 ) ", QColor( 127, 153, 0, 128 ) );
colorTests.insert( "rgba(50%,60%,0%,0);", QColor( 127, 153, 0, 0 ) );
colorTests.insert( "(50%,60%,0%,1);", QColor( 127, 153, 0, 255 ) );
colorTests.insert( "(50%,60%,0%,1.0)", QColor( 127, 153, 0, 255 ) );
colorTests.insert( "050%,060%,000%,0", QColor( 127, 153, 0, 0 ) );

QMap<QString, QColor >::const_iterator i = colorTests.constBegin();
while ( i != colorTests.constEnd() )
{
QgsDebugMsg( "color list string: " + i.key() );
QList< QColor > result = QgsSymbolLayerV2Utils::parseColorList( i.key() );
if ( i.value().isValid() )
{
QCOMPARE( result.length(), 1 );
QVERIFY( result.at( 0 ) == i.value() );
}
else
{
QCOMPARE( result.length(), 0 );
}
++i;
}

QList< QPair< QString, QList<QColor> > > colorListTests;
QList<QColor> list1;
list1 << QColor( QString( "blue" ) ) << QColor( QString( "red" ) ) << QColor( QString( "green" ) );
colorListTests.append( qMakePair( QString( "blue red green" ), list1 ) );
colorListTests.append( qMakePair( QString( "blue,red,green" ), list1 ) );
colorListTests.append( qMakePair( QString( "blue\nred\ngreen" ), list1 ) );
QList<QColor> list2;
list2 << QColor( QString( "#ff0000" ) ) << QColor( QString( "#00ff00" ) ) << QColor( QString( "#0000ff" ) );
colorListTests.append( qMakePair( QString( "#ff0000 #00ff00 #0000ff" ), list2 ) );
colorListTests.append( qMakePair( QString( "#ff0000,#00ff00,#0000ff" ), list2 ) );
colorListTests.append( qMakePair( QString( "#ff0000\n#00ff00\n#0000ff" ), list2 ) );
QList<QColor> list3;
list3 << QColor( QString( "#ff0000" ) ) << QColor( QString( "#00ff00" ) ) << QColor( QString( "#0000ff" ) );
colorListTests.append( qMakePair( QString( "rgb(255,0,0) rgb(0,255,0) rgb(0,0,255)" ), list3 ) );
colorListTests.append( qMakePair( QString( "rgb(255,0,0)\nrgb(0,255,0)\nrgb(0,0,255)" ), list3 ) );

QList< QPair< QString, QList<QColor> > >::const_iterator it = colorListTests.constBegin();
while ( it != colorListTests.constEnd() )
{
QgsDebugMsg( "color list string: " + ( *it ).first );
QList< QColor > result = QgsSymbolLayerV2Utils::parseColorList(( *it ).first );
if (( *it ).second.length() > 0 )
{
QCOMPARE( result.length(), ( *it ).second.length() );
int index = 0;
for ( QList<QColor>::const_iterator colorIt = ( *it ).second.constBegin(); colorIt != ( *it ).second.constEnd(); ++colorIt )
{
QVERIFY( result.at( index ) == ( *colorIt ) );
index++;
}
}
else
{
QCOMPARE( result.length(), 0 );
}
++it;
}

}


QTEST_MAIN( TestStyleV2 )
#include "moc_testqgsstylev2.cxx"

0 comments on commit 6d10ff3

Please sign in to comment.