KoShape *KPrPlaceholderPictureStrategy::createShape(KoDocumentResourceManager *rm)
{
    KoShape * shape = 0;

    QUrl url = QFileDialog::getOpenFileUrl();
    if ( !url.isEmpty() ) {
        shape = KPrPlaceholderStrategy::createShape(rm);

        KoImageCollection *collection = rm->imageCollection();
        Q_ASSERT(collection);

        QString tmpFile;
        if (KIO::NetAccess::download(url, tmpFile, 0)) {
            QImage image(tmpFile);
            if (!image.isNull()) {
                //setSuffix(url.prettyUrl());
                KoImageData *data = collection->createImageData(image);
                if (data->isValid()) {
                    shape->setUserData( data );
                    // TODO the pic should be fit into the space provided
                    shape->setSize( data->imageSize() );
                }
            }
            KIO::NetAccess::removeTempFile(tmpFile);
        } else {
            warnStage << "open image" << url << "failed";
        }
    }
    return shape;
}
예제 #2
0
bool PictureShape::loadSvg(const KoXmlElement &element, SvgLoadingContext &context)
{
    const qreal x = SvgUtil::parseUnitX(context.currentGC(), element.attribute("x", "0"));
    const qreal y = SvgUtil::parseUnitY(context.currentGC(), element.attribute("y", "0"));
    const qreal w = SvgUtil::parseUnitX(context.currentGC(), element.attribute("width", "0"));
    const qreal h = SvgUtil::parseUnitY(context.currentGC(), element.attribute("height", "0"));

    // zero width of height disables rendering this image (see svg spec)
    if (w == 0.0 || h == 0.0)
        return 0;

    const QString href = element.attribute("xlink:href");

    QImage image;

    if (href.startsWith(QLatin1String("data:"))) {
        int start = href.indexOf("base64,");
        if (start <= 0)
            return false;
        if(!image.loadFromData(QByteArray::fromBase64(href.mid(start + 7).toLatin1())))
            return false;
    } else if (!image.load(context.absoluteFilePath(href))) {
        return false;
    }

    KoImageCollection *imageCollection = context.imageCollection();
    if (!imageCollection)
        return false;

    // TODO use it already for loading
    KoImageData *data = imageCollection->createImageData(image);

    setUserData(data);
    setSize(QSizeF(w, h));
    setPosition(QPointF(x, y));
    return true;
}
void KoListLevelProperties::loadOdf(KoShapeLoadingContext& scontext, const KoXmlElement& style)
{
    KoOdfLoadingContext &context = scontext.odfLoadingContext();

    // The text:level attribute specifies the level of the number list
    // style. It can be used on all list-level styles.
    const int level = qMax(1, style.attributeNS(KoXmlNS::text, "level", QString()).toInt());
    // The text:display-levels attribute specifies the number of
    // levels whose numbers are displayed at the current level.
    const QString displayLevel = style.attributeNS(KoXmlNS::text,
                                 "display-levels", QString());

    if (style.localName() == "list-level-style-bullet") {   // list with bullets

        //1.6: KoParagCounter::loadOasisListStyle
        QString bulletChar = style.isNull() ? QString() : style.attributeNS(KoXmlNS::text, "bullet-char", QString());
        kDebug(32500) << "style.localName()=" << style.localName() << "level=" << level << "displayLevel=" << displayLevel << "bulletChar=" << bulletChar;
        if (bulletChar.isEmpty()) {  // list without any visible bullets
            setStyle(KoListStyle::CustomCharItem);
            setBulletCharacter(QChar());
        } else { // try to determinate the bullet we should use
            switch (bulletChar[0].unicode()) {
            case 0x2022: // bullet, a small disc -> circle
                //TODO use BulletSize to differ between small and large discs
                setStyle(KoListStyle::DiscItem);
                break;
            case 0x25CF: // black circle, large disc -> disc
            case 0xF0B7: // #113361
                setStyle(KoListStyle::DiscItem);
                break;
            case 0xE00C: // losange => rhombus
                setStyle(KoListStyle::RhombusItem);
                break;
            case 0xE00A: // square. Not in OASIS (reserved Unicode area!), but used in both OOo and kotext.
                setStyle(KoListStyle::SquareItem);
                break;
            case 0x27A2: // two-colors right-pointing triangle
                setStyle(KoListStyle::RightArrowHeadItem);
                break;
            case 0x2794: // arrow to right
                setStyle(KoListStyle::RightArrowItem);
                break;
            case 0x2714: // checkmark
                setStyle(KoListStyle::HeavyCheckMarkItem);
                break;
            case 0x2d: // minus
                setStyle(KoListStyle::CustomCharItem);
                break;
            case 0x2717: // cross
                setStyle(KoListStyle::BallotXItem);
                break;
            default:
                QChar customBulletChar = bulletChar[0];
                kDebug(32500) << "Unhandled bullet code 0x" << QString::number((uint)customBulletChar.unicode(), 16);
                kDebug(32500) << "Should use the style =>" << style.attributeNS(KoXmlNS::text, "style-name", QString()) << "<=";
                setStyle(KoListStyle::CustomCharItem);
                /*
                QString customBulletFont;
                // often StarSymbol when it comes from OO; doesn't matter, Qt finds it in another font if needed.
                if ( listStyleProperties.hasAttributeNS( KoXmlNS::style, "font-name" ) )
                {
                    customBulletFont = listStyleProperties.attributeNS( KoXmlNS::style, "font-name", QString::null );
                    kDebug(32500) <<"customBulletFont style:font-name =" << listStyleProperties.attributeNS( KoXmlNS::style,"font-name", QString::null );
                }
                else if ( listStyleTextProperties.hasAttributeNS( KoXmlNS::fo, "font-family" ) )
                {
                    customBulletFont = listStyleTextProperties.attributeNS( KoXmlNS::fo, "font-family", QString::null );
                    kDebug(32500) <<"customBulletFont fo:font-family =" << listStyleTextProperties.attributeNS( KoXmlNS::fo,"font-family", QString::null );
                }
                // ## TODO in fact we're supposed to read it from the style pointed to by text:style-name
                */
//                     setStyle(KoListStyle::BoxItem); //fallback
                break;
            } // switch
            setBulletCharacter(bulletChar[0]);
        }

    } else if (style.localName() == "list-level-style-number" || style.localName() == "outline-level-style") { // it's a numbered list

        KoOdfNumberDefinition numberDefinition;
        numberDefinition.loadOdf(style);

        switch(numberDefinition.formatSpecification()) {
        case KoOdfNumberDefinition::Empty:
            setStyle(KoListStyle::CustomCharItem);
            setBulletCharacter(QChar());
            break;
        case KoOdfNumberDefinition::AlphabeticLowerCase:
            setStyle(KoListStyle::AlphaLowerItem);
            break;
        case KoOdfNumberDefinition::AlphabeticUpperCase:
            setStyle(KoListStyle::UpperAlphaItem);
            break;
        case KoOdfNumberDefinition::RomanLowerCase:
            setStyle(KoListStyle::RomanLowerItem);
            break;
        case KoOdfNumberDefinition::RomanUpperCase:
            setStyle(KoListStyle::UpperRomanItem);
            break;
        case KoOdfNumberDefinition::Numeric:
        default:
            setStyle(KoListStyle::DecimalItem);
        }

        if (!numberDefinition.prefix().isNull()) {
            setListItemPrefix(numberDefinition.prefix());
        }

        if (!numberDefinition.suffix().isNull()) {
            setListItemSuffix(numberDefinition.suffix());
        }
        const QString startValue = style.attributeNS(KoXmlNS::text, "start-value", QString("1"));
        setStartValue(startValue.toInt());
    }
    else if (style.localName() == "list-level-style-image") {   // list with image
        setStyle(KoListStyle::ImageItem);
        KoImageCollection *imageCollection = scontext.imageCollection();
        const QString href = style.attribute("href");
        if(imageCollection) {
            if (!href.isEmpty()) {
                KoStore *store = context.store();
                setBulletImage(imageCollection->createImageData(href, store));
            } else {
                // check if we have an office:binary data element containing the image data
                const KoXmlElement &binaryData(KoXml::namedItemNS(style, KoXmlNS::office, "binary-data"));
                if (!binaryData.isNull()) {
                    QImage image;
                    if (image.loadFromData(QByteArray::fromBase64(binaryData.text().toLatin1()))) {
                        setBulletImage(imageCollection->createImageData(image));
                    }
                }
            }
        }
    }
    else { // if not defined, we have do nothing
        kDebug(32500) << "stylename else:" << style.localName() << "level=" << level << "displayLevel=" << displayLevel;
        setStyle(KoListStyle::DecimalItem);
        setListItemSuffix(".");
    }

    setLevel(level);
    if (!displayLevel.isEmpty())
        setDisplayLevel(displayLevel.toInt());

    KoXmlElement property;
    forEachElement(property, style) {
        if (property.namespaceURI() != KoXmlNS::style)
            continue;
        const QString localName = property.localName();
        if (localName == "list-level-properties") {
            QString mode(property.attributeNS(KoXmlNS::text, "list-level-position-and-space-mode"));
            if (mode == "label-alignment") {
                KoXmlElement p;
                forEachElement(p, property) {
                     if (p.namespaceURI() == KoXmlNS::style && p.localName() == "list-level-label-alignment") {
                        // The <style:list-level-label-alignment> element and the fo:text-align attribute are used to define
                        // the position and spacing of the list label and the list item. The values of the attributes for
                        // text:space-before, text:min-label-width and text:min-label-distance are assumed to be 0.

                        QString textAlign(p.attributeNS(KoXmlNS::fo, "text-align"));
                        setAlignment(textAlign.isEmpty() ? Qt::AlignLeft : KoText::alignmentFromString(textAlign));

                        QString textindent(p.attributeNS(KoXmlNS::fo, "text-indent"));
                        QString marginleft(p.attributeNS(KoXmlNS::fo, "margin-left"));
                        qreal ti = textindent.isEmpty() ? 0 : KoUnit::parseValue(textindent);
                        qreal ml = marginleft.isEmpty() ? 0 : KoUnit::parseValue(marginleft);
                        setIndent(qMax(0.0, ti + ml));
                
                        setMinimumWidth(0);
                        setMinimumDistance(0);
                        
                        //TODO support ODF 18.829 text:label-followed-by and 18.832 text:list-tab-stop-position
                     }   
                }
            } else { // default is mode == "label-width-and-position"
void KoListLevelProperties::loadOdf(KoShapeLoadingContext& scontext, const KoXmlElement& style)
{
    KoOdfLoadingContext &context = scontext.odfLoadingContext();

    // The text:level attribute specifies the level of the number list
    // style. It can be used on all list-level styles.
    const int level = qMax(1, style.attributeNS(KoXmlNS::text, "level", QString()).toInt());
    // The text:display-levels attribute specifies the number of
    // levels whose numbers are displayed at the current level.
    const QString displayLevel = style.attributeNS(KoXmlNS::text,
                                 "display-levels", QString());

    const QString styleName = style.attributeNS(KoXmlNS::text, "style-name", QString());
    KoCharacterStyle *cs = 0;
    if (!styleName.isEmpty()) {
//         kDebug(32500) << "Should use the style =>" << styleName << "<=";

        KoSharedLoadingData *sharedData = scontext.sharedData(KOTEXT_SHARED_LOADING_ID);
        KoTextSharedLoadingData *textSharedData = 0;
        if (sharedData) {
            textSharedData = dynamic_cast<KoTextSharedLoadingData *>(sharedData);
        }
        if (textSharedData) {
            cs = textSharedData->characterStyle(styleName, context.useStylesAutoStyles());
            if (!cs) {
               kWarning(32500) << "Missing KoCharacterStyle!";
            }
            else {
//                kDebug(32500) << "==> cs.name:" << cs->name();
//                kDebug(32500) << "==> cs.styleId:" << cs->styleId();
                setCharacterStyleId(cs->styleId());
            }
        }
    }

    if (style.localName() == "list-level-style-bullet") {   // list with bullets
        // special case bullets:
        //qDebug() << QChar(0x2202) << QChar(0x25CF) << QChar(0xF0B7) << QChar(0xE00C)
        //<< QChar(0xE00A) << QChar(0x27A2)<< QChar(0x2794) << QChar(0x2714) << QChar(0x2d) << QChar(0x2717);

        //1.6: KoParagCounter::loadOasisListStyle
        QString bulletChar = style.attributeNS(KoXmlNS::text, "bullet-char", QString());
//         kDebug(32500) << "style.localName()=" << style.localName() << "level=" << level << "displayLevel=" << displayLevel << "bulletChar=" << bulletChar;
        if (bulletChar.isEmpty()) {  // list without any visible bullets
            setStyle(KoListStyle::CustomCharItem);
            setBulletCharacter(QChar());
        } else { // try to determinate the bullet we should use
            switch (bulletChar[0].unicode()) {
            case 0x2022: // bullet, a small disc -> circle
                setStyle(KoListStyle::Bullet);
                break;
            case 0x25CF: // black circle, large disc -> disc
                setStyle(KoListStyle::BlackCircle);
                break;
            case 0x25CB:           //white circle, no fill
                setStyle(KoListStyle::CircleItem);
                break;
            case 0x25C6: // losange => rhombus
                setStyle(KoListStyle::RhombusItem);
                break;
            case 0x25A0: // square. Not in OASIS (reserved Unicode area!), but used in both OOo and kotext.
                setStyle(KoListStyle::SquareItem);
                break;
            case 0x27A2: // two-colors right-pointing triangle
                setStyle(KoListStyle::RightArrowHeadItem);
                break;
            case 0x2794: // arrow to right
                setStyle(KoListStyle::RightArrowItem);
                break;
            case 0x2714: // checkmark
                setStyle(KoListStyle::HeavyCheckMarkItem);
                break;
            case 0x2d: // minus
                setStyle(KoListStyle::CustomCharItem);
                break;
            case 0x2717: // cross
                setStyle(KoListStyle::BallotXItem);
                break;
            default:
                QChar customBulletChar = bulletChar[0];
                kDebug(32500) << "Unhandled bullet code 0x" << QString::number((uint)customBulletChar.unicode(), 16) << bulletChar;
                kDebug(32500) << "Should use the style =>" << style.attributeNS(KoXmlNS::text, "style-name", QString()) << "<=";
                setStyle(KoListStyle::CustomCharItem);
                /*
                QString customBulletFont;
                // often StarSymbol when it comes from OO; doesn't matter, Qt finds it in another font if needed.
                if ( listStyleProperties.hasAttributeNS( KoXmlNS::style, "font-name" ) )
                {
                    customBulletFont = listStyleProperties.attributeNS( KoXmlNS::style, "font-name", QString() );
                    kDebug(32500) <<"customBulletFont style:font-name =" << listStyleProperties.attributeNS( KoXmlNS::style,"font-name", QString() );
                }
                else if ( listStyleTextProperties.hasAttributeNS( KoXmlNS::fo, "font-family" ) )
                {
                    customBulletFont = listStyleTextProperties.attributeNS( KoXmlNS::fo, "font-family", QString() );
                    kDebug(32500) <<"customBulletFont fo:font-family =" << listStyleTextProperties.attributeNS( KoXmlNS::fo,"font-family", QString() );
                }
                // ## TODO in fact we're supposed to read it from the style pointed to by text:style-name
                */
//                     setStyle(KoListStyle::BoxItem); //fallback
                break;
            } // switch
            setBulletCharacter(bulletChar[0]);
        }
        QString size = style.attributeNS(KoXmlNS::text, "bullet-relative-size", QString());
        if (!size.isEmpty()) {
            setRelativeBulletSize(size.remove('%').toInt());
        }

    } else if (style.localName() == "list-level-style-number" || style.localName() == "outline-level-style") { // it's a numbered list

        if (style.localName() == "outline-level-style") {
            setOutlineList(true);
        }
        setRelativeBulletSize(100); //arbitrary value for numbered list

        KoOdfNumberDefinition numberDefinition;
        numberDefinition.loadOdf(style);

        switch(numberDefinition.formatSpecification()) {
        case KoOdfNumberDefinition::Empty:
            setStyle(KoListStyle::None);
            break;
        case KoOdfNumberDefinition::AlphabeticLowerCase:
            setStyle(KoListStyle::AlphaLowerItem);
            break;
        case KoOdfNumberDefinition::AlphabeticUpperCase:
            setStyle(KoListStyle::UpperAlphaItem);
            break;
        case KoOdfNumberDefinition::RomanLowerCase:
            setStyle(KoListStyle::RomanLowerItem);
            break;
        case KoOdfNumberDefinition::RomanUpperCase:
            setStyle(KoListStyle::UpperRomanItem);
            break;
        case KoOdfNumberDefinition::ArabicAlphabet:
                    setStyle(KoListStyle::ArabicAlphabet);
                    break;
        case KoOdfNumberDefinition::Thai:
            setStyle(KoListStyle::Thai);
            break;
        case KoOdfNumberDefinition::Abjad:
            setStyle(KoListStyle::Abjad);
            break;
        case KoOdfNumberDefinition::AbjadMinor:
            setStyle(KoListStyle::AbjadMinor);
            break;
        case KoOdfNumberDefinition::Tibetan:
            setStyle(KoListStyle::Tibetan);
            break;
        case KoOdfNumberDefinition::Telugu:
            setStyle(KoListStyle::Telugu);
            break;
        case KoOdfNumberDefinition::Tamil:
            setStyle(KoListStyle::Tamil);
            break;
        case KoOdfNumberDefinition::Oriya:
            setStyle(KoListStyle::Oriya);
            break;
        case KoOdfNumberDefinition::Malayalam:
            setStyle(KoListStyle::Malayalam);
            break;
        case KoOdfNumberDefinition::Kannada:
            setStyle(KoListStyle::Kannada);
            break;
        case KoOdfNumberDefinition::Gurumukhi:
            setStyle(KoListStyle::Gurumukhi);
            break;
        case KoOdfNumberDefinition::Gujarati:
            setStyle(KoListStyle::Gujarati);
            break;
        case KoOdfNumberDefinition::Bengali:
            setStyle(KoListStyle::Bengali);
            break;
        case KoOdfNumberDefinition::Numeric:
        default:
            setStyle(KoListStyle::DecimalItem);
        }

        if (!numberDefinition.prefix().isNull()) {
            setListItemPrefix(numberDefinition.prefix());
        }

        if (!numberDefinition.suffix().isNull()) {
            setListItemSuffix(numberDefinition.suffix());
        }
        const QString startValue = style.attributeNS(KoXmlNS::text, "start-value", QString("1"));
        setStartValue(startValue.toInt());
    }
    else if (style.localName() == "list-level-style-image") {   // list with image
        setStyle(KoListStyle::ImageItem);
        KoImageCollection *imageCollection = scontext.imageCollection();
        const QString href = style.attribute("href");
        if(imageCollection) {
            if (!href.isEmpty()) {
                KoStore *store = context.store();
                setBulletImage(imageCollection->createImageData(href, store));
            } else {
                // check if we have an office:binary data element containing the image data
                const KoXmlElement &binaryData(KoXml::namedItemNS(style, KoXmlNS::office, "binary-data"));
                if (!binaryData.isNull()) {
                    QImage image;
                    if (image.loadFromData(QByteArray::fromBase64(binaryData.text().toLatin1()))) {
                        setBulletImage(imageCollection->createImageData(image));
                    }
                }
            }
        }
    }
    else { // if not defined, we have do nothing
//         kDebug(32500) << "stylename else:" << style.localName() << "level=" << level << "displayLevel=" << displayLevel;
        setStyle(KoListStyle::DecimalItem);
        setListItemSuffix(".");
    }

    setLevel(level);
    if (!displayLevel.isEmpty())
        setDisplayLevel(displayLevel.toInt());

    KoXmlElement property;
    forEachElement(property, style) {
        if (property.namespaceURI() != KoXmlNS::style)
            continue;
        const QString localName = property.localName();
        if (localName == "list-level-properties") {
            QString mode(property.attributeNS(KoXmlNS::text, "list-level-position-and-space-mode"));
            if (mode == "label-alignment") {
                QString textAlign(property.attributeNS(KoXmlNS::fo, "text-align"));
                setAlignment(textAlign.isEmpty() ? Qt::AlignLeft : KoText::alignmentFromString(textAlign));

                KoXmlElement p;
                forEachElement(p, property) {
                     if (p.namespaceURI() == KoXmlNS::style && p.localName() == "list-level-label-alignment") {
                        // The <style:list-level-label-alignment> element and the fo:text-align attribute are used to define
                        // the position and spacing of the list label and the list item. The values of the attributes for
                        // text:space-before, text:min-label-width and text:min-label-distance are assumed to be 0.
                        setAlignmentMode(true);

                        QString textindent(p.attributeNS(KoXmlNS::fo, "text-indent"));
                        QString marginleft(p.attributeNS(KoXmlNS::fo, "margin-left"));
                        qreal ti = textindent.isEmpty() ? 0 : KoUnit::parseValue(textindent);
                        qreal ml = marginleft.isEmpty() ? 0 : KoUnit::parseValue(marginleft);
                        setTextIndent(ti);
                        setMargin(ml);

                        QString labelFollowedBy(p.attributeNS(KoXmlNS::text, "label-followed-by","space"));
                        if(labelFollowedBy.compare("listtab",Qt::CaseInsensitive)==0) {

                            setLabelFollowedBy(KoListStyle::ListTab);

                            // list tab position is evaluated only if label is followed by listtab
                            // the it is only evaluated if there is a list-tab-stop-position specified
                            // if not specified use the fo:margin-left:
                            QString tabStop(p.attributeNS(KoXmlNS::text, "list-tab-stop-position"));
                            if (!tabStop.isEmpty()) {
                                qreal tabStopPos = KoUnit::parseValue(tabStop);
                                setTabStopPosition(qMax<qreal>(0.0, tabStopPos));
                            }

                        }else if(labelFollowedBy.compare("nothing",Qt::CaseInsensitive)==0) {

                            setLabelFollowedBy(KoListStyle::Nothing);

                        }else {

                            setLabelFollowedBy(KoListStyle::Space);

                        }

                        setMinimumWidth(0);
                        setMinimumDistance(0);

                        //TODO support ODF 18.829 text:label-followed-by and 18.832 text:list-tab-stop-position
                     }
                }
            }

            if(alignmentMode()!=true ){ // default is mode == "label-width-and-position"
                // The text:space-before, text:min-label-width, text:minimum-label-distance and fo:text-align attributes
                // are used to define the position and spacing of the list label and the list item.

                setAlignmentMode(false);

                QString spaceBefore(property.attributeNS(KoXmlNS::text, "space-before"));
                if (!spaceBefore.isEmpty())
                    setIndent(KoUnit::parseValue(spaceBefore));

                QString minLableWidth(property.attributeNS(KoXmlNS::text, "min-label-width"));
                if (!minLableWidth.isEmpty())
                    setMinimumWidth(KoUnit::parseValue(minLableWidth));

                QString textAlign(property.attributeNS(KoXmlNS::fo, "text-align"));
                if (!textAlign.isEmpty())
                    setAlignment(KoText::alignmentFromString(textAlign));

                QString minLableDistance(property.attributeNS(KoXmlNS::text, "min-label-distance"));
                if (!minLableDistance.isEmpty())
                    setMinimumDistance(KoUnit::parseValue(minLableDistance));               
            }

            QString width(property.attributeNS(KoXmlNS::fo, "width"));
            if (!width.isEmpty())
                setWidth(KoUnit::parseValue(width));

            QString height(property.attributeNS(KoXmlNS::fo, "height"));
            if (!height.isEmpty())
                setHeight(KoUnit::parseValue(height));

        } else if (localName == "text-properties") {