[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [Calligra] 44dc689: DOC: Added initial support for the TOC field.
From: Matus Uzak <matus.uzak () ixonos ! com>
Date: 2011-01-11 19:44:01
Message-ID: 20110111194401.C5396A6092 () git ! kde ! org
[Download RAW message or body]
commit 44dc689370083e63e006bef3337bd571fc2c72a2
branch master
Author: Matus Uzak <matus.uzak@ixonos.com>
Date: Tue Jan 11 20:35:34 2011 +0100
DOC: Added initial support for the TOC field.
Added support for the most important instructions of the TOC field.
The text:table-of-content element required to generate a toc is stored
together with text:index-body element containing the toc snapshot
originally created by MS Word.
diff --git a/filters/words/msword-odf/document.cpp \
b/filters/words/msword-odf/document.cpp index 084dc88..0ff2e01 100644
--- a/filters/words/msword-odf/document.cpp
+++ b/filters/words/msword-odf/document.cpp
@@ -340,6 +340,11 @@ void Document::processStyles()
// had in the .doc.
QString actualName = m_mainStyles->insert(userStyle, name, \
KoGenStyles::DontAddNumberToName); kDebug(30513) << "added style " << actualName;
+
+ //save names of TOC related styles
+ if (actualName.contains("TOC")) {
+ m_tocStyleNames.append(actualName);
+ }
} else if (style && style->type() == wvWare::Style::sgcChp) {
//create this style & add formatting info to it
kDebug(30513) << "creating ODT textstyle" << name;
diff --git a/filters/words/msword-odf/document.h \
b/filters/words/msword-odf/document.h index 818310d..cc2d7a2 100644
--- a/filters/words/msword-odf/document.h
+++ b/filters/words/msword-odf/document.h
@@ -136,7 +136,12 @@ public:
/**
* @return the current background-color.
*/
- QString currentBgColor() { return m_bgColors.isEmpty() ? QString() : \
m_bgColors.top(); } + QString currentBgColor(void) { return m_bgColors.isEmpty() ? \
QString() : m_bgColors.top(); } +
+ /**
+ * @return the list of names of TOC related styles.
+ */
+ QList<QString> tocStyleNames(void) { return m_tocStyleNames; }
/**
* Checks if the header/footer content of the current section differs from
@@ -246,6 +251,10 @@ private:
//A stack for backgroud-colors, which represets a background color context
//for automatic colors.
QStack<QString> m_bgColors;
+
+ //A list storing names of TOC related styles required in TextHandler to
+ //process the TOC field.
+ QList<QString> m_tocStyleNames;
};
#endif // DOCUMENT_H
diff --git a/filters/words/msword-odf/texthandler.cpp \
b/filters/words/msword-odf/texthandler.cpp index b1d562a..dc123ea 100644
--- a/filters/words/msword-odf/texthandler.cpp
+++ b/filters/words/msword-odf/texthandler.cpp
@@ -248,7 +248,7 @@ void KWordTextHandler::sectionStart(wvWare::SharedPtr<const \
wvWare::Word97::SEP>
}
}
-}
+} //end sectionStart()
void KWordTextHandler::sectionEnd()
{
@@ -417,7 +417,7 @@ void KWordTextHandler::footnoteFound(wvWare::FootnoteData::Type \
type, // Keep name in sync with Document::startFootnote
// footnoteElem.setAttribute( "frameset", i18n("Footnote %1", \
++m_footNoteNumber ) ); //varElem.appendChild( footnoteElem );
-}
+} //end footnoteFound()
void KWordTextHandler::bookmarkStart( const wvWare::BookmarkData& data )
{
@@ -875,7 +875,7 @@ void KWordTextHandler::paragraphEnd()
//add nested field snippets to this paragraph
if (m_fldStates.empty()) {
- QList<QString>* flds = &fld_snippets;
+ QList<QString>* flds = &m_fld_snippets;
while (!flds->isEmpty()) {
//add writer content to m_paragraph as a runOfText with no text style
m_paragraph->addRunOfText(flds->takeFirst(), 0, QString(""), \
m_parser->styleSheet()); @@ -989,8 +989,7 @@ void KWordTextHandler::fieldStart(const \
wvWare::FLD* fld, wvWare::SharedPtr<cons m_fieldType = UNSUPPORTED;
break;
case TOC:
- kWarning(30513) << "Warning: unsupported field (TOC)";
- m_fieldType = UNSUPPORTED;
+ kDebug(30513) << "processing field... TOC";
break;
case AUTHOR:
case EDITTIME:
@@ -1015,24 +1014,133 @@ void KWordTextHandler::fieldSeparator(const wvWare::FLD* \
/*fld*/, wvWare::Shared {
kDebug(30513) ;
m_fieldAfterSeparator = true;
- QString* str = &m_fldInst;
+ QString* inst = &m_fldInst;
//process field instructions if required
switch (m_fieldType) {
case HYPERLINK:
- str->remove(" HYPERLINK ");
- str->replace('\"', "");
+ inst->remove(" HYPERLINK ");
+ inst->replace('\"', "");
//field-argument which specifies a location in the file, such as
//bookmark, where this hyperlink will jump
- if (str->contains("\\l")) {
- str->remove("\\l");
+ if (inst->contains("\\l")) {
+ inst->remove("\\l");
m_bkmkRefActive = true;
} else {
m_hyperLinkActive = true;
}
- *str = str->trimmed();
+ *inst = inst->trimmed();
break;
+ case TOC:
+ {
+ QList<QString> styleNames = document()->tocStyleNames();
+ *inst = inst->trimmed();
+
+ // TODO:
+ // \a field-argument -
+ // \b field-argument -
+ // \c field-argument -
+ // \d field-argument -
+ // \f field-argument -
+ // \l field-argument -
+ // \s field-argument -
+ // \t field-argument -
+ // \u - Uses the applied paragraph outline level.
+ // \w - Preserves tab entries within table entries.
+ // \x - Preserves newline characters within table entries.
+ // \z - Hides tab leader and page numbers in Web layout view.
+
+ // \h - Makes the table of contents entries hyperlinks.
+ QRegExp rx("\\s\\\\h\\s");
+ bool hyperlink = false;
+
+ if (rx.indexIn(*inst) >= 0) {
+ hyperlink = true;
+ }
+
+ // \n field-argument - Without field-argument, omits page numbers from
+ // the table of contents. Page numbers are omitted from all levels
+ // unless a range of entry levels is specified by text in this switch's
+ // field-argument. A range is specified as for \l.
+ rx = QRegExp("\\s\\\\n\\s");
+ bool pgnum = true;
+
+ if (rx.indexIn(*inst) >= 0) {
+ pgnum = false;
+ }
+
+ // \o field-argument - Uses paragraphs formatted with all or the
+ // specified range of built-in heading styles. Headings in a style
+ // range are specified by text in field-argument. If no heading range
+ // is specified, all heading levels used in the document are listed.
+ rx = QRegExp("^TOC\\s\\\\o\\s\"(\\S+)\"");
+ QStringList levels_lst;
+ uint levels;
+
+ if (rx.indexIn(*inst) >= 0) {
+ levels_lst = rx.cap(1).split("-");
+ levels = levels_lst.last().toUInt();
+ } else {
+ levels = styleNames.size();
+ }
+
+ // \p field-argument - text in this switch's field-argument specifies a
+ // sequence of characters that separate an entry and its page number.
+ // The default is a tab with leader dots.
+ rx = QRegExp("\\s\\\\p\\s\"(\\s)\"");
+ QString separator;
+
+ if (rx.indexIn(*inst) >= 0) {
+ separator = rx.cap(1);
+ }
+
+ //NOTE: text:table-of-content and text:index-body closed by fieldEnd f.
+ KoXmlWriter* writer = currentWriter();
+ writer->startElement("text:table-of-content");
+ writer->addAttribute("text:name", "_TOC0");
+ writer->startElement("text:table-of-content-source");
+ writer->addAttribute("text:index-scope", "document");
+ writer->addAttribute("text:outline-level", levels);
+ writer->addAttribute("text:relative-tab-stop-position", "false");
+ writer->addAttribute("text:use-index-marks", "false");
+ writer->addAttribute("text:use-index-source-styles", "false");
+ writer->addAttribute("text:use-outline-level", "true");
+
+ for (uint i = 0; i < levels; i++) {
+ writer->startElement("text:table-of-content-entry-template");
+ writer->addAttribute("text:outline-level", i + 1);
+ writer->addAttribute("text:style-name", styleNames[i]);
+ if (hyperlink) {
+ writer->startElement("text:index-entry-link-start");
+ writer->endElement(); //text:index-entry-link-start
+ }
+ writer->startElement("text:index-entry-text");
+ writer->endElement(); //text:index-entry-text
+ if (pgnum) {
+ if (separator.isEmpty()) {
+ writer->startElement("text:index-entry-tab-stop");
+ //TODO: not provided in the TOC field, reuse from paragraph
+ //styles used in index-body
+ writer->addAttribute("style:leader-char", ".");
+ //NOTE: "right" is the only option available
+ writer->addAttribute("style:type", "right");
+ writer->endElement(); //text:index-entry-tab-stop
+ }
+ writer->startElement("text:index-entry-page-number");
+ writer->endElement(); //text:index-entry-page-number
+ }
+ if (hyperlink) {
+ writer->startElement("text:index-entry-link-end");
+ writer->endElement(); //text:index-entry-link-end
+ }
+ writer->endElement(); //text:table-of-content-entry-template
+ }
+
+ writer->endElement(); //text:table-of-content-source
+ writer->startElement("text:index-body");
+ break;
+ }
default:
break;
}
@@ -1048,57 +1156,60 @@ void KWordTextHandler::fieldEnd(const wvWare::FLD* /*fld*/, \
wvWare::SharedPtr<co QBuffer buf;
buf.open(QIODevice::WriteOnly);
KoXmlWriter writer(&buf);
- QString* str = &m_fldInst;
+ QString* inst = &m_fldInst;
QString tmp;
switch (m_fieldType) {
case EQ:
+ {
//TODO: nested fields support required
//NOTE: actually combined characters stored as 'equation'
- {
- QRegExp rx("eq \\\\o\\(\\\\s\\\\up 36\\(([^\\)]*)\\),\\\\s\\\\do \
12\\(([^\\)]*)\\)\\)");
- int where = rx.indexIn(*str);
-
- if (where != -1) {
- QString cc = rx.cap(1) + rx.cap(2);
- if (!cc.isEmpty()) {
- m_paragraph->setCombinedCharacters(true);
- m_paragraph->addRunOfText(cc, chp, QString(""), \
m_parser->styleSheet());
- m_paragraph->setCombinedCharacters(false);
- }
+ QRegExp rx("eq \\\\o\\(\\\\s\\\\up 36\\(([^\\)]*)\\),\\\\s\\\\do \
12\\(([^\\)]*)\\)\\)"); + int where = rx.indexIn(*inst);
+
+ if (where != -1) {
+ QString cc = rx.cap(1) + rx.cap(2);
+ if (!cc.isEmpty()) {
+ m_paragraph->setCombinedCharacters(true);
+ m_paragraph->addRunOfText(cc, chp, QString(""), \
m_parser->styleSheet()); + m_paragraph->setCombinedCharacters(false);
}
}
break;
+ }
case HYPERLINK:
if (m_hyperLinkActive) {
writer.startElement("text:a", false);
writer.addAttribute("xlink:type", "simple");
- writer.addAttribute("xlink:href", QUrl(*str).toEncoded());
+ writer.addAttribute("xlink:href", QUrl(*inst).toEncoded());
writer.startElement("text:span");
writer.addAttribute("text:style-name", m_fldStyleName.toUtf8());
writer.addCompleteElement(m_fldBuffer);
- writer.endElement();
- writer.endElement();
+ writer.endElement(); //text:span
+ writer.endElement(); //text:a
}
else if (m_bkmkRefActive) {
writer.startElement("text:bookmark-ref", false);
writer.addAttribute("text:reference-format","text");
- writer.addAttribute("text:ref-name", *str);
+ writer.addAttribute("text:ref-name", *inst);
+ writer.startElement("text:span");
+ writer.addAttribute("text:style-name", m_fldStyleName.toUtf8());
writer.addCompleteElement(m_fldBuffer);
- writer.endElement();
+ writer.endElement(); //text:span
+ writer.endElement(); //text:a
}
//else a frame or drawing shape acting as a hyperlink already processed
break;
case MACROBUTTON:
+ {
//TODO: nested fields support required
- {
- QRegExp rx("MACROBUTTON\\s\\s?\\w+\\s\\s?(.+)$");
- *str = str->trimmed();
- if (rx.indexIn(*str) >= 0) {
- m_paragraph->addRunOfText(rx.cap(1), chp, QString(""), \
m_parser->styleSheet());
- }
+ QRegExp rx("MACROBUTTON\\s\\s?\\w+\\s\\s?(.+)$");
+ *inst = inst->trimmed();
+ if (rx.indexIn(*inst) >= 0) {
+ m_paragraph->addRunOfText(rx.cap(1), chp, QString(""), \
m_parser->styleSheet()); }
break;
+ }
case NUMPAGES:
writer.startElement("text:page-count");
writer.endElement();
@@ -1110,62 +1221,72 @@ void KWordTextHandler::fieldEnd(const wvWare::FLD* /*fld*/, \
wvWare::SharedPtr<co break;
case PAGEREF:
//NOTE: reference-format can be: chapter, direction, page, text
- if (str->contains("PAGEREF")) {
- str->remove("PAGEREF");
+ if (inst->contains("PAGEREF")) {
+ inst->remove("PAGEREF");
}
//we should create a hyperlink to the bookmarked paragraph
- if (str->contains("\\h")) {
- str->remove("\\h");
+ if (inst->contains("\\h")) {
+ inst->remove("\\h");
tmp = "text";
} else {
tmp = "page";
}
- *str = str->trimmed();
+ *inst = inst->trimmed();
writer.startElement("text:bookmark-ref");
writer.addAttribute("text:reference-format", tmp);
- writer.addAttribute("text:ref-name", *str);
+ writer.addAttribute("text:ref-name", *inst);
writer.addTextNode(m_fldResult);
writer.endElement();
break;
case SYMBOL:
+ {
//TODO: nested fields support required
- {
- QRegExp rx_txt("SYMBOL\\s{2}(\\S+)\\s+.+$");
- QString txt;
- *str = str->trimmed();
-
- //check for text in field instructions
- if (rx_txt.indexIn(*str) >= 0) {
- txt = rx_txt.cap(1);
-
- //ascii code
- if (str->contains("\\a")) {
- QRegExp rx16("0\\D.+");
- bool ok = false;
- int n;
-
- if (rx16.indexIn(txt) >= 0) {
- n = txt.toInt(&ok, 16);
- }
- else {
- n = txt.toInt(&ok, 10);
- }
- if (ok) {
- tmp.append((char) n);
- }
+ QRegExp rx_txt("SYMBOL\\s{2}(\\S+)\\s+.+$");
+ QString txt;
+ *inst = inst->trimmed();
+
+ //check for text in field instructions
+ if (rx_txt.indexIn(*inst) >= 0) {
+ txt = rx_txt.cap(1);
+
+ //ascii code
+ if (inst->contains("\\a")) {
+ QRegExp rx16("0\\D.+");
+ bool ok = false;
+ int n;
+
+ if (rx16.indexIn(txt) >= 0) {
+ n = txt.toInt(&ok, 16);
+ } else {
+ n = txt.toInt(&ok, 10);
}
- //unicode
- if (str->contains("\\u")) {
- qDebug() << "Warning: unicode symbols not supported!";
+ if (ok) {
+ tmp.append((char) n);
}
}
- //default value (check the corresponding test)
- if (tmp.isEmpty()) {
- tmp = "###";
+ //unicode
+ if (inst->contains("\\u")) {
+ qDebug() << "Warning: unicode symbols not supported!";
}
- m_paragraph->addRunOfText(tmp, chp, QString(""), \
m_parser->styleSheet()); }
+ //default value (check the corresponding test)
+ if (tmp.isEmpty()) {
+ tmp = "###";
+ }
+ m_paragraph->addRunOfText(tmp, chp, QString(""), m_parser->styleSheet());
+ break;
+ }
+ case TOC:
+ {
+ //NOTE: Nested fields had been processed and wrote into content.xml by
+ //the writeToFile function. The m_fldStates stack should be empty.
+ Q_ASSERT(m_fldStates.empty());
+
+ KoXmlWriter* out_writer = currentWriter();
+ out_writer->endElement(); //text:index-body
+ out_writer->endElement(); //text:table-of-content
break;
+ }
default:
break;
}
@@ -1173,7 +1294,7 @@ void KWordTextHandler::fieldEnd(const wvWare::FLD* /*fld*/, \
wvWare::SharedPtr<co if (!contents.isEmpty()) {
//nested field
if (!m_fldStates.empty()) {
- fld_snippets.prepend(contents);
+ m_fld_snippets.prepend(contents);
} else {
//add writer content to m_paragraph as a runOfText with no text style
m_paragraph->addRunOfText(contents, 0, QString(""), \
m_parser->styleSheet()); @@ -1203,7 +1324,7 @@ void KWordTextHandler::fieldEnd(const \
wvWare::FLD* /*fld*/, wvWare::SharedPtr<co if (!m_fldStates.empty()) {
fld_restoreState();
} else {
- QList<QString>* list = &fld_snippets;
+ QList<QString>* list = &m_fld_snippets;
while (!list->isEmpty()) {
//add writer content to m_paragraph as a runOfText with no text style
m_paragraph->addRunOfText(list->takeFirst(), 0, QString(""), \
m_parser->styleSheet()); @@ -1232,6 +1353,7 @@ void KWordTextHandler::runOfText(const \
wvWare::UString& text, wvWare::SharedPtr< case MACROBUTTON:
case PAGEREF:
case SYMBOL:
+ case TOC:
m_fldInst.append(newText);
break;
default:
@@ -1261,6 +1383,7 @@ void KWordTextHandler::runOfText(const wvWare::UString& text, \
wvWare::SharedPtr< case MERGEFIELD:
case SHAPE:
case TITLE:
+ case TOC:
//Ignoring any nested fields around the result!
kDebug(30513) << "Processing field result as common text string.";
common_flag = true;
@@ -1271,6 +1394,9 @@ void KWordTextHandler::runOfText(const wvWare::UString& text, \
wvWare::SharedPtr< }
}
if (!common_flag) {
+ //TODO: This is a temporary solution in which we ignore a lot of
+ //styles related information. Reuse the addRunOfText function.
+
//create a style for the <text:span> element (if applicable)
if (m_fldStyleName.isEmpty()) {
m_fldStyleName = m_paragraph->createTextStyle(chp, \
m_parser->styleSheet()); @@ -1450,7 +1576,7 @@ bool \
KWordTextHandler::writeListInfo(KoXmlWriter* writer, const wvWare::Word97:: \
writer->startElement("text:list-item");
return true;
-} //writeListInfo()
+} //end writeListInfo()
QString KWordTextHandler::createBulletStyle(const QString& textStyleName) const
@@ -1703,7 +1829,7 @@ void KWordTextHandler::updateListStyle(const QString& \
textStyleName) //we'll add each one with a unique name
QString name("listlevels");
listStyle->addChildElement(name.append(QString::number(pap.ilvl)), contents);
-} //setListStyle
+} //end updateListStyle()
void KWordTextHandler::closeList()
{
diff --git a/filters/words/msword-odf/texthandler.h \
b/filters/words/msword-odf/texthandler.h index f0715c9..db22ae0 100644
--- a/filters/words/msword-odf/texthandler.h
+++ b/filters/words/msword-odf/texthandler.h
@@ -286,7 +286,7 @@ private:
void fld_restoreState();
//storage for XML snippets of already processed fields
- QList<QString> fld_snippets;
+ QList<QString> m_fld_snippets;
//field type enumeration as defined in MS-DOC page 354/609
enum fldType
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic