KOffice – TDE office suite
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.

525 lines
14KB

  1. /* This file is part of the KDE project
  2. Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Library General Public
  5. License as published by the Free Software Foundation; either
  6. version 2 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public License
  12. along with this library; see the file COPYING.LIB. If not, write to
  13. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  14. * Boston, MA 02110-1301, USA.
  15. */
  16. #include <stdlib.h>
  17. #include <time.h>
  18. #include <tqfile.h>
  19. #include <kmdcodec.h>
  20. #include <tdetempfile.h>
  21. #include <KoDom.h>
  22. #include <KoGenStyles.h>
  23. #include <KoOasisSettings.h>
  24. #include <KoOasisStyles.h>
  25. #include <KoXmlNS.h>
  26. #include <KoXmlWriter.h>
  27. #include "kspread_canvas.h"
  28. #include "kspread_doc.h"
  29. #include "kspread_genvalidationstyle.h"
  30. #include "kspread_locale.h"
  31. #include "kspread_sheet.h"
  32. #include "kspread_style.h"
  33. #include "kspread_style_manager.h"
  34. #include "kspread_view.h"
  35. #include "KSpreadMapIface.h"
  36. #include "kspread_map.h"
  37. using namespace KSpread;
  38. bool Map::respectCase = true;
  39. Map::Map ( Doc* doc, const char* name)
  40. : TQObject( doc, name ),
  41. m_doc( doc ),
  42. m_initialActiveSheet( 0 ),
  43. m_initialMarkerColumn( 0 ),
  44. m_initialMarkerRow( 0 ),
  45. m_initialXOffset(0.0),
  46. m_initialYOffset(0.0),
  47. tableId (1),
  48. m_dcop( 0 )
  49. {
  50. m_lstSheets.setAutoDelete( true );
  51. }
  52. Map::~Map()
  53. {
  54. delete m_dcop;
  55. }
  56. Doc* Map::doc() const
  57. {
  58. return m_doc;
  59. }
  60. void Map::setProtected( TQCString const & passwd )
  61. {
  62. m_strPassword = passwd;
  63. }
  64. Sheet* Map::createSheet()
  65. {
  66. TQString s( i18n("Sheet%1") );
  67. s = s.arg( tableId++ );
  68. Sheet *t = new Sheet ( this, s , s.utf8());
  69. t->setSheetName( s, true ); // huh? (Werner)
  70. return t;
  71. }
  72. void Map::addSheet( Sheet *_sheet )
  73. {
  74. m_lstSheets.append( _sheet );
  75. m_doc->setModified( true );
  76. emit sig_addSheet( _sheet );
  77. }
  78. Sheet *Map::addNewSheet ()
  79. {
  80. Sheet *t = createSheet ();
  81. addSheet (t);
  82. return t;
  83. }
  84. void Map::moveSheet( const TQString & _from, const TQString & _to, bool _before )
  85. {
  86. Sheet* sheetfrom = findSheet( _from );
  87. Sheet* sheetto = findSheet( _to );
  88. int from = m_lstSheets.find( sheetfrom ) ;
  89. int to = m_lstSheets.find( sheetto ) ;
  90. if ( !_before )
  91. ++to;
  92. if ( to > (int)m_lstSheets.count() )
  93. {
  94. m_lstSheets.append( sheetfrom );
  95. m_lstSheets.take( from );
  96. }
  97. else if ( from < to )
  98. {
  99. m_lstSheets.insert( to, sheetfrom );
  100. m_lstSheets.take( from );
  101. }
  102. else
  103. {
  104. m_lstSheets.take( from );
  105. m_lstSheets.insert( to, sheetfrom );
  106. }
  107. }
  108. void Map::loadOasisSettings( KoOasisSettings &settings )
  109. {
  110. KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" );
  111. KoOasisSettings::IndexedMap viewMap = viewSettings.indexedMap( "Views" );
  112. KoOasisSettings::Items firstView = viewMap.entry( 0 );
  113. KoOasisSettings::NamedMap sheetsMap = firstView.namedMap( "Tables" );
  114. kdDebug()<<" loadOasisSettings( KoOasisSettings &settings ) exist : "<< !sheetsMap.isNull() <<endl;
  115. if ( !sheetsMap.isNull() )
  116. {
  117. TQPtrListIterator<Sheet> it( m_lstSheets );
  118. for( ; it.current(); ++it )
  119. {
  120. it.current()->loadOasisSettings( sheetsMap );
  121. }
  122. }
  123. TQString activeSheet = firstView.parseConfigItemString( "ActiveTable" );
  124. kdDebug()<<" loadOasisSettings( KoOasisSettings &settings ) activeSheet :"<<activeSheet<<endl;
  125. if (!activeSheet.isEmpty())
  126. {
  127. // Used by View's constructor
  128. m_initialActiveSheet = findSheet( activeSheet );
  129. }
  130. }
  131. void Map::saveOasisSettings( KoXmlWriter &settingsWriter )
  132. {
  133. settingsWriter.addConfigItem( "ViewId", TQString::fromLatin1( "View1" ) );
  134. // Save visual info for the first view, such as active sheet and active cell
  135. // It looks like a hack, but reopening a document creates only one view anyway (David)
  136. View * view = m_doc->views().isEmpty() ? 0 : dynamic_cast<View*>(m_doc->views().getFirst());
  137. if ( view ) // no view if embedded document
  138. {
  139. // save current sheet selection before to save marker, otherwise current pos is not saved
  140. view->saveCurrentSheetSelection();
  141. //<config:config-item config:name="ActiveTable" config:type="string">Feuille1</config:config-item>
  142. settingsWriter.addConfigItem( "ActiveTable", view->activeSheet()->sheetName() );
  143. }
  144. //<config:config-item-map-named config:name="Tables">
  145. settingsWriter.startElement("config:config-item-map-named" );
  146. settingsWriter.addAttribute("config:name","Tables" );
  147. TQPtrListIterator<Sheet> it( m_lstSheets );
  148. for( ; it.current(); ++it )
  149. {
  150. settingsWriter.startElement( "config:config-item-map-entry" );
  151. settingsWriter.addAttribute( "config:name", ( *it )->sheetName() );
  152. if ( view )
  153. {
  154. TQPoint marker = view->markerFromSheet( *it );
  155. KoPoint offset = view->offsetFromSheet( *it );
  156. settingsWriter.addConfigItem( "CursorPositionX", marker.x() );
  157. settingsWriter.addConfigItem( "CursorPositionY", marker.y() );
  158. settingsWriter.addConfigItem( "xOffset", offset.x() );
  159. settingsWriter.addConfigItem( "yOffset", offset.y() );
  160. }
  161. it.current()->saveOasisSettings( settingsWriter );
  162. settingsWriter.endElement();
  163. }
  164. settingsWriter.endElement();
  165. }
  166. bool Map::saveOasis( KoXmlWriter & xmlWriter, KoGenStyles & mainStyles, KoStore *store, KoXmlWriter* manifestWriter, int &_indexObj, int &_partIndexObj )
  167. {
  168. if ( !m_strPassword.isEmpty() )
  169. {
  170. xmlWriter.addAttribute("table:structure-protected", "true" );
  171. TQCString str = KCodecs::base64Encode( m_strPassword );
  172. xmlWriter.addAttribute("table:protection-key", TQString( str.data() ) );/* FIXME !!!!*/
  173. }
  174. GenValidationStyles valStyle;
  175. KTempFile bodyTmpFile;
  176. //Check that creation of temp file was successful
  177. if (bodyTmpFile.status() != 0)
  178. {
  179. tqWarning("Creation of temporary file to store document body failed.");
  180. return false;
  181. }
  182. bodyTmpFile.setAutoDelete( true );
  183. TQFile* tmpFile = bodyTmpFile.file();
  184. KoXmlWriter bodyTmpWriter( TQT_TQIODEVICE(tmpFile) );
  185. TQPtrListIterator<Sheet> it( m_lstSheets );
  186. for( ; it.current(); ++it )
  187. {
  188. it.current()->saveOasis( bodyTmpWriter, mainStyles, valStyle, store, manifestWriter, _indexObj, _partIndexObj );
  189. }
  190. valStyle.writeStyle( xmlWriter );
  191. tmpFile->close();
  192. xmlWriter.addCompleteElement( TQT_TQIODEVICE(tmpFile) );
  193. bodyTmpFile.close();
  194. return true;
  195. }
  196. TQDomElement Map::save( TQDomDocument& doc )
  197. {
  198. TQDomElement mymap = doc.createElement( "map" );
  199. // Save visual info for the first view, such as active sheet and active cell
  200. // It looks like a hack, but reopening a document creates only one view anyway (David)
  201. View * view = static_cast<View*>(m_doc->views().getFirst());
  202. if ( view ) // no view if embedded document
  203. {
  204. Canvas * canvas = view->canvasWidget();
  205. mymap.setAttribute( "activeTable", canvas->activeSheet()->sheetName() );
  206. mymap.setAttribute( "markerColumn", canvas->markerColumn() );
  207. mymap.setAttribute( "markerRow", canvas->markerRow() );
  208. mymap.setAttribute( "xOffset", canvas->xOffset() );
  209. mymap.setAttribute( "yOffset", canvas->yOffset() );
  210. }
  211. if ( !m_strPassword.isNull() )
  212. {
  213. if ( m_strPassword.size() > 0 )
  214. {
  215. TQCString str = KCodecs::base64Encode( m_strPassword );
  216. mymap.setAttribute( "protected", TQString( str.data() ) );
  217. }
  218. else
  219. mymap.setAttribute( "protected", "" );
  220. }
  221. TQPtrListIterator<Sheet> it( m_lstSheets );
  222. for( ; it.current(); ++it )
  223. {
  224. TQDomElement e = it.current()->saveXML( doc );
  225. if ( e.isNull() )
  226. return e;
  227. mymap.appendChild( e );
  228. }
  229. return mymap;
  230. }
  231. bool Map::loadOasis( const TQDomElement& body, KoOasisLoadingContext& oasisContext )
  232. {
  233. if ( body.hasAttributeNS( KoXmlNS::table, "structure-protected" ) )
  234. {
  235. TQCString passwd( "" );
  236. if ( body.hasAttributeNS( KoXmlNS::table, "protection-key" ) )
  237. {
  238. TQString p = body.attributeNS( KoXmlNS::table, "protection-key", TQString() );
  239. TQCString str( p.latin1() );
  240. passwd = KCodecs::base64Decode( str );
  241. }
  242. m_strPassword = passwd;
  243. }
  244. TQDomNode sheetNode = KoDom::namedItemNS( body, KoXmlNS::table, "table" );
  245. // sanity check
  246. if ( sheetNode.isNull() ) return false;
  247. while ( !sheetNode.isNull() )
  248. {
  249. TQDomElement sheetElement = sheetNode.toElement();
  250. if( !sheetElement.isNull() )
  251. {
  252. //kdDebug()<<" Map::loadOasis tableElement is not null \n";
  253. //kdDebug()<<"tableElement.nodeName() :"<<sheetElement.nodeName()<<endl;
  254. if( sheetElement.nodeName() == "table:table" )
  255. {
  256. if( !sheetElement.attributeNS( KoXmlNS::table, "name", TQString() ).isEmpty() )
  257. {
  258. Sheet* sheet = addNewSheet();
  259. sheet->setSheetName( sheetElement.attributeNS( KoXmlNS::table, "name", TQString() ), true, false );
  260. }
  261. }
  262. }
  263. sheetNode = sheetNode.nextSibling();
  264. }
  265. //pre-load auto styles
  266. TQDict<Style> autoStyles = doc()->styleManager()->loadOasisAutoStyles( oasisContext.oasisStyles() );
  267. // load the sheet
  268. sheetNode = body.firstChild();
  269. while ( !sheetNode.isNull() )
  270. {
  271. TQDomElement sheetElement = sheetNode.toElement();
  272. if( !sheetElement.isNull() )
  273. {
  274. //kdDebug()<<"tableElement.nodeName() bis :"<<sheetElement.nodeName()<<endl;
  275. if( sheetElement.nodeName() == "table:table" )
  276. {
  277. if( !sheetElement.attributeNS( KoXmlNS::table, "name", TQString() ).isEmpty() )
  278. {
  279. TQString name = sheetElement.attributeNS( KoXmlNS::table, "name", TQString() );
  280. Sheet* sheet = findSheet( name );
  281. if( sheet )
  282. sheet->loadOasis( sheetElement, oasisContext, autoStyles );
  283. }
  284. }
  285. }
  286. sheetNode = sheetNode.nextSibling();
  287. }
  288. //delete any styles which were not used
  289. doc()->styleManager()->releaseUnusedAutoStyles( autoStyles );
  290. return true;
  291. }
  292. bool Map::loadXML( const TQDomElement& mymap )
  293. {
  294. TQString activeSheet = mymap.attribute( "activeTable" );
  295. m_initialMarkerColumn = mymap.attribute( "markerColumn" ).toInt();
  296. m_initialMarkerRow = mymap.attribute( "markerRow" ).toInt();
  297. m_initialXOffset = mymap.attribute( "xOffset" ).toDouble();
  298. m_initialYOffset = mymap.attribute( "yOffset" ).toDouble();
  299. TQDomNode n = mymap.firstChild();
  300. if ( n.isNull() )
  301. {
  302. // We need at least one sheet !
  303. doc()->setErrorMessage( i18n("This document has no sheets (tables).") );
  304. return false;
  305. }
  306. while( !n.isNull() )
  307. {
  308. TQDomElement e = n.toElement();
  309. if ( !e.isNull() && e.tagName() == "table" )
  310. {
  311. Sheet *t = addNewSheet();
  312. if ( !t->loadXML( e ) )
  313. return false;
  314. }
  315. n = n.nextSibling();
  316. }
  317. if ( mymap.hasAttribute( "protected" ) )
  318. {
  319. TQString passwd = mymap.attribute( "protected" );
  320. if ( passwd.length() > 0 )
  321. {
  322. TQCString str( passwd.latin1() );
  323. m_strPassword = KCodecs::base64Decode( str );
  324. }
  325. else
  326. m_strPassword = TQCString( "" );
  327. }
  328. if (!activeSheet.isEmpty())
  329. {
  330. // Used by View's constructor
  331. m_initialActiveSheet = findSheet( activeSheet );
  332. }
  333. return true;
  334. }
  335. void Map::update()
  336. {
  337. TQPtrListIterator<Sheet> it( m_lstSheets );
  338. for( ; it.current(); ++it )
  339. it.current()->recalc();
  340. }
  341. Sheet* Map::findSheet( const TQString & _name )
  342. {
  343. Sheet * t;
  344. for ( t = m_lstSheets.first(); t != 0L; t = m_lstSheets.next() )
  345. {
  346. if ( _name.lower() == t->sheetName().lower() )
  347. return t;
  348. }
  349. return 0L;
  350. }
  351. Sheet * Map::nextSheet( Sheet * currentSheet )
  352. {
  353. Sheet * t;
  354. if( currentSheet == m_lstSheets.last())
  355. return currentSheet;
  356. for ( t = m_lstSheets.first(); t != 0L; t = m_lstSheets.next() )
  357. {
  358. if ( t == currentSheet )
  359. return m_lstSheets.next();
  360. }
  361. return 0L;
  362. }
  363. Sheet * Map::previousSheet( Sheet * currentSheet )
  364. {
  365. Sheet * t;
  366. if( currentSheet == m_lstSheets.first())
  367. return currentSheet;
  368. for ( t = m_lstSheets.first(); t != 0L; t = m_lstSheets.next() )
  369. {
  370. if ( t == currentSheet )
  371. return m_lstSheets.prev();
  372. }
  373. return 0L;
  374. }
  375. bool Map::saveChildren( KoStore * _store )
  376. {
  377. TQPtrListIterator<Sheet> it( m_lstSheets );
  378. for( ; it.current(); ++it )
  379. {
  380. // set the child document's url to an internal url (ex: "tar:/0/1")
  381. if ( !it.current()->saveChildren( _store, it.current()->sheetName() ) )
  382. return false;
  383. }
  384. return true;
  385. }
  386. bool Map::loadChildren( KoStore * _store )
  387. {
  388. TQPtrListIterator<Sheet> it( m_lstSheets );
  389. for( ; it.current(); ++it )
  390. if ( !it.current()->loadChildren( _store ) )
  391. return false;
  392. return true;
  393. }
  394. DCOPObject * Map::dcopObject()
  395. {
  396. if ( !m_dcop )
  397. m_dcop = new MapIface( this );
  398. return m_dcop;
  399. }
  400. void Map::takeSheet( Sheet * sheet )
  401. {
  402. int pos = m_lstSheets.findRef( sheet );
  403. m_lstSheets.take( pos );
  404. m_lstDeletedSheets.append( sheet );
  405. }
  406. void Map::insertSheet( Sheet * sheet )
  407. {
  408. int pos = m_lstDeletedSheets.findRef( sheet );
  409. if ( pos != -1 )
  410. m_lstDeletedSheets.take( pos );
  411. m_lstSheets.append(sheet);
  412. }
  413. // FIXME cache this for faster operation
  414. TQStringList Map::visibleSheets() const
  415. {
  416. TQStringList result;
  417. TQPtrListIterator<Sheet> it( m_lstSheets );
  418. for( ; it; ++it )
  419. {
  420. Sheet* sheet = it.current();
  421. if( !sheet->isHidden() )
  422. result.append( sheet->sheetName() );
  423. }
  424. return result;
  425. }
  426. // FIXME cache this for faster operation
  427. TQStringList Map::hiddenSheets() const
  428. {
  429. TQStringList result;
  430. TQPtrListIterator<Sheet> it( m_lstSheets );
  431. for( ; it; ++it )
  432. {
  433. Sheet* sheet = it.current();
  434. if( sheet->isHidden() )
  435. result.append( sheet->sheetName() );
  436. }
  437. return result;
  438. }
  439. #include "kspread_map.moc"