kspread

kspread_map.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <stdlib.h>
00021 #include <time.h>
00022 
00023 #include <qfile.h>
00024 
00025 #include <kmdcodec.h>
00026 #include <ktempfile.h>
00027 
00028 #include <KoDom.h>
00029 #include <KoGenStyles.h>
00030 #include <KoOasisSettings.h>
00031 #include <KoXmlNS.h>
00032 #include <KoXmlWriter.h>
00033 
00034 #include "kspread_canvas.h"
00035 #include "kspread_doc.h"
00036 #include "kspread_genvalidationstyle.h"
00037 #include "kspread_locale.h"
00038 #include "kspread_sheet.h"
00039 #include "kspread_view.h"
00040 #include "KSpreadMapIface.h"
00041 
00042 #include "kspread_map.h"
00043 
00044 using namespace KSpread;
00045 
00046 bool Map::respectCase = true;
00047 
00048 Map::Map ( Doc* doc, const char* name)
00049   : QObject( doc, name ),
00050     m_doc( doc ),
00051     m_initialActiveSheet( 0 ),
00052     m_initialMarkerColumn( 0 ),
00053     m_initialMarkerRow( 0 ),
00054     m_initialXOffset(0.0),
00055     m_initialYOffset(0.0),
00056     tableId (1),
00057     m_dcop( 0 )
00058 {
00059   m_lstSheets.setAutoDelete( true );
00060 }
00061 
00062 Map::~Map()
00063 {
00064     delete m_dcop;
00065 }
00066 
00067 Doc* Map::doc() const
00068 {
00069   return m_doc;
00070 }
00071 
00072 void Map::setProtected( QCString const & passwd )
00073 {
00074   m_strPassword = passwd;
00075 }
00076 
00077 Sheet* Map::createSheet()
00078 {
00079   QString s( i18n("Sheet%1") );
00080   s = s.arg( tableId++ );
00081   Sheet *t = new Sheet ( this, s , s.utf8());
00082   t->setSheetName( s, true ); // huh? (Werner)
00083   return t;
00084 }
00085 
00086 void Map::addSheet( Sheet *_sheet )
00087 {
00088   m_lstSheets.append( _sheet );
00089 
00090   m_doc->setModified( true );
00091 
00092   emit sig_addSheet( _sheet );
00093 }
00094 
00095 Sheet *Map::addNewSheet ()
00096 {
00097   Sheet *t = createSheet ();
00098   addSheet (t);
00099   return t;
00100 }
00101 
00102 void Map::moveSheet( const QString & _from, const QString & _to, bool _before )
00103 {
00104   Sheet* sheetfrom = findSheet( _from );
00105   Sheet* sheetto = findSheet( _to );
00106 
00107   int from = m_lstSheets.find( sheetfrom ) ;
00108   int to = m_lstSheets.find( sheetto ) ;
00109   if ( !_before )
00110   ++to;
00111 
00112   if ( to > (int)m_lstSheets.count() )
00113   {
00114     m_lstSheets.append( sheetfrom );
00115     m_lstSheets.take( from );
00116   }
00117   else if ( from < to )
00118   {
00119     m_lstSheets.insert( to, sheetfrom );
00120     m_lstSheets.take( from );
00121   }
00122   else
00123   {
00124     m_lstSheets.take( from );
00125     m_lstSheets.insert( to, sheetfrom );
00126   }
00127 }
00128 
00129 void Map::loadOasisSettings( KoOasisSettings &settings )
00130 {
00131     KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" );
00132     KoOasisSettings::IndexedMap viewMap = viewSettings.indexedMap( "Views" );
00133     KoOasisSettings::Items firstView = viewMap.entry( 0 );
00134 
00135     KoOasisSettings::NamedMap sheetsMap = firstView.namedMap( "Tables" );
00136     kdDebug()<<" loadOasisSettings( KoOasisSettings &settings ) exist : "<< !sheetsMap.isNull() <<endl;
00137     if ( !sheetsMap.isNull() )
00138     {
00139         QPtrListIterator<Sheet> it( m_lstSheets );
00140         for( ; it.current(); ++it )
00141         {
00142             it.current()->loadOasisSettings( sheetsMap );
00143         }
00144     }
00145 
00146     QString activeSheet = firstView.parseConfigItemString( "ActiveTable" );
00147     kdDebug()<<" loadOasisSettings( KoOasisSettings &settings ) activeSheet :"<<activeSheet<<endl;
00148 
00149     if (!activeSheet.isEmpty())
00150     {
00151         // Used by View's constructor
00152         m_initialActiveSheet = findSheet( activeSheet );
00153     }
00154 
00155 }
00156 
00157 void Map::saveOasisSettings( KoXmlWriter &settingsWriter )
00158 {
00159     settingsWriter.addConfigItem( "ViewId", QString::fromLatin1( "View1" ) );
00160     // Save visual info for the first view, such as active sheet and active cell
00161     // It looks like a hack, but reopening a document creates only one view anyway (David)
00162     View * view = static_cast<View*>( m_doc->views().getFirst());
00163     if ( view ) // no view if embedded document
00164     {
00165         // save current sheet selection before to save marker, otherwise current pos is not saved
00166         view->saveCurrentSheetSelection();
00167         Canvas * canvas = view->canvasWidget();
00168         //<config:config-item config:name="ActiveTable" config:type="string">Feuille1</config:config-item>
00169         settingsWriter.addConfigItem( "ActiveTable",  canvas->activeSheet()->sheetName() );
00170     }
00171 
00172     //<config:config-item-map-named config:name="Tables">
00173     settingsWriter.startElement("config:config-item-map-named" );
00174     settingsWriter.addAttribute("config:name","Tables" );
00175     QPtrListIterator<Sheet> it( m_lstSheets );
00176     for( ; it.current(); ++it )
00177     {
00178         QPoint marker;
00179         if ( view )
00180         {
00181             marker = view->markerFromSheet( *it );
00182         }
00183         settingsWriter.startElement( "config:config-item-map-entry" );
00184         settingsWriter.addAttribute( "config:name", ( *it )->sheetName() );
00185         it.current()->saveOasisSettings( settingsWriter, marker);
00186         settingsWriter.endElement();
00187     }
00188     settingsWriter.endElement();
00189 }
00190 
00191 
00192 bool Map::saveOasis( KoXmlWriter & xmlWriter, KoGenStyles & mainStyles, KoStore *store, KoXmlWriter* manifestWriter, int &_indexObj, int &_partIndexObj )
00193 {
00194     if ( !m_strPassword.isEmpty() )
00195     {
00196         xmlWriter.addAttribute("table:structure-protected", "true" );
00197         QCString str = KCodecs::base64Encode( m_strPassword );
00198         xmlWriter.addAttribute("table:protection-key", QString( str.data() ) );/* FIXME !!!!*/
00199     }
00200 
00201     GenValidationStyles valStyle;
00202 
00203     KTempFile bodyTmpFile;
00204     //Check that creation of temp file was successful
00205     if (bodyTmpFile.status() != 0)
00206     {
00207         qWarning("Creation of temporary file to store document body failed.");
00208         return false;
00209     }
00210 
00211     bodyTmpFile.setAutoDelete( true );
00212     QFile* tmpFile = bodyTmpFile.file();
00213     KoXmlWriter bodyTmpWriter( tmpFile );
00214 
00215 
00216     QPtrListIterator<Sheet> it( m_lstSheets );
00217     for( ; it.current(); ++it )
00218     {
00219         it.current()->saveOasis( bodyTmpWriter, mainStyles, valStyle, store, manifestWriter, _indexObj, _partIndexObj );
00220     }
00221 
00222     valStyle.writeStyle( xmlWriter );
00223 
00224 
00225     tmpFile->close();
00226     xmlWriter.addCompleteElement( tmpFile );
00227     bodyTmpFile.close();
00228 
00229     return true;
00230 }
00231 
00232 QDomElement Map::save( QDomDocument& doc )
00233 {
00234     QDomElement mymap = doc.createElement( "map" );
00235   // Save visual info for the first view, such as active sheet and active cell
00236   // It looks like a hack, but reopening a document creates only one view anyway (David)
00237   View * view = static_cast<View*>(m_doc->views().getFirst());
00238   if ( view ) // no view if embedded document
00239   {
00240     Canvas * canvas = view->canvasWidget();
00241     mymap.setAttribute( "activeTable",  canvas->activeSheet()->sheetName() );
00242     mymap.setAttribute( "markerColumn", canvas->markerColumn() );
00243     mymap.setAttribute( "markerRow",    canvas->markerRow() );
00244     mymap.setAttribute( "xOffset",      canvas->xOffset() );
00245     mymap.setAttribute( "yOffset",      canvas->yOffset() );
00246   }
00247 
00248   if ( !m_strPassword.isNull() )
00249   {
00250     if ( m_strPassword.size() > 0 )
00251     {
00252       QCString str = KCodecs::base64Encode( m_strPassword );
00253       mymap.setAttribute( "protected", QString( str.data() ) );
00254     }
00255     else
00256       mymap.setAttribute( "protected", "" );
00257   }
00258 
00259   QPtrListIterator<Sheet> it( m_lstSheets );
00260   for( ; it.current(); ++it )
00261   {
00262     QDomElement e = it.current()->saveXML( doc );
00263     if ( e.isNull() )
00264       return e;
00265     mymap.appendChild( e );
00266   }
00267   return mymap;
00268 }
00269 
00270 bool Map::loadOasis( const QDomElement& body, KoOasisLoadingContext& oasisContext, QDict<Style>& styleMap )
00271 {
00272     if ( body.hasAttributeNS( KoXmlNS::table, "structure-protected" ) )
00273     {
00274         QCString passwd( "" );
00275         if ( body.hasAttributeNS( KoXmlNS::table, "protection-key" ) )
00276         {
00277             QString p = body.attributeNS( KoXmlNS::table, "protection-key", QString::null );
00278             QCString str( p.latin1() );
00279             passwd = KCodecs::base64Decode( str );
00280         }
00281         m_strPassword = passwd;
00282     }
00283     QDomNode sheetNode = KoDom::namedItemNS( body, KoXmlNS::table, "table" );
00284 
00285     // sanity check
00286     if ( sheetNode.isNull() ) return false;
00287 
00288     while ( !sheetNode.isNull() )
00289     {
00290         QDomElement sheetElement = sheetNode.toElement();
00291         if( !sheetElement.isNull() )
00292         {
00293             //kdDebug()<<"  Map::loadOasis tableElement is not null \n";
00294             //kdDebug()<<"tableElement.nodeName() :"<<sheetElement.nodeName()<<endl;
00295             if( sheetElement.nodeName() == "table:table" )
00296             {
00297                 if( !sheetElement.attributeNS( KoXmlNS::table, "name", QString::null ).isEmpty() )
00298                 {
00299                     Sheet* sheet = addNewSheet();
00300                     sheet->setSheetName( sheetElement.attributeNS( KoXmlNS::table, "name", QString::null ), true, false );
00301                 }
00302             }
00303         }
00304         sheetNode = sheetNode.nextSibling();
00305     }
00306 
00307     // load the sheet
00308     sheetNode = body.firstChild();
00309     while ( !sheetNode.isNull() )
00310     {
00311         QDomElement sheetElement = sheetNode.toElement();
00312         if( !sheetElement.isNull() )
00313         {
00314             kdDebug()<<"tableElement.nodeName() bis :"<<sheetElement.nodeName()<<endl;
00315             if( sheetElement.nodeName() == "table:table" )
00316             {
00317                 if( !sheetElement.attributeNS( KoXmlNS::table, "name", QString::null ).isEmpty() )
00318                 {
00319                     QString name = sheetElement.attributeNS( KoXmlNS::table, "name", QString::null );
00320                     Sheet* sheet = findSheet( name );
00321                     if( sheet )
00322                         sheet->loadOasis( sheetElement , oasisContext , styleMap);
00323                 }
00324             }
00325         }
00326         sheetNode = sheetNode.nextSibling();
00327     }
00328 
00329     return true;
00330 }
00331 
00332 
00333 bool Map::loadXML( const QDomElement& mymap )
00334 {
00335   QString activeSheet   = mymap.attribute( "activeTable" );
00336   m_initialMarkerColumn = mymap.attribute( "markerColumn" ).toInt();
00337   m_initialMarkerRow    = mymap.attribute( "markerRow" ).toInt();
00338   m_initialXOffset      = mymap.attribute( "xOffset" ).toDouble();
00339   m_initialYOffset      = mymap.attribute( "yOffset" ).toDouble();
00340 
00341   QDomNode n = mymap.firstChild();
00342   if ( n.isNull() )
00343   {
00344       // We need at least one sheet !
00345       doc()->setErrorMessage( i18n("This document has no sheets (tables).") );
00346       return false;
00347   }
00348   while( !n.isNull() )
00349   {
00350     QDomElement e = n.toElement();
00351     if ( !e.isNull() && e.tagName() == "table" )
00352     {
00353       Sheet *t = addNewSheet();
00354       if ( !t->loadXML( e ) )
00355         return false;
00356     }
00357     n = n.nextSibling();
00358   }
00359 
00360   if ( mymap.hasAttribute( "protected" ) )
00361   {
00362     QString passwd = mymap.attribute( "protected" );
00363 
00364     if ( passwd.length() > 0 )
00365     {
00366       QCString str( passwd.latin1() );
00367       m_strPassword = KCodecs::base64Decode( str );
00368     }
00369     else
00370       m_strPassword = QCString( "" );
00371   }
00372 
00373   if (!activeSheet.isEmpty())
00374   {
00375     // Used by View's constructor
00376     m_initialActiveSheet = findSheet( activeSheet );
00377   }
00378 
00379   return true;
00380 }
00381 
00382 void Map::update()
00383 {
00384   QPtrListIterator<Sheet> it( m_lstSheets );
00385   for( ; it.current(); ++it )
00386     it.current()->recalc();
00387 }
00388 
00389 Sheet* Map::findSheet( const QString & _name )
00390 {
00391     Sheet * t;
00392 
00393     for ( t = m_lstSheets.first(); t != 0L; t = m_lstSheets.next() )
00394     {
00395         if ( _name.lower() == t->sheetName().lower() )
00396             return t;
00397     }
00398 
00399     return 0L;
00400 }
00401 
00402 Sheet * Map::nextSheet( Sheet * currentSheet )
00403 {
00404     Sheet * t;
00405 
00406     if( currentSheet == m_lstSheets.last())
00407       return currentSheet;
00408 
00409     for ( t = m_lstSheets.first(); t != 0L; t = m_lstSheets.next() )
00410     {
00411         if ( t  == currentSheet )
00412             return m_lstSheets.next();
00413     }
00414 
00415     return 0L;
00416 }
00417 
00418 Sheet * Map::previousSheet( Sheet * currentSheet )
00419 {
00420     Sheet * t;
00421 
00422     if( currentSheet == m_lstSheets.first())
00423       return currentSheet;
00424 
00425     for ( t = m_lstSheets.first(); t != 0L; t = m_lstSheets.next() )
00426     {
00427         if ( t  == currentSheet )
00428             return m_lstSheets.prev();
00429     }
00430 
00431     return 0L;
00432 }
00433 
00434 bool Map::saveChildren( KoStore * _store )
00435 {
00436   QPtrListIterator<Sheet> it( m_lstSheets );
00437   for( ; it.current(); ++it )
00438   {
00439     // set the child document's url to an internal url (ex: "tar:/0/1")
00440     if ( !it.current()->saveChildren( _store, it.current()->sheetName() ) )
00441       return false;
00442   }
00443   return true;
00444 }
00445 
00446 bool Map::loadChildren( KoStore * _store )
00447 {
00448   QPtrListIterator<Sheet> it( m_lstSheets );
00449   for( ; it.current(); ++it )
00450     if ( !it.current()->loadChildren( _store ) )
00451       return false;
00452 
00453   return true;
00454 }
00455 
00456 DCOPObject * Map::dcopObject()
00457 {
00458     if ( !m_dcop )
00459         m_dcop = new MapIface( this );
00460 
00461     return m_dcop;
00462 }
00463 
00464 void Map::takeSheet( Sheet * sheet )
00465 {
00466     int pos = m_lstSheets.findRef( sheet );
00467     m_lstSheets.take( pos );
00468     m_lstDeletedSheets.append( sheet );
00469 }
00470 
00471 void Map::insertSheet( Sheet * sheet )
00472 {
00473     int pos = m_lstDeletedSheets.findRef( sheet );
00474     if ( pos != -1 )
00475         m_lstDeletedSheets.take( pos );
00476     m_lstSheets.append(sheet);
00477 }
00478 
00479 // FIXME cache this for faster operation
00480 QStringList Map::visibleSheets() const
00481 {
00482     QStringList result;
00483 
00484     QPtrListIterator<Sheet> it( m_lstSheets );
00485     for( ; it; ++it )
00486     {
00487         Sheet* sheet = it.current();
00488         if( !sheet->isHidden() )
00489             result.append( sheet->sheetName() );
00490     }
00491 
00492     return result;
00493 }
00494 
00495 // FIXME cache this for faster operation
00496 QStringList Map::hiddenSheets() const
00497 {
00498     QStringList result;
00499 
00500     QPtrListIterator<Sheet> it( m_lstSheets );
00501     for( ; it; ++it )
00502     {
00503         Sheet* sheet = it.current();
00504         if( sheet->isHidden() )
00505             result.append( sheet->sheetName() );
00506     }
00507 
00508     return result;
00509 }
00510 
00511 #include "kspread_map.moc"
00512 
KDE Home | KDE Accessibility Home | Description of Access Keys