You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/kspread/kspread_map.cc

525 lines
14 KiB

/* 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 <ktempfile.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.tqarg( 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.tqfind( sheetfrom ) ;
int to = m_lstSheets.tqfind( 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::tqfromLatin1( "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)
{
qWarning("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.tqfindRef( sheet );
m_lstSheets.take( pos );
m_lstDeletedSheets.append( sheet );
}
void Map::insertSheet( Sheet * sheet )
{
int pos = m_lstDeletedSheets.tqfindRef( 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"