Subversion Repositories public

Rev

Rev 280 | Blame | Compare with Previous | Last modification | View Log | RSS feed

//
// C++ Implementation: SRender
//
// Description: Renders a map from some shape files. This class assumes,
//              that the shape files are in open street map format!
//
//
// Author: Andreas Theofilu <andreas@theosys.at>, (C) 2009
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "config.h"

// This module will only exist, if Mapnik is available!
#if defined HAVE_MAPNIK

#define BOOST_SPIRIT_THREADSAFE
#include <QPixmap>
#include <QBitmap>
#include <QString>
#include <QXmlReader>
#include <QDir>
#include <QColor>
#include <QImage>
#include <KStandardDirs>
#include <KConfig>
#include <KLocale>
#include <KMessageBox>
#include <KGlobalSettings>
#include <KConfigGroup>
#include <KIconLoader>

#include "render.h"
#include <iostream>

#define CON_MAP                 100
#define CON_STYLE               101
#define CON_RULE                102
#define CON_LINESYMBOLIZER      103
#define CON_POINTSYMBOLIZER     104
#define CON_POLYGONSYMBOLIZER   105
#define CON_TEXTSYMBOLIZER      106
#define CON_POLYGONPATTERNSYMBOLIZER    107
#define CON_LAYER               108
#define CON_DATASOURCE          109
#define CON_SHIELDSYMBOLIZER    110
#define CON_LINEPATTERNSYMBOLIZER       111
#define CON_ELSEFILTER          112

#define FLD_FILTER              200
#define FLD_CSSPARAMETER        201
#define FLD_MINSCALE            202
#define FLD_MAXSCALE            203
#define FLD_STYLENAME           204
#define FLD_PARAMETER           205

#define ATT_FILL                300
#define ATT_FILE                301
#define ATT_TYPE                302
#define ATT_WIDTH               303
#define ATT_HEIGHT              304
#define ATT_SIZE                305
#define ATT_NAME                306
#define ATT_FACENAME            307
#define ATT_DY                  308
#define ATT_HALORADIUS          309
#define ATT_WRAPWIDTH           310
#define ATT_MINDISTANCE         311
#define ATT_MAXDISTANCE         312
#define ATT_PLACEMENT           313
#define ATT_ALLOWOVERLAP        314
#define ATT_STATUS              315
#define ATT_SRS                 316
#define ATT_DX                  317
#define ATT_ALIGNMENT           318

#define FIRST_CON               100
#define LAST_CON                112

#define FIRST_FLD               200
#define LAST_FLD                205

#define FIRST_ATT               300
#define LAST_ATT                318

using std::cout;
using std::cerr;
using std::clog;
using std::endl;

TOKEN token[] = {
        // Containers
        { CON_MAP,                      in_map,                 QString("Map") },
        { CON_STYLE,                    in_style,               QString("Style") },
        { CON_RULE,                     in_rule,                QString("Rule") },
        { CON_LINESYMBOLIZER,           in_linesymbolizer,      QString("LineSymbolizer") },
        { CON_POINTSYMBOLIZER,          in_pointsymbolizer,     QString("PointSymbolizer") },
        { CON_POLYGONSYMBOLIZER,        in_polygonsymbolizer,   QString("PolygonSymbolizer") },
        { CON_TEXTSYMBOLIZER,           in_textsymbolizer,      QString("TextSymbolizer") },
        { CON_POLYGONPATTERNSYMBOLIZER, in_polygonpatternsymbolizer,    QString("PolygonPatternSymbolizer") },
        { CON_LAYER,                    in_layer,               QString("Layer") },
        { CON_DATASOURCE,               in_datasource,          QString("Datasource") },
        { CON_SHIELDSYMBOLIZER,         in_shieldsymbolizer,    QString("ShieldSymbolizer") },
        { CON_LINEPATTERNSYMBOLIZER,    in_linepatternsymbolizer, QString("LinePatternSymbolizer") },
        { CON_ELSEFILTER,               in_rule,                QString("ElseFilter") },
        // Fields
        { FLD_FILTER,                   in_rule,                QString("Filter") },
        { FLD_CSSPARAMETER,             in_symbolizer,          QString("CSSParameter") },
        { FLD_MINSCALE,                 in_rule,                QString("MinScaleDenominator") },
        { FLD_MAXSCALE,                 in_rule,                QString("MaxScaleDenominator") },
        { FLD_STYLENAME,                in_style,               QString("StyleName") },
        { FLD_PARAMETER,                in_datasource,          QString("Parameter") },
        // Attributes
        { ATT_FILL,                     in_symbolizer,          QString("fill") },
        { ATT_NAME,                     in_symbolizer,          QString("name") },
        { ATT_FILE,                     in_symbolizer,          QString("file") },
        { ATT_TYPE,                     in_symbolizer,          QString("type") },
        { ATT_WIDTH,                    in_symbolizer,          QString("width") },
        { ATT_HEIGHT,                   in_symbolizer,          QString("height") },
        { ATT_SIZE,                     in_symbolizer,          QString("size") },
        { ATT_FACENAME,                 in_symbolizer,          QString("face_name") },
        { ATT_DX,                       in_symbolizer,          QString("dx") },
        { ATT_DY,                       in_symbolizer,          QString("dy") },
        { ATT_HALORADIUS,               in_symbolizer,          QString("halo_radius") },
        { ATT_WRAPWIDTH,                in_symbolizer,          QString("wrap_width") },
        { ATT_MINDISTANCE,              in_symbolizer,          QString("min_distance") },
        { ATT_MAXDISTANCE,              in_symbolizer,          QString("max_distance") },
        { ATT_PLACEMENT,                in_symbolizer,          QString("placement") },
        { ATT_ALLOWOVERLAP,             in_symbolizer,          QString("allow_overlap") },
        { ATT_STATUS,                   in_layer,               QString("status") },
        { ATT_SRS,                      in_layer,               QString("srs") },
        { ATT_ALIGNMENT,                in_symbolizer,          QString("alignment") },
        { 0,                            in_root,                QString::null }
};

SRender::SRender()
{
        _width = _height = 0;
        shapePath = QString::null;
        XmlPath = QString::null;
        Lay = firstLayer = lastLayer = 0;
        Style = firstStyle = lastStyle = 0;
        Rule = 0;
        LineSymbolizer = 0;
        PolygonSymbolizer = 0;
        TextSymbolizer = 0;
        PointSymbolizer = 0;
        PolygonPatternSymbolizer = 0;
        ShieldSymbolizer = 0;
        LinePatternSymbolizer = 0;
        _lx = _ly = 180.0;
        _rx = _ry = -180.0;
        __map_type = MAP_SHAPE;         // The default map type
        // This is true, when a XML file was parsed successfully
        ControlSet = false;

        // Read settings from config file
        KConfig cfg (QString("sportwatcher.rc"), KConfig::SimpleConfig);
        KConfigGroup ic (&cfg, "SportWatcher");
        KConfigGroup sh (&cfg, "ShapeFile");
        QString basePath = ic.readEntry("Data", QDir::home().absolutePath() + "/.sportwatcher");
        shapePath = ic.readEntry("MAP", basePath + "/shapefiles");
        // Read the shape specific informations
#ifdef MAPNIK_PLUGINS
        pluginPath = QString(MAPNIK_PLUGINS);
#else
        QDir dir;
        // Test some default path
        if (dir.exists(QString("/usr/lib/mapnik/input")))
           pluginPath = sh.readEntry("PluginPath", QString("/usr/lib/mapnik/input"));
        else if (dir.exists(QString("/usr/local/lib/mapnik/input")))
           pluginPath = sh.readEntry("PluginPath", QString("/usr/local/lib/mapnik/input"));
        else if (dir.exists(QString("/usr/lib/mapnik/0.6/input")))
           pluginPath = sh.readEntry("PluginPath", QString("/usr/lib/mapnik/0.6/input"));
        else
           pluginPath = sh.readEntry("PluginPath", QString(""));
#endif
#ifdef MAPNIK_FONTS
        fontPath = QString(MAPNIK_FONTS);
#else
        // Test some default path
        if (dir.exists(QString("/usr/lib/mapnik/fonts")))
           fontPath = sh.readEntry("FontPath", QString("/usr/lib/mapnik/fonts"));
        else if (dir.exists(QString("/usr/local/lib/mapnik/fonts")))
           fontPath = sh.readEntry("FontPath", QString("/usr/local/lib/mapnik/fonts"));
        else if (dir.exists(QString("/usr/share/mapnik/fonts")))
           fontPath = sh.readEntry("FontPath", QString("/usr/share/mapnik/fonts"));
        else if (dir.exists(QString("/usr/share/fonts/truetype/ttf-dejavu")))
           fontPath = sh.readEntry("FontPath", QString("/usr/share/fonts/truetype/ttf-dejavu"));
        else
           fontPath = sh.readEntry("FontPath", QString(""));
#endif
        XmlPath = sh.readEntry("XmlFile", basePath + "/shapefiles/osm.xml");
        geographic = sh.readEntry("Geographic", false);
}

