filters

ooimpressimport.cc

00001 // -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4; -*-
00002 /* This file is part of the KDE project
00003    Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com>
00004    Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "ooimpressimport.h"
00023 
00024 #include <math.h>
00025 
00026 #include <qregexp.h>
00027 #include <qdatetime.h>
00028 #include <qfileinfo.h>
00029 #include <qdir.h>
00030 
00031 #include <kzip.h>
00032 #include <karchive.h>
00033 #include <kdebug.h>
00034 #include <KoUnit.h>
00035 #include <KoDocumentInfo.h>
00036 #include <KoDocument.h>
00037 
00038 #include <kgenericfactory.h>
00039 #include <KoFilterChain.h>
00040 #include <KoGlobal.h>
00041 #include <ooutils.h>
00042 #include <KoDom.h>
00043 #include <KoOasisSettings.h>
00044 
00045 typedef KGenericFactory<OoImpressImport, KoFilter> OoImpressImportFactory;
00046 K_EXPORT_COMPONENT_FACTORY( libooimpressimport, OoImpressImportFactory( "kofficefilters" ) )
00047 
00048 
00049 OoImpressImport::OoImpressImport( KoFilter *, const char *, const QStringList & )
00050     : KoFilter(),
00051       m_numPicture( 1 ),
00052       m_numSound(1),
00053       m_styles( 23, true ),
00054       m_styleStack( ooNS::style, ooNS::fo )
00055 {
00056     m_styles.setAutoDelete( true );
00057     m_listStyles.setAutoDelete( true );
00058 }
00059 
00060 OoImpressImport::~OoImpressImport()
00061 {
00062     QDictIterator<animationList> it( m_animations ); // See QDictIterator
00063     for( ; it.current(); ++it )
00064     {
00065         delete it.current()->element;
00066     }
00067     m_animations.clear();
00068 }
00069 
00070 KoFilter::ConversionStatus OoImpressImport::convert( QCString const & from, QCString const & to )
00071 {
00072     kdDebug(30518) << "Entering Ooimpress Import filter: " << from << " - " << to << endl;
00073 
00074     if ( (from != "application/vnd.sun.xml.impress" && from != "application/vnd.sun.xml.impress.template" )
00075                 || to != "application/x-kpresenter" )
00076     {
00077         kdWarning(30518) << "Invalid mimetypes " << from << " " << to << endl;
00078         return KoFilter::NotImplemented;
00079     }
00080 
00081     m_zip = new KZip( m_chain->inputFile() );
00082 
00083     if ( !m_zip->open( IO_ReadOnly ) )
00084     {
00085         kdError(30518) << "Couldn't open the requested file "<< m_chain->inputFile() << endl;
00086         delete m_zip;
00087         return KoFilter::FileNotFound;
00088     }
00089 
00090     KoFilter::ConversionStatus preStatus = openFile();
00091 
00092     if ( preStatus != KoFilter::OK )
00093     {
00094         m_zip->close();
00095         delete m_zip;
00096         return preStatus;
00097     }
00098 
00099     QDomDocument docinfo;
00100     createDocumentInfo( docinfo );
00101 
00102     // store document info
00103     KoStoreDevice* out = m_chain->storageFile( "documentinfo.xml", KoStore::Write );
00104     if( out )
00105     {
00106         QCString info = docinfo.toCString();
00107         //kdDebug(30518) << " info :" << info << endl;
00108         // WARNING: we cannot use KoStore::write(const QByteArray&) because it gives an extra NULL character at the end.
00109         out->writeBlock( info , info.length() );
00110     }
00111 
00112     QDomDocument doccontent;
00113     createDocumentContent( doccontent );
00114 
00115     // store document content
00116     out = m_chain->storageFile( "maindoc.xml", KoStore::Write );
00117     if( out )
00118     {
00119         QCString content = doccontent.toCString();
00120         kdDebug(30518) << " content :" << content << endl;
00121         out->writeBlock( content , content.length() );
00122     }
00123 
00124     m_zip->close();
00125     delete m_zip;
00126 
00127     kdDebug(30518) << "######################## OoImpressImport::convert done ####################" << endl;
00128     return KoFilter::OK;
00129 }
00130 
00131 // Very related to OoWriterImport::openFile()
00132 KoFilter::ConversionStatus OoImpressImport::openFile()
00133 {
00134     KoFilter::ConversionStatus status = loadAndParse( "content.xml", m_content );
00135     if ( status != KoFilter::OK )
00136     {
00137         kdError(30518) << "Content.xml could not be parsed correctly! Aborting!" << endl;
00138         return status;
00139     }
00140 
00141     // We do not stop if the following calls fail.
00142     QDomDocument styles;
00143     loadAndParse( "styles.xml", styles );
00144     loadAndParse( "meta.xml", m_meta );
00145     loadAndParse( "settings.xml", m_settings );
00146 
00147     emit sigProgress( 10 );
00148     createStyleMap( styles );
00149 
00150     return KoFilter::OK;
00151 }
00152 
00153 KoFilter::ConversionStatus OoImpressImport::loadAndParse(const QString& filename, QDomDocument& doc)
00154 {
00155     return OoUtils::loadAndParse( filename, doc, m_zip);
00156 }
00157 
00158 // Very related to OoWriterImport::createDocumentInfo
00159 void OoImpressImport::createDocumentInfo( QDomDocument &docinfo )
00160 {
00161     docinfo = KoDocument::createDomDocument( "document-info" /*DTD name*/, "document-info" /*tag name*/, "1.1" );
00162 
00163     OoUtils::createDocumentInfo(m_meta, docinfo);
00164     //kdDebug(30518) << " meta-info :" << m_meta.toCString() << endl;
00165 }
00166 
00167 void OoImpressImport::createDocumentContent( QDomDocument &doccontent )
00168 {
00169     QDomDocument doc = KoDocument::createDomDocument( "kpresenter", "DOC", "1.2" );
00170     QDomElement docElement = doc.documentElement();
00171     docElement.setAttribute( "editor", "KPresenter" );
00172     docElement.setAttribute( "mime", "application/x-kpresenter" );
00173     docElement.setAttribute( "syntaxVersion", "2" );
00174 
00175     QDomElement content = m_content.documentElement();
00176 
00177     // content.xml contains some automatic-styles that we need to store
00178     QDomNode automaticStyles = KoDom::namedItemNS( content, ooNS::office, "automatic-styles" );
00179     if ( !automaticStyles.isNull() )
00180         insertStyles( automaticStyles.toElement() );
00181 
00182     QDomNode body = KoDom::namedItemNS( content, ooNS::office, "body" );
00183     if ( body.isNull() )
00184         return;
00185 
00186     QDomElement customSlideShow = doc.createElement( "CUSTOMSLIDESHOWCONFIG" );
00187 
00188     // presentation settings
00189     QDomElement settings = KoDom::namedItemNS( body, ooNS::presentation, "settings");
00190     if (!settings.isNull())
00191     {
00192         if (settings.attributeNS( ooNS::presentation, "endless", QString::null)=="true")
00193         {
00194             QDomElement infElem = doc.createElement("INFINITLOOP");
00195             infElem.setAttribute("value", 1);
00196             docElement.appendChild(infElem);
00197         }
00198 
00199         if (settings.attributeNS( ooNS::presentation, "show-end-of-presentation-slide", QString::null)=="true")
00200         {
00201             QDomElement infElem = doc.createElement("SHOWENDOFPRESENTATIONSLIDE");
00202             infElem.setAttribute("value", 1);
00203             docElement.appendChild(infElem);
00204         }
00205 
00206         if (settings.attributeNS( ooNS::presentation, "force-manual", QString::null)=="true")
00207         {
00208             QDomElement manualElem = doc.createElement("MANUALSWITCH");
00209             manualElem.setAttribute("value", 1);
00210             docElement.appendChild(manualElem);
00211         }
00212         if ( settings.hasAttributeNS( ooNS::presentation, "show") )
00213         {
00214             QDomElement defaultPage = doc.createElement("DEFAULTCUSTOMSLIDESHOWNAME");
00215             defaultPage.setAttribute("name", settings.attributeNS( ooNS::presentation, "show", QString::null) );
00216             docElement.appendChild(defaultPage);
00217         }
00218     }
00219 
00220     QDomElement presentationShow;
00221     forEachElement( presentationShow, settings )
00222     {
00223         if ( presentationShow.localName()=="show" && presentationShow.namespaceURI() == ooNS::presentation )
00224         {
00225             if ( presentationShow.hasAttributeNS( ooNS::presentation, "pages")  &&
00226                  presentationShow.hasAttributeNS( ooNS::presentation, "name"))
00227             {
00228                 QDomElement slide=doc.createElement("CUSTOMSLIDESHOW");
00229                 slide.setAttribute( "pages",  presentationShow.attributeNS( ooNS::presentation, "pages", QString::null ));
00230                 slide.setAttribute( "name", presentationShow.attributeNS( ooNS::presentation, "name", QString::null ));
00231                 customSlideShow.appendChild( slide );
00232             }
00233         }
00234     }
00235     // it seems that ooimpress has different paper-settings for every slide.
00236     // we take the settings of the first slide for the whole document.
00237     QDomElement drawPage = KoDom::namedItemNS( body, ooNS::draw, "page" );
00238     if ( drawPage.isNull() ) // no slides? give up.
00239         return;
00240 
00241     QDomElement objectElement = doc.createElement( "OBJECTS" );
00242     QDomElement pictureElement = doc.createElement( "PICTURES" );
00243     QDomElement pageTitleElement = doc.createElement( "PAGETITLES" );
00244     QDomElement pageNoteElement = doc.createElement( "PAGENOTES" );
00245     QDomElement backgroundElement = doc.createElement( "BACKGROUND" );
00246     QDomElement soundElement = doc.createElement( "SOUNDS" );
00247     QDomElement selSlideElement = doc.createElement( "SELSLIDES" );
00248     QDomElement helpLineElement = doc.createElement( "HELPLINES" );
00249     QDomElement attributeElement = doc.createElement( "ATTRIBUTES" );
00250     QDomElement *master = m_styles[drawPage.attributeNS( ooNS::draw, "master-page-name", QString::null )];
00251 
00252     appendObject(*master, doc, soundElement,pictureElement,pageNoteElement,objectElement, 0, true);
00253 
00254     QDomElement *style = m_styles[master->attributeNS( ooNS::style, "page-master-name", QString::null )];
00255     QDomElement properties = KoDom::namedItemNS( *style, ooNS::style, "properties" );
00256     //kdDebug(30518)<<" master->attribute( draw:style-name ) :"<<master->attributeNS( ooNS::draw, "style-name", QString::null )<<endl;
00257     QDomElement *backgroundStyle = m_stylesPresentation[ master->attributeNS( ooNS::draw, "style-name", QString::null ).isEmpty() ? "Standard-background" : master->attributeNS( ooNS::draw, "style-name", QString::null ) ];
00258 
00259     //kdDebug(30518)<<" backgroundStyle :"<<backgroundStyle<<endl;
00260     double pageHeight;
00261     QDomElement paperElement = doc.createElement( "PAPER" );
00262     if ( properties.isNull() )
00263     {
00264         paperElement.setAttribute( "ptWidth", CM_TO_POINT(28) );
00265         paperElement.setAttribute( "ptHeight", CM_TO_POINT(21) );
00266         paperElement.setAttribute( "unit", 0 );
00267         paperElement.setAttribute( "format", 5 );
00268         paperElement.setAttribute( "tabStopValue", 42.5198 );
00269         paperElement.setAttribute( "orientation", 0 );
00270         pageHeight = 21;
00271 
00272         QDomElement paperBorderElement = doc.createElement( "PAPERBORDERS" );
00273         paperBorderElement.setAttribute( "ptRight", 0 );
00274         paperBorderElement.setAttribute( "ptBottom", 0 );
00275         paperBorderElement.setAttribute( "ptLeft", 0 );
00276         paperBorderElement.setAttribute( "ptTop", 0 );
00277         paperElement.appendChild( paperBorderElement );
00278     }
00279     else
00280     {
00281         paperElement.setAttribute( "ptWidth", KoUnit::parseValue(properties.attributeNS( ooNS::fo, "page-width", QString::null ) ) );
00282         paperElement.setAttribute( "ptHeight", KoUnit::parseValue(properties.attributeNS( ooNS::fo, "page-height", QString::null ) ) );
00283 //         paperElement.setAttribute( "unit", 0 );
00284 //         paperElement.setAttribute( "format", 5 );
00285 //         paperElement.setAttribute( "tabStopValue", 42.5198 );
00286 //         paperElement.setAttribute( "orientation", 0 );
00287         // Keep pageHeight in cm to avoid rounding-errors that would
00288         // get multiplied with every new slide.
00289 
00290         if (properties.attributeNS( ooNS::style, "print-orientation", QString::null)=="portrait")
00291             paperElement.setAttribute("orientation", 0);
00292         else if (properties.attributeNS( ooNS::style, "print-orientation", QString::null)=="landscape")
00293             paperElement.setAttribute("orientation", 1);
00294 
00295 
00296 
00297         pageHeight = properties.attributeNS( ooNS::fo, "page-height", QString::null ).remove( "cm" ).toDouble();
00298 
00299         QDomElement paperBorderElement = doc.createElement( "PAPERBORDERS" );
00300         paperBorderElement.setAttribute( "ptRight", KoUnit::parseValue( properties.attributeNS( ooNS::fo, "margin-right", QString::null ) ) );
00301         paperBorderElement.setAttribute( "ptBottom", KoUnit::parseValue( properties.attributeNS( ooNS::fo, "margin-bottom", QString::null ) ) );
00302         paperBorderElement.setAttribute( "ptLeft", KoUnit::parseValue( properties.attributeNS( ooNS::fo, "margin-left", QString::null ) ) );
00303         paperBorderElement.setAttribute( "ptTop", KoUnit::parseValue( properties.attributeNS( ooNS::fo, "margin-top", QString::null ) ) );
00304         paperElement.appendChild( paperBorderElement );
00305     }
00306 
00307 
00308     // parse all pages
00309     forEachElement( drawPage, body )
00310     {
00311         if ( drawPage.localName()=="page" && drawPage.namespaceURI() == ooNS::draw && drawPage.hasAttributeNS( ooNS::draw, "id" ))
00312         {
00313             m_styleStack.clear(); // remove all styles
00314             fillStyleStack( drawPage );
00315             m_styleStack.save();
00316             int pagePos = drawPage.attributeNS( ooNS::draw, "id", QString::null ).toInt() - 1;
00317             // take care of a possible page background or slide transition or sound
00318             if ( m_styleStack.hasAttributeNS( ooNS::draw, "fill" )
00319                  || m_styleStack.hasAttributeNS( ooNS::presentation, "transition-style" ))
00320             {
00321                 appendBackgroundPage( doc, backgroundElement,pictureElement, soundElement );
00322             }
00323             else if ( !m_styleStack.hasAttributeNS( ooNS::draw, "fill" ) && backgroundStyle)
00324             {
00325                 m_styleStack.save();
00326                 m_styleStack.push( *backgroundStyle );
00327                 appendBackgroundPage( doc, backgroundElement,pictureElement, soundElement );
00328                 m_styleStack.restore();
00329                 kdDebug(30518)<<" load standard bacground \n";
00330             }
00331             if ( m_styleStack.hasAttributeNS( ooNS::presentation, "visibility" ) )
00332             {
00333                 QString str = m_styleStack.attributeNS( ooNS::presentation, "visibility" );
00334                 QDomElement slide = doc.createElement("SLIDE");
00335                 slide.setAttribute( "nr", pagePos );
00336                 slide.setAttribute( "show", ( ( str=="hidden" ) ? "0" : "1" ));
00337                 selSlideElement.appendChild( slide );
00338 
00339                 //todo add support
00340                 kdDebug(30518)<<"m_styleStack.hasAttribute( presentation:visibility ) :"<<str<<" position page "<<pagePos<<endl;
00341             }
00342             // set the pagetitle
00343             QDomElement titleElement = doc.createElement( "Title" );
00344             titleElement.setAttribute( "title", drawPage.attributeNS( ooNS::draw, "name", QString::null ) );
00345             pageTitleElement.appendChild( titleElement );
00346 
00347             // The '+1' is necessary to avoid that objects that start on the first line
00348             // of a slide will show up on the last line of the previous slide.
00349             double offset = CM_TO_POINT( ( drawPage.attributeNS( ooNS::draw, "id", QString::null ).toInt() - 1 ) * pageHeight ) + 1;
00350 
00351             // animations (object effects)
00352             createPresentationAnimation(KoDom::namedItemNS( drawPage, ooNS::presentation, "animations") );
00353 
00354             // parse all objects
00355             appendObject(drawPage, doc, soundElement,pictureElement,pageNoteElement,objectElement, offset);
00356 
00357             //m_animations.clear();
00358             m_styleStack.restore();
00359         }
00360     }
00361 
00362     docElement.appendChild( paperElement );
00363     docElement.appendChild( backgroundElement );
00364     if ( parseSettings( doc, helpLineElement, attributeElement ) )
00365         docElement.appendChild( helpLineElement );
00366     docElement.appendChild( attributeElement );
00367     docElement.appendChild( pageTitleElement );
00368     docElement.appendChild( pageNoteElement );
00369     docElement.appendChild( objectElement );
00370     docElement.appendChild( selSlideElement );
00371     docElement.appendChild( customSlideShow );
00372     docElement.appendChild( soundElement );
00373     docElement.appendChild( pictureElement );
00374 
00375     doccontent.appendChild( doc );
00376 }
00377 
00378 bool OoImpressImport::parseSettings( QDomDocument &doc, QDomElement &helpLineElement, QDomElement &attributeElement )
00379 {
00380     bool foundElement = false;
00381     KoOasisSettings settings( m_settings, ooNS::office, ooNS::config );
00382     KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" );
00383     //setUnit(KoUnit::unit(viewSettings.parseConfigItemString("unit")));
00384     KoOasisSettings::IndexedMap viewMap = viewSettings.indexedMap( "Views" );
00385     KoOasisSettings::Items firstView = viewMap.entry( 0 );
00386     //<config:config-item config:name="SnapLinesDrawing" config:type="string">V7939H1139</config:config-item>
00387     //by default show line
00388 
00389     if ( !firstView.isNull() )
00390     {
00391         QString str = firstView.parseConfigItemString( "SnapLinesDrawing" );
00392         if ( !str.isEmpty() )
00393         {
00394             parseHelpLine( doc, helpLineElement, str );
00395             //display it by default
00396             helpLineElement.setAttribute( "show", true );
00397             foundElement = true;
00398         }
00399 
00400         int gridX = firstView.parseConfigItemInt( "GridFineWidth" );
00401         int gridY = firstView.parseConfigItemInt( "GridFineHeight" );
00402         bool snapToGrid = firstView.parseConfigItemBool( "IsSnapToGrid" );
00403         int selectedPage = firstView.parseConfigItemInt( "SelectedPage" );
00404 
00405         attributeElement.setAttribute( "activePage", selectedPage );
00406         attributeElement.setAttribute( "gridx", MM_TO_POINT( gridX / 100.0 ) );
00407         attributeElement.setAttribute( "gridy", MM_TO_POINT( gridY / 100.0 ) );
00408         attributeElement.setAttribute( "snaptogrid", (int)snapToGrid );
00409 
00410     }
00411 
00412     //kdDebug(30518)<<" gridX :"<<gridX<<" gridY :"<<gridY<<" snapToGrid :"<<snapToGrid<<" selectedPage :"<<selectedPage<<endl;
00413     return foundElement;
00414 }
00415 
00416 void OoImpressImport::parseHelpLine( QDomDocument &doc,QDomElement &helpLineElement, const QString &text )
00417 {
00418     QString str;
00419     int newPos = text.length()-1; //start to element = 1
00420     for ( int pos = text.length()-1; pos >=0;--pos )
00421     {
00422         if ( text[pos]=='P' )
00423         {
00424 
00425             //point
00426             str = text.mid( pos+1, ( newPos-pos ) );
00427             QDomElement point=doc.createElement("HelpPoint");
00428 
00429             //kdDebug(30518)<<" point element  :"<< str <<endl;
00430             QStringList listVal = QStringList::split( ",", str );
00431             int posX = ( listVal[0].toInt()/100 );
00432             int posY = ( listVal[1].toInt()/100 );
00433             point.setAttribute("posX", MM_TO_POINT(  posX ));
00434             point.setAttribute("posY", MM_TO_POINT(  posY ));
00435 
00436             helpLineElement.appendChild( point );
00437             newPos = pos-1;
00438         }
00439         else if ( text[pos]=='V' )
00440         {
00441             QDomElement lines=doc.createElement("Vertical");
00442             //vertical element
00443             str = text.mid( pos+1, ( newPos-pos ) );
00444             //kdDebug(30518)<<" vertical  :"<< str <<endl;
00445             int posX = ( str.toInt()/100 );
00446             lines.setAttribute( "value",  MM_TO_POINT( posX ) );
00447             helpLineElement.appendChild( lines );
00448 
00449             newPos = ( pos-1 );
00450 
00451         }
00452         else if ( text[pos]=='H' )
00453         {
00454             //horizontal element
00455             QDomElement lines=doc.createElement("Horizontal");
00456             str = text.mid( pos+1, ( newPos-pos ) );
00457             //kdDebug(30518)<<" horizontal  :"<< str <<endl;
00458             int posY = ( str.toInt()/100 );
00459             lines.setAttribute( "value", MM_TO_POINT(  posY )  );
00460             helpLineElement.appendChild( lines );
00461             newPos = pos-1;
00462         }
00463     }
00464 }
00465 
00466 void OoImpressImport::appendObject(QDomNode & drawPage,  QDomDocument & doc,  QDomElement & soundElement, QDomElement & pictureElement, QDomElement & pageNoteElement, QDomElement &objectElement, double offset, bool sticky)
00467 {
00468     QDomElement o;
00469     forEachElement( o, drawPage )
00470     {
00471         const QString localName = o.localName();
00472         const QString ns = o.namespaceURI();
00473         const QString drawID = o.attributeNS( ooNS::draw, "id", QString::null);
00474         m_styleStack.save();
00475 
00476         QDomElement e;
00477         if ( localName == "text-box" && ns == ooNS::draw ) // textbox
00478         {
00479             fillStyleStack( o, sticky );
00480             e = doc.createElement( "OBJECT" );
00481             e.setAttribute( "type", 4 );
00482             if ( sticky )
00483                 e.setAttribute( "sticky", "1" );
00484             append2DGeometry( doc, e, o, (int)offset );
00485             appendName(doc, e, o);
00486             appendPen( doc, e );
00487             appendBrush( doc, e );
00488             appendRounding( doc, e, o );
00489             appendShadow( doc, e );
00490             appendObjectEffect(doc, e, o, soundElement);
00491             e.appendChild( parseTextBox( doc, o ) );
00492         }
00493         else if ( localName == "rect" && ns == ooNS::draw ) // rectangle
00494         {
00495             fillStyleStack( o, sticky );
00496             e = doc.createElement( "OBJECT" );
00497             e.setAttribute( "type", 2 );
00498             if ( sticky )
00499                 e.setAttribute( "sticky", "1" );
00500             append2DGeometry( doc, e, o, (int)offset );
00501             appendName(doc, e, o);
00502             appendPen( doc, e );
00503             appendBrush( doc, e );
00504             appendRounding( doc, e, o );
00505             appendShadow( doc, e );
00506 
00507             appendObjectEffect(doc, e, o, soundElement);
00508         }
00509         else if ( ( localName == "circle" || localName == "ellipse" ) && ns == ooNS::draw )
00510         {
00511             fillStyleStack( o, sticky );
00512             e = doc.createElement( "OBJECT" );
00513             if ( sticky )
00514                 e.setAttribute( "sticky", "1" );
00515             append2DGeometry( doc, e, o, (int)offset );
00516             appendName(doc, e, o);
00517             appendPen( doc, e );
00518             appendShadow( doc, e );
00519             appendLineEnds( doc, e );
00520             appendObjectEffect(doc, e, o, soundElement);
00521 
00522             if ( o.hasAttributeNS( ooNS::draw, "kind" ) ) // pie, chord or arc
00523             {
00524                 e.setAttribute( "type", 8 );
00525                 appendPie( doc, e, o );
00526                 QDomElement type = doc.createElement( "PIETYPE" );
00527 
00528                 QString kind = o.attributeNS( ooNS::draw, "kind", QString::null );
00529                 if ( kind == "section" )
00530                 {
00531                     appendBrush( doc, e );
00532                     type.setAttribute( "value", 0 );
00533                 }
00534                 else if ( kind == "cut" )
00535                 {
00536                     appendBrush( doc, e );
00537                     type.setAttribute( "value", 2 );
00538                 }
00539                 else if ( kind == "arc" )
00540                 {
00541                     // arc has no brush
00542                     type.setAttribute( "value", 1 );
00543                 }
00544                 e.appendChild( type );
00545             }
00546             else  // circle or ellipse
00547             {
00548                 e.setAttribute( "type", 3 );
00549                 appendBrush( doc, e );
00550             }
00551         }
00552         else if ( localName == "line" && ns == ooNS::draw ) // line
00553         {
00554             fillStyleStack( o, sticky );
00555             e = doc.createElement( "OBJECT" );
00556             e.setAttribute( "type", 1 );
00557             if ( sticky )
00558                 e.setAttribute( "sticky", "1" );
00559             bool orderEndStartLine = appendLineGeometry( doc, e, o, (int)offset );
00560             appendName(doc, e, o);
00561             appendPen( doc, e );
00562             appendBrush( doc, e );
00563             appendShadow( doc, e );
00564             appendLineEnds( doc, e, orderEndStartLine );
00565             appendObjectEffect(doc, e, o, soundElement);
00566         }
00567         else if ( localName=="polyline" && ns == ooNS::draw ) { // polyline
00568             fillStyleStack(o, sticky);
00569             e = doc.createElement("OBJECT");
00570             e.setAttribute("type", 12);
00571             if ( sticky )
00572                 e.setAttribute( "sticky", "1" );
00573             append2DGeometry(doc, e, o, (int)offset);
00574             appendName(doc, e, o);
00575             appendPoints(doc, e, o);
00576             appendPen(doc, e);
00577             appendBrush(doc, e);
00578             appendLineEnds(doc, e);
00579             //appendShadow(doc, e);
00580             appendObjectEffect(doc, e, o, soundElement);
00581         }
00582         else if ( localName=="polygon" && ns == ooNS::draw ) { // polygon
00583             fillStyleStack(o, sticky);
00584             e = doc.createElement("OBJECT");
00585             e.setAttribute("type", 16);
00586             if ( sticky )
00587                 e.setAttribute( "sticky", "1" );
00588             append2DGeometry(doc, e, o, (int)offset);
00589             appendName(doc, e, o);
00590             appendPoints(doc, e, o);
00591             appendPen(doc, e);
00592             appendBrush(doc, e);
00593             //appendLineEnds(doc, e);
00594             //appendShadow(doc, e);
00595             appendObjectEffect(doc, e, o, soundElement);
00596         }
00597         else if ( localName == "image" && ns == ooNS::draw ) // image
00598         {
00599             fillStyleStack( o, sticky );
00600             e = doc.createElement( "OBJECT" );
00601             e.setAttribute( "type", 0 );
00602             if ( sticky )
00603                 e.setAttribute( "sticky", "1" );
00604             append2DGeometry( doc, e, o, (int)offset );
00605             appendName(doc, e, o);
00606             appendImage( doc, e, pictureElement, o );
00607             appendObjectEffect(doc, e, o, soundElement);
00608         }
00609         else if ( localName == "object" && ns == ooNS::draw )
00610         {
00611             //todo add part object
00612         }
00613         else if ( localName == "g" && ns == ooNS::draw )
00614         {
00615             //todo add group object
00616         }
00617         else if ( localName == "path" && ns == ooNS::draw )
00618         {
00619             //todo add path object (freehand/cubic/quadricbeziercurve
00620         }
00621         else if ( localName == "notes" && ns == ooNS::presentation ) // notes
00622         {
00623             QDomNode textBox = KoDom::namedItemNS( o, ooNS::draw, "text-box" );
00624             if ( !textBox.isNull() )
00625             {
00626                 QString note;
00627                 QDomElement t;
00628                 forEachElement( t, textBox )
00629                 {
00630                     // We don't care about styles as they are not supported in kpresenter.
00631                     // Only add a linebreak for every child.
00632                     note += t.text() + "\n";
00633                 }
00634                 QDomElement notesElement = doc.createElement( "Note" );
00635                 notesElement.setAttribute( "note", note );
00636                 pageNoteElement.appendChild( notesElement );
00637             }
00638         }
00639         else
00640         {
00641             kdDebug(30518) << "Unsupported object '" << localName << "'" << endl;
00642             m_styleStack.restore();
00643             continue;
00644         }
00645 
00646         objectElement.appendChild( e );
00647         m_styleStack.restore();
00648     }
00649 }
00650 
00651 void OoImpressImport::appendBackgroundPage( QDomDocument &doc, QDomElement &backgroundElement, QDomElement & pictureElement,  QDomElement &soundElement)
00652 {
00653     QDomElement bgPage = doc.createElement( "PAGE" );
00654 
00655     // background
00656     if ( m_styleStack.hasAttributeNS( ooNS::draw, "fill" ) )
00657     {
00658         const QString fill = m_styleStack.attributeNS( ooNS::draw, "fill" );
00659         if ( fill == "solid" )
00660         {
00661             QDomElement backColor1 = doc.createElement( "BACKCOLOR1" );
00662             backColor1.setAttribute( "color", m_styleStack.attributeNS( ooNS::draw, "fill-color" ) );
00663             bgPage.appendChild( backColor1 );
00664 
00665             QDomElement bcType = doc.createElement( "BCTYPE" );
00666             bcType.setAttribute( "value", 0 ); // plain
00667             bgPage.appendChild( bcType );
00668 
00669             QDomElement backType = doc.createElement( "BACKTYPE" );
00670             backType.setAttribute( "value", 0 ); // color/gradient
00671             bgPage.appendChild( backType );
00672         }
00673         else if ( fill == "gradient" )
00674         {
00675             QString style = m_styleStack.attributeNS( ooNS::draw, "fill-gradient-name" );
00676             QDomElement* draw = m_draws[style];
00677             appendBackgroundGradient( doc, bgPage, *draw );
00678         }
00679         else if ( fill == "bitmap" )
00680         {
00681             QString style = m_styleStack.attributeNS( ooNS::draw, "fill-image-name" );
00682             QDomElement* draw = m_draws[style];
00683             appendBackgroundImage( doc, bgPage, pictureElement, *draw );
00684 
00685             QDomElement backView = doc.createElement( "BACKVIEW" );
00686             if ( m_styleStack.hasAttributeNS( ooNS::style, "repeat" ) )
00687             {
00688                 QString repeat = m_styleStack.attributeNS( ooNS::style, "repeat" );
00689                 if ( repeat == "stretch" )
00690                     backView.setAttribute( "value", 0 ); // zoomed
00691                 else if ( repeat == "no-repeat" )
00692                     backView.setAttribute( "value", 1 ); // centered
00693                 else
00694                     backView.setAttribute( "value", 2 ); // use tiled as default
00695             }
00696             else
00697                 backView.setAttribute( "value", 2 ); // use tiled as default
00698             bgPage.appendChild( backView );
00699 
00700             QDomElement backType = doc.createElement( "BACKTYPE" );
00701             backType.setAttribute( "value", 1 ); // image
00702             bgPage.appendChild( backType );
00703         }
00704     }
00705 
00706     if ( m_styleStack.hasAttributeNS( ooNS::presentation, "duration" ) )
00707     {
00708         QString str = m_styleStack.attributeNS( ooNS::presentation, "duration");
00709         kdDebug(30518)<<"styleStack.hasAttribute(presentation:duration ) :"<<str<<endl;
00710         //convert date duration
00711         int hour( str.mid( 2, 2 ).toInt() );
00712         int minute( str.mid( 5, 2 ).toInt() );
00713         int second( str.mid( 8, 2 ).toInt() );
00714         int pageTimer = second + minute*60 + hour*60*60;
00715         QDomElement pgEffect = doc.createElement("PGTIMER");
00716         pgEffect.setAttribute( "timer", pageTimer );
00717         bgPage.appendChild(pgEffect);
00718     }
00719     // slide transition
00720     if (m_styleStack.hasAttributeNS( ooNS::presentation, "transition-style"))
00721     {
00722         QDomElement pgEffect = doc.createElement("PGEFFECT");
00723 
00724         const QString effect = m_styleStack.attributeNS( ooNS::presentation, "transition-style");
00725         //kdDebug(30518) << "Transition name: " << effect << endl;
00726         int pef;
00727 
00728         if (effect=="vertical-stripes" || effect=="vertical-lines") // PEF_BLINDS_VER
00729             pef=14;
00730         else if (effect=="horizontal-stripes" || effect=="horizontal-lines") // PEF_BLINDS_HOR
00731             pef=13;
00732         else if (effect=="spiralin-left" || effect=="spiralin-right"
00733                  || effect== "spiralout-left" || effect=="spiralout-right") // PEF_SURROUND1
00734             pef=11;
00735         else if (effect=="fade-from-upperleft") // PEF_STRIPS_RIGHT_DOWN
00736             pef=39;
00737         else if (effect=="fade-from-upperright") // PEF_STRIPS_LEFT_DOWN
00738             pef=37;
00739         else if (effect=="fade-from-lowerleft") // PEF_STRIPS_RIGHT_UP
00740             pef=38;
00741         else if (effect=="fade-from-lowerright") // PEF_STRIPS_LEFT_UP
00742             pef=36;
00743         else if (effect=="fade-from-top") // PEF_COVER_DOWN
00744             pef=19;
00745         else if (effect=="fade-from-bottom") // PEF_COVER_UP
00746             pef=21;
00747         else if (effect=="fade-from-left") // PEF_COVER_RIGHT
00748             pef=25;
00749         else if (effect=="fade-from-right") // PEF_COVER_LEFT
00750             pef=23;
00751         else if (effect=="fade-to-center") // PEF_CLOSE_ALL
00752             pef=3;
00753         else if (effect=="fade-from-center") // PEF_OPEN_ALL
00754             pef=6;
00755         else if (effect=="open-vertical") // PEF_OPEN_HORZ; really, no kidding ;)
00756             pef=4;
00757         else if (effect=="open-horizontal") // PEF_OPEN_VERT
00758             pef=5;
00759         else if (effect=="close-vertical") // PEF_CLOSE_HORZ
00760             pef=1;
00761         else if (effect=="close-horizontal") // PEF_CLOSE_VERT
00762             pef=2;
00763         else if (effect=="dissolve") // PEF_DISSOLVE; perfect hit ;)
00764             pef=35;
00765         else if (effect=="horizontal-checkerboard") // PEF_CHECKBOARD_ACROSS
00766             pef=17;
00767         else if (effect=="vertical-checkerboard") // PEF_CHECKBOARD_DOWN
00768             pef=18;
00769         else if (effect=="roll-from-left") // PEF_UNCOVER_RIGHT
00770             pef=26;
00771         else if (effect=="roll-from-right") // PEF_UNCOVER_LEFT
00772             pef=24;
00773         else if (effect=="roll-from-bottom") // PEF_UNCOVER_UP
00774             pef=22;
00775         else if (effect=="roll-from-top") // PEF_UNCOVER_DOWN
00776             pef=20;
00777         else if (effect=="random") // PEF_RANDOM
00778             pef=-1;
00779         else         // we choose a random transition instead of the unsupported ones ;)
00780             pef=-1;
00781 
00782         pgEffect.setAttribute("value", pef);
00783         bgPage.appendChild(pgEffect);
00784     }
00785 
00786     // slide transition sound
00787     if (m_styleStack.hasChildNodeNS( ooNS::presentation, "sound"))
00788     {
00789         QString soundUrl = storeSound(m_styleStack.childNodeNS( ooNS::presentation, "sound"),
00790                                       soundElement, doc);
00791 
00792         if (!soundUrl.isNull())
00793         {
00794             QDomElement pseElem = doc.createElement("PGSOUNDEFFECT");
00795             pseElem.setAttribute("soundEffect", 1);
00796             pseElem.setAttribute("soundFileName", soundUrl);
00797 
00798             bgPage.appendChild(pseElem);
00799         }
00800     }
00801 
00802     backgroundElement.appendChild(bgPage);
00803 }
00804 
00805 void OoImpressImport::appendName(QDomDocument& doc, QDomElement& e, const QDomElement& object)
00806 {
00807     if( object.hasAttributeNS( ooNS::draw, "name" ))
00808         {
00809             QDomElement name = doc.createElement( "OBJECTNAME" );
00810             name.setAttribute( "objectName", object.attributeNS( ooNS::draw, "name", QString::null ));
00811             e.appendChild( name );
00812         }
00813 }
00814 
00815 void OoImpressImport::append2DGeometry( QDomDocument& doc, QDomElement& e, const QDomElement& object, int offset )
00816 {
00817     QDomElement orig = doc.createElement( "ORIG" );
00818     orig.setAttribute( "x", KoUnit::parseValue( object.attributeNS( ooNS::svg, "x", QString::null ) ) );
00819     orig.setAttribute( "y", KoUnit::parseValue( object.attributeNS( ooNS::svg, "y", QString::null ) ) + offset );
00820     e.appendChild( orig );
00821 
00822     QDomElement size = doc.createElement( "SIZE" );
00823     size.setAttribute( "width", KoUnit::parseValue( object.attributeNS( ooNS::svg, "width", QString::null ) ) );
00824     size.setAttribute( "height", KoUnit::parseValue( object.attributeNS( ooNS::svg, "height", QString::null ) ) );
00825     e.appendChild( size );
00826     if( object.hasAttributeNS( ooNS::draw, "transform" ))
00827         {
00828             kdDebug(30518)<<" object transform \n";
00829             //todo parse it
00830             QString transform = object.attributeNS( ooNS::draw, "transform", QString::null );
00831             if( transform.contains("rotate ("))
00832                 {
00833                     //kdDebug(30518)<<" rotate object \n";
00834                     transform = transform.remove("rotate (" );
00835                     transform = transform.left(transform.find(")"));
00836                     //kdDebug(30518)<<" transform :"<<transform<<endl;
00837                     bool ok;
00838                     double radian = transform.toDouble(&ok);
00839                     if( ok )
00840                         {
00841                             QDomElement angle = doc.createElement( "ANGLE" );
00842                             //angle is defined as a radian in oo but degree into kpresenter.
00843                             angle.setAttribute("value", (-1 * ((radian*180)/M_PI)));
00844 
00845                             e.appendChild( angle );
00846                         }
00847                 }
00848         }
00849 }
00850 
00851 //return true if (x1 < x2) necessary to load correctly start-line and end-line
00852 bool OoImpressImport::appendLineGeometry( QDomDocument& doc, QDomElement& e, const QDomElement& object, int offset )
00853 {
00854     double x1 = KoUnit::parseValue( object.attributeNS( ooNS::svg, "x1", QString::null ) );
00855     double y1 = KoUnit::parseValue( object.attributeNS( ooNS::svg, "y1", QString::null ) );
00856     double x2 = KoUnit::parseValue( object.attributeNS( ooNS::svg, "x2", QString::null ) );
00857     double y2 = KoUnit::parseValue( object.attributeNS( ooNS::svg, "y2", QString::null ) );
00858 
00859     double x = QMIN( x1, x2 );
00860     double y = QMIN( y1, y2 );
00861 
00862     QDomElement orig = doc.createElement( "ORIG" );
00863     orig.setAttribute( "x", x );
00864     orig.setAttribute( "y", y + offset );
00865     e.appendChild( orig );
00866 
00867     QDomElement size = doc.createElement( "SIZE" );
00868     size.setAttribute( "width", fabs( x1 - x2 ) );
00869     size.setAttribute( "height", fabs( y1 - y2 ) );
00870     e.appendChild( size );
00871 
00872     QDomElement linetype = doc.createElement( "LINETYPE" );
00873     if ( ( x1 < x2 && y1 < y2 ) || ( x1 > x2 && y1 > y2 ) )
00874         linetype.setAttribute( "value", 2 );
00875     else
00876         linetype.setAttribute( "value", 3 );
00877 
00878     e.appendChild( linetype );
00879     return (x1 < x2);
00880 }
00881 
00882 void OoImpressImport::appendPen( QDomDocument& doc, QDomElement& e )
00883 {
00884     if ( m_styleStack.hasAttributeNS( ooNS::draw, "stroke" ))
00885     {
00886         QDomElement pen = doc.createElement( "PEN" );
00887         if ( m_styleStack.attributeNS( ooNS::draw, "stroke" ) == "none" )
00888             pen.setAttribute( "style", 0 );
00889         else if ( m_styleStack.attributeNS( ooNS::draw, "stroke" ) == "solid" )
00890             pen.setAttribute( "style", 1 );
00891         else if ( m_styleStack.attributeNS( ooNS::draw, "stroke" ) == "dash" )
00892         {
00893             QString style = m_styleStack.attributeNS( ooNS::draw, "stroke-dash" );
00894             if ( style == "Ultrafine Dashed" || style == "Fine Dashed" ||
00895                  style == "Fine Dashed (var)" || style == "Dashed (var)" )
00896                 pen.setAttribute( "style", 2 );
00897             else if ( style == "Fine Dotted" || style == "Ultrafine Dotted (var)" ||
00898                       style == "Line with Fine Dots" )
00899                 pen.setAttribute( "style", 3 );
00900             else if ( style == "3 Dashes 3 Dots (var)" || style == "Ultrafine 2 Dots 3 Dashes" )
00901                 pen.setAttribute( "style", 4 );
00902             else if ( style == "2 Dots 1 Dash" )
00903                 pen.setAttribute( "style", 5 );
00904         }
00905 
00906         if ( m_styleStack.hasAttributeNS( ooNS::svg, "stroke-width" ) )
00907             pen.setAttribute( "width", (int) KoUnit::parseValue( m_styleStack.attributeNS( ooNS::svg, "stroke-width" ) ) );
00908         if ( m_styleStack.hasAttributeNS( ooNS::svg, "stroke-color" ) )
00909             pen.setAttribute( "color", m_styleStack.attributeNS( ooNS::svg, "stroke-color" ) );
00910         e.appendChild( pen );
00911     }
00912 }
00913 
00914 void OoImpressImport::appendBrush( QDomDocument& doc, QDomElement& e )
00915 {
00916     if ( m_styleStack.hasAttributeNS( ooNS::draw, "fill" ) )
00917     {
00918         const QString fill = m_styleStack.attributeNS( ooNS::draw, "fill" );
00919         //kdDebug(30518)<<"void OoImpressImport::appendBrush( QDomDocument& doc, QDomElement& e ) :"<<fill<<endl;
00920         if (  fill == "solid"  )
00921         {
00922             QDomElement brush = doc.createElement( "BRUSH" );
00923             if ( m_styleStack.hasAttributeNS( ooNS::draw, "transparency" ) )
00924             {
00925                 QString transparency = m_styleStack.attributeNS( ooNS::draw, "transparency" );
00926                 transparency = transparency.remove( '%' );
00927                 int value = transparency.toInt();
00928                 if ( value >= 94 && value <= 99 )
00929                 {
00930                     brush.setAttribute( "style", 2 );
00931                 }
00932                 else if ( value>=64 && value <= 93 )
00933                 {
00934                     brush.setAttribute( "style", 3 );
00935                 }
00936                 else if ( value>=51 && value <= 63 )
00937                 {
00938                     brush.setAttribute( "style", 4 );
00939                 }
00940                 else if ( value>=38 && value <= 50 )
00941                 {
00942                     brush.setAttribute( "style", 5 );
00943                 }
00944                 else if ( value>=13 && value <= 37 )
00945                 {
00946                     brush.setAttribute( "style", 6 );
00947                 }
00948                 else if ( value>=7 && value <= 12 )
00949                 {
00950                     brush.setAttribute( "style", 7 );
00951                 }
00952                 else if ( value>=1 && value <= 6 )
00953                 {
00954                     brush.setAttribute( "style", 8 );
00955                 }
00956             }
00957             else
00958                 brush.setAttribute( "style", 1 );
00959             if ( m_styleStack.hasAttributeNS( ooNS::draw, "fill-color" ) )
00960                 brush.setAttribute( "color", m_styleStack.attributeNS( ooNS::draw, "fill-color" ) );
00961             e.appendChild( brush );
00962         }
00963         else if ( fill == "hatch" )
00964         {
00965             QDomElement brush = doc.createElement( "BRUSH" );
00966             QString style = m_styleStack.attributeNS( ooNS::draw, "fill-hatch-name" );
00967             QDomElement* draw = m_draws[style];
00968             if ( draw )
00969                 {
00970                     if( draw->hasAttributeNS( ooNS::draw, "color" ) )
00971                         brush.setAttribute( "color", draw->attributeNS( ooNS::draw, "color", QString::null ) );
00972                     int angle = 0;
00973                     if( draw->hasAttributeNS( ooNS::draw, "rotation" ))
00974                         {
00975                             angle = (draw->attributeNS( ooNS::draw, "rotation", QString::null ).toInt())/10;
00976                             kdDebug(30518)<<"angle :"<<angle<<endl;
00977                         }
00978                     if( draw->hasAttributeNS( ooNS::draw, "style" ))
00979                         {
00980                             QString styleHash = draw->attributeNS( ooNS::draw, "style", QString::null );
00981                             if( styleHash == "single")
00982                                 {
00983                                     switch( angle )
00984                                         {
00985                                         case 0:
00986                                         case 180:
00987                                             brush.setAttribute( "style", 9 );
00988                                             break;
00989                                         case 45:
00990                                         case 225:
00991                                             brush.setAttribute( "style", 12 );
00992                                             break;
00993                                         case 90:
00994                                         case 270:
00995                                             brush.setAttribute( "style", 10 );
00996                                             break;
00997                                         case 135:
00998                                         case 315:
00999                                             brush.setAttribute( "style", 13 );
01000                                             break;
01001                                         default:
01002                                             //todo fixme when we will have a kopaint
01003                                             kdDebug(30518)<<" draw:rotation 'angle' : "<<angle<<endl;
01004                                             break;
01005                                         }
01006                                 }
01007                             else if( styleHash == "double")
01008                                 {
01009                                     switch( angle )
01010                                         {
01011                                         case 0:
01012                                         case 180:
01013                                         case 90:
01014                                         case 270:
01015                                             brush.setAttribute("style", 11 );
01016                                             break;
01017                                         case 45:
01018                                         case 135:
01019                                         case 225:
01020                                         case 315:
01021                                             brush.setAttribute("style",14 );
01022                                             break;
01023                                         default:
01024                                             //todo fixme when we will have a kopaint
01025                                             kdDebug(30518)<<" draw:rotation 'angle' : "<<angle<<endl;
01026                                             break;
01027                                         }
01028 
01029                                 }
01030                             else if( styleHash == "triple")
01031                                 {
01032                                     kdDebug(30518)<<" it is not implemented :( \n";
01033                                 }
01034 
01035                         }
01036                 }
01037             e.appendChild( brush );
01038         }
01039         else if ( fill == "gradient" )
01040         {
01041             // We have to set a brush with brushstyle != no background fill
01042             // otherwise the properties dialog for the object won't
01043             // display the preview for the gradient.
01044             QDomElement brush = doc.createElement( "BRUSH" );
01045             brush.setAttribute( "style", 1 );
01046             e.appendChild( brush );
01047 
01048             QDomElement gradient = doc.createElement( "GRADIENT" );
01049             QString style = m_styleStack.attributeNS( ooNS::draw, "fill-gradient-name" );
01050 
01051             QDomElement* draw = m_draws[style];
01052             if ( draw )
01053             {
01054                 gradient.setAttribute( "color1", draw->attributeNS( ooNS::draw, "start-color", QString::null ) );
01055                 gradient.setAttribute( "color2", draw->attributeNS( ooNS::draw, "end-color", QString::null ) );
01056 
01057                 QString type = draw->attributeNS( ooNS::draw, "style", QString::null );
01058                 //kdDebug(30518)<<" type !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! :"<<type<<endl;
01059                 if ( type == "linear" )
01060                 {
01061                     int angle = draw->attributeNS( ooNS::draw, "angle", QString::null ).toInt() / 10;
01062 
01063                     // make sure the angle is between 0 and 359
01064                     angle = abs( angle );
01065                     angle -= ( (int) ( angle / 360 ) ) * 360;
01066 
01067                     // What we are trying to do here is to find out if the given
01068                     // angle belongs to a horizontal, vertical or diagonal gradient.
01069                     int lower, upper, nearAngle = 0;
01070                     for ( lower = 0, upper = 45; upper < 360; lower += 45, upper += 45 )
01071                     {
01072                         if ( upper >= angle )
01073                         {
01074                             int distanceToUpper = abs( angle - upper );
01075                             int distanceToLower = abs( angle - lower );
01076                             nearAngle = distanceToUpper > distanceToLower ? lower : upper;
01077                             break;
01078                         }
01079                     }
01080                     kdDebug(30518)<<"nearAngle :"<<nearAngle<<endl;
01081                     // nearAngle should now be one of: 0, 45, 90, 135, 180...
01082                     if ( nearAngle == 0 || nearAngle == 180 )
01083                         gradient.setAttribute( "type", 1 ); // horizontal
01084                     else if ( nearAngle == 90 || nearAngle == 270 )
01085                         gradient.setAttribute( "type", 2 ); // vertical
01086                     else if ( nearAngle == 45 || nearAngle == 225 )
01087                         gradient.setAttribute( "type", 3 ); // diagonal 1
01088                     else if ( nearAngle == 135 || nearAngle == 315 )
01089                         gradient.setAttribute( "type", 4 ); // diagonal 2
01090                 }
01091                 else if ( type == "radial" || type == "ellipsoid" )
01092                     gradient.setAttribute( "type", 5 ); // circle
01093                 else if ( type == "square" || type == "rectangular" )
01094                     gradient.setAttribute( "type", 6 ); // rectangle
01095                 else if ( type == "axial" )
01096                     gradient.setAttribute( "type", 7 ); // pipecross
01097 
01098                 // Hard to map between x- and y-center settings of ooimpress
01099                 // and (un-)balanced settings of kpresenter. Let's try it.
01100                 int x, y;
01101                 if ( draw->hasAttributeNS( ooNS::draw, "cx" ) )
01102                     x = draw->attributeNS( ooNS::draw, "cx", QString::null ).remove( '%' ).toInt();
01103                 else
01104                     x = 50;
01105 
01106                 if ( draw->hasAttributeNS( ooNS::draw, "cy" ) )
01107                     y = draw->attributeNS( ooNS::draw, "cy", QString::null ).remove( '%' ).toInt();
01108                 else
01109                     y = 50;
01110 
01111                 if ( x == 50 && y == 50 )
01112                 {
01113                     gradient.setAttribute( "unbalanced", 0 );
01114                     gradient.setAttribute( "xfactor", 100 );
01115                     gradient.setAttribute( "yfactor", 100 );
01116                 }
01117                 else
01118                 {
01119                     gradient.setAttribute( "unbalanced", 1 );
01120                     // map 0 - 100% to -200 - 200
01121                     gradient.setAttribute( "xfactor", 4 * x - 200 );
01122                     gradient.setAttribute( "yfactor", 4 * y - 200 );
01123                 }
01124             }
01125             e.appendChild( gradient );
01126 
01127             QDomElement fillType = doc.createElement( "FILLTYPE" );
01128             fillType.setAttribute( "value", 1 );
01129             e.appendChild( fillType );
01130         }
01131     }
01132 }
01133 
01134 void OoImpressImport::appendPie( QDomDocument& doc, QDomElement& e, const QDomElement& object )
01135 {
01136     QDomElement angle = doc.createElement( "PIEANGLE" );
01137     int start = (int) ( object.attributeNS( ooNS::draw, "start-angle", QString::null ).toDouble() );
01138     angle.setAttribute( "value",  start * 16 );
01139     e.appendChild( angle );
01140 
01141     QDomElement length = doc.createElement( "PIELENGTH" );
01142     int end = (int) ( object.attributeNS( ooNS::draw, "end-angle", QString::null ).toDouble() );
01143     if ( end < start )
01144         length.setAttribute( "value",  ( 360 - start + end ) * 16 );
01145     else
01146         length.setAttribute( "value",  ( end - start ) * 16 );
01147     e.appendChild( length );
01148 }
01149 
01150 void OoImpressImport::appendImage( QDomDocument& doc, QDomElement& e, QDomElement& p,
01151                                    const QDomElement& object )
01152 {
01153     QString fileName = storeImage( object );
01154 
01155     // create a key for the picture
01156     QTime time = QTime::currentTime();
01157     QDate date = QDate::currentDate();
01158 
01159     QDomElement image = doc.createElement( "KEY" );
01160     image.setAttribute( "msec", time.msec() );
01161     image.setAttribute( "second", time.second() );
01162     image.setAttribute( "minute", time.minute() );
01163     image.setAttribute( "hour", time.hour() );
01164     image.setAttribute( "day", date.day() );
01165     image.setAttribute( "month", date.month() );
01166     image.setAttribute( "year", date.year() );
01167     image.setAttribute( "filename", fileName );
01168     e.appendChild( image );
01169 
01170     QDomElement settings = doc.createElement( "PICTURESETTINGS" );
01171     if ( m_styleStack.hasAttributeNS( ooNS::draw, "color-mode" ) &&  ( m_styleStack.attributeNS( ooNS::draw, "color-mode" )=="greyscale" ) )
01172         settings.setAttribute( "grayscal", 1 );
01173     else
01174         settings.setAttribute( "grayscal", 0 );
01175 
01176     if ( m_styleStack.hasAttributeNS( ooNS::draw, "luminance" ) )
01177     {
01178         QString str( m_styleStack.attributeNS( ooNS::draw, "luminance" ) );
01179         str = str.remove( '%' );
01180         settings.setAttribute( "bright", str );
01181     }
01182     else
01183         settings.setAttribute( "bright", 0 );
01184 
01185     settings.setAttribute( "mirrorType", 0 );
01186     settings.setAttribute( "swapRGB", 0 );
01187     settings.setAttribute( "depth", 0 );
01188     e.appendChild( settings );
01189 
01190     QDomElement effects = doc.createElement( "EFFECTS" );
01191     bool hasEffect = false;
01192     if ( m_styleStack.hasAttributeNS( ooNS::draw, "contrast" ) )
01193     {
01194         QString str( m_styleStack.attributeNS( ooNS::draw, "contrast" ) );
01195         str = str.remove( '%' );
01196         int val = str.toInt();
01197         val = ( int )( 255.0 *val/100.0 );
01198         effects.setAttribute( "type", "5" );
01199         effects.setAttribute( "param1", QString::number( val ) );
01200         hasEffect = true;
01201     }
01202     if ( hasEffect )
01203         e.appendChild( effects );
01204 
01205     QDomElement key = image.cloneNode().toElement();
01206     key.setAttribute( "name", "pictures/" + fileName );
01207     p.appendChild( key );
01208 }
01209 
01210 void OoImpressImport::appendBackgroundImage( QDomDocument& doc, QDomElement& e,
01211                                              QDomElement& p, const QDomElement& object )
01212 {
01213     QString fileName = storeImage( object );
01214 
01215     // create a key for the picture
01216     QTime time = QTime::currentTime();
01217     QDate date = QDate::currentDate();
01218 
01219     QDomElement image = doc.createElement( "BACKPICTUREKEY" );
01220     image.setAttribute( "msec", time.msec() );
01221     image.setAttribute( "second", time.second() );
01222     image.setAttribute( "minute", time.minute() );
01223     image.setAttribute( "hour", time.hour() );
01224     image.setAttribute( "day", date.day() );
01225     image.setAttribute( "month", date.month() );
01226     image.setAttribute( "year", date.year() );
01227     image.setAttribute( "filename", fileName );
01228     e.appendChild( image );
01229 
01230     QDomElement key = image.cloneNode().toElement();
01231     key.setTagName( "KEY" );
01232     key.setAttribute( "name", "pictures/" + fileName );
01233     p.appendChild( key );
01234 }
01235 
01236 void OoImpressImport::appendBackgroundGradient( QDomDocument& doc, QDomElement& e,
01237                                                 const QDomElement& object )
01238 {
01239     QDomElement backColor1 = doc.createElement( "BACKCOLOR1" );
01240     backColor1.setAttribute( "color", object.attributeNS( ooNS::draw, "start-color", QString::null ) );
01241     e.appendChild( backColor1 );
01242 
01243     QDomElement backColor2 = doc.createElement( "BACKCOLOR2" );
01244     backColor2.setAttribute( "color", object.attributeNS( ooNS::draw, "end-color", QString::null ) );
01245     e.appendChild( backColor2 );
01246 
01247     QDomElement backType = doc.createElement( "BACKTYPE" );
01248     backType.setAttribute( "value", 0 ); // color/gradient
01249     e.appendChild( backType );
01250 
01251     QDomElement bcType = doc.createElement( "BCTYPE" );
01252     QString type = object.attributeNS( ooNS::draw, "style", QString::null );
01253     if ( type == "linear" )
01254     {
01255         int angle = object.attributeNS( ooNS::draw, "angle", QString::null ).toInt() / 10;
01256 
01257         // make sure the angle is between 0 and 359
01258         angle = abs( angle );
01259         angle -= ( (int) ( angle / 360 ) ) * 360;
01260 
01261         // What we are trying to do here is to find out if the given
01262         // angle belongs to a horizontal, vertical or diagonal gradient.
01263         int lower, upper, nearAngle = 0;
01264         for ( lower = 0, upper = 45; upper < 360; lower += 45, upper += 45 )
01265         {
01266             if ( upper >= angle )
01267             {
01268                 int distanceToUpper = abs( angle - upper );
01269                 int distanceToLower = abs( angle - lower );
01270                 nearAngle = distanceToUpper > distanceToLower ? lower : upper;
01271                 break;
01272             }
01273         }
01274 
01275         // nearAngle should now be one of: 0, 45, 90, 135, 180...
01276         if ( nearAngle == 0 || nearAngle == 180 )
01277             bcType.setAttribute( "value", 1 ); // horizontal
01278         else if ( nearAngle == 90 || nearAngle == 270 )
01279             bcType.setAttribute( "value", 2 ); // vertical
01280         else if ( nearAngle == 45 || nearAngle == 225 )
01281             bcType.setAttribute( "value", 3 ); // diagonal 1
01282         else if ( nearAngle == 135 || nearAngle == 315 )
01283             bcType.setAttribute( "value", 4 ); // diagonal 2
01284     }
01285     else if ( type == "radial" || type == "ellipsoid" )
01286         bcType.setAttribute( "value", 5 ); // circle
01287     else if ( type == "square" || type == "rectangular" )
01288         bcType.setAttribute( "value", 6 ); // rectangle
01289     else if ( type == "axial" )
01290         bcType.setAttribute( "value", 7 ); // pipecross
01291 
01292     e.appendChild( bcType );
01293 
01294     QDomElement bGradient = doc.createElement( "BGRADIENT" );
01295 
01296     // Hard to map between x- and y-center settings of ooimpress
01297     // and (un-)balanced settings of kpresenter. Let's try it.
01298     int x, y;
01299     if ( object.hasAttributeNS( ooNS::draw, "cx" ) )
01300         x = object.attributeNS( ooNS::draw, "cx", QString::null ).remove( '%' ).toInt();
01301     else
01302         x = 50;
01303 
01304     if ( object.hasAttributeNS( ooNS::draw, "cy" ) )
01305         y = object.attributeNS( ooNS::draw, "cy", QString::null ).remove( '%' ).toInt();
01306     else
01307         y = 50;
01308 
01309     if ( x == 50 && y == 50 )
01310     {
01311         bGradient.setAttribute( "unbalanced", 0 );
01312         bGradient.setAttribute( "xfactor", 100 );
01313         bGradient.setAttribute( "yfactor", 100 );
01314     }
01315     else
01316     {
01317         bGradient.setAttribute( "unbalanced", 1 );
01318         // map 0 - 100% to -200 - 200
01319         bGradient.setAttribute( "xfactor", 4 * x - 200 );
01320         bGradient.setAttribute( "yfactor", 4 * y - 200 );
01321     }
01322 
01323     e.appendChild( bGradient );
01324 }
01325 
01326 void OoImpressImport::appendRounding( QDomDocument& doc, QDomElement& e, const QDomElement& object )
01327 {
01328     if ( object.hasAttributeNS( ooNS::draw, "corner-radius" ) )
01329     {
01330         // kpresenter uses percent, ooimpress uses cm ... hmm?
01331         QDomElement rounding = doc.createElement( "RNDS" );
01332         int corner = static_cast<int>(KoUnit::parseValue(object.attributeNS( ooNS::draw, "corner-radius", QString::null)));
01333         rounding.setAttribute( "x", corner );
01334         rounding.setAttribute( "y", corner );
01335         e.appendChild( rounding );
01336     }
01337 }
01338 
01339 void OoImpressImport::appendShadow( QDomDocument& doc, QDomElement& e )
01340 {
01341     // Note that ooimpress makes a difference between shadowed text and
01342     // a shadowed object while kpresenter only knows the attribute 'shadow'.
01343     // This means that a shadowed textobject in kpresenter will always show
01344     // a shadowed text but no shadow for the object itself.
01345 
01346     // make sure this is a textobject or textspan
01347     if ( !e.hasAttribute( "type" ) ||
01348          ( e.hasAttribute( "type" ) && e.attribute( "type" ) == "4" ) )
01349     {
01350         if ( m_styleStack.hasAttributeNS( ooNS::fo, "text-shadow" ) &&
01351              m_styleStack.attributeNS( ooNS::fo, "text-shadow" ) != "none" )
01352         {
01353             // use the shadow attribute to indicate a text-shadow
01354             QDomElement shadow = doc.createElement( "SHADOW" );
01355             QString distance = m_styleStack.attributeNS( ooNS::fo, "text-shadow" );
01356             distance.truncate( distance.find( ' ' ) );
01357             shadow.setAttribute( "distance", KoUnit::parseValue( distance ) );
01358             shadow.setAttribute( "direction", 5 );
01359             shadow.setAttribute( "color", "#a0a0a0" );
01360             e.appendChild( shadow );
01361         }
01362     }
01363     else if ( m_styleStack.hasAttributeNS( ooNS::draw, "shadow" ) &&
01364               m_styleStack.attributeNS( ooNS::draw, "shadow" ) == "visible" )
01365     {
01366         // use the shadow attribute to indicate an object-shadow
01367         QDomElement shadow = doc.createElement( "SHADOW" );
01368         double x = KoUnit::parseValue( m_styleStack.attributeNS( ooNS::draw, "shadow-offset-x" ) );
01369         double y = KoUnit::parseValue( m_styleStack.attributeNS( ooNS::draw, "shadow-offset-y" ) );
01370 
01371         if ( x < 0 && y < 0 )
01372         {
01373             shadow.setAttribute( "direction", 1 );
01374             shadow.setAttribute( "distance", (int) fabs ( x ) );
01375         }
01376         else if ( x == 0 && y < 0 )
01377         {
01378             shadow.setAttribute( "direction", 2 );
01379             shadow.setAttribute( "distance", (int) fabs ( y ) );
01380         }
01381         else if ( x > 0 && y < 0 )
01382         {
01383             shadow.setAttribute( "direction", 3 );
01384             shadow.setAttribute( "distance", (int) fabs ( x ) );
01385         }
01386         else if ( x > 0 && y == 0 )
01387         {
01388             shadow.setAttribute( "direction", 4 );
01389             shadow.setAttribute( "distance", (int) fabs ( x ) );
01390         }
01391         else if ( x > 0 && y > 0 )
01392         {
01393             shadow.setAttribute( "direction", 5 );
01394             shadow.setAttribute( "distance", (int) fabs ( x ) );
01395         }
01396         else if ( x == 0 && y > 0 )
01397         {
01398             shadow.setAttribute( "direction", 6 );
01399             shadow.setAttribute( "distance", (int) fabs ( y ) );
01400         }
01401         else if ( x < 0 && y > 0 )
01402         {
01403             shadow.setAttribute( "direction", 7 );
01404             shadow.setAttribute( "distance", (int) fabs ( x ) );
01405         }
01406         else if ( x < 0 && y == 0 )
01407         {
01408             shadow.setAttribute( "direction", 8 );
01409             shadow.setAttribute( "distance", (int) fabs ( x ) );
01410         }
01411 
01412         if ( m_styleStack.hasAttributeNS( ooNS::draw, "shadow-color" ) )
01413             shadow.setAttribute( "color", m_styleStack.attributeNS( ooNS::draw, "shadow-color" ) );
01414 
01415         e.appendChild( shadow );
01416     }
01417     if ( m_styleStack.hasAttributeNS( ooNS::draw, "size-protect" ) || m_styleStack.hasAttributeNS( ooNS::draw, "move-protect" ) )
01418     {
01419         bool b = ( m_styleStack.attributeNS( ooNS::draw, "size-protect" ) == "true" ) || ( m_styleStack.attributeNS( ooNS::draw, "move-protect" ) == "true" );
01420         if ( b )
01421         {
01422             QDomElement protect  = doc.createElement( "PROTECT" );
01423             protect.setAttribute("state" , b);
01424             e.appendChild(protect);
01425         }
01426     }
01427 }
01428 
01429 void OoImpressImport::appendLineEnds( QDomDocument& doc, QDomElement& e, bool orderEndStartLine)
01430 {
01431     const char* attr = orderEndStartLine ? "marker-start" : "marker-end";
01432     if ( m_styleStack.hasAttributeNS( ooNS::draw, attr ) )
01433     {
01434         QDomElement lineBegin = doc.createElement( "LINEBEGIN" );
01435         QString type = m_styleStack.attributeNS( ooNS::draw, attr );
01436         if ( type == "Arrow" || type == "Small Arrow" || type == "Rounded short Arrow" ||
01437              type == "Symmetric Arrow" || type == "Rounded large Arrow" || type == "Arrow concave" )
01438             lineBegin.setAttribute( "value", 1 );
01439         else if ( type == "Square" )
01440             lineBegin.setAttribute( "value", 2 );
01441         else if ( type == "Circle" || type == "Square 45" )
01442             lineBegin.setAttribute( "value", 3 );
01443         else if ( type == "Line Arrow" )
01444             lineBegin.setAttribute( "value", 4 );
01445         else if ( type == "Dimension Lines" )
01446             lineBegin.setAttribute( "value", 5 );
01447         else if ( type == "Double Arrow" )
01448             lineBegin.setAttribute( "value", 6 );
01449         e.appendChild( lineBegin );
01450     }
01451     attr = orderEndStartLine ? "marker-end" : "marker-start";
01452     if ( m_styleStack.hasAttributeNS( ooNS::draw, attr ) )
01453     {
01454         QDomElement lineEnd = doc.createElement( "LINEEND" );
01455         QString type = m_styleStack.attributeNS( ooNS::draw, attr );
01456         if ( type == "Arrow" || type == "Small Arrow" || type == "Rounded short Arrow" ||
01457              type == "Symmetric Arrow" || type == "Rounded large Arrow" || type == "Arrow concave" )
01458             lineEnd.setAttribute( "value", 1 );
01459         else if ( type == "Square" )
01460             lineEnd.setAttribute( "value", 2 );
01461         else if ( type == "Circle" || type == "Square 45" )
01462             lineEnd.setAttribute( "value", 3 );
01463         else if ( type == "Line Arrow" )
01464             lineEnd.setAttribute( "value", 4 );
01465         else if ( type == "Dimension Lines" )
01466             lineEnd.setAttribute( "value", 5 );
01467         else if ( type == "Double Arrow" )
01468             lineEnd.setAttribute( "value", 6 );
01469         e.appendChild( lineEnd );
01470     }
01471 }
01472 
01473 void OoImpressImport::appendTextObjectMargin( QDomDocument& /*doc*/, QDomElement& e )
01474 {
01475     if ( m_styleStack.hasAttributeNS( ooNS::fo, "padding" ) )
01476     {
01477         double tmpValue = KoUnit::parseValue(m_styleStack.attributeNS( ooNS::fo, "padding" ) );
01478         e.setAttribute( "btoppt", tmpValue );
01479         e.setAttribute( "bbottompt", tmpValue );
01480         e.setAttribute( "bleftpt", tmpValue );
01481         e.setAttribute( "brightpt", tmpValue );
01482     }
01483     else
01484     {
01485         if( m_styleStack.hasAttributeNS( ooNS::fo, "padding-top" ) )
01486             e.setAttribute( "btoppt", KoUnit::parseValue( m_styleStack.attributeNS( ooNS::fo, "padding-top" ) ) );
01487         if( m_styleStack.hasAttributeNS( ooNS::fo, "padding-bottom" ) )
01488             e.setAttribute( "bbottompt", KoUnit::parseValue( m_styleStack.attributeNS( ooNS::fo, "padding-bottom" ) ) );
01489         if( m_styleStack.hasAttributeNS( ooNS::fo, "padding-left" ) )
01490             e.setAttribute( "bleftpt", KoUnit::parseValue( m_styleStack.attributeNS( ooNS::fo, "padding-left" ) ) );
01491         if( m_styleStack.hasAttributeNS( ooNS::fo, "padding-right" ) )
01492             e.setAttribute( "brightpt", KoUnit::parseValue( m_styleStack.attributeNS( ooNS::fo, "padding-right" ) ) );
01493     }
01494 }
01495 
01496 QDomElement OoImpressImport::parseTextBox( QDomDocument& doc, const QDomElement& textBox )
01497 {
01498     QDomElement textObjectElement = doc.createElement( "TEXTOBJ" );
01499     appendTextObjectMargin( doc, textObjectElement );
01500 
01501     // vertical alignment
01502     if ( m_styleStack.hasAttributeNS( ooNS::draw, "textarea-vertical-align" ) )
01503     {
01504         QString alignment = m_styleStack.attributeNS( ooNS::draw, "textarea-vertical-align" );
01505         if ( alignment == "top" )
01506             textObjectElement.setAttribute( "verticalAlign", "top" );
01507         else if ( alignment == "middle" )
01508             textObjectElement.setAttribute( "verticalAlign", "center" );
01509         else if ( alignment == "bottom" )
01510             textObjectElement.setAttribute( "verticalAlign", "bottom" );
01511 
01512         textObjectElement.setAttribute("verticalValue", 0.0);
01513     }
01514 
01515     parseParagraphs( doc, textObjectElement, textBox );
01516 
01517     return textObjectElement;
01518 }
01519 
01520 void OoImpressImport::parseParagraphs( QDomDocument& doc, QDomElement& textObjectElement, const QDomElement& parent )
01521 {
01522     QDomElement t;
01523     forEachElement( t, parent )
01524     {
01525         m_styleStack.save();
01526         const QString localName = t.localName();
01527         const QString ns = t.namespaceURI();
01528         const bool isTextNS = ns == ooNS::text;
01529 
01530         QDomElement e;
01531         if ( isTextNS && localName == "p" ) // text paragraph
01532             e = parseParagraph( doc, t );
01533         else if ( isTextNS && localName == "h" ) // heading - can this happen in ooimpress?
01534         {
01535             e = parseParagraph( doc, t );
01536         }
01537         else if ( isTextNS && ( localName == "unordered-list" || localName == "ordered-list" ) )
01538         {
01539             parseList( doc, textObjectElement, t );
01540             m_styleStack.restore();
01541             continue;
01542         }
01543         // TODO text:sequence-decls
01544         else
01545         {
01546             kdDebug(30518) << "Unsupported texttype '" << localName << "'" << endl;
01547         }
01548 
01549         if ( !e.isNull() )
01550             textObjectElement.appendChild( e );
01551         m_styleStack.restore(); // remove the styles added by the paragraph or list
01552     }
01553 }
01554 
01555 void OoImpressImport::applyListStyle( QDomElement& paragraph )
01556 {
01557     // Spec: see 3.3.5 p137
01558     if ( m_listStyleStack.hasListStyle() && m_nextItemIsListItem ) {
01559         //const QDomElement listStyle = m_listStyleStack.currentListStyle();
01560         //bool heading = paragraph.localName() == "h";
01561         m_nextItemIsListItem = false;
01562         /*int level = heading ? paragraph.attributeNS( ooNS::text, "level", QString::null ).toInt()
01563                     : m_listStyleStack.level();*/
01564 
01565         QDomElement counter = paragraph.ownerDocument().createElement( "COUNTER" );
01566         counter.setAttribute( "numberingtype", 0 );
01567         counter.setAttribute( "depth", 0 );
01568 
01569         if ( m_insideOrderedList )
01570             counter.setAttribute( "type", 1 );
01571         else
01572             counter.setAttribute( "type", 10 ); // a disc bullet
01573         paragraph.appendChild( counter );
01574     }
01575 }
01576 
01577 static QDomElement findListLevelStyle( QDomElement& fullListStyle, int level )
01578 {
01579     QDomElement listLevelItem;
01580     forEachElement( listLevelItem, fullListStyle )
01581     {
01582        if ( listLevelItem.attributeNS( ooNS::text, "level", QString::null ).toInt() == level )
01583            return listLevelItem;
01584     }
01585     return QDomElement();
01586 }
01587 
01588 bool OoImpressImport::pushListLevelStyle( const QString& listStyleName, int level )
01589 {
01590     QDomElement* fullListStyle = m_listStyles[listStyleName];
01591     if ( !fullListStyle ) {
01592         kdWarning(30518) << "List style " << listStyleName << " not found!" << endl;
01593         return false;
01594     }
01595     else
01596         return pushListLevelStyle( listStyleName, *fullListStyle, level );
01597 }
01598 
01599 bool OoImpressImport::pushListLevelStyle( const QString& listStyleName, // for debug only
01600                                           QDomElement& fullListStyle, int level )
01601 {
01602     // Find applicable list-level-style for level
01603     int i = level;
01604     QDomElement listLevelStyle;
01605     while ( i > 0 && listLevelStyle.isNull() ) {
01606         listLevelStyle = findListLevelStyle( fullListStyle, i );
01607         --i;
01608     }
01609     if ( listLevelStyle.isNull() ) {
01610         kdWarning(30518) << "List level style for level " << level << " in list style " << listStyleName << " not found!" << endl;
01611         return false;
01612     }
01613     kdDebug(30518) << "Pushing list-level-style from list-style " << listStyleName << " level " << level << endl;
01614     m_listStyleStack.push( listLevelStyle );
01615     return true;
01616 }
01617 
01618 void OoImpressImport::parseList( QDomDocument& doc, QDomElement& textObjectElement, const QDomElement& list )
01619 {
01620     //kdDebug(30518) << k_funcinfo << "parseList"<< endl;
01621 
01622     m_insideOrderedList = ( list.localName() == "ordered-list" );
01623     QString oldListStyleName = m_currentListStyleName;
01624     if ( list.hasAttributeNS( ooNS::text, "style-name" ) )
01625         m_currentListStyleName = list.attributeNS( ooNS::text, "style-name", QString::null );
01626     bool listOK = !m_currentListStyleName.isEmpty();
01627     const int level = m_listStyleStack.level() + 1;
01628     //kdDebug(30518) << k_funcinfo << " listOK=" << listOK << " level=" << level << endl;
01629     if ( listOK )
01630         listOK = pushListLevelStyle( m_currentListStyleName, level );
01631 
01632     // Iterate over list items
01633     QDomElement listItem;
01634     forEachElement( listItem, list )
01635     {
01636         // It's either list-header (normal text on top of list) or list-item
01637         m_nextItemIsListItem = ( listItem.localName() != "list-header" );
01638         m_restartNumbering = -1;
01639         if ( listItem.hasAttributeNS( ooNS::text, "start-value" ) )
01640             m_restartNumbering = listItem.attributeNS( ooNS::text, "start-value", QString::null ).toInt();
01641         // ### Oasis: can be p h or list only.
01642         parseParagraphs( doc, textObjectElement, listItem );
01643         m_restartNumbering = -1;
01644     }
01645     if ( listOK )
01646         m_listStyleStack.pop();
01647     m_currentListStyleName = oldListStyleName;
01648 }
01649 
01650 QDomElement OoImpressImport::parseParagraph( QDomDocument& doc, const QDomElement& paragraph )
01651 {
01652     QDomElement p = doc.createElement( "P" );
01653 
01654     // parse the paragraph-properties
01655     fillStyleStack( paragraph );
01656 
01657     // Style name
01658     QString styleName = m_styleStack.userStyleName("paragraph");
01659     if ( !styleName.isEmpty() )
01660     {
01661         QDomElement nameElem = doc.createElement("NAME");
01662         nameElem.setAttribute("value", styleName);
01663         p.appendChild(nameElem);
01664     }
01665 
01666     // Paragraph alignment
01667     if ( m_styleStack.hasAttributeNS( ooNS::fo, "text-align" ) )
01668     {
01669         QString align = m_styleStack.attributeNS( ooNS::fo, "text-align" );
01670         if ( align == "center" )
01671             p.setAttribute( "align", 4 );
01672         else if ( align == "justify" )
01673             p.setAttribute( "align", 8 );
01674         else if ( align == "start" )
01675             p.setAttribute( "align", 0 );
01676         else if ( align == "end" )
01677             p.setAttribute( "align", 2 );
01678     }
01679     else
01680         p.setAttribute( "align", 0 ); // use left aligned as default
01681 
01682 
01683     // Offset before and after paragraph
01684     OoUtils::importTopBottomMargin( p, m_styleStack );
01685 
01686     // Indentation (margins)
01687     OoUtils::importIndents( p, m_styleStack );
01688 
01689     // Line spacing
01690     OoUtils::importLineSpacing( p, m_styleStack );
01691 
01692     // Tabulators
01693     OoUtils::importTabulators( p, m_styleStack );
01694 
01695     // Borders
01696     OoUtils::importBorders( p, m_styleStack );
01697 
01698     applyListStyle( p );
01699 
01700     uint pos = 0;
01701 
01702     m_styleStack.save();
01703     // parse every childnode of the paragraph
01704     parseSpanOrSimilar( doc, paragraph, p, pos);
01705     m_styleStack.restore(); // remove possible garbage (should not be needed)
01706 
01707     return p;
01708 }
01709 
01710 void OoImpressImport::parseSpanOrSimilar( QDomDocument& doc, const QDomElement& parent,
01711     QDomElement& outputParagraph, uint& pos)
01712 {
01713     // Parse every child node of the parent
01714     // Can't use forEachElement here since we also care about text nodes
01715     for( QDomNode node = parent.firstChild(); !node.isNull(); node = node.nextSibling() )
01716     {
01717         QDomElement ts = node.toElement();
01718         QString textData;
01719         const QString localName( ts.localName() );
01720         const QString ns = ts.namespaceURI();
01721         const bool isTextNS = ns == ooNS::text;
01722         QDomText t = node.toText();
01723 
01724         // Try to keep the order of the tag names by probability of happening
01725         if ( isTextNS && localName == "span" ) // text:span
01726         {
01727             m_styleStack.save();
01728             fillStyleStack( ts );
01729             parseSpanOrSimilar( doc, ts, outputParagraph, pos);
01730             m_styleStack.restore();
01731         }
01732         else if ( isTextNS && localName == "s" ) // text:s
01733         {
01734             textData = OoUtils::expandWhitespace(ts);
01735         }
01736         else if ( isTextNS && localName == "tab-stop" ) // text:tab-stop
01737         {
01738             // KPresenter currently uses \t.
01739             // Known bug: a line with only \t\t\t\t isn't loaded - XML (QDom) strips out whitespace.
01740             // One more good reason to switch to <text:tab-stop> instead...
01741             textData = '\t';
01742         }
01743         else if ( isTextNS && localName == "line-break" )
01744         {
01745             textData = '\n';
01746         }
01747         else if ( localName == "image" && ns == ooNS::draw )
01748         {
01749             textData = '#'; // anchor placeholder
01750             // TODO
01751         }
01752         else if ( isTextNS && localName == "a" )
01753         {
01754             m_styleStack.save();
01755             QString href( ts.attributeNS( ooNS::xlink, "href", QString::null) );
01756             if ( href.startsWith("#") )
01757             {
01758                 // We have a reference to a bookmark (### TODO)
01759                 // As we do not support it now, treat it as a <text:span> without formatting
01760                 parseSpanOrSimilar( doc, ts, outputParagraph, pos);
01761             }
01762             else
01763             {
01764 #if 0 // TODO
01765                 // The problem is that KPresenter's hyperlink text is not inside the normal text, but for OOWriter it is nearly a <text:span>
01766                 // So we have to fake.
01767                 QDomElement fakeParagraph, fakeFormats;
01768                 uint fakePos=0;
01769                 QString text;
01770                 parseSpanOrSimilar( doc, ts, fakeParagraph, fakeFormats, text, fakePos);
01771                 textData = '#'; // hyperlink placeholder
01772                 QDomElement linkElement (doc.createElement("LINK"));
01773                 linkElement.setAttribute("hrefName",ts.attributeNS( ooNS::xlink, "href", QString::null));
01774                 linkElement.setAttribute("linkName",text);
01775                 appendVariable(doc, ts, pos, "STRING", 9, text, linkElement);
01776 #endif
01777             }
01778             m_styleStack.restore();
01779         }
01780         else if ( isTextNS &&
01781                   (localName == "date" // fields
01782                  || localName == "time"
01783                  || localName == "page-number"
01784                  || localName == "file-name"
01785                  || localName == "author-name"
01786                  || localName == "author-initials" ) )
01787         {
01788             textData = "#";     // field placeholder
01789             appendField(doc, outputParagraph, ts, pos);
01790         }
01791         else if ( t.isNull() ) // no textnode, we must ignore
01792         {
01793             kdWarning(30518) << "Ignoring tag " << ts.tagName() << endl;
01794             continue;
01795         }
01796         else
01797             textData = t.data();
01798 
01799         pos += textData.length();
01800 
01801         QDomElement text = saveHelper(textData, doc);
01802 
01803         kdDebug(30518) << k_funcinfo << "Para text is: " << textData << endl;
01804 
01805         if (m_styleStack.hasAttributeNS( ooNS::fo, "language" )) {
01806             QString lang = m_styleStack.attributeNS( ooNS::fo, "language" );
01807             if (lang=="en")
01808                 text.setAttribute("language", "en_US");
01809             else
01810                 text.setAttribute("language", lang);
01811         }
01812 
01813         // parse the text-properties
01814         if ( m_styleStack.hasAttributeNS( ooNS::fo, "color" ) ) {
01815             kdDebug(30518) << "color=" << m_styleStack.attributeNS( ooNS::fo, "color" ) << endl;
01816             text.setAttribute( "color", m_styleStack.attributeNS( ooNS::fo, "color" ) );
01817         }
01818         if ( m_styleStack.hasAttributeNS( ooNS::fo, "font-family" )  // 3.10.9
01819              || m_styleStack.hasAttributeNS( ooNS::style, "font-name") )//3.10.8
01820         {
01821             // 'Thorndale/Albany' are not known outside OpenOffice so we substitute them
01822             // with 'Times New Roman/Arial' that look nearly the same.
01823             if ( m_styleStack.attributeNS( ooNS::fo, "font-family" ) == "Thorndale" )
01824                 text.setAttribute( "family", "Times New Roman" );
01825             else if ( m_styleStack.attributeNS( ooNS::fo, "font-family" ) == "Albany" )
01826                 text.setAttribute( "family", "Arial" );
01827             else
01828                 text.setAttribute( "family", m_styleStack.attributeNS( ooNS::fo, "font-family" ).remove( "'" ) );
01829         }
01830         if ( m_styleStack.hasAttributeNS( ooNS::fo, "font-size" ) )
01831         {
01832             double pointSize = m_styleStack.fontSize();
01833             text.setAttribute( "pointSize", qRound(pointSize) ); // KPresenter uses toInt()!
01834         }
01835         if ( m_styleStack.hasAttributeNS( ooNS::fo, "font-weight" ) ) // 3.10.24
01836             if ( m_styleStack.attributeNS( ooNS::fo, "font-weight" ) == "bold" )
01837                 text.setAttribute( "bold", 1 );
01838         if ( m_styleStack.hasAttributeNS( ooNS::fo, "font-style" ) )
01839             if ( m_styleStack.attributeNS( ooNS::fo, "font-style" ) == "italic" )
01840                 text.setAttribute( "italic", 1 );
01841 
01842         if ( m_styleStack.hasAttributeNS( ooNS::style, "text-position" ) ) // 3.10.17
01843         {
01844             QString text_position = m_styleStack.attributeNS( ooNS::style, "text-position");
01845             QString value;
01846             QString relativetextsize;
01847             OoUtils::importTextPosition( text_position, value, relativetextsize );
01848             text.setAttribute( "VERTALIGN", value );
01849             if ( !relativetextsize.isEmpty() )
01850                 text.setAttribute( "relativetextsize", relativetextsize );
01851         }
01852 
01853         bool wordByWord = (m_styleStack.hasAttributeNS( ooNS::fo, "score-spaces"))// 3.10.25
01854                           && (m_styleStack.attributeNS( ooNS::fo, "score-spaces") == "false");
01855 
01856         // strikeout
01857         if ( m_styleStack.hasAttributeNS( ooNS::style, "text-crossing-out")// 3.10.6
01858              && m_styleStack.attributeNS( ooNS::style, "text-crossing-out") != "none")
01859         {
01860             QString strikeOutType = m_styleStack.attributeNS( ooNS::style, "text-crossing-out" );
01861             if ( strikeOutType =="double-line" )
01862             {
01863                 text.setAttribute( "strikeOut", "double" );
01864                 text.setAttribute( "strikeoutstyleline", "solid" );
01865             }
01866             else if ( strikeOutType =="thick-line" )
01867             {
01868                 text.setAttribute( "strikeOut", "single-bold" );
01869                 text.setAttribute( "strikeoutstyleline", "solid" );
01870             }
01871             else //if ( strikeOutType == "single-line" ) //fall back to the default strikeout
01872             {
01873                 text.setAttribute( "strikeOut", "single" );
01874                 text.setAttribute( "strikeoutstyleline", "solid" );
01875             }
01876 
01877             if (wordByWord)
01878                 text.setAttribute("wordbyword", 1);
01879         }
01880 
01881         // underlining
01882         if ( m_styleStack.hasAttributeNS( ooNS::style, "text-underline" ) ) // 3.10.22
01883         {
01884             QString underline;
01885             QString styleline;
01886             OoUtils::importUnderline( m_styleStack.attributeNS( ooNS::style, "text-underline" ),
01887                                       underline, styleline );
01888             QString underLineColor = m_styleStack.attributeNS( ooNS::style, "text-underline-color" );// 3.10.23
01889 
01890             text.setAttribute( "value", underline );
01891             text.setAttribute( "styleline", styleline );
01892 
01893             if ( !underLineColor.isEmpty() && underLineColor != "font-color" )
01894                 text.setAttribute("underlinecolor", underLineColor);
01895             if ( wordByWord )
01896                 text.setAttribute("wordbyword", 1);
01897         }
01898 #if 0 // strange ooimpress doesn't implement it
01899          // Small caps, lowercase, uppercase
01900         if ( m_styleStack.hasAttributeNS( ooNS::fo, "font-variant" ) // 3.10.1
01901          || m_styleStack.hasAttributeNS( ooNS::fo, "text-transform" ) ) // 3.10.2
01902         {
01903             QDomElement fontAttrib( doc.createElement( "FONTATTRIBUTE" ) );
01904             bool smallCaps = m_styleStack.attributeNS( ooNS::fo, "font-variant" ) == "small-caps";
01905             if ( smallCaps )
01906             {
01907                 text.setAttribute( "fontattribute", "smallcaps" );
01908             } else
01909             {
01910                 // Both KWord/KPresenter and OO use "uppercase" and "lowercase".
01911                 // TODO in KWord: "capitalize".
01912                 text.setAttribute( "fontattribute", m_styleStack.attributeNS( ooNS::fo, "text-transform" ) );
01913             }
01914         }
01915 #endif
01916         // background color (property of the paragraph in OOo, of the text in kword/kpresenter)
01917         if (m_styleStack.hasAttributeNS( ooNS::fo, "background-color" ))
01918         {
01919             QString bgColor = m_styleStack.attributeNS( ooNS::fo, "background-color");
01920             if (bgColor != "transparent")
01921                 text.setAttribute("textbackcolor", bgColor);
01922         }
01923 
01924         appendShadow( doc, outputParagraph ); // this is necessary to take care of shadowed paragraphs
01925         outputParagraph.appendChild( text );
01926     } // for each text span
01927 }
01928 
01929 void OoImpressImport::createStyleMap( QDomDocument &docstyles )
01930 {
01931     QDomElement styles = docstyles.documentElement();
01932     if ( styles.isNull() )
01933         return;
01934 
01935     QDomNode fixedStyles = KoDom::namedItemNS( styles, ooNS::office, "styles" );
01936     if ( !fixedStyles.isNull() )
01937     {
01938         insertDraws( fixedStyles.toElement() );
01939         insertStyles( fixedStyles.toElement() );
01940         insertStylesPresentation( fixedStyles.toElement() );
01941     }
01942 
01943     QDomNode automaticStyles = KoDom::namedItemNS( styles, ooNS::office, "automatic-styles" );
01944     if ( !automaticStyles.isNull() )
01945     {
01946         insertStyles( automaticStyles.toElement() );
01947         insertStylesPresentation( automaticStyles.toElement() );
01948     }
01949     QDomNode masterStyles = KoDom::namedItemNS( styles, ooNS::office, "master-styles" );
01950     if ( !masterStyles.isNull() )
01951         insertStyles( masterStyles.toElement() );
01952 }
01953 
01954 void OoImpressImport::insertDraws( const QDomElement& styles )
01955 {
01956     QDomElement e;
01957     forEachElement( e, styles )
01958     {
01959         if ( !e.hasAttributeNS( ooNS::draw, "name" ) )
01960             continue;
01961 
01962         QString name = e.attributeNS( ooNS::draw, "name", QString::null );
01963         m_draws.insert( name, new QDomElement( e ) );
01964     }
01965 }
01966 
01967 void OoImpressImport::insertStyles( const QDomElement& styles )
01968 {
01969     QDomElement e;
01970     forEachElement( e, styles )
01971     {
01972         const QString localName = e.localName();
01973         const QString ns = e.namespaceURI();
01974         if ( !e.hasAttributeNS( ooNS::style, "name" ) )
01975             continue;
01976 
01977         const QString name = e.attributeNS( ooNS::style, "name", QString::null );
01978         if ( localName == "list-style" && ns == ooNS::text ) {
01979             QDomElement* ep = new QDomElement( e );
01980             m_listStyles.insert( name, ep );
01981             kdDebug(30518) << "List style: '" << name << "' loaded " << endl;
01982         }
01983         else
01984         {
01985             m_styles.insert( name, new QDomElement( e ) );
01986             kdDebug(30518) << "Style: '" << name << "' loaded " << endl;
01987         }
01988     }
01989 }
01990 
01991 void OoImpressImport::insertStylesPresentation( const QDomElement& styles )
01992 {
01993     QDomElement e;
01994     forEachElement( e, styles )
01995     {
01996         if ( !e.hasAttributeNS( ooNS::style, "name" ) )
01997             continue;
01998 
01999         QString name = e.attributeNS( ooNS::style, "name", QString::null );
02000         m_stylesPresentation.insert( name, new QDomElement( e ) );
02001         //kdDebug(30518) << "Style: '" << name << "' loaded " << endl;
02002     }
02003 }
02004 
02005 void OoImpressImport::fillStyleStack( const QDomElement& object, bool sticky )
02006 {
02007     // find all styles associated with an object and push them on the stack
02008     if ( object.hasAttributeNS( ooNS::presentation, "style-name" ) )
02009     {
02010         kdDebug(30518)<<" presentation:style-name **************************** :"<<object.attributeNS( ooNS::presentation, "style-name", QString::null )<<endl;
02011         if ( sticky )
02012             addStyles( m_stylesPresentation[object.attributeNS( ooNS::presentation, "style-name", QString::null )] );
02013         else
02014             addStyles( m_styles[object.attributeNS( ooNS::presentation, "style-name", QString::null )] );
02015     }
02016     if ( object.hasAttributeNS( ooNS::draw, "style-name" ) )
02017         addStyles( m_styles[object.attributeNS( ooNS::draw, "style-name", QString::null )] );
02018 
02019     if ( object.hasAttributeNS( ooNS::draw, "text-style-name" ) )
02020         addStyles( m_styles[object.attributeNS( ooNS::draw, "text-style-name", QString::null )] );
02021 
02022     if ( object.hasAttributeNS( ooNS::text, "style-name" ) ) {
02023         QString styleName = object.attributeNS( ooNS::text, "style-name", QString::null );
02024         //kdDebug(30518) << "adding style " << styleName << endl;
02025         addStyles( m_styles[styleName] );
02026     }
02027 }
02028 
02029 void OoImpressImport::addStyles( const QDomElement* style )
02030 {
02031     kdDebug(30518)<<" addStyle :" << style->attributeNS( ooNS::style, "name", QString::null ) <<endl;
02032     // this function is necessary as parent styles can have parents themself
02033     if ( style->hasAttributeNS( ooNS::style, "parent-style-name" ) )
02034     {
02035         //kdDebug(30518)<<"m_styles[style->attribute( style:parent-style-name )] :"<<m_styles[style->attributeNS( ooNS::style, "parent-style-name", QString::null )]<<endl;
02036         addStyles( m_styles[style->attributeNS( ooNS::style, "parent-style-name", QString::null )] );
02037     }
02038     //kdDebug(30518)<<" void OoImpressImport::addStyles( const QDomElement* style ) :"<<style<<endl;
02039     m_styleStack.push( *style );
02040 }
02041 
02042 QString OoImpressImport::storeImage( const QDomElement& object )
02043 {
02044     // store the picture
02045     QString url = object.attributeNS( ooNS::xlink, "href", QString::null ).remove( '#' );
02046     KArchiveFile* file = (KArchiveFile*) m_zip->directory()->entry( url );
02047 
02048     QString extension = url.mid( url.find( '.' ) );
02049     QString fileName = QString( "picture%1" ).arg( m_numPicture++ ) + extension;
02050     KoStoreDevice* out = m_chain->storageFile( "pictures/" + fileName, KoStore::Write );
02051 
02052     if ( file && out )
02053     {
02054         QByteArray buffer = file->data();
02055         out->writeBlock( buffer.data(), buffer.size() );
02056     }
02057 
02058     return fileName;
02059 }
02060 
02061 QString OoImpressImport::storeSound(const QDomElement & object, QDomElement & p, QDomDocument & doc)
02062 {
02063     QFileInfo fi(m_chain->inputFile()); // handle relative URLs
02064     QDir::setCurrent(fi.dirPath(true));
02065     fi.setFile(object.attributeNS( ooNS::xlink, "href", QString::null));
02066     QString url = fi.absFilePath();
02067 
02068     //kdDebug(30518) << "Sound URL: " << url << endl;
02069 
02070     QFile file(url);
02071     if (!file.exists())
02072         return QString::null;
02073 
02074     QString extension = url.mid( url.find( '.' ) );
02075     QString fileName = QString( "sound%1" ).arg( m_numSound++ ) + extension;
02076     fileName = "sounds/" + fileName;
02077     KoStoreDevice* out = m_chain->storageFile( fileName, KoStore::Write );
02078 
02079     if (out)
02080     {
02081         if (!file.open(IO_ReadOnly))
02082             return QString::null;
02083 
02084         QByteArray data(8*1024);
02085 
02086         uint total = 0;
02087         for ( int block = 0; ( block = file.readBlock(data.data(), data.size()) ) > 0;
02088               total += block )
02089             out->writeBlock(data.data(), data.size());
02090 
02091         Q_ASSERT(total == fi.size());
02092 
02093         file.close();
02094     }
02095     else
02096         return QString::null;
02097 
02098     QDomElement key = doc.createElement("FILE");
02099     key.setAttribute("name", fileName);
02100     key.setAttribute("filename", url);
02101     p.appendChild(key);
02102 
02103     return url;
02104 }
02105 
02106 QDomElement OoImpressImport::saveHelper(const QString &tmpText, QDomDocument &doc)
02107 {
02108     QDomElement element=doc.createElement("TEXT");
02109 
02110     if(tmpText.stripWhiteSpace().isEmpty()) // ### careful, this also strips \t and \n ....
02111         // working around a bug in QDom
02112         element.setAttribute("whitespace", tmpText.length());
02113 
02114     element.appendChild(doc.createTextNode(tmpText));
02115     return element;
02116 }
02117 
02118 void OoImpressImport::appendPoints(QDomDocument& doc, QDomElement& e, const QDomElement& object)
02119 {
02120     QDomElement ptsElem = doc.createElement("POINTS");
02121 
02122     QStringList ptList = QStringList::split(' ', object.attributeNS( ooNS::draw, "points", QString::null));
02123 
02124     QString pt_x, pt_y;
02125     double tmp_x, tmp_y;
02126     for (QStringList::Iterator it = ptList.begin(); it != ptList.end(); ++it)
02127     {
02128         QDomElement point = doc.createElement("Point");
02129 
02130         tmp_x = (*it).section(',',0,0).toInt() / 100;
02131         tmp_y = (*it).section(',',1,1).toInt() / 100;
02132 
02133         pt_x.setNum(tmp_x);
02134         pt_x+="mm";
02135 
02136         pt_y.setNum(tmp_y);
02137         pt_y+="mm";
02138 
02139         point.setAttribute("point_x", KoUnit::parseValue(pt_x));
02140         point.setAttribute("point_y", KoUnit::parseValue(pt_y));
02141         ptsElem.appendChild(point);
02142     }
02143 
02144     e.appendChild(ptsElem);
02145 }
02146 
02147 void OoImpressImport::appendField(QDomDocument& doc, QDomElement& e, const QDomElement& object, uint pos)
02148 {
02149     const QString tag = object.localName();
02150     const QString ns = object.namespaceURI();
02151     const bool isTextNS = ns == ooNS::text;
02152 
02153     QDomElement custom = doc.createElement("CUSTOM");
02154     custom.setAttribute("pos", pos);
02155     QDomElement variable = doc.createElement("VARIABLE");
02156 
02157     if (isTextNS && tag == "date")
02158     {
02159         QDateTime dt(QDate::fromString(object.attributeNS( ooNS::text, "date-value", QString::null), Qt::ISODate));
02160 
02161         bool fixed = (object.hasAttributeNS( ooNS::text, "fixed") && object.attributeNS( ooNS::text, "fixed", QString::null)=="true");
02162 
02163         if (!dt.isValid()) {
02164             dt = QDateTime::currentDateTime(); // OOo docs say so :)
02165             fixed = false;
02166         }
02167 
02168         QDomElement typeElem = doc.createElement("TYPE");
02169         typeElem.setAttribute("key", "DATE0locale"); // ### find out the correlation between KOffice and OOo date/time types
02170         typeElem.setAttribute("type", 0); // VT_DATE
02171         typeElem.setAttribute("text", object.text());
02172 
02173         variable.appendChild(typeElem);
02174 
02175         const QDate date(dt.date());
02176         const QTime time(dt.time());
02177         QDomElement dateElement = doc.createElement("DATE");
02178         dateElement.setAttribute("subtype", fixed ? 0 : 1); // VST_DATE_FIX, VST_DATE_CURRENT
02179         dateElement.setAttribute("fix", fixed ? 1 : 0);
02180         dateElement.setAttribute("day", date.day());
02181         dateElement.setAttribute("month", date.month());
02182         dateElement.setAttribute("year", date.year());
02183         dateElement.setAttribute("hour", time.hour());
02184         dateElement.setAttribute("minute", time.minute());
02185         dateElement.setAttribute("second", time.second());
02186         if (object.hasAttributeNS( ooNS::text, "date-adjust"))
02187             dateElement.setAttribute("correct", object.attributeNS( ooNS::text, "date-adjust", QString::null));
02188 
02189         variable.appendChild(dateElement);
02190     }
02191     else if (isTextNS && tag == "time")
02192     {
02193         // Use QDateTime to work around a possible problem of QTime::FromString in Qt 3.2.2
02194         QDateTime dt(QDateTime::fromString(object.attributeNS( ooNS::text, "time-value", QString::null), Qt::ISODate));
02195 
02196         bool fixed = (object.hasAttributeNS( ooNS::text, "fixed") && object.attributeNS( ooNS::text, "fixed", QString::null)=="true");
02197 
02198         if (!dt.isValid()) {
02199             dt = QDateTime::currentDateTime(); // OOo docs say so :)
02200             fixed = false;
02201         }
02202 
02203         QDomElement typeElem = doc.createElement("TYPE");
02204         typeElem.setAttribute("key", "TIMElocale"); // ### find out the correlation between KOffice and OOo date/time types
02205         typeElem.setAttribute("type", 2); // VT_TIME
02206         typeElem.setAttribute("text", object.text());
02207 
02208         variable.appendChild(typeElem);
02209 
02210         const QTime time(dt.time());
02211         QDomElement timeElement = doc.createElement("TIME");
02212         timeElement.setAttribute("subtype", fixed ? 0 : 1); // VST_TIME_FIX, VST_TIME_CURRENT
02213         timeElement.setAttribute("fix", fixed ? 1 : 0);
02214         timeElement.setAttribute("hour", time.hour());
02215         timeElement.setAttribute("minute", time.minute());
02216         timeElement.setAttribute("second", time.second());
02217         /*if (object.hasAttributeNS( ooNS::text, "time-adjust"))
02218           timeElem.setAttribute("correct", object.attributeNS( ooNS::text, "time-adjust", QString::null));*/ // ### TODO
02219 
02220         variable.appendChild(timeElement);
02221     }
02222     else if (isTextNS && tag == "page-number")
02223     {
02224         QDomElement typeElem = doc.createElement("TYPE");
02225         typeElem.setAttribute("key", "NUMBER");
02226         typeElem.setAttribute("type", 4); // VT_PGNUM
02227         typeElem.setAttribute("text", object.text());
02228 
02229         variable.appendChild(typeElem);
02230 
02231         QDomElement pgNumElem = doc.createElement("PGNUM");
02232 
02233         int subtype = 0;        // VST_PGNUM_CURRENT
02234 
02235         if (object.hasAttributeNS( ooNS::text, "select-page"))
02236         {
02237             const QString select = object.attributeNS( ooNS::text, "select-page", QString::null);
02238 
02239             if (select == "previous")
02240                 subtype = 3;    // VST_PGNUM_PREVIOUS
02241             else if (select == "next")
02242                 subtype = 4;    // VST_PGNUM_NEXT
02243             else
02244                 subtype = 0;    // VST_PGNUM_CURRENT
02245         }
02246 
02247         pgNumElem.setAttribute("subtype", subtype);
02248         pgNumElem.setAttribute("value", object.text());
02249 
02250         variable.appendChild(pgNumElem);
02251     }
02252     else if (isTextNS && tag == "file-name")
02253     {
02254         QDomElement typeElem = doc.createElement("TYPE");
02255         typeElem.setAttribute("key", "STRING");
02256         typeElem.setAttribute("type", 8); // VT_FIELD
02257         typeElem.setAttribute("text", object.text());
02258 
02259         variable.appendChild(typeElem);
02260 
02261         int subtype = 5;
02262 
02263         if (object.hasAttributeNS( ooNS::text, "display"))
02264         {
02265             const QString display = object.attributeNS( ooNS::text, "display", QString::null);
02266 
02267             if (display == "path")
02268                 subtype = 1;    // VST_DIRECTORYNAME
02269             else if (display == "name")
02270                 subtype = 6;    // VST_FILENAMEWITHOUTEXTENSION
02271             else if (display == "name-and-extension")
02272                 subtype = 0;    // VST_FILENAME
02273             else
02274                 subtype = 5;    // VST_PATHFILENAME
02275         }
02276 
02277         QDomElement fileNameElem = doc.createElement("FIELD");
02278         fileNameElem.setAttribute("subtype", subtype);
02279         fileNameElem.setAttribute("value", object.text());
02280 
02281         variable.appendChild(fileNameElem);
02282     }
02283     else if (isTextNS && tag == "author-name"
02284              || isTextNS && tag == "author-initials")
02285     {
02286         QDomElement typeElem = doc.createElement("TYPE");
02287         typeElem.setAttribute("key", "STRING");
02288         typeElem.setAttribute("type", 8); // VT_FIELD
02289         typeElem.setAttribute("text", object.text());
02290 
02291         variable.appendChild(typeElem);
02292 
02293         int subtype = 2;        // VST_AUTHORNAME
02294 
02295         if (isTextNS && tag == "author-initials")
02296             subtype = 16;       // VST_INITIAL
02297 
02298         QDomElement authorElem = doc.createElement("FIELD");
02299         authorElem.setAttribute("subtype", subtype);
02300         authorElem.setAttribute("value", object.text());
02301 
02302         variable.appendChild(authorElem);
02303     }
02304 
02305     custom.appendChild(variable);
02306     e.appendChild(custom);
02307 }
02308 
02309 void OoImpressImport::createPresentationAnimation(const QDomElement& element)
02310 {
02311     int order = 0;
02312     QDomElement e;
02313     forEachElement( e, element )
02314     {
02315         const QString localName = e.localName();
02316         const QString ns = e.namespaceURI();
02317         if ( ns == ooNS::presentation && localName == "show-shape" && e.hasAttributeNS( ooNS::draw, "shape-id" ) )
02318         {
02319             QString name = e.attributeNS( ooNS::draw, "shape-id", QString::null );
02320             //kdDebug(30518)<<" insert animation style : name :"<<name<<endl;
02321             animationList *lst = new animationList;
02322             QDomElement* ep = new QDomElement( e );
02323             lst->element = ep;
02324             lst->order = order;
02325             m_animations.insert( name, lst );
02326             ++order;
02327         }
02328     }
02329 }
02330 
02331 QDomElement OoImpressImport::findAnimationByObjectID(const QString & id,  int & order)
02332 {
02333     kdDebug(30518)<<"QDomElement OoImpressImport::findAnimationByObjectID(const QString & id) :"<<id<<endl;
02334     if (m_animations.isEmpty() )
02335         return QDomElement();
02336 
02337     animationList *animation = m_animations[id];
02338     //kdDebug(30518)<<"QDomElement *animation = m_animations[id]; :"<<animation<<endl;
02339     if ( !animation )
02340         return QDomElement();
02341     for (QDomNode node = *( animation->element ); !node.isNull(); node = node.nextSibling())
02342     {
02343         QDomElement e = node.toElement();
02344         order = animation->order;
02345         kdDebug(30518)<<"e.tagName() :"<<e.tagName()<<" e.attribute(draw:shape-id) :"<<e.attributeNS( ooNS::draw, "shape-id", QString::null)<<endl;
02346         if (e.tagName()=="presentation:show-shape" && e.attributeNS( ooNS::draw, "shape-id", QString::null)==id)
02347                 return e;
02348     }
02349 
02350     return QDomElement();
02351 }
02352 
02353 
02354 void OoImpressImport::appendObjectEffect(QDomDocument& doc, QDomElement& e, const QDomElement& object,
02355                                          QDomElement& sound)
02356 {
02357     int order = 0;
02358     QDomElement origEffect = findAnimationByObjectID(object.attributeNS( ooNS::draw, "id", QString::null), order).toElement();
02359 
02360     if (origEffect.isNull())
02361         return;
02362 
02363     QString effect = origEffect.attributeNS( ooNS::presentation, "effect", QString::null);
02364     QString dir = origEffect.attributeNS( ooNS::presentation, "direction", QString::null);
02365     QString speed = origEffect.attributeNS( ooNS::presentation, "speed", QString::null);
02366     kdDebug(30518)<<"speed :"<<speed<<endl;
02367     //todo implement speed value.
02368 
02369     int effVal=0;
02370     //kdDebug(30518)<<" effect :"<<effect<<" dir :"<<dir<<endl;
02371     if (effect=="fade")
02372     {
02373         if (dir=="from-right")
02374             effVal=10;          // EF_WIPE_RIGHT
02375         else if (dir=="from-left")
02376             effVal=9;           // EF_WIPE_LEFT
02377         else if (dir=="from-top")
02378             effVal=11;          // EF_WIPE_TOP
02379         else if (dir=="from-bottom")
02380             effVal=12;          // EF_WIPE_BOTTOM
02381         else
02382             return;
02383     }
02384     else if (effect=="move")
02385     {
02386         if (dir=="from-right")
02387             effVal=1;           // EF_COME_RIGHT
02388         else if (dir=="from-left")
02389             effVal=2;           // EF_COME_LEFT
02390         else if (dir=="from-top")
02391             effVal=3;           // EF_COME_TOP
02392         else if (dir=="from-bottom")
02393             effVal=4;           // EF_COME_BOTTOM
02394         else if (dir=="from-upper-right")
02395             effVal=5;           // EF_COME_RIGHT_TOP
02396         else if (dir=="from-lower-right")
02397             effVal=6;           // EF_COME_RIGHT_BOTTOM
02398         else if (dir=="from-upper-left")
02399             effVal=7;           // EF_COME_LEFT_TOP
02400         else if (dir=="from-lower-left")
02401             effVal=8;           // EF_COME_LEFT_BOTTOM
02402         else
02403             return;
02404     }
02405     else
02406         return;                 // sorry, no more supported effects :(
02407 
02408     QDomElement effElem = doc.createElement("EFFECTS");
02409     effElem.setAttribute("effect", effVal);
02410     e.appendChild(effElem);
02411 
02412     QDomElement presNum = doc.createElement( "PRESNUM" );
02413     presNum.setAttribute("value", order);
02414     e.appendChild( presNum );
02415 
02416     // sound effect
02417     QDomElement origSoundEff = KoDom::namedItemNS( origEffect, ooNS::presentation, "sound");
02418     if (!origSoundEff.isNull())
02419     {
02420         QString soundUrl = storeSound(origSoundEff, sound, doc);
02421 
02422         if (!soundUrl.isNull())
02423         {
02424             QDomElement pseElem = doc.createElement("APPEARSOUNDEFFECT");
02425             pseElem.setAttribute("appearSoundEffect", 1);
02426             pseElem.setAttribute("appearSoundFileName", soundUrl);
02427 
02428             e.appendChild(pseElem);
02429         }
02430     }
02431 }
02432 
02433 #include "ooimpressimport.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys