コード例 #1
0
int QTextCopyHelper::appendFragment(int pos, int endPos, int objectIndex)
{
    QTextDocumentPrivate::FragmentIterator fragIt = src->find(pos);
    const QTextFragmentData * const frag = fragIt.value();

    Q_ASSERT(objectIndex == -1
             || (frag->size_array[0] == 1 && src->formatCollection()->format(frag->format).objectIndex() != -1));

    int charFormatIndex;
    if (forceCharFormat)
       charFormatIndex = primaryCharFormatIndex;
    else
       charFormatIndex = convertFormatIndex(frag->format, objectIndex);

    const int inFragmentOffset = qMax(0, pos - fragIt.position());
    int charsToCopy = qMin(int(frag->size_array[0] - inFragmentOffset), endPos - pos);

    QTextBlock nextBlock = src->blocksFind(pos + 1);

    int blockIdx = -2;
    if (nextBlock.position() == pos + 1) {
        blockIdx = convertFormatIndex(nextBlock.blockFormat());
    } else if (pos == 0 && insertPos == 0) {
        dst->setBlockFormat(dst->blocksBegin(), dst->blocksBegin(), convertFormat(src->blocksBegin().blockFormat()).toBlockFormat());
        dst->setCharFormat(-1, 1, convertFormat(src->blocksBegin().charFormat()).toCharFormat());
    }

    QString txtToInsert(originalText.constData() + frag->stringPosition + inFragmentOffset, charsToCopy);
    if (txtToInsert.length() == 1
        && (txtToInsert.at(0) == QChar::ParagraphSeparator
            || txtToInsert.at(0) == QTextBeginningOfFrame
            || txtToInsert.at(0) == QTextEndOfFrame
           )
       ) {
        dst->insertBlock(txtToInsert.at(0), insertPos, blockIdx, charFormatIndex);
        ++insertPos;
    } else {
        if (nextBlock.textList()) {
            QTextBlock dstBlock = dst->blocksFind(insertPos);
            if (!dstBlock.textList()) {
                // insert a new text block with the block and char format from the
                // source block to make sure that the following text fragments
                // end up in a list as they should
                int listBlockFormatIndex = convertFormatIndex(nextBlock.blockFormat());
                int listCharFormatIndex = convertFormatIndex(nextBlock.charFormat());
                dst->insertBlock(insertPos, listBlockFormatIndex, listCharFormatIndex);
                ++insertPos;
            }
        }
        dst->insert(insertPos, txtToInsert, charFormatIndex);
        const int userState = nextBlock.userState();
        if (userState != -1)
            dst->blocksFind(insertPos).setUserState(userState);
        insertPos += txtToInsert.length();
    }

    return charsToCopy;
}
コード例 #2
0
ファイル: KoList.cpp プロジェクト: KDE/koffice
int KoList::level(const QTextBlock &block)
{
    if (!block.textList())
        return 0;
    int l = block.blockFormat().intProperty(KParagraphStyle::ListLevel);
    if (!l) { // not a numbered-paragraph
        QTextListFormat format = block.textList()->format();
        l = format.intProperty(KListStyle::Level);
    }
    return l;
}
コード例 #3
0
ファイル: KoList.cpp プロジェクト: KDE/koffice
void KoList::updateStoredList(const QTextBlock &block)
{
    if (block.textList()) {
        int level = block.textList()->format().property(KListStyle::Level).toInt();
        QTextList *textList = block.textList();
        QTextListFormat format = textList->format();
        format.setProperty(KListStyle::ListId, (KListStyle::ListIdType)(textList));
        textList->setFormat(format);
        d->textLists[level-1] = textList;
        d->textListIds[level-1] = (KListStyle::ListIdType)textList;
    }
}
コード例 #4
0
        void visit(QTextBlock &block) const {
            QTextBlockFormat format = block.blockFormat();
            // TODO make the 10 configurable.
            format.setLeftMargin(qMax(qreal(0.0), format.leftMargin() - 10));

            if (block.textList()) {
                const QTextListFormat listFormat = block.textList()->format();
                if (format.leftMargin() < listFormat.doubleProperty(KoListStyle::Margin)) {
                    format.setLeftMargin(listFormat.doubleProperty(KoListStyle::Margin));
                }
            }
            QTextCursor cursor(block);
            cursor.setBlockFormat(format);
        }