SRender::~SRender()
{
        _width = _height = 0;
        startDocument();        // Clean everything
        ControlSet = false;
}

void SRender::setDrawArea(int w, int h)
{
        _width = w;
        _height = h;
}

bool SRender::startDocument()
{
        m.remove_all();         // delete styles and layers from map

        if (firstStyle)         // free if allocated
        {
           Style = firstStyle;

           while (Style)
           {
              STYLE *sakt = Style->next;

              if (Style->rule)
              {
                 RULE *rule = Style->rule;

                 while (rule)
                 {
                    RULE *rakt = rule->next;
                    LINESYMBOLIZER *LineSymbolizer = rule->LineSymbolizer;
                    POLYGONSYMBOLIZER *PolygonSymbolizer = rule->PolygonSymbolizer;
                    TEXTSYMBOLIZER *TextSymbolizer = rule->TextSymbolizer;
                    POINTSYMBOLIZER *PointSymbolizer = rule->PointSymbolizer;
                    POLYGONPATTERNSYMBOLIZER *PolygonPatternSymbolizer = rule->PolygonPatternSymbolizer;
                    SHIELDSYMBOLIZER *ShieldSymbolizer = rule->ShieldSymbolizer;
                    LINEPATTERNSYMBOLIZER *LinePatternSymbolizer = rule->LinePatternSymbolizer;

                    while (LineSymbolizer)
                    {
                       LINESYMBOLIZER *akt = LineSymbolizer->next;
                       delete LineSymbolizer;
                       LineSymbolizer = akt;
                    }

                    while (PolygonSymbolizer)
                    {
                       POLYGONSYMBOLIZER *akt = PolygonSymbolizer->next;
                       delete PolygonSymbolizer;
                       PolygonSymbolizer = akt;
                    }

                    while (TextSymbolizer)
                    {
                       TEXTSYMBOLIZER *akt = TextSymbolizer->next;
                       delete TextSymbolizer;
                       TextSymbolizer = akt;
                    }

                    while (PointSymbolizer)
                    {
                       POINTSYMBOLIZER *akt = PointSymbolizer->next;
                       delete PointSymbolizer;
                       PointSymbolizer = akt;
                    }

                    while (PolygonPatternSymbolizer)
                    {
                       POLYGONPATTERNSYMBOLIZER *akt = PolygonPatternSymbolizer->next;
                       delete PolygonPatternSymbolizer;
                       PolygonPatternSymbolizer = akt;
                    }

                    while (ShieldSymbolizer)
                    {
                       SHIELDSYMBOLIZER *akt = ShieldSymbolizer->next;
                       delete ShieldSymbolizer;
                       ShieldSymbolizer = akt;
                    }

                    while (LinePatternSymbolizer)
                    {
                       LINEPATTERNSYMBOLIZER *akt = LinePatternSymbolizer->next;
                       delete LinePatternSymbolizer;
                       LinePatternSymbolizer = akt;
                    }

                    delete rule;
                    rule = rakt;
                 }
              }

              delete Style;
              Style = sakt;
           }
        }

        Style = firstStyle = lastStyle = 0;

        if (firstLayer)
        {
           Lay = firstLayer;

           while (Lay)
           {
           LAYER *akt;

              akt = Lay->next;
              delete Lay;
              Lay = akt;
           }
        }

        Lay = firstLayer = lastLayer = 0;
        Rule = 0;
        LineSymbolizer = 0;
        PolygonSymbolizer = 0;
        TextSymbolizer = 0;
        PointSymbolizer = 0;
        PolygonPatternSymbolizer = 0;
        ShieldSymbolizer = 0;
        LinePatternSymbolizer = 0;
        _lx = _ly = 180.0;
        _rx = _ry = -180.0;
        ControlSet = false;
        XmlLine = 1;
        Container = in_root;
        return true;
}

/*
 * This is called every time a new start element was parsed.
 */
