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") {