コード例 #5
0
ChangeListLevelCommand::ChangeListLevelCommand(const QTextCursor &cursor, ChangeListLevelCommand::CommandType type,
                                               int coef, KUndo2Command *parent)
    : KoTextCommandBase(parent),
      m_type(type),
      m_coefficient(coef),
      m_first(true)
{
    setText(kundo2_i18n("Change List Level"));

    int selectionStart = qMin(cursor.anchor(), cursor.position());
    int selectionEnd = qMax(cursor.anchor(), cursor.position());

    QTextBlock block = cursor.block().document()->findBlock(selectionStart);

    bool oneOf = (selectionStart == selectionEnd); //ensures the block containing the cursor is selected in that case

    while (block.isValid() && ((block.position() < selectionEnd) || oneOf)) {
        m_blocks.append(block);
        if (block.textList()) {
            m_lists.insert(m_blocks.size() - 1, KoTextDocument(block.document()).list(block.textList()));
            Q_ASSERT(m_lists.value(m_blocks.size() - 1));
            m_levels.insert(m_blocks.size() - 1, effectiveLevel(m_lists.value(m_blocks.size() - 1)->level(block)));
        }
        oneOf = false;
        block = block.next();
    }
}
コード例 #6
0
ファイル: TestLists.cpp プロジェクト: HOST-Oman/krita
void TestDocumentLayout::testInvalidateLists()
{
    initForNewTest("Base\nListItem1\nListItem2");

    //KoParagraphStyle style;
    KoListStyle listStyle;
    KoListLevelProperties llp;
    llp.setStyle(KoListStyle::DecimalItem);
    listStyle.setLevelProperties(llp);
    //style.setListStyle(&listStyle);

    QTextBlock block = m_doc->begin().next();
    QVERIFY(block.isValid());
    listStyle.applyStyle(block);
    block = block.next();
    QVERIFY(block.isValid());
    listStyle.applyStyle(block);

    m_layout->layout();

    // check the list items were done (semi) properly
    block = m_doc->begin().next();
    QVERIFY(block.textList());
    KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
    QVERIFY(data);
    QVERIFY(data->hasCounterData());

    QTextCursor cursor(m_doc);
    cursor.setPosition(10); // list item1
    cursor.insertText("x");
    QCOMPARE(data->hasCounterData(), true); // nothing changed

    cursor.setPosition(22); // list item2
    cursor.insertText("x");
    QCOMPARE(data->hasCounterData(), true); // nothing changed
    cursor.deleteChar();
    QCOMPARE(data->hasCounterData(), true); // nothing changed

    cursor.setPosition(25); // end of doc
    cursor.insertBlock();
    block = cursor.block();
    QVERIFY(block.textList());
    QVERIFY(block.userData() == 0);

    QCOMPARE(data->hasCounterData(), false); // inserting a new block on this list made the list be invalidated
}
コード例 #7
0
ファイル: TestLists.cpp プロジェクト: HOST-Oman/krita
void TestDocumentLayout::testBasicList()
{
    initForNewTest("Base\nListItem\nListItem2: The quick brown fox jums over the lazy dog.\nNormal\nNormal");

    KoParagraphStyle style;
    QTextBlock block = m_doc->begin();
    style.applyStyle(block);
    block = block.next();
    QVERIFY(block.isValid());

    KoListStyle listStyle;
    KoListLevelProperties level1;
    level1.setStyle(KoListStyle::Bullet);
    listStyle.setLevelProperties(level1);
    style.setListStyle(&listStyle);
    style.applyStyle(block); // make this a listStyle
    QVERIFY(block.textList());
    QCOMPARE(block.textList()->format().intProperty(QTextListFormat::ListStyle), (int) KoListStyle::Bullet);
    block = block.next();
    QVERIFY(block.isValid());
    style.applyStyle(block); // make this a listStyle

    m_layout->layout();
    QTextLayout *blockLayout = m_block.layout();

    QCOMPARE(blockLayout->lineAt(0).x(), 0.0);
    block = m_doc->begin().next();
    QVERIFY(block.isValid());
    blockLayout = block.layout(); // parag 2
    KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
    QVERIFY(data);
    qreal counterSpacing = data->counterSpacing();
    QVERIFY(counterSpacing > 0.);
    // 12 is hardcoded to be the width of a discitem (taken from the default font):
    QCOMPARE(blockLayout->lineAt(0).x(), 12.0 + counterSpacing);
    block = block.next();
    QVERIFY(block.isValid());
    blockLayout = block.layout(); // parag 3
    QCOMPARE(blockLayout->lineAt(0).x(), 12.0 + counterSpacing);
    QVERIFY(blockLayout->lineCount() > 1);
    QCOMPARE(blockLayout->lineAt(1).x(), 12.0 + counterSpacing); // make sure not only the first line is indented
    block = block.next();
    QVERIFY(block.isValid());
    blockLayout = block.layout(); // parag 4
    QCOMPARE(blockLayout->lineAt(0).x(), 0.0);
}
コード例 #8
0
QString TextDocumentSerializer::processBlock(QTextBlock block,
                                             QTextFrame::iterator &it)
{
    if(block.textList())
        return processList(it);
    else
        return processBlockContent(block);
}
コード例 #9
0
        void visit(QTextBlock &block) const {
            QTextBlockFormat format = block.blockFormat();
            // TODO make the 10 configurable.

            if (!block.textList()) {
                format.setLeftMargin(format.leftMargin() + 10);
            } else {
                const QTextListFormat listFormat = block.textList()->format();
                if (format.leftMargin() == 0) {
                    format.setLeftMargin(listFormat.doubleProperty(KoListStyle::Margin) + 10);
                } else {
                    format.setLeftMargin(format.leftMargin() + 10);
                }
            }
            QTextCursor cursor(block);
            cursor.setBlockFormat(format);
        }