bool SRender::startElement( const QString&, const QString&,
                                    const QString& qName,
                                    const QXmlAttributes& att)
{
int i = FIRST_CON;
int index;
QString hv0;

        while (i <= LAST_CON)
        {
           if (qName.toLower() == getKey(i).toLower())
           {
              Container = token[i].con;

              switch (i)
              {
                 case CON_MAP:
                    Container = in_map;

                    if (ControlSet)     // Must be false here!
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: There is another MAP! Only one map information is allowed!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }

                    if ((index = att.index(QString("bgcolor"))) != -1)
                    {
                       MapPars.bgcolor = colorToUInt(att.value(index));
                       m.set_background(setColor(MapPars.bgcolor));
                    }

                    if ((index = att.index(QString("buffer_size"))) != -1)
                    {
                       MapPars.buf_size = att.value(index).toInt();
                       m.set_buffer_size(MapPars.buf_size);
                    }

                    if ((index = att.index(QString("srs"))) != -1)
                    {
                       MapPars.srs = att.value(index);
                       m.set_srs(MapPars.srs.toAscii().data());
                    }
                 break;

                 case CON_STYLE:
                    Container = in_style;

                    if (!lastStyle)
                    {
                       Style = allocStyle();
                       firstStyle = lastStyle = Style;
                    }
                    else
                    {
                       Style = allocStyle();
                       lastStyle->next = Style;
                       lastStyle = Style;
                    }

                    if ((index = att.index(QString("name"))) != -1)
                       Style->name = att.value(index);
                    else
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: Open STYLE without a name!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }
                 break;

                 case CON_RULE:
                    Container = in_rule;

                    if (!Style)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: Open RULE outside of a STYLE!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }

                    Rule = getLastRule (Style->rule);

                    if (!Rule)
                    {
                       Rule = allocRule();
                       Style->rule = Rule;
                    }
                    else
                    {
                       Rule->next = allocRule();
                       Rule = Rule->next;
                    }

                    if ((index = att.index(QString("name"))) != -1)
                    {
                       Rule->name = att.value(index);
                       Rule->rl.set_name(Rule->name.toAscii().data());
                    }

                    if ((index = att.index(QString("title"))) != -1)
                    {
                       Rule->title = att.value(index);
                       Rule->rl.set_title(Rule->title.toAscii().data());
                    }
                 break;

                 case CON_ELSEFILTER:
                    Container = in_elsefilter;

                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: Open ELSEFILTER outside of a RULE!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }
                 break;

                 case CON_LAYER:
                    Container = in_layer;

                    if (!firstLayer)
                    {
                       Lay = allocLayer();
                       firstLayer = lastLayer = Lay;
                    }
                    else
                    {
                       Lay = allocLayer();
                       lastLayer->next = Lay;
                       lastLayer = Lay;
                    }

                    if ((index = att.index(QString("name"))) != -1)
                       Lay->name = att.value(index);

                    if ((index = att.index(QString("status"))) != -1)
                       Lay->status = getBool(att.value(index));

                    if ((index = att.index(QString("srs"))) != -1)
                       Lay->srs = att.value(index);

                    if ((index = att.index(QString("minzoom"))) != -1)
                       Lay->minzoom = att.value(index).toDouble();

                    if ((index = att.index(QString("maxzoom"))) != -1)
                       Lay->maxzoom = att.value(index).toDouble();

                    if ((index = att.index(QString("queryable"))) != -1)
                       Lay->queryable = getBool(att.value(index));

                    if ((index = att.index(QString("title"))) != -1)
                       Lay->title = att.value(index);

                    if ((index = att.index(QString("abstract"))) != -1)
                       Lay->abstract = att.value(index);

                    if ((index = att.index(QString("clear_label_cache"))) != -1)
                       Lay->clear_label = getBool(att.value(index));
                 break;

                 case CON_DATASOURCE:
                    Container = in_datasource;
                 break;

                 case CON_POINTSYMBOLIZER:
                    Container = in_pointsymbolizer;

                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: Open POINTSYMBOLIZER outside of a RULE!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }

                    PointSymbolizer = getLastPointSymbolizer(Rule->PointSymbolizer);

                    if (!PointSymbolizer)
                    {
                       PointSymbolizer = allocPointSymbolizer();
                       Rule->PointSymbolizer = PointSymbolizer;
                    }
                    else
                    {
                       PointSymbolizer->next = allocPointSymbolizer();
                       PointSymbolizer = PointSymbolizer->next;
                    }

                    if ((index = att.index(QString("file"))) != -1)
                       PointSymbolizer->file = att.value(index);

                    if ((index = att.index(QString("type"))) != -1)
                       PointSymbolizer->type = getType(att.value(index));

                    if ((index = att.index(QString("width"))) != -1)
                       PointSymbolizer->width = att.value(index).toDouble();

                    if ((index = att.index(QString("height"))) != -1)
                       PointSymbolizer->height = att.value(index).toDouble();

                    if ((index = att.index(QString("allow_overlap"))) != -1)
                       PointSymbolizer->allow_overlap = getBool(att.value(index));
                 break;

                 break;

                 case CON_LINESYMBOLIZER:
                    Container = in_linesymbolizer;

                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: Open LINESYMBOLIZER outside of a RULE!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }

                    LineSymbolizer = getLastLineSymbolizer(Rule->LineSymbolizer);

                    if (!LineSymbolizer)
                    {
                       LineSymbolizer = allocLineSymbolizer();
                       Rule->LineSymbolizer = LineSymbolizer;
                    }
                    else
                    {
                       LineSymbolizer->next = allocLineSymbolizer();
                       LineSymbolizer = LineSymbolizer->next;
                    }
                 break;

                 case CON_POLYGONSYMBOLIZER:
                    Container = in_polygonsymbolizer;

                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: Open POLYGONSYMBOLIZER outside of a RULE!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }

                    PolygonSymbolizer = getLastPolygonSymbolizer(Rule->PolygonSymbolizer);

                    if (!PolygonSymbolizer)
                    {
                       PolygonSymbolizer = allocPolygonSymbolizer();
                       Rule->PolygonSymbolizer = PolygonSymbolizer;
                    }
                    else
                    {
                       PolygonSymbolizer->next = allocPolygonSymbolizer();
                       PolygonSymbolizer = PolygonSymbolizer->next;
                    }
                 break;

                 case CON_TEXTSYMBOLIZER:
                    Container = in_textsymbolizer;

                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: Open TEXTSYMBOLIZER outside of a RULE!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }

                    TextSymbolizer = getLastTextSymbolizer(Rule->TextSymbolizer);

                    if (!TextSymbolizer)
                    {
                       TextSymbolizer = allocTextSymbolizer();
                       Rule->TextSymbolizer = TextSymbolizer;
                    }
                    else
                    {
                       TextSymbolizer->next = allocTextSymbolizer();
                       TextSymbolizer = TextSymbolizer->next;
                    }

                    if ((index = att.index(QString("name"))) != -1)
                       TextSymbolizer->name = att.value(index);

                    if ((index = att.index(QString("face_name"))) != -1)
                       TextSymbolizer->face_name = att.value(index);

                    if ((index = att.index(QString("placement"))) != -1)
                       TextSymbolizer->placement = att.value(index);

                    if ((index = att.index(QString("size"))) != -1)
                       TextSymbolizer->size = att.value(index).toDouble();

                    if ((index = att.index(QString("fill"))) != -1)
                       TextSymbolizer->fill = colorToUInt(att.value(index));

                    if ((index = att.index(QString("halo_radius"))) != -1)
                       TextSymbolizer->halo_radius = att.value(index).toDouble();

                    if ((index = att.index(QString("wrap_width"))) != -1)
                       TextSymbolizer->wrap_width = att.value(index).toDouble();

                    if ((index = att.index(QString("alignment"))) != -1)
                       TextSymbolizer->alignment = att.value(index);

                    if ((index = att.index(QString("dx"))) != -1)
                       TextSymbolizer->dx = att.value(index).toDouble();

                    if ((index = att.index(QString("dy"))) != -1)
                       TextSymbolizer->dy = att.value(index).toDouble();

                    if ((index = att.index(QString("max_distance"))) != -1)
                       TextSymbolizer->maxdistance = att.value(index).toDouble();

                    if ((index = att.index(QString("min_distance"))) != -1)
                       TextSymbolizer->mindistance = att.value(index).toDouble();
                 break;

                 case CON_POLYGONPATTERNSYMBOLIZER:
                    Container = in_polygonpatternsymbolizer;

                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: Open POLYGONPATTERNSYMBOLIZER outside of a RULE!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }

                    PolygonPatternSymbolizer = getLastPolygonPatternSymbolizer(Rule->PolygonPatternSymbolizer);

                    if (!PolygonPatternSymbolizer)
                    {
                       PolygonPatternSymbolizer = allocPolygonPatternSymbolizer();
                       Rule->PolygonPatternSymbolizer = PolygonPatternSymbolizer;
                    }
                    else
                    {
                       PolygonPatternSymbolizer->next = allocPolygonPatternSymbolizer();
                       PolygonPatternSymbolizer = PolygonPatternSymbolizer->next;
                    }

                    if ((index = att.index(QString("file"))) != -1)
                       PolygonPatternSymbolizer->file = att.value(index);

                    if ((index = att.index(QString("type"))) != -1)
                       PolygonPatternSymbolizer->type = getType(att.value(index));

                    if ((index = att.index(QString("width"))) != -1)
                       PolygonPatternSymbolizer->width = att.value(index).toDouble();

                    if ((index = att.index(QString("height"))) != -1)
                       PolygonPatternSymbolizer->height = att.value(index).toDouble();

                    if ((index = att.index(QString("allow_overlap"))) != -1)
                       PolygonPatternSymbolizer->allow_overlap = getBool(att.value(index));
                 break;

                 case CON_SHIELDSYMBOLIZER:
                    Container = in_shieldsymbolizer;

                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: Open SHIELDSYMBOLIZER outside of a RULE!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }

                    ShieldSymbolizer = getLastShieldSymbolizer(Rule->ShieldSymbolizer);

                    if (!ShieldSymbolizer)
                    {
                       ShieldSymbolizer = allocShieldSymbolizer();
                       Rule->ShieldSymbolizer = ShieldSymbolizer;
                    }
                    else
                    {
                       ShieldSymbolizer->next = allocShieldSymbolizer();
                       ShieldSymbolizer = ShieldSymbolizer->next;
                    }

                    if ((index = att.index(QString("name"))) != -1)
                       ShieldSymbolizer->name = att.value(index);

                    if ((index = att.index(QString("face_name"))) != -1)
                       ShieldSymbolizer->face_name = att.value(index);

                    if ((index = att.index(QString("fill"))) != -1)
                       ShieldSymbolizer->fill = colorToUInt(att.value(index));

                    if ((index = att.index(QString("placement"))) != -1)
                       ShieldSymbolizer->placement = att.value(index);

                    if ((index = att.index(QString("file"))) != -1)
                       ShieldSymbolizer->file = att.value(index);

                    if ((index = att.index(QString("type"))) != -1)
                       ShieldSymbolizer->type = getType(att.value(index));

                    if ((index = att.index(QString("size"))) != -1)
                       ShieldSymbolizer->size = att.value(index).toDouble();

                    if ((index = att.index(QString("width"))) != -1)
                       ShieldSymbolizer->width = att.value(index).toDouble();

                    if ((index = att.index(QString("height"))) != -1)
                       ShieldSymbolizer->height = att.value(index).toDouble();

                    if ((index = att.index(QString("dx"))) != -1)
                       ShieldSymbolizer->dx = att.value(index).toDouble();

                    if ((index = att.index(QString("dy"))) != -1)
                       ShieldSymbolizer->dy = att.value(index).toDouble();

                    if ((index = att.index(QString("min_distance"))) != -1)
                       ShieldSymbolizer->mindistance = att.value(index).toDouble();

                    if ((index = att.index(QString("max_distance"))) != -1)
                       ShieldSymbolizer->maxdistance = att.value(index).toDouble();
                 break;

                 case CON_LINEPATTERNSYMBOLIZER:
                    Container = in_linepatternsymbolizer;

                    if (!Rule)
                    {
                       KMessageBox::error(0, i18n("Error parsing %1, line %2: Open LINEPATTERNSYMBOLIZER outside of a RULE!").arg(XmlPath).arg(XmlLine));
                       return false;
                    }

                    LinePatternSymbolizer = getLastLinePatternSymbolizer(Rule->LinePatternSymbolizer);

                    if (!LinePatternSymbolizer)
                    {
                       LinePatternSymbolizer = allocLinePatternSymbolizer();
                       Rule->LinePatternSymbolizer = LinePatternSymbolizer;
                    }
                    else
                    {
                       LinePatternSymbolizer->next = allocLinePatternSymbolizer();
                       LinePatternSymbolizer = LinePatternSymbolizer->next;
                    }

                    if ((index = att.index(QString("file"))) != -1)
                       LinePatternSymbolizer->file = att.value(index);

                    if ((index = att.index(QString("type"))) != -1)
                       LinePatternSymbolizer->type = getType(att.value(index));

                    if ((index = att.index(QString("width"))) != -1)
                       LinePatternSymbolizer->width = att.value(index).toDouble();

                    if ((index = att.index(QString("height"))) != -1)
                       LinePatternSymbolizer->height = att.value(index).toDouble();
                 break;
              }
           }

           i++;
        }

        i = FIRST_FLD;

        while (i <= LAST_FLD)
        {
           if (qName.toLower() == getKey(i).toLower())
           {
              Field = i;

              switch(Container)
              {
                 case in_linesymbolizer:
                    Names = empty;

                    if (i == FLD_CSSPARAMETER)
                    {
                       if ((index = att.index(QString("name"))) != -1)
                       {
                          if (att.value(index).toLower() == QString("stroke"))
                             Names = stroke_stroke;
                          else if (att.value(index).toLower() == QString("stroke-width"))
                             Names = stroke_width;
                          else if (att.value(index).toLower() == QString("stroke-opacity"))
                             Names = stroke_opacity;
                          else if (att.value(index).toLower() == QString("stroke-linejoin"))
                             Names = stroke_linejoin;
                          else if (att.value(index).toLower() == QString("stroke-linecap"))
                             Names = stroke_linecap;
                          else if (att.value(index).toLower() == QString("stroke-dasharray"))
                             Names = stroke_dasharray;
                       }
                       else
                       {
                          KMessageBox::error(0, i18n("Error parsing %1, line %2: Required attribute NAME is missing in CSSPARAMETER inside LINESYMBOLIZER!").arg(XmlPath).arg(XmlLine));
                          return false;
                       }
                    }
                 break;

                 case in_polygonsymbolizer:
                    Names = empty;

                    if (i == FLD_CSSPARAMETER)
                    {
                       if ((index = att.index(QString("name"))) != -1)
                       {
                          if (att.value(index).toLower() == QString("fill"))
                             Names = fill;
                          else if (att.value(index).toLower() == QString("fill-opacity"))
                             Names = fill_opacity;
                       }
                       else
                       {
                          KMessageBox::error(0, i18n("Error parsing %1, line %2: Required attribute NAME is missing in CSSPARAMETER inside POLYGONSYMBOLIZER!").arg(XmlPath).arg(XmlLine));
                          return false;
                       }
                    }
                 break;

                 case in_datasource:
                    Names = empty;

                    if (i == FLD_PARAMETER)
                    {
                       if ((index = att.index(QString("name"))) != -1)
                       {
                          if (att.value(index).toLower() == QString("type"))
                             Names = type;
                          else if (att.value(index).toLower() == QString("file"))
                             Names = file;
                          else if (att.value(index).toLower() == QString("host"))
                             Names = host;
                          else if (att.value(index).toLower() == QString("user"))
                             Names = user;
                          else if (att.value(index).toLower() == QString("dbname"))
                             Names = dbname;
                          else if (att.value(index).toLower() == QString("table"))
                             Names = table;
                          else if (att.value(index).toLower() == QString("estimate_extent"))
                             Names = estimate_extent;
                          else if (att.value(index).toLower() == QString("extent"))
                             Names = extent;
                          else if (att.value(index).toLower() == QString("parser"))
                             Names = parser__;
                          else if (att.value(index).toLower() == QString("url"))
                             Names = url;
                          else if (att.value(index).toLower() == QString("bbox"))
                             Names = bbox;
                       }
                       else
                       {
                          KMessageBox::error(0, i18n("Error parsing %1, line %2: Required attribute NAME is missing in PARAMETER inside DATASOURCE!").arg(XmlPath).arg(XmlLine));
                          return false;
                       }
                    }
                 break;

                 case in_root:
                    Names = empty;
                 break;
                 case in_map:
                    Names = empty;
                 break;
                 case in_style:
                    Names = empty;
                 break;
                 case in_rule:
                    Names = empty;
                 break;
                 case in_pointsymbolizer:
                    Names = empty;
                 break;
                 case in_textsymbolizer:
                    Names = empty;
                 break;
                 case in_polygonpatternsymbolizer:
                    Names = empty;
                 break;
                 case in_layer:
                    Names = empty;
                 break;
                 case in_symbolizer:
                    Names = empty;
                 break;
                 case in_shieldsymbolizer:
                    Names = empty;
                 break;
                 case in_linepatternsymbolizer:
                    Names = empty;
                 break;
                 case in_elsefilter:
                    Names = empty;
                 break;
              }
           }

           i++;
        }

        return true;
}

