filters

ImportFormatting.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001, 2002, 2004 Nicolas GOUTTE <goutte@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <kdebug.h>
21
22#include "ImportFormatting.h"
23#include "ImportStyle.h"
24
25StackItem::StackItem() : fontSize(0), /* No explicit font size */
26 pos(0), italic(false), bold(false), underline(false), strikeout(false),
27 textPosition(0)
28{
29}
30
31StackItem::~StackItem()
32{
33}
34
35void PopulateProperties(StackItem* stackItem, const TQString& strStyleProps,
36 const TQXmlAttributes& attributes, AbiPropsMap& abiPropsMap,
37 const bool allowInit)
38// TODO: find a better name for this function
39{
40 if (allowInit)
41 {
42 // Initialize the TQStrings with the previous values of the properties
43 // TODO: any others needed?
44 if (stackItem->italic)
45 {
46 abiPropsMap.setProperty("font-style","italic");
47 }
48 if (stackItem->bold)
49 {
50 abiPropsMap.setProperty("font-weight","bold");
51 }
52
53 if (stackItem->underline)
54 {
55 abiPropsMap.setProperty("text-decoration","underline");
56 }
57 else if (stackItem->strikeout)
58 {
59 abiPropsMap.setProperty("text-decoration","line-through");
60 }
61 }
62
63 // Style goes first
64 kdDebug(30506)<< "===== from style=\"" << strStyleProps << "\"" << endl;
65 abiPropsMap.splitAndAddAbiProps(strStyleProps);
66 // Treat the props attributes in the two available flavors: lower case and upper case.
67 kdDebug(30506)<< "========== props=\"" << attributes.value("props") << "\"" << endl;
68 abiPropsMap.splitAndAddAbiProps(attributes.value("props"));
69 abiPropsMap.splitAndAddAbiProps(attributes.value("PROPS")); // PROPS is deprecated
70
71 stackItem->italic=(abiPropsMap["font-style"].getValue()=="italic");
72 stackItem->bold=(abiPropsMap["font-weight"].getValue()=="bold");
73
74 TQString strDecoration=abiPropsMap["text-decoration"].getValue();
75 stackItem->underline=(strDecoration=="underline");
76 stackItem->strikeout=(strDecoration=="line-through");
77
78 TQString strTextPosition=abiPropsMap["text-position"].getValue();
79 if (strTextPosition=="subscript")
80 {
81 stackItem->textPosition=1;
82 }
83 else if (strTextPosition=="superscript")
84 {
85 stackItem->textPosition=2;
86 }
87 else if (!strTextPosition.isEmpty())
88 {
89 // we have any other new value, assume it means normal!
90 stackItem->textPosition=0;
91 }
92
93 TQString strColour=abiPropsMap["color"].getValue();
94 if (!strColour.isEmpty())
95 {
96 // The colour information is *not* lead by a hash (#)
97 stackItem->fgColor.setNamedColor("#"+strColour);
98 }
99
100 TQString strBackgroundTextColor=abiPropsMap["bgcolor"].getValue();
101 if (strBackgroundTextColor=="transparent")
102 {
103 // KWord has no idea what transparency is, so we use white
104 stackItem->bgColor.setRgb(255,255,255);
105 }
106 else if(!strBackgroundTextColor.isEmpty())
107 {
108 // The colour information is *not* lead by a hash (#)
109 stackItem->bgColor.setNamedColor("#"+strBackgroundTextColor);
110 }
111
112 TQString strFontSize=abiPropsMap["font-size"].getValue();
113 if (!strFontSize.isEmpty())
114 {
115 const int size=int(ValueWithLengthUnit(strFontSize));
116 if (size>0)
117 {
118 stackItem->fontSize=size;
119 }
120 }
121
122 TQString strFontFamily=abiPropsMap["font-family"].getValue();
123 if (!strFontFamily.isEmpty() && (strFontFamily!="(null)"))
124 {
125 // TODO: transform the font-family in a font that we have on the system on which KWord runs.
126 stackItem->fontName=strFontFamily;
127 }
128}
129
130void AddFormat(TQDomElement& formatElementOut, StackItem* stackItem, TQDomDocument& mainDocument)
131{
132 TQDomElement element;
133 if (!stackItem->fontName.isEmpty())
134 {
135 element=mainDocument.createElement("FONT");
136 element.setAttribute("name",stackItem->fontName); // Font name
137 formatElementOut.appendChild(element); //Append to <FORMAT>
138 }
139
140 if (stackItem->fontSize>0)
141 {
142 element=mainDocument.createElement("SIZE");
143 element.setAttribute("value",stackItem->fontSize);
144 formatElementOut.appendChild(element); //Append to <FORMAT>
145 }
146
147 element=mainDocument.createElement("ITALIC");
148 element.setAttribute("value",stackItem->italic?1:0);
149 formatElementOut.appendChild(element); //Append to <FORMAT>
150
151 element=mainDocument.createElement("WEIGHT");
152 element.setAttribute("value",stackItem->bold?75:50);
153 formatElementOut.appendChild(element); //Append to <FORMAT>
154
155 element=mainDocument.createElement("UNDERLINE");
156 element.setAttribute("value",stackItem->underline?1:0);
157 formatElementOut.appendChild(element); //Append to <FORMAT>
158
159 element=mainDocument.createElement("STRIKEOUT");
160 element.setAttribute("value",stackItem->strikeout?1:0);
161 formatElementOut.appendChild(element); //Append to <FORMAT>
162
163 if ((stackItem->textPosition>=0) && (stackItem->textPosition<=2))
164 {
165 element=mainDocument.createElement("VERTALIGN");
166 element.setAttribute("value",stackItem->textPosition);
167 formatElementOut.appendChild(element); //Append to <FORMAT>
168 }
169
170 if (stackItem->fgColor.isValid())
171 {
172 element=mainDocument.createElement("COLOR");
173 element.setAttribute("red", stackItem->fgColor.red());
174 element.setAttribute("green",stackItem->fgColor.green());
175 element.setAttribute("blue", stackItem->fgColor.blue());
176 formatElementOut.appendChild(element); //Append to <FORMAT>
177 }
178
179 if (stackItem->bgColor.isValid())
180 {
181 element=mainDocument.createElement("TEXTBACKGROUNDCOLOR");
182 element.setAttribute("red", stackItem->bgColor.red());
183 element.setAttribute("green",stackItem->bgColor.green());
184 element.setAttribute("blue", stackItem->bgColor.blue());
185 formatElementOut.appendChild(element); //Append to <FORMAT>
186 }
187}
188
189void AddLayout(const TQString& strStyleName, TQDomElement& layoutElement,
190 StackItem* stackItem, TQDomDocument& mainDocument,
191 const AbiPropsMap& abiPropsMap, const int level, const bool isStyle)
192{
193 TQDomElement element;
194 element=mainDocument.createElement("NAME");
195 element.setAttribute("value",strStyleName);
196 layoutElement.appendChild(element);
197
198 TQString strFollowing=abiPropsMap["followedby"].getValue();
199 TQDomElement followingElement=mainDocument.createElement("FOLLOWING");
200 followingElement.setAttribute("name",strFollowing);
201 if ((strFollowing.isEmpty())
202 || (strFollowing=="Current Settings")) // "Current Settings" is only a pseudo-style!
203 {
204 // We have no idea what style follows
205 if (isStyle)
206 {
207 // We are a style, so we need a default
208 followingElement.setAttribute("name","Normal");
209 layoutElement.appendChild(followingElement);
210 }
211 // Else: we are a layout, so we leave the work to KWord (from the style)
212 }
213 else
214 {
215 // Following style is defined
216 // TODO: we should be sure that this style is defined!
217 layoutElement.appendChild(followingElement);
218 }
219
220 TQString strFlow=abiPropsMap["text-align"].getValue();
221 element=mainDocument.createElement("FLOW");
222 if ((strFlow=="left") || (strFlow=="center") || (strFlow=="right") || (strFlow=="justify"))
223 {
224 element.setAttribute("align",strFlow);
225 }
226 else
227 {
228 element.setAttribute("align","left");
229 }
230 layoutElement.appendChild(element);
231
232 int kwordDepth;
233 int kwordNumberingType;
234 int kwordType;
235 TQString kwordRightText;
236 // level is 1 based like AbiWord, any value lower than 1 means no level!
237 if ((level<=0) || (level>=15))
238 {
239 kwordDepth=0;
240 kwordNumberingType=2;
241 kwordType=0;
242 }
243 else
244 {
245 kwordDepth=level-1;
246 kwordNumberingType=1;
247 kwordType=1; // PROVISORY
248 kwordRightText=".";
249 }
250
251 element=mainDocument.createElement("COUNTER");
252 element.setAttribute("type",kwordType);
253 element.setAttribute("depth",kwordDepth);
254 element.setAttribute("start",1);
255 element.setAttribute("numberingtype",kwordNumberingType);
256 element.setAttribute("lefttext","");
257 element.setAttribute("righttext",kwordRightText);
258 element.setAttribute("bullet",64);
259 element.setAttribute("bulletfont","Symbol");
260 element.setAttribute("customdef","");
261 layoutElement.appendChild(element);
262
263 TQString strLeftMargin=abiPropsMap["margin-left"].getValue();
264 TQString strRightMargin=abiPropsMap["margin-right"].getValue();
265 TQString strTextIndent=abiPropsMap["text-indent"].getValue();
266
267 if ( !strLeftMargin.isEmpty()
268 || !strRightMargin.isEmpty()
269 || !strTextIndent.isEmpty() )
270 {
271 element=mainDocument.createElement("INDENTS");
272 if (!strLeftMargin.isEmpty())
273 element.setAttribute("left",ValueWithLengthUnit(strLeftMargin));
274 if (!strRightMargin.isEmpty())
275 element.setAttribute("right",ValueWithLengthUnit(strRightMargin));
276 if (!strTextIndent.isEmpty())
277 element.setAttribute("first",ValueWithLengthUnit(strTextIndent));
278 layoutElement.appendChild(element);
279 }
280
281 TQString strTopMargin=abiPropsMap["margin-top"].getValue();
282 TQString strBottomMargin=abiPropsMap["margin-bottom"].getValue();
283 if (!strTopMargin.isEmpty() || !strBottomMargin.isEmpty() )
284 {
285 element=mainDocument.createElement("OFFSETS");
286 const double margin_top=ValueWithLengthUnit(strTopMargin);
287 const double margin_bottom=ValueWithLengthUnit(strBottomMargin);
288 // Zero is propably a valid value!
289 if (!strBottomMargin.isEmpty())
290 element.setAttribute("after",margin_bottom);
291 if (!strTopMargin.isEmpty())
292 element.setAttribute("before",margin_top);
293 layoutElement.appendChild(element);
294 }
295
296 TQString strLineHeight=abiPropsMap["line-height"].getValue();
297 if(!strLineHeight.isEmpty())
298 {
299 element=mainDocument.createElement("LINESPACING");
300 double lineHeight;
301 // Do we have a unit symbol or not?
302 bool flag=false;
303 lineHeight=strLineHeight.toDouble(&flag);
304
305 if (flag)
306 {
307 if ( lineHeight == 1.0 )
308 {
309 element.setAttribute( "value", "single" );
310 element.setAttribute( "type", "single" );
311 }
312 else if (lineHeight==1.5)
313 {
314 element.setAttribute( "value", "oneandhalf" );
315 element.setAttribute( "type", "oneandhalf" );
316 }
317 else if (lineHeight==2.0)
318 {
319 element.setAttribute( "value", "double" );
320 element.setAttribute( "type", "double" );
321 }
322 else if ( lineHeight > 0.0 )
323 {
324 element.setAttribute( "type", "multiple" );
325 element.setAttribute( "spacingvalue", lineHeight );
326 }
327 else
328 {
329 kdWarning(30506) << "Unsupported line height " << lineHeight << " (Ignoring !)" << endl;
330 }
331 }
332 else
333 {
334 // Something went wrong, so we assume that an unit is specified
335 bool atleast = false;
336 lineHeight = ValueWithLengthUnit( strLineHeight, &atleast );
337 if (lineHeight>1.0)
338 {
339 if ( atleast )
340 {
341 kdDebug(30506) << "at-least" << endl;
342 element.setAttribute( "type", "atleast" );
343 }
344 else
345 {
346 element.setAttribute( "type", "exact" );
347 }
348
349 // We have a meaningful value, so use it!
350 //element.setAttribute( "value", lineHeight );
351 element.setAttribute( "spacingvalue", lineHeight );
352 }
353 }
354 layoutElement.appendChild(element);
355 }
356
357 TQString strTab=abiPropsMap["tabstops"].getValue();
358 if(!strTab.isEmpty())
359 {
360 TQStringList listTab=TQStringList::split(",",strTab);
361 for ( TQStringList::Iterator it = listTab.begin(); it != listTab.end(); ++it )
362 {
363 TQStringList tab=TQStringList::split("/",*it);
364 const TQChar tabType=tab[1].at(0);
365 const TQChar tabFilling=tab[1].at(1); // Might be empty in old AbiWord files
366 int type;
367 if (tabType=='L') // left
368 type=0;
369 else if (tabType=='C') // center
370 type=1;
371 else if (tabType=='R') // right
372 type=2;
373 else if(tabType=='D') // decimal
374 type=3;
375 else if(tabType=='B') // bar (unsupported by KWord)
376 type=0;
377 else
378 {
379 kdWarning(30506)<<"Unknown tabulator type: " << TQString(tabType) << endl;
380 type=0;
381 }
382 int filling;
383 int width=72; // Any non-null value
384 if (tabFilling.isNull() || tabFilling=='0') // No filling
385 filling=0;
386 else if (tabFilling=='1') // dot
387 {
388 filling=1;
389 width=2; // TODO: which width?
390 }
391 else if (tabFilling=='3') // underline
392 filling=2;
393 else
394 filling=0;
395 element=mainDocument.createElement("TABULATOR");
396 element.setAttribute("ptpos",ValueWithLengthUnit(tab[0]));
397 element.setAttribute("type",type);
398 element.setAttribute("filling",filling);
399 element.setAttribute("width",width);
400 layoutElement.appendChild(element);
401 }
402 }
403
404 TQDomElement formatElementOut=mainDocument.createElement("FORMAT");
405 layoutElement.appendChild(formatElementOut);
406
407 AddFormat(formatElementOut, stackItem, mainDocument);
408}
409
410void AddStyle(TQDomElement& styleElement, const TQString& strStyleName,
411 const StyleData& styleData, TQDomDocument& mainDocument)
412{
413 // NOTE; styleElement is <STYLE> (singular), not <STYLES> (plural)
414
415 StackItem stackItem;
416 TQXmlAttributes attributes; // This is just a dummy for reusing already existing functions (TODO)
417 AbiPropsMap abiPropsMap;
418
419 PopulateProperties(&stackItem, styleData.m_props, attributes, abiPropsMap, false);
420 AddLayout(strStyleName, styleElement, &stackItem, mainDocument, abiPropsMap, styleData.m_level, true);
421}