コード例 #10
0
ファイル: KoList.cpp プロジェクト: KDE/koffice
void KoList::remove(const QTextBlock &block)
{
    if (QTextList *textList = block.textList()) {
        // invalidate the list before we remove the item
        // (since the list might disappear if the block is the only item)
        KoListPrivate::invalidateList(block);
        textList->remove(block);
    }
    KoListPrivate::invalidate(block);
}
コード例 #11
0
ファイル: KTextDocumentLayout.cpp プロジェクト: KDE/koffice
void KTextDocumentLayout::documentChanged(int position, int charsRemoved, int charsAdded)
{
    Q_UNUSED(charsRemoved);
    if (shapes().count() == 0) // nothing to do.
        return;

/*
    switch (document()->documentLayout()->property("KoTextRelayoutForPage").toInt()) {
    case KTextShapeData::NormalState:
        kDebug() << "KoTextRelayoutForPage in NormalState"; break;
    case KTextShapeData::LayoutCopyShape:
        kDebug() << "KoTextRelayoutForPage in LayoutCopyShape"; break;
    case KTextShapeData::LayoutOrig:
        kDebug() << "KoTextRelayoutForPage in LayoutOrig, skipping relayout"; break;
    }
*/
    if (document()->documentLayout()->property("KoTextRelayoutForPage").toInt() == KTextShapeData::LayoutOrig) {
        // don't refresh if we relayout after a relayout-for-page
        return;
    }

    int from = position;
    const int to = from + charsAdded;
    while (from < to) { // find blocks that have been added
        QTextBlock block = document()->findBlock(from);
        if (! block.isValid())
            break;
        if (from == block.position() && block.textList()) {
            KTextBlockData *data = dynamic_cast<KTextBlockData*>(block.userData());
            if (data)
                data->setCounterWidth(-1); // invalidate whole list.
        }

        from = block.position() + block.length();
    }

    foreach (KShape *shape, shapes()) {
        KTextShapeData *data = qobject_cast<KTextShapeData*>(shape->userData());
        Q_ASSERT(data);
        if (data && data->position() <= position && data->endPosition() >= position) {
            // found our (first) shape to re-layout
            data->foul();
            m_state->interrupted = true;
            scheduleLayout();
            return;
        }
    }
コード例 #12
0
QString TextDocumentSerializer::processList(QTextFrame::iterator &it)
{
    QString text;

    QTextBlock block = it.currentBlock();

    while(block.textList()){
        text += processBlockContent(block);

        ++it;
        block = it.currentBlock();
    }

    --it;

    return QString("<ul>%1</ul>").arg(text);
}
コード例 #13
0
QString TextDocumentSerializer::processBlockContent(QTextBlock block)
{
    QTextBlock::iterator it = block.begin();

    QString text;

    while(!it.atEnd()){
        QTextFragment currentFragment = it.fragment();

        if (currentFragment.isValid())
            text += processFragment(currentFragment);

        ++it;
    }

    if(block.textList())
        return QString("<li>%1</li>").arg(text);
    else
        return QString("%1<br>").arg(text);
}
コード例 #14
0
ファイル: TestLists.cpp プロジェクト: HOST-Oman/krita
void TestDocumentLayout::testMultiLevel()
{
    initForNewTest("ListItem1\n");
    KoListStyle listStyle;
    KoListLevelProperties llp;
    llp.setStyle(KoListStyle::DecimalItem);
    llp.setLevel(3);
    llp.setDisplayLevel(4); // we won't show a .0 at the end so this is truncated to 3
    listStyle.setLevelProperties(llp);

    QTextBlock block = m_doc->begin();
    QVERIFY(block.isValid());
    listStyle.applyStyle(block);
    QVERIFY(block.textList());

    m_layout->layout();

    KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
    QVERIFY(data);
    QVERIFY(data->hasCounterData());
    QCOMPARE(data->counterText(), QString("1.1.1"));
}
コード例 #15
0
QHash<QTextList *, QString> KoTextWriter::saveListStyles(QTextBlock block, int to)
{
    QHash<KoList *, QString> generatedLists;
    QHash<QTextList *, QString> listStyles;
    KoTextDocument document(block.document());

    for (;block.isValid() && ((to == -1) || (block.position() < to)); block = block.next()) {
        QTextList *textList = block.textList();
        if (!textList)
            continue;
        if (KoList *list = document.list(block)) {
            if (generatedLists.contains(list)) {
                if (!listStyles.contains(textList))
                    listStyles.insert(textList, generatedLists.value(list));
                continue;
            }
            KoListStyle *listStyle = list->style();
            bool automatic = listStyle->styleId() == 0;
            KoGenStyle style(automatic ? KoGenStyle::StyleListAuto : KoGenStyle::StyleList);
            listStyle->saveOdf(style);
            QString generatedName = d->context.mainStyles().lookup(style, listStyle->name(), KoGenStyles::AllowDuplicates);
            listStyles[textList] = generatedName;
            generatedLists.insert(list, generatedName);
        } else {
            if (listStyles.contains(textList))
                continue;
            KoListLevelProperties llp = KoListLevelProperties::fromTextList(textList);
            KoGenStyle style(KoGenStyle::StyleListAuto);
            KoListStyle listStyle;
            listStyle.setLevelProperties(llp);
            listStyle.saveOdf(style);
            QString generatedName = d->context.mainStyles().lookup(style, listStyle.name());
            listStyles[textList] = generatedName;
        }
    }
    return listStyles;
}
コード例 #16
0
QString TextDocumentSerializer::processFrame(QTextFrame *frame)
{
    QString text;

    QTextFrame::iterator it = frame->begin();
    while(!it.atEnd()){
        QTextFrame *childFrame = it.currentFrame();
        QTextBlock childBlock = it.currentBlock();

        if(childFrame)
            text += processFrame(childFrame);
        else if(childBlock.isValid()){
            if(childBlock.textList())
                text = removeTrailingLineBreaks(text);
            text += processBlock(childBlock, it);
        }

        ++it;
    }

    text = removeTrailingLineBreaks(text);

    return text;
}
コード例 #17
0
ファイル: format.cpp プロジェクト: cornelius/todoodle
QString Format::frameToString( QTextFrame *frame )
{
  QString out;

  QTextFrame::iterator it;
  for( it = frame->begin(); it != frame->end(); ++it ) {
    QTextBlock block = it.currentBlock();
    if ( block.isValid() ) {
      out += "<block";

      QTextCursor c( block );

      QDateTime dt = TextFormats::lastModified( c );
      if ( dt.isValid() ) {
        out += " lastmodified=\"" + dt.toString( Qt::ISODate ) + "\"";
      }

      if ( TextFormats::isTitle( c ) ) {
        out += " titlestyle=\"title\"";
      } else if ( TextFormats::isSubTitle( c ) ) {
        out += " titlestyle=\"subtitle\"";
      }

      QTextBlockFormat blockFormat = block.blockFormat();
      if ( blockFormat.isValid() ) {
        QTextList *list = block.textList();
        if ( list ) {
          QTextListFormat f = list->format();
          out += " liststyle=\"";
          switch( f.style() ) {
            default:
            case QTextListFormat::ListDisc:
              out += "disc";
              break;
            case QTextListFormat::ListDecimal:
              out += "decimal";
              break;
          }
          out += "\"";

          out += " listindent=\"" + QString::number( f.indent() ) + "\"";
        } else {
          if ( blockFormat.indent() != 0 ) {
            out += " blockindent=\"" + QString::number( blockFormat.indent() ) +
              "\"";
          }
        }
      }

      out += ">\n";
      
      QTextBlock::iterator it2;
      for( it2 = block.begin(); it2 != block.end(); ++it2 ) {
        QTextFragment fragment = it2.fragment();
        if ( !fragment.isValid() ) continue;

        QString text = fragment.text();

        QString outText;
        for( int i = 0; i < text.size(); ++i ) {
          if ( text.at( i ) == 0xfffc ) {
            outText += "<todo status=\"";

            QTextImageFormat imageFormat = fragment.charFormat().toImageFormat();
            if ( imageFormat.isValid() ) {
              if ( imageFormat.name().contains( "done" ) ) outText += "done";
              else outText += "todo";
            } else {
              dbg() << "NO IMAGE FORMAT" << endl;
            }
            
            outText += "\"/>";
          } else {
            outText += escape( QString( text.at( i ) ) );
          }
        }

        out += "  <fragment";

        QTextCharFormat format = fragment.charFormat();
        if ( !format.anchorHref().isEmpty() ) {
          out += " link=\"" + escape( format.anchorHref() ) + "\"";
        }
        if ( format.fontWeight() == QFont::Bold ) {
          out += " bold=\"true\"";
        }
        if ( format.fontItalic() ) {
          out += " italic=\"true\"";
        }
        if ( format.hasProperty( QTextFormat::FontPointSize ) &&
             format.fontPointSize() != 10 ) {
          out += " fontsize=\"" + QString::number( format.fontPointSize() ) +
            "\"";
        }

        if ( outText.trimmed().isEmpty() ) outText.replace( " ", "[FIXME:space]" );

        out += ">" + outText + "</fragment>\n";
      }
      
      out += "</block>";

      out += "\n";
    }
    QTextFrame *f = it.currentFrame();
    if ( f ) {
      QTextFrameFormat format = f->frameFormat();
      out += "<frame";
      if ( format.hasProperty( TextFormats::FrameType ) ) {
        out += " type=";
        if ( format.property( TextFormats::FrameType ) == TextFormats::CodeFrame ) {
          out += "\"code\"";
        } else {
          out += "\"undefined\"";
        }
      }
      out += ">\n";
      out += frameToString( f );
      out += "</frame>\n";
    }
  }

  return out;
}
コード例 #18
0
void QTextOdfWriter::writeBlock(QXmlStreamWriter &writer, const QTextBlock &block)
{
    if (block.textList()) { // its a list-item
        const int listLevel = block.textList()->format().indent();
        if (m_listStack.isEmpty() || m_listStack.top() != block.textList()) {
            // not the same list we were in.
            while (m_listStack.count() >= listLevel && !m_listStack.isEmpty() && m_listStack.top() != block.textList() ) { // we need to close tags
                m_listStack.pop();
                writer.writeEndElement(); // list
                if (m_listStack.count())
                    writer.writeEndElement(); // list-item
            }
            while (m_listStack.count() < listLevel) {
                if (m_listStack.count())
                    writer.writeStartElement(textNS, QString::fromLatin1("list-item"));
                writer.writeStartElement(textNS, QString::fromLatin1("list"));
                if (m_listStack.count() == listLevel - 1) {
                    m_listStack.push(block.textList());
                    writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("L%1")
                            .arg(block.textList()->formatIndex()));
                }
                else {
                    m_listStack.push(0);
                }
            }
        }
        writer.writeStartElement(textNS, QString::fromLatin1("list-item"));
    }
    else {
        while (! m_listStack.isEmpty()) {
            m_listStack.pop();
            writer.writeEndElement(); // list
            if (m_listStack.count())
                writer.writeEndElement(); // list-item
        }
    }

    if (block.length() == 1) { // only a linefeed
        writer.writeEmptyElement(textNS, QString::fromLatin1("p"));
        writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("p%1")
            .arg(block.blockFormatIndex()));
        if (block.textList())
            writer.writeEndElement(); // numbered-paragraph
        return;
    }
    writer.writeStartElement(textNS, QString::fromLatin1("p"));
    writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("p%1")
        .arg(block.blockFormatIndex()));
    for (QTextBlock::Iterator frag= block.begin(); !frag.atEnd(); frag++) {
        writer.writeCharacters(QString()); // Trick to make sure that the span gets no linefeed in front of it.
        writer.writeStartElement(textNS, QString::fromLatin1("span"));

        QString fragmentText = frag.fragment().text();
        if (fragmentText.length() == 1 && fragmentText[0] == 0xFFFC) { // its an inline character.
            writeInlineCharacter(writer, frag.fragment());
            writer.writeEndElement(); // span
            continue;
        }

        writer.writeAttribute(textNS, QString::fromLatin1("style-name"), QString::fromLatin1("c%1")
            .arg(frag.fragment().charFormatIndex()));
        bool escapeNextSpace = true;
        int precedingSpaces = 0;
        int exportedIndex = 0;
        for (int i=0; i <= fragmentText.count(); ++i) {
            QChar character = fragmentText[i];
            bool isSpace = character.unicode() == ' ';

            // find more than one space. -> <text:s text:c="2" />
            if (!isSpace && escapeNextSpace && precedingSpaces > 1) {
                const bool startParag = exportedIndex == 0 && i == precedingSpaces;
                if (!startParag)
                    writer.writeCharacters(fragmentText.mid(exportedIndex, i - precedingSpaces + 1 - exportedIndex));
                writer.writeEmptyElement(textNS, QString::fromLatin1("s"));
                const int count = precedingSpaces - (startParag?0:1);
                if (count > 1)
                    writer.writeAttribute(textNS, QString::fromLatin1("c"), QString::number(count));
                precedingSpaces = 0;
                exportedIndex = i;
            }

            if (i < fragmentText.count()) {
                if (character.unicode() == 0x2028) { // soft-return
                    //if (exportedIndex < i)
                        writer.writeCharacters(fragmentText.mid(exportedIndex, i - exportedIndex));
                    writer.writeEmptyElement(textNS, QString::fromLatin1("line-break"));
                    exportedIndex = i+1;
                    continue;
                } else if (character.unicode() == '\t') { // Tab
                    //if (exportedIndex < i)
                        writer.writeCharacters(fragmentText.mid(exportedIndex, i - exportedIndex));
                    writer.writeEmptyElement(textNS, QString::fromLatin1("tab"));
                    exportedIndex = i+1;
                    precedingSpaces = 0;
                } else if (isSpace) {
                    ++precedingSpaces;
                    escapeNextSpace = true;
                } else if (!isSpace) {
                    precedingSpaces = 0;
                }
            }
        }

        writer.writeCharacters(fragmentText.mid(exportedIndex));
        writer.writeEndElement(); // span
    }
    writer.writeCharacters(QString()); // Trick to make sure that the span gets no linefeed behind it.
    writer.writeEndElement(); // p
    if (block.textList())
        writer.writeEndElement(); // list-item
}
コード例 #19
0
ファイル: mainwindow.cpp プロジェクト: cedrus/qt4
void MainWindow::showList()
{
    QTextCursor cursor = editor->textCursor();
    QTextFrame *frame = cursor.currentFrame();

    if (!frame)
        return;

    QTreeWidget *treeWidget = new QTreeWidget;
    treeWidget->setColumnCount(1);
    QStringList headerLabels;
    headerLabels << tr("Lists");
    treeWidget->setHeaderLabels(headerLabels);

    QTreeWidgetItem *parentItem = 0;
    QTreeWidgetItem *item;
    QTreeWidgetItem *lastItem = 0;
    parentItems.clear();
    previousItems.clear();

//! [3]
    QTextFrame::iterator it;
    for (it = frame->begin(); !(it.atEnd()); ++it) {

        QTextBlock block = it.currentBlock();

        if (block.isValid()) {

            QTextList *list = block.textList();

            if (list) {
                int index = list->itemNumber(block);
//! [3]
                if (index == 0) {
                    parentItems.append(parentItem);
                    previousItems.append(lastItem);
                    listStructures.append(list);
                    parentItem = lastItem;
                    lastItem = 0;

                    if (parentItem != 0)
                        item = new QTreeWidgetItem(parentItem, lastItem);
                    else
                        item = new QTreeWidgetItem(treeWidget, lastItem);

                } else {

                    while (parentItem != 0 && listStructures.last() != list) {
                        listStructures.pop_back();
                        parentItem = parentItems.takeLast();
                        lastItem = previousItems.takeLast();
                    }
                    if (parentItem != 0)
                        item = new QTreeWidgetItem(parentItem, lastItem);
                    else
                        item = new QTreeWidgetItem(treeWidget, lastItem);
                }
                item->setText(0, block.text());
                lastItem = item;
                /*
//! [4]
                processListItem(list, index);
//! [4]
                */
//! [5]
            }
//! [5] //! [6]
        }
//! [6] //! [7]
    }
//! [7]

    treeWidget->setWindowTitle(tr("List Contents"));
    treeWidget->show();
}
コード例 #20
0
ファイル: QMarkdown.cpp プロジェクト: 02JanDal/QMarkdown
QByteArray QGithubMarkdown::write(QTextDocument *source)
{
	QStringList output;
	bool wasInList = false;
	bool inCodeBlock = false;
	auto endCodeBlock = [&]()
	{
		if (inCodeBlock)
		{
			output.append("```\n");
		}
		inCodeBlock = false;
	};
	auto formatForPos = [&](const QTextBlock &block, const int pos) -> QTextCharFormat
	{
		for (const auto fmtRange : block.textFormats())
		{
			if (fmtRange.start <= pos && pos <= (fmtRange.start + fmtRange.length))
			{
				return fmtRange.format;
			}
		}
		Q_ASSERT(false);
		return QTextCharFormat();
	};
	auto blockToMarkdown = [&](const QTextBlock &block, const int offset = 0) -> QString
	{
		QString out;
		bool inBold = false;
		bool inItalic = false;
		QString currentLink;
		for (int i = offset; i < block.text().size(); ++i)
		{
			const QChar c = block.text().at(i);
			const QTextCharFormat fmt = formatForPos(block, i);
			if (fmt.fontItalic() != inItalic)
			{
				out.insert(out.size() - 1, '_');
				inItalic = !inItalic;
			}
			if ((fmt.fontWeight() == QFont::Bold) != inBold)
			{
				out.insert(out.size() - 1, "**");
				inBold = !inBold;
			}
			if (fmt.anchorHref().isEmpty() && !currentLink.isNull())
			{
				out.insert(out.size() - 1, "](" + currentLink + ")");
			}
			else if (!fmt.anchorHref().isEmpty() && currentLink.isNull())
			{
				out.insert(out.size() - 1, "[");
				currentLink = fmt.anchorHref();
			}
			// FIXME images
			out.append(c);
		}
		return out;
	};
	for (QTextBlock block = source->begin(); block != source->end(); block = block.next())
	{
		// heading
		if (block.charFormat().toolTip() == block.text())
		{
			endCodeBlock();
			output.append(QString(sizeMap.key(block.charFormat().fontPointSize()), '#') + " " + block.text() + "\n");
		}
		else
		{
			// list
			if (QTextList *list = block.textList())
			{
				endCodeBlock();
				const QString indent = QString((list->format().indent()-1) * 2, ' ');
				if (list->format().style() == QTextListFormat::ListDisc)
				{
					output.append(indent + "* " + blockToMarkdown(block));
				}
				else
				{
					output.append(indent + QString::number(list->itemNumber(block) + 1) + ". " + blockToMarkdown(block));
				}
				wasInList = true;
			}
			else
			{
				if (wasInList)
				{
					output.append("");
					wasInList = false;
				}
				if (block.charFormat().fontFamily() == "Monospace")
				{
					if (!inCodeBlock)
					{
						inCodeBlock = true;
						output.insert(output.size() - 1, "```");
					}
					output.append(block.text().remove("\n"));
				}
				else
				{
					endCodeBlock();
					output.append(blockToMarkdown(block) + "\n");
				}
			}
		}
	}
	QString string = output.join("\n");
	return string.trimmed().toUtf8();
}
コード例 #21
0
void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QTextBlock &block, const QPointF &position, const QColor &textColor, const QColor &anchorColor, int selectionStart, int selectionEnd)
{
    Q_ASSERT(textDocument);
#ifndef QT_NO_IM
    int preeditLength = block.isValid() ? block.layout()->preeditAreaText().length() : 0;
    int preeditPosition = block.isValid() ? block.layout()->preeditAreaPosition() : -1;
#endif

    QVarLengthArray<QTextLayout::FormatRange> colorChanges;
    mergeFormats(block.layout(), &colorChanges);

    QPointF blockPosition = textDocument->documentLayout()->blockBoundingRect(block).topLeft() + position;
    if (QTextList *textList = block.textList()) {
        QPointF pos = blockPosition;
        QTextLayout *layout = block.layout();
        if (layout->lineCount() > 0) {
            QTextLine firstLine = layout->lineAt(0);
            Q_ASSERT(firstLine.isValid());

            setCurrentLine(firstLine);

            QRectF textRect = firstLine.naturalTextRect();
            pos += textRect.topLeft();
            if (block.textDirection() == Qt::RightToLeft)
                pos.rx() += textRect.width();

            const QTextCharFormat charFormat = block.charFormat();
            QFont font(charFormat.font());
            QFontMetricsF fontMetrics(font);
            QTextListFormat listFormat = textList->format();

            QString listItemBullet;
            switch (listFormat.style()) {
            case QTextListFormat::ListCircle:
                listItemBullet = QChar(0x25E6); // White bullet
                break;
            case QTextListFormat::ListSquare:
                listItemBullet = QChar(0x25AA); // Black small square
                break;
            case QTextListFormat::ListDecimal:
            case QTextListFormat::ListLowerAlpha:
            case QTextListFormat::ListUpperAlpha:
            case QTextListFormat::ListLowerRoman:
            case QTextListFormat::ListUpperRoman:
                listItemBullet = textList->itemText(block);
                break;
            default:
                listItemBullet = QChar(0x2022); // Black bullet
                break;
            };

            QSizeF size(fontMetrics.width(listItemBullet), fontMetrics.height());
            qreal xoff = fontMetrics.width(QLatin1Char(' '));
            if (block.textDirection() == Qt::LeftToRight)
                xoff = -xoff - size.width();
            setPosition(pos + QPointF(xoff, 0));

            QTextLayout layout;
            layout.setFont(font);
            layout.setText(listItemBullet); // Bullet
            layout.beginLayout();
            QTextLine line = layout.createLine();
            line.setPosition(QPointF(0, 0));
            layout.endLayout();

            QList<QGlyphRun> glyphRuns = layout.glyphRuns();
            for (int i=0; i<glyphRuns.size(); ++i)
                addUnselectedGlyphs(glyphRuns.at(i));
        }
    }

    int textPos = block.position();
    QTextBlock::iterator blockIterator = block.begin();

    while (!blockIterator.atEnd()) {
        QTextFragment fragment = blockIterator.fragment();
        QString text = fragment.text();
        if (text.isEmpty())
            continue;

        QTextCharFormat charFormat = fragment.charFormat();
        QFont font(charFormat.font());
        QFontMetricsF fontMetrics(font);

        int fontHeight = fontMetrics.descent() + fontMetrics.ascent();
        int valign = charFormat.verticalAlignment();
        if (valign == QTextCharFormat::AlignSuperScript)
            setPosition(QPointF(blockPosition.x(), blockPosition.y() - fontHeight / 2));
        else if (valign == QTextCharFormat::AlignSubScript)
            setPosition(QPointF(blockPosition.x(), blockPosition.y() + fontHeight / 6));
        else
            setPosition(blockPosition);

        if (text.contains(QChar::ObjectReplacementCharacter)) {
            QTextFrame *frame = qobject_cast<QTextFrame *>(textDocument->objectForFormat(charFormat));
            if (frame && frame->frameFormat().position() == QTextFrameFormat::InFlow) {
                int blockRelativePosition = textPos - block.position();
                QTextLine line = block.layout()->lineForTextPosition(blockRelativePosition);
                if (!currentLine().isValid()
                        || line.lineNumber() != currentLine().lineNumber()) {
                    setCurrentLine(line);
                }

                QQuickTextNodeEngine::SelectionState selectionState =
                        (selectionStart < textPos + text.length()
                         && selectionEnd >= textPos)
                        ? QQuickTextNodeEngine::Selected
                        : QQuickTextNodeEngine::Unselected;

                addTextObject(QPointF(), charFormat, selectionState, textDocument, textPos);
            }
            textPos += text.length();
        } else {
            if (charFormat.foreground().style() != Qt::NoBrush)
                setTextColor(charFormat.foreground().color());
            else if (charFormat.isAnchor())
                setTextColor(anchorColor);
            else
                setTextColor(textColor);

            int fragmentEnd = textPos + fragment.length();
#ifndef QT_NO_IM
            if (preeditPosition >= 0
                    && (preeditPosition + block.position()) >= textPos
                    && (preeditPosition + block.position()) <= fragmentEnd) {
                fragmentEnd += preeditLength;
            }
#endif
            if (charFormat.background().style() != Qt::NoBrush) {
                QTextLayout::FormatRange additionalFormat;
                additionalFormat.start = textPos - block.position();
                additionalFormat.length = fragmentEnd - textPos;
                additionalFormat.format = charFormat;
                colorChanges << additionalFormat;
            }

            textPos = addText(block, charFormat, textColor, colorChanges, textPos, fragmentEnd,
                                                 selectionStart, selectionEnd);
        }

        ++blockIterator;
    }

#ifndef QT_NO_IM
    if (preeditLength >= 0 && textPos <= block.position() + preeditPosition) {
        setPosition(blockPosition);
        textPos = block.position() + preeditPosition;
        QTextLine line = block.layout()->lineForTextPosition(preeditPosition);
        if (!currentLine().isValid()
                || line.lineNumber() != currentLine().lineNumber()) {
            setCurrentLine(line);
        }
        textPos = addText(block, block.charFormat(), textColor, colorChanges,
                                             textPos, textPos + preeditLength,
                                             selectionStart, selectionEnd);
    }
#endif

    setCurrentLine(QTextLine()); // Reset current line because the text layout changed
    m_hasContents = true;
}
コード例 #22
0
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>
        }
    }
}
コード例 #23
0
ファイル: TestListStyle.cpp プロジェクト: KDE/koffice
void TestListStyle::testListStyle()
{
    KListStyle ls;
    KListLevelProperties llp = ls.levelProperties(2);
    QCOMPARE(llp.level(), 2);

    llp.setStyle(KListStyle::AlphaLowerItem);
    KListLevelProperties llp2 = ls.levelProperties(2);
    QVERIFY(llp2.style() != llp.style());

    ls.setLevelProperties(llp);
    QCOMPARE(llp.level(), 2);
    QCOMPARE(llp.style(), KListStyle::AlphaLowerItem);

    llp = ls.levelProperties(2);
    QCOMPARE(llp.level(), 2);
    QCOMPARE(llp.style(), KListStyle::AlphaLowerItem);

    QTextDocument doc;
    KTextDocument kodoc(&doc);
    kodoc.setStyleManager(new KStyleManager);
    QTextCursor cursor(&doc);
    cursor.insertText("foo\nbar\nBaz\n");
    QTextBlock block = doc.begin();
    ls.applyStyle(block, 2);
    QVERIFY(block.textList());
    QTextList *textList = block.textList();
    QTextListFormat format = textList->format();
    QCOMPARE(format.intProperty(QTextListFormat::ListStyle), (int)(KListStyle::AlphaLowerItem));

    block = block.next();
    QVERIFY(block.isValid());
    ls.applyStyle(block, 2);
    QVERIFY(block.textList());
    QCOMPARE(block.textList(), textList);

    ls.applyStyle(block, 10); // should set the properties of the only one that is set, level 1
    QVERIFY(block.textList());
    textList = block.textList();
    format = textList->format();
    QCOMPARE(format.intProperty(QTextListFormat::ListStyle), (int)(KListStyle::AlphaLowerItem));

    // getting a properties without setting it doesn't change the list.
    KListLevelProperties l4 = ls.levelProperties(4);
    QCOMPARE(l4.level(), 4);
    QCOMPARE(l4.displayLevel(), 0); // default
    l4.setDisplayLevel(3);
    QCOMPARE(l4.displayLevel(), 3);
    QCOMPARE(ls.hasLevelProperties(4), false);

    KListLevelProperties anotherL4 = ls.levelProperties(4);
    QCOMPARE(anotherL4.level(), 4);
    QCOMPARE(anotherL4.displayLevel(), 0); // default
    QCOMPARE(ls.hasLevelProperties(4), false);

    QCOMPARE(ls.hasLevelProperties(5), false);
    // new levels are a copy of the existing level.
    KListLevelProperties l5 = ls.levelProperties(5);
    QCOMPARE(l5.displayLevel(), 0);
    QCOMPARE(l5.style(), KListStyle::AlphaLowerItem);
    QCOMPARE(l5.indent(), 0.);
}
コード例 #24
0
ファイル: TestLists.cpp プロジェクト: HOST-Oman/krita
void TestDocumentLayout::testNumberedList()
{
    initForNewTest("Base\nListItem1\nListItem2\nListItem3\nListItem4\nListItem5\nListItem6\nListItem6\nListItem7\nListItem8\nListItem9\nListItem10\nListItem11\nListItem12\n");

    KoParagraphStyle style;
    m_styleManager->add(&style);
    QTextBlock block = m_doc->begin();
    style.applyStyle(block);
    block = block.next();

    KoListStyle listStyle;
    KoListLevelProperties llp;
    llp.setStyle(KoListStyle::DecimalItem);
    listStyle.setLevelProperties(llp);
    style.setListStyle(&listStyle);

    QTextList *previous = 0;
    int i;
    for (i = 1; i <= 9; i++) {
        QVERIFY(block.isValid());
        // qDebug() << "->" << block.text();
        style.applyStyle(block);
        QTextList *textList = block.textList();
        QVERIFY(textList);
        if (previous == 0) {
            previous = textList;
        } else {
            QCOMPARE(textList, previous);
        }
        QCOMPARE(textList->format().intProperty(QTextListFormat::ListStyle), (int)(KoListStyle::DecimalItem));
        block = block.next();
    }
    m_layout->layout();
    QTextLayout *blockLayout = m_block.layout();

    QCOMPARE(blockLayout->lineAt(0).x(), 0.0);
    QTextBlock blok = m_doc->begin().next();
    qreal indent = blok.layout()->lineAt(0).x();
    QVERIFY(indent > 0.0);
    for (i = 1; i <= 9; ++i) {
        // qDebug() << "=>" << blok.text();
        QTextList *textList = blok.textList();
        QVERIFY(textList);
        QCOMPARE(blok.layout()->lineAt(0).x(), indent); // all the same indent.
        blok = blok.next();
    }

    // now make number of listitems be more than 10, so we use 2 digits.
    for (i = 9; i <= 12; ++i) {
        QVERIFY(block.isValid());
        style.applyStyle(block);
        // qDebug() << "->" << block.text();
        block = block.next();
    }
    m_layout->layout();
    blockLayout = m_block.layout();

    QCOMPARE(blockLayout->lineAt(0).x(), 0.0);
    blok = m_doc->begin().next();
    qreal indent2 = blok.layout()->lineAt(0).x();
    QVERIFY(indent2 > indent); // since it takes an extra digit
    for (i = 2; i <= 12; ++i) {
        // qDebug() << "=>" << blok.text();
        QCOMPARE(blok.layout()->lineAt(0).x(), indent2); // all the same indent.
        blok = blok.next();
    }

    // now to make sure the text is actually properly set.
    block = m_doc->begin().next();
    i = 1;
    while (block.isValid() && i < 13) {
        KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
        QVERIFY(data);
        QCOMPARE(data->counterText(), QString::number(i++));
        block = block.next();
    }

    llp.setListItemSuffix(".");
    llp.setStartValue(4);
    listStyle.setLevelProperties(llp);

    QTextCursor cursor(m_doc);
    cursor.setPosition(10); // listItem1
    QTextBlockFormat format = cursor.blockFormat();
    format.setProperty(KoParagraphStyle::ListStartValue, 4);
    cursor.setBlockFormat(format);

    cursor.setPosition(40); // listItem4
    format = cursor.blockFormat();
    format.setProperty(KoParagraphStyle::ListStartValue, 12);
    cursor.setBlockFormat(format);

    // at this point we start numbering at 4. Have 4, 5, 6, 12, 13, 14, 15 etc
    m_layout->layout();

    // now to make sur the text is actually properly set.
    block = m_doc->begin().next();
    i = 4;
    while (block.isValid() && i < 22) {
        if (i == 7) {
            i = 12;
        }
        KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
        QVERIFY(data);
        QCOMPARE(data->counterText(), QString::number(i++));
        block = block.next();
    }
}
コード例 #25
0
ファイル: htmlexporter.cpp プロジェクト: mtux/bilbo
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 />&nbsp;<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;
}
コード例 #26
0
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);
}