/*
 * This is called every time an element is closed.
 */
bool SRender::endElement( const QString&, const QString&, const QString& qName)
{
        if (qName.toLower() == QString("datasource"))
           Container = in_layer;
        else if (qName.toLower() == QString("layer"))
        {
           parameters p;
           Container = in_map;

           if (Lay->Datasource.type.toLower() == QString("shape") && __map_type == MAP_SHAPE)
           {
           QFileInfo qdi(Lay->Datasource.file);
           QString hv0;

              hv0 = qdi.fileName();

              if (shapePath.right(1) == QChar('/'))
                 hv0 = shapePath + hv0;
              else
                 hv0 = shapePath + "/" + hv0;

              p["type"] = "shape";
              p["file"] = hv0.toAscii().data();
           }
           else if (Lay->Datasource.type.toLower() == QString("postgis") && __map_type == MAP_GIS)
           {
              p["type"] = "postgis";
              p["host"] = Lay->Datasource.host.toAscii().data();
              p["user"] = Lay->Datasource.user.toAscii().data();
              p["dbname"] = Lay->Datasource.dbname.toAscii().data();
              p["table"] = Lay->Datasource.table.toAscii().data();
              p["estimate_extent"] = (Lay->Datasource.estimate_extent) ? "true" : "false";
              p["extent"] = QString("%1,%2,%3,%4").arg(Lay->Datasource.ext_lx).arg(Lay->Datasource.ext_ly).arg(Lay->Datasource.ext_rx).arg(Lay->Datasource.ext_ry).toAscii().data();
           }
           else if (Lay->Datasource.type.toAscii() == QString("osm") && __map_type == MAP_OSM)
           {
              p["type"] = "osm";

              if (Lay->Datasource.parser.length() <= 0)
                 p["parser"] = "libxml2";
              else
                 p["parser"] = Lay->Datasource.parser.toAscii().data();

              if (!Lay->Datasource.url.isEmpty() && !Lay->Datasource.bbox.isEmpty())
              {
                 p["url"] = Lay->Datasource.url.toAscii().data();
                 p["bbox"] = Lay->Datasource.bbox.toAscii().data();
              }
              else
                 p["file"] = shapePath.toAscii().data();
           }
           else
           {
              cerr << "Warning file " << XmlPath.toAscii().data() << ", line " << XmlLine << ": Layer with no source! Ingnoring!" << endl;
              return true;
           }

           layer lyr(Lay->name.toAscii().data());

           if (!Lay->title.isEmpty())
              lyr.set_title(Lay->title.toAscii().data());

           if (!Lay->abstract.isEmpty())
              lyr.set_abstract(Lay->abstract.toAscii().data());

           lyr.set_datasource(datasource_cache::instance()->create(p));

           if (!Lay->srs.isEmpty())
              lyr.set_srs(Lay->srs.toAscii().data());

           if (Lay->minzoom > 0.0)
              lyr.setMinZoom(Lay->minzoom);

           if (Lay->maxzoom > 0.0)
              lyr.setMaxZoom(Lay->maxzoom);

           lyr.set_clear_label_cache(Lay->clear_label);

           // Add the styles
           for (int i = 0; i < Lay->Styles.size(); i++)
           {
              if (findStyle (Lay->Styles.at(i)) != 0)
                 lyr.add_style(Lay->Styles.at(i).toAscii().data());
              else
                 cerr << "Warning file " << XmlPath.toAscii().data() << ", line " << XmlLine << ": Style \"" << Lay->Styles.at(i).toAscii().data() << "\" does not exist!" << endl;
           }

           lyr.setActive(Lay->status);
           lyr.setQueryable(true);
           m.addLayer(lyr);
           box2d <double>le(lyr.envelope());
           setMaxExtent(le.minx(), le.miny(), le.maxx(), le.maxy());
        }
        else if (qName.toLower() == QString("map"))
        {
           Container = in_root;
           ControlSet = true;
        }
        else if (qName.toLower() == QString("pointsymbolizer"))
        {
           Container = in_rule;

           if (!Rule || !PointSymbolizer)
           {
              KMessageBox::error(0, i18n("Error parsing %1, line %2: Ending of POINTSYMBOLIZER without start, or outside of a RULE detected!").arg(XmlPath).arg(XmlLine));
              return false;
           }

           if (PointSymbolizer->file.length() == 0 || PointSymbolizer->width == 0 || PointSymbolizer->height == 0)
           {
              cerr << "Warning file " << XmlPath.toAscii().data() << ", line " << XmlLine << ": Empty POINTSYMBOLIZER!" << endl;
              point_symbolizer psym;
              Rule->rl.append(psym);
           }
           else
           {
//            point_symbolizer ps(findIcon(PointSymbolizer->file).toAscii().data(), getTypeText(PointSymbolizer->type), PointSymbolizer->width, PointSymbolizer->height);
              point_symbolizer ps(parse_path(findIcon(PointSymbolizer->file).toAscii().data()));
              ps.set_allow_overlap (PointSymbolizer->allow_overlap);
              Rule->rl.append(ps);
           }
        }
        else if (qName.toLower() == QString("linesymbolizer"))
        {
           Container = in_rule;

           if (!Rule || !LineSymbolizer)
           {
              KMessageBox::error(0, i18n("Error parsing %1, line %2: Ending of LINESYMBOLIZER without start, or outside of a RULE detected!").arg(XmlPath).arg(XmlLine));
              return false;
           }

           stroke st;
           st.set_color (setColor(LineSymbolizer->stroke));

           if (LineSymbolizer->stroke_width != 0.0)
              st.set_width (LineSymbolizer->stroke_width);

           if (!LineSymbolizer->stroke_linejoin.isEmpty())
           {
              if (LineSymbolizer->stroke_linejoin.toLower() == QString("miter"))
                 st.set_line_join (mapnik::MITER_JOIN);
              else if (LineSymbolizer->stroke_linejoin.toLower() == QString("miter_revert") ||
                         LineSymbolizer->stroke_linejoin.toLower() == QString("miter-revert"))
                 st.set_line_join (mapnik::MITER_REVERT_JOIN);
              else if (LineSymbolizer->stroke_linejoin.toLower() == QString("round"))
                 st.set_line_join (mapnik::ROUND_JOIN);
              else if (LineSymbolizer->stroke_linejoin.toLower() == QString("bevel"))
                 st.set_line_join (mapnik::BEVEL_JOIN);
              else
                 cerr << "Error parsing " << XmlPath.toAscii().data() << ", line " << XmlLine << ": Unknown >>line_join<< \"" << LineSymbolizer->stroke_linejoin.toAscii().data() << "\" --> ignoring!" << endl;
           }

           if (!LineSymbolizer->stroke_linecap.isEmpty())
           {
              if (LineSymbolizer->stroke_linecap.toLower() == QString("butt"))
                st.set_line_cap (mapnik::BUTT_CAP);
              else if (LineSymbolizer->stroke_linecap.toLower() == QString("square"))
                st.set_line_cap (mapnik::SQUARE_CAP);
              else if (LineSymbolizer->stroke_linecap.toLower() == QString("round"))
                st.set_line_cap (mapnik::ROUND_CAP);
              else
                 cerr << "Error parsing " << XmlPath.toAscii().data() << ", line " << XmlLine << ": Unknown >>line_cap<< \"" << LineSymbolizer->stroke_linecap.toAscii().data() << "\" --> ignoring!" << endl;
           }

           if (LineSymbolizer->stroke_dasharray[0] > 0 || LineSymbolizer->stroke_dasharray[1] > 0)
              st.add_dash(LineSymbolizer->stroke_dasharray[0], LineSymbolizer->stroke_dasharray[1]);

           if (LineSymbolizer->stroke_opacity != 0)
              st.set_opacity(LineSymbolizer->stroke_opacity);

           Rule->rl.append(line_symbolizer(st));
        }
        else if (qName.toLower() == QString("polygonsymbolizer"))
        {
           Container = in_rule;

           if (!Rule || !PolygonSymbolizer)
           {
              KMessageBox::error(0, i18n("Error parsing %1, line %2: Ending of POLYGONSYMBOLIZER without start, or outside of a RULE detected!").arg(XmlPath).arg(XmlLine));
              return false;
           }

           polygon_symbolizer ps(setColor(PolygonSymbolizer->fill));

           if (PolygonSymbolizer->fill_opacity > 0.0)
              ps.set_opacity(PolygonSymbolizer->fill_opacity);

           Rule->rl.append(ps);
        }
        else if (qName.toLower() == QString("textsymbolizer"))
        {
           Container = in_rule;

           if (!Rule || !TextSymbolizer)
           {
              KMessageBox::error(0, i18n("Error parsing %1, line %2: Ending of TEXTSYMBOLIZER without start, or outside of a RULE detected!").arg(XmlPath).arg(XmlLine));
              return false;
           }

           if (TextSymbolizer->name.length() <= 0 || TextSymbolizer->face_name.length() <= 0 || TextSymbolizer->size <= 0)
              cerr << "Error parsing " << XmlPath.toAscii().data() << ", line " << XmlLine << ": Empty TEXTSYMBOLIZER found --> ignoring!" << endl;
           else
           {
//            text_symbolizer ts(TextSymbolizer->name.toAscii().data(), TextSymbolizer->face_name.toAscii().data(), TextSymbolizer->size, setColor(TextSymbolizer->fill));
              std::stringstream s;
              s << "[" << TextSymbolizer->name.toAscii().data() << "]";
              text_symbolizer ts(parse_expression(s.str()), TextSymbolizer->face_name.toAscii().data(), TextSymbolizer->size, setColor(TextSymbolizer->fill));

              if (TextSymbolizer->halo_radius != 0.0)
                 ts.set_halo_radius((unsigned int)TextSymbolizer->halo_radius);

              if (TextSymbolizer->wrap_width != 0.0)
                 ts.set_wrap_width((unsigned int)TextSymbolizer->wrap_width);

              if (TextSymbolizer->mindistance != 0)
                 ts.set_label_spacing(TextSymbolizer->mindistance);

              if (!TextSymbolizer->placement.isEmpty())
              {
                 if (TextSymbolizer->placement.toLower() == QString("point"))
                    ts.set_label_placement(mapnik::POINT_PLACEMENT);
                 else if (TextSymbolizer->placement.toLower() == QString("line"))
                    ts.set_label_placement(mapnik::LINE_PLACEMENT);
                 else
                    cerr << "Error parsing " << XmlPath.toAscii().data() << ", line " << XmlLine << ": Unknown >>label placement<< \"" << TextSymbolizer->placement.toAscii().data() << "\" --> ignoring!" << endl;
              }

              if (!TextSymbolizer->alignment.isEmpty())
              {
                 if (TextSymbolizer->alignment.toLower() == QString("top"))
                    ts.set_vertical_alignment(mapnik::V_TOP);
                 else if (TextSymbolizer->alignment.toLower() == QString("middle"))
                    ts.set_vertical_alignment(mapnik::V_MIDDLE);
                 else if (TextSymbolizer->alignment.toLower() == QString("bottom"))
                    ts.set_vertical_alignment(mapnik::V_BOTTOM);
                 else
                    cerr << "Error parsing " << XmlPath.toAscii().data() << ", line " << XmlLine << ": Unknown >>vertical placement<< \"" << TextSymbolizer->alignment.toAscii().data() << "\" --> ignoring!" << endl;
              }

              if (TextSymbolizer->dx != 0 || TextSymbolizer->dy != 0)
                 ts.set_displacement(TextSymbolizer->dx, TextSymbolizer->dy);

              Rule->rl.append(ts);
           }
        }
        else if (qName.toLower() == QString("polygonpatternsymbolizer"))
        {
           Container = in_rule;

           if (!Rule || !PolygonPatternSymbolizer)
           {
              KMessageBox::error(0, i18n("Error parsing %1, line %2: Endin of POLYGONPATTERNSYMBOLIZER without start, or outside of a RULE detected!").arg(XmlPath).arg(XmlLine));
              return false;
           }

           if (PolygonPatternSymbolizer->file.length() <= 0)
              cerr << "Error parsing " << XmlPath.toAscii().data() << ", line " << XmlLine << ": Incomplete POLYGONPATTERNSYMBOLIZER --> ignoring!" << endl;
           else
           {
//            Rule->rl.append(polygon_pattern_symbolizer(findIcon(PolygonPatternSymbolizer->file).toAscii().data(),
//                                              getTypeText(PolygonPatternSymbolizer->type),
//                                              PolygonPatternSymbolizer->width,
//                                              PolygonPatternSymbolizer->height));
              Rule->rl.append(polygon_pattern_symbolizer(parse_path(findIcon(PolygonPatternSymbolizer->file).toAscii().data())));
           }
        }
        else if (qName.toLower() == QString("shieldsymbolizer"))
        {
           Container = in_rule;

           if (!Rule || !ShieldSymbolizer)
           {
              KMessageBox::error(0, i18n("Error parsing %1, line %2: Ending of SHIELDSYMBOLIZER without start, or outside of a RULE detected!").arg(XmlPath).arg(XmlLine));
              return false;
           }

//         shield_symbolizer ss(ShieldSymbolizer->name.toAscii().data(),
//                              ShieldSymbolizer->face_name.toAscii().data(),
//                              ShieldSymbolizer->size, setColor(ShieldSymbolizer->fill),
//                              findIcon(ShieldSymbolizer->file).toAscii().data(),
//                              getTypeText(ShieldSymbolizer->type),
//                              ShieldSymbolizer->width, ShieldSymbolizer->height);
           std::stringstream s;
           s << "[" << ShieldSymbolizer->name.toAscii().data() << "]";
           shield_symbolizer ss(parse_expression(s.str()),
                                ShieldSymbolizer->face_name.toAscii().data(),
                                ShieldSymbolizer->size, setColor(ShieldSymbolizer->fill),
                                parse_path(findIcon(ShieldSymbolizer->file).toAscii().data()));

           if (!ShieldSymbolizer->placement.isEmpty())
              ss.set_label_placement((ShieldSymbolizer->placement.toLower() == QString("point")) ? mapnik::POINT_PLACEMENT : mapnik::LINE_PLACEMENT);

           if (ShieldSymbolizer->dx != 0 || ShieldSymbolizer->dy != 0)
              ss.set_displacement(ShieldSymbolizer->dx, ShieldSymbolizer->dy);

           if (ShieldSymbolizer->mindistance != 0)
              ss.set_label_spacing(ShieldSymbolizer->mindistance);

           Rule->rl.append(ss);
        }
        else if (qName.toLower() == QString("linepatternsymbolizer"))
        {
           Container = in_rule;

           if (!Rule || !LinePatternSymbolizer)
           {
              KMessageBox::error(0, i18n("Error parsing %1, line %2: Ending of LINEPATTERNSYMBOLIZER without start, or outside of a RULE detected!").arg(XmlPath).arg(XmlLine));
              return false;
           }

//         Rule->rl.append(line_pattern_symbolizer(findIcon(LinePatternSymbolizer->file).toAscii().data(),
//                                              getTypeText(LinePatternSymbolizer->type),
//                                              LinePatternSymbolizer->width,
//                                              LinePatternSymbolizer->height));
           Rule->rl.append(line_pattern_symbolizer(parse_path(findIcon(LinePatternSymbolizer->file).toAscii().data())));
        }
        else if (qName.toLower() == QString("filter") ||
                 qName.toLower() == QString("maxscaledenominator") ||
                 qName.toLower() == QString("minscaledenominator"))
           Container = in_rule;
        else if (qName.toLower() == QString("rule"))
           Container = in_style;
        else if (qName.toLower() == QString("elsefilter"))
        {
           Container = in_rule;

           if (!Rule)
           {
              KMessageBox::error(0, i18n("Error parsing %1, line %2: Ending of ELSEFILTER outside of a RULE detected!").arg(XmlPath).arg(XmlLine));
              return false;
           }

           Rule->rl.set_else(true);
        }
        else if (qName.toLower() == QString("style"))
        {
           Container = in_map;
           feature_type_style style;

           if (Style->rule)
           {
              Rule = Style->rule;

              while (Rule)
              {
                 style.add_rule(Rule->rl);
                 Rule = Rule->next;
              }
           }

           // Add style to map
           m.insert_style(Style->name.toAscii().data(), style);
        }

        return true;
}

