Exemplo n.º 1
0
bool MorphologyEffect::load(const KoXmlElement &element, const KoFilterEffectLoadingContext &context)
{
    if (element.tagName() != id())
        return false;

    m_radius = QPointF();
    m_operator = Erode;

    if (element.hasAttribute("radius")) {
        QString radiusStr = element.attribute("radius").trimmed();
        QStringList params = radiusStr.replace(',', ' ').simplified().split(' ');
        switch (params.count()) {
        case 1:
            m_radius.rx() = params[0].toDouble()*72./90.;
            m_radius.ry() = m_radius.x();
            break;
        case 2:
            m_radius.rx() = params[0].toDouble()*72./90.;
            m_radius.ry() = params[1].toDouble()*72./90.;
            break;
        default:
            m_radius = QPointF();
        }
    }

    m_radius = context.convertFilterPrimitiveUnits(m_radius);

    if (element.hasAttribute("operator")) {
        QString op = element.attribute("operator");
        if (op == "dilate")
            m_operator = Dilate;
    }

    return true;
}
KoFilterEffectStack * FilterEffectResource::toFilterStack() const
{
    KoFilterEffectStack * filterStack = new KoFilterEffectStack();
    if (!filterStack)
        return 0;

    QByteArray data = m_data.toByteArray();
    KoXmlDocument doc;
    doc.setContent(data);
    KoXmlElement e = doc.documentElement();

    // only allow obect bounding box units
    if (e.hasAttribute("filterUnits") && e.attribute("filterUnits") != "objectBoundingBox")
        return 0;

    if (e.attribute("primitiveUnits") != "objectBoundingBox")
        return 0;

    // parse filter region rectangle
    QRectF filterRegion;
    filterRegion.setX(fromPercentage(e.attribute("x", "-0.1")));
    filterRegion.setY(fromPercentage(e.attribute("y", "-0.1")));
    filterRegion.setWidth(fromPercentage(e.attribute("width", "1.2")));
    filterRegion.setHeight(fromPercentage(e.attribute("height", "1.2")));
    filterStack->setClipRect(filterRegion);

    KoFilterEffectLoadingContext context(QString(""));

    KoFilterEffectRegistry * registry = KoFilterEffectRegistry::instance();

    // create the filter effects and add them to the shape
    for (KoXmlNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
        KoXmlElement primitive = n.toElement();
        KoFilterEffect * filterEffect = registry->createFilterEffectFromXml(primitive, context);
        if (!filterEffect) {
            qWarning() << "filter effect" << primitive.tagName() << "is not implemented yet";
            continue;
        }

        // parse subregion
        qreal x = fromPercentage(primitive.attribute("x", "0"));
        qreal y = fromPercentage(primitive.attribute("y", "0"));
        qreal w = fromPercentage(primitive.attribute("width", "1"));
        qreal h = fromPercentage(primitive.attribute("height", "1"));
        QRectF subRegion(QPointF(x, y), QSizeF(w, h));

        if (primitive.hasAttribute("in"))
            filterEffect->setInput(0, primitive.attribute("in"));
        if (primitive.hasAttribute("result"))
            filterEffect->setOutput(primitive.attribute("result"));

        filterEffect->setFilterRect(subRegion);

        filterStack->appendFilterEffect(filterEffect);
    }

    return filterStack;
}
Exemplo n.º 3
0
bool SvgParser::parseClipPath(const KoXmlElement &e, const KoXmlElement &referencedBy)
{
    SvgClipPathHelper clipPath;

    // Use the filter that is referencing, or if there isn't one, the original filter
    KoXmlElement b;
    if (!referencedBy.isNull())
        b = referencedBy;
    else
        b = e;

    // check if we are referencing another clip path
    if (e.hasAttribute("xlink:href")) {
        QString href = e.attribute("xlink:href").mid(1);
        if (! href.isEmpty()) {
            // copy the referenced clip path if found
            SvgClipPathHelper *refClipPath = findClipPath(href);
            if (refClipPath)
                clipPath = *refClipPath;
        }
    } else {
        clipPath.setContent(b);
    }

    if (b.attribute("clipPathUnits") == "objectBoundingBox")
        clipPath.setClipPathUnits(SvgClipPathHelper::ObjectBoundingBox);


    m_clipPaths.insert(b.attribute("id"), clipPath);

    return true;
}
Exemplo n.º 4
0
void Conditions::loadConditions(const KoXmlElement &element, const ValueParser *parser)
{
    Conditional newCondition;

    KoXmlElement conditionElement;
    forEachElement(conditionElement, element) {
        if (!conditionElement.hasAttribute("cond"))
            continue;

        bool ok = true;
        newCondition.cond = (Conditional::Type) conditionElement.attribute("cond").toInt(&ok);
        if(!ok)
            continue;

        if (conditionElement.hasAttribute("val1")) {
            newCondition.value1 = parser->parse(conditionElement.attribute("val1"));

            if (conditionElement.hasAttribute("val2"))
                newCondition.value2 = parser->parse(conditionElement.attribute("val2"));
        }

        if (conditionElement.hasAttribute("strval1")) {
            newCondition.value1 = Value(conditionElement.attribute("strval1"));

            if (conditionElement.hasAttribute("strval2"))
                newCondition.value2 = Value(conditionElement.attribute("strval2"));
        }

        if (conditionElement.hasAttribute("style")) {
            newCondition.styleName = conditionElement.attribute("style");
        }

        d->conditionList.append(newCondition);
    }
}
Exemplo n.º 5
0
bool CompositeEffect::load(const KoXmlElement &element, const KoFilterEffectLoadingContext &)
{
    if (element.tagName() != id())
        return false;

    QString opStr = element.attribute("operator");
    if (opStr == "over") {
        m_operation = CompositeOver;
    } else if (opStr == "in") {
        m_operation = CompositeIn;
    } else if (opStr == "out") {
        m_operation = CompositeOut;
    } else if (opStr == "atop") {
        m_operation = CompositeAtop;
    } else if (opStr == "xor") {
        m_operation = CompositeXor;
    } else if (opStr == "arithmetic") {
        m_operation = Arithmetic;
        if (element.hasAttribute("k1"))
            m_k[0] = element.attribute("k1").toDouble();
        if (element.hasAttribute("k2"))
            m_k[1] = element.attribute("k2").toDouble();
        if (element.hasAttribute("k3"))
            m_k[2] = element.attribute("k3").toDouble();
        if (element.hasAttribute("k4"))
            m_k[3] = element.attribute("k4").toDouble();
    } else {
        return false;
    }

    if (element.hasAttribute("in2")) {
        if (inputs().count() == 2)
            setInput(1, element.attribute("in2"));
        else
            addInput(element.attribute("in2"));
    }

    return true;
}
Exemplo n.º 6
0
bool FloodEffect::load(const KoXmlElement &element, const KoFilterEffectLoadingContext &)
{
    if (element.tagName() != id())
        return false;

    m_color = Qt::black;

    if (element.hasAttribute("flood-color")) {
        QString colorStr = element.attribute("flood-color").trimmed();
        if (colorStr.startsWith(QLatin1String("rgb("))) {
            QStringList channels = colorStr.mid(4, colorStr.length() - 5).split(',');
            float r = channels[0].toDouble();
            if (channels[0].contains('%'))
                r /= 100.0;
            else
                r /= 255.0;
            float g = channels[1].toDouble();
            if (channels[1].contains('%'))
                g /= 100.0;
            else
                g /= 255.0;
            float b = channels[2].toDouble();
            if (channels[2].contains('%'))
                b /= 100.0;
            else
                b /= 255.0;
            m_color.setRgbF(r, g, b);

        } else {
            m_color.setNamedColor(colorStr);
        }
        // TODO: add support for currentColor
    }

    if (element.hasAttribute("flood-opacity"))
        m_color.setAlphaF(element.attribute("flood-opacity").toDouble());

    return true;
}
Exemplo n.º 7
0
QFont Calligra::Sheets::NativeFormat::toFont(KoXmlElement & element)
{
    QFont f;
    f.setFamily(element.attribute("family"));

    bool ok;
    const int size = element.attribute("size").toInt(&ok);
    if (ok)
        f.setPointSize(size);

    const int weight = element.attribute("weight").toInt(&ok);
    if (!ok)
        f.setWeight(weight);

    if (element.hasAttribute("italic") && element.attribute("italic") == "yes")
        f.setItalic(true);

    if (element.hasAttribute("bold") && element.attribute("bold") == "yes")
        f.setBold(true);

    if (element.hasAttribute("underline") && element.attribute("underline") == "yes")
        f.setUnderline(true);

    if (element.hasAttribute("strikeout") && element.attribute("strikeout") == "yes")
        f.setStrikeOut(true);

    /* Uncomment when charset is added to kspread_dlg_layout
       + save a document-global charset
       if ( element.hasAttribute( "charset" ) )
         KGlobal::charsets()->setQFont( f, element.attribute("charset") );
        else
    */
    // ######## Not needed anymore in 3.0?
    //KGlobal::charsets()->setQFont( f, KGlobal::locale()->charset() );

    return f;
}
Exemplo n.º 8
0
bool SvgParser::parseFilter(const KoXmlElement &e, const KoXmlElement &referencedBy)
{
    SvgFilterHelper filter;

    // Use the filter that is referencing, or if there isn't one, the original filter
    KoXmlElement b;
    if (!referencedBy.isNull())
        b = referencedBy;
    else
        b = e;

    // check if we are referencing another filter
    if (e.hasAttribute("xlink:href")) {
        QString href = e.attribute("xlink:href").mid(1);
        if (! href.isEmpty()) {
            // copy the referenced filter if found
            SvgFilterHelper *refFilter = findFilter(href);
            if (refFilter)
                filter = *refFilter;
        }
    } else {
        filter.setContent(b);
    }

    if (b.attribute("filterUnits") == "userSpaceOnUse")
        filter.setFilterUnits(SvgFilterHelper::UserSpaceOnUse);
    if (b.attribute("primitiveUnits") == "objectBoundingBox")
        filter.setPrimitiveUnits(SvgFilterHelper::ObjectBoundingBox);

    // parse filter region rectangle
    if (filter.filterUnits() == SvgFilterHelper::UserSpaceOnUse) {
        filter.setPosition(QPointF(parseUnitX(b.attribute("x")),
                                   parseUnitY(b.attribute("y"))));
        filter.setSize(QSizeF(parseUnitX(b.attribute("width")),
                              parseUnitY(b.attribute("height"))));
    } else {
        // x, y, width, height are in percentages of the object referencing the filter
        // so we just parse the percentages
        filter.setPosition(QPointF(SvgUtil::fromPercentage(b.attribute("x", "-0.1")),
                                   SvgUtil::fromPercentage(b.attribute("y", "-0.1"))));
        filter.setSize(QSizeF(SvgUtil::fromPercentage(b.attribute("width", "1.2")),
                              SvgUtil::fromPercentage(b.attribute("height", "1.2"))));
    }

    m_filters.insert(b.attribute("id"), filter);

    return true;
}
Exemplo n.º 9
0
void Localization::load(const KoXmlElement& element)
{
    if (element.hasAttribute("weekStartsMonday")) {
        QString c = element.attribute("weekStartsMonday");
        if (c != "False") {
            setWeekStartDay(1 /*Monday*/);
        }
    }
    if (element.hasAttribute("decimalSymbol"))
        setDecimalSymbol(element.attribute("decimalSymbol"));
    if (element.hasAttribute("thousandsSeparator"))
        setThousandsSeparator(element.attribute("thousandsSeparator"));
    if (element.hasAttribute("currencySymbol"))
        setCurrencySymbol(element.attribute("currencySymbol"));
    if (element.hasAttribute("monetaryDecimalSymbol"))
        setMonetaryDecimalSymbol(element.attribute("monetaryDecimalSymbol"));
    if (element.hasAttribute("monetaryThousandsSeparator"))
        setMonetaryThousandsSeparator(element.attribute("monetaryThousandsSeparator"));
    if (element.hasAttribute("positiveSign"))
        setPositiveSign(element.attribute("positiveSign"));
    if (element.hasAttribute("negativeSign"))
        setNegativeSign(element.attribute("negativeSign"));
    if (element.hasAttribute("fracDigits"))
        setMonetaryDecimalPlaces(element.attribute("fracDigits").toInt());
    if (element.hasAttribute("positivePrefixCurrencySymbol")) {
        QString c = element.attribute("positivePrefixCurrencySymbol");
        setPositivePrefixCurrencySymbol(c == "True");
    }
    if (element.hasAttribute("negativePrefixCurrencySymbol")) {
        QString c = element.attribute("negativePrefixCurrencySymbol");
        setNegativePrefixCurrencySymbol(c == "True");
    }
    if (element.hasAttribute("positiveMonetarySignPosition"))
        setPositiveMonetarySignPosition((SignPosition)element.attribute("positiveMonetarySignPosition").toInt());
    if (element.hasAttribute("negativeMonetarySignPosition"))
        setNegativeMonetarySignPosition((SignPosition)element.attribute("negativeMonetarySignPosition").toInt());
    if (element.hasAttribute("timeFormat"))
        setTimeFormat(element.attribute("timeFormat"));
    if (element.hasAttribute("dateFormat"))
        setDateFormat(element.attribute("dateFormat"));
    if (element.hasAttribute("dateFormatShort"))
        setDateFormatShort(element.attribute("dateFormatShort"));
}
Exemplo n.º 10
0
KisNodeSP KisKraLoader::loadNode(const KoXmlElement& element, KisImageWSP image, KisNodeSP parent)
{
    // Nota bene: If you add new properties to layers, you should
    // ALWAYS define a default value in case the property is not
    // present in the layer definition: this helps a LOT with backward
    // compatibility.
    QString name = element.attribute(NAME, "No Name");

    QUuid id = QUuid(element.attribute(UUID, QUuid().toString()));

    qint32 x = element.attribute(X, "0").toInt();
    qint32 y = element.attribute(Y, "0").toInt();

    qint32 opacity = element.attribute(OPACITY, QString::number(OPACITY_OPAQUE_U8)).toInt();
    if (opacity < OPACITY_TRANSPARENT_U8) opacity = OPACITY_TRANSPARENT_U8;
    if (opacity > OPACITY_OPAQUE_U8) opacity = OPACITY_OPAQUE_U8;

    const KoColorSpace* colorSpace = 0;
    if ((element.attribute(COLORSPACE_NAME)).isNull()) {
        dbgFile << "No attribute color space for layer: " << name;
        colorSpace = image->colorSpace();
    }
    else {
        QString colorspacename = element.attribute(COLORSPACE_NAME);
        QString profileProductName;

        convertColorSpaceNames(colorspacename, profileProductName);

        QString colorspaceModel = KoColorSpaceRegistry::instance()->colorSpaceColorModelId(colorspacename).id();
        QString colorspaceDepth = KoColorSpaceRegistry::instance()->colorSpaceColorDepthId(colorspacename).id();
        dbgFile << "Searching color space: " << colorspacename << colorspaceModel << colorspaceDepth << " for layer: " << name;
        // use default profile - it will be replaced later in completeLoading

        colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, "");
        dbgFile << "found colorspace" << colorSpace;
        if (!colorSpace) {
            m_d->errorMessages << i18n("Layer %1 specifies an unsupported color model: %2.", name, colorspacename);
            return 0;
        }
    }

    bool visible = element.attribute(VISIBLE, "1") == "0" ? false : true;
    bool locked = element.attribute(LOCKED, "0") == "0" ? false : true;
    bool collapsed = element.attribute(COLLAPSED, "0") == "0" ? false : true;

    // Now find out the layer type and do specific handling
    QString nodeType;

    if (m_d->syntaxVersion == 1) {
        nodeType = element.attribute("layertype");
        if (nodeType.isEmpty()) {
            nodeType = PAINT_LAYER;
        }
    }
    else {
        nodeType = element.attribute(NODE_TYPE);
    }

    if (nodeType.isEmpty()) {
        m_d->errorMessages << i18n("Layer %1 has an unsupported type.", name);
        return 0;
    }


    KisNodeSP node = 0;

    if (nodeType == PAINT_LAYER)
        node = loadPaintLayer(element, image, name, colorSpace, opacity);
    else if (nodeType == GROUP_LAYER)
        node = loadGroupLayer(element, image, name, colorSpace, opacity);
    else if (nodeType == ADJUSTMENT_LAYER)
        node = loadAdjustmentLayer(element, image, name, colorSpace, opacity);
    else if (nodeType == SHAPE_LAYER)
        node = loadShapeLayer(element, image, name, colorSpace, opacity);
    else if (nodeType == GENERATOR_LAYER)
        node = loadGeneratorLayer(element, image, name, colorSpace, opacity);
    else if (nodeType == CLONE_LAYER)
        node = loadCloneLayer(element, image, name, colorSpace, opacity);
    else if (nodeType == FILTER_MASK)
        node = loadFilterMask(element, parent);
    else if (nodeType == TRANSFORM_MASK)
        node = loadTransformMask(element, parent);
    else if (nodeType == TRANSPARENCY_MASK)
        node = loadTransparencyMask(element, parent);
    else if (nodeType == SELECTION_MASK)
        node = loadSelectionMask(image, element, parent);
    else if (nodeType == FILE_LAYER) {
        node = loadFileLayer(element, image, name, opacity);
    }
    else {
        m_d->errorMessages << i18n("Layer %1 has an unsupported type: %2.", name, nodeType);
        return 0;
    }

    // Loading the node went wrong. Return empty node and leave to
    // upstream to complain to the user
    if (!node) {
        m_d->errorMessages << i18n("Failure loading layer %1 of type: %2.", name, nodeType);
        return 0;
    }

    node->setVisible(visible, true);
    node->setUserLocked(locked);
    node->setCollapsed(collapsed);
    node->setX(x);
    node->setY(y);
    node->setName(name);

    if (! id.isNull())          // if no uuid in file, new one has been generated already
        node->setUuid(id);

    if (node->inherits("KisLayer")) {
        KisLayer* layer           = qobject_cast<KisLayer*>(node.data());
        QBitArray channelFlags    = stringToFlags(element.attribute(CHANNEL_FLAGS, ""), colorSpace->channelCount());
        QString   compositeOpName = element.attribute(COMPOSITE_OP, "normal");

        layer->setChannelFlags(channelFlags);
        layer->setCompositeOpId(compositeOpName);

        if (element.hasAttribute(LAYER_STYLE_UUID)) {
            QString uuidString = element.attribute(LAYER_STYLE_UUID);
            QUuid uuid(uuidString);
            if (!uuid.isNull()) {
                KisPSDLayerStyleSP dumbLayerStyle(new KisPSDLayerStyle());
                dumbLayerStyle->setUuid(uuid);
                layer->setLayerStyle(dumbLayerStyle);
            } else {
                warnKrita << "WARNING: Layer style for layer" << layer->name() << "contains invalid UUID" << uuidString;
            }
        }
    }

    if (node->inherits("KisGroupLayer")) {
        if (element.hasAttribute(PASS_THROUGH_MODE)) {
            bool value = element.attribute(PASS_THROUGH_MODE, "0") != "0";

            KisGroupLayer *group = qobject_cast<KisGroupLayer*>(node.data());
            group->setPassThroughMode(value);
        }
    }

    if (node->inherits("KisPaintLayer")) {
        KisPaintLayer* layer            = qobject_cast<KisPaintLayer*>(node.data());
        QBitArray      channelLockFlags = stringToFlags(element.attribute(CHANNEL_LOCK_FLAGS, ""), colorSpace->channelCount());
        layer->setChannelLockFlags(channelLockFlags);

        bool onionEnabled = element.attribute(ONION_SKIN_ENABLED, "0") == "0" ? false : true;
        layer->setOnionSkinEnabled(onionEnabled);

        bool timelineEnabled = element.attribute(VISIBLE_IN_TIMELINE, "0") == "0" ? false : true;
        layer->setUseInTimeline(timelineEnabled);
    }

    if (element.attribute(FILE_NAME).isNull()) {
        m_d->layerFilenames[node.data()] = name;
    }
    else {
        m_d->layerFilenames[node.data()] = element.attribute(FILE_NAME);
    }

    if (element.hasAttribute("selected") && element.attribute("selected") == "true")  {
        m_d->selectedNodes.append(node);
    }

    if (element.hasAttribute(KEYFRAME_FILE)) {
        node->enableAnimation();
        m_d->keyframeFilenames.insert(node.data(), element.attribute(KEYFRAME_FILE));
    }

    return node;
}
Exemplo n.º 11
0
KisImageWSP KisKraLoader::loadXML(const KoXmlElement& element)
{
    QString attr;
    KisImageWSP image = 0;
    QString name;
    qint32 width;
    qint32 height;
    QString profileProductName;
    double xres;
    double yres;
    QString colorspacename;
    const KoColorSpace * cs;

    if ((attr = element.attribute(MIME)) == NATIVE_MIMETYPE) {

        if ((m_d->imageName = element.attribute(NAME)).isNull()) {
            m_d->errorMessages << i18n("Image does not have a name.");
            return KisImageWSP(0);
        }

        if ((attr = element.attribute(WIDTH)).isNull()) {
            m_d->errorMessages << i18n("Image does not specify a width.");
            return KisImageWSP(0);
        }
        width = attr.toInt();

        if ((attr = element.attribute(HEIGHT)).isNull()) {
            m_d->errorMessages << i18n("Image does not specify a height.");
            return KisImageWSP(0);
        }

        height = attr.toInt();

        m_d->imageComment = element.attribute(DESCRIPTION);

        xres = 100.0 / 72.0;
        if (!(attr = element.attribute(X_RESOLUTION)).isNull()) {
            if (attr.toDouble() > 1.0) {
                xres = attr.toDouble() / 72.0;
            }
        }

        yres = 100.0 / 72.0;
        if (!(attr = element.attribute(Y_RESOLUTION)).isNull()) {
            if (attr.toDouble() > 1.0) {
                yres = attr.toDouble() / 72.0;
            }
        }

        if ((colorspacename = element.attribute(COLORSPACE_NAME)).isNull()) {
            // An old file: take a reasonable default.
            // Krita didn't support anything else in those
            // days anyway.
            colorspacename = "RGBA";
        }

        profileProductName = element.attribute(PROFILE);
        // A hack for an old colorspacename
        convertColorSpaceNames(colorspacename, profileProductName);

        QString colorspaceModel = KoColorSpaceRegistry::instance()->colorSpaceColorModelId(colorspacename).id();
        QString colorspaceDepth = KoColorSpaceRegistry::instance()->colorSpaceColorDepthId(colorspacename).id();

        if (profileProductName.isNull()) {
            // no mention of profile so get default profile";
            cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, "");
        } else {
            cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, profileProductName);
        }

        if (cs == 0) {
            // try once more without the profile
            cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, "");
            if (cs == 0) {
                m_d->errorMessages << i18n("Image specifies an unsupported color model: %1.", colorspacename);
                return KisImageWSP(0);
            }
        }

        if (m_d->document) {
            image = new KisImage(m_d->document->createUndoStore(), width, height, cs, name);
        }
        else {
            image = new KisImage(0, width, height, cs, name);
        }
        image->setResolution(xres, yres);
        loadNodes(element, image, const_cast<KisGroupLayer*>(image->rootLayer().data()));

        KoXmlNode child;
        for (child = element.lastChild(); !child.isNull(); child = child.previousSibling()) {
            KoXmlElement e = child.toElement();
            if(e.tagName() == "ProjectionBackgroundColor") {
                if (e.hasAttribute("ColorData")) {
                    QByteArray colorData = QByteArray::fromBase64(e.attribute("ColorData").toLatin1());
                    KoColor color((const quint8*)colorData.data(), image->colorSpace());
                    image->setDefaultProjectionColor(color);
                }
            }

            if (e.tagName().toLower() == "animation") {
                loadAnimationMetadata(e, image);
            }
        }

        for (child = element.lastChild(); !child.isNull(); child = child.previousSibling()) {
            KoXmlElement e = child.toElement();
            if(e.tagName() == "compositions") {
                loadCompositions(e, image);
            }
        }
    }
    KoXmlNode child;
    for (child = element.lastChild(); !child.isNull(); child = child.previousSibling()) {
        KoXmlElement e = child.toElement();
        if (e.tagName() == "assistants") {
            loadAssistantsList(e);
        }
    }
    return image;
}
Exemplo n.º 12
0
MetaInfo ZefaniaLex::buildIndexFromXmlDoc(KoXmlDocument *xmldoc)
{
    try {

    MetaInfo info;
    int couldBe = 0;//1 = RMac

    Document indexdoc;
    const QString index = indexPath();
    QString fileTitle;
    QString uid;
    QString type;

    QDir dir("/");
    dir.mkpath(index);

    RefText refText;
    refText.setSettings(m_settings);

    IndexWriter* writer = NULL;
    const TCHAR* stop_words[] = { NULL };
    standard::StandardAnalyzer an(stop_words);

    if(IndexReader::indexExists(index.toStdString().c_str())) {
        if(IndexReader::isLocked(index.toStdString().c_str())) {
            myDebug() << "Index was locked... unlocking it.";
            IndexReader::unlock(index.toStdString().c_str());
        }
    }
    writer = new IndexWriter(index.toStdString().c_str() , &an, true);

    writer->setMaxFieldLength(0x7FFFFFFFL);
    writer->setUseCompoundFile(false);

    KoXmlNode item = xmldoc->documentElement().firstChild();
    type = xmldoc->documentElement().toElement().attribute("type", "");

    for(int c = 0; !item.isNull();) {
        QString key = "";
        QString title = "";
        QString trans = "";
        QString pron = "";
        QString desc = "";
        KoXmlElement e = item.toElement();
        if(e.tagName().compare("INFORMATION", Qt::CaseInsensitive) == 0) {
            KoXmlNode title = item.namedItem("subject");
            KoXmlNode identifer = item.namedItem("identifier");

            fileTitle = title.toElement().text();
            uid = identifer.toElement().text();

        } else if(e.tagName().compare("item", Qt::CaseInsensitive) == 0) {
            key = e.attribute("id");
            KoXmlNode details = item.firstChild();
            while(!details.isNull()) {
                KoXmlElement edetails = details.toElement();
                if(edetails.tagName().compare("title", Qt::CaseInsensitive) == 0) {
                    title = edetails.text();
                } else if(edetails.tagName().compare("transliteration", Qt::CaseInsensitive) == 0) {
                    trans = edetails.text();
                } else if(edetails.tagName().compare("pronunciation", Qt::CaseInsensitive) == 0) {
                    KoXmlNode em = details.firstChild();
                    while(!em.isNull()) {
                        if(em.toElement().tagName().compare("em", Qt::CaseInsensitive) == 0)
                            pron = "<em>" + em.toElement().text() + "</em>";
                        em = em.nextSibling();
                    }
                } else if(edetails.tagName().compare("description", Qt::CaseInsensitive) == 0) {
                    KoXmlNode descNode = details.firstChild();
                    while(!descNode.isNull()) {
                        if(descNode.nodeType() == 2) {
                            desc += descNode.toText().data();
                        } else if(descNode.nodeType() == 1) {
                            KoXmlElement descElement = descNode.toElement();
                            if(descElement.tagName().compare("reflink", Qt::CaseInsensitive) == 0) {
                                if(descElement.hasAttribute("mscope")) {
                                    const QString mscope = descElement.attribute("mscope", ";;;");

                                    VerseUrl url;
                                    url.fromMscope(mscope);

                                    desc += " <a href=\"" + url.toString() + "\">" + refText.toString(url) + "</a> ";
                                } else if(descElement.hasAttribute("target")) {
                                    desc += descElement.text();
                                }

                            } else if(descElement.tagName().compare("see", Qt::CaseInsensitive) == 0) {
                                const QString target = descElement.attribute("target", "");
                                //todo: currently we assume target = x-self
                                StrongUrl url;
                                bool ok = url.fromText(descElement.text());
                                if(ok)
                                    desc += " <a href=\"" + url.toString() + "\">" + descElement.text() + "</a> ";
                            }
                        }

                        descNode = descNode.nextSibling();
                    }
                    desc += "<hr />";
                }
                details = details.nextSibling();
            }
            if(couldBe == 0) {
                if(key.toUpper() == "A-APF" || key.toUpper() == "X-NSN" || key.toUpper() == "V-PAP-DPN") {
                    couldBe = 1;
                }
            }
            QString content = "<h3 class='strongTitle'>" + key + " - " + title + "</h3>";
            if(!trans.isEmpty()) {
                content += " (" + trans + ") ";
            }
            if(!pron.isEmpty()) {
                content += " [" + pron + "] ";
            }
            content += "<br />" + desc;
            indexdoc.clear();
#ifdef OBV_USE_WSTRING
            indexdoc.add(*_CLNEW Field(_T("key"), key.toStdWString().c_str(), Field::STORE_YES |  Field::INDEX_TOKENIZED));
            indexdoc.add(*_CLNEW Field(_T("content"), content.toStdWString().c_str(), Field::STORE_YES |  Field::INDEX_TOKENIZED));
#else
            indexdoc.add(*_CLNEW Field(_T("key"), reinterpret_cast<const wchar_t *>(key.utf16()), Field::STORE_YES |  Field::INDEX_TOKENIZED));
            indexdoc.add(*_CLNEW Field(_T("content"), reinterpret_cast<const wchar_t *>(content.utf16()), Field::STORE_YES |  Field::INDEX_TOKENIZED));
#endif
            writer->addDocument(&indexdoc);

        }
        item = item.nextSibling();
        c++;
    }
    writer->setUseCompoundFile(true);
    writer->optimize();

    writer->close();
    delete writer;
    info.setName(fileTitle);
    info.setUID(uid);
    if(type == "x-strong") {
        info.setDefaultModule(OBVCore::DefaultStrongDictModule);
        info.setContent(OBVCore::StrongsContent);
    } else if(type == "x-dictionary") {
        if(couldBe == 1) {
            info.setDefaultModule(OBVCore::DefaultRMACDictModule);
            info.setContent(OBVCore::RMacContent);
        } else {
            info.setDefaultModule(OBVCore::DefaultDictModule);
        }
    }
    return info;
    }
    catch(...) {
        return MetaInfo();
    }
}
Exemplo n.º 13
0
bool PasteCommand::processXmlData(Element *element, KoXmlDocument *data)
{
    const QRect pasteArea = element->rect();
    Sheet *const sheet = element->sheet();
    Q_ASSERT(sheet == m_sheet);
    Map *const map = sheet->map();

    const KoXmlElement root = data->documentElement(); // "spreadsheet-snippet"
    if (root.hasAttribute("cut")) {
        const Region cutRegion(root.attribute("cut"), map, sheet);
        if (cutRegion.isValid()) {
            const Cell destination(sheet, pasteArea.topLeft());
            map->dependencyManager()->regionMoved(cutRegion, destination);
        }
    }

    const int sourceHeight = root.attribute("rows").toInt();
    const int sourceWidth  = root.attribute("columns").toInt();

    // Find size of rectangle that we want to paste to (either clipboard size or current selection)
    const bool noRowsInClipboard    = root.namedItem("rows").toElement().isNull();
    const bool noColumnsInClipboard = root.namedItem("columns").toElement().isNull();
    const bool noRowsSelected       = !Region::Range(pasteArea).isRow();
    const bool noColumnsSelected    = !Region::Range(pasteArea).isColumn();
    const bool biggerSelectedWidth  = pasteArea.width()  >= sourceWidth;
    const bool biggerSelectedHeight = pasteArea.height() >= sourceHeight;

    const int pasteWidth  = biggerSelectedWidth && noRowsSelected && noRowsInClipboard
                            ? pasteArea.width() : sourceWidth;
    const int pasteHeight = biggerSelectedHeight && noColumnsSelected && noColumnsInClipboard
                            ? pasteArea.height() : sourceHeight;

    const int xOffset = noRowsInClipboard ? pasteArea.left() - 1 : 0;
    const int yOffset = noColumnsInClipboard ? pasteArea.top() - 1 : 0;

    kDebug(36005) << "selected size (col x row):" << pasteArea.width() << 'x' << pasteArea.height();
    kDebug(36005) << "source size (col x row):" << sourceWidth << 'x' << sourceHeight;
    kDebug(36005) << "paste area size (col x row):" << pasteWidth << 'x' << pasteHeight;
    kDebug(36005) << "xOffset:" << xOffset << "yOffset:" << yOffset;

    // Determine the shift direction, if needed.
    if (m_insertMode == ShiftCells) {
        if (!noColumnsInClipboard && !noRowsInClipboard) {
            // There are columns and rows in the source data.
            m_insertMode = ShiftCellsRight; // faster than down
        } else if (!noColumnsInClipboard) {
            // There are columns in the source data.
            m_insertMode = ShiftCellsRight;
        } else if (!noRowsInClipboard) {
            // There are rows in the source data.
            m_insertMode = ShiftCellsDown;
        } else {
            // Should not happen.
            // ShiftCells should only be set, if the data contains columns/rows.
            Q_ASSERT(false);
            m_insertMode = ShiftCellsRight; // faster than down
        }
    }

    const bool noColumns = noColumnsInClipboard && noColumnsSelected;
    const bool noRows = noRowsInClipboard && noRowsSelected;

    // Shift cells down.
    if (m_insertMode == ShiftCellsDown) {
        // Cases:
        // 1. Columns AND rows are contained in either source or selection
        // 1.a Columns in source and rows in selection
        //      I.e. yOffset=0
        //      Clear everything.
        //      Taking the column data/style and fill all columns.
        // 1.b Columns and rows in source, but not in selection
        //      I.e. xOffset=0,yOffset=0
        //      Leave everything as is? No, data from different sheet is possible!
        //      Clear everything.
        //      Fill with the source column/row data/style,
        //      i.e. the sheet data becomes equal to the source data.
        //      Same procedure as in 1.e
        // 1.c Columns and rows in selection, but not in source
        //      Clear everything.
        //      Fill with the source data. Tiling -> HUGE task!
        // 1.d Rows in source and columns in selection
        //      I.e. xOffset=0
        //      Clear everything.
        //      Taking the row data/style and fill all rows.
        // 1.e Columns AND rows in both
        //      I.e. xOffset=0,yOffset=0
        //      Leave everything as is? No, data from different sheet is possible!
        //      Clear everything.
        //      Fill with the source column/row data/style,
        //      i.e. the sheet data becomes equal to the source data.
        //      Same procedure as in 1.b
        // 2. Columns are present in either source or selection, but no rows
        // 2a Columns in source
        //      I.e. yOffset=0
        //      Clear the appropriate columns in the paste area.
        //      Fill them with the source data.
        // 2b Columns in selection
        //      Clear the selected columns.
        //      Fill them with the source data. Tiling -> HUGE task!
        // 2c Columns in both
        //      I.e. yOffset=0
        //      Clear the selected columns.
        //      Fill them with the source column data/style.
        // 3. Rows are present in either source or selection, but no columns
        // 3a Rows in source
        //      I.e. xOffset=0
        //      Insert rows.
        //      Fill in data.
        // 3b Rows in selection
        //      Insert rows.
        //      Fill in data. Tiling -> HUGE task!
        // 3c Rows in both
        //      I.e. xOffset=0
        //      Insert rows.
        //      Fill in data/style from source rows.
        // 4. Neither column, nor rows are present
        //      Shift the cell down.
        //      Fill in data.
        if ((!noColumns && !noRows) || (!noColumns && noRows)) {
            // Everything or only columns present.
            DeleteCommand *const command = new DeleteCommand(this);
            command->setSheet(m_sheet);
            command->add(Region(pasteArea.x(), pasteArea.y(), pasteWidth, pasteHeight, sheet));
            command->setMode(DeleteCommand::OnlyCells);
        } else if (noColumns && !noRows) {
            // Rows present.
            InsertDeleteRowManipulator *const command = new InsertDeleteRowManipulator(this);
            command->setSheet(sheet);
            command->add(Region(pasteArea.x(), pasteArea.y(), pasteWidth, pasteHeight, sheet));
        } else {
            // Neither columns, nor rows present.
            ShiftManipulator *const command = new ShiftManipulator(this);
            command->setSheet(sheet);
            command->add(Region(pasteArea.x(), pasteArea.y(), pasteWidth, pasteHeight, sheet));
            command->setDirection(ShiftManipulator::ShiftBottom);
        }
    }
    // Shift cells right.
    if (m_insertMode == ShiftCellsRight) {
        // Cases:
        // Same as for ShiftCellsDown,
        // except that clearing and inserting are exchanged for cases 2 and 3.
        // Shifting a column to the right is the same as column insertion.
        // Shifting a row to the right is the same as clearing the row.
        if ((!noColumns && !noRows) || (noColumns && !noRows)) {
            // Everything or only rows present.
            DeleteCommand *const command = new DeleteCommand(this);
            command->setSheet(m_sheet);
            command->add(Region(pasteArea.x(), pasteArea.y(), pasteWidth, pasteHeight, sheet));
            command->setMode(DeleteCommand::OnlyCells);
        } else if (!noColumns && noRows) {
            // Columns present.
            InsertDeleteColumnManipulator *const command = new InsertDeleteColumnManipulator(this);
            command->setSheet(sheet);
            command->add(Region(pasteArea.x(), pasteArea.y(), pasteWidth, pasteHeight, sheet));
        } else {
            // Neither columns, nor rows present.
            ShiftManipulator *const command = new ShiftManipulator(this);
            command->setSheet(sheet);
            command->add(Region(pasteArea.x(), pasteArea.y(), pasteWidth, pasteHeight, sheet));
            command->setDirection(ShiftManipulator::ShiftRight);
        }
    }

    // This command will collect as many cell loads as possible in the iteration.
    PasteCellCommand *pasteCellCommand = 0;

    KoXmlElement e = root.firstChild().toElement(); // "columns", "rows" or "cell"
    for (; !e.isNull(); e = e.nextSibling().toElement()) {
        // If the element is not a cell, unset the pasteCellCommand pointer.
        // If existing, it is attached as child commnand, so no leaking here.
        if (e.tagName() != "cell") {
            pasteCellCommand = 0;
        }

        // entire columns given
        if (e.tagName() == "columns" && !sheet->isProtected()) {
            const int number = e.attribute("count").toInt();
            if (m_insertMode == NoInsertion) {
                // Clear the existing content; not the column style.
                DeleteCommand *const command = new DeleteCommand(this);
                command->setSheet(m_sheet);
                const int col = e.attribute("column").toInt();
                const int cols = qMax(pasteArea.width(), number);
                const Region region(col + xOffset, 1, cols, KS_rowMax, m_sheet);
                command->add(region);
                command->setMode(DeleteCommand::OnlyCells);
            }

            // Set the column style.
            ColumnFormat columnFormat;
            columnFormat.setSheet(sheet);
            KoXmlElement c = e.firstChild().toElement();
            for (; !c.isNull(); c = c.nextSibling().toElement()) {
                if (c.tagName() != "column") {
                    continue;
                }
                if (columnFormat.load(c, xOffset, m_pasteMode)) {
                    const int col = columnFormat.column();
                    const int cols = qMax(pasteArea.width(), number);
                    for (int coff = 0; col - xOffset + coff <= cols; coff += number) {
                        ColumnStyleCommand *const command = new ColumnStyleCommand(this);
                        command->setSheet(m_sheet);
                        command->add(Region(col + coff, 1, 1, 1, m_sheet));
                        command->setTemplate(columnFormat);
                    }
                }
            }
        }

        // entire rows given
        if (e.tagName() == "rows" && !sheet->isProtected()) {
            const int number = e.attribute("count").toInt();
            if (m_insertMode == NoInsertion) {
                // Clear the existing content; not the row style.
                DeleteCommand *const command = new DeleteCommand(this);
                command->setSheet(m_sheet);
                const int row = e.attribute("row").toInt();
                const int rows = qMax(pasteArea.height(), number);
                const Region region(1, row + yOffset, KS_colMax, rows, m_sheet);
                command->add(region);
                command->setMode(DeleteCommand::OnlyCells);
            }

            // Set the row style.
            RowFormat rowFormat;
            rowFormat.setSheet(sheet);
            KoXmlElement c = e.firstChild().toElement();
            for (; !c.isNull(); c = c.nextSibling().toElement()) {
                if (c.tagName() != "row") {
                    continue;
                }
                if (rowFormat.load(c, yOffset, m_pasteMode)) {
                    const int row = rowFormat.row();
                    const int rows = qMax(pasteArea.height(), number);
                    for (int roff = 0; row - yOffset + roff <= rows; roff += number) {
                        RowStyleCommand *const command = new RowStyleCommand(this);
                        command->setSheet(m_sheet);
                        command->add(Region(1, rowFormat.row(), 1, 1, m_sheet));
                        command->setTemplate(rowFormat);
                    }
                }
            }
        }

        if (e.tagName() == "cell") {
            // Create a new PasteCellCommand, if necessary.
            if (!pasteCellCommand) {
                pasteCellCommand = new PasteCellCommand(this);
                pasteCellCommand->setSheet(m_sheet);
                pasteCellCommand->m_pasteMode = m_pasteMode;
                pasteCellCommand->m_pasteOperation = m_operation;
                pasteCellCommand->m_pasteFC = m_pasteFC;
            }

            // Source cell location:
            const int row = e.attribute("row").toInt();
            const int col = e.attribute("column").toInt();

            // tile the selection with the clipboard contents
            for (int roff = 0; row + roff <= pasteHeight; roff += sourceHeight) {
                for (int coff = 0; col + coff <= pasteWidth; coff += sourceWidth) {
                    kDebug(36005) << "cell at" << (col + xOffset + coff) << ',' << (row + yOffset + roff)
                    << " with roff,coff=" << roff << ',' << coff
                    << ", xOffset:" << xOffset << ", yOffset:" << yOffset << endl;

                    // Destination cell:
                    const Cell cell(sheet, col + xOffset + coff, row + yOffset + roff);
                    // Do nothing, if the sheet and the cell are protected.
                    if (sheet->isProtected() && !cell.style().notProtected()) {
                        continue;
                    }
                    // Add the destination cell and the XML element itself.
                    pasteCellCommand->addXmlElement(cell, e);
                }
            }
        }
    }
    return true;
}
Exemplo n.º 14
0
bool Validity::loadXML(Cell* const cell, const KoXmlElement& validityElement)
{
    ValueParser *const parser = cell->sheet()->map()->parser();
    bool ok = false;
    KoXmlElement param = validityElement.namedItem("param").toElement();
    if (!param.isNull()) {
        if (param.hasAttribute("cond")) {
            d->cond = (Conditional::Type) param.attribute("cond").toInt(&ok);
            if (!ok)
                return false;
        }
        if (param.hasAttribute("action")) {
            d->action = (Action) param.attribute("action").toInt(&ok);
            if (!ok)
                return false;
        }
        if (param.hasAttribute("allow")) {
            d->restriction = (Restriction) param.attribute("allow").toInt(&ok);
            if (!ok)
                return false;
        }
        if (param.hasAttribute("valmin")) {
            d->minValue = parser->tryParseNumber(param.attribute("valmin"), &ok);
            if (!ok)
                return false;
        }
        if (param.hasAttribute("valmax")) {
            d->maxValue = parser->tryParseNumber(param.attribute("valmax"), &ok);
            if (!ok)
                return false;
        }
        if (param.hasAttribute("displaymessage")) {
            d->displayMessage = (bool)param.attribute("displaymessage").toInt();
        }
        if (param.hasAttribute("displayvalidationinformation")) {
            d->displayValidationInformation = (bool)param.attribute("displayvalidationinformation").toInt();
        }
        if (param.hasAttribute("allowemptycell")) {
            d->allowEmptyCell = (bool)param.attribute("allowemptycell").toInt();
        }
        if (param.hasAttribute("listvalidity")) {
            d->listValidity = param.attribute("listvalidity").split(';', QString::SkipEmptyParts);
        }
    }
    KoXmlElement inputTitle = validityElement.namedItem("inputtitle").toElement();
    if (!inputTitle.isNull()) {
        d->titleInfo = inputTitle.text();
    }
    KoXmlElement inputMessage = validityElement.namedItem("inputmessage").toElement();
    if (!inputMessage.isNull()) {
        d->messageInfo = inputMessage.text();
    }

    KoXmlElement titleElement = validityElement.namedItem("title").toElement();
    if (!titleElement.isNull()) {
        d->title = titleElement.text();
    }
    KoXmlElement messageElement = validityElement.namedItem("message").toElement();
    if (!messageElement.isNull()) {
        d->message = messageElement.text();
    }
    KoXmlElement timeMinElement = validityElement.namedItem("timemin").toElement();
    if (!timeMinElement.isNull()) {
        d->minValue = parser->tryParseTime(timeMinElement.text());
    }
    KoXmlElement timeMaxElement = validityElement.namedItem("timemax").toElement();
    if (!timeMaxElement.isNull()) {
        d->maxValue = parser->tryParseTime(timeMaxElement.text());
    }
    KoXmlElement dateMinElement = validityElement.namedItem("datemin").toElement();
    if (!dateMinElement.isNull()) {
        d->minValue = parser->tryParseTime(dateMinElement.text());
    }
    KoXmlElement dateMaxElement = validityElement.namedItem("datemax").toElement();
    if (!dateMaxElement.isNull()) {
        d->maxValue = parser->tryParseTime(dateMaxElement.text());
    }
    return true;
}
Exemplo n.º 15
0
bool SvgParser::parseGradient(const KoXmlElement &e, const KoXmlElement &referencedBy)
{
    // IMPROVEMENTS:
    // - Store the parsed colorstops in some sort of a cache so they don't need to be parsed again.
    // - A gradient inherits attributes it does not have from the referencing gradient.
    // - Gradients with no color stops have no fill or stroke.
    // - Gradients with one color stop have a solid color.

    SvgGraphicsContext *gc = m_context.currentGC();
    if (!gc)
        return false;

    SvgGradientHelper gradhelper;

    if (e.hasAttribute("xlink:href")) {
        QString href = e.attribute("xlink:href").mid(1);
        if (! href.isEmpty()) {
            // copy the referenced gradient if found
            SvgGradientHelper *pGrad = findGradient(href);
            if (pGrad)
                gradhelper = *pGrad;
        } else {
            //gc->fillType = SvgGraphicsContext::None; // <--- TODO Fill OR Stroke are none
            return false;
        }
    }

    // Use the gradient that is referencing, or if there isn't one, the original gradient.
    KoXmlElement b;
    if (!referencedBy.isNull())
        b = referencedBy;
    else
        b = e;

    QString gradientId = b.attribute("id");

    if (! gradientId.isEmpty()) {
        // check if we have this gradient already parsed
        // copy existing gradient if it exists
        if (m_gradients.find(gradientId) != m_gradients.end())
            gradhelper.copyGradient(m_gradients[ gradientId ].gradient());
    }

    if (b.attribute("gradientUnits") == "userSpaceOnUse")
        gradhelper.setGradientUnits(SvgGradientHelper::UserSpaceOnUse);

    // parse color prop
    QColor c = gc->currentColor;

    if (!b.attribute("color").isEmpty()) {
        m_context.styleParser().parseColor(c, b.attribute("color"));
    } else {
        // try style attr
        QString style = b.attribute("style").simplified();
        const QStringList substyles = style.split(';', QString::SkipEmptyParts);
        for (QStringList::ConstIterator it = substyles.begin(); it != substyles.end(); ++it) {
            QStringList substyle = it->split(':');
            QString command = substyle[0].trimmed();
            QString params  = substyle[1].trimmed();
            if (command == "color")
                m_context.styleParser().parseColor(c, params);
        }
    }
    gc->currentColor = c;

    if (b.tagName() == "linearGradient") {
        QLinearGradient *g = new QLinearGradient();
        if (gradhelper.gradientUnits() == SvgGradientHelper::ObjectBoundingBox) {
            g->setCoordinateMode(QGradient::ObjectBoundingMode);
            g->setStart(QPointF(SvgUtil::fromPercentage(b.attribute("x1", "0%")),
                                SvgUtil::fromPercentage(b.attribute("y1", "0%"))));
            g->setFinalStop(QPointF(SvgUtil::fromPercentage(b.attribute("x2", "100%")),
                                    SvgUtil::fromPercentage(b.attribute("y2", "0%"))));
        } else {
            g->setStart(QPointF(SvgUtil::fromUserSpace(b.attribute("x1").toDouble()),
                                SvgUtil::fromUserSpace(b.attribute("y1").toDouble())));
            g->setFinalStop(QPointF(SvgUtil::fromUserSpace(b.attribute("x2").toDouble()),
                                    SvgUtil::fromUserSpace(b.attribute("y2").toDouble())));
        }
        // preserve color stops
        if (gradhelper.gradient())
            g->setStops(gradhelper.gradient()->stops());
        gradhelper.setGradient(g);
    } else if (b.tagName() == "radialGradient") {
        QRadialGradient *g = new QRadialGradient();
        if (gradhelper.gradientUnits() == SvgGradientHelper::ObjectBoundingBox) {
            g->setCoordinateMode(QGradient::ObjectBoundingMode);
            g->setCenter(QPointF(SvgUtil::fromPercentage(b.attribute("cx", "50%")),
                                 SvgUtil::fromPercentage(b.attribute("cy", "50%"))));
            g->setRadius(SvgUtil::fromPercentage(b.attribute("r", "50%")));
            g->setFocalPoint(QPointF(SvgUtil::fromPercentage(b.attribute("fx", "50%")),
                                     SvgUtil::fromPercentage(b.attribute("fy", "50%"))));
        } else {
            g->setCenter(QPointF(SvgUtil::fromUserSpace(b.attribute("cx").toDouble()),
                                 SvgUtil::fromUserSpace(b.attribute("cy").toDouble())));
            g->setFocalPoint(QPointF(SvgUtil::fromUserSpace(b.attribute("fx").toDouble()),
                                     SvgUtil::fromUserSpace(b.attribute("fy").toDouble())));
            g->setRadius(SvgUtil::fromUserSpace(b.attribute("r").toDouble()));
        }
        // preserve color stops
        if (gradhelper.gradient())
            g->setStops(gradhelper.gradient()->stops());
        gradhelper.setGradient(g);
    } else {
        return false;
    }

    // handle spread method
    QString spreadMethod = b.attribute("spreadMethod");
    if (!spreadMethod.isEmpty()) {
        if (spreadMethod == "reflect")
            gradhelper.gradient()->setSpread(QGradient::ReflectSpread);
        else if (spreadMethod == "repeat")
            gradhelper.gradient()->setSpread(QGradient::RepeatSpread);
        else
            gradhelper.gradient()->setSpread(QGradient::PadSpread);
    } else
        gradhelper.gradient()->setSpread(QGradient::PadSpread);

    // Parse the color stops. The referencing gradient does not have colorstops,
    // so use the stops from the gradient it references to (e in this case and not b)
    m_context.styleParser().parseColorStops(gradhelper.gradient(), e);
    gradhelper.setTransform(SvgUtil::parseTransform(b.attribute("gradientTransform")));
    m_gradients.insert(gradientId, gradhelper);

    return true;
}