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