/*
 * The reader calls this function when it has parsed a chunk of character data
 * - either normal character data or character data inside a CDATA section.
 */
bool SRender::characters (const QString& chraw)
{
        if (chraw.at(0) == QChar('\n'))
        {
           XmlLine++;
           return true;
        }

        QString ch = chraw.trimmed();

        if (ch.length() == 0)
           return true;

        if (Container == in_rule && Rule)
        {
           if (Field == FLD_FILTER)
           {
              Rule->filter = ch;

              if (!Rule->filter.isEmpty())
              {
                 std::stringstream s;
                 s << "[" << Rule->filter.toLatin1().data() << "] = 'latin1'";
                 Rule->rl.set_filter(parse_expression(s.str()));
//               Rule->rl.set_filter(create_filter(Rule->filter.toLatin1().data(), "latin1"));
              }
              else
                 cerr << "Warning in file " << XmlPath.toAscii().data() << " at line " << XmlLine << ": Ignoring empty filter!" << endl;
           }
           else if (Field == FLD_MAXSCALE)
           {
              Rule->maxscale = ch.toDouble();
              Rule->rl.set_max_scale(Rule->maxscale);
           }
           else if (Field == FLD_MINSCALE)
           {
              Rule->minscale = ch.toDouble();
              Rule->rl.set_min_scale(Rule->minscale);
           }
        }
        else if (Container == in_linesymbolizer && LineSymbolizer)
        {
           if (Field == FLD_CSSPARAMETER)
           {
              if (Names == stroke_stroke)
                 LineSymbolizer->stroke = colorToUInt(ch);
              else if (Names == stroke_width)
                 LineSymbolizer->stroke_width = ch.toDouble();
              else if (Names == stroke_linejoin)
                 LineSymbolizer->stroke_linejoin = ch;
              else if (Names == stroke_linecap)
                 LineSymbolizer->stroke_linecap = ch;
              else if (Names == stroke_opacity)
                 LineSymbolizer->stroke_opacity = ch.toDouble();
              else if (Names == stroke_dasharray)
              {
              int pos;
              QString arr = ch;
              QStringList list;

                 list = arr.split(",", QString::SkipEmptyParts);

                 for (pos = 0; pos < list.size() && pos < 10; pos++)
                    LineSymbolizer->stroke_dasharray[pos] = list.at(pos).toDouble();

                 LineSymbolizer->stroke_anz = pos;
              }
           }
        }
        else if (Container == in_polygonsymbolizer && PolygonSymbolizer)
        {
           if (Field == FLD_CSSPARAMETER)
           {
              if (Names == fill)
                 PolygonSymbolizer->fill = colorToUInt(ch);
              else if (Names == fill_opacity)
                 PolygonSymbolizer->fill_opacity = ch.toDouble();
           }
        }
        else if (Container == in_layer && Lay)
        {
           if (Field == FLD_STYLENAME)
              Lay->Styles << ch;
        }
        else if (Container == in_datasource && Lay)
        {
           if (Field == FLD_PARAMETER)
           {
              if (Names == type)
                 Lay->Datasource.type = ch;
              else if (Names == file)
              {
              QFileInfo qf(ch);
              QString hv0;

                 hv0 = shapePath;

                 if (hv0.right(1) != QString("/"))
                    hv0 += "/";

                 hv0 += qf.fileName();

                 if (__map_type == MAP_SHAPE)
                    qf.setFile (hv0 + ".shp");
                 else if (__map_type == MAP_OSM)
                    qf.setFile (hv0 + ".osm");

                 if (!qf.exists())
                 {
                    if (__map_type == MAP_SHAPE)
                       KMessageBox::error(0, i18n("The shape file \"%1\" at line %2 does not exist!").arg(hv0+".shp").arg(XmlLine));
                    else if (__map_type == MAP_OSM)
                       KMessageBox::error(0, i18n("The OSM file \"%1\" at line %2 does not exist!").arg(hv0+".osm").arg(XmlLine));

                    return false;
                 }

                 Lay->Datasource.file = hv0;
              }
              else if (Names == parser__)
                 Lay->Datasource.parser = ch;
              else if (Names == url)
                 Lay->Datasource.url = ch;
              else if (Names == bbox)
                 Lay->Datasource.bbox = ch;
              else if (Names == host)
                 Lay->Datasource.host = ch;
              else if (Names == user)
                 Lay->Datasource.user = ch;
              else if (Names == dbname)
                 Lay->Datasource.dbname = ch;
              else if (Names == table)
                 Lay->Datasource.table = ch;
              else if (Names == estimate_extent)
                 Lay->Datasource.estimate_extent = getBool(ch);
              else if (Names == extent)
              {
                 QString arr = ch;
                 QStringList list;
                 list = arr.split(",");

                 if (list.size() >= 1)
                    Lay->Datasource.ext_lx = list.at(0).toDouble();

                 if (list.size() >= 2)
                    Lay->Datasource.ext_ly = list.at(1).toDouble();

                 if (list.size() >= 3)
                    Lay->Datasource.ext_rx = list.at(2).toDouble();

                 if (list.size() >= 4)
                    Lay->Datasource.ext_ry = list.at(3).toDouble();
              }
           }
        }

        return true;
}

