ooimpressimport.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com>
3 Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include "ooimpressimport.h"
22
23#include <math.h>
24
25#include <tqregexp.h>
26#include <tqdatetime.h>
27#include <tqfileinfo.h>
28#include <tqdir.h>
29
30#include <kzip.h>
31#include <karchive.h>
32#include <kdebug.h>
33#include <KoUnit.h>
34#include <KoDocumentInfo.h>
35#include <KoDocument.h>
36
37#include <kgenericfactory.h>
38#include <KoFilterChain.h>
39#include <KoGlobal.h>
40#include <ooutils.h>
41#include <KoDom.h>
42#include <KoOasisSettings.h>
43
44typedef KGenericFactory<OoImpressImport, KoFilter> OoImpressImportFactory;
45K_EXPORT_COMPONENT_FACTORY( libooimpressimport, OoImpressImportFactory( "kofficefilters" ) )
46
47
48OoImpressImport::OoImpressImport( KoFilter *, const char *, const TQStringList & )
49 : KoFilter(),
50 m_numPicture( 1 ),
51 m_numSound(1),
52 m_styles( 23, true ),
53 m_styleStack( ooNS::style, ooNS::fo )
54{
55 m_styles.setAutoDelete( true );
56 m_listStyles.setAutoDelete( true );
57}
58
59OoImpressImport::~OoImpressImport()
60{
61 TQDictIterator<animationList> it( m_animations ); // See TQDictIterator
62 for( ; it.current(); ++it )
63 {
64 delete it.current()->element;
65 }
66 m_animations.clear();
67}
68
69KoFilter::ConversionStatus OoImpressImport::convert( TQCString const & from, TQCString const & to )
70{
71 kdDebug(30518) << "Entering Ooimpress Import filter: " << from << " - " << to << endl;
72
73 if ( (from != "application/vnd.sun.xml.impress" && from != "application/vnd.sun.xml.impress.template" )
74 || to != "application/x-kpresenter" )
75 {
76 kdWarning(30518) << "Invalid mimetypes " << from << " " << to << endl;
77 return KoFilter::NotImplemented;
78 }
79
80 m_zip = new KZip( m_chain->inputFile() );
81
82 if ( !m_zip->open( IO_ReadOnly ) )
83 {
84 kdError(30518) << "Couldn't open the requested file "<< m_chain->inputFile() << endl;
85 delete m_zip;
86 return KoFilter::FileNotFound;
87 }
88
89 KoFilter::ConversionStatus preStatus = openFile();
90
91 if ( preStatus != KoFilter::OK )
92 {
93 m_zip->close();
94 delete m_zip;
95 return preStatus;
96 }
97
98 TQDomDocument docinfo;
99 createDocumentInfo( docinfo );
100
101 // store document info
102 KoStoreDevice* out = m_chain->storageFile( "documentinfo.xml", KoStore::Write );
103 if( out )
104 {
105 TQCString info = docinfo.toCString();
106 //kdDebug(30518) << " info :" << info << endl;
107 // WARNING: we cannot use KoStore::write(const TQByteArray&) because it gives an extra NULL character at the end.
108 out->writeBlock( info , info.length() );
109 }
110
111 TQDomDocument doccontent;
112 createDocumentContent( doccontent );
113
114 // store document content
115 out = m_chain->storageFile( "maindoc.xml", KoStore::Write );
116 if( out )
117 {
118 TQCString content = doccontent.toCString();
119 kdDebug(30518) << " content :" << content << endl;
120 out->writeBlock( content , content.length() );
121 }
122
123 m_zip->close();
124 delete m_zip;
125
126 kdDebug(30518) << "######################## OoImpressImport::convert done ####################" << endl;
127 return KoFilter::OK;
128}
129
130// Very related to OoWriterImport::openFile()
131KoFilter::ConversionStatus OoImpressImport::openFile()
132{
133 KoFilter::ConversionStatus status = loadAndParse( "content.xml", m_content );
134 if ( status != KoFilter::OK )
135 {
136 kdError(30518) << "Content.xml could not be parsed correctly! Aborting!" << endl;
137 return status;
138 }
139
140 // We do not stop if the following calls fail.
141 TQDomDocument styles;
142 loadAndParse( "styles.xml", styles );
143 loadAndParse( "meta.xml", m_meta );
144 loadAndParse( "settings.xml", m_settings );
145
146 emit sigProgress( 10 );
147 createStyleMap( styles );
148
149 return KoFilter::OK;
150}
151
152KoFilter::ConversionStatus OoImpressImport::loadAndParse(const TQString& filename, TQDomDocument& doc)
153{
154 return OoUtils::loadAndParse( filename, doc, m_zip);
155}
156
157// Very related to OoWriterImport::createDocumentInfo
158void OoImpressImport::createDocumentInfo( TQDomDocument &docinfo )
159{
160 docinfo = KoDocument::createDomDocument( "document-info" /*DTD name*/, "document-info" /*tag name*/, "1.1" );
161
162 OoUtils::createDocumentInfo(m_meta, docinfo);
163 //kdDebug(30518) << " meta-info :" << m_meta.toCString() << endl;
164}
165
166void OoImpressImport::createDocumentContent( TQDomDocument &doccontent )
167{
168 TQDomDocument doc = KoDocument::createDomDocument( "kpresenter", "DOC", "1.2" );
169 TQDomElement docElement = doc.documentElement();
170 docElement.setAttribute( "editor", "KPresenter" );
171 docElement.setAttribute( "mime", "application/x-kpresenter" );
172 docElement.setAttribute( "syntaxVersion", "2" );
173
174 TQDomElement content = m_content.documentElement();
175
176 // content.xml contains some automatic-styles that we need to store
177 TQDomNode automaticStyles = KoDom::namedItemNS( content, ooNS::office, "automatic-styles" );
178 if ( !automaticStyles.isNull() )
179 insertStyles( automaticStyles.toElement() );
180
181 TQDomNode body = KoDom::namedItemNS( content, ooNS::office, "body" );
182 if ( body.isNull() )
183 return;
184
185 TQDomElement customSlideShow = doc.createElement( "CUSTOMSLIDESHOWCONFIG" );
186
187 // presentation settings
188 TQDomElement settings = KoDom::namedItemNS( body, ooNS::presentation, "settings");
189 if (!settings.isNull())
190 {
191 if (settings.attributeNS( ooNS::presentation, "endless", TQString())=="true")
192 {
193 TQDomElement infElem = doc.createElement("INFINITLOOP");
194 infElem.setAttribute("value", 1);
195 docElement.appendChild(infElem);
196 }
197
198 if (settings.attributeNS( ooNS::presentation, "show-end-of-presentation-slide", TQString())=="true")
199 {
200 TQDomElement infElem = doc.createElement("SHOWENDOFPRESENTATIONSLIDE");
201 infElem.setAttribute("value", 1);
202 docElement.appendChild(infElem);
203 }
204
205 if (settings.attributeNS( ooNS::presentation, "force-manual", TQString())=="true")
206 {
207 TQDomElement manualElem = doc.createElement("MANUALSWITCH");
208 manualElem.setAttribute("value", 1);
209 docElement.appendChild(manualElem);
210 }
211 if ( settings.hasAttributeNS( ooNS::presentation, "show") )
212 {
213 TQDomElement defaultPage = doc.createElement("DEFAULTCUSTOMSLIDESHOWNAME");
214 defaultPage.setAttribute("name", settings.attributeNS( ooNS::presentation, "show", TQString()) );
215 docElement.appendChild(defaultPage);
216 }
217 }
218
219 TQDomElement presentationShow;
220 forEachElement( presentationShow, settings )
221 {
222 if ( presentationShow.localName()=="show" && presentationShow.namespaceURI() == ooNS::presentation )
223 {
224 if ( presentationShow.hasAttributeNS( ooNS::presentation, "pages") &&
225 presentationShow.hasAttributeNS( ooNS::presentation, "name"))
226 {
227 TQDomElement slide=doc.createElement("CUSTOMSLIDESHOW");
228 slide.setAttribute( "pages", presentationShow.attributeNS( ooNS::presentation, "pages", TQString() ));
229 slide.setAttribute( "name", presentationShow.attributeNS( ooNS::presentation, "name", TQString() ));
230 customSlideShow.appendChild( slide );
231 }
232 }
233 }
234 // it seems that ooimpress has different paper-settings for every slide.
235 // we take the settings of the first slide for the whole document.
236 TQDomElement drawPage = KoDom::namedItemNS( body, ooNS::draw, "page" );
237 if ( drawPage.isNull() ) // no slides? give up.
238 return;
239
240 TQDomElement objectElement = doc.createElement( "OBJECTS" );
241 TQDomElement pictureElement = doc.createElement( "PICTURES" );
242 TQDomElement pageTitleElement = doc.createElement( "PAGETITLES" );
243 TQDomElement pageNoteElement = doc.createElement( "PAGENOTES" );
244 TQDomElement backgroundElement = doc.createElement( "BACKGROUND" );
245 TQDomElement soundElement = doc.createElement( "SOUNDS" );
246 TQDomElement selSlideElement = doc.createElement( "SELSLIDES" );
247 TQDomElement helpLineElement = doc.createElement( "HELPLINES" );
248 TQDomElement attributeElement = doc.createElement( "ATTRIBUTES" );
249 TQDomElement *master = m_styles[drawPage.attributeNS( ooNS::draw, "master-page-name", TQString() )];
250
251 appendObject(*master, doc, soundElement,pictureElement,pageNoteElement,objectElement, 0, true);
252
253 TQDomElement *style = m_styles[master->attributeNS( ooNS::style, "page-master-name", TQString() )];
254 TQDomElement properties = KoDom::namedItemNS( *style, ooNS::style, "properties" );
255 //kdDebug(30518)<<" master->attribute( draw:style-name ) :"<<master->attributeNS( ooNS::draw, "style-name", TQString() )<<endl;
256 TQDomElement *backgroundStyle = m_stylesPresentation[ master->attributeNS( ooNS::draw, "style-name", TQString() ).isEmpty() ? "Standard-background" : master->attributeNS( ooNS::draw, "style-name", TQString() ) ];
257
258 //kdDebug(30518)<<" backgroundStyle :"<<backgroundStyle<<endl;
259 double pageHeight;
260 TQDomElement paperElement = doc.createElement( "PAPER" );
261 if ( properties.isNull() )
262 {
263 paperElement.setAttribute( "ptWidth", CM_TO_POINT(28) );
264 paperElement.setAttribute( "ptHeight", CM_TO_POINT(21) );
265 paperElement.setAttribute( "unit", 0 );
266 paperElement.setAttribute( "format", 5 );
267 paperElement.setAttribute( "tabStopValue", 42.5198 );
268 paperElement.setAttribute( "orientation", 0 );
269 pageHeight = 21;
270
271 TQDomElement paperBorderElement = doc.createElement( "PAPERBORDERS" );
272 paperBorderElement.setAttribute( "ptRight", 0 );
273 paperBorderElement.setAttribute( "ptBottom", 0 );
274 paperBorderElement.setAttribute( "ptLeft", 0 );
275 paperBorderElement.setAttribute( "ptTop", 0 );
276 paperElement.appendChild( paperBorderElement );
277 }
278 else
279 {
280 paperElement.setAttribute( "ptWidth", KoUnit::parseValue(properties.attributeNS( ooNS::fo, "page-width", TQString() ) ) );
281 paperElement.setAttribute( "ptHeight", KoUnit::parseValue(properties.attributeNS( ooNS::fo, "page-height", TQString() ) ) );
282// paperElement.setAttribute( "unit", 0 );
283// paperElement.setAttribute( "format", 5 );
284// paperElement.setAttribute( "tabStopValue", 42.5198 );
285// paperElement.setAttribute( "orientation", 0 );
286 // Keep pageHeight in cm to avoid rounding-errors that would
287 // get multiplied with every new slide.
288
289 if (properties.attributeNS( ooNS::style, "print-orientation", TQString())=="portrait")
290 paperElement.setAttribute("orientation", 0);
291 else if (properties.attributeNS( ooNS::style, "print-orientation", TQString())=="landscape")
292 paperElement.setAttribute("orientation", 1);
293
294
295
296 pageHeight = properties.attributeNS( ooNS::fo, "page-height", TQString() ).remove( "cm" ).toDouble();
297
298 TQDomElement paperBorderElement = doc.createElement( "PAPERBORDERS" );
299 paperBorderElement.setAttribute( "ptRight", KoUnit::parseValue( properties.attributeNS( ooNS::fo, "margin-right", TQString() ) ) );
300 paperBorderElement.setAttribute( "ptBottom", KoUnit::parseValue( properties.attributeNS( ooNS::fo, "margin-bottom", TQString() ) ) );
301 paperBorderElement.setAttribute( "ptLeft", KoUnit::parseValue( properties.attributeNS( ooNS::fo, "margin-left", TQString() ) ) );
302 paperBorderElement.setAttribute( "ptTop", KoUnit::parseValue( properties.attributeNS( ooNS::fo, "margin-top", TQString() ) ) );
303 paperElement.appendChild( paperBorderElement );
304 }
305
306
307 // parse all pages
308 forEachElement( drawPage, body )
309 {
310 if ( drawPage.localName()=="page" && drawPage.namespaceURI() == ooNS::draw && drawPage.hasAttributeNS( ooNS::draw, "id" ))
311 {
312 m_styleStack.clear(); // remove all styles
313 fillStyleStack( drawPage );
314 m_styleStack.save();
315 int pagePos = drawPage.attributeNS( ooNS::draw, "id", TQString() ).toInt() - 1;
316 // take care of a possible page background or slide transition or sound
317 if ( m_styleStack.hasAttributeNS( ooNS::draw, "fill" )
318 || m_styleStack.hasAttributeNS( ooNS::presentation, "transition-style" ))
319 {
320 appendBackgroundPage( doc, backgroundElement,pictureElement, soundElement );
321 }
322 else if ( !m_styleStack.hasAttributeNS( ooNS::draw, "fill" ) && backgroundStyle)
323 {
324 m_styleStack.save();
325 m_styleStack.push( *backgroundStyle );
326 appendBackgroundPage( doc, backgroundElement,pictureElement, soundElement );
327 m_styleStack.restore();
328 kdDebug(30518)<<" load standard bacground \n";
329 }
330 if ( m_styleStack.hasAttributeNS( ooNS::presentation, "visibility" ) )
331 {
332 TQString str = m_styleStack.attributeNS( ooNS::presentation, "visibility" );
333 TQDomElement slide = doc.createElement("SLIDE");
334 slide.setAttribute( "nr", pagePos );
335 slide.setAttribute( "show", ( ( str=="hidden" ) ? "0" : "1" ));
336 selSlideElement.appendChild( slide );
337
338 //todo add support
339 kdDebug(30518)<<"m_styleStack.hasAttribute( presentation:visibility ) :"<<str<<" position page "<<pagePos<<endl;
340 }
341 // set the pagetitle
342 TQDomElement titleElement = doc.createElement( "Title" );
343 titleElement.setAttribute( "title", drawPage.attributeNS( ooNS::draw, "name", TQString() ) );
344 pageTitleElement.appendChild( titleElement );
345
346 // The '+1' is necessary to avoid that objects that start on the first line
347 // of a slide will show up on the last line of the previous slide.
348 double offset = CM_TO_POINT( ( drawPage.attributeNS( ooNS::draw, "id", TQString() ).toInt() - 1 ) * pageHeight ) + 1;
349
350 // animations (object effects)
351 createPresentationAnimation(KoDom::namedItemNS( drawPage, ooNS::presentation, "animations") );
352
353 // parse all objects
354 appendObject(drawPage, doc, soundElement,pictureElement,pageNoteElement,objectElement, offset);
355
356 //m_animations.clear();
357 m_styleStack.restore();
358 }
359 }
360
361 docElement.appendChild( paperElement );
362 docElement.appendChild( backgroundElement );
363 if ( parseSettings( doc, helpLineElement, attributeElement ) )
364 docElement.appendChild( helpLineElement );
365 docElement.appendChild( attributeElement );
366 docElement.appendChild( pageTitleElement );
367 docElement.appendChild( pageNoteElement );
368 docElement.appendChild( objectElement );
369 docElement.appendChild( selSlideElement );
370 docElement.appendChild( customSlideShow );
371 docElement.appendChild( soundElement );
372 docElement.appendChild( pictureElement );
373
374 doccontent.appendChild( doc );
375}
376
377bool OoImpressImport::parseSettings( TQDomDocument &doc, TQDomElement &helpLineElement, TQDomElement &attributeElement )
378{
379 bool foundElement = false;
380 KoOasisSettings settings( m_settings, ooNS::office, ooNS::config );
381 KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" );
382 //setUnit(KoUnit::unit(viewSettings.parseConfigItemString("unit")));
383 KoOasisSettings::IndexedMap viewMap = viewSettings.indexedMap( "Views" );
384 KoOasisSettings::Items firstView = viewMap.entry( 0 );
385 //<config:config-item config:name="SnapLinesDrawing" config:type="string">V7939H1139</config:config-item>
386 //by default show line
387
388 if ( !firstView.isNull() )
389 {
390 TQString str = firstView.parseConfigItemString( "SnapLinesDrawing" );
391 if ( !str.isEmpty() )
392 {
393 parseHelpLine( doc, helpLineElement, str );
394 //display it by default
395 helpLineElement.setAttribute( "show", true );
396 foundElement = true;
397 }
398
399 int gridX = firstView.parseConfigItemInt( "GridFineWidth" );
400 int gridY = firstView.parseConfigItemInt( "GridFineHeight" );
401 bool snapToGrid = firstView.parseConfigItemBool( "IsSnapToGrid" );
402 int selectedPage = firstView.parseConfigItemInt( "SelectedPage" );
403
404 attributeElement.setAttribute( "activePage", selectedPage );
405 attributeElement.setAttribute( "gridx", MM_TO_POINT( gridX / 100.0 ) );
406 attributeElement.setAttribute( "gridy", MM_TO_POINT( gridY / 100.0 ) );
407 attributeElement.setAttribute( "snaptogrid", (int)snapToGrid );
408
409 }
410
411 //kdDebug(30518)<<" gridX :"<<gridX<<" gridY :"<<gridY<<" snapToGrid :"<<snapToGrid<<" selectedPage :"<<selectedPage<<endl;
412 return foundElement;
413}
414
415void OoImpressImport::parseHelpLine( TQDomDocument &doc,TQDomElement &helpLineElement, const TQString &text )
416{
417 TQString str;
418 int newPos = text.length()-1; //start to element = 1
419 for ( int pos = text.length()-1; pos >=0;--pos )
420 {
421 if ( text[pos]=='P' )
422 {
423
424 //point
425 str = text.mid( pos+1, ( newPos-pos ) );
426 TQDomElement point=doc.createElement("HelpPoint");
427
428 //kdDebug(30518)<<" point element :"<< str <<endl;
429 TQStringList listVal = TQStringList::split( ",", str );
430 int posX = ( listVal[0].toInt()/100 );
431 int posY = ( listVal[1].toInt()/100 );
432 point.setAttribute("posX", MM_TO_POINT( posX ));
433 point.setAttribute("posY", MM_TO_POINT( posY ));
434
435 helpLineElement.appendChild( point );
436 newPos = pos-1;
437 }
438 else if ( text[pos]=='V' )
439 {
440 TQDomElement lines=doc.createElement("Vertical");
441 //vertical element
442 str = text.mid( pos+1, ( newPos-pos ) );
443 //kdDebug(30518)<<" vertical :"<< str <<endl;
444 int posX = ( str.toInt()/100 );
445 lines.setAttribute( "value", MM_TO_POINT( posX ) );
446 helpLineElement.appendChild( lines );
447
448 newPos = ( pos-1 );
449
450 }
451 else if ( text[pos]=='H' )
452 {
453 //horizontal element
454 TQDomElement lines=doc.createElement("Horizontal");
455 str = text.mid( pos+1, ( newPos-pos ) );
456 //kdDebug(30518)<<" horizontal :"<< str <<endl;
457 int posY = ( str.toInt()/100 );
458 lines.setAttribute( "value", MM_TO_POINT( posY ) );
459 helpLineElement.appendChild( lines );
460 newPos = pos-1;
461 }
462 }
463}
464
465void OoImpressImport::appendObject(TQDomNode & drawPage, TQDomDocument & doc, TQDomElement & soundElement, TQDomElement & pictureElement, TQDomElement & pageNoteElement, TQDomElement &objectElement, double offset, bool sticky)
466{
467 TQDomElement o;
468 forEachElement( o, drawPage )
469 {
470 const TQString localName = o.localName();
471 const TQString ns = o.namespaceURI();
472 const TQString drawID = o.attributeNS( ooNS::draw, "id", TQString());
473 m_styleStack.save();
474
475 TQDomElement e;
476 if ( localName == "text-box" && ns == ooNS::draw ) // textbox
477 {
478 fillStyleStack( o, sticky );
479 e = doc.createElement( "OBJECT" );
480 e.setAttribute( "type", 4 );
481 if ( sticky )
482 e.setAttribute( "sticky", "1" );
483 append2DGeometry( doc, e, o, (int)offset );
484 appendName(doc, e, o);
485 appendPen( doc, e );
486 appendBrush( doc, e );
487 appendRounding( doc, e, o );
488 appendShadow( doc, e );
489 appendObjectEffect(doc, e, o, soundElement);
490 e.appendChild( parseTextBox( doc, o ) );
491 }
492 else if ( localName == "rect" && ns == ooNS::draw ) // rectangle
493 {
494 fillStyleStack( o, sticky );
495 e = doc.createElement( "OBJECT" );
496 e.setAttribute( "type", 2 );
497 if ( sticky )
498 e.setAttribute( "sticky", "1" );
499 append2DGeometry( doc, e, o, (int)offset );
500 appendName(doc, e, o);
501 appendPen( doc, e );
502 appendBrush( doc, e );
503 appendRounding( doc, e, o );
504 appendShadow( doc, e );
505
506 appendObjectEffect(doc, e, o, soundElement);
507 }
508 else if ( ( localName == "circle" || localName == "ellipse" ) && ns == ooNS::draw )
509 {
510 fillStyleStack( o, sticky );
511 e = doc.createElement( "OBJECT" );
512 if ( sticky )
513 e.setAttribute( "sticky", "1" );
514 append2DGeometry( doc, e, o, (int)offset );
515 appendName(doc, e, o);
516 appendPen( doc, e );
517 appendShadow( doc, e );
518 appendLineEnds( doc, e );
519 appendObjectEffect(doc, e, o, soundElement);
520
521 if ( o.hasAttributeNS( ooNS::draw, "kind" ) ) // pie, chord or arc
522 {
523 e.setAttribute( "type", 8 );
524 appendPie( doc, e, o );
525 TQDomElement type = doc.createElement( "PIETYPE" );
526
527 TQString kind = o.attributeNS( ooNS::draw, "kind", TQString() );
528 if ( kind == "section" )
529 {
530 appendBrush( doc, e );
531 type.setAttribute( "value", 0 );
532 }
533 else if ( kind == "cut" )
534 {
535 appendBrush( doc, e );
536 type.setAttribute( "value", 2 );
537 }
538 else if ( kind == "arc" )
539 {
540 // arc has no brush
541 type.setAttribute( "value", 1 );
542 }
543 e.appendChild( type );
544 }
545 else // circle or ellipse
546 {
547 e.setAttribute( "type", 3 );
548 appendBrush( doc, e );
549 }
550 }
551 else if ( localName == "line" && ns == ooNS::draw ) // line
552 {
553 fillStyleStack( o, sticky );
554 e = doc.createElement( "OBJECT" );
555 e.setAttribute( "type", 1 );
556 if ( sticky )
557 e.setAttribute( "sticky", "1" );
558 bool orderEndStartLine = appendLineGeometry( doc, e, o, (int)offset );
559 appendName(doc, e, o);
560 appendPen( doc, e );
561 appendBrush( doc, e );
562 appendShadow( doc, e );
563 appendLineEnds( doc, e, orderEndStartLine );
564 appendObjectEffect(doc, e, o, soundElement);
565 }
566 else if ( localName=="polyline" && ns == ooNS::draw ) { // polyline
567 fillStyleStack(o, sticky);
568 e = doc.createElement("OBJECT");
569 e.setAttribute("type", 12);
570 if ( sticky )
571 e.setAttribute( "sticky", "1" );
572 append2DGeometry(doc, e, o, (int)offset);
573 appendName(doc, e, o);
574 appendPoints(doc, e, o);
575 appendPen(doc, e);
576 appendBrush(doc, e);
577 appendLineEnds(doc, e);
578 //appendShadow(doc, e);
579 appendObjectEffect(doc, e, o, soundElement);
580 }
581 else if ( localName=="polygon" && ns == ooNS::draw ) { // polygon
582 fillStyleStack(o, sticky);
583 e = doc.createElement("OBJECT");
584 e.setAttribute("type", 16);
585 if ( sticky )
586 e.setAttribute( "sticky", "1" );
587 append2DGeometry(doc, e, o, (int)offset);
588 appendName(doc, e, o);
589 appendPoints(doc, e, o);
590 appendPen(doc, e);
591 appendBrush(doc, e);
592 //appendLineEnds(doc, e);
593 //appendShadow(doc, e);
594 appendObjectEffect(doc, e, o, soundElement);
595 }
596 else if ( localName == "image" && ns == ooNS::draw ) // image
597 {
598 fillStyleStack( o, sticky );
599 e = doc.createElement( "OBJECT" );
600 e.setAttribute( "type", 0 );
601 if ( sticky )
602 e.setAttribute( "sticky", "1" );
603 append2DGeometry( doc, e, o, (int)offset );
604 appendName(doc, e, o);
605 appendImage( doc, e, pictureElement, o );
606 appendObjectEffect(doc, e, o, soundElement);
607 }
608 else if ( localName == "object" && ns == ooNS::draw )
609 {
610 //todo add part object
611 }
612 else if ( localName == "g" && ns == ooNS::draw )
613 {
614 //todo add group object
615 }
616 else if ( localName == "path" && ns == ooNS::draw )
617 {
618 //todo add path object (freehand/cubic/quadricbeziercurve
619 }
620 else if ( localName == "notes" && ns == ooNS::presentation ) // notes
621 {
622 TQDomNode textBox = KoDom::namedItemNS( o, ooNS::draw, "text-box" );
623 if ( !textBox.isNull() )
624 {
625 TQString note;
626 TQDomElement t;
627 forEachElement( t, textBox )
628 {
629 // We don't care about styles as they are not supported in kpresenter.
630 // Only add a linebreak for every child.
631 note += t.text() + "\n";
632 }
633 TQDomElement notesElement = doc.createElement( "Note" );
634 notesElement.setAttribute( "note", note );
635 pageNoteElement.appendChild( notesElement );
636 }
637 }
638 else
639 {
640 kdDebug(30518) << "Unsupported object '" << localName << "'" << endl;
641 m_styleStack.restore();
642 continue;
643 }
644
645 objectElement.appendChild( e );
646 m_styleStack.restore();
647 }
648}
649
650void OoImpressImport::appendBackgroundPage( TQDomDocument &doc, TQDomElement &backgroundElement, TQDomElement & pictureElement, TQDomElement &soundElement)
651{
652 TQDomElement bgPage = doc.createElement( "PAGE" );
653
654 // background
655 if ( m_styleStack.hasAttributeNS( ooNS::draw, "fill" ) )
656 {
657 const TQString fill = m_styleStack.attributeNS( ooNS::draw, "fill" );
658 if ( fill == "solid" )
659 {
660 TQDomElement backColor1 = doc.createElement( "BACKCOLOR1" );
661 backColor1.setAttribute( "color", m_styleStack.attributeNS( ooNS::draw, "fill-color" ) );
662 bgPage.appendChild( backColor1 );
663
664 TQDomElement bcType = doc.createElement( "BCTYPE" );
665 bcType.setAttribute( "value", 0 ); // plain
666 bgPage.appendChild( bcType );
667
668 TQDomElement backType = doc.createElement( "BACKTYPE" );
669 backType.setAttribute( "value", 0 ); // color/gradient
670 bgPage.appendChild( backType );
671 }
672 else if ( fill == "gradient" )
673 {
674 TQString style = m_styleStack.attributeNS( ooNS::draw, "fill-gradient-name" );
675 TQDomElement* draw = m_draws[style];
676 appendBackgroundGradient( doc, bgPage, *draw );
677 }
678 else if ( fill == "bitmap" )
679 {
680 TQString style = m_styleStack.attributeNS( ooNS::draw, "fill-image-name" );
681 TQDomElement* draw = m_draws[style];
682 appendBackgroundImage( doc, bgPage, pictureElement, *draw );
683
684 TQDomElement backView = doc.createElement( "BACKVIEW" );
685 if ( m_styleStack.hasAttributeNS( ooNS::style, "repeat" ) )
686 {
687 TQString repeat = m_styleStack.attributeNS( ooNS::style, "repeat" );
688 if ( repeat == "stretch" )
689 backView.setAttribute( "value", 0 ); // zoomed
690 else if ( repeat == "no-repeat" )
691 backView.setAttribute( "value", 1 ); // centered
692 else
693 backView.setAttribute( "value", 2 ); // use tiled as default
694 }
695 else
696 backView.setAttribute( "value", 2 ); // use tiled as default
697 bgPage.appendChild( backView );
698
699 TQDomElement backType = doc.createElement( "BACKTYPE" );
700 backType.setAttribute( "value", 1 ); // image
701 bgPage.appendChild( backType );
702 }
703 }
704
705 if ( m_styleStack.hasAttributeNS( ooNS::presentation, "duration" ) )
706 {
707 TQString str = m_styleStack.attributeNS( ooNS::presentation, "duration");
708 kdDebug(30518)<<"styleStack.hasAttribute(presentation:duration ) :"<<str<<endl;
709 //convert date duration
710 int hour( str.mid( 2, 2 ).toInt() );
711 int minute( str.mid( 5, 2 ).toInt() );
712 int second( str.mid( 8, 2 ).toInt() );
713 int pageTimer = second + minute*60 + hour*60*60;
714 TQDomElement pgEffect = doc.createElement("PGTIMER");
715 pgEffect.setAttribute( "timer", pageTimer );
716 bgPage.appendChild(pgEffect);
717 }
718 // slide transition
719 if (m_styleStack.hasAttributeNS( ooNS::presentation, "transition-style"))
720 {
721 TQDomElement pgEffect = doc.createElement("PGEFFECT");
722
723 const TQString effect = m_styleStack.attributeNS( ooNS::presentation, "transition-style");
724 //kdDebug(30518) << "Transition name: " << effect << endl;
725 int pef;
726
727 if (effect=="vertical-stripes" || effect=="vertical-lines") // PEF_BLINDS_VER
728 pef=14;
729 else if (effect=="horizontal-stripes" || effect=="horizontal-lines") // PEF_BLINDS_HOR
730 pef=13;
731 else if (effect=="spiralin-left" || effect=="spiralin-right"
732 || effect== "spiralout-left" || effect=="spiralout-right") // PEF_SURROUND1
733 pef=11;
734 else if (effect=="fade-from-upperleft") // PEF_STRIPS_RIGHT_DOWN
735 pef=39;
736 else if (effect=="fade-from-upperright") // PEF_STRIPS_LEFT_DOWN
737 pef=37;
738 else if (effect=="fade-from-lowerleft") // PEF_STRIPS_RIGHT_UP
739 pef=38;
740 else if (effect=="fade-from-lowerright") // PEF_STRIPS_LEFT_UP
741 pef=36;
742 else if (effect=="fade-from-top") // PEF_COVER_DOWN
743 pef=19;
744 else if (effect=="fade-from-bottom") // PEF_COVER_UP
745 pef=21;
746 else if (effect=="fade-from-left") // PEF_COVER_RIGHT
747 pef=25;
748 else if (effect=="fade-from-right") // PEF_COVER_LEFT
749 pef=23;
750 else if (effect=="fade-to-center") // PEF_CLOSE_ALL
751 pef=3;
752 else if (effect=="fade-from-center") // PEF_OPEN_ALL
753 pef=6;
754 else if (effect=="open-vertical") // PEF_OPEN_HORZ; really, no kidding ;)
755 pef=4;
756 else if (effect=="open-horizontal") // PEF_OPEN_VERT
757 pef=5;
758 else if (effect=="close-vertical") // PEF_CLOSE_HORZ
759 pef=1;
760 else if (effect=="close-horizontal") // PEF_CLOSE_VERT
761 pef=2;
762 else if (effect=="dissolve") // PEF_DISSOLVE; perfect hit ;)
763 pef=35;
764 else if (effect=="horizontal-checkerboard") // PEF_CHECKBOARD_ACROSS
765 pef=17;
766 else if (effect=="vertical-checkerboard") // PEF_CHECKBOARD_DOWN
767 pef=18;
768 else if (effect=="roll-from-left") // PEF_UNCOVER_RIGHT
769 pef=26;
770 else if (effect=="roll-from-right") // PEF_UNCOVER_LEFT
771 pef=24;
772 else if (effect=="roll-from-bottom") // PEF_UNCOVER_UP
773 pef=22;
774 else if (effect=="roll-from-top") // PEF_UNCOVER_DOWN
775 pef=20;
776 else if (effect=="random") // PEF_RANDOM
777 pef=-1;
778 else // we choose a random transition instead of the unsupported ones ;)
779 pef=-1;
780
781 pgEffect.setAttribute("value", pef);
782 bgPage.appendChild(pgEffect);
783 }
784
785 // slide transition sound
786 if (m_styleStack.hasChildNodeNS( ooNS::presentation, "sound"))
787 {
788 TQString soundUrl = storeSound(m_styleStack.childNodeNS( ooNS::presentation, "sound"),
789 soundElement, doc);
790
791 if (!soundUrl.isNull())
792 {
793 TQDomElement pseElem = doc.createElement("PGSOUNDEFFECT");
794 pseElem.setAttribute("soundEffect", 1);
795 pseElem.setAttribute("soundFileName", soundUrl);
796
797 bgPage.appendChild(pseElem);
798 }
799 }
800
801 backgroundElement.appendChild(bgPage);
802}
803
804void OoImpressImport::appendName(TQDomDocument& doc, TQDomElement& e, const TQDomElement& object)
805{
806 if( object.hasAttributeNS( ooNS::draw, "name" ))
807 {
808 TQDomElement name = doc.createElement( "OBJECTNAME" );
809 name.setAttribute( "objectName", object.attributeNS( ooNS::draw, "name", TQString() ));
810 e.appendChild( name );
811 }
812}
813
814void OoImpressImport::append2DGeometry( TQDomDocument& doc, TQDomElement& e, const TQDomElement& object, int offset )
815{
816 TQDomElement orig = doc.createElement( "ORIG" );
817 orig.setAttribute( "x", KoUnit::parseValue( object.attributeNS( ooNS::svg, "x", TQString() ) ) );
818 orig.setAttribute( "y", KoUnit::parseValue( object.attributeNS( ooNS::svg, "y", TQString() ) ) + offset );
819 e.appendChild( orig );
820
821 TQDomElement size = doc.createElement( "SIZE" );
822 size.setAttribute( "width", KoUnit::parseValue( object.attributeNS( ooNS::svg, "width", TQString() ) ) );
823 size.setAttribute( "height", KoUnit::parseValue( object.attributeNS( ooNS::svg, "height", TQString() ) ) );
824 e.appendChild( size );
825 if( object.hasAttributeNS( ooNS::draw, "transform" ))
826 {
827 kdDebug(30518)<<" object transform \n";
828 //todo parse it
829 TQString transform = object.attributeNS( ooNS::draw, "transform", TQString() );
830 if( transform.contains("rotate ("))
831 {
832 //kdDebug(30518)<<" rotate object \n";
833 transform = transform.remove("rotate (" );
834 transform = transform.left(transform.find(")"));
835 //kdDebug(30518)<<" transform :"<<transform<<endl;
836 bool ok;
837 double radian = transform.toDouble(&ok);
838 if( ok )
839 {
840 TQDomElement angle = doc.createElement( "ANGLE" );
841 //angle is defined as a radian in oo but degree into kpresenter.
842 angle.setAttribute("value", (-1 * ((radian*180)/M_PI)));
843
844 e.appendChild( angle );
845 }
846 }
847 }
848}
849
850//return true if (x1 < x2) necessary to load correctly start-line and end-line
851bool OoImpressImport::appendLineGeometry( TQDomDocument& doc, TQDomElement& e, const TQDomElement& object, int offset )
852{
853 double x1 = KoUnit::parseValue( object.attributeNS( ooNS::svg, "x1", TQString() ) );
854 double y1 = KoUnit::parseValue( object.attributeNS( ooNS::svg, "y1", TQString() ) );
855 double x2 = KoUnit::parseValue( object.attributeNS( ooNS::svg, "x2", TQString() ) );
856 double y2 = KoUnit::parseValue( object.attributeNS( ooNS::svg, "y2", TQString() ) );
857
858 double x = TQMIN( x1, x2 );
859 double y = TQMIN( y1, y2 );
860
861 TQDomElement orig = doc.createElement( "ORIG" );
862 orig.setAttribute( "x", x );
863 orig.setAttribute( "y", y + offset );
864 e.appendChild( orig );
865
866 TQDomElement size = doc.createElement( "SIZE" );
867 size.setAttribute( "width", fabs( x1 - x2 ) );
868 size.setAttribute( "height", fabs( y1 - y2 ) );
869 e.appendChild( size );
870
871 TQDomElement linetype = doc.createElement( "LINETYPE" );
872 if ( ( x1 < x2 && y1 < y2 ) || ( x1 > x2 && y1 > y2 ) )
873 linetype.setAttribute( "value", 2 );
874 else
875 linetype.setAttribute( "value", 3 );
876
877 e.appendChild( linetype );
878 return (x1 < x2);
879}
880
881void OoImpressImport::appendPen( TQDomDocument& doc, TQDomElement& e )
882{
883 if ( m_styleStack.hasAttributeNS( ooNS::draw, "stroke" ))
884 {
885 TQDomElement pen = doc.createElement( "PEN" );
886 if ( m_styleStack.attributeNS( ooNS::draw, "stroke" ) == "none" )
887 pen.setAttribute( "style", 0 );
888 else if ( m_styleStack.attributeNS( ooNS::draw, "stroke" ) == "solid" )
889 pen.setAttribute( "style", 1 );
890 else if ( m_styleStack.attributeNS( ooNS::draw, "stroke" ) == "dash" )
891 {
892 TQString style = m_styleStack.attributeNS( ooNS::draw, "stroke-dash" );
893 if ( style == "Ultrafine Dashed" || style == "Fine Dashed" ||
894 style == "Fine Dashed (var)" || style == "Dashed (var)" )
895 pen.setAttribute( "style", 2 );
896 else if ( style == "Fine Dotted" || style == "Ultrafine Dotted (var)" ||
897 style == "Line with Fine Dots" )
898 pen.setAttribute( "style", 3 );
899 else if ( style == "3 Dashes 3 Dots (var)" || style == "Ultrafine 2 Dots 3 Dashes" )
900 pen.setAttribute( "style", 4 );
901 else if ( style == "2 Dots 1 Dash" )
902 pen.setAttribute( "style", 5 );
903 }
904
905 if ( m_styleStack.hasAttributeNS( ooNS::svg, "stroke-width" ) )
906 pen.setAttribute( "width", (int) KoUnit::parseValue( m_styleStack.attributeNS( ooNS::svg, "stroke-width" ) ) );
907 if ( m_styleStack.hasAttributeNS( ooNS::svg, "stroke-color" ) )
908 pen.setAttribute( "color", m_styleStack.attributeNS( ooNS::svg, "stroke-color" ) );
909 e.appendChild( pen );
910 }
911}
912
913void OoImpressImport::appendBrush( TQDomDocument& doc, TQDomElement& e )
914{
915 if ( m_styleStack.hasAttributeNS( ooNS::draw, "fill" ) )
916 {
917 const TQString fill = m_styleStack.attributeNS( ooNS::draw, "fill" );
918 //kdDebug(30518)<<"void OoImpressImport::appendBrush( TQDomDocument& doc, TQDomElement& e ) :"<<fill<<endl;
919 if ( fill == "solid" )
920 {
921 TQDomElement brush = doc.createElement( "BRUSH" );
922 if ( m_styleStack.hasAttributeNS( ooNS::draw, "transparency" ) )
923 {
924 TQString transparency = m_styleStack.attributeNS( ooNS::draw, "transparency" );
925 transparency = transparency.remove( '%' );
926 int value = transparency.toInt();
927 if ( value >= 94 && value <= 99 )
928 {
929 brush.setAttribute( "style", 2 );
930 }
931 else if ( value>=64 && value <= 93 )
932 {
933 brush.setAttribute( "style", 3 );
934 }
935 else if ( value>=51 && value <= 63 )
936 {
937 brush.setAttribute( "style", 4 );
938 }
939 else if ( value>=38 && value <= 50 )
940 {
941 brush.setAttribute( "style", 5 );
942 }
943 else if ( value>=13 && value <= 37 )
944 {
945 brush.setAttribute( "style", 6 );
946 }
947 else if ( value>=7 && value <= 12 )
948 {
949 brush.setAttribute( "style", 7 );
950 }
951 else if ( value>=1 && value <= 6 )
952 {
953 brush.setAttribute( "style", 8 );
954 }
955 }
956 else
957 brush.setAttribute( "style", 1 );
958 if ( m_styleStack.hasAttributeNS( ooNS::draw, "fill-color" ) )
959 brush.setAttribute( "color", m_styleStack.attributeNS( ooNS::draw, "fill-color" ) );
960 e.appendChild( brush );
961 }
962 else if ( fill == "hatch" )
963 {
964 TQDomElement brush = doc.createElement( "BRUSH" );
965 TQString style = m_styleStack.attributeNS( ooNS::draw, "fill-hatch-name" );
966 TQDomElement* draw = m_draws[style];
967 if ( draw )
968 {
969 if( draw->hasAttributeNS( ooNS::draw, "color" ) )
970 brush.setAttribute( "color", draw->attributeNS( ooNS::draw, "color", TQString() ) );
971 int angle = 0;
972 if( draw->hasAttributeNS( ooNS::draw, "rotation" ))
973 {
974 angle = (draw->attributeNS( ooNS::draw, "rotation", TQString() ).toInt())/10;
975 kdDebug(30518)<<"angle :"<<angle<<endl;
976 }
977 if( draw->hasAttributeNS( ooNS::draw, "style" ))
978 {
979 TQString styleHash = draw->attributeNS( ooNS::draw, "style", TQString() );
980 if( styleHash == "single")
981 {
982 switch( angle )
983 {
984 case 0:
985 case 180:
986 brush.setAttribute( "style", 9 );
987 break;
988 case 45:
989 case 225:
990 brush.setAttribute( "style", 12 );
991 break;
992 case 90:
993 case 270:
994 brush.setAttribute( "style", 10 );
995 break;
996 case 135:
997 case 315:
998 brush.setAttribute( "style", 13 );
999 break;
1000 default:
1001 //todo fixme when we will have a kopaint
1002 kdDebug(30518)<<" draw:rotation 'angle' : "<<angle<<endl;
1003 break;
1004 }
1005 }
1006 else if( styleHash == "double")
1007 {
1008 switch( angle )
1009 {
1010 case 0:
1011 case 180:
1012 case 90:
1013 case 270:
1014 brush.setAttribute("style", 11 );
1015 break;
1016 case 45:
1017 case 135:
1018 case 225:
1019 case 315:
1020 brush.setAttribute("style",14 );
1021 break;
1022 default:
1023 //todo fixme when we will have a kopaint
1024 kdDebug(30518)<<" draw:rotation 'angle' : "<<angle<<endl;
1025 break;
1026 }
1027
1028 }
1029 else if( styleHash == "triple")
1030 {
1031 kdDebug(30518)<<" it is not implemented :( \n";
1032 }
1033
1034 }
1035 }
1036 e.appendChild( brush );
1037 }
1038 else if ( fill == "gradient" )
1039 {
1040 // We have to set a brush with brushstyle != no background fill
1041 // otherwise the properties dialog for the object won't
1042 // display the preview for the gradient.
1043 TQDomElement brush = doc.createElement( "BRUSH" );
1044 brush.setAttribute( "style", 1 );
1045 e.appendChild( brush );
1046
1047 TQDomElement gradient = doc.createElement( "GRADIENT" );
1048 TQString style = m_styleStack.attributeNS( ooNS::draw, "fill-gradient-name" );
1049
1050 TQDomElement* draw = m_draws[style];
1051 if ( draw )
1052 {
1053 gradient.setAttribute( "color1", draw->attributeNS( ooNS::draw, "start-color", TQString() ) );
1054 gradient.setAttribute( "color2", draw->attributeNS( ooNS::draw, "end-color", TQString() ) );
1055
1056 TQString type = draw->attributeNS( ooNS::draw, "style", TQString() );
1057 //kdDebug(30518)<<" type !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! :"<<type<<endl;
1058 if ( type == "linear" )
1059 {
1060 int angle = draw->attributeNS( ooNS::draw, "angle", TQString() ).toInt() / 10;
1061
1062 // make sure the angle is between 0 and 359
1063 angle = abs( angle );
1064 angle -= ( (int) ( angle / 360 ) ) * 360;
1065
1066 // What we are trying to do here is to find out if the given
1067 // angle belongs to a horizontal, vertical or diagonal gradient.
1068 int lower, upper, nearAngle = 0;
1069 for ( lower = 0, upper = 45; upper < 360; lower += 45, upper += 45 )
1070 {
1071 if ( upper >= angle )
1072 {
1073 int distanceToUpper = abs( angle - upper );
1074 int distanceToLower = abs( angle - lower );
1075 nearAngle = distanceToUpper > distanceToLower ? lower : upper;
1076 break;
1077 }
1078 }
1079 kdDebug(30518)<<"nearAngle :"<<nearAngle<<endl;
1080 // nearAngle should now be one of: 0, 45, 90, 135, 180...
1081 if ( nearAngle == 0 || nearAngle == 180 )
1082 gradient.setAttribute( "type", 1 ); // horizontal
1083 else if ( nearAngle == 90 || nearAngle == 270 )
1084 gradient.setAttribute( "type", 2 ); // vertical
1085 else if ( nearAngle == 45 || nearAngle == 225 )
1086 gradient.setAttribute( "type", 3 ); // diagonal 1
1087 else if ( nearAngle == 135 || nearAngle == 315 )
1088 gradient.setAttribute( "type", 4 ); // diagonal 2
1089 }
1090 else if ( type == "radial" || type == "ellipsoid" )
1091 gradient.setAttribute( "type", 5 ); // circle
1092 else if ( type == "square" || type == "rectangular" )
1093 gradient.setAttribute( "type", 6 ); // rectangle
1094 else if ( type == "axial" )
1095 gradient.setAttribute( "type", 7 ); // pipecross
1096
1097 // Hard to map between x- and y-center settings of ooimpress
1098 // and (un-)balanced settings of kpresenter. Let's try it.
1099 int x, y;
1100 if ( draw->hasAttributeNS( ooNS::draw, "cx" ) )
1101 x = draw->attributeNS( ooNS::draw, "cx", TQString() ).remove( '%' ).toInt();
1102 else
1103 x = 50;
1104
1105 if ( draw->hasAttributeNS( ooNS::draw, "cy" ) )
1106 y = draw->attributeNS( ooNS::draw, "cy", TQString() ).remove( '%' ).toInt();
1107 else
1108 y = 50;
1109
1110 if ( x == 50 && y == 50 )
1111 {
1112 gradient.setAttribute( "unbalanced", 0 );
1113 gradient.setAttribute( "xfactor", 100 );
1114 gradient.setAttribute( "yfactor", 100 );
1115 }
1116 else
1117 {
1118 gradient.setAttribute( "unbalanced", 1 );
1119 // map 0 - 100% to -200 - 200
1120 gradient.setAttribute( "xfactor", 4 * x - 200 );
1121 gradient.setAttribute( "yfactor", 4 * y - 200 );
1122 }
1123 }
1124 e.appendChild( gradient );
1125
1126 TQDomElement fillType = doc.createElement( "FILLTYPE" );
1127 fillType.setAttribute( "value", 1 );
1128 e.appendChild( fillType );
1129 }
1130 }
1131}
1132
1133void OoImpressImport::appendPie( TQDomDocument& doc, TQDomElement& e, const TQDomElement& object )
1134{
1135 TQDomElement angle = doc.createElement( "PIEANGLE" );
1136 int start = (int) ( object.attributeNS( ooNS::draw, "start-angle", TQString() ).toDouble() );
1137 angle.setAttribute( "value", start * 16 );
1138 e.appendChild( angle );
1139
1140 TQDomElement length = doc.createElement( "PIELENGTH" );
1141 int end = (int) ( object.attributeNS( ooNS::draw, "end-angle", TQString() ).toDouble() );
1142 if ( end < start )
1143 length.setAttribute( "value", ( 360 - start + end ) * 16 );
1144 else
1145 length.setAttribute( "value", ( end - start ) * 16 );
1146 e.appendChild( length );
1147}
1148
1149void OoImpressImport::appendImage( TQDomDocument& doc, TQDomElement& e, TQDomElement& p,
1150 const TQDomElement& object )
1151{
1152 TQString fileName = storeImage( object );
1153
1154 // create a key for the picture
1155 TQTime time = TQTime::currentTime();
1156 TQDate date = TQDate::currentDate();
1157
1158 TQDomElement image = doc.createElement( "KEY" );
1159 image.setAttribute( "msec", time.msec() );
1160 image.setAttribute( "second", time.second() );
1161 image.setAttribute( "minute", time.minute() );
1162 image.setAttribute( "hour", time.hour() );
1163 image.setAttribute( "day", date.day() );
1164 image.setAttribute( "month", date.month() );
1165 image.setAttribute( "year", date.year() );
1166 image.setAttribute( "filename", fileName );
1167 e.appendChild( image );
1168
1169 TQDomElement settings = doc.createElement( "PICTURESETTINGS" );
1170 if ( m_styleStack.hasAttributeNS( ooNS::draw, "color-mode" ) && ( m_styleStack.attributeNS( ooNS::draw, "color-mode" )=="greyscale" ) )
1171 settings.setAttribute( "grayscal", 1 );
1172 else
1173 settings.setAttribute( "grayscal", 0 );
1174
1175 if ( m_styleStack.hasAttributeNS( ooNS::draw, "luminance" ) )
1176 {
1177 TQString str( m_styleStack.attributeNS( ooNS::draw, "luminance" ) );
1178 str = str.remove( '%' );
1179 settings.setAttribute( "bright", str );
1180 }
1181 else
1182 settings.setAttribute( "bright", 0 );
1183
1184 settings.setAttribute( "mirrorType", 0 );
1185 settings.setAttribute( "swapRGB", 0 );
1186 settings.setAttribute( "depth", 0 );
1187 e.appendChild( settings );
1188
1189 TQDomElement effects = doc.createElement( "EFFECTS" );
1190 bool hasEffect = false;
1191 if ( m_styleStack.hasAttributeNS( ooNS::draw, "contrast" ) )
1192 {
1193 TQString str( m_styleStack.attributeNS( ooNS::draw, "contrast" ) );
1194 str = str.remove( '%' );
1195 int val = str.toInt();
1196 val = ( int )( 255.0 *val/100.0 );
1197 effects.setAttribute( "type", "5" );
1198 effects.setAttribute( "param1", TQString::number( val ) );
1199 hasEffect = true;
1200 }
1201 if ( hasEffect )
1202 e.appendChild( effects );
1203
1204 TQDomElement key = image.cloneNode().toElement();
1205 key.setAttribute( "name", "pictures/" + fileName );
1206 p.appendChild( key );
1207}
1208
1209void OoImpressImport::appendBackgroundImage( TQDomDocument& doc, TQDomElement& e,
1210 TQDomElement& p, const TQDomElement& object )
1211{
1212 TQString fileName = storeImage( object );
1213
1214 // create a key for the picture
1215 TQTime time = TQTime::currentTime();
1216 TQDate date = TQDate::currentDate();
1217
1218 TQDomElement image = doc.createElement( "BACKPICTUREKEY" );
1219 image.setAttribute( "msec", time.msec() );
1220 image.setAttribute( "second", time.second() );
1221 image.setAttribute( "minute", time.minute() );
1222 image.setAttribute( "hour", time.hour() );
1223 image.setAttribute( "day", date.day() );
1224 image.setAttribute( "month", date.month() );
1225 image.setAttribute( "year", date.year() );
1226 image.setAttribute( "filename", fileName );
1227 e.appendChild( image );
1228
1229 TQDomElement key = image.cloneNode().toElement();
1230 key.setTagName( "KEY" );
1231 key.setAttribute( "name", "pictures/" + fileName );
1232 p.appendChild( key );
1233}
1234
1235void OoImpressImport::appendBackgroundGradient( TQDomDocument& doc, TQDomElement& e,
1236 const TQDomElement& object )
1237{
1238 TQDomElement backColor1 = doc.createElement( "BACKCOLOR1" );
1239 backColor1.setAttribute( "color", object.attributeNS( ooNS::draw, "start-color", TQString() ) );
1240 e.appendChild( backColor1 );
1241
1242 TQDomElement backColor2 = doc.createElement( "BACKCOLOR2" );
1243 backColor2.setAttribute( "color", object.attributeNS( ooNS::draw, "end-color", TQString() ) );
1244 e.appendChild( backColor2 );
1245
1246 TQDomElement backType = doc.createElement( "BACKTYPE" );
1247 backType.setAttribute( "value", 0 ); // color/gradient
1248 e.appendChild( backType );
1249
1250 TQDomElement bcType = doc.createElement( "BCTYPE" );
1251 TQString type = object.attributeNS( ooNS::draw, "style", TQString() );
1252 if ( type == "linear" )
1253 {
1254 int angle = object.attributeNS( ooNS::draw, "angle", TQString() ).toInt() / 10;
1255
1256 // make sure the angle is between 0 and 359
1257 angle = abs( angle );
1258 angle -= ( (int) ( angle / 360 ) ) * 360;
1259
1260 // What we are trying to do here is to find out if the given
1261 // angle belongs to a horizontal, vertical or diagonal gradient.
1262 int lower, upper, nearAngle = 0;
1263 for ( lower = 0, upper = 45; upper < 360; lower += 45, upper += 45 )
1264 {
1265 if ( upper >= angle )
1266 {
1267 int distanceToUpper = abs( angle - upper );
1268 int distanceToLower = abs( angle - lower );
1269 nearAngle = distanceToUpper > distanceToLower ? lower : upper;
1270 break;
1271 }
1272 }
1273
1274 // nearAngle should now be one of: 0, 45, 90, 135, 180...
1275 if ( nearAngle == 0 || nearAngle == 180 )
1276 bcType.setAttribute( "value", 1 ); // horizontal
1277 else if ( nearAngle == 90 || nearAngle == 270 )
1278 bcType.setAttribute( "value", 2 ); // vertical
1279 else if ( nearAngle == 45 || nearAngle == 225 )
1280 bcType.setAttribute( "value", 3 ); // diagonal 1
1281 else if ( nearAngle == 135 || nearAngle == 315 )
1282 bcType.setAttribute( "value", 4 ); // diagonal 2
1283 }
1284 else if ( type == "radial" || type == "ellipsoid" )
1285 bcType.setAttribute( "value", 5 ); // circle
1286 else if ( type == "square" || type == "rectangular" )
1287 bcType.setAttribute( "value", 6 ); // rectangle
1288 else if ( type == "axial" )
1289 bcType.setAttribute( "value", 7 ); // pipecross
1290
1291 e.appendChild( bcType );
1292
1293 TQDomElement bGradient = doc.createElement( "BGRADIENT" );
1294
1295 // Hard to map between x- and y-center settings of ooimpress
1296 // and (un-)balanced settings of kpresenter. Let's try it.
1297 int x, y;
1298 if ( object.hasAttributeNS( ooNS::draw, "cx" ) )
1299 x = object.attributeNS( ooNS::draw, "cx", TQString() ).remove( '%' ).toInt();
1300 else
1301 x = 50;
1302
1303 if ( object.hasAttributeNS( ooNS::draw, "cy" ) )
1304 y = object.attributeNS( ooNS::draw, "cy", TQString() ).remove( '%' ).toInt();
1305 else
1306 y = 50;
1307
1308 if ( x == 50 && y == 50 )
1309 {
1310 bGradient.setAttribute( "unbalanced", 0 );
1311 bGradient.setAttribute( "xfactor", 100 );
1312 bGradient.setAttribute( "yfactor", 100 );
1313 }
1314 else
1315 {
1316 bGradient.setAttribute( "unbalanced", 1 );
1317 // map 0 - 100% to -200 - 200
1318 bGradient.setAttribute( "xfactor", 4 * x - 200 );
1319 bGradient.setAttribute( "yfactor", 4 * y - 200 );
1320 }
1321
1322 e.appendChild( bGradient );
1323}
1324
1325void OoImpressImport::appendRounding( TQDomDocument& doc, TQDomElement& e, const TQDomElement& object )
1326{
1327 if ( object.hasAttributeNS( ooNS::draw, "corner-radius" ) )
1328 {
1329 // kpresenter uses percent, ooimpress uses cm ... hmm?
1330 TQDomElement rounding = doc.createElement( "RNDS" );
1331 int corner = static_cast<int>(KoUnit::parseValue(object.attributeNS( ooNS::draw, "corner-radius", TQString())));
1332 rounding.setAttribute( "x", corner );
1333 rounding.setAttribute( "y", corner );
1334 e.appendChild( rounding );
1335 }
1336}
1337
1338void OoImpressImport::appendShadow( TQDomDocument& doc, TQDomElement& e )
1339{
1340 // Note that ooimpress makes a difference between shadowed text and
1341 // a shadowed object while kpresenter only knows the attribute 'shadow'.
1342 // This means that a shadowed textobject in kpresenter will always show
1343 // a shadowed text but no shadow for the object itself.
1344
1345 // make sure this is a textobject or textspan
1346 if ( !e.hasAttribute( "type" ) ||
1347 ( e.hasAttribute( "type" ) && e.attribute( "type" ) == "4" ) )
1348 {
1349 if ( m_styleStack.hasAttributeNS( ooNS::fo, "text-shadow" ) &&
1350 m_styleStack.attributeNS( ooNS::fo, "text-shadow" ) != "none" )
1351 {
1352 // use the shadow attribute to indicate a text-shadow
1353 TQDomElement shadow = doc.createElement( "SHADOW" );
1354 TQString distance = m_styleStack.attributeNS( ooNS::fo, "text-shadow" );
1355 distance.truncate( distance.find( ' ' ) );
1356 shadow.setAttribute( "distance", KoUnit::parseValue( distance ) );
1357 shadow.setAttribute( "direction", 5 );
1358 shadow.setAttribute( "color", "#a0a0a0" );
1359 e.appendChild( shadow );
1360 }
1361 }
1362 else if ( m_styleStack.hasAttributeNS( ooNS::draw, "shadow" ) &&
1363 m_styleStack.attributeNS( ooNS::draw, "shadow" ) == "visible" )
1364 {
1365 // use the shadow attribute to indicate an object-shadow
1366 TQDomElement shadow = doc.createElement( "SHADOW" );
1367 double x = KoUnit::parseValue( m_styleStack.attributeNS( ooNS::draw, "shadow-offset-x" ) );
1368 double y = KoUnit::parseValue( m_styleStack.attributeNS( ooNS::draw, "shadow-offset-y" ) );
1369
1370 if ( x < 0 && y < 0 )
1371 {
1372 shadow.setAttribute( "direction", 1 );
1373 shadow.setAttribute( "distance", (int) fabs ( x ) );
1374 }
1375 else if ( x == 0 && y < 0 )
1376 {
1377 shadow.setAttribute( "direction", 2 );
1378 shadow.setAttribute( "distance", (int) fabs ( y ) );
1379 }
1380 else if ( x > 0 && y < 0 )
1381 {
1382 shadow.setAttribute( "direction", 3 );
1383 shadow.setAttribute( "distance", (int) fabs ( x ) );
1384 }
1385 else if ( x > 0 && y == 0 )
1386 {
1387 shadow.setAttribute( "direction", 4 );
1388 shadow.setAttribute( "distance", (int) fabs ( x ) );
1389 }
1390 else if ( x > 0 && y > 0 )
1391 {
1392 shadow.setAttribute( "direction", 5 );
1393 shadow.setAttribute( "distance", (int) fabs ( x ) );
1394 }
1395 else if ( x == 0 && y > 0 )
1396 {
1397 shadow.setAttribute( "direction", 6 );
1398 shadow.setAttribute( "distance", (int) fabs ( y ) );
1399 }
1400 else if ( x < 0 && y > 0 )
1401 {
1402 shadow.setAttribute( "direction", 7 );
1403 shadow.setAttribute( "distance", (int) fabs ( x ) );
1404 }
1405 else if ( x < 0 && y == 0 )
1406 {
1407 shadow.setAttribute( "direction", 8 );
1408 shadow.setAttribute( "distance", (int) fabs ( x ) );
1409 }
1410
1411 if ( m_styleStack.hasAttributeNS( ooNS::draw, "shadow-color" ) )
1412 shadow.setAttribute( "color", m_styleStack.attributeNS( ooNS::draw, "shadow-color" ) );
1413
1414 e.appendChild( shadow );
1415 }
1416 if ( m_styleStack.hasAttributeNS( ooNS::draw, "size-protect" ) || m_styleStack.hasAttributeNS( ooNS::draw, "move-protect" ) )
1417 {
1418 bool b = ( m_styleStack.attributeNS( ooNS::draw, "size-protect" ) == "true" ) || ( m_styleStack.attributeNS( ooNS::draw, "move-protect" ) == "true" );
1419 if ( b )
1420 {
1421 TQDomElement protect = doc.createElement( "PROTECT" );
1422 protect.setAttribute("state" , b);
1423 e.appendChild(protect);
1424 }
1425 }
1426}
1427
1428void OoImpressImport::appendLineEnds( TQDomDocument& doc, TQDomElement& e, bool orderEndStartLine)
1429{
1430 const char* attr = orderEndStartLine ? "marker-start" : "marker-end";
1431 if ( m_styleStack.hasAttributeNS( ooNS::draw, attr ) )
1432 {
1433 TQDomElement lineBegin = doc.createElement( "LINEBEGIN" );
1434 TQString type = m_styleStack.attributeNS( ooNS::draw, attr );
1435 if ( type == "Arrow" || type == "Small Arrow" || type == "Rounded short Arrow" ||
1436 type == "Symmetric Arrow" || type == "Rounded large Arrow" || type == "Arrow concave" )
1437 lineBegin.setAttribute( "value", 1 );
1438 else if ( type == "Square" )
1439 lineBegin.setAttribute( "value", 2 );
1440 else if ( type == "Circle" || type == "Square 45" )
1441 lineBegin.setAttribute( "value", 3 );
1442 else if ( type == "Line Arrow" )
1443 lineBegin.setAttribute( "value", 4 );
1444 else if ( type == "Dimension Lines" )
1445 lineBegin.setAttribute( "value", 5 );
1446 else if ( type == "Double Arrow" )
1447 lineBegin.setAttribute( "value", 6 );
1448 e.appendChild( lineBegin );
1449 }
1450 attr = orderEndStartLine ? "marker-end" : "marker-start";
1451 if ( m_styleStack.hasAttributeNS( ooNS::draw, attr ) )
1452 {
1453 TQDomElement lineEnd = doc.createElement( "LINEEND" );
1454 TQString type = m_styleStack.attributeNS( ooNS::draw, attr );
1455 if ( type == "Arrow" || type == "Small Arrow" || type == "Rounded short Arrow" ||
1456 type == "Symmetric Arrow" || type == "Rounded large Arrow" || type == "Arrow concave" )
1457 lineEnd.setAttribute( "value", 1 );
1458 else if ( type == "Square" )
1459 lineEnd.setAttribute( "value", 2 );
1460 else if ( type == "Circle" || type == "Square 45" )
1461 lineEnd.setAttribute( "value", 3 );
1462 else if ( type == "Line Arrow" )
1463 lineEnd.setAttribute( "value", 4 );
1464 else if ( type == "Dimension Lines" )
1465 lineEnd.setAttribute( "value", 5 );
1466 else if ( type == "Double Arrow" )
1467 lineEnd.setAttribute( "value", 6 );
1468 e.appendChild( lineEnd );
1469 }
1470}
1471
1472void OoImpressImport::appendTextObjectMargin( TQDomDocument& /*doc*/, TQDomElement& e )
1473{
1474 if ( m_styleStack.hasAttributeNS( ooNS::fo, "padding" ) )
1475 {
1476 double tmpValue = KoUnit::parseValue(m_styleStack.attributeNS( ooNS::fo, "padding" ) );
1477 e.setAttribute( "btoppt", tmpValue );
1478 e.setAttribute( "bbottompt", tmpValue );
1479 e.setAttribute( "bleftpt", tmpValue );
1480 e.setAttribute( "brightpt", tmpValue );
1481 }
1482 else
1483 {
1484 if( m_styleStack.hasAttributeNS( ooNS::fo, "padding-top" ) )
1485 e.setAttribute( "btoppt", KoUnit::parseValue( m_styleStack.attributeNS( ooNS::fo, "padding-top" ) ) );
1486 if( m_styleStack.hasAttributeNS( ooNS::fo, "padding-bottom" ) )
1487 e.setAttribute( "bbottompt", KoUnit::parseValue( m_styleStack.attributeNS( ooNS::fo, "padding-bottom" ) ) );
1488 if( m_styleStack.hasAttributeNS( ooNS::fo, "padding-left" ) )
1489 e.setAttribute( "bleftpt", KoUnit::parseValue( m_styleStack.attributeNS( ooNS::fo, "padding-left" ) ) );
1490 if( m_styleStack.hasAttributeNS( ooNS::fo, "padding-right" ) )
1491 e.setAttribute( "brightpt", KoUnit::parseValue( m_styleStack.attributeNS( ooNS::fo, "padding-right" ) ) );
1492 }
1493}
1494
1495TQDomElement OoImpressImport::parseTextBox( TQDomDocument& doc, const TQDomElement& textBox )
1496{
1497 TQDomElement textObjectElement = doc.createElement( "TEXTOBJ" );
1498 appendTextObjectMargin( doc, textObjectElement );
1499
1500 // vertical alignment
1501 if ( m_styleStack.hasAttributeNS( ooNS::draw, "textarea-vertical-align" ) )
1502 {
1503 TQString alignment = m_styleStack.attributeNS( ooNS::draw, "textarea-vertical-align" );
1504 if ( alignment == "top" )
1505 textObjectElement.setAttribute( "verticalAlign", "top" );
1506 else if ( alignment == "middle" )
1507 textObjectElement.setAttribute( "verticalAlign", "center" );
1508 else if ( alignment == "bottom" )
1509 textObjectElement.setAttribute( "verticalAlign", "bottom" );
1510
1511 textObjectElement.setAttribute("verticalValue", 0.0);
1512 }
1513
1514 parseParagraphs( doc, textObjectElement, textBox );
1515
1516 return textObjectElement;
1517}
1518
1519void OoImpressImport::parseParagraphs( TQDomDocument& doc, TQDomElement& textObjectElement, const TQDomElement& parent )
1520{
1521 TQDomElement t;
1522 forEachElement( t, parent )
1523 {
1524 m_styleStack.save();
1525 const TQString localName = t.localName();
1526 const TQString ns = t.namespaceURI();
1527 const bool isTextNS = ns == ooNS::text;
1528
1529 TQDomElement e;
1530 if ( isTextNS && localName == "p" ) // text paragraph
1531 e = parseParagraph( doc, t );
1532 else if ( isTextNS && localName == "h" ) // heading - can this happen in ooimpress?
1533 {
1534 e = parseParagraph( doc, t );
1535 }
1536 else if ( isTextNS && ( localName == "unordered-list" || localName == "ordered-list" ) )
1537 {
1538 parseList( doc, textObjectElement, t );
1539 m_styleStack.restore();
1540 continue;
1541 }
1542 // TODO text:sequence-decls
1543 else
1544 {
1545 kdDebug(30518) << "Unsupported texttype '" << localName << "'" << endl;
1546 }
1547
1548 if ( !e.isNull() )
1549 textObjectElement.appendChild( e );
1550 m_styleStack.restore(); // remove the styles added by the paragraph or list
1551 }
1552}
1553
1554void OoImpressImport::applyListStyle( TQDomElement& paragraph )
1555{
1556 // Spec: see 3.3.5 p137
1557 if ( m_listStyleStack.hasListStyle() && m_nextItemIsListItem ) {
1558 //const TQDomElement listStyle = m_listStyleStack.currentListStyle();
1559 //bool heading = paragraph.localName() == "h";
1560 m_nextItemIsListItem = false;
1561 /*int level = heading ? paragraph.attributeNS( ooNS::text, "level", TQString() ).toInt()
1562 : m_listStyleStack.level();*/
1563
1564 TQDomElement counter = paragraph.ownerDocument().createElement( "COUNTER" );
1565 counter.setAttribute( "numberingtype", 0 );
1566 counter.setAttribute( "depth", 0 );
1567
1568 if ( m_insideOrderedList )
1569 counter.setAttribute( "type", 1 );
1570 else
1571 counter.setAttribute( "type", 10 ); // a disc bullet
1572 paragraph.appendChild( counter );
1573 }
1574}
1575
1576static TQDomElement findListLevelStyle( TQDomElement& fullListStyle, int level )
1577{
1578 TQDomElement listLevelItem;
1579 forEachElement( listLevelItem, fullListStyle )
1580 {
1581 if ( listLevelItem.attributeNS( ooNS::text, "level", TQString() ).toInt() == level )
1582 return listLevelItem;
1583 }
1584 return TQDomElement();
1585}
1586
1587bool OoImpressImport::pushListLevelStyle( const TQString& listStyleName, int level )
1588{
1589 TQDomElement* fullListStyle = m_listStyles[listStyleName];
1590 if ( !fullListStyle ) {
1591 kdWarning(30518) << "List style " << listStyleName << " not found!" << endl;
1592 return false;
1593 }
1594 else
1595 return pushListLevelStyle( listStyleName, *fullListStyle, level );
1596}
1597
1598bool OoImpressImport::pushListLevelStyle( const TQString& listStyleName, // for debug only
1599 TQDomElement& fullListStyle, int level )
1600{
1601 // Find applicable list-level-style for level
1602 int i = level;
1603 TQDomElement listLevelStyle;
1604 while ( i > 0 && listLevelStyle.isNull() ) {
1605 listLevelStyle = findListLevelStyle( fullListStyle, i );
1606 --i;
1607 }
1608 if ( listLevelStyle.isNull() ) {
1609 kdWarning(30518) << "List level style for level " << level << " in list style " << listStyleName << " not found!" << endl;
1610 return false;
1611 }
1612 kdDebug(30518) << "Pushing list-level-style from list-style " << listStyleName << " level " << level << endl;
1613 m_listStyleStack.push( listLevelStyle );
1614 return true;
1615}
1616
1617void OoImpressImport::parseList( TQDomDocument& doc, TQDomElement& textObjectElement, const TQDomElement& list )
1618{
1619 //kdDebug(30518) << k_funcinfo << "parseList"<< endl;
1620
1621 m_insideOrderedList = ( list.localName() == "ordered-list" );
1622 TQString oldListStyleName = m_currentListStyleName;
1623 if ( list.hasAttributeNS( ooNS::text, "style-name" ) )
1624 m_currentListStyleName = list.attributeNS( ooNS::text, "style-name", TQString() );
1625 bool listOK = !m_currentListStyleName.isEmpty();
1626 const int level = m_listStyleStack.level() + 1;
1627 //kdDebug(30518) << k_funcinfo << " listOK=" << listOK << " level=" << level << endl;
1628 if ( listOK )
1629 listOK = pushListLevelStyle( m_currentListStyleName, level );
1630
1631 // Iterate over list items
1632 TQDomElement listItem;
1633 forEachElement( listItem, list )
1634 {
1635 // It's either list-header (normal text on top of list) or list-item
1636 m_nextItemIsListItem = ( listItem.localName() != "list-header" );
1637 m_restartNumbering = -1;
1638 if ( listItem.hasAttributeNS( ooNS::text, "start-value" ) )
1639 m_restartNumbering = listItem.attributeNS( ooNS::text, "start-value", TQString() ).toInt();
1640 // ### Oasis: can be p h or list only.
1641 parseParagraphs( doc, textObjectElement, listItem );
1642 m_restartNumbering = -1;
1643 }
1644 if ( listOK )
1645 m_listStyleStack.pop();
1646 m_currentListStyleName = oldListStyleName;
1647}
1648
1649TQDomElement OoImpressImport::parseParagraph( TQDomDocument& doc, const TQDomElement& paragraph )
1650{
1651 TQDomElement p = doc.createElement( "P" );
1652
1653 // parse the paragraph-properties
1654 fillStyleStack( paragraph );
1655
1656 // Style name
1657 TQString styleName = m_styleStack.userStyleName("paragraph");
1658 if ( !styleName.isEmpty() )
1659 {
1660 TQDomElement nameElem = doc.createElement("NAME");
1661 nameElem.setAttribute("value", styleName);
1662 p.appendChild(nameElem);
1663 }
1664
1665 // Paragraph alignment
1666 if ( m_styleStack.hasAttributeNS( ooNS::fo, "text-align" ) )
1667 {
1668 TQString align = m_styleStack.attributeNS( ooNS::fo, "text-align" );
1669 if ( align == "center" )
1670 p.setAttribute( "align", 4 );
1671 else if ( align == "justify" )
1672 p.setAttribute( "align", 8 );
1673 else if ( align == "start" )
1674 p.setAttribute( "align", 0 );
1675 else if ( align == "end" )
1676 p.setAttribute( "align", 2 );
1677 }
1678 else
1679 p.setAttribute( "align", 0 ); // use left aligned as default
1680
1681
1682 // Offset before and after paragraph
1683 OoUtils::importTopBottomMargin( p, m_styleStack );
1684
1685 // Indentation (margins)
1686 OoUtils::importIndents( p, m_styleStack );
1687
1688 // Line spacing
1689 OoUtils::importLineSpacing( p, m_styleStack );
1690
1691 // Tabulators
1692 OoUtils::importTabulators( p, m_styleStack );
1693
1694 // Borders
1695 OoUtils::importBorders( p, m_styleStack );
1696
1697 applyListStyle( p );
1698
1699 uint pos = 0;
1700
1701 m_styleStack.save();
1702 // parse every childnode of the paragraph
1703 parseSpanOrSimilar( doc, paragraph, p, pos);
1704 m_styleStack.restore(); // remove possible garbage (should not be needed)
1705
1706 return p;
1707}
1708
1709void OoImpressImport::parseSpanOrSimilar( TQDomDocument& doc, const TQDomElement& parent,
1710 TQDomElement& outputParagraph, uint& pos)
1711{
1712 // Parse every child node of the parent
1713 // Can't use forEachElement here since we also care about text nodes
1714 for( TQDomNode node = parent.firstChild(); !node.isNull(); node = node.nextSibling() )
1715 {
1716 TQDomElement ts = node.toElement();
1717 TQString textData;
1718 const TQString localName( ts.localName() );
1719 const TQString ns = ts.namespaceURI();
1720 const bool isTextNS = ns == ooNS::text;
1721 TQDomText t = node.toText();
1722
1723 // Try to keep the order of the tag names by probability of happening
1724 if ( isTextNS && localName == "span" ) // text:span
1725 {
1726 m_styleStack.save();
1727 fillStyleStack( ts );
1728 parseSpanOrSimilar( doc, ts, outputParagraph, pos);
1729 m_styleStack.restore();
1730 }
1731 else if ( isTextNS && localName == "s" ) // text:s
1732 {
1733 textData = OoUtils::expandWhitespace(ts);
1734 }
1735 else if ( isTextNS && localName == "tab-stop" ) // text:tab-stop
1736 {
1737 // KPresenter currently uses \t.
1738 // Known bug: a line with only \t\t\t\t isn't loaded - XML (TQDom) strips out whitespace.
1739 // One more good reason to switch to <text:tab-stop> instead...
1740 textData = '\t';
1741 }
1742 else if ( isTextNS && localName == "line-break" )
1743 {
1744 textData = '\n';
1745 }
1746 else if ( localName == "image" && ns == ooNS::draw )
1747 {
1748 textData = '#'; // anchor placeholder
1749 // TODO
1750 }
1751 else if ( isTextNS && localName == "a" )
1752 {
1753 m_styleStack.save();
1754 TQString href( ts.attributeNS( ooNS::xlink, "href", TQString()) );
1755 if ( href.startsWith("#") )
1756 {
1757 // We have a reference to a bookmark (### TODO)
1758 // As we do not support it now, treat it as a <text:span> without formatting
1759 parseSpanOrSimilar( doc, ts, outputParagraph, pos);
1760 }
1761 else
1762 {
1763#if 0 // TODO
1764 // The problem is that KPresenter's hyperlink text is not inside the normal text, but for OOWriter it is nearly a <text:span>
1765 // So we have to fake.
1766 TQDomElement fakeParagraph, fakeFormats;
1767 uint fakePos=0;
1768 TQString text;
1769 parseSpanOrSimilar( doc, ts, fakeParagraph, fakeFormats, text, fakePos);
1770 textData = '#'; // hyperlink placeholder
1771 TQDomElement linkElement (doc.createElement("LINK"));
1772 linkElement.setAttribute("hrefName",ts.attributeNS( ooNS::xlink, "href", TQString()));
1773 linkElement.setAttribute("linkName",text);
1774 appendVariable(doc, ts, pos, "STRING", 9, text, linkElement);
1775#endif
1776 }
1777 m_styleStack.restore();
1778 }
1779 else if ( isTextNS &&
1780 (localName == "date" // fields
1781 || localName == "time"
1782 || localName == "page-number"
1783 || localName == "file-name"
1784 || localName == "author-name"
1785 || localName == "author-initials" ) )
1786 {
1787 textData = "#"; // field placeholder
1788 appendField(doc, outputParagraph, ts, pos);
1789 }
1790 else if ( t.isNull() ) // no textnode, we must ignore
1791 {
1792 kdWarning(30518) << "Ignoring tag " << ts.tagName() << endl;
1793 continue;
1794 }
1795 else
1796 textData = t.data();
1797
1798 pos += textData.length();
1799
1800 TQDomElement text = saveHelper(textData, doc);
1801
1802 kdDebug(30518) << k_funcinfo << "Para text is: " << textData << endl;
1803
1804 if (m_styleStack.hasAttributeNS( ooNS::fo, "language" )) {
1805 TQString lang = m_styleStack.attributeNS( ooNS::fo, "language" );
1806 if (lang=="en")
1807 text.setAttribute("language", "en_US");
1808 else
1809 text.setAttribute("language", lang);
1810 }
1811
1812 // parse the text-properties
1813 if ( m_styleStack.hasAttributeNS( ooNS::fo, "color" ) ) {
1814 kdDebug(30518) << "color=" << m_styleStack.attributeNS( ooNS::fo, "color" ) << endl;
1815 text.setAttribute( "color", m_styleStack.attributeNS( ooNS::fo, "color" ) );
1816 }
1817 if ( m_styleStack.hasAttributeNS( ooNS::fo, "font-family" ) // 3.10.9
1818 || m_styleStack.hasAttributeNS( ooNS::style, "font-name") )//3.10.8
1819 {
1820 // 'Thorndale/Albany' are not known outside OpenOffice so we substitute them
1821 // with 'Times New Roman/Arial' that look nearly the same.
1822 if ( m_styleStack.attributeNS( ooNS::fo, "font-family" ) == "Thorndale" )
1823 text.setAttribute( "family", "Times New Roman" );
1824 else if ( m_styleStack.attributeNS( ooNS::fo, "font-family" ) == "Albany" )
1825 text.setAttribute( "family", "Arial" );
1826 else
1827 text.setAttribute( "family", m_styleStack.attributeNS( ooNS::fo, "font-family" ).remove( "'" ) );
1828 }
1829 if ( m_styleStack.hasAttributeNS( ooNS::fo, "font-size" ) )
1830 {
1831 double pointSize = m_styleStack.fontSize();
1832 text.setAttribute( "pointSize", tqRound(pointSize) ); // KPresenter uses toInt()!
1833 }
1834 if ( m_styleStack.hasAttributeNS( ooNS::fo, "font-weight" ) ) // 3.10.24
1835 if ( m_styleStack.attributeNS( ooNS::fo, "font-weight" ) == "bold" )
1836 text.setAttribute( "bold", 1 );
1837 if ( m_styleStack.hasAttributeNS( ooNS::fo, "font-style" ) )
1838 if ( m_styleStack.attributeNS( ooNS::fo, "font-style" ) == "italic" )
1839 text.setAttribute( "italic", 1 );
1840
1841 if ( m_styleStack.hasAttributeNS( ooNS::style, "text-position" ) ) // 3.10.17
1842 {
1843 TQString text_position = m_styleStack.attributeNS( ooNS::style, "text-position");
1844 TQString value;
1845 TQString relativetextsize;
1846 OoUtils::importTextPosition( text_position, value, relativetextsize );
1847 text.setAttribute( "VERTALIGN", value );
1848 if ( !relativetextsize.isEmpty() )
1849 text.setAttribute( "relativetextsize", relativetextsize );
1850 }
1851
1852 bool wordByWord = (m_styleStack.hasAttributeNS( ooNS::fo, "score-spaces"))// 3.10.25
1853 && (m_styleStack.attributeNS( ooNS::fo, "score-spaces") == "false");
1854
1855 // strikeout
1856 if ( m_styleStack.hasAttributeNS( ooNS::style, "text-crossing-out")// 3.10.6
1857 && m_styleStack.attributeNS( ooNS::style, "text-crossing-out") != "none")
1858 {
1859 TQString strikeOutType = m_styleStack.attributeNS( ooNS::style, "text-crossing-out" );
1860 if ( strikeOutType =="double-line" )
1861 {
1862 text.setAttribute( "strikeOut", "double" );
1863 text.setAttribute( "strikeoutstyleline", "solid" );
1864 }
1865 else if ( strikeOutType =="thick-line" )
1866 {
1867 text.setAttribute( "strikeOut", "single-bold" );
1868 text.setAttribute( "strikeoutstyleline", "solid" );
1869 }
1870 else //if ( strikeOutType == "single-line" ) //fall back to the default strikeout
1871 {
1872 text.setAttribute( "strikeOut", "single" );
1873 text.setAttribute( "strikeoutstyleline", "solid" );
1874 }
1875
1876 if (wordByWord)
1877 text.setAttribute("wordbyword", 1);
1878 }
1879
1880 // underlining
1881 if ( m_styleStack.hasAttributeNS( ooNS::style, "text-underline" ) ) // 3.10.22
1882 {
1883 TQString underline;
1884 TQString styleline;
1885 OoUtils::importUnderline( m_styleStack.attributeNS( ooNS::style, "text-underline" ),
1886 underline, styleline );
1887 TQString underLineColor = m_styleStack.attributeNS( ooNS::style, "text-underline-color" );// 3.10.23
1888
1889 text.setAttribute( "value", underline );
1890 text.setAttribute( "styleline", styleline );
1891
1892 if ( !underLineColor.isEmpty() && underLineColor != "font-color" )
1893 text.setAttribute("underlinecolor", underLineColor);
1894 if ( wordByWord )
1895 text.setAttribute("wordbyword", 1);
1896 }
1897#if 0 // strange ooimpress doesn't implement it
1898 // Small caps, lowercase, uppercase
1899 if ( m_styleStack.hasAttributeNS( ooNS::fo, "font-variant" ) // 3.10.1
1900 || m_styleStack.hasAttributeNS( ooNS::fo, "text-transform" ) ) // 3.10.2
1901 {
1902 TQDomElement fontAttrib( doc.createElement( "FONTATTRIBUTE" ) );
1903 bool smallCaps = m_styleStack.attributeNS( ooNS::fo, "font-variant" ) == "small-caps";
1904 if ( smallCaps )
1905 {
1906 text.setAttribute( "fontattribute", "smallcaps" );
1907 } else
1908 {
1909 // Both KWord/KPresenter and OO use "uppercase" and "lowercase".
1910 // TODO in KWord: "capitalize".
1911 text.setAttribute( "fontattribute", m_styleStack.attributeNS( ooNS::fo, "text-transform" ) );
1912 }
1913 }
1914#endif
1915 // background color (property of the paragraph in OOo, of the text in kword/kpresenter)
1916 if (m_styleStack.hasAttributeNS( ooNS::fo, "background-color" ))
1917 {
1918 TQString bgColor = m_styleStack.attributeNS( ooNS::fo, "background-color");
1919 if (bgColor != "transparent")
1920 text.setAttribute("textbackcolor", bgColor);
1921 }
1922
1923 appendShadow( doc, outputParagraph ); // this is necessary to take care of shadowed paragraphs
1924 outputParagraph.appendChild( text );
1925 } // for each text span
1926}
1927
1928void OoImpressImport::createStyleMap( TQDomDocument &docstyles )
1929{
1930 TQDomElement styles = docstyles.documentElement();
1931 if ( styles.isNull() )
1932 return;
1933
1934 TQDomNode fixedStyles = KoDom::namedItemNS( styles, ooNS::office, "styles" );
1935 if ( !fixedStyles.isNull() )
1936 {
1937 insertDraws( fixedStyles.toElement() );
1938 insertStyles( fixedStyles.toElement() );
1939 insertStylesPresentation( fixedStyles.toElement() );
1940 }
1941
1942 TQDomNode automaticStyles = KoDom::namedItemNS( styles, ooNS::office, "automatic-styles" );
1943 if ( !automaticStyles.isNull() )
1944 {
1945 insertStyles( automaticStyles.toElement() );
1946 insertStylesPresentation( automaticStyles.toElement() );
1947 }
1948 TQDomNode masterStyles = KoDom::namedItemNS( styles, ooNS::office, "master-styles" );
1949 if ( !masterStyles.isNull() )
1950 insertStyles( masterStyles.toElement() );
1951}
1952
1953void OoImpressImport::insertDraws( const TQDomElement& styles )
1954{
1955 TQDomElement e;
1956 forEachElement( e, styles )
1957 {
1958 if ( !e.hasAttributeNS( ooNS::draw, "name" ) )
1959 continue;
1960
1961 TQString name = e.attributeNS( ooNS::draw, "name", TQString() );
1962 m_draws.insert( name, new TQDomElement( e ) );
1963 }
1964}
1965
1966void OoImpressImport::insertStyles( const TQDomElement& styles )
1967{
1968 TQDomElement e;
1969 forEachElement( e, styles )
1970 {
1971 const TQString localName = e.localName();
1972 const TQString ns = e.namespaceURI();
1973 if ( !e.hasAttributeNS( ooNS::style, "name" ) )
1974 continue;
1975
1976 const TQString name = e.attributeNS( ooNS::style, "name", TQString() );
1977 if ( localName == "list-style" && ns == ooNS::text ) {
1978 TQDomElement* ep = new TQDomElement( e );
1979 m_listStyles.insert( name, ep );
1980 kdDebug(30518) << "List style: '" << name << "' loaded " << endl;
1981 }
1982 else
1983 {
1984 m_styles.insert( name, new TQDomElement( e ) );
1985 kdDebug(30518) << "Style: '" << name << "' loaded " << endl;
1986 }
1987 }
1988}
1989
1990void OoImpressImport::insertStylesPresentation( const TQDomElement& styles )
1991{
1992 TQDomElement e;
1993 forEachElement( e, styles )
1994 {
1995 if ( !e.hasAttributeNS( ooNS::style, "name" ) )
1996 continue;
1997
1998 TQString name = e.attributeNS( ooNS::style, "name", TQString() );
1999 m_stylesPresentation.insert( name, new TQDomElement( e ) );
2000 //kdDebug(30518) << "Style: '" << name << "' loaded " << endl;
2001 }
2002}
2003
2004void OoImpressImport::fillStyleStack( const TQDomElement& object, bool sticky )
2005{
2006 // find all styles associated with an object and push them on the stack
2007 if ( object.hasAttributeNS( ooNS::presentation, "style-name" ) )
2008 {
2009 kdDebug(30518)<<" presentation:style-name **************************** :"<<object.attributeNS( ooNS::presentation, "style-name", TQString() )<<endl;
2010 if ( sticky )
2011 addStyles( m_stylesPresentation[object.attributeNS( ooNS::presentation, "style-name", TQString() )] );
2012 else
2013 addStyles( m_styles[object.attributeNS( ooNS::presentation, "style-name", TQString() )] );
2014 }
2015 if ( object.hasAttributeNS( ooNS::draw, "style-name" ) )
2016 addStyles( m_styles[object.attributeNS( ooNS::draw, "style-name", TQString() )] );
2017
2018 if ( object.hasAttributeNS( ooNS::draw, "text-style-name" ) )
2019 addStyles( m_styles[object.attributeNS( ooNS::draw, "text-style-name", TQString() )] );
2020
2021 if ( object.hasAttributeNS( ooNS::text, "style-name" ) ) {
2022 TQString styleName = object.attributeNS( ooNS::text, "style-name", TQString() );
2023 //kdDebug(30518) << "adding style " << styleName << endl;
2024 addStyles( m_styles[styleName] );
2025 }
2026}
2027
2028void OoImpressImport::addStyles( const TQDomElement* style )
2029{
2030 kdDebug(30518)<<" addStyle :" << style->attributeNS( ooNS::style, "name", TQString() ) <<endl;
2031 // this function is necessary as parent styles can have parents themself
2032 if ( style->hasAttributeNS( ooNS::style, "parent-style-name" ) )
2033 {
2034 //kdDebug(30518)<<"m_styles[style->attribute( style:parent-style-name )] :"<<m_styles[style->attributeNS( ooNS::style, "parent-style-name", TQString() )]<<endl;
2035 addStyles( m_styles[style->attributeNS( ooNS::style, "parent-style-name", TQString() )] );
2036 }
2037 //kdDebug(30518)<<" void OoImpressImport::addStyles( const TQDomElement* style ) :"<<style<<endl;
2038 m_styleStack.push( *style );
2039}
2040
2041TQString OoImpressImport::storeImage( const TQDomElement& object )
2042{
2043 // store the picture
2044 TQString url = object.attributeNS( ooNS::xlink, "href", TQString() ).remove( '#' );
2045 KArchiveFile* file = (KArchiveFile*) m_zip->directory()->entry( url );
2046
2047 TQString extension = url.mid( url.find( '.' ) );
2048 TQString fileName = TQString( "picture%1" ).arg( m_numPicture++ ) + extension;
2049 KoStoreDevice* out = m_chain->storageFile( "pictures/" + fileName, KoStore::Write );
2050
2051 if ( file && out )
2052 {
2053 TQByteArray buffer = file->data();
2054 out->writeBlock( buffer.data(), buffer.size() );
2055 }
2056
2057 return fileName;
2058}
2059
2060TQString OoImpressImport::storeSound(const TQDomElement & object, TQDomElement & p, TQDomDocument & doc)
2061{
2062 TQFileInfo fi(m_chain->inputFile()); // handle relative URLs
2063 TQDir::setCurrent(fi.dirPath(true));
2064 fi.setFile(object.attributeNS( ooNS::xlink, "href", TQString()));
2065 TQString url = fi.absFilePath();
2066
2067 //kdDebug(30518) << "Sound URL: " << url << endl;
2068
2069 TQFile file(url);
2070 if (!file.exists())
2071 return TQString();
2072
2073 TQString extension = url.mid( url.find( '.' ) );
2074 TQString fileName = TQString( "sound%1" ).arg( m_numSound++ ) + extension;
2075 fileName = "sounds/" + fileName;
2076 KoStoreDevice* out = m_chain->storageFile( fileName, KoStore::Write );
2077
2078 if (out)
2079 {
2080 if (!file.open(IO_ReadOnly))
2081 return TQString();
2082
2083 TQByteArray data(8*1024);
2084
2085 uint total = 0;
2086 for ( int block = 0; ( block = file.readBlock(data.data(), data.size()) ) > 0;
2087 total += block )
2088 out->writeBlock(data.data(), data.size());
2089
2090 Q_ASSERT(total == fi.size());
2091
2092 file.close();
2093 }
2094 else
2095 return TQString();
2096
2097 TQDomElement key = doc.createElement("FILE");
2098 key.setAttribute("name", fileName);
2099 key.setAttribute("filename", url);
2100 p.appendChild(key);
2101
2102 return url;
2103}
2104
2105TQDomElement OoImpressImport::saveHelper(const TQString &tmpText, TQDomDocument &doc)
2106{
2107 TQDomElement element=doc.createElement("TEXT");
2108
2109 if(tmpText.stripWhiteSpace().isEmpty()) // ### careful, this also strips \t and \n ....
2110 // working around a bug in TQDom
2111 element.setAttribute("whitespace", tmpText.length());
2112
2113 element.appendChild(doc.createTextNode(tmpText));
2114 return element;
2115}
2116
2117void OoImpressImport::appendPoints(TQDomDocument& doc, TQDomElement& e, const TQDomElement& object)
2118{
2119 TQDomElement ptsElem = doc.createElement("POINTS");
2120
2121 TQStringList ptList = TQStringList::split(' ', object.attributeNS( ooNS::draw, "points", TQString()));
2122
2123 TQString pt_x, pt_y;
2124 double tmp_x, tmp_y;
2125 for (TQStringList::Iterator it = ptList.begin(); it != ptList.end(); ++it)
2126 {
2127 TQDomElement point = doc.createElement("Point");
2128
2129 tmp_x = (*it).section(',',0,0).toInt() / 100;
2130 tmp_y = (*it).section(',',1,1).toInt() / 100;
2131
2132 pt_x.setNum(tmp_x);
2133 pt_x+="mm";
2134
2135 pt_y.setNum(tmp_y);
2136 pt_y+="mm";
2137
2138 point.setAttribute("point_x", KoUnit::parseValue(pt_x));
2139 point.setAttribute("point_y", KoUnit::parseValue(pt_y));
2140 ptsElem.appendChild(point);
2141 }
2142
2143 e.appendChild(ptsElem);
2144}
2145
2146void OoImpressImport::appendField(TQDomDocument& doc, TQDomElement& e, const TQDomElement& object, uint pos)
2147{
2148 const TQString tag = object.localName();
2149 const TQString ns = object.namespaceURI();
2150 const bool isTextNS = ns == ooNS::text;
2151
2152 TQDomElement custom = doc.createElement("CUSTOM");
2153 custom.setAttribute("pos", pos);
2154 TQDomElement variable = doc.createElement("VARIABLE");
2155
2156 if (isTextNS && tag == "date")
2157 {
2158 TQDateTime dt(TQDate::fromString(object.attributeNS( ooNS::text, "date-value", TQString()), TQt::ISODate));
2159
2160 bool fixed = (object.hasAttributeNS( ooNS::text, "fixed") && object.attributeNS( ooNS::text, "fixed", TQString())=="true");
2161
2162 if (!dt.isValid()) {
2163 dt = TQDateTime::currentDateTime(); // OOo docs say so :)
2164 fixed = false;
2165 }
2166
2167 TQDomElement typeElem = doc.createElement("TYPE");
2168 typeElem.setAttribute("key", "DATE0locale"); // ### find out the correlation between KOffice and OOo date/time types
2169 typeElem.setAttribute("type", 0); // VT_DATE
2170 typeElem.setAttribute("text", object.text());
2171
2172 variable.appendChild(typeElem);
2173
2174 const TQDate date(dt.date());
2175 const TQTime time(dt.time());
2176 TQDomElement dateElement = doc.createElement("DATE");
2177 dateElement.setAttribute("subtype", fixed ? 0 : 1); // VST_DATE_FIX, VST_DATE_CURRENT
2178 dateElement.setAttribute("fix", fixed ? 1 : 0);
2179 dateElement.setAttribute("day", date.day());
2180 dateElement.setAttribute("month", date.month());
2181 dateElement.setAttribute("year", date.year());
2182 dateElement.setAttribute("hour", time.hour());
2183 dateElement.setAttribute("minute", time.minute());
2184 dateElement.setAttribute("second", time.second());
2185 if (object.hasAttributeNS( ooNS::text, "date-adjust"))
2186 dateElement.setAttribute("correct", object.attributeNS( ooNS::text, "date-adjust", TQString()));
2187
2188 variable.appendChild(dateElement);
2189 }
2190 else if (isTextNS && tag == "time")
2191 {
2192 // Use TQDateTime to work around a possible problem of TQTime::FromString in Qt 3.2.2
2193 TQDateTime dt(TQDateTime::fromString(object.attributeNS( ooNS::text, "time-value", TQString()), TQt::ISODate));
2194
2195 bool fixed = (object.hasAttributeNS( ooNS::text, "fixed") && object.attributeNS( ooNS::text, "fixed", TQString())=="true");
2196
2197 if (!dt.isValid()) {
2198 dt = TQDateTime::currentDateTime(); // OOo docs say so :)
2199 fixed = false;
2200 }
2201
2202 TQDomElement typeElem = doc.createElement("TYPE");
2203 typeElem.setAttribute("key", "TIMElocale"); // ### find out the correlation between KOffice and OOo date/time types
2204 typeElem.setAttribute("type", 2); // VT_TIME
2205 typeElem.setAttribute("text", object.text());
2206
2207 variable.appendChild(typeElem);
2208
2209 const TQTime time(dt.time());
2210 TQDomElement timeElement = doc.createElement("TIME");
2211 timeElement.setAttribute("subtype", fixed ? 0 : 1); // VST_TIME_FIX, VST_TIME_CURRENT
2212 timeElement.setAttribute("fix", fixed ? 1 : 0);
2213 timeElement.setAttribute("hour", time.hour());
2214 timeElement.setAttribute("minute", time.minute());
2215 timeElement.setAttribute("second", time.second());
2216 /*if (object.hasAttributeNS( ooNS::text, "time-adjust"))
2217 timeElem.setAttribute("correct", object.attributeNS( ooNS::text, "time-adjust", TQString()));*/ // ### TODO
2218
2219 variable.appendChild(timeElement);
2220 }
2221 else if (isTextNS && tag == "page-number")
2222 {
2223 TQDomElement typeElem = doc.createElement("TYPE");
2224 typeElem.setAttribute("key", "NUMBER");
2225 typeElem.setAttribute("type", 4); // VT_PGNUM
2226 typeElem.setAttribute("text", object.text());
2227
2228 variable.appendChild(typeElem);
2229
2230 TQDomElement pgNumElem = doc.createElement("PGNUM");
2231
2232 int subtype = 0; // VST_PGNUM_CURRENT
2233
2234 if (object.hasAttributeNS( ooNS::text, "select-page"))
2235 {
2236 const TQString select = object.attributeNS( ooNS::text, "select-page", TQString());
2237
2238 if (select == "previous")
2239 subtype = 3; // VST_PGNUM_PREVIOUS
2240 else if (select == "next")
2241 subtype = 4; // VST_PGNUM_NEXT
2242 else
2243 subtype = 0; // VST_PGNUM_CURRENT
2244 }
2245
2246 pgNumElem.setAttribute("subtype", subtype);
2247 pgNumElem.setAttribute("value", object.text());
2248
2249 variable.appendChild(pgNumElem);
2250 }
2251 else if (isTextNS && tag == "file-name")
2252 {
2253 TQDomElement typeElem = doc.createElement("TYPE");
2254 typeElem.setAttribute("key", "STRING");
2255 typeElem.setAttribute("type", 8); // VT_FIELD
2256 typeElem.setAttribute("text", object.text());
2257
2258 variable.appendChild(typeElem);
2259
2260 int subtype = 5;
2261
2262 if (object.hasAttributeNS( ooNS::text, "display"))
2263 {
2264 const TQString display = object.attributeNS( ooNS::text, "display", TQString());
2265
2266 if (display == "path")
2267 subtype = 1; // VST_DIRECTORYNAME
2268 else if (display == "name")
2269 subtype = 6; // VST_FILENAMEWITHOUTEXTENSION
2270 else if (display == "name-and-extension")
2271 subtype = 0; // VST_FILENAME
2272 else
2273 subtype = 5; // VST_PATHFILENAME
2274 }
2275
2276 TQDomElement fileNameElem = doc.createElement("FIELD");
2277 fileNameElem.setAttribute("subtype", subtype);
2278 fileNameElem.setAttribute("value", object.text());
2279
2280 variable.appendChild(fileNameElem);
2281 }
2282 else if (isTextNS && tag == "author-name"
2283 || isTextNS && tag == "author-initials")
2284 {
2285 TQDomElement typeElem = doc.createElement("TYPE");
2286 typeElem.setAttribute("key", "STRING");
2287 typeElem.setAttribute("type", 8); // VT_FIELD
2288 typeElem.setAttribute("text", object.text());
2289
2290 variable.appendChild(typeElem);
2291
2292 int subtype = 2; // VST_AUTHORNAME
2293
2294 if (isTextNS && tag == "author-initials")
2295 subtype = 16; // VST_INITIAL
2296
2297 TQDomElement authorElem = doc.createElement("FIELD");
2298 authorElem.setAttribute("subtype", subtype);
2299 authorElem.setAttribute("value", object.text());
2300
2301 variable.appendChild(authorElem);
2302 }
2303
2304 custom.appendChild(variable);
2305 e.appendChild(custom);
2306}
2307
2308void OoImpressImport::createPresentationAnimation(const TQDomElement& element)
2309{
2310 int order = 0;
2311 TQDomElement e;
2312 forEachElement( e, element )
2313 {
2314 const TQString localName = e.localName();
2315 const TQString ns = e.namespaceURI();
2316 if ( ns == ooNS::presentation && localName == "show-shape" && e.hasAttributeNS( ooNS::draw, "shape-id" ) )
2317 {
2318 TQString name = e.attributeNS( ooNS::draw, "shape-id", TQString() );
2319 //kdDebug(30518)<<" insert animation style : name :"<<name<<endl;
2320 animationList *lst = new animationList;
2321 TQDomElement* ep = new TQDomElement( e );
2322 lst->element = ep;
2323 lst->order = order;
2324 m_animations.insert( name, lst );
2325 ++order;
2326 }
2327 }
2328}
2329
2330TQDomElement OoImpressImport::findAnimationByObjectID(const TQString & id, int & order)
2331{
2332 kdDebug(30518)<<"TQDomElement OoImpressImport::findAnimationByObjectID(const TQString & id) :"<<id<<endl;
2333 if (m_animations.isEmpty() )
2334 return TQDomElement();
2335
2336 animationList *animation = m_animations[id];
2337 //kdDebug(30518)<<"TQDomElement *animation = m_animations[id]; :"<<animation<<endl;
2338 if ( !animation )
2339 return TQDomElement();
2340 for (TQDomNode node = *( animation->element ); !node.isNull(); node = node.nextSibling())
2341 {
2342 TQDomElement e = node.toElement();
2343 order = animation->order;
2344 kdDebug(30518)<<"e.tagName() :"<<e.tagName()<<" e.attribute(draw:shape-id) :"<<e.attributeNS( ooNS::draw, "shape-id", TQString())<<endl;
2345 if (e.tagName()=="presentation:show-shape" && e.attributeNS( ooNS::draw, "shape-id", TQString())==id)
2346 return e;
2347 }
2348
2349 return TQDomElement();
2350}
2351
2352
2353void OoImpressImport::appendObjectEffect(TQDomDocument& doc, TQDomElement& e, const TQDomElement& object,
2354 TQDomElement& sound)
2355{
2356 int order = 0;
2357 TQDomElement origEffect = findAnimationByObjectID(object.attributeNS( ooNS::draw, "id", TQString()), order).toElement();
2358
2359 if (origEffect.isNull())
2360 return;
2361
2362 TQString effect = origEffect.attributeNS( ooNS::presentation, "effect", TQString());
2363 TQString dir = origEffect.attributeNS( ooNS::presentation, "direction", TQString());
2364 TQString speed = origEffect.attributeNS( ooNS::presentation, "speed", TQString());
2365 kdDebug(30518)<<"speed :"<<speed<<endl;
2366 //todo implement speed value.
2367
2368 int effVal=0;
2369 //kdDebug(30518)<<" effect :"<<effect<<" dir :"<<dir<<endl;
2370 if (effect=="fade")
2371 {
2372 if (dir=="from-right")
2373 effVal=10; // EF_WIPE_RIGHT
2374 else if (dir=="from-left")
2375 effVal=9; // EF_WIPE_LEFT
2376 else if (dir=="from-top")
2377 effVal=11; // EF_WIPE_TOP
2378 else if (dir=="from-bottom")
2379 effVal=12; // EF_WIPE_BOTTOM
2380 else
2381 return;
2382 }
2383 else if (effect=="move")
2384 {
2385 if (dir=="from-right")
2386 effVal=1; // EF_COME_RIGHT
2387 else if (dir=="from-left")
2388 effVal=2; // EF_COME_LEFT
2389 else if (dir=="from-top")
2390 effVal=3; // EF_COME_TOP
2391 else if (dir=="from-bottom")
2392 effVal=4; // EF_COME_BOTTOM
2393 else if (dir=="from-upper-right")
2394 effVal=5; // EF_COME_RIGHT_TOP
2395 else if (dir=="from-lower-right")
2396 effVal=6; // EF_COME_RIGHT_BOTTOM
2397 else if (dir=="from-upper-left")
2398 effVal=7; // EF_COME_LEFT_TOP
2399 else if (dir=="from-lower-left")
2400 effVal=8; // EF_COME_LEFT_BOTTOM
2401 else
2402 return;
2403 }
2404 else
2405 return; // sorry, no more supported effects :(
2406
2407 TQDomElement effElem = doc.createElement("EFFECTS");
2408 effElem.setAttribute("effect", effVal);
2409 e.appendChild(effElem);
2410
2411 TQDomElement presNum = doc.createElement( "PRESNUM" );
2412 presNum.setAttribute("value", order);
2413 e.appendChild( presNum );
2414
2415 // sound effect
2416 TQDomElement origSoundEff = KoDom::namedItemNS( origEffect, ooNS::presentation, "sound");
2417 if (!origSoundEff.isNull())
2418 {
2419 TQString soundUrl = storeSound(origSoundEff, sound, doc);
2420
2421 if (!soundUrl.isNull())
2422 {
2423 TQDomElement pseElem = doc.createElement("APPEARSOUNDEFFECT");
2424 pseElem.setAttribute("appearSoundEffect", 1);
2425 pseElem.setAttribute("appearSoundFileName", soundUrl);
2426
2427 e.appendChild(pseElem);
2428 }
2429 }
2430}
2431
2432#include "ooimpressimport.moc"