1 /* This file is part of the KDE project
2 * Copyright (C) 2006 Thomas Zander <zander@kde.org>
3 * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
4 * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
5 * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
6 * Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com>
7 * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
8 * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26 #include "KoTextWriter.h"
27
28 #include <KoTextWriter_p.h>
29 #include <KoStyleManager.h>
30 #include <KoParagraphStyle.h>
31 #include <KoTextDocument.h>
32 #include <KoShapeSavingContext.h>
33 #include <KoGenStyles.h>
34 #include <opendocument/KoTextSharedSavingData.h>
35
36 #include <QTextList>
37 #include <QTextTableCell>
38
39 #include "TextDebug.h"
40
KoTextWriter(KoShapeSavingContext & context,KoDocumentRdfBase * rdfData)41 KoTextWriter::KoTextWriter(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData)
42 : d(new Private(context))
43 {
44 d->rdfData = rdfData;
45 KoSharedSavingData *sharedData = context.sharedData(KOTEXT_SHARED_SAVING_ID);
46 if (sharedData) {
47 d->sharedData = dynamic_cast<KoTextSharedSavingData *>(sharedData);
48 }
49
50 if (!d->sharedData) {
51 d->sharedData = new KoTextSharedSavingData();
52 if (!sharedData) {
53 context.addSharedData(KOTEXT_SHARED_SAVING_ID, d->sharedData);
54 } else {
55 warnText << "A different type of sharedData was found under the" << KOTEXT_SHARED_SAVING_ID;
56 Q_ASSERT(false);
57 }
58 }
59 }
60
~KoTextWriter()61 KoTextWriter::~KoTextWriter()
62 {
63 delete d;
64 }
65
saveOdf(KoShapeSavingContext & context,KoDocumentRdfBase * rdfData,QTextDocument * document,int from,int to)66 void KoTextWriter::saveOdf(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData, QTextDocument *document, int from, int to)
67 {
68 KoTextWriter writer(context, rdfData);
69 writer.write(document, from, to);
70 }
71
saveParagraphStyle(const QTextBlock & block,KoStyleManager * styleManager,KoShapeSavingContext & context)72 QString KoTextWriter::saveParagraphStyle(const QTextBlock &block, KoStyleManager *styleManager, KoShapeSavingContext &context)
73 {
74 QTextBlockFormat blockFormat = block.blockFormat();
75 QTextCharFormat charFormat = QTextCursor(block).blockCharFormat();
76 return saveParagraphStyle(blockFormat, charFormat, styleManager, context);
77 }
78
saveParagraphStyle(const QTextBlockFormat & blockFormat,const QTextCharFormat & charFormat,KoStyleManager * styleManager,KoShapeSavingContext & context)79 QString KoTextWriter::saveParagraphStyle(const QTextBlockFormat &blockFormat, const QTextCharFormat &charFormat, KoStyleManager * styleManager, KoShapeSavingContext &context)
80 {
81 KoParagraphStyle *defaultParagraphStyle = styleManager->defaultParagraphStyle();
82 KoParagraphStyle *originalParagraphStyle = styleManager->paragraphStyle(blockFormat.intProperty(KoParagraphStyle::StyleId));
83 if (!originalParagraphStyle)
84 originalParagraphStyle = defaultParagraphStyle;
85
86 QString generatedName;
87 QString displayName = originalParagraphStyle->name();
88 QString internalName = QString(QUrl::toPercentEncoding(displayName, "", " ")).replace('%', '_');
89
90 // we'll convert the blockFormat to a KoParagraphStyle to check for local changes.
91 KoParagraphStyle paragStyle(blockFormat, charFormat);
92 if (paragStyle == (*originalParagraphStyle)) { // This is the real, unmodified character style.
93 // TODO zachmann: this could use the name of the saved style without saving it again
94 // therefore we would need to store that information in the saving context
95 if (originalParagraphStyle != defaultParagraphStyle) {
96 KoGenStyle style(KoGenStyle::ParagraphStyle, "paragraph");
97 originalParagraphStyle->saveOdf(style, context);
98 generatedName = context.mainStyles().insert(style, internalName, KoGenStyles::DontAddNumberToName);
99 }
100 } else { // There are manual changes... We'll have to store them then
101 KoGenStyle style(KoGenStyle::ParagraphAutoStyle, "paragraph", internalName);
102 if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml))
103 style.setAutoStyleInStylesDotXml(true);
104 if (originalParagraphStyle) {
105 paragStyle.removeDuplicates(*originalParagraphStyle);
106 paragStyle.setParentStyle(originalParagraphStyle);
107 }
108 paragStyle.saveOdf(style, context);
109 generatedName = context.mainStyles().insert(style, "P");
110 }
111 return generatedName;
112 }
113
write(const QTextDocument * document,int from,int to)114 void KoTextWriter::write(const QTextDocument *document, int from, int to)
115 {
116 d->document = const_cast<QTextDocument*>(document);
117 d->styleManager = KoTextDocument(document).styleManager();
118
119 QTextBlock fromblock = document->findBlock(from);
120 QTextBlock toblock = document->findBlock(to);
121
122 QTextCursor fromcursor(fromblock);
123
124 QTextList *currentList = fromcursor.currentList();
125
126 // NOTE even better would be if we create a new list out of multiple selected
127 // listitems that contain only the selected items. But following
128 // at least enables copying a whole list while still being able to copy/paste
129 // only parts of the text within a list (see also bug 275990).
130 // NOTE this has been fixed for tables now, and it looks like the list code is seriously wrong
131 // not just like the table code was, but more fundamentally as lists in qt is an orthogonal concept
132 if (currentList) {
133 if (from == 0 && to < 0) {
134 // save everything means also save current table and list
135 currentList = 0;
136 } else {
137 QTextCursor toCursor(toblock);
138 toCursor.setPosition(to, QTextCursor::KeepAnchor);
139
140 if (!fromcursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor)) {
141 fromcursor = QTextCursor();
142 }
143 if (!toCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor)) {
144 toCursor = QTextCursor();
145 }
146
147 // save the whole list if all list-items are selected
148 int fromindex = currentList->itemNumber(fromblock);
149 int toindex = currentList->itemNumber(toblock);
150 if ((fromcursor.isNull() || fromcursor.currentList() != currentList) &&
151 (toCursor.isNull() || toCursor.currentList() != currentList) &&
152 fromindex <= 0 && (toindex < 0 || toindex == currentList->count()-1)
153 ) {
154 currentList = 0;
155 }
156 }
157 }
158
159 QHash<QTextList *, QString> listStyles = d->saveListStyles(fromblock, to);
160 d->globalFrom = from;
161 d->globalTo = to;
162 d->writeBlocks(const_cast<QTextDocument *>(document), from, to, listStyles, 0, currentList);
163 }
164