QString SRender::getKey (int pos)
{
int i = 0;

        while (token[i].id > 0)
        {
           if (token[i].id == pos)
              return token[i].name;

           i++;
        }

        return QString::null;
}

TYPES SRender::getType(QString ty)
{
        if (ty.toLower() == QString("png"))
           return type_png;
        else if (ty.toLower() == QString("gif"))
           return type_gif;
        else if (ty.toLower() == QString("jpg"))
           return type_jpg;
        else if (ty.toLower() == QString("xpm"))
           return type_xpm;
        else if (ty.toLower() == QString("bmp"))
           return type_bmp;
        else if (ty.toLower() == QString("tif") || ty.toLower() == QString("tiff"))
           return type_tif;

        return type_png;
}

char *grTypes[] = { (char *)"png", (char *)"gif", (char *)"jpg", (char*)"xpm",
                    (char *)"bmp", (char *)"tif" };

char *SRender::getTypeText(TYPES type)
{
        switch (type)
        {
           case type_png: return grTypes[0]; break;
           case type_gif: return grTypes[1]; break;
           case type_jpg: return grTypes[2]; break;
           case type_xpm: return grTypes[3]; break;
           case type_bmp: return grTypes[4]; break;
           case type_tif: return grTypes[5]; break;
        }

        return 0;
}

