Skip to content

Commit

Permalink
smart groups implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
Arunmozhi committed Jul 23, 2012
1 parent dec6216 commit 3943e8a
Show file tree
Hide file tree
Showing 11 changed files with 889 additions and 45 deletions.
Binary file modified resources/symbology-ng-style.db
Binary file not shown.
7 changes: 6 additions & 1 deletion scripts/symbol_xml2db.py
Expand Up @@ -52,7 +52,12 @@
"name TEXT,"\
"parent INTEGER)"

create_tables = [ _symbol, _colorramp, _tag, _tagmap, _symgroup ]
_smartgroup = "CREATE TABLE smartgroup("\
"id INTEGER PRIMARY KEY,"\
"name TEXT,"\
"xml TEXT)"

create_tables = [ _symbol, _colorramp, _tag, _tagmap, _symgroup, _smartgroup ]

# Create the DB with required Schema
conn = sqlite3.connect( dbfile )
Expand Down
292 changes: 292 additions & 0 deletions src/core/symbology-ng/qgsstylev2.cpp
Expand Up @@ -25,6 +25,8 @@

#include <QDomDocument>
#include <QDomElement>
#include <QDomNode>
#include <QDomNodeList>
#include <QFile>
#include <QTextStream>
#include <QByteArray>
Expand Down Expand Up @@ -572,6 +574,8 @@ void QgsStyleV2::rename( StyleEntity type, int id, QString newName )
break;
case ColorrampEntity : query = sqlite3_mprintf( "UPDATE colorramp SET name='%q' WHERE id=%d;", nameArray.constData(), id );
break;
case SmartgroupEntity : query = sqlite3_mprintf( "UPDATE smartgroup SET name='%q' WHERE id=%d;", nameArray.constData(), id );
break;
default : QgsDebugMsg( "Invalid Style Entity indicated" );
return;
}
Expand Down Expand Up @@ -616,6 +620,8 @@ void QgsStyleV2::remove( StyleEntity type, int id )
break;
case ColorrampEntity : query = sqlite3_mprintf( "DELETE FROM colorramp WHERE id=%d;", id );
break;
case SmartgroupEntity : query = sqlite3_mprintf( "DELETE FROM smartgroup WHERE id=%d;", id );
break;
default : QgsDebugMsg( "Invalid Style Entity indicated" );
return;
}
Expand Down Expand Up @@ -864,3 +870,289 @@ int QgsStyleV2::groupId( QString name )
sqlite3_finalize( ppStmt );
return groupid;
}

int QgsStyleV2::tagId( QString name )
{
int tagid = 0;
char *query;
sqlite3_stmt *ppStmt;
QByteArray array = name.toUtf8();
query = sqlite3_mprintf( "SELECT id FROM tag WHERE name='%q';", array.constData() );
int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
{
tagid = sqlite3_column_int( ppStmt, 0 );
}
sqlite3_finalize( ppStmt );
return tagid;
}


int QgsStyleV2::addSmartgroup( QString name, QString op, QgsSmartConditionMap conditions )
{
int sgId = 0;

QDomDocument doc( "dummy" );
QDomElement smartEl = doc.createElement( "smartgroup" );
smartEl.setAttribute( "name", name );
smartEl.setAttribute( "operator", op );

QStringList constraints;
constraints << "tag" << "group" << "name" << "!tag" << "!group" << "!name" ;

foreach ( const QString &constraint, constraints )
{
QStringList parameters = conditions.values( constraint );
foreach ( const QString &param, parameters )
{
QDomElement condEl = doc.createElement( "condition" );
condEl.setAttribute( "constraint", constraint);
condEl.setAttribute( "param", param );
smartEl.appendChild( condEl );
}
}

QByteArray *xmlArray = new QByteArray();
QTextStream stream( xmlArray );
smartEl.save( stream, 4 );
QByteArray nameArray = name.toUtf8();
char *query = sqlite3_mprintf( "INSERT INTO smartgroup VALUES (NULL, '%q', '%q');",
nameArray.constData(), xmlArray->constData() );

if ( !runEmptyQuery( query ) )
{
QgsDebugMsg( "Couldnot insert symbol into the Database!" );
}
else
{
sgId = (int)sqlite3_last_insert_rowid( mCurrentDB );
}
return sgId;
}

