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