bool SRender::getBool(QString b)
{
        if (b.toLower() == QString("true") ||
            b.toLower() == QString("on") ||
            b.toLower() == QString("1") ||
            b.toLower() == QString("yes") ||
            b.toLower() == QString("t") ||
            b.toLower() == QString("y"))
           return true;

        return false;
}

bool SRender::getMap (double lx, double ly, double rx, double ry)
{
QXmlSimpleReader reader;
QString hv0;
QFile file(XmlPath);
QDir dir(fontPath);
double plx, ply, prx, pry;

        if (_width <= 0 || _height <= 0)
           return false;

        hv0 = pluginPath;

        if (hv0.right(1) != QString("/"))
           hv0 += "/";

        datasource_cache::instance()->register_datasources(hv0.toAscii().data());
        hv0 = fontPath;

        if (hv0.right(1) != QString("/"))
           hv0 += "/";

        // Load all fonts in directory
        if (!dir.exists())
        {
           KMessageBox::error(0, i18n("The font directory does not exist! Please select a valid directory with at least one true type font in it!"));
           return false;
        }

        QStringList filters;
        filters << "*.ttf";
        dir.setNameFilters(filters);
        dir.setFilter(QDir::Readable | QDir::Files);
        QFileInfoList list = dir.entryInfoList();

        for (int i = 0; i < list.size(); ++i)
        {
        QString f;

           QFileInfo fileInfo = list.at(i);
           f = hv0 + fileInfo.fileName();
           freetype_engine::register_font(f.toAscii().data());
        }

        m.set_width(_width);
        m.set_height(_height);

        try
        {
           if (!ControlSet)     // Initialize the map?
           {
              QXmlInputSource source (&file);
              reader.setContentHandler (this);
              reader.parse (source);
           }

           plx = lx;
           ply = ly;
           prx = rx;
           pry = ry;
           projection pj(m.srs());

           if (!geographic && pj.is_geographic())
           {
              pj.inverse(plx, ply);
              pj.inverse(prx, pry);
           }

           if (geographic && pj.is_geographic())
           {
              pj.forward(plx, ply);
              pj.forward(prx, pry);
           }

           // First we use Mapnik to create the map
           m.zoom_to_box(box2d<double>(plx, ply, prx, pry));

           // Here we render the map to an image buffer
           image_32 buf(m.width(), m.height());
           agg_renderer<image_32> ren(m, buf);
           ren.apply();

           // Put the image into a Qt object
           QImage image((uchar*)buf.raw_data(), m.width(), m.height(), QImage::Format_ARGB32);
           pxmap = QPixmap::fromImage(image.rgbSwapped());
        }

        catch (const mapnik::config_error &ex)
        {
           KMessageBox::error(0, i18n("Configuration error: %1").arg(ex.what()));
           return false;
        }

        catch (const std::exception &ex)
        {
           KMessageBox::error(0, i18n("Exception at file %1: %2").arg(XmlPath).arg(ex.what()));
           return false;
        }

        catch (...)
        {
           KMessageBox::error(0, i18n("Unknown exception occured!"));
           return false;
        }

        return true;
}

void SRender::setMaxExtent(double lx, double ly, double rx, double ry)
{
        if (lx > 0 && _lx > lx)
           _lx = lx;

        if (lx < 0 && _lx < lx)
           _lx = lx;

        if (ly > 0 && _ly > ly)
           _ly = ly;

        if (ly < 0 && _ly < ly)
           _ly = ly;

        if (rx > 0 && _rx < rx)
           _rx = rx;

        if (rx < 0 && _rx > rx)
           _rx = rx;

        if (ry > 0 && _ry < ry)
           _ry = ry;

        if (ry < 0 && _ry > ry)
           _ry = ry;
}

QString SRender::findIcon(QString ic)
{
QString ptf, icon;
QFileInfo fi(ic);

        icon = fi.fileName();
        ptf = KStandardDirs::locate("data", QString("sportwatcher/icons/%1").arg(icon));

        if (ptf.length() < icon.length())
        {
           KMessageBox::error(0, i18n("The icon %1 was not found!").arg(icon));
           ptf.clear();
        }

        return ptf;
}