QgsSymbolGroupMap QgsStyleV2::smartgroupsListMap()
{
if( mCurrentDB == NULL )
{
QgsDebugMsg( "Cannot open database for listing groups" );
return QgsSymbolGroupMap();
}
char *query;
int nError;
sqlite3_stmt *ppStmt;
QgsSymbolGroupMap groupNames;

query = sqlite3_mprintf( "SELECT * FROM smartgroup;" );

// Now run the query and retrive the group names
nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
{
QString group = QString( reinterpret_cast<const char*>( sqlite3_column_text( ppStmt, SmartgroupName ) ) );
groupNames.insert( sqlite3_column_int( ppStmt, SmartgroupId ), group );
}
sqlite3_finalize( ppStmt );
return groupNames;
}

QStringList QgsStyleV2::smartgroupNames()
{
QStringList groups;

if( mCurrentDB == NULL )
{
QgsDebugMsg( "Cannot open database for listing groups" );
return QStringList();
}
char *query;
int nError;
sqlite3_stmt *ppStmt;

query = sqlite3_mprintf( "SELECT name FROM smartgroup;" );
// Now run the query and retrive the group names
nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
{
groups.append( QString( reinterpret_cast<const char*>( sqlite3_column_text( ppStmt, 0 ) ) ) );
}
sqlite3_finalize( ppStmt );
return groups;
}

QStringList QgsStyleV2::symbolsOfSmartgroup( int id )
{
char *query;
int nErr;
sqlite3_stmt *ppStmt;

QStringList symbols;
bool firstSet = true;

query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d;", id );
nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
if ( !( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) )
{
sqlite3_finalize( ppStmt );
return QStringList();
}
else
{
QDomDocument doc;
QString xmlstr = QString( reinterpret_cast<const char*>( sqlite3_column_text( ppStmt, 0 ) ) );
if ( !doc.setContent( xmlstr ) )
{
QgsDebugMsg( "Cannot open smartgroup id: " + id );
}
QDomElement smartEl = doc.documentElement();
QString op = smartEl.attribute( "operator" );
QDomNodeList conditionNodes = smartEl.childNodes();

for ( int i = 0; i < conditionNodes.count(); i++ )
{
QDomElement condEl = conditionNodes.at( i ).toElement();
QString constraint = condEl.attribute( "constraint" );
QString param = condEl.attribute( "param" );

QStringList resultNames;
// perform suitable action for the given constraint
if ( constraint == "tag" )
{
resultNames = symbolsWithTag( tagId( param ) );
}
else if ( constraint == "group" )
{
// XXX Validating group id might be a good idea here
resultNames = symbolsOfGroup( groupId( param ) );
}
else if ( constraint == "name" )
{
resultNames = symbolNames().filter( param, Qt::CaseInsensitive );
}
else if ( constraint == "!tag" )
{
resultNames = symbolNames();
QStringList unwanted = symbolsWithTag( tagId( param ) );
foreach( QString name, unwanted )
{
resultNames.removeOne( name );
}
}
else if ( constraint == "!group" )
{
resultNames = symbolNames();
QStringList unwanted = symbolsOfGroup( groupId( param ) );
foreach( QString name, unwanted )
{
resultNames.removeOne( name );
}
}
else if ( constraint == "!name" )
{
QStringList all = symbolNames();
foreach ( const QString &str, all )
{
if ( !str.contains( param, Qt::CaseInsensitive ) )
resultNames.append( str );
}
}

// not apply the operator
if ( firstSet )
{
symbols = resultNames;
firstSet = false;
}
else
{
if ( op == "OR" )
{
symbols.append( resultNames );
}
else if ( op == "AND" )
{
QStringList dummy = symbols;
symbols.clear();
foreach ( const QString &result, resultNames )
{
if ( dummy.contains( result ) )
symbols.append( result );
}
}
}
} // DOM loop ends here
}
sqlite3_finalize( ppStmt );
return symbols;
}

