PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/AODL/Document/SpreadsheetDocuments/SpreadsheetDocument.cs

https://bitbucket.org/chrisc/aodl
C# | 580 lines | 302 code | 69 blank | 209 comment | 25 complexity | 59c080eb844938a4845caae4b52af316 MD5 | raw file
  1. /*************************************************************************
  2. *
  3. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
  4. *
  5. * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
  6. *
  7. * Use is subject to license terms.
  8. *
  9. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  10. * use this file except in compliance with the License. You may obtain a copy
  11. * of the License at http://www.apache.org/licenses/LICENSE-2.0. You can also
  12. * obtain a copy of the License at http://odftoolkit.org/docs/license.txt
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  16. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. *
  18. * See the License for the specific language governing permissions and
  19. * limitations under the License.
  20. *
  21. ************************************************************************/
  22. using System;
  23. using System.Collections.Generic;
  24. using System.IO;
  25. using System.Linq;
  26. using System.Reflection;
  27. using System.Xml;
  28. using System.Xml.Linq;
  29. using AODL.Document.Content;
  30. using AODL.Document.Content.Draw;
  31. using AODL.Document.Content.EmbedObjects;
  32. using AODL.Document.Content.Tables;
  33. using AODL.Document.Custom;
  34. using AODL.Document.Exceptions;
  35. using AODL.Document.Export;
  36. using AODL.Document.Import;
  37. using AODL.Document.Import.OpenDocument;
  38. using AODL.Document.Import.OpenDocument.NodeProcessors;
  39. using AODL.Document.Styles;
  40. using AODL.Document.TextDocuments;
  41. namespace AODL.Document.SpreadsheetDocuments
  42. {
  43. /// <summary>
  44. /// The SpreadsheetDocument class represent an OpenDocument
  45. /// spreadsheet document.
  46. /// </summary>
  47. public class SpreadsheetDocument : IDocument, IDisposable
  48. {
  49. private readonly IList<Graphic> _graphics;
  50. private bool _isLoadedFile;
  51. private const string _mimeTyp = "application/vnd.oasis.opendocument.spreadsheet";
  52. private int _tableCount;
  53. private readonly CustomFileCollection _customFiles;
  54. private XDocument _xmldoc;
  55. private IImporter _importer;
  56. private readonly StyleFactory m_styleFactory;
  57. /// <summary>
  58. /// Initializes a new instance of the <see cref="SpreadsheetDocument"/> class.
  59. /// </summary>
  60. public SpreadsheetDocument()
  61. {
  62. TableCollection = new TableCollection();
  63. Styles = new StyleCollection();
  64. m_styleFactory = new StyleFactory(this);
  65. CommonStyles = new StyleCollection();
  66. Content = new ContentCollection();
  67. _graphics = new List<Graphic>();
  68. FontList = new List<string>();
  69. EmbedObjects = new List<EmbedObject>();
  70. TableCollection.Inserted += TableCollection_Inserted;
  71. TableCollection.Removed += TableCollection_Removed;
  72. Content.Inserted += Content_Inserted;
  73. Content.Removed += Content_Removed;
  74. _customFiles = new CustomFileCollection();
  75. _customFiles.Clearing += CustomFiles_Clearing;
  76. _customFiles.Inserting += CustomFiles_Inserting;
  77. _customFiles.Removing += CustomFiles_Removing;
  78. }
  79. /// <summary>
  80. /// Gets the table count.
  81. /// </summary>
  82. /// <value>The table count.</value>
  83. public int TableCount
  84. {
  85. get { return _tableCount; }
  86. }
  87. /// <summary>
  88. /// Gets or sets the table collection.
  89. /// </summary>
  90. /// <value>The table collection.</value>
  91. public TableCollection TableCollection { get; set; }
  92. /// <summary>
  93. /// Gets or sets the document styes.
  94. /// </summary>
  95. /// <value>The document styes.</value>
  96. public DocumentStyles DocumentStyles { get; set; }
  97. /// <summary>
  98. /// Gets or sets the document setting.
  99. /// </summary>
  100. /// <value>The document setting.</value>
  101. public DocumentSetting DocumentSetting { get; set; }
  102. /// <summary>
  103. /// Gets or sets the document manifest.
  104. /// </summary>
  105. /// <value>The document manifest.</value>
  106. public DocumentManifest DocumentManifest { get; set; }
  107. /// <summary>
  108. /// Gets the MIME typ.
  109. /// </summary>
  110. /// <value>The MIME typ.</value>
  111. public string MimeTyp
  112. {
  113. get { return _mimeTyp; }
  114. }
  115. #region IDocument Members
  116. public IImporter Importer
  117. {
  118. get { return _importer; }
  119. }
  120. public StyleFactory StyleFactory
  121. {
  122. get { return m_styleFactory; }
  123. }
  124. /// <summary>
  125. /// The xml document the spreadsheet document based on.
  126. /// </summary>
  127. public XDocument XmlDoc
  128. {
  129. get { return _xmldoc; }
  130. set { _xmldoc = value; }
  131. }
  132. /// <summary>
  133. /// If this file was loaded
  134. /// </summary>
  135. /// <value></value>
  136. public bool IsLoadedFile
  137. {
  138. get { return _isLoadedFile; }
  139. }
  140. /// <summary>
  141. /// The font list
  142. /// </summary>
  143. /// <value></value>
  144. public IList<string> FontList { get; set; }
  145. /// <summary>
  146. /// Collection of local styles used with this document.
  147. /// </summary>
  148. /// <value></value>
  149. public StyleCollection Styles { get; set; }
  150. /// <summary>
  151. /// Collection of common styles used with this document.
  152. /// </summary>
  153. /// <value></value>
  154. public StyleCollection CommonStyles { get; set; }
  155. /// <summary>
  156. /// Collection of contents used by this document.
  157. /// </summary>
  158. /// <value></value>
  159. public ContentCollection Content { get; set; }
  160. /// <summary>
  161. /// Collection of custom files to include in package
  162. /// </summary>
  163. public CustomFileCollection CustomFiles
  164. {
  165. get { return _customFiles; }
  166. }
  167. /// <summary>
  168. /// Gets or sets the document metadata.
  169. /// </summary>
  170. /// <value>The document metadata.</value>
  171. public DocumentMetadata DocumentMetadata { get; set; }
  172. /// <summary>
  173. /// Gets or sets the document configuration2.
  174. /// </summary>
  175. /// <value>The document configuration2.</value>
  176. public DocumentConfiguration2 DocumentConfigurations2 { get; set; }
  177. /// <summary>
  178. /// Gets or sets the document pictures.
  179. /// </summary>
  180. /// <value>The document pictures.</value>
  181. public DocumentPictureCollection DocumentPictures { get; set; }
  182. /// <summary>
  183. /// Gets or sets the document thumbnails.
  184. /// </summary>
  185. /// <value>The document thumbnails.</value>
  186. public DocumentPictureCollection DocumentThumbnails { get; set; }
  187. /// <summary>
  188. /// Gets the graphics.
  189. /// </summary>
  190. /// <value>The graphics.</value>
  191. public IList<Graphic> Graphics
  192. {
  193. get { return _graphics; }
  194. }
  195. /// <summary>
  196. /// Gets the embedobject.
  197. /// </summary>
  198. /// <value>The embedobject.</value>
  199. public IList<EmbedObject> EmbedObjects { get; set; }
  200. /// <summary>
  201. /// Save the document by using the passed IExporter
  202. /// with the passed file name.
  203. /// </summary>
  204. /// <param name="filename">The name of the new file.</param>
  205. /// <param name="exporter"></param>
  206. public void Save(string filename, IExporter exporter)
  207. {
  208. CreateContentBody();
  209. exporter.Export(this, filename);
  210. }
  211. /// <summary>
  212. /// Load the given file.
  213. /// </summary>
  214. /// <param name="file"></param>
  215. /// <param name="importer"></param>
  216. public void Load(string file, IImporter importer)
  217. {
  218. _importer = importer;
  219. _isLoadedFile = true;
  220. LoadBlankContent();
  221. if (_importer != null)
  222. {
  223. if (_importer.NeedNewOpenDocument)
  224. New();
  225. _importer.Import(this, file);
  226. if (_importer.ImportError != null)
  227. if (_importer.ImportError.Count > 0)
  228. foreach (AODLWarning ob in _importer.ImportError)
  229. {
  230. if (ob.Message != null)
  231. Console.WriteLine("Err: {0}", ob.Message);
  232. if (ob.Node != null)
  233. {
  234. using (XmlWriter writer = XmlWriter.Create(Console.Out, new XmlWriterSettings { Indent = true }))
  235. {
  236. ob.Node.WriteTo(writer);
  237. }
  238. }
  239. }
  240. }
  241. }
  242. #endregion
  243. /// <summary>
  244. /// Create a new blank spreadsheet document.
  245. /// </summary>
  246. public void New()
  247. {
  248. LoadBlankContent();
  249. DocumentConfigurations2 = new DocumentConfiguration2();
  250. DocumentManifest = new DocumentManifest();
  251. DocumentManifest.New();
  252. DocumentMetadata = new DocumentMetadata(this);
  253. DocumentMetadata.New();
  254. DocumentPictures = new DocumentPictureCollection();
  255. DocumentSetting = new DocumentSetting();
  256. DocumentSetting.New();
  257. DocumentStyles = new DocumentStyles();
  258. DocumentStyles.New();
  259. ReadCommonStyles();
  260. DocumentThumbnails = new DocumentPictureCollection();
  261. }
  262. /// <summary>
  263. /// Reads the common styles.
  264. /// </summary>
  265. private void ReadCommonStyles()
  266. {
  267. OpenDocumentImporter odImporter = new OpenDocumentImporter(null) {Document = this};
  268. odImporter.ImportCommonStyles();
  269. LocalStyleProcessor lsp = new LocalStyleProcessor(this, true);
  270. lsp.ReadStyles();
  271. }
  272. /// <summary>
  273. /// Load a blank the spreadsheet content document.
  274. /// </summary>
  275. private void LoadBlankContent()
  276. {
  277. Assembly ass = Assembly.GetExecutingAssembly();
  278. Stream str = ass.GetManifestResourceStream("AODL.Resources.OD.spreadsheetcontent.xml");
  279. using (XmlReader reader = XmlReader.Create(str))
  280. {
  281. _xmldoc = XDocument.Load(reader);
  282. }
  283. }
  284. /// <summary>
  285. /// Tables the collection_ inserted.
  286. /// </summary>
  287. /// <param name="index">The index.</param>
  288. /// <param name="value">The value.</param>
  289. private void TableCollection_Inserted(int index, object value)
  290. {
  291. _tableCount++;
  292. if (!Content.Contains(value as IContent))
  293. Content.Add(value as IContent);
  294. }
  295. /// <summary>
  296. /// Tables the collection_ removed.
  297. /// </summary>
  298. /// <param name="index">The index.</param>
  299. /// <param name="value">The value.</param>
  300. private void TableCollection_Removed(int index, object value)
  301. {
  302. _tableCount--;
  303. if (Content.Contains(value as IContent))
  304. Content.Remove(value as IContent);
  305. }
  306. /// <summary>
  307. /// Content_s the inserted.
  308. /// </summary>
  309. /// <param name="index">The index.</param>
  310. /// <param name="value">The value.</param>
  311. private void Content_Inserted(int index, object value)
  312. {
  313. if (value is Table)
  314. if (!TableCollection.Contains((Table) value))
  315. TableCollection.Add(value as Table);
  316. }
  317. /// <summary>
  318. /// Content_s the removed.
  319. /// </summary>
  320. /// <param name="index">The index.</param>
  321. /// <param name="value">The value.</param>
  322. private void Content_Removed(int index, object value)
  323. {
  324. if (value is Table)
  325. if (TableCollection.Contains((Table) value))
  326. TableCollection.Remove(value as Table);
  327. }
  328. /// <summary>
  329. /// Creates the content body.
  330. /// </summary>
  331. private void CreateContentBody()
  332. {
  333. XElement nodeSpreadSheets = XmlDoc.Elements(Ns.Office + "document-content")
  334. .Elements(Ns.Office + "body")
  335. .Elements(Ns.Office + "spreadsheet").First();
  336. foreach (IContent iContent in Content)
  337. {
  338. //only table content
  339. if (iContent is Table)
  340. nodeSpreadSheets.Add(((Table) iContent).BuildNode());
  341. }
  342. CreateLocalStyleContent();
  343. CreateCommonStyleContent();
  344. }
  345. /// <summary>
  346. /// Creates the content of the local style.
  347. /// </summary>
  348. private void CreateLocalStyleContent()
  349. {
  350. XElement nodeAutomaticStyles = XmlDoc.Elements(Ns.Office + "document-content")
  351. .Elements(Ns.Office + "automatic-styles").First();
  352. foreach (IStyle style in Styles.ToValueList())
  353. nodeAutomaticStyles.Add(style.Node);
  354. }
  355. /// <summary>
  356. /// Creates the content of the common style.
  357. /// </summary>
  358. private void CreateCommonStyleContent()
  359. {
  360. XElement nodeCommonStyles = DocumentStyles.Styles.Elements(Ns.Office + "document-styles")
  361. .Elements(Ns.Office + "styles").First();
  362. nodeCommonStyles.Value = "";
  363. foreach (IStyle style in CommonStyles.ToValueList())
  364. {
  365. nodeCommonStyles.Add(new XElement(style.Node));
  366. }
  367. //Remove styles node
  368. nodeCommonStyles = XmlDoc.Elements(Ns.Office + "document-content")
  369. .Elements(Ns.Office + "styles").FirstOrDefault();
  370. if (nodeCommonStyles != null)
  371. nodeCommonStyles.Remove();
  372. }
  373. public EmbedObject GetObjectByName(string objectName)
  374. {
  375. for (int i = 0; i < EmbedObjects.Count; i++)
  376. {
  377. if ((EmbedObjects[i]).ObjectName == objectName)
  378. return (EmbedObject) EmbedObjects[i];
  379. }
  380. return null;
  381. }
  382. private void CustomFiles_Clearing()
  383. {
  384. XElement root = DocumentManifest.Manifest.Element(Ns.Manifest + "manifest");
  385. foreach (ICustomFile customFile in _customFiles)
  386. {
  387. IEnumerable<XElement> fileEntries =
  388. root.Elements(Ns.Manifest + "file-entry").Where(
  389. e =>
  390. ((string)e.Attribute(Ns.Manifest + "media-type")).Equals(customFile.MediaType ?? string.Empty,
  391. StringComparison.InvariantCulture) &&
  392. ((string)e.Attribute(Ns.Manifest + "full-path")).Equals(customFile.FullPath,
  393. StringComparison.InvariantCulture));
  394. foreach (XElement fileEntry in fileEntries)
  395. {
  396. fileEntry.Remove();
  397. }
  398. }
  399. }
  400. private void CustomFiles_Inserting(int index, ICustomFile value)
  401. {
  402. XElement root = DocumentManifest.Manifest.Element(Ns.Manifest + "manifest");
  403. IEnumerable<XElement> fileEntries =
  404. root.Elements(Ns.Manifest + "file-entry").Where(
  405. e =>
  406. ((string)e.Attribute(Ns.Manifest + "media-type")).Equals(value.MediaType ?? string.Empty,
  407. StringComparison.InvariantCulture) &&
  408. ((string)e.Attribute(Ns.Manifest + "full-path")).Equals(value.FullPath,
  409. StringComparison.InvariantCulture));
  410. if (fileEntries.Count() > 0)
  411. return;
  412. XElement fileEntry = new XElement(Ns.Manifest + "file-entry");
  413. fileEntry.SetAttributeValue(Ns.Manifest + "media-type", value.MediaType ?? string.Empty);
  414. fileEntry.SetAttributeValue(Ns.Manifest + "full-path", value.FullPath);
  415. root.Add(fileEntry);
  416. }
  417. private void CustomFiles_Removing(int index, ICustomFile value)
  418. {
  419. XElement root = DocumentManifest.Manifest.Element(Ns.Manifest + "manifest");
  420. IEnumerable<XElement> fileEntries =
  421. root.Elements(Ns.Manifest + "file-entry").Where(
  422. e =>
  423. ((string)e.Attribute(Ns.Manifest + "media-type")).Equals(value.MediaType ?? string.Empty,
  424. StringComparison.InvariantCulture) &&
  425. ((string)e.Attribute(Ns.Manifest + "full-path")).Equals(value.FullPath,
  426. StringComparison.InvariantCulture));
  427. foreach (XElement fileEntry in fileEntries)
  428. {
  429. fileEntry.Remove();
  430. }
  431. }
  432. #region IDisposable Member
  433. private bool _disposed;
  434. /// <summary>
  435. /// Releases unmanaged resources and performs other cleanup operations before the
  436. /// is reclaimed by garbage collection.
  437. /// </summary>
  438. public void Dispose()
  439. {
  440. Dispose(true);
  441. GC.SuppressFinalize(this);
  442. }
  443. /// <summary>
  444. /// Disposes the specified disposing.
  445. /// </summary>
  446. /// <param name="disposing">if set to <c>true</c> [disposing].</param>
  447. private void Dispose(bool disposing)
  448. {
  449. if (!_disposed)
  450. {
  451. if (disposing)
  452. {
  453. //DeleteUnpackedFiles();
  454. }
  455. }
  456. _disposed = true;
  457. }
  458. /// <summary>
  459. /// Releases unmanaged resources and performs other cleanup operations before the
  460. /// <see cref="AODL.Document.TextDocuments.TextDocument"/> is reclaimed by garbage collection.
  461. /// </summary>
  462. ~SpreadsheetDocument()
  463. {
  464. Dispose();
  465. }
  466. #endregion
  467. }
  468. }
  469. /*
  470. * $Log: SpreadsheetDocument.cs,v $
  471. * Revision 1.3 2008/04/29 15:39:53 mt
  472. * new copyright header
  473. *
  474. * Revision 1.2 2008/02/08 07:12:20 larsbehr
  475. * - added initial chart support
  476. * - several bug fixes
  477. *
  478. * Revision 1.1 2007/02/25 08:58:47 larsbehr
  479. * initial checkin, import from Sourceforge.net to OpenOffice.org
  480. *
  481. * Revision 1.7 2007/02/04 22:52:57 larsbm
  482. * - fixed bug in resize algorithm for rows and cells
  483. * - extending IDocument, overload SaveTo to accept external exporter impl.
  484. * - initial version of AODL PDF exporter add on
  485. *
  486. * Revision 1.6 2006/02/21 19:34:55 larsbm
  487. * - Fixed Bug text that contains a xml tag will be imported as UnknowText and not correct displayed if document is exported as HTML.
  488. * - Fixed Bug [ 1436080 ] Common styles
  489. *
  490. * Revision 1.5 2006/02/06 19:27:23 larsbm
  491. * - fixed bug in spreadsheet document
  492. * - added smal OpenOfficeLib for document printing
  493. *
  494. * Revision 1.4 2006/02/05 20:03:32 larsbm
  495. * - Fixed several bugs
  496. * - clean up some messy code
  497. *
  498. * Revision 1.3 2006/02/02 21:55:59 larsbm
  499. * - Added Clone object support for many AODL object types
  500. * - New Importer implementation PlainTextImporter and CsvImporter
  501. * - New tests
  502. *
  503. * Revision 1.2 2006/01/29 18:52:14 larsbm
  504. * - Added support for common styles (style templates in OpenOffice)
  505. * - Draw TextBox import and export
  506. * - DrawTextBox html export
  507. *
  508. * Revision 1.1 2006/01/29 11:28:23 larsbm
  509. * - Changes for the new version. 1.2. see next changelog for details
  510. *
  511. */