color SRender::setColor(unsigned col)
{
color c;
#if MAPNIK_VERSION == 600
        c.set_bgr(col);
#else
        int r, g, b;
        b = col / 65536;
        g = (col - (b * 65536)) / 256;
        r = col - ((b* 65536) + (g * 256));
        c.set_red(r);
        c.set_green(g);
        c.set_blue(b);
#endif
        return c;
}

RULE *SRender::getLastRule(RULE *first)
{
RULE *akt = first;

        while (akt)
        {
           if (!akt->next)
              return akt;

           akt = akt->next;
        }

        return 0;
}

POINTSYMBOLIZER *SRender::getLastPointSymbolizer(POINTSYMBOLIZER *first)
{
POINTSYMBOLIZER *akt = first;

        while (akt)
        {
           if (!akt->next)
              return akt;

           akt = akt->next;
        }

        return 0;
}

LINESYMBOLIZER *SRender::getLastLineSymbolizer(LINESYMBOLIZER *first)
{
LINESYMBOLIZER *akt = first;

        while (akt)
        {
           if (!akt->next)
              return akt;

           akt = akt->next;
        }

        return 0;
}

POLYGONSYMBOLIZER *SRender::getLastPolygonSymbolizer(POLYGONSYMBOLIZER *first)
{
POLYGONSYMBOLIZER *akt = first;

        while (akt)
        {
           if (!akt->next)
              return akt;

           akt = akt->next;
        }

        return 0;
}

TEXTSYMBOLIZER *SRender::getLastTextSymbolizer(TEXTSYMBOLIZER *first)
{
TEXTSYMBOLIZER *akt = first;

        while (akt)
        {
           if (!akt->next)
              return akt;

           akt = akt->next;
        }

        return 0;
}

POLYGONPATTERNSYMBOLIZER *SRender::getLastPolygonPatternSymbolizer(POLYGONPATTERNSYMBOLIZER *first)
{
POLYGONPATTERNSYMBOLIZER *akt = first;

        while (akt)
        {
           if (!akt->next)
              return akt;

           akt = akt->next;
        }

        return 0;
}

SHIELDSYMBOLIZER *SRender::getLastShieldSymbolizer(SHIELDSYMBOLIZER *first)
{
SHIELDSYMBOLIZER *akt = first;

        while (akt)
        {
           if (!akt->next)
              return akt;

           akt = akt->next;
        }

        return 0;
}

LINEPATTERNSYMBOLIZER *SRender::getLastLinePatternSymbolizer(LINEPATTERNSYMBOLIZER *first)
{
LINEPATTERNSYMBOLIZER *akt = first;

        while (akt)
        {
           if (!akt->next)
              return akt;

           akt = akt->next;
        }

        return 0;
}

STYLE *SRender::findStyle(QString name)
{
STYLE *akt = firstStyle;

        while (akt)
        {
           if (akt->name.toLower() == name.toLower())
              return akt;

           akt = akt->next;
        }

        return 0;
}

unsigned SRender::colorToUInt(QString col)
{
QColor qc(col);

        return (qc.blue() * 65536) + (qc.green() * 256) + qc.red();
}

STYLE *SRender::allocStyle()
{
STYLE *St = new STYLE;

        St->name.clear();
        St->rule = 0;
        St->next = 0;
        return St;
}

RULE *SRender::allocRule()
{
RULE *Ru = new RULE;

        Ru->name.clear();
        Ru->title.clear();
        Ru->maxscale = 0;
        Ru->minscale = 0;
        Ru->elsefilter = false;
        Ru->filter.clear();
        Ru->LineSymbolizer = 0;
        Ru->PolygonSymbolizer = 0;
        Ru->TextSymbolizer = 0;
        Ru->PointSymbolizer = 0;
        Ru->PolygonPatternSymbolizer = 0;
        Ru->ShieldSymbolizer = 0;
        Ru->LinePatternSymbolizer = 0;
        Ru->next = 0;
        return Ru;
}

LAYER *SRender::allocLayer()
{
LAYER *La = new LAYER;

        La->name.clear();       // The unique name
        La->title.clear();
        La->abstract.clear();
        La->status = false;     // Is it active?
        La->clear_label = false;
        La->srs.clear();        // Projection
        La->minzoom = 0.0;
        La->maxzoom = 0.0;
        La->queryable = false;
        La->Datasource.type.clear();
        La->Datasource.file.clear();
        La->Datasource.parser.clear();
        La->Datasource.url.clear();
        La->Datasource.bbox.clear();
        La->Datasource.host.clear();
        La->Datasource.user.clear();
        La->Datasource.dbname.clear();
        La->Datasource.table.clear();
        La->Datasource.estimate_extent = false;
        La->Datasource.ext_lx = 0.0;
        La->Datasource.ext_ly = 0.0;
        La->Datasource.ext_rx = 0.0;
        La->Datasource.ext_ry = 0.0;
        La->next = 0;
        return La;
}

LINEPATTERNSYMBOLIZER *SRender::allocLinePatternSymbolizer()
{
LINEPATTERNSYMBOLIZER *lps = new LINEPATTERNSYMBOLIZER;

        lps->file.clear();
        lps->type = type_png;           // enum TYPES
        lps->width = 0.0;
        lps->height = 0.0;
        lps->next = 0;
        return lps;
}

SHIELDSYMBOLIZER *SRender::allocShieldSymbolizer()
{
SHIELDSYMBOLIZER *ss = new SHIELDSYMBOLIZER;

        ss->name.clear();
        ss->face_name.clear();
        ss->size = 0.0;
        ss->fill = 0;                   // Color
        ss->placement.clear();
        ss->file.clear();
        ss->type = type_png;            // enum TYPES
        ss->width = 0.0;
        ss->height = 0.0;
        ss->dx = 0.0;
        ss->dy = 0.0;
        ss->mindistance = 0.0;
        ss->maxdistance = 0.0;
        ss->next = 0;
        return ss;
}

POLYGONPATTERNSYMBOLIZER *SRender::allocPolygonPatternSymbolizer()
{
POLYGONPATTERNSYMBOLIZER *pps = new POLYGONPATTERNSYMBOLIZER;

        pps->file.clear();
        pps->type = type_png;           // enum TYPES
        pps->width = 0.0;
        pps->height = 0.0;
        pps->allow_overlap = false;
        pps->next = 0;
        return pps;
}

POINTSYMBOLIZER *SRender::allocPointSymbolizer()
{
POINTSYMBOLIZER *ps = new POINTSYMBOLIZER;

        ps->file.clear();
        ps->type = type_png;            // enum TYPES
        ps->width = 0.0;
        ps->height = 0.0;
        ps->allow_overlap = false;
        ps->next = 0;
        return ps;
}

TEXTSYMBOLIZER *SRender::allocTextSymbolizer()
{
TEXTSYMBOLIZER *ts = new TEXTSYMBOLIZER;

        ts->name.clear();
        ts->face_name.clear();
        ts->placement.clear();
        ts->alignment.clear();
        ts->size = 0;
        ts->fill = 0;                   // Color
        ts->halo_radius = 0;
        ts->wrap_width = 0;
        ts->dx = 0.0;
        ts->dy = 0.0;
        ts->mindistance = 0.0;
        ts->maxdistance = 0.0;
        ts->next = 0;
        return ts;
}

POLYGONSYMBOLIZER *SRender::allocPolygonSymbolizer()
{
POLYGONSYMBOLIZER *ps = new POLYGONSYMBOLIZER;

        memset (ps, 0, sizeof(POLYGONSYMBOLIZER));
        return ps;
}

LINESYMBOLIZER *SRender::allocLineSymbolizer()
{
LINESYMBOLIZER *ls = new LINESYMBOLIZER;

        ls->stroke = 0;         // Color
        ls->stroke_width = 0.0;
        ls->stroke_linejoin.clear();
        ls->stroke_linecap.clear();

        for (int i = 0; i < 10; i++)
           ls->stroke_dasharray[i] = 0.0;

        ls->stroke_anz = 0;             // number of entries in dasharray
        ls->stroke_opacity = 0.0;
        ls->next = 0;
        return ls;
}

#endif // HAVE_MAPNIK