QgsSmartConditionMap QgsStyleV2::smartgroup( int id )
{
if( mCurrentDB == NULL )
{
QgsDebugMsg( "Cannot open database for listing groups" );
return QgsSmartConditionMap();
}
char *query;
int nError;
sqlite3_stmt *ppStmt;

QgsSmartConditionMap condition;

query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d;", id );
nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
{
QDomDocument doc;
QString xmlstr = QString( reinterpret_cast<const char*>( sqlite3_column_text( ppStmt, 0 ) ) );
if ( !doc.setContent( xmlstr ) )
{
QgsDebugMsg( "Cannot open smartgroup id: " + id );
}
QDomElement smartEl = doc.documentElement();
QString op = smartEl.attribute( "operator" );
QDomNodeList conditionNodes = smartEl.childNodes();

for ( int i = 0; i < conditionNodes.count(); i++ )
{
QDomElement condEl = conditionNodes.at( i ).toElement();
QString constraint = condEl.attribute( "constraint" );
QString param = condEl.attribute( "param" );

condition.insert( constraint, param );
}
}
sqlite3_finalize( ppStmt );

return condition;
}

QString QgsStyleV2::smartgroupOperator( int id )
{
if( mCurrentDB == NULL )
{
QgsDebugMsg( "Cannot open database for listing groups" );
return QString();
}
char *query;
int nError;
sqlite3_stmt *ppStmt;

QString op;

query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d;", id );
nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
{
QDomDocument doc;
QString xmlstr = QString( reinterpret_cast<const char*>( sqlite3_column_text( ppStmt, 0 ) ) );
if ( !doc.setContent( xmlstr ) )
{
QgsDebugMsg( "Cannot open smartgroup id: " + id );
}
QDomElement smartEl = doc.documentElement();
op = smartEl.attribute( "operator" );
}
sqlite3_finalize( ppStmt );

return op;
}
25 changes: 24 additions & 1 deletion src/core/symbology-ng/qgsstylev2.h
Expand Up @@ -17,6 +17,7 @@
#define QGSSTYLEV2_H

#include <QMap>
#include <QMultiMap>
#include <QString>

#include <sqlite3.h>
Expand All @@ -32,16 +33,18 @@ class QDomElement;

typedef QMap<QString, QgsVectorColorRampV2* > QgsVectorColorRampV2Map;
typedef QMap<int, QString> QgsSymbolGroupMap;
typedef QMultiMap<QString, QString> QgsSmartConditionMap;

// Enumeraters representing sqlite DB columns
enum SymbolTable { SymbolId, SymbolName, SymbolXML, SymbolGroupId };
enum SymgroupTable { SymgroupId, SymgroupName, SymgroupParent };
enum TagTable { TagId, TagName };
enum TagmapTable { TagmapTagId, TagmapSymbolId };
enum ColorrampTable { ColorrampId, ColorrampName, ColorrampXML };
enum SmartgroupTable { SmartgroupId, SmartgroupName, SmartgroupXML };

// Enums for types
enum StyleEntity { SymbolEntity, GroupEntity, TagEntity, ColorrampEntity };
enum StyleEntity { SymbolEntity, GroupEntity, TagEntity, ColorrampEntity, SmartgroupEntity };

class CORE_EXPORT QgsStyleV2
{
Expand Down Expand Up @@ -84,6 +87,7 @@ class CORE_EXPORT QgsStyleV2

//! return the id in the style database for the given group name
int groupId( QString group );
int tagId( QString tag );

//! return the all the groups in the style
QStringList groupNames();
Expand Down Expand Up @@ -158,6 +162,25 @@ class CORE_EXPORT QgsStyleV2
//! return the tags associated with the symbol
QStringList tagsOfSymbol( QString symbol );

//! adds the smartgroup to the database and returns the id
int addSmartgroup( QString name, QString op, QgsSmartConditionMap conditions );

//! returns the smart groups map
QgsSymbolGroupMap smartgroupsListMap();

//! returns the smart groups list
QStringList smartgroupNames();

//! returns the QgsSmartConditionMap for the given id
QgsSmartConditionMap smartgroup( int id );

//! returns the operator for the smartgroup
//! @note: clumsy implementation TODO create a class for smartgroups
QString smartgroupOperator( int id );

//! returns the symbols for the smartgroup
QStringList symbolsOfSmartgroup( int id );

protected:

QgsSymbolV2Map mSymbols;
Expand Down

0 comments on commit 3943e8a

Please sign in to comment.