void TextContentsModelImpl::documentLayoutFinished() { QTextBlock block = d->textDocument->firstBlock(); d->entries.clear(); while (block.isValid()) { QTextBlockFormat format = block.blockFormat(); if (format.hasProperty(KoParagraphStyle::OutlineLevel)) { ContentsEntry entry; entry.title = block.text(); entry.level = format.intProperty(KoParagraphStyle::OutlineLevel); auto rootArea = d->layout->rootAreaForPosition(block.position()); if (rootArea) { if (rootArea->page()) { entry.pageNumber = rootArea->page()->visiblePageNumber(); entry.page = static_cast<KWPage*>(rootArea->page()); } } d->entries.append(entry); } block = block.next(); } emit listContentsCompleted(); }
void tst_QTextFormat::defaultAlignment() { QTextBlockFormat fmt; QVERIFY(!fmt.hasProperty(QTextFormat::BlockAlignment)); QCOMPARE(fmt.intProperty(QTextFormat::BlockAlignment), 0); QVERIFY(fmt.alignment() == Qt::AlignLeft); }
void KoTextBlockBorderData::setEdge(Side side, const QTextBlockFormat &bf, KoParagraphStyle::Property style, KoParagraphStyle::Property width, KoParagraphStyle::Property color, KoParagraphStyle::Property space, KoParagraphStyle::Property innerWidth) { Edge edge; KoBorder::BorderStyle borderStyle; borderStyle = static_cast<KoBorder::BorderStyle>(bf.intProperty(style)); switch (borderStyle) { case KoBorder::BorderDotted: edge.innerPen.setStyle(Qt::DotLine); break; case KoBorder::BorderDashed: edge.innerPen.setStyle(Qt::DashLine); break; case KoBorder::BorderDashDot: edge.innerPen.setStyle(Qt::DashDotLine); break; case KoBorder::BorderDashDotDot: edge.innerPen.setStyle(Qt::DashDotDotLine); break; case KoBorder::BorderGroove: /* TODO */ break; case KoBorder::BorderRidge: /* TODO */ break; case KoBorder::BorderInset: /* TODO */ break; case KoBorder::BorderOutset: /* TODO */ break; default: edge.innerPen.setStyle(Qt::SolidLine); } edge.innerPen.setColor(bf.colorProperty(color)); edge.innerPen.setJoinStyle(Qt::MiterJoin); edge.innerPen.setCapStyle(Qt::FlatCap); edge.outerPen = edge.innerPen; edge.outerPen.setWidthF(bf.doubleProperty(width)); // TODO check if this does not need any conversion edge.distance = bf.doubleProperty(space); edge.innerPen.setWidthF(bf.doubleProperty(innerWidth)); d->edges[side] = edge; }
QString KoTextWriter::saveParagraphStyle(const QTextBlockFormat &blockFormat, const QTextCharFormat &charFormat, KoStyleManager * styleManager, KoShapeSavingContext &context) { KoParagraphStyle *defaultParagraphStyle = styleManager->defaultParagraphStyle(); KoParagraphStyle *originalParagraphStyle = styleManager->paragraphStyle(blockFormat.intProperty(KoParagraphStyle::StyleId)); if (!originalParagraphStyle) originalParagraphStyle = defaultParagraphStyle; QString generatedName; QString displayName = originalParagraphStyle->name(); QString internalName = QString(QUrl::toPercentEncoding(displayName, "", " ")).replace('%', '_'); // we'll convert the blockFormat to a KoParagraphStyle to check for local changes. KoParagraphStyle paragStyle(blockFormat, charFormat); if (paragStyle == (*originalParagraphStyle)) { // This is the real, unmodified character style. // TODO zachmann: this could use the name of the saved style without saving it again // therefore we would need to store that information in the saving context if (originalParagraphStyle != defaultParagraphStyle) { KoGenStyle style(KoGenStyle::ParagraphStyle, "paragraph"); originalParagraphStyle->saveOdf(style, context); generatedName = context.mainStyles().insert(style, internalName, KoGenStyles::DontAddNumberToName); } } else { // There are manual changes... We'll have to store them then KoGenStyle style(KoGenStyle::ParagraphAutoStyle, "paragraph", internalName); if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml)) style.setAutoStyleInStylesDotXml(true); if (originalParagraphStyle) { paragStyle.removeDuplicates(*originalParagraphStyle); paragStyle.setParentStyle(originalParagraphStyle); } paragStyle.saveOdf(style, context); generatedName = context.mainStyles().insert(style, "P"); } return generatedName; }
void ChangeFollower::processUpdates(const QList<int> &changedStyles) { KoStyleManager *sm = m_styleManager.data(); if (!sm) { // since the stylemanager would be the one calling this method, I doubt this // will ever happen. But better safe than sorry.. deleteLater(); return; } // optimization strategy; store the formatid of the formats we checked into // a qset for 'hits' and 'ignores' and avoid the copying of the format // (fragment.charFormat() / block.blockFormat()) when the formatId is // already checked previosly QTextCursor cursor(m_document); QTextBlock block = cursor.block(); while (block.isValid()) { QTextBlockFormat bf = block.blockFormat(); int id = bf.intProperty(KoParagraphStyle::StyleId); if (id > 0 && changedStyles.contains(id)) { cursor.setPosition(block.position()); KoParagraphStyle *style = sm->paragraphStyle(id); Q_ASSERT(style); style->applyStyle(bf); cursor.setBlockFormat(bf); } QTextCharFormat cf = block.charFormat(); id = cf.intProperty(KoCharacterStyle::StyleId); if (id > 0 && changedStyles.contains(id)) { KoCharacterStyle *style = sm->characterStyle(id); Q_ASSERT(style); style->applyStyle(block); } QTextBlock::iterator iter = block.begin(); while (! iter.atEnd()) { QTextFragment fragment = iter.fragment(); cf = fragment.charFormat(); id = cf.intProperty(KoCharacterStyle::StyleId); if (id > 0 && changedStyles.contains(id)) { // create selection cursor.setPosition(fragment.position()); cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor); KoCharacterStyle *style = sm->characterStyle(id); Q_ASSERT(style); style->applyStyle(cf); cursor.mergeCharFormat(cf); } iter++; } block = block.next(); } }
void KoTextWriter::write(QTextDocument *document, int from, int to) { d->styleManager = KoTextDocument(document).styleManager(); d->layout = dynamic_cast<KoTextDocumentLayout*>(document->documentLayout()); d->changeTracker = KoTextDocument(document).changeTracker(); // Q_ASSERT(d->changeTracker); Q_ASSERT(d->layout); Q_ASSERT(d->layout->inlineTextObjectManager()); QTextBlock block = document->findBlock(from); KoTextDocument textDocument(document); QHash<QTextList *, QString> listStyles = saveListStyles(block, to); QList<QTextList*> textLists; // Store the current lists being stored. KoList *currentList = 0; while (block.isValid() && ((to == -1) || (block.position() <= to))) { QTextBlockFormat blockFormat = block.blockFormat(); QTextList *textList = block.textList(); int headingLevel = 0, numberedParagraphLevel = 0; if (textList) { headingLevel = blockFormat.intProperty(KoParagraphStyle::OutlineLevel); numberedParagraphLevel = blockFormat.intProperty(KoParagraphStyle::ListLevel); } if (textList && !headingLevel && !numberedParagraphLevel) { if (!textLists.contains(textList)) { KoList *list = textDocument.list(block); if (currentList != list) { while (!textLists.isEmpty()) { textLists.removeLast(); d->writer->endElement(); // </text:list> if (!textLists.isEmpty()) { d->writer->endElement(); // </text:list-element> } } currentList = list; } else if (!textLists.isEmpty()) // sublists should be written within a list-item d->writer->startElement("text:list-item", false); d->writer->startElement("text:list", false); d->writer->addAttribute("text:style-name", listStyles[textList]); if (textList->format().hasProperty(KoListStyle::ContinueNumbering)) d->writer->addAttribute("text:continue-numbering", textList->format().boolProperty(KoListStyle::ContinueNumbering) ? "true" : "false"); textLists.append(textList); } else if (textList != textLists.last()) { while ((!textLists.isEmpty()) && (textList != textLists.last())) { textLists.removeLast(); d->writer->endElement(); // </text:list> d->writer->endElement(); // </text:list-element> } } const bool listHeader = blockFormat.boolProperty(KoParagraphStyle::IsListHeader) || blockFormat.boolProperty(KoParagraphStyle::UnnumberedListItem); d->writer->startElement(listHeader ? "text:list-header" : "text:list-item", false); if (KoListStyle::isNumberingStyle(textList->format().style())) { if (KoTextBlockData *blockData = dynamic_cast<KoTextBlockData *>(block.userData())) { d->writer->startElement("text:number", false); d->writer->addTextSpan(blockData->counterText()); d->writer->endElement(); } } } else { // Close any remaining list... while (!textLists.isEmpty()) { textLists.removeLast(); d->writer->endElement(); // </text:list> if (!textLists.isEmpty()) { d->writer->endElement(); // </text:list-element> } } if (textList && numberedParagraphLevel) { d->writer->startElement("text:numbered-paragraph", false); d->writer->addAttribute("text:level", numberedParagraphLevel); d->writer->addAttribute("text:style-name", listStyles.value(textList)); } } saveParagraph(block, from, to); if (!textLists.isEmpty() || numberedParagraphLevel) { // we are generating a text:list-item. Look forward and generate unnumbered list items. while (true) { QTextBlock nextBlock = block.next(); if (!nextBlock.isValid() || !((to == -1) || (nextBlock.position() < to))) break; if (!nextBlock.textList() || !nextBlock.blockFormat().boolProperty(KoParagraphStyle::UnnumberedListItem)) break; block = nextBlock; saveParagraph(block, from, to); } } // We must check if we need to close a previously-opened text:list node. if ((block.textList() && !headingLevel) || numberedParagraphLevel) d->writer->endElement(); block = block.next(); } // while // Close any remaining lists while (!textLists.isEmpty()) { textLists.removeLast(); d->writer->endElement(); // </text:list> if (!textLists.isEmpty()) { d->writer->endElement(); // </text:list-element> } } }
void KoTextWriter::saveParagraph(const QTextBlock &block, int from, int to) { QString changeName = QString(); QTextBlockFormat blockFormat = block.blockFormat(); int outlineLevel = blockFormat.intProperty(KoParagraphStyle::OutlineLevel); if (outlineLevel > 0) { d->writer->startElement("text:h", false); d->writer->addAttribute("text:outline-level", outlineLevel); } else d->writer->startElement("text:p", false); QString styleName = saveParagraphStyle(block); if (!styleName.isEmpty()) d->writer->addAttribute("text:style-name", styleName); // Write the fragments and their formats QTextCursor cursor(block); QTextCharFormat blockCharFormat = cursor.blockCharFormat(); QTextCharFormat previousCharFormat; QTextBlock::iterator it; for (it = block.begin(); !(it.atEnd()); ++it) { QTextFragment currentFragment = it.fragment(); const int fragmentStart = currentFragment.position(); const int fragmentEnd = fragmentStart + currentFragment.length(); if (to != -1 && fragmentStart >= to) break; if (currentFragment.isValid()) { QTextCharFormat charFormat = currentFragment.charFormat(); QTextCharFormat compFormat = charFormat; bool identical; previousCharFormat.clearProperty(KoCharacterStyle::ChangeTrackerId); compFormat.clearProperty(KoCharacterStyle::ChangeTrackerId); if (previousCharFormat == compFormat) identical = true; else identical = false; if ( d->changeTracker && d->changeTracker->containsInlineChanges(charFormat) && d->changeTracker->elementById(charFormat.property(KoCharacterStyle::ChangeTrackerId).toInt())->isEnabled()) { KoGenChange change; d->changeTracker->saveInlineChange(charFormat.property(KoCharacterStyle::ChangeTrackerId).toInt(), change); changeName = d->sharedData->genChanges().insert(change); d->writer->startElement("text:change-start", false); d->writer->addAttribute("text:change-id", changeName); d->writer->endElement(); } KoInlineObject *inlineObject = d->layout->inlineTextObjectManager()->inlineTextObject(charFormat); if (currentFragment.length() == 1 && inlineObject && currentFragment.text()[0].unicode() == QChar::ObjectReplacementCharacter) { inlineObject->saveOdf(d->context); } else { QString styleName = saveCharacterStyle(charFormat, blockCharFormat); if (charFormat.isAnchor()) { d->writer->startElement("text:a", false); d->writer->addAttribute("xlink:type", "simple"); d->writer->addAttribute("xlink:href", charFormat.anchorHref()); } else if (!styleName.isEmpty() /*&& !identical*/) { d->writer->startElement("text:span", false); d->writer->addAttribute("text:style-name", styleName); } QString text = currentFragment.text(); int spanFrom = fragmentStart >= from ? 0 : from; int spanTo = to == -1 ? fragmentEnd : (fragmentEnd > to ? to : fragmentEnd); if (spanFrom != fragmentStart || spanTo != fragmentEnd) { // avoid mid, if possible d->writer->addTextSpan(text.mid(spanFrom - fragmentStart, spanTo - spanFrom)); } else { d->writer->addTextSpan(text); } if ((!styleName.isEmpty() /*&& !identical*/) || charFormat.isAnchor()) d->writer->endElement(); } // if (inlineObject) if (!changeName.isEmpty()) { d->writer->startElement("text:change-end", false); d->writer->addAttribute("text:change-id",changeName); d->writer->endElement(); changeName=QString(); } previousCharFormat = charFormat; } // if (fragment.valid()) } // foeach(fragment) d->writer->endElement(); }
void HtmlExporter::emitBlock( const QTextBlock &block ) { // save and later restore, in case we 'change' the default format by // emitting block char format information // NOTE the bottom line is commented, to use default charFormat, which can be set from outside. //QTextCharFormat oldDefaultCharFormat = defaultCharFormat; QString blockTag; bool isBlockQuote = false; const QTextBlockFormat blockFormat = block.blockFormat(); if ( blockFormat.hasProperty( BilboTextFormat::IsBlockQuote ) && blockFormat.boolProperty( BilboTextFormat::IsBlockQuote ) ) { isBlockQuote = true; } QTextList *list = block.textList(); if ( list ) { if ( list->itemNumber( block ) == 0 ) { // first item? emit <ul> or appropriate // qDebug() << "first item" << endl; if ( isBlockQuote ) { html += QLatin1String( "<blockquote>" ); } const QTextListFormat format = list->format(); const int style = format.style(); switch ( style ) { case QTextListFormat::ListDecimal: html += QLatin1String( "<ol" ); break; case QTextListFormat::ListDisc: html += QLatin1String( "<ul" ); break; case QTextListFormat::ListCircle: html += QLatin1String( "<ul type=\"circle\"" ); break; case QTextListFormat::ListSquare: html += QLatin1String( "<ul type=\"square\"" ); break; case QTextListFormat::ListLowerAlpha: html += QLatin1String( "<ol type=\"a\"" ); break; case QTextListFormat::ListUpperAlpha: html += QLatin1String( "<ol type=\"A\"" ); break; default: html += QLatin1String( "<ul" ); // ### should not happen //qDebug() << html; } /* if (format.hasProperty(QTextFormat::ListIndent)) { html += QLatin1String(" style=\"-qt-list-indent: "); html += QString::number(format.indent()); html += QLatin1String(";\""); }*/ html += QLatin1Char( '>' ); } blockTag = QLatin1String( "li" ); // html += QLatin1String( "<li " ); } // const QTextBlockFormat blockFormat = block.blockFormat(); if ( blockFormat.hasProperty( QTextFormat::BlockTrailingHorizontalRulerWidth ) ) { if ( ( blockFormat.hasProperty( BilboTextFormat::IsHtmlTagSign ) ) && ( blockFormat.boolProperty( BilboTextFormat::IsHtmlTagSign ) ) ) { html += QLatin1String( "<!--split-->" ); return; } else { html += QLatin1String( "<hr" ); QTextLength width = blockFormat.lengthProperty( QTextFormat::BlockTrailingHorizontalRulerWidth ); if ( width.type() != QTextLength::VariableLength ) { emitTextLength( "width", width ); } else { html += QLatin1Char( ' ' ); } html += QLatin1String( "/>" ); return; } } const bool pre = blockFormat.nonBreakableLines(); if ( pre ) { // qDebug() << "NonBreakable lines" << endl; // if (list) { // html += QLatin1Char('>'); // } // html += QLatin1String( "<pre" ); // emitBlockAttributes( block ); // html += QLatin1Char( '>' ); blockTag = QLatin1String( "pre" ); } else { if (!list) { if ( isBlockQuote ) { html += QLatin1String( "<blockquote>" ); } if ( ( blockFormat.hasProperty( BilboTextFormat::HtmlHeading ) ) && ( blockFormat.intProperty( BilboTextFormat::HtmlHeading ) ) ) { const int index = blockFormat.intProperty( BilboTextFormat::HtmlHeading ); blockTag = QLatin1Char( 'h' ) + QString::number( index ); } else { //html += QLatin1String("<div"); // html += QLatin1String( "<p" ); blockTag = QLatin1String( "p" ); } } } if ( !blockTag.isEmpty() ) { html += QLatin1Char( '<' ) + blockTag; emitBlockAttributes( block ); html += QLatin1Char( '>' ); } QTextBlock::Iterator it = block.begin(); for ( ; !it.atEnd(); ++it ) { emitFragment( it.fragment(), blockFormat ); } if ( !blockTag.isEmpty() ) { html += QLatin1String( "</" ) + blockTag + QLatin1String( ">\n" ); } // if ( pre ) { // html += QLatin1String( "</pre>\n" ); // } else { // if ( list ) { // html += QLatin1String( "</li>\n" ); // } else { // if ( blockFormat::boolProperty( BilboTextFormat::IsHtmlHeading ) ) { // const int index = format.intProperty( QTextFormat::FontSizeAdjustment ); // switch ( index ) { // case -2: // html += QLatin1String( "</h6>" ); // break; // case -1: // html += QLatin1String( "</h5>" ); // break; // case 0: // html += QLatin1String( "</h4>" ); // break; // case 1: // html += QLatin1String( "</h3>" ); // break; // case 2: // html += QLatin1String( "<h2" ); // break; // case 3: // html += QLatin1String( "<h1" ); // break; // } // } else { // html += QLatin1String( "</p>\n" ); // } // } // } // HACK html.replace( QRegExp("<br[\\s]*/>[\\n]*<br[\\s]*/>[\\n]*"),"<br /> <br />" ); if ( list ) { if ( list->itemNumber( block ) == list->count() - 1 ) { // last item? close list if ( isOrderedList( list->format().style() ) ) { html += QLatin1String( "</ol>\n" ); } else { html += QLatin1String( "</ul>\n" ); } if ( isBlockQuote ) { html += QLatin1String( "</blockquote>\n" ); } } } else { if ( isBlockQuote ) { html += QLatin1String( "</blockquote>\n" ); } } // NOTE the bottom line is commented, to use default charFormat, which can be set from outside. //defaultCharFormat = oldDefaultCharFormat; }
QList<HtmlExporter::tag> HtmlExporter::emitCharFormatStyle( const QTextCharFormat &charFormat, const QTextBlockFormat &blockFormat ) { // kDebug() << "html" << html; QList<HtmlExporter::tag> tags; bool attributesEmitted = false; QLatin1String styleTag( "<span style=\"" ); const QString family = charFormat.fontFamily(); //if (!family.isEmpty() && family != defaultCharFormat.fontFamily()) { // NOTE the above line replaced with the bottom line to use default charFormat, which can be set from outside. if ( charFormat.hasProperty( BilboTextFormat::HasCodeStyle ) && charFormat.boolProperty( BilboTextFormat::HasCodeStyle ) ) { tags << code; } else if ( !family.isEmpty() && family != mDefaultCharFormat.fontFamily() ) { // if ( family.right( 7 ) == "courier" ) { // tags << code; // } else { if ( ! attributesEmitted ) { html += styleTag; } html += QLatin1String( " font-family:'" ); html += family; html += QLatin1String( "';" ); attributesEmitted = true; // } } // if (format.hasProperty(QTextFormat::FontPointSize) // && format.fontPointSize() != defaultCharFormat.fontPointSize()) { // NOTE the above line replaced with the bottom line to use default charFormat, which can be set from outside. if ( charFormat.hasProperty( QTextFormat::FontPointSize ) && charFormat.fontPointSize() != mDefaultCharFormat.fontPointSize() ) { if ( ! attributesEmitted ) { html += styleTag; } html += QLatin1String( " font-size:" ); html += QString::number( charFormat.fontPointSize() ); html += QLatin1String( "pt;" ); attributesEmitted = true; } else if ( charFormat.hasProperty( QTextFormat::FontSizeAdjustment ) && !( blockFormat.hasProperty( BilboTextFormat::HtmlHeading ) && blockFormat.intProperty( BilboTextFormat::HtmlHeading ) ) ) { ///To use <h1-5> tags for font size // const int idx = format.intProperty(QTextFormat::FontSizeAdjustment) + 1; // // switch (idx) { // case 0: tags << h5; break; // //case 1: tags << h4; break; //NOTE h4 will be the normal text! // case 2: tags << h3; break; // case 3: tags << h2; break; // case 4: tags << h1; break; // } ///To use <span> tags for font size static const char * const sizeNames[] = { "small", "medium", "large", "x-large", "xx-large" }; const char *name = 0; const int idx = charFormat.intProperty( QTextFormat::FontSizeAdjustment ) + 1; if ( idx == 1 ) { // assume default to not bloat the html too much } else if ( idx >= 0 && idx <= 4 ) { name = sizeNames[idx]; } if ( name ) { if ( ! attributesEmitted ) { html += styleTag; } html += QLatin1String( " font-size:" ); html += QLatin1String( name ); html += QLatin1Char( ';' ); attributesEmitted = true; } } // if (format.fontWeight() > defaultCharFormat.fontWeight()) { // NOTE the above line replaced with the bottom line to use default charFormat, which can be set from outside. if ( charFormat.fontWeight() > mDefaultCharFormat.fontWeight() && !( blockFormat.hasProperty( BilboTextFormat::HtmlHeading ) && blockFormat.intProperty( BilboTextFormat::HtmlHeading ) ) ) { tags << strong; /*if (! attributesEmitted ) html += styleTag; html += QLatin1String(" font-weight:"); html += QString::number(format.fontWeight() * 8); html += QLatin1Char(';'); attributesEmitted = true;*/ } // if (format.fontItalic() != defaultCharFormat.fontItalic()) { // NOTE the above line replaced with the bottom line to use default charFormat, which can be set from outside. if ( charFormat.fontItalic() != mDefaultCharFormat.fontItalic() ) { tags << em; /* if (! attributesEmitted ) html += styleTag; html += QLatin1String(" font-style:"); html += (format.fontItalic() ? QLatin1String("italic") : QLatin1String("normal")); html += QLatin1Char(';'); attributesEmitted = true;*/ } // if (format.fontUnderline() != defaultCharFormat.fontUnderline()) { // NOTE the above line replaced with the bottom line to use default charFormat, which can be set from outside. if ( charFormat.fontUnderline() != mDefaultCharFormat.fontUnderline() ) { tags << u; } // if (format.fontStrikeOut() != defaultCharFormat.fontStrikeOut()) { // NOTE the above line replaced with the bottom line to use default charFormat, which can be set from outside. if ( charFormat.fontStrikeOut() != mDefaultCharFormat.fontStrikeOut() ) { tags << s; } // if (format.fontOverline() != defaultCharFormat.fontOverline()) { // NOTE the above line replaced with the bottom line to use default charFormat, which can be set from outside. if ( charFormat.fontOverline() != mDefaultCharFormat.fontOverline() ) { if ( charFormat.fontOverline() ) { if ( ! attributesEmitted ) { html += styleTag; } html += QLatin1String( " text-decoration: overline;" ); attributesEmitted = true; } } /* bool hasDecoration = false; bool atLeastOneDecorationSet = false; QLatin1String decorationTag(" text-decoration:"); if (format.fontUnderline() != defaultCharFormat.fontUnderline() || format.fontOverline() != defaultCharFormat.fontOverline() || format.fontStrikeOut() != defaultCharFormat.fontStrikeOut() ) { if (! attributesEmitted ) html += styleTag; html += decorationTag; } if (format.fontUnderline() != defaultCharFormat.fontUnderline()) { hasDecoration = true; if (format.fontUnderline()) { html += QLatin1String(" underline"); atLeastOneDecorationSet = true; } } if (format.fontOverline() != defaultCharFormat.fontOverline()) { hasDecoration = true; if (format.fontOverline()) { html += QLatin1String(" overline"); atLeastOneDecorationSet = true; } } if (format.fontStrikeOut() != defaultCharFormat.fontStrikeOut()) { hasDecoration = true; if (format.fontStrikeOut()) { html += QLatin1String(" line-through"); atLeastOneDecorationSet = true; } } if (hasDecoration) { if (!atLeastOneDecorationSet) html += QLatin1String("none"); html += QLatin1Char(';'); attributesEmitted = true; }*/ /* else { html.chop(qstrlen(decorationTag.latin1())); }*/ // QBrush linkColor = KColorScheme(QPalette::Active, KColorScheme::Window).foreground(KColorScheme::LinkText); // if ( format.foreground() != defaultCharFormat.foreground() && // format.foreground().style() != Qt::NoBrush) { // NOTE the above line replaced with the bottom line to use default charFormat, which can be set from outside. if ( charFormat.foreground() != mDefaultCharFormat.foreground() && charFormat.foreground().style() != Qt::NoBrush && !charFormat.isAnchor() ) { // if ( format.foreground() != linkColor ) { // if ( format.anchorHref().isNull() ) { if ( ! attributesEmitted ) { html += styleTag; attributesEmitted = true; } // } else { // html += QLatin1String(" style=\""); // } html += QLatin1String( " color:" ); html += charFormat.foreground().color().name(); html += QLatin1Char( ';' ); // if ( !format.anchorHref().isNull() ) { // html += QLatin1String("\""); // } // attributesEmitted = true; // } } // if (format.background() != defaultCharFormat.background() // && format.background().style() != Qt::NoBrush) { // NOTE the above line replaced with the bottom line to use default charFormat, which can be set from outside. if ( !( charFormat.hasProperty( BilboTextFormat::HasCodeStyle ) && charFormat.boolProperty( BilboTextFormat::HasCodeStyle ) ) ) { if ( charFormat.background() != mDefaultCharFormat.background() && charFormat.background().style() != Qt::NoBrush ) { if ( ! attributesEmitted ) { html += styleTag; } html += QLatin1String( " background-color:" ); html += charFormat.background().color().name(); html += QLatin1Char( ';' ); attributesEmitted = true; } } // if (format.verticalAlignment() != defaultCharFormat.verticalAlignment()) { //TODO // NOTE the above line replaced with the bottom line to use default charFormat, which can be set from outside. if ( charFormat.verticalAlignment() != mDefaultCharFormat.verticalAlignment() ) { //TODO if ( ! attributesEmitted ) { html += styleTag; } html += QLatin1String( " vertical-align:" ); QTextCharFormat::VerticalAlignment valign = charFormat.verticalAlignment(); if ( valign == QTextCharFormat::AlignSubScript ) { html += QLatin1String( "sub" ); } else if ( valign == QTextCharFormat::AlignSuperScript ) { html += QLatin1String( "super" ); } html += QLatin1Char( ';' ); attributesEmitted = true; } //Append close span Tag if ( attributesEmitted ) { html += QLatin1String( "\">" ); tags.prepend( span ); } // kDebug() << "html=>" << html << tags; return tags; }
void ListItemsHelper::recalculate() { //kDebug(32500); const QTextListFormat format = m_textList->format(); const KoListStyle::Style listStyle = static_cast<KoListStyle::Style>(m_textList->format().style()); const QString prefix = format.stringProperty(KoListStyle::ListItemPrefix); const QString suffix = format.stringProperty(KoListStyle::ListItemSuffix); const int level = format.intProperty(KoListStyle::Level); int dp = format.intProperty(KoListStyle::DisplayLevel); if (dp > level) dp = level; const int displayLevel = dp ? dp : 1; int startValue = 1; if (format.hasProperty(KoListStyle::StartValue)) startValue = format.intProperty(KoListStyle::StartValue); if (format.boolProperty(KoListStyle::ContinueNumbering)) { // Look for the index of a previous list of the same numbering style and level for (QTextBlock tb = m_textList->item(0).previous(); tb.isValid(); tb = tb.previous()) { if (!tb.textList() || tb.textList() == m_textList) continue; // no list here or it's the same list; keep looking QTextListFormat otherFormat = tb.textList()->format(); if (otherFormat.intProperty(KoListStyle::Level) != level) break; // found a different list but of a different level if (otherFormat.style() == format.style()) { if (KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(tb.userData())) startValue = data->counterIndex() + 1; // Start from previous list value + 1 } break; } } int index = startValue; QList<QTextList*> sublistsToRecalculate; qreal width = format.doubleProperty(KoListStyle::MinimumWidth); for (int i = 0; i < m_textList->count(); i++) { QTextBlock tb = m_textList->item(i); //kDebug(32500) <<" *" << tb.text(); KoTextBlockData *data = dynamic_cast<KoTextBlockData*>(tb.userData()); if (!data) { data = new KoTextBlockData(); tb.setUserData(data); } QTextBlockFormat blockFormat = tb.blockFormat(); if (blockFormat.boolProperty(KoParagraphStyle::UnnumberedListItem) || blockFormat.boolProperty(KoParagraphStyle::IsListHeader)) { data->setCounterText(QString()); data->setPartialCounterText(QString()); continue; } if (blockFormat.boolProperty(KoParagraphStyle::RestartListNumbering)) index = format.intProperty(KoListStyle::StartValue); const int paragIndex = blockFormat.intProperty(KoParagraphStyle::ListStartValue); if (paragIndex > 0) index = paragIndex; //check if this is the first of this level meaning we should start from startvalue QTextBlock b = tb.previous(); for (;b.isValid(); b = b.previous()) { if (b.textList() == m_textList) break; // all fine if (b.textList() == 0) continue; QTextListFormat otherFormat = b.textList()->format(); if (otherFormat.style() != format.style()) continue; // uninteresting for us if (b.textList()->format().intProperty(KoListStyle::Level) < level) { index = startValue; break; } } QString item; if (displayLevel > 1) { int checkLevel = level; int tmpDisplayLevel = displayLevel; for (QTextBlock b = tb.previous(); tmpDisplayLevel > 1 && b.isValid(); b = b.previous()) { if (b.textList() == 0) continue; QTextListFormat lf = b.textList()->format(); if (lf.style() != format.style()) continue; // uninteresting for us const int otherLevel = lf.intProperty(KoListStyle::Level); if (checkLevel <= otherLevel) continue; /*if(needsRecalc(b->textList())) { TODO } */ KoTextBlockData *otherData = dynamic_cast<KoTextBlockData*>(b.userData()); if (! otherData) { kWarning(32500) << "Missing KoTextBlockData, Skipping textblock"; continue; } if (tmpDisplayLevel - 1 < otherLevel) { // can't just copy it fully since we are // displaying less then the full counter item += otherData->partialCounterText(); tmpDisplayLevel--; checkLevel--; for (int i = otherLevel + 1; i < level; i++) { tmpDisplayLevel--; item += ".1"; // add missing counters. } } else { // just copy previous counter as prefix QString otherPrefix = lf.stringProperty(KoListStyle::ListItemPrefix); QString otherSuffix = lf.stringProperty(KoListStyle::ListItemSuffix); QString pureCounter = otherData->counterText().mid(otherPrefix.size()); pureCounter = pureCounter.left(pureCounter.size() - otherSuffix.size()); item += pureCounter; for (int i = otherLevel + 1; i < level; i++) item += ".1"; // add missing counters. tmpDisplayLevel = 0; break; } } for (int i = 1; i < tmpDisplayLevel; i++) item = "1." + item; // add missing counters. } if ((listStyle == KoListStyle::DecimalItem || listStyle == KoListStyle::AlphaLowerItem || listStyle == KoListStyle::UpperAlphaItem || listStyle == KoListStyle::RomanLowerItem || listStyle == KoListStyle::UpperRomanItem) && !(item.isEmpty() || item.endsWith('.') || item.endsWith(' '))) { item += '.'; } bool calcWidth = true; QString partialCounterText; switch (listStyle) { case KoListStyle::DecimalItem: partialCounterText = QString::number(index); break; case KoListStyle::AlphaLowerItem: partialCounterText = intToAlpha(index, Lowercase, m_textList->format().boolProperty(KoListStyle::LetterSynchronization)); break; case KoListStyle::UpperAlphaItem: partialCounterText = intToAlpha(index, Uppercase, m_textList->format().boolProperty(KoListStyle::LetterSynchronization)); break; case KoListStyle::RomanLowerItem: partialCounterText = intToRoman(index); break; case KoListStyle::UpperRomanItem: partialCounterText = intToRoman(index).toUpper(); break; case KoListStyle::SquareItem: case KoListStyle::DiscItem: case KoListStyle::CircleItem: case KoListStyle::HeavyCheckMarkItem: case KoListStyle::BallotXItem: case KoListStyle::RightArrowItem: case KoListStyle::RightArrowHeadItem: case KoListStyle::RhombusItem: case KoListStyle::BoxItem: { calcWidth = false; item = ' '; width = m_displayFont.pointSizeF(); int percent = format.intProperty(KoListStyle::BulletSize); if (percent > 0) width = width * (percent / 100.0); break; } case KoListStyle::CustomCharItem: calcWidth = false; if (format.intProperty(KoListStyle::BulletCharacter)) item = QString(QChar(format.intProperty(KoListStyle::BulletCharacter))); width = m_fm.width(item); break; case KoListStyle::None: calcWidth = false; width = 10.0; // simple indenting break; case KoListStyle::Bengali: case KoListStyle::Gujarati: case KoListStyle::Gurumukhi: case KoListStyle::Kannada: case KoListStyle::Malayalam: case KoListStyle::Oriya: case KoListStyle::Tamil: case KoListStyle::Telugu: case KoListStyle::Tibetan: case KoListStyle::Thai: partialCounterText = intToScript(index, listStyle); break; case KoListStyle::Abjad: case KoListStyle::ArabicAlphabet: case KoListStyle::AbjadMinor: partialCounterText = intToScriptList(index, listStyle); break; case KoListStyle::ImageItem: calcWidth = false; width = qMax(format.doubleProperty(KoListStyle::Width), (qreal)1.0); break; default: // others we ignore. calcWidth = false; } data->setCounterIsImage(listStyle == KoListStyle::ImageItem); data->setPartialCounterText(partialCounterText); data->setCounterIndex(index); item += partialCounterText; if (calcWidth) width = qMax(width, m_fm.width(item)); data->setCounterText(prefix + item + suffix); index++; // have to recalculate any sublists under this element too QTextBlock nb = tb.next(); while (nb.isValid() && nb.textList() == 0) nb = nb.next(); if (nb.isValid()) { QTextListFormat lf = nb.textList()->format(); if ((lf.style() == format.style()) && nb.textList()->format().intProperty(KoListStyle::Level) > level) { // this is a sublist // have to remember to recalculate this list after the current level is done // cant do it right away since the sublist's prefix text is dependant on this level sublistsToRecalculate.append(nb.textList()); } } } for (int i = 0; i < sublistsToRecalculate.count(); i++) { ListItemsHelper lih(sublistsToRecalculate.at(i), m_displayFont); lih.recalculate(); } qreal counterSpacing = m_fm.width(' '); counterSpacing = qMax(format.doubleProperty(KoListStyle::MinimumDistance), counterSpacing); width += m_fm.width(prefix + suffix); // same for all width = qMax(format.doubleProperty(KoListStyle::MinimumWidth), width); for (int i = 0; i < m_textList->count(); i++) { QTextBlock tb = m_textList->item(i); KoTextBlockData *data = dynamic_cast<KoTextBlockData*>(tb.userData()); Q_ASSERT(data); data->setCounterWidth(width); data->setCounterSpacing(counterSpacing); //kDebug(32500) << data->counterText() <<"" << tb.text(); //kDebug(32500) <<" setCounterWidth:" << width; } //kDebug(32500); }