/* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include <stdlib.h> #include <time.h> #include <tqfile.h> #include <kmdcodec.h> #include <tdetempfile.h> #include <KoDom.h> #include <KoGenStyles.h> #include <KoOasisSettings.h> #include <KoOasisStyles.h> #include <KoXmlNS.h> #include <KoXmlWriter.h> #include "kspread_canvas.h" #include "kspread_doc.h" #include "kspread_genvalidationstyle.h" #include "kspread_locale.h" #include "kspread_sheet.h" #include "kspread_style.h" #include "kspread_style_manager.h" #include "kspread_view.h" #include "KSpreadMapIface.h" #include "kspread_map.h" using namespace KSpread; bool Map::respectCase = true; Map::Map ( Doc* doc, const char* name) : TQObject( doc, name ), m_doc( doc ), m_initialActiveSheet( 0 ), m_initialMarkerColumn( 0 ), m_initialMarkerRow( 0 ), m_initialXOffset(0.0), m_initialYOffset(0.0), tableId (1), m_dcop( 0 ) { m_lstSheets.setAutoDelete( true ); } Map::~Map() { delete m_dcop; } Doc* Map::doc() const { return m_doc; } void Map::setProtected( TQCString const & passwd ) { m_strPassword = passwd; } Sheet* Map::createSheet() { TQString s( i18n("Sheet%1") ); s = s.arg( tableId++ ); Sheet *t = new Sheet ( this, s , s.utf8()); t->setSheetName( s, true ); // huh? (Werner) return t; } void Map::addSheet( Sheet *_sheet ) { m_lstSheets.append( _sheet ); m_doc->setModified( true ); emit sig_addSheet( _sheet ); } Sheet *Map::addNewSheet () { Sheet *t = createSheet (); addSheet (t); return t; } void Map::moveSheet( const TQString & _from, const TQString & _to, bool _before ) { Sheet* sheetfrom = findSheet( _from ); Sheet* sheetto = findSheet( _to ); int from = m_lstSheets.find( sheetfrom ) ; int to = m_lstSheets.find( sheetto ) ; if ( !_before ) ++to; if ( to > (int)m_lstSheets.count() ) { m_lstSheets.append( sheetfrom ); m_lstSheets.take( from ); } else if ( from < to ) { m_lstSheets.insert( to, sheetfrom ); m_lstSheets.take( from ); } else { m_lstSheets.take( from ); m_lstSheets.insert( to, sheetfrom ); } } void Map::loadOasisSettings( KoOasisSettings &settings ) { KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" ); KoOasisSettings::IndexedMap viewMap = viewSettings.indexedMap( "Views" ); KoOasisSettings::Items firstView = viewMap.entry( 0 ); KoOasisSettings::NamedMap sheetsMap = firstView.namedMap( "Tables" ); kdDebug()<<" loadOasisSettings( KoOasisSettings &settings ) exist : "<< !sheetsMap.isNull() <<endl; if ( !sheetsMap.isNull() ) { TQPtrListIterator<Sheet> it( m_lstSheets ); for( ; it.current(); ++it ) { it.current()->loadOasisSettings( sheetsMap ); } } TQString activeSheet = firstView.parseConfigItemString( "ActiveTable" ); kdDebug()<<" loadOasisSettings( KoOasisSettings &settings ) activeSheet :"<<activeSheet<<endl; if (!activeSheet.isEmpty()) { // Used by View's constructor m_initialActiveSheet = findSheet( activeSheet ); } } void Map::saveOasisSettings( KoXmlWriter &settingsWriter ) { settingsWriter.addConfigItem( "ViewId", TQString::fromLatin1( "View1" ) ); // Save visual info for the first view, such as active sheet and active cell // It looks like a hack, but reopening a document creates only one view anyway (David) View * view = m_doc->views().isEmpty() ? 0 : dynamic_cast<View*>(m_doc->views().getFirst()); if ( view ) // no view if embedded document { // save current sheet selection before to save marker, otherwise current pos is not saved view->saveCurrentSheetSelection(); //<config:config-item config:name="ActiveTable" config:type="string">Feuille1</config:config-item> settingsWriter.addConfigItem( "ActiveTable", view->activeSheet()->sheetName() ); } //<config:config-item-map-named config:name="Tables"> settingsWriter.startElement("config:config-item-map-named" ); settingsWriter.addAttribute("config:name","Tables" ); TQPtrListIterator<Sheet> it( m_lstSheets ); for( ; it.current(); ++it ) { settingsWriter.startElement( "config:config-item-map-entry" ); settingsWriter.addAttribute( "config:name", ( *it )->sheetName() ); if ( view ) { TQPoint marker = view->markerFromSheet( *it ); KoPoint offset = view->offsetFromSheet( *it ); settingsWriter.addConfigItem( "CursorPositionX", marker.x() ); settingsWriter.addConfigItem( "CursorPositionY", marker.y() ); settingsWriter.addConfigItem( "xOffset", offset.x() ); settingsWriter.addConfigItem( "yOffset", offset.y() ); } it.current()->saveOasisSettings( settingsWriter ); settingsWriter.endElement(); } settingsWriter.endElement(); } bool Map::saveOasis( KoXmlWriter & xmlWriter, KoGenStyles & mainStyles, KoStore *store, KoXmlWriter* manifestWriter, int &_indexObj, int &_partIndexObj ) { if ( !m_strPassword.isEmpty() ) { xmlWriter.addAttribute("table:structure-protected", "true" ); TQCString str = KCodecs::base64Encode( m_strPassword ); xmlWriter.addAttribute("table:protection-key", TQString( str.data() ) );/* FIXME !!!!*/ } GenValidationStyles valStyle; KTempFile bodyTmpFile; //Check that creation of temp file was successful if (bodyTmpFile.status() != 0) { tqWarning("Creation of temporary file to store document body failed."); return false; } bodyTmpFile.setAutoDelete( true ); TQFile* tmpFile = bodyTmpFile.file(); KoXmlWriter bodyTmpWriter( TQT_TQIODEVICE(tmpFile) ); TQPtrListIterator<Sheet> it( m_lstSheets ); for( ; it.current(); ++it ) { it.current()->saveOasis( bodyTmpWriter, mainStyles, valStyle, store, manifestWriter, _indexObj, _partIndexObj ); } valStyle.writeStyle( xmlWriter ); tmpFile->close(); xmlWriter.addCompleteElement( TQT_TQIODEVICE(tmpFile) ); bodyTmpFile.close(); return true; } TQDomElement Map::save( TQDomDocument& doc ) { TQDomElement mymap = doc.createElement( "map" ); // Save visual info for the first view, such as active sheet and active cell // It looks like a hack, but reopening a document creates only one view anyway (David) View * view = static_cast<View*>(m_doc->views().getFirst()); if ( view ) // no view if embedded document { Canvas * canvas = view->canvasWidget(); mymap.setAttribute( "activeTable", canvas->activeSheet()->sheetName() ); mymap.setAttribute( "markerColumn", canvas->markerColumn() ); mymap.setAttribute( "markerRow", canvas->markerRow() ); mymap.setAttribute( "xOffset", canvas->xOffset() ); mymap.setAttribute( "yOffset", canvas->yOffset() ); } if ( !m_strPassword.isNull() ) { if ( m_strPassword.size() > 0 ) { TQCString str = KCodecs::base64Encode( m_strPassword ); mymap.setAttribute( "protected", TQString( str.data() ) ); } else mymap.setAttribute( "protected", "" ); } TQPtrListIterator<Sheet> it( m_lstSheets ); for( ; it.current(); ++it ) { TQDomElement e = it.current()->saveXML( doc ); if ( e.isNull() ) return e; mymap.appendChild( e ); } return mymap; } bool Map::loadOasis( const TQDomElement& body, KoOasisLoadingContext& oasisContext ) { if ( body.hasAttributeNS( KoXmlNS::table, "structure-protected" ) ) { TQCString passwd( "" ); if ( body.hasAttributeNS( KoXmlNS::table, "protection-key" ) ) { TQString p = body.attributeNS( KoXmlNS::table, "protection-key", TQString() ); TQCString str( p.latin1() ); passwd = KCodecs::base64Decode( str ); } m_strPassword = passwd; } TQDomNode sheetNode = KoDom::namedItemNS( body, KoXmlNS::table, "table" ); // sanity check if ( sheetNode.isNull() ) return false; while ( !sheetNode.isNull() ) { TQDomElement sheetElement = sheetNode.toElement(); if( !sheetElement.isNull() ) { //kdDebug()<<" Map::loadOasis tableElement is not null \n"; //kdDebug()<<"tableElement.nodeName() :"<<sheetElement.nodeName()<<endl; if( sheetElement.nodeName() == "table:table" ) { if( !sheetElement.attributeNS( KoXmlNS::table, "name", TQString() ).isEmpty() ) { Sheet* sheet = addNewSheet(); sheet->setSheetName( sheetElement.attributeNS( KoXmlNS::table, "name", TQString() ), true, false ); } } } sheetNode = sheetNode.nextSibling(); } //pre-load auto styles TQDict<Style> autoStyles = doc()->styleManager()->loadOasisAutoStyles( oasisContext.oasisStyles() ); // load the sheet sheetNode = body.firstChild(); while ( !sheetNode.isNull() ) { TQDomElement sheetElement = sheetNode.toElement(); if( !sheetElement.isNull() ) { //kdDebug()<<"tableElement.nodeName() bis :"<<sheetElement.nodeName()<<endl; if( sheetElement.nodeName() == "table:table" ) { if( !sheetElement.attributeNS( KoXmlNS::table, "name", TQString() ).isEmpty() ) { TQString name = sheetElement.attributeNS( KoXmlNS::table, "name", TQString() ); Sheet* sheet = findSheet( name ); if( sheet ) sheet->loadOasis( sheetElement, oasisContext, autoStyles ); } } } sheetNode = sheetNode.nextSibling(); } //delete any styles which were not used doc()->styleManager()->releaseUnusedAutoStyles( autoStyles ); return true; } bool Map::loadXML( const TQDomElement& mymap ) { TQString activeSheet = mymap.attribute( "activeTable" ); m_initialMarkerColumn = mymap.attribute( "markerColumn" ).toInt(); m_initialMarkerRow = mymap.attribute( "markerRow" ).toInt(); m_initialXOffset = mymap.attribute( "xOffset" ).toDouble(); m_initialYOffset = mymap.attribute( "yOffset" ).toDouble(); TQDomNode n = mymap.firstChild(); if ( n.isNull() ) { // We need at least one sheet ! doc()->setErrorMessage( i18n("This document has no sheets (tables).") ); return false; } while( !n.isNull() ) { TQDomElement e = n.toElement(); if ( !e.isNull() && e.tagName() == "table" ) { Sheet *t = addNewSheet(); if ( !t->loadXML( e ) ) return false; } n = n.nextSibling(); } if ( mymap.hasAttribute( "protected" ) ) { TQString passwd = mymap.attribute( "protected" ); if ( passwd.length() > 0 ) { TQCString str( passwd.latin1() ); m_strPassword = KCodecs::base64Decode( str ); } else m_strPassword = TQCString( "" ); } if (!activeSheet.isEmpty()) { // Used by View's constructor m_initialActiveSheet = findSheet( activeSheet ); } return true; } void Map::update() { TQPtrListIterator<Sheet> it( m_lstSheets ); for( ; it.current(); ++it ) it.current()->recalc(); } Sheet* Map::findSheet( const TQString & _name ) { Sheet * t; for ( t = m_lstSheets.first(); t != 0L; t = m_lstSheets.next() ) { if ( _name.lower() == t->sheetName().lower() ) return t; } return 0L; } Sheet * Map::nextSheet( Sheet * currentSheet ) { Sheet * t; if( currentSheet == m_lstSheets.last()) return currentSheet; for ( t = m_lstSheets.first(); t != 0L; t = m_lstSheets.next() ) { if ( t == currentSheet ) return m_lstSheets.next(); } return 0L; } Sheet * Map::previousSheet( Sheet * currentSheet ) { Sheet * t; if( currentSheet == m_lstSheets.first()) return currentSheet; for ( t = m_lstSheets.first(); t != 0L; t = m_lstSheets.next() ) { if ( t == currentSheet ) return m_lstSheets.prev(); } return 0L; } bool Map::saveChildren( KoStore * _store ) { TQPtrListIterator<Sheet> it( m_lstSheets ); for( ; it.current(); ++it ) { // set the child document's url to an internal url (ex: "tar:/0/1") if ( !it.current()->saveChildren( _store, it.current()->sheetName() ) ) return false; } return true; } bool Map::loadChildren( KoStore * _store ) { TQPtrListIterator<Sheet> it( m_lstSheets ); for( ; it.current(); ++it ) if ( !it.current()->loadChildren( _store ) ) return false; return true; } DCOPObject * Map::dcopObject() { if ( !m_dcop ) m_dcop = new MapIface( this ); return m_dcop; } void Map::takeSheet( Sheet * sheet ) { int pos = m_lstSheets.findRef( sheet ); m_lstSheets.take( pos ); m_lstDeletedSheets.append( sheet ); } void Map::insertSheet( Sheet * sheet ) { int pos = m_lstDeletedSheets.findRef( sheet ); if ( pos != -1 ) m_lstDeletedSheets.take( pos ); m_lstSheets.append(sheet); } // FIXME cache this for faster operation TQStringList Map::visibleSheets() const { TQStringList result; TQPtrListIterator<Sheet> it( m_lstSheets ); for( ; it; ++it ) { Sheet* sheet = it.current(); if( !sheet->isHidden() ) result.append( sheet->sheetName() ); } return result; } // FIXME cache this for faster operation TQStringList Map::hiddenSheets() const { TQStringList result; TQPtrListIterator<Sheet> it( m_lstSheets ); for( ; it; ++it ) { Sheet* sheet = it.current(); if( sheet->isHidden() ) result.append( sheet->sheetName() ); } return result; } #include "kspread_map.moc"