filters

kprkword.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001 David Faure <faure@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 <config.h>
21
22#include <kgenericfactory.h>
23#include <KoStoreDevice.h>
24#include <KoFilterChain.h>
25#include <KoGlobal.h>
26#include <kprkword.h>
27#include <tdelocale.h>
28#include <kdebug.h>
29#include <tqsortedlist.h>
30#include <tqcolor.h>
31
32typedef KGenericFactory<KprKword, KoFilter> KprKwordFactory;
33K_EXPORT_COMPONENT_FACTORY( libkprkword, KprKwordFactory( "kofficefilters" ) )
34
35KprKword::KprKword(KoFilter *, const char *, const TQStringList&) :
36 KoFilter(),
37 outdoc( "DOC" )
38{
39}
40
41// This filter can act as an import filter for KWord and as an export
42// filter for KPresenter (isn't our architecture really nice ? :)
43// This is why we use the file-to-file method, not a TQDomDoc one.
44KoFilter::ConversionStatus KprKword::convert( const TQCString& from, const TQCString& to )
45{
46 if(to!="application/x-kword" || from!="application/x-kpresenter")
47 return KoFilter::NotImplemented;
48
49 KoStoreDevice* inpdev = m_chain->storageFile( "root", KoStore::Read );
50 if ( !inpdev )
51 {
52 kdError(30502) << "Unable to open input stream" << endl;
53 return KoFilter::StorageCreationError;
54 }
55
56 inpdoc.setContent( inpdev );
57
58
59 outdoc.appendChild( outdoc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
60 TQDomElement kwdoc = outdoc.createElement( "DOC" );
61 kwdoc.setAttribute( "editor", "KprKword converter" );
62 kwdoc.setAttribute( "mime", "application/x-kword" );
63 kwdoc.setAttribute( "syntaxVersion", 1 );
64 outdoc.appendChild( kwdoc );
65
66 TQDomElement paper = outdoc.createElement( "PAPER" );
67 kwdoc.appendChild( paper );
68 paper.setAttribute( "format", 1 ); // A4. How on earth could I know what the user really wants ? :)
69 paper.setAttribute( "width", 595 );
70 paper.setAttribute( "height", 841 );
71 TQDomElement borders = outdoc.createElement( "PAPERBORDERS" );
72 paper.appendChild( borders );
73 borders.setAttribute( "left", 28 );
74 borders.setAttribute( "top", 42 );
75 borders.setAttribute( "right", 28 );
76 borders.setAttribute( "bottom", 42 );
77
78 TQDomElement framesets = outdoc.createElement( "FRAMESETS" );
79 kwdoc.appendChild( framesets );
80
81 frameset = outdoc.createElement( "FRAMESET" );
82 framesets.appendChild( frameset );
83 frameset.setAttribute( "frameType", 1 ); // text
84 frameset.setAttribute( "frameInfo", 0 ); // body
85 TQDomElement frame = outdoc.createElement( "FRAME" );
86 frameset.appendChild( frame );
87 frame.setAttribute( "left", 28 );
88 frame.setAttribute( "top", 42 );
89 frame.setAttribute( "right", 566 );
90 frame.setAttribute( "bottom", 798 );
91 frame.setAttribute( "autoCreateNewFrame", 1 );
92 frame.setAttribute( "newFrameBehaviour", 0 );
93
94 titleStyleName = i18n("Slide Title");
95
96 // Convert !
97
98 convert();
99
100 // Create a style for the slide titles
101
102 TQDomElement styles = outdoc.createElement( "STYLES" );
103 kwdoc.appendChild( styles );
104
105 TQDomElement style = outdoc.createElement( "STYLE" );
106 styles.appendChild( style );
107 TQDomElement elem = outdoc.createElement( "NAME" );
108 style.appendChild( elem );
109 elem.setAttribute( "value", titleStyleName );
110 elem = outdoc.createElement( "FOLLOWING" );
111 style.appendChild( elem );
112 elem.setAttribute( "name", "Standard" ); // no i18n here!
113
114 TQDomElement counter = outdoc.createElement( "COUNTER" );
115 style.appendChild( counter );
116 counter.setAttribute( "type", 1 ); // numbered
117 counter.setAttribute( "depth", 0 );
118 counter.setAttribute( "start", 1 );
119 counter.setAttribute( "numberingtype", 1 ); // chapter
120 counter.setAttribute( "righttext", "." );
121
122 TQDomElement format = outdoc.createElement( "FORMAT" );
123 style.appendChild( format );
124 TQDomElement font = outdoc.createElement( "FONT" );
125 format.appendChild( font );
126 font.setAttribute( "name", titleFont ); // found when reading the first title
127 TQDomElement size = outdoc.createElement( "SIZE" );
128 format.appendChild( size );
129 size.setAttribute( "value", 24 );
130 TQDomElement bold = outdoc.createElement( "WEIGHT" );
131 format.appendChild( bold );
132 bold.setAttribute( "value", 75 );
133
134 // Create the standard style
135 style = outdoc.createElement( "STYLE" );
136 styles.appendChild( style );
137 elem = outdoc.createElement( "NAME" );
138 style.appendChild( elem );
139 elem.setAttribute( "value", "Standard" ); // no i18n here!
140 format = outdoc.createElement( "FORMAT" );
141 style.appendChild( format ); // empty format == use defaults
142
143 // Write output file
144
145 KoStoreDevice* out = m_chain->storageFile( "root", KoStore::Write );
146 if(!out) {
147 kdError(30502) << "Unable to open output file!" << endl;
148 return KoFilter::StorageCreationError;
149 }
150 TQCString cstring = outdoc.toCString(); // utf-8 already
151 out->writeBlock( cstring.data(), cstring.length() );
152 return KoFilter::OK;
153}
154
155// This class is used to sort the objects by y position
156class KprObject {
157 public:
158 double y;
159 TQDomElement elem;
160 bool operator < ( const KprObject & c ) const
161 {
162 return y < c.y;
163 }
164 bool operator == ( const KprObject & c ) const
165 {
166 return y == c.y;
167 }
168};
169
170void KprKword::convert()
171{
172 TQDomElement docElem = inpdoc.documentElement();
173 TQDomElement paper = docElem.namedItem( "PAPER" ).toElement();
174 int ptPageHeight = paper.attribute( "ptHeight" ).toInt();
175
176 TQDomElement objects = docElem.namedItem( "OBJECTS" ).toElement();
177 if ( objects.isNull() )
178 return;
179
180 TQSortedList< KprObject > objList;
181 objList.setAutoDelete( true );
182
183 TQDomNodeList lst = objects.elementsByTagName( "OBJECT" );
184 uint lstcount = lst.count();
185 for ( uint item = 0 ; item < lstcount ; ++item )
186 {
187 TQDomElement object = lst.item( item ).toElement();
188 if ( object.attribute( "type" ).toInt() == 4 ) // we only care about text objs
189 {
190 TQDomElement orig = object.namedItem( "ORIG" ).toElement();
191 if ( !orig.isNull() )
192 {
193 KprObject * obj = new KprObject;
194 obj->y = orig.attribute( "y" ).toDouble();
195 obj->elem = object;
196 objList.inSort( obj );
197 }
198 }
199 }
200
201 int curPage = -1;
202 //kdDebug() << "found " << objList.count() << " objects" << endl;
203
204 for ( TQPtrListIterator<KprObject> it(objList); it.current(); ++it )
205 {
206 TQDomElement elem = it.current()->elem;
207 // Detect the first object of each page
208 int page = int( it.current()->y / ptPageHeight );
209 bool isTitle = ( page > curPage );
210 //kdDebug() << "KprKword::convert y=" << it.current()->y << " ptPageHeight=" << ptPageHeight
211 // << " isTitle=" << isTitle << endl;
212 curPage = page;
213
214 TQDomElement textObj = elem.namedItem( "TEXTOBJ" ).toElement();
215 if (textObj.isNull())
216 continue;
217 // For each paragraph in this text object...
218 TQDomNodeList lst = textObj.elementsByTagName( "P" );
219 uint lstcount = lst.count();
220 for ( uint item = 0; item < lstcount ; ++item )
221 {
222 TQDomElement p = lst.item( item ).toElement();
223
224 // Create paragraph in KWord doc
225 TQDomElement parag = outdoc.createElement( "PARAGRAPH" );
226 frameset.appendChild( parag );
227
228 TQDomElement outFormatsElem = outdoc.createElement( "FORMATS" );
229
230 TQString text;
231 // For each text element in the paragraph...
232 TQDomElement textElem = p.firstChild().toElement();
233
234 TQDomElement counter = p.namedItem( "COUNTER" ).toElement();
235 TQDomElement indent=p.namedItem("INDENTS").toElement();
236 TQDomElement lineSpacing=p.namedItem( "LINESPACING" ).toElement();
237 TQDomElement offset=p.namedItem("OFFSETS").toElement();
238 TQDomElement leftBorder = p.namedItem( "LEFTBORDER" ).toElement();
239 TQDomElement rightBorder = p.namedItem( "RIGHTBORDER" ).toElement();
240 TQDomElement topBorder = p.namedItem( "TOPBORDER" ).toElement();
241 TQDomElement bottomBorder = p.namedItem( "BOTTOMBORDER" ).toElement();
242
243 TQDomElement shadow=p.namedItem("SHADOW").toElement();
244
245 for ( ; !textElem.isNull() ; textElem = textElem.nextSibling().toElement() )
246 {
247 int oldLen = text.length();
248 text += textElem.text();
249 //kdDebug() << "KprKword::convert text now " << text << endl;
250 TQDomElement outFormatElem = outdoc.createElement( "FORMAT" );
251
252 if ( textElem.attribute( "italic" ).toInt() )
253 {
254 TQDomElement e = outdoc.createElement("ITALIC");
255 e.setAttribute( "value", 1 );
256 outFormatElem.appendChild( e );
257 }
258 TQColor underlineColor;
259 if ( textElem.hasAttribute("underlinecolor" ))
260 {
261 underlineColor =TQColor(textElem.attribute("underlinecolor" ));
262 }
263 TQString underlineStyleLine;
264 if ( textElem.hasAttribute("underlinestyleline"))
265 {
266 underlineStyleLine = textElem.attribute("underlinestyleline");
267 }
268 if ( textElem.hasAttribute("underline" ))
269 {
270 TQDomElement e = outdoc.createElement("UNDERLINE");
271 TQString value = textElem.attribute( "underline" );
272 if ( value == "double" )
273 {
274 e.setAttribute( "value", "double" );
275 }
276 else if ( value == "single" )
277 {
278 e.setAttribute( "value", "double" );
279 }
280 else
281 {
282 e.setAttribute( "value", (bool)value.toInt() ? "1" :"0" );
283 }
284 if ( underlineColor.isValid())
285 {
286 e.setAttribute("underlinecolor", underlineColor.name());
287 }
288 if ( !underlineStyleLine.isEmpty() )
289 e.setAttribute("styleline", underlineStyleLine);
290 outFormatElem.appendChild( e );
291
292 }
293
294 TQString strikeOutStyleLine;
295 if ( textElem.hasAttribute("strikeoutstyleline"))
296 {
297 strikeOutStyleLine = textElem.attribute("strikeoutstyleline");
298 }
299 TQString strikeOutValue;
300 if ( textElem.hasAttribute("strikeOut"))
301 {
302 strikeOutValue = textElem.attribute("strikeOut");
303 }
304
305 if( !strikeOutValue.isEmpty())
306 {
307 TQDomElement e = outdoc.createElement("STRIKEOUT");
308 e.setAttribute( "value", strikeOutValue );
309 if ( !strikeOutStyleLine.isEmpty())
310 e.setAttribute("styleline", strikeOutStyleLine);
311 outFormatElem.appendChild( e );
312 }
313 /*if ( textElem.attribute( "bold" ).toInt() )
314 {
315 TQDomElement e = outdoc.createElement("WEIGHT");
316 e.setAttribute( "value", 75 );
317 outFormatElem.appendChild( e );
318 }*/ // doesn't look good
319 if ( titleFont.isEmpty() && isTitle )
320 titleFont = textElem.attribute( "family" );
321
322 // Family and point size are voluntarily NOT passed over.
323 if ( !textElem.attribute( "color" ).isEmpty())
324 {
325 TQColor col;
326 col.setNamedColor(textElem.attribute( "color" ));
327 TQDomElement e = outdoc.createElement("COLOR");
328 e.setAttribute( "red", col.red() );
329 e.setAttribute( "green", col.green() );
330 e.setAttribute( "blue", col.blue() );
331 outFormatElem.appendChild( e );
332 }
333 if ( !textElem.attribute("textbackcolor").isEmpty())
334 {
335 TQColor col;
336 col.setNamedColor(textElem.attribute( "textbackcolor" ));
337 TQDomElement e = outdoc.createElement("TEXTBACKGROUNDCOLOR");
338 e.setAttribute( "red", col.red() );
339 e.setAttribute( "green", col.green() );
340 e.setAttribute( "blue", col.blue() );
341 outFormatElem.appendChild( e );
342 }
343
344 //before VERTICAL align
345 double relative = 0;
346 if( textElem.attribute("relativetextsize").toDouble())
347 {
348 relative = textElem.attribute("relativetextsize").toDouble();
349 }
350
351
352 if( textElem.attribute("VERTALIGN").toInt())
353 {
354 TQDomElement e = outdoc.createElement("VERTALIGN");
355 e.setAttribute( "value", textElem.attribute("VERTALIGN").toInt() );
356 if ( relative != 0)
357 e.setAttribute( "relativetextsize", relative );
358 outFormatElem.appendChild( e );
359 }
360
361 if( textElem.hasAttribute("shadowtext"))
362 {
363 TQDomElement e = outdoc.createElement("SHADOWTEXT");
364 e.setAttribute( "value", textElem.attribute("shadowtext").toInt() );
365 outFormatElem.appendChild( e );
366 }
367
368 if( textElem.hasAttribute("offsetfrombaseline"))
369 {
370 TQDomElement e = outdoc.createElement("OFFSETFROMBASELINE");
371 e.setAttribute( "value", textElem.attribute("offsetfrombaseline").toInt() );
372 outFormatElem.appendChild( e );
373 }
374
375 if( textElem.hasAttribute("wordbyword"))
376 {
377 TQDomElement e = outdoc.createElement("WORDBYWORD");
378 e.setAttribute( "value", textElem.attribute("wordbyword").toInt() );
379 outFormatElem.appendChild( e );
380 }
381
382 if( textElem.hasAttribute("fontattribute"))
383 {
384 TQDomElement e = outdoc.createElement("FONTATTRIBUTE");
385 e.setAttribute( "value", textElem.attribute("fontattribute") );
386 outFormatElem.appendChild( e );
387 }
388 if( textElem.hasAttribute("language"))
389 {
390 TQDomElement e = outdoc.createElement("LANGUAGE");
391 e.setAttribute( "value", textElem.attribute("language") );
392 outFormatElem.appendChild( e );
393 }
394 if ( !outFormatElem.firstChild().isNull() )
395 {
396 outFormatElem.setAttribute( "id", 1 ); // normal exte
397 outFormatElem.setAttribute( "pos", oldLen );
398 outFormatElem.setAttribute( "len", text.length() - oldLen );
399 outFormatsElem.appendChild( outFormatElem );
400 }
401
402 } // end "for each text element"
403
404 // KPresenter seems to save a trailing space (bug!)
405 int len = text.length();
406 if ( len > 0 && text[ len - 1 ] == ' ' )
407 text.truncate( len - 1 );
408
409 TQDomElement outTextElem = outdoc.createElement( "TEXT" );
410 parag.appendChild( outTextElem );
411 outTextElem.appendChild( outdoc.createTextNode( text ) );
412
413 if ( !outFormatsElem.firstChild().isNull() ) // Do we have formats to save ?
414 parag.appendChild( outFormatsElem );
415
416 TQDomElement layoutElem = outdoc.createElement( "LAYOUT" );
417 parag.appendChild( layoutElem );
418 TQDomElement nameElem = outdoc.createElement( "NAME" );
419 layoutElem.appendChild( nameElem );
420 nameElem.setAttribute( "value", isTitle ? titleStyleName : TQString("Standard") );
421 TQDomElement align=outdoc.createElement("FLOW");
422 if(p.hasAttribute("align"))
423 {
424 switch(p.attribute( "align" ).toInt())
425 {
426 case 1:
427 align.setAttribute( "align","left");
428 break;
429 case 2:
430 align.setAttribute( "align","right");
431 break;
432 case 4:
433 align.setAttribute( "align","center");
434 break;
435 case 8:
436 align.setAttribute( "align","justify");
437 break;
438 }
439 }
440 if(!counter.isNull() )
441 layoutElem.appendChild( counter );
442 if(!indent.isNull())
443 layoutElem.appendChild( indent );
444 if(!lineSpacing.isNull())
445 layoutElem.appendChild( lineSpacing );
446 if(!offset.isNull())
447 layoutElem.appendChild( offset);
448 if(!leftBorder.isNull())
449 layoutElem.appendChild(leftBorder);
450 if(!rightBorder.isNull())
451 layoutElem.appendChild(rightBorder);
452 if(!topBorder.isNull())
453 layoutElem.appendChild(topBorder);
454 if(!bottomBorder.isNull())
455 layoutElem.appendChild(bottomBorder);
456 if(!align.isNull())
457 layoutElem.appendChild(align);
458 if(!shadow.isNull())
459 layoutElem.appendChild(shadow);
460 // Only the first parag of the top text object is set to the 'title' style
461 isTitle = false;
462 }
463 }
464}
465
466#include <kprkword.moc>