- "Calc Class - Used to create OpenDocument Format Calc Spreadsheets."
- def __init__(self, sheetname=None, opendoc=None, debug=False):
- "Initialize ooolib Calc instance"
- # Default to no debugging
- self.debug = debug
- if not sheetname: sheetname = "Sheet1"
- self.sheets = [CalcSheet(sheetname)] # The main sheet will be initially called 'Sheet1'
- self.sheet_index = 0 # We initially start on the first sheet
- self.styles = CalcStyles()
- self.meta = Meta('ods')
- self.styles.get_style_code('column') # Force generation of default column
- self.styles.get_style_code('row') # Force generation of default row
- self.styles.get_style_code('table') # Force generation of default table
- self.styles.get_style_code('cell') # Force generation of default cell
- self.manifest_files = [] # List of extra files included
- self.manifest_index = 1 # Index of added manifest files
-
- # Data Parsing
- self.parser_element_list = []
- self.parser_element = ""
- self.parser_sheet_num = 0
- self.parser_sheet_row = 0
- self.parser_sheet_column = 0
- self.parser_cell_repeats = 0
- self.parser_cell_string_pending = False
- self.parser_cell_string_line = ""
-
- # See if we need to read a document
- if opendoc:
- # Verify that the document exists
- if self.debug: print "Opening Document: %s" % opendoc
-
- # Okay, now we load the file
- self.load(opendoc)
-
- def debug_level(self, level):
- """Set debug level:
- True if you want debugging messages
- False if you do not.
- """
- self.debug = level
-
- def file_mimetype(self, filename):
- "Determine the filetype from the filename"
- parts = filename.lower().split('.')
- ext = parts[-1]
- if (ext == 'png'): return (ext, "image/png")
- if (ext == 'gif'): return (ext, "image/gif")
- return (ext, "image/unknown")
-
- def add_file(self, filename):
- """Prepare a file for loading into ooolib
-
- The filename should be the local filesystem name for
- the file. The file is then prepared to be included in
- the creation of the final document. The file needs to
- remain in place so that it is available when the actual
- document creation happens.
- """
- # mimetype set to (ext, filetype)
- mimetype = self.file_mimetype(filename)
- newname = "Pictures/%08d.%s" % (self.manifest_index, mimetype[0])
- self.manifest_index += 1
- filetype = mimetype[1]
- self.manifest_files.append((filename, filetype, newname))
- return newname
-
- def set_meta(self, metaname, value):
- "Set meta data in your document."
- self.meta.set_meta(metaname, value)
-
- def get_meta_value(self, metaname):
- "Get meta data value for a given metaname"
- return self.meta.get_meta_value(metaname)
-
- def get_sheet_name(self):
- "Returns the sheet name"
- return self.sheets[self.sheet_index].get_name()
-
- def get_sheet_dimensions(self):
- "Returns the sheet dimensions in (cols, rows)"
- return self.sheets[self.sheet_index].get_sheet_dimensions()
-
- def set_column_property(self, column, name, value):
- "Set Column Properties"
- if name == 'width':
- # column number column needs column-width set to value
- self.styles.set_property('column', 'style:column-width', value)
- style_code = self.styles.get_style_code('column')
- self.sheets[self.sheet_index].set_sheet_config(('col', column), style_code)
-
- def set_row_property(self, row, name, value):
- "Set row Properties"
- if name == 'height':
- # row number row needs row-height set to value
- self.styles.set_property('row', 'style:row-height', value)
- style_code = self.styles.get_style_code('row')
- self.sheets[self.sheet_index].set_sheet_config(('row', row), style_code)
-
- def set_cell_property(self, name, value):
- """Turn and off cell properties
-
- Actual application of properties is handled by setting a value."""
- # background images need to be handled a little differently
- # because they need to also be inserted into the final document
- if (name == 'backgroundimage'):
- # Add file and modify value
- value = self.add_file(value)
- self.styles.set_property('cell', name, value)
-
- def get_sheet_index(self):
- "Return the current sheet index number"
- return self.sheet_index
-
- def set_sheet_index(self, index):
- "Set the sheet index"
- if type(index) == type(1):
- if index >= 0 and index < len(self.sheets):
- self.sheet_index = index
- return self.sheet_index
-
- def get_sheet_count(self):
- "Returns the number of existing sheets"
- return len(self.sheets)
-
- def new_sheet(self, sheetname):
- "Create a new sheet"
- self.sheet_index = len(self.sheets)
- self.sheets.append(CalcSheet(sheetname))
- return self.sheet_index
-
- def set_cell_value(self, col, row, datatype, value):
- "Set the value for a given cell"
- self.sheets[self.sheet_index].set_sheet_value((col, row), datatype, value)
- style_code = self.styles.get_style_code('cell')
- self.sheets[self.sheet_index].set_sheet_config((col, row), style_code)
-
- def get_cell_value(self, col, row):
- "Get a cell value tuple (type, value) for a given cell"
- sheetvalue = self.sheets[self.sheet_index].get_sheet_value(col, row)
- # We stop here if there is no value for sheetvalue
- if sheetvalue == None: return sheetvalue
- # Now check to see if we have a value tuple
- if 'value' in sheetvalue:
- return sheetvalue['value']
- else:
- return None
-
- def load(self, filename):
- """Load .ods spreadsheet.
-
- The load function loads data from a document into the current cells.
- """
- # Read in the important files
-
- # meta.xml
- data = self._zip_read(filename, "meta.xml")
- self.meta.meta_parse(data)
-
- # content.xml
- data = self._zip_read(filename, "content.xml")
- self.content_parse(data)
-
- # settings.xml - I do not remember putting anything here
- # styles.xml - I do not remember putting anything here
-
- def parse_content_start_element(self, name, attrs):
- if self.debug: print '* Start element:', name
- self.parser_element_list.append(name)
- self.parser_element = self.parser_element_list[-1]
-
- # Keep track of the current sheet number
- if (self.parser_element == 'table:table'):
- # Move to starting cell
- self.parser_sheet_row = 0
- self.parser_sheet_column = 0
- # Increment the sheet number count
- self.parser_sheet_num += 1
- if (self.parser_sheet_num - 1 != self.sheet_index):
- # We are not on the first sheet and need to create a new sheet.
- # We will automatically move to the new sheet
- sheetname = "Sheet%d" % self.parser_sheet_num
- if 'table:name' in attrs: sheetname = attrs['table:name']
- self.new_sheet(sheetname)
- else:
- # We are on the first sheet and will need to overwrite the default name
- sheetname = "Sheet%d" % self.parser_sheet_num
- if 'table:name' in attrs: sheetname = attrs['table:name']
- self.sheets[self.sheet_index].set_name(sheetname)
-
- # Update the row numbers
- if (self.parser_element == 'table:table-row'):
- self.parser_sheet_row += 1
- self.parser_sheet_column = 0
-
- # Okay, now keep track of the sheet cell data
- if (self.parser_element == 'table:table-cell'):
- # By default it will repeat zero times
- self.parser_cell_repeats = 0
- # We must be in a new column
- self.parser_sheet_column += 1
- # Set some default values
- datatype = ""
- value = ""
- # Get values from attrs hash
- if 'office:value-type' in attrs: datatype = attrs['office:value-type']
- if 'office:value' in attrs: value = attrs['office:value']
- if 'table:formula' in attrs:
- datatype = 'formula'
- value = attrs['table:formula']
- if datatype == 'string':
- datatype = ""
- self.parser_cell_string_pending = True
- self.parser_cell_string_line = ""
- if 'table:number-columns-repeated' in attrs:
- self.parser_cell_repeats = int(attrs['table:number-columns-repeated']) - 1
- # Set the cell value
- if datatype:
- # I should do this once per cell repeat above 0
- for i in range(0, self.parser_cell_repeats+1):
- self.set_cell_value(self.parser_sheet_column+i, self.parser_sheet_row, datatype, value)
-
- # There are lots of interesting cases with table:table-cell data. One problem is
- # reading the number of embedded spaces correctly. This code should help us get
- # the number of spaces out.
-
- if (self.parser_element == 'text:s'):
- # This means we have a number of spaces
- count_num = 0
- if 'text:c' in attrs:
- count_alpha = attrs['text:c']
- if (count_alpha.isdigit()):
- count_num = int(count_alpha)
- # I am not sure what to do if we do not have a string pending
- if (self.parser_cell_string_pending == True):
- # Append the currect number of spaces to the end
- self.parser_cell_string_line = "%s%s" % (self.parser_cell_string_line, ' '*count_num)
-
- if (self.parser_element == 'text:tab-stop'):
- if (self.parser_cell_string_pending == True):
- self.parser_cell_string_line = "%s\t" % (self.parser_cell_string_line)
-
- if (self.parser_element == 'text:line-break'):
- if (self.parser_cell_string_pending == True):
- self.parser_cell_string_line = "%s\n" % (self.parser_cell_string_line)
-
- # Debugging statements
- if self.debug: print " List: ", self.parser_element_list
- if self.debug: print " Attributes: ", attrs
-
-
- def parse_content_end_element(self, name):
- if self.debug: print '* End element:', name
- if name != self.parser_element:
- print "Tag Mismatch: '%s' != '%s'" % (name, self.parser_element)
- self.parser_element_list.pop()
-
- # If the element was text:p and we are in string mode
- if (self.parser_element == 'text:p'):
- if (self.parser_cell_string_pending):
- self.parser_cell_string_pending = False
-
- # Take care of repeated cells
- if (self.parser_element == 'table:table-cell'):
- self.parser_sheet_column += self.parser_cell_repeats
-
- # Readjust parser_element_list and parser_element
- if (self.parser_element_list):
- self.parser_element = self.parser_element_list[-1]
- else:
- self.parser_element = ""
-
- def parse_content_char_data(self, data):
- if self.debug: print " Character data: ", repr(data)
-
- if (self.parser_element == 'text:p' or self.parser_element == 'text:span'):
- if (self.parser_cell_string_pending):
- # Set the string and leave string pending mode
- # This does feel a little kludgy, but it does the job
- self.parser_cell_string_line = "%s%s" % (self.parser_cell_string_line, data)
-
- # I should do this once per cell repeat above 0
- for i in range(0, self.parser_cell_repeats+1):
- self.set_cell_value(self.parser_sheet_column+i, self.parser_sheet_row,
- 'string', self.parser_cell_string_line)
-
-
- def content_parse(self, data):
- "Parse Content Data from a content.xml file"
-
- # Debugging statements
- if self.debug:
- # Sometimes it helps to see the document that was read from
- print data
- print "\n\n\n"
-
- # Create parser
- parser = xml.parsers.expat.ParserCreate()
- # Set up parser callback functions
- parser.StartElementHandler = self.parse_content_start_element
- parser.EndElementHandler = self.parse_content_end_element
- parser.CharacterDataHandler = self.parse_content_char_data
-
- # Actually parse the data
- parser.Parse(data, 1)
-
- def save(self, filename):
- """Save .ods spreadsheet.
-
- The save function saves the current cells and settings into a document.
- """
- if self.debug: print "Writing %s" % filename
- self.savefile = zipfile.ZipFile(filename, "w")
- if self.debug: print " meta.xml"
- self._zip_insert(self.savefile, "meta.xml", self.meta.get_meta())
- if self.debug: print " mimetype"
- self._zip_insert(self.savefile, "mimetype", "application/vnd.oasis.opendocument.spreadsheet")
- if self.debug: print " Configurations2/accelerator/current.xml"
- self._zip_insert(self.savefile, "Configurations2/accelerator/current.xml", "")
- if self.debug: print " META-INF/manifest.xml"
- self._zip_insert(self.savefile, "META-INF/manifest.xml", self._ods_manifest())
- if self.debug: print " content.xml"
- self._zip_insert(self.savefile, "content.xml", self._ods_content())
- if self.debug: print " settings.xml"
- self._zip_insert(self.savefile, "settings.xml", self._ods_settings())
- if self.debug: print " styles.xml"
- self._zip_insert(self.savefile, "styles.xml", self._ods_styles())
-
- # Add additional files if needed
- for fileset in self.manifest_files:
- (filename, filetype, newname) = fileset
- # Read in the file
- data = self._file_load(filename)
- if self.debug: print " Inserting '%s' as '%s'" % (filename, newname)
- self._zip_insert_binary(self.savefile, newname, data)
-
- def _file_load(self, filename):
- "Load a file"
- file = open(filename, "rb")
- data = file.read()
- file.close()
- return data
-
- def _zip_insert_binary(self, file, filename, data):
- "Insert a binary file into the zip archive"
- now = time.localtime(time.time())[:6]
- info = zipfile.ZipInfo(filename)
- info.date_time = now
- info.compress_type = zipfile.ZIP_DEFLATED
- file.writestr(info, data)
-
-
- def _zip_insert(self, file, filename, data):
- "Insert a file into the zip archive"
-
- # zip seems to struggle with non-ascii characters
- data = data.encode('utf-8')
-
- now = time.localtime(time.time())[:6]
- info = zipfile.ZipInfo(filename)
- info.date_time = now
- info.compress_type = zipfile.ZIP_DEFLATED
- file.writestr(info, data)
-
- def _zip_read(self, file, filename):
- "Get the data from a file in the zip archive by filename"
- file = zipfile.ZipFile(file, "r")
- data = file.read(filename)
- # Need to close the file
- file.close()
- return data
-
- def _ods_content(self):
- "Generate ods content.xml data"
-
- # This will list all of the sheets in the document
- self.sheetdata = ['tag', 'office:spreadsheet']
- for sheet in self.sheets:
- if self.debug:
- sheet_name = sheet.get_name()
- print " Creating Sheet '%s'" % sheet_name
- sheet_list = sheet.get_lists()
- self.sheetdata.append(sheet_list)
- # Automatic Styles
- self.automatic_styles = self.styles.get_automatic_styles()
-
- self.data = ['tag', 'office:document-content',
- ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'],
- ['element', 'xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'],
- ['element', 'xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'],
- ['element', 'xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'],
- ['element', 'xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'],
- ['element', 'xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'],
- ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'],
- ['element', 'xmlns:dc', 'http://purl.org/dc/elements/1.1/'],
- ['element', 'xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'],
- ['element', 'xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'],
- ['element', 'xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'],
- ['element', 'xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'],
- ['element', 'xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'],
- ['element', 'xmlns:math', 'http://www.w3.org/1998/Math/MathML'],
- ['element', 'xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'],
- ['element', 'xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'],
- ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'],
- ['element', 'xmlns:ooow', 'http://openoffice.org/2004/writer'],
- ['element', 'xmlns:oooc', 'http://openoffice.org/2004/calc'],
- ['element', 'xmlns:dom', 'http://www.w3.org/2001/xml-events'],
- ['element', 'xmlns:xforms', 'http://www.w3.org/2002/xforms'],
- ['element', 'xmlns:xsd', 'http://www.w3.org/2001/XMLSchema'],
- ['element', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'],
- ['element', 'office:version', '1.0'],
- ['tagline', 'office:scripts'],
- ['tag', 'office:font-face-decls',
- ['tagline', 'style:font-face',
- ['element', 'style:name', 'DejaVu Sans'],
- ['element', 'svg:font-family', ''DejaVu Sans''],
- ['element', 'style:font-pitch', 'variable']],
- ['tagline', 'style:font-face',
- ['element', 'style:name', 'Nimbus Sans L'],
- ['element', 'svg:font-family', ''Nimbus Sans L''],
- ['element', 'style:font-family-generic', 'swiss'],
- ['element', 'style:font-pitch', 'variable']]],
-
- # Automatic Styles
- self.automatic_styles,
-
- ['tag', 'office:body',
- self.sheetdata]] # Sheets are generated from the CalcSheet class
-
- # Generate content.xml XML data
- xml = XML()
- self.lines = xml.convert(self.data)
- self.filedata = '\n'.join(self.lines)
- # Return generated data
- return self.filedata
-
- def _ods_manifest(self):
- "Generate ods manifest.xml data"
- self.data = ['tag', 'manifest:manifest',
- ['element', 'xmlns:manifest', 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'],
- ['tagline', 'manifest:file-entry',
- ['element', 'manifest:media-type', 'application/vnd.oasis.opendocument.spreadsheet'],
- ['element', 'manifest:full-path', '/']],
- ['tagline', 'manifest:file-entry',
- ['element', 'manifest:media-type', 'application/vnd.sun.xml.ui.configuration'],
- ['element', 'manifest:full-path', 'Configurations2/']],
- ['tagline', 'manifest:file-entry',
- ['element', 'manifest:media-type', ''],
- ['element', 'manifest:full-path', 'Configurations2/accelerator/']],
- ['tagline', 'manifest:file-entry',
- ['element', 'manifest:media-type', ''],
- ['element', 'manifest:full-path', 'Configurations2/accelerator/current.xml']],
- ['tagline', 'manifest:file-entry',
- ['element', 'manifest:media-type', 'text/xml'],
- ['element', 'manifest:full-path', 'content.xml']],
- ['tagline', 'manifest:file-entry',
- ['element', 'manifest:media-type', 'text/xml'],
- ['element', 'manifest:full-path', 'styles.xml']],
- ['tagline', 'manifest:file-entry',
- ['element', 'manifest:media-type', 'text/xml'],
- ['element', 'manifest:full-path', 'meta.xml']],
- ['tagline', 'manifest:file-entry',
- ['element', 'manifest:media-type', 'text/xml'],
- ['element', 'manifest:full-path', 'settings.xml']]]
-
- # Add additional files to manifest list
- for fileset in self.manifest_files:
- (filename, filetype, newname) = fileset
- addfile = ['tagline', 'manifest:file-entry',
- ['element', 'manifest:media-type', filetype],
- ['element', 'manifest:full-path', newname]]
- self.data.append(addfile)
-
- # Generate content.xml XML data
- xml = XML()
- self.lines = xml.convert(self.data)
- self.filedata = '\n'.join(self.lines)
- # Return generated data
- return self.filedata
-
-
- def _ods_settings(self):
- "Generate ods settings.xml data"
- self.data = ['tag', 'office:document-settings',
- ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'],
- ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'],
- ['element', 'xmlns:config', 'urn:oasis:names:tc:opendocument:xmlns:config:1.0'],
- ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'],
- ['element', 'office:version', '1.0'],
- ['tag', 'office:settings',
- ['tag', 'config:config-item-set',
- ['element', 'config:name', 'ooo:view-settings'],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'VisibleAreaTop'],
- ['element', 'config:type', 'int'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'VisibleAreaLeft'],
- ['element', 'config:type', 'int'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'VisibleAreaWidth'],
- ['element', 'config:type', 'int'],
- ['data', '6774']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'VisibleAreaHeight'],
- ['element', 'config:type', 'int'],
- ['data', '2389']],
- ['tag', 'config:config-item-map-indexed',
- ['element', 'config:name', 'Views'],
- ['tag', 'config:config-item-map-entry',
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ViewId'],
- ['element', 'config:type', 'string'],
- ['data', 'View1']],
- ['tag', 'config:config-item-map-named',
- ['element', 'config:name', 'Tables'],
- ['tag', 'config:config-item-map-entry',
- ['element', 'config:name', 'Sheet1'],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'CursorPositionX'], # Cursor Position A
- ['element', 'config:type', 'int'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'CursorPositionY'], # Cursor Position 1
- ['element', 'config:type', 'int'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'HorizontalSplitMode'],
- ['element', 'config:type', 'short'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'VerticalSplitMode'],
- ['element', 'config:type', 'short'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'HorizontalSplitPosition'],
- ['element', 'config:type', 'int'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'VerticalSplitPosition'],
- ['element', 'config:type', 'int'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ActiveSplitRange'],
- ['element', 'config:type', 'short'],
- ['data', '2']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'PositionLeft'],
- ['element', 'config:type', 'int'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'PositionRight'],
- ['element', 'config:type', 'int'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'PositionTop'],
- ['element', 'config:type', 'int'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'PositionBottom'],
- ['element', 'config:type', 'int'],
- ['data', '0']]]],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ActiveTable'],
- ['element', 'config:type', 'string'],
- ['data', 'Sheet1']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'HorizontalScrollbarWidth'],
- ['element', 'config:type', 'int'],
- ['data', '270']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ZoomType'],
- ['element', 'config:type', 'short'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ZoomValue'],
- ['element', 'config:type', 'int'],
- ['data', '100']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'PageViewZoomValue'],
- ['element', 'config:type', 'int'],
- ['data', '60']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ShowPageBreakPreview'],
- ['element', 'config:type', 'boolean'],
- ['data', 'false']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ShowZeroValues'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ShowNotes'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ShowGrid'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'GridColor'],
- ['element', 'config:type', 'long'],
- ['data', '12632256']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ShowPageBreaks'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'HasColumnRowHeaders'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'HasSheetTabs'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'IsOutlineSymbolsSet'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'IsSnapToRaster'],
- ['element', 'config:type', 'boolean'],
- ['data', 'false']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'RasterIsVisible'],
- ['element', 'config:type', 'boolean'],
- ['data', 'false']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'RasterResolutionX'],
- ['element', 'config:type', 'int'],
- ['data', '1270']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'RasterResolutionY'],
- ['element', 'config:type', 'int'],
- ['data', '1270']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'RasterSubdivisionX'],
- ['element', 'config:type', 'int'],
- ['data', '1']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'RasterSubdivisionY'],
- ['element', 'config:type', 'int'],
- ['data', '1']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'IsRasterAxisSynchronized'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']]]]],
- ['tag', 'config:config-item-set',
- ['element', 'config:name', 'ooo:configuration-settings'],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ShowZeroValues'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ShowNotes'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ShowGrid'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'GridColor'],
- ['element', 'config:type', 'long'],
- ['data', '12632256']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ShowPageBreaks'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'LinkUpdateMode'],
- ['element', 'config:type', 'short'],
- ['data', '3']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'HasColumnRowHeaders'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'HasSheetTabs'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'IsOutlineSymbolsSet'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'IsSnapToRaster'],
- ['element', 'config:type', 'boolean'],
- ['data', 'false']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'RasterIsVisible'],
- ['element', 'config:type', 'boolean'],
- ['data', 'false']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'RasterResolutionX'],
- ['element', 'config:type', 'int'],
- ['data', '1270']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'RasterResolutionY'],
- ['element', 'config:type', 'int'],
- ['data', '1270']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'RasterSubdivisionX'],
- ['element', 'config:type', 'int'],
- ['data', '1']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'RasterSubdivisionY'],
- ['element', 'config:type', 'int'],
- ['data', '1']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'IsRasterAxisSynchronized'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'AutoCalculate'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'PrinterName'],
- ['element', 'config:type', 'string'],
- ['data', 'Generic Printer']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'PrinterSetup'],
- ['element', 'config:type', 'base64Binary'],
- ['data', 'YgH+/0dlbmVyaWMgUHJpbnRlcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU0dFTlBSVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAMAqAAAAAAA//8FAFZUAAAkbQAASm9iRGF0YSAxCnByaW50ZXI9R2VuZXJpYyBQcmludGVyCm9yaWVudGF0aW9uPVBvcnRyYWl0CmNvcGllcz0xCnNjYWxlPTEwMAptYXJnaW5kYWp1c3RtZW50PTAsMCwwLDAKY29sb3JkZXB0aD0yNApwc2xldmVsPTAKY29sb3JkZXZpY2U9MApQUERDb250ZXhEYXRhClBhZ2VTaXplOkxldHRlcgAA']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'ApplyUserData'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'CharacterCompressionType'],
- ['element', 'config:type', 'short'],
- ['data', '0']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'IsKernAsianPunctuation'],
- ['element', 'config:type', 'boolean'],
- ['data', 'false']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'SaveVersionOnClose'],
- ['element', 'config:type', 'boolean'],
- ['data', 'false']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'UpdateFromTemplate'],
- ['element', 'config:type', 'boolean'],
- ['data', 'false']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'AllowPrintJobCancel'],
- ['element', 'config:type', 'boolean'],
- ['data', 'true']],
- ['tag', 'config:config-item',
- ['element', 'config:name', 'LoadReadonly'],
- ['element', 'config:type', 'boolean'],
- ['data', 'false']]]]]
-
- # Generate content.xml XML data
- xml = XML()
- self.lines = xml.convert(self.data)
- self.filedata = '\n'.join(self.lines)
- # Return generated data
- return self.filedata
-
-
- def _ods_styles(self):
- "Generate ods styles.xml data"
- self.data = ['tag', 'office:document-styles',
- ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'],
- ['element', 'xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'],
- ['element', 'xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'],
- ['element', 'xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'],
- ['element', 'xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'],
- ['element', 'xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'],
- ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'],
- ['element', 'xmlns:dc', 'http://purl.org/dc/elements/1.1/'],
- ['element', 'xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'],
- ['element', 'xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'],
- ['element', 'xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'],
- ['element', 'xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'],
- ['element', 'xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'],
- ['element', 'xmlns:math', 'http://www.w3.org/1998/Math/MathML'],
- ['element', 'xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'],
- ['element', 'xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'],
- ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'],
- ['element', 'xmlns:ooow', 'http://openoffice.org/2004/writer'],
- ['element', 'xmlns:oooc', 'http://openoffice.org/2004/calc'],
- ['element', 'xmlns:dom', 'http://www.w3.org/2001/xml-events'],
- ['element', 'office:version', '1.0'],
- ['tag', 'office:font-face-decls',
- ['tagline', 'style:font-face',
- ['element', 'style:name', 'DejaVu Sans'],
- ['element', 'svg:font-family', ''DejaVu Sans''],
- ['element', 'style:font-pitch', 'variable']],
- ['tagline', 'style:font-face',
- ['element', 'style:name', 'Nimbus Sans L'],
- ['element', 'svg:font-family', ''Nimbus Sans L''],
- ['element', 'style:font-family-generic', 'swiss'],
- ['element', 'style:font-pitch', 'variable']]],
- ['tag', 'office:styles',
- ['tag', 'style:default-style',
- ['element', 'style:family', 'table-cell'],
- ['tagline', 'style:table-cell-properties',
- ['element', 'style:decimal-places', '2']],
- ['tagline', 'style:paragraph-properties',
- ['element', 'style:tab-stop-distance', '0.5in']],
- ['tagline', 'style:text-properties',
- ['element', 'style:font-name', 'Nimbus Sans L'],
- ['element', 'fo:language', 'en'],
- ['element', 'fo:country', 'US'],
- ['element', 'style:font-name-asian', 'DejaVu Sans'],
- ['element', 'style:language-asian', 'none'],
- ['element', 'style:country-asian', 'none'],
- ['element', 'style:font-name-complex', 'DejaVu Sans'],
- ['element', 'style:language-complex', 'none'],
- ['element', 'style:country-complex', 'none']]],
- ['tag', 'number:number-style',
- ['element', 'style:name', 'N0'],
- ['tagline', 'number:number',
- ['element', 'number:min-integer-digits', '1']]],
- ['tag', 'number:currency-style',
- ['element', 'style:name', 'N104P0'],
- ['element', 'style:volatile', 'true'],
- ['tag', 'number:currency-symbol',
- ['element', 'number:language', 'en'],
- ['element', 'number:country', 'US'],
- ['data', '$']],
- ['tagline', 'number:number',
- ['element', 'number:decimal-places', '2'],
- ['element', 'number:min-integer-digits', '1'],
- ['element', 'number:grouping', 'true']]],
- ['tag', 'number:currency-style',
- ['element', 'style:name', 'N104'],
- ['tagline', 'style:text-properties',
- ['element', 'fo:color', '#ff0000']],
- ['tag', 'number:text',
- ['data', '-']],
- ['tag', 'number:currency-symbol',
- ['element', 'number:language', 'en'],
- ['element', 'number:country', 'US'],
- ['data', '$']],
- ['tagline', 'number:number',
- ['element', 'number:decimal-places', '2'],
- ['element', 'number:min-integer-digits', '1'],
- ['element', 'number:grouping', 'true']],
- ['tagline', 'style:map',
- ['element', 'style:condition', 'value()>=0'],
- ['element', 'style:apply-style-name', 'N104P0']]],
- ['tagline', 'style:style',
- ['element', 'style:name', 'Default'],
- ['element', 'style:family', 'table-cell']],
- ['tag', 'style:style',
- ['element', 'style:name', 'Result'],
- ['element', 'style:family', 'table-cell'],
- ['element', 'style:parent-style-name', 'Default'],
- ['tagline', 'style:text-properties',
- ['element', 'fo:font-style', 'italic'],
- ['element', 'style:text-underline-style', 'solid'],
- ['element', 'style:text-underline-width', 'auto'],
- ['element', 'style:text-underline-color', 'font-color'],
- ['element', 'fo:font-weight', 'bold']]],
- ['tagline', 'style:style',
- ['element', 'style:name', 'Result2'],
- ['element', 'style:family', 'table-cell'],
- ['element', 'style:parent-style-name', 'Result'],
- ['element', 'style:data-style-name', 'N104']],
- ['tag', 'style:style',
- ['element', 'style:name', 'Heading'],
- ['element', 'style:family', 'table-cell'],
- ['element', 'style:parent-style-name', 'Default'],
- ['tagline', 'style:table-cell-properties',
- ['element', 'style:text-align-source', 'fix'],
- ['element', 'style:repeat-content', 'false']],
- ['tagline', 'style:paragraph-properties',
- ['element', 'fo:text-align', 'center']],
- ['tagline', 'style:text-properties',
- ['element', 'fo:font-size', '16pt'],
- ['element', 'fo:font-style', 'italic'],
- ['element', 'fo:font-weight', 'bold']]],
- ['tag', 'style:style',
- ['element', 'style:name', 'Heading1'],
- ['element', 'style:family', 'table-cell'],
- ['element', 'style:parent-style-name', 'Heading'],
- ['tagline', 'style:table-cell-properties',
- ['element', 'style:rotation-angle', '90']]]],
- ['tag', 'office:automatic-styles',
- ['tag', 'style:page-layout',
- ['element', 'style:name', 'pm1'],
- ['tagline', 'style:page-layout-properties',
- ['element', 'style:writing-mode', 'lr-tb']],
- ['tag', 'style:header-style',
- ['tagline', 'style:header-footer-properties',
- ['element', 'fo:min-height', '0.2957in'],
- ['element', 'fo:margin-left', '0in'],
- ['element', 'fo:margin-right', '0in'],
- ['element', 'fo:margin-bottom', '0.0984in']]],
- ['tag', 'style:footer-style',
- ['tagline', 'style:header-footer-properties',
- ['element', 'fo:min-height', '0.2957in'],
- ['element', 'fo:margin-left', '0in'],
- ['element', 'fo:margin-right', '0in'],
- ['element', 'fo:margin-top', '0.0984in']]]],
- ['tag', 'style:page-layout',
- ['element', 'style:name', 'pm2'],
- ['tagline', 'style:page-layout-properties',
- ['element', 'style:writing-mode', 'lr-tb']],
- ['tag', 'style:header-style',
- ['tag', 'style:header-footer-properties',
- ['element', 'fo:min-height', '0.2957in'],
- ['element', 'fo:margin-left', '0in'],
- ['element', 'fo:margin-right', '0in'],
- ['element', 'fo:margin-bottom', '0.0984in'],
- ['element', 'fo:border', '0.0346in solid #000000'],
- ['element', 'fo:padding', '0.0071in'],
- ['element', 'fo:background-color', '#c0c0c0'],
- ['tagline', 'style:background-image']]],
- ['tag', 'style:footer-style',
- ['tag', 'style:header-footer-properties',
- ['element', 'fo:min-height', '0.2957in'],
- ['element', 'fo:margin-left', '0in'],
- ['element', 'fo:margin-right', '0in'],
- ['element', 'fo:margin-top', '0.0984in'],
- ['element', 'fo:border', '0.0346in solid #000000'],
- ['element', 'fo:padding', '0.0071in'],
- ['element', 'fo:background-color', '#c0c0c0'],
- ['tagline', 'style:background-image']]]]],
- ['tag', 'office:master-styles',
- ['tag', 'style:master-page',
- ['element', 'style:name', 'Default'],
- ['element', 'style:page-layout-name', 'pm1'],
- ['tag', 'style:header',
- ['tag', 'text:p',
- ['data', '<text:sheet-name>???</text:sheet-name>']]],
- ['tagline', 'style:header-left',
- ['element', 'style:display', 'false']],
- ['tag', 'style:footer',
- ['tag', 'text:p',
- ['data', 'Page <text:page-number>1</text:page-number>']]],
- ['tagline', 'style:footer-left',
- ['element', 'style:display', 'false']]],
- ['tag', 'style:master-page',
- ['element', 'style:name', 'Report'],
- ['element', 'style:page-layout-name', 'pm2'],
- ['tag', 'style:header',
- ['tag', 'style:region-left',
- ['tag', 'text:p',
- ['data', '<text:sheet-name>???</text:sheet-name> (<text:title>???</text:title>)']]],
- ['tag', 'style:region-right',
- ['tag', 'text:p',
- ['data', '<text:date style:data-style-name="N2" text:date-value="2006-09-29">09/29/2006</text:date>, <text:time>13:02:56</text:time>']]]],
- ['tagline', 'style:header-left',
- ['element', 'style:display', 'false']],
- ['tag', 'style:footer',
- ['tag', 'text:p',
- ['data', 'Page <text:page-number>1</text:page-number> / <text:page-count>99</text:page-count>']]],
- ['tagline', 'style:footer-left',
- ['element', 'style:display', 'false']]]]]
-
-
- # Generate content.xml XML data
- xml = XML()
- self.lines = xml.convert(self.data)
- self.filedata = '\n'.join(self.lines)
- # Return generated data
- return self.filedata
+ "Calc Class - Used to create OpenDocument Format Calc Spreadsheets."
+
+ def __init__(self, sheetname=None, opendoc=None, debug=False):
+ "Initialize ooolib Calc instance"
+ # Default to no debugging
+ self.debug = debug
+ if not sheetname: sheetname = "Sheet1"
+ self.sheets = [CalcSheet(sheetname)] # The main sheet will be initially called 'Sheet1'
+ self.sheet_index = 0 # We initially start on the first sheet
+ self.styles = CalcStyles()
+ self.meta = Meta('ods')
+ self.styles.get_style_code('column') # Force generation of default column
+ self.styles.get_style_code('row') # Force generation of default row
+ self.styles.get_style_code('table') # Force generation of default table
+ self.styles.get_style_code('cell') # Force generation of default cell
+ self.manifest_files = [] # List of extra files included
+ self.manifest_index = 1 # Index of added manifest files
+ # Data Parsing
+ self.parser_element_list = []
+ self.parser_element = ""
+ self.parser_sheet_num = 0
+ self.parser_sheet_row = 0
+ self.parser_sheet_column = 0
+ self.parser_cell_repeats = 0
+ self.parser_cell_string_pending = False
+ self.parser_cell_string_line = ""
+ # See if we need to read a document
+ if opendoc:
+ # Verify that the document exists
+ if self.debug: print("Opening Document: %s" % opendoc)
+ # Okay, now we load the file
+ self.load(opendoc)
+
+ def debug_level(self, level):
+ """Set debug level:
+ True if you want debugging messages
+ False if you do not.
+ """
+ self.debug = level
+
+ def file_mimetype(self, filename):
+ "Determine the filetype from the filename"
+ parts = filename.lower().split('.')
+ ext = parts[-1]
+ if (ext == 'png'): return (ext, "image/png")
+ if (ext == 'gif'): return (ext, "image/gif")
+ return (ext, "image/unknown")
+
+ def add_file(self, filename):
+ """Prepare a file for loading into ooolib
+
+ The filename should be the local filesystem name for
+ the file. The file is then prepared to be included in
+ the creation of the final document. The file needs to
+ remain in place so that it is available when the actual
+ document creation happens.
+ """
+ # mimetype set to (ext, filetype)
+ mimetype = self.file_mimetype(filename)
+ newname = "Pictures/%08d.%s" % (self.manifest_index, mimetype[0])
+ self.manifest_index += 1
+ filetype = mimetype[1]
+ self.manifest_files.append((filename, filetype, newname))
+ return newname
+
+ def set_meta(self, metaname, value):
+ "Set meta data in your document."
+ self.meta.set_meta(metaname, value)
+
+ def get_meta_value(self, metaname):
+ "Get meta data value for a given metaname"
+ return self.meta.get_meta_value(metaname)
+
+ def get_sheet_name(self):
+ "Returns the sheet name"
+ return self.sheets[self.sheet_index].get_name()
+
+ def get_sheet_dimensions(self):
+ "Returns the sheet dimensions in (cols, rows)"
+ return self.sheets[self.sheet_index].get_sheet_dimensions()
+
+ def set_column_property(self, column, name, value):
+ "Set Column Properties"
+ if name == 'width':
+ # column number column needs column-width set to value
+ self.styles.set_property('column', 'style:column-width', value)
+ style_code = self.styles.get_style_code('column')
+ self.sheets[self.sheet_index].set_sheet_config(('col', column), style_code)
+
+ def set_row_property(self, row, name, value):
+ "Set row Properties"
+ if name == 'height':
+ # row number row needs row-height set to value
+ self.styles.set_property('row', 'style:row-height', value)
+ style_code = self.styles.get_style_code('row')
+ self.sheets[self.sheet_index].set_sheet_config(('row', row), style_code)
+
+ def set_cell_property(self, name, value):
+ """Turn and off cell properties
+
+ Actual application of properties is handled by setting a value."""
+ # background images need to be handled a little differently
+ # because they need to also be inserted into the final document
+ if (name == 'backgroundimage'):
+ # Add file and modify value
+ value = self.add_file(value)
+ self.styles.set_property('cell', name, value)
+
+ def get_sheet_index(self):
+ "Return the current sheet index number"
+ return self.sheet_index
+
+ def set_sheet_index(self, index):
+ "Set the sheet index"
+ if type(index) == type(1):
+ if index >= 0 and index < len(self.sheets):
+ self.sheet_index = index
+ return self.sheet_index
+
+ def get_sheet_count(self):
+ "Returns the number of existing sheets"
+ return len(self.sheets)
+
+ def new_sheet(self, sheetname):
+ "Create a new sheet"
+ self.sheet_index = len(self.sheets)
+ self.sheets.append(CalcSheet(sheetname))
+ return self.sheet_index
+
+ def set_cell_value(self, col, row, datatype, value):
+ "Set the value for a given cell"
+ self.sheets[self.sheet_index].set_sheet_value((col, row), datatype, value)
+ style_code = self.styles.get_style_code('cell')
+ self.sheets[self.sheet_index].set_sheet_config((col, row), style_code)
+
+ def get_cell_value(self, col, row):
+ "Get a cell value tuple (type, value) for a given cell"
+ sheetvalue = self.sheets[self.sheet_index].get_sheet_value(col, row)
+ # We stop here if there is no value for sheetvalue
+ if sheetvalue == None: return sheetvalue
+ # Now check to see if we have a value tuple
+ if 'value' in sheetvalue:
+ return sheetvalue['value']
+ else:
+ return None
+
+ def load(self, filename):
+ """Load .ods spreadsheet.
+
+ The load function loads data from a document into the current cells.
+ """
+ # Read in the important files
+ # meta.xml
+ data = self._zip_read(filename, "meta.xml")
+ self.meta.meta_parse(data)
+ # content.xml
+ data = self._zip_read(filename, "content.xml")
+ self.content_parse(data)
+ # settings.xml - I do not remember putting anything here
+ # styles.xml - I do not remember putting anything here
+
+ def parse_content_start_element(self, name, attrs):
+ if self.debug: print('* Start element:', name)
+ self.parser_element_list.append(name)
+ self.parser_element = self.parser_element_list[-1]
+ # Keep track of the current sheet number
+ if (self.parser_element == 'table:table'):
+ # Move to starting cell
+ self.parser_sheet_row = 0
+ self.parser_sheet_column = 0
+ # Increment the sheet number count
+ self.parser_sheet_num += 1
+ if (self.parser_sheet_num - 1 != self.sheet_index):
+ # We are not on the first sheet and need to create a new sheet.
+ # We will automatically move to the new sheet
+ sheetname = "Sheet%d" % self.parser_sheet_num
+ if 'table:name' in attrs: sheetname = attrs['table:name']
+ self.new_sheet(sheetname)
+ else:
+ # We are on the first sheet and will need to overwrite the default name
+ sheetname = "Sheet%d" % self.parser_sheet_num
+ if 'table:name' in attrs: sheetname = attrs['table:name']
+ self.sheets[self.sheet_index].set_name(sheetname)
+ # Update the row numbers
+ if (self.parser_element == 'table:table-row'):
+ self.parser_sheet_row += 1
+ self.parser_sheet_column = 0
+ # Okay, now keep track of the sheet cell data
+ if (self.parser_element == 'table:table-cell'):
+ # By default it will repeat zero times
+ self.parser_cell_repeats = 0
+ # We must be in a new column
+ self.parser_sheet_column += 1
+ # Set some default values
+ datatype = ""
+ value = ""
+ # Get values from attrs hash
+ if 'office:value-type' in attrs: datatype = attrs['office:value-type']
+ if 'office:value' in attrs: value = attrs['office:value']
+ if 'table:formula' in attrs:
+ datatype = 'formula'
+ value = attrs['table:formula']
+ if datatype == 'string':
+ datatype = ""
+ self.parser_cell_string_pending = True
+ self.parser_cell_string_line = ""
+ if 'table:number-columns-repeated' in attrs:
+ self.parser_cell_repeats = int(attrs['table:number-columns-repeated']) - 1
+ # Set the cell value
+ if datatype:
+ # I should do this once per cell repeat above 0
+ for i in range(0, self.parser_cell_repeats+1):
+ self.set_cell_value(self.parser_sheet_column+i, self.parser_sheet_row, datatype, value)
+ # There are lots of interesting cases with table:table-cell data. One problem is
+ # reading the number of embedded spaces correctly. This code should help us get
+ # the number of spaces out.
+ if (self.parser_element == 'text:s'):
+ # This means we have a number of spaces
+ count_num = 0
+ if 'text:c' in attrs:
+ count_alpha = attrs['text:c']
+ if (count_alpha.isdigit()):
+ count_num = int(count_alpha)
+ # I am not sure what to do if we do not have a string pending
+ if (self.parser_cell_string_pending == True):
+ # Append the currect number of spaces to the end
+ self.parser_cell_string_line = "%s%s" % (self.parser_cell_string_line, ' '*count_num)
+ if (self.parser_element == 'text:tab-stop'):
+ if (self.parser_cell_string_pending == True):
+ self.parser_cell_string_line = "%s\t" % (self.parser_cell_string_line)
+ if (self.parser_element == 'text:line-break'):
+ if (self.parser_cell_string_pending == True):
+ self.parser_cell_string_line = "%s\n" % (self.parser_cell_string_line)
+ # Debugging statements
+ if self.debug: print(" List: ", self.parser_element_list)
+ if self.debug: print(" Attributes: ", attrs)
+
+ def parse_content_end_element(self, name):
+ if self.debug: print('* End element:', name)
+ if name != self.parser_element:
+ print("Tag Mismatch: '%s' != '%s'" % (name, self.parser_element))
+ self.parser_element_list.pop()
+ # If the element was text:p and we are in string mode
+ if (self.parser_element == 'text:p'):
+ if (self.parser_cell_string_pending):
+ self.parser_cell_string_pending = False
+ # Take care of repeated cells
+ if (self.parser_element == 'table:table-cell'):
+ self.parser_sheet_column += self.parser_cell_repeats
+ # Readjust parser_element_list and parser_element
+ if (self.parser_element_list):
+ self.parser_element = self.parser_element_list[-1]
+ else:
+ self.parser_element = ""
+
+ def parse_content_char_data(self, data):
+ if self.debug:
+ print(" Character data: ", repr(data))
+ if (self.parser_element == 'text:p' or self.parser_element == 'text:span'):
+ if (self.parser_cell_string_pending):
+ # Set the string and leave string pending mode
+ # This does feel a little kludgy, but it does the job
+ self.parser_cell_string_line = "%s%s" % (self.parser_cell_string_line, data)
+ # I should do this once per cell repeat above 0
+ for i in range(0, self.parser_cell_repeats+1):
+ self.set_cell_value(self.parser_sheet_column+i, self.parser_sheet_row,
+ 'string', self.parser_cell_string_line)
+
+ def content_parse(self, data):
+ "Parse Content Data from a content.xml file"
+ # Debugging statements
+ if self.debug:
+ # Sometimes it helps to see the document that was read from
+ print(data)
+ print("\n\n\n")
+ # Create parser
+ parser = xml.parsers.expat.ParserCreate()
+ # Set up parser callback functions
+ parser.StartElementHandler = self.parse_content_start_element
+ parser.EndElementHandler = self.parse_content_end_element
+ parser.CharacterDataHandler = self.parse_content_char_data
+ # Actually parse the data
+ parser.Parse(data, 1)
+
+ def save(self, filename):
+ """Save .ods spreadsheet.
+
+ The save function saves the current cells and settings into a document.
+ """
+ if self.debug: print("Writing %s" % filename)
+ self.savefile = zipfile.ZipFile(filename, "w")
+ if self.debug: print(" meta.xml")
+ self._zip_insert(self.savefile, "meta.xml", self.meta.get_meta())
+ if self.debug: print(" mimetype")
+ self._zip_insert(self.savefile, "mimetype", "application/vnd.oasis.opendocument.spreadsheet")
+ if self.debug: print(" Configurations2/accelerator/current.xml")
+ self._zip_insert(self.savefile, "Configurations2/accelerator/current.xml", "")
+ if self.debug: print(" META-INF/manifest.xml")
+ self._zip_insert(self.savefile, "META-INF/manifest.xml", self._ods_manifest())
+ if self.debug: print(" content.xml")
+ self._zip_insert(self.savefile, "content.xml", self._ods_content())
+ if self.debug: print(" settings.xml")
+ self._zip_insert(self.savefile, "settings.xml", self._ods_settings())
+ if self.debug: print(" styles.xml")
+ self._zip_insert(self.savefile, "styles.xml", self._ods_styles())
+ # Add additional files if needed
+ for fileset in self.manifest_files:
+ (filename, filetype, newname) = fileset
+ # Read in the file
+ data = self._file_load(filename)
+ if self.debug: print(" Inserting '%s' as '%s'" % (filename, newname))
+ self._zip_insert_binary(self.savefile, newname, data)
+
+ def _file_load(self, filename):
+ "Load a file"
+ file = open(filename, "r")
+ data = file.read()
+ file.close()
+ return data
+
+ def _zip_insert_binary(self, file, filename, data):
+ "Insert a binary file into the zip archive"
+ now = time.localtime(time.time())[:6]
+ info = zipfile.ZipInfo(filename)
+ info.date_time = now
+ info.compress_type = zipfile.ZIP_DEFLATED
+ file.writestr(info, data)
+
+ def _zip_insert(self, file, filename, data):
+ "Insert a file into the zip archive"
+ # zip seems to struggle with non-ascii characters
+ data = data.encode('utf-8')
+ now = time.localtime(time.time())[:6]
+ info = zipfile.ZipInfo(filename)
+ info.date_time = now
+ info.compress_type = zipfile.ZIP_DEFLATED
+ file.writestr(info, data)
+
+ def _zip_read(self, file, filename):
+ "Get the data from a file in the zip archive by filename"
+ file = zipfile.ZipFile(file, "r")
+ data = file.read(filename)
+ # Need to close the file
+ file.close()
+ return data
+
+ def _ods_content(self):
+ "Generate ods content.xml data"
+ # This will list all of the sheets in the document
+ self.sheetdata = ['tag', 'office:spreadsheet']
+ for sheet in self.sheets:
+ if self.debug:
+ sheet_name = sheet.get_name()
+ print(" Creating Sheet '%s'" % sheet_name)
+ sheet_list = sheet.get_lists()
+ self.sheetdata.append(sheet_list)
+ # Automatic Styles
+ self.automatic_styles = self.styles.get_automatic_styles()
+ self.data = ['tag', 'office:document-content',
+ ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'],
+ ['element', 'xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'],
+ ['element', 'xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'],
+ ['element', 'xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'],
+ ['element', 'xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'],
+ ['element', 'xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'],
+ ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'],
+ ['element', 'xmlns:dc', 'http://purl.org/dc/elements/1.1/'],
+ ['element', 'xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'],
+ ['element', 'xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'],
+ ['element', 'xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'],
+ ['element', 'xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'],
+ ['element', 'xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'],
+ ['element', 'xmlns:math', 'http://www.w3.org/1998/Math/MathML'],
+ ['element', 'xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'],
+ ['element', 'xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'],
+ ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'],
+ ['element', 'xmlns:ooow', 'http://openoffice.org/2004/writer'],
+ ['element', 'xmlns:oooc', 'http://openoffice.org/2004/calc'],
+ ['element', 'xmlns:dom', 'http://www.w3.org/2001/xml-events'],
+ ['element', 'xmlns:xforms', 'http://www.w3.org/2002/xforms'],
+ ['element', 'xmlns:xsd', 'http://www.w3.org/2001/XMLSchema'],
+ ['element', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'],
+ ['element', 'office:version', '1.0'],
+ ['tagline', 'office:scripts'],
+ ['tag', 'office:font-face-decls',
+ ['tagline', 'style:font-face',
+ ['element', 'style:name', 'DejaVu Sans'],
+ ['element', 'svg:font-family', ''DejaVu Sans''],
+ ['element', 'style:font-pitch', 'variable']],
+ ['tagline', 'style:font-face',
+ ['element', 'style:name', 'Nimbus Sans L'],
+ ['element', 'svg:font-family', ''Nimbus Sans L''],
+ ['element', 'style:font-family-generic', 'swiss'],
+ ['element', 'style:font-pitch', 'variable']]],
+ # Automatic Styles
+ self.automatic_styles,
+ ['tag', 'office:body',
+ self.sheetdata]] # Sheets are generated from the CalcSheet class
+ # Generate content.xml XML data
+ xml = XML()
+ self.lines = xml.convert(self.data)
+ self.filedata = '\n'.join(self.lines)
+ # Return generated data
+ return self.filedata
+
+ def _ods_manifest(self):
+ "Generate ods manifest.xml data"
+ self.data = ['tag', 'manifest:manifest',
+ ['element', 'xmlns:manifest', 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'],
+ ['tagline', 'manifest:file-entry',
+ ['element', 'manifest:media-type', 'application/vnd.oasis.opendocument.spreadsheet'],
+ ['element', 'manifest:full-path', '/']],
+ ['tagline', 'manifest:file-entry',
+ ['element', 'manifest:media-type', 'application/vnd.sun.xml.ui.configuration'],
+ ['element', 'manifest:full-path', 'Configurations2/']],
+ ['tagline', 'manifest:file-entry',
+ ['element', 'manifest:media-type', ''],
+ ['element', 'manifest:full-path', 'Configurations2/accelerator/']],
+ ['tagline', 'manifest:file-entry',
+ ['element', 'manifest:media-type', ''],
+ ['element', 'manifest:full-path', 'Configurations2/accelerator/current.xml']],
+ ['tagline', 'manifest:file-entry',
+ ['element', 'manifest:media-type', 'text/xml'],
+ ['element', 'manifest:full-path', 'content.xml']],
+ ['tagline', 'manifest:file-entry',
+ ['element', 'manifest:media-type', 'text/xml'],
+ ['element', 'manifest:full-path', 'styles.xml']],
+ ['tagline', 'manifest:file-entry',
+ ['element', 'manifest:media-type', 'text/xml'],
+ ['element', 'manifest:full-path', 'meta.xml']],
+ ['tagline', 'manifest:file-entry',
+ ['element', 'manifest:media-type', 'text/xml'],
+ ['element', 'manifest:full-path', 'settings.xml']]]
+ # Add additional files to manifest list
+ for fileset in self.manifest_files:
+ (filename, filetype, newname) = fileset
+ addfile = ['tagline', 'manifest:file-entry',
+ ['element', 'manifest:media-type', filetype],
+ ['element', 'manifest:full-path', newname]]
+ self.data.append(addfile)
+ # Generate content.xml XML data
+ xml = XML()
+ self.lines = xml.convert(self.data)
+ self.filedata = '\n'.join(self.lines)
+ # Return generated data
+ return self.filedata
+
+ def _ods_settings(self):
+ "Generate ods settings.xml data"
+ self.data = ['tag', 'office:document-settings',
+ ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'],
+ ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'],
+ ['element', 'xmlns:config', 'urn:oasis:names:tc:opendocument:xmlns:config:1.0'],
+ ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'],
+ ['element', 'office:version', '1.0'],
+ ['tag', 'office:settings',
+ ['tag', 'config:config-item-set',
+ ['element', 'config:name', 'ooo:view-settings'],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'VisibleAreaTop'],
+ ['element', 'config:type', 'int'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'VisibleAreaLeft'],
+ ['element', 'config:type', 'int'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'VisibleAreaWidth'],
+ ['element', 'config:type', 'int'],
+ ['data', '6774']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'VisibleAreaHeight'],
+ ['element', 'config:type', 'int'],
+ ['data', '2389']],
+ ['tag', 'config:config-item-map-indexed',
+ ['element', 'config:name', 'Views'],
+ ['tag', 'config:config-item-map-entry',
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ViewId'],
+ ['element', 'config:type', 'string'],
+ ['data', 'View1']],
+ ['tag', 'config:config-item-map-named',
+ ['element', 'config:name', 'Tables'],
+ ['tag', 'config:config-item-map-entry',
+ ['element', 'config:name', 'Sheet1'],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'CursorPositionX'], # Cursor Position A
+ ['element', 'config:type', 'int'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'CursorPositionY'], # Cursor Position 1
+ ['element', 'config:type', 'int'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'HorizontalSplitMode'],
+ ['element', 'config:type', 'short'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'VerticalSplitMode'],
+ ['element', 'config:type', 'short'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'HorizontalSplitPosition'],
+ ['element', 'config:type', 'int'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'VerticalSplitPosition'],
+ ['element', 'config:type', 'int'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ActiveSplitRange'],
+ ['element', 'config:type', 'short'],
+ ['data', '2']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'PositionLeft'],
+ ['element', 'config:type', 'int'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'PositionRight'],
+ ['element', 'config:type', 'int'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'PositionTop'],
+ ['element', 'config:type', 'int'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'PositionBottom'],
+ ['element', 'config:type', 'int'],
+ ['data', '0']]]],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ActiveTable'],
+ ['element', 'config:type', 'string'],
+ ['data', 'Sheet1']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'HorizontalScrollbarWidth'],
+ ['element', 'config:type', 'int'],
+ ['data', '270']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ZoomType'],
+ ['element', 'config:type', 'short'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ZoomValue'],
+ ['element', 'config:type', 'int'],
+ ['data', '100']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'PageViewZoomValue'],
+ ['element', 'config:type', 'int'],
+ ['data', '60']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ShowPageBreakPreview'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'false']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ShowZeroValues'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ShowNotes'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ShowGrid'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'GridColor'],
+ ['element', 'config:type', 'long'],
+ ['data', '12632256']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ShowPageBreaks'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'HasColumnRowHeaders'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'HasSheetTabs'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'IsOutlineSymbolsSet'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'IsSnapToRaster'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'false']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'RasterIsVisible'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'false']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'RasterResolutionX'],
+ ['element', 'config:type', 'int'],
+ ['data', '1270']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'RasterResolutionY'],
+ ['element', 'config:type', 'int'],
+ ['data', '1270']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'RasterSubdivisionX'],
+ ['element', 'config:type', 'int'],
+ ['data', '1']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'RasterSubdivisionY'],
+ ['element', 'config:type', 'int'],
+ ['data', '1']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'IsRasterAxisSynchronized'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']]]]],
+ ['tag', 'config:config-item-set',
+ ['element', 'config:name', 'ooo:configuration-settings'],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ShowZeroValues'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ShowNotes'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ShowGrid'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'GridColor'],
+ ['element', 'config:type', 'long'],
+ ['data', '12632256']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ShowPageBreaks'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'LinkUpdateMode'],
+ ['element', 'config:type', 'short'],
+ ['data', '3']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'HasColumnRowHeaders'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'HasSheetTabs'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'IsOutlineSymbolsSet'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'IsSnapToRaster'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'false']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'RasterIsVisible'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'false']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'RasterResolutionX'],
+ ['element', 'config:type', 'int'],
+ ['data', '1270']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'RasterResolutionY'],
+ ['element', 'config:type', 'int'],
+ ['data', '1270']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'RasterSubdivisionX'],
+ ['element', 'config:type', 'int'],
+ ['data', '1']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'RasterSubdivisionY'],
+ ['element', 'config:type', 'int'],
+ ['data', '1']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'IsRasterAxisSynchronized'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'AutoCalculate'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'PrinterName'],
+ ['element', 'config:type', 'string'],
+ ['data', 'Generic Printer']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'PrinterSetup'],
+ ['element', 'config:type', 'base64Binary'],
+ ['data', 'YgH+/0dlbmVyaWMgUHJpbnRlcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU0dFTlBSVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAMAqAAAAAAA//8FAFZUAAAkbQAASm9iRGF0YSAxCnByaW50ZXI9R2VuZXJpYyBQcmludGVyCm9yaWVudGF0aW9uPVBvcnRyYWl0CmNvcGllcz0xCnNjYWxlPTEwMAptYXJnaW5kYWp1c3RtZW50PTAsMCwwLDAKY29sb3JkZXB0aD0yNApwc2xldmVsPTAKY29sb3JkZXZpY2U9MApQUERDb250ZXhEYXRhClBhZ2VTaXplOkxldHRlcgAA']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'ApplyUserData'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'CharacterCompressionType'],
+ ['element', 'config:type', 'short'],
+ ['data', '0']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'IsKernAsianPunctuation'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'false']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'SaveVersionOnClose'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'false']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'UpdateFromTemplate'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'false']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'AllowPrintJobCancel'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'true']],
+ ['tag', 'config:config-item',
+ ['element', 'config:name', 'LoadReadonly'],
+ ['element', 'config:type', 'boolean'],
+ ['data', 'false']]]]]
+ # Generate content.xml XML data
+ xml = XML()
+ self.lines = xml.convert(self.data)
+ self.filedata = '\n'.join(self.lines)
+ # Return generated data
+ return self.filedata
+
+ def _ods_styles(self):
+ "Generate ods styles.xml data"
+ self.data = ['tag', 'office:document-styles',
+ ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'],
+ ['element', 'xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'],
+ ['element', 'xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'],
+ ['element', 'xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'],
+ ['element', 'xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'],
+ ['element', 'xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'],
+ ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'],
+ ['element', 'xmlns:dc', 'http://purl.org/dc/elements/1.1/'],
+ ['element', 'xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'],
+ ['element', 'xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'],
+ ['element', 'xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'],
+ ['element', 'xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'],
+ ['element', 'xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'],
+ ['element', 'xmlns:math', 'http://www.w3.org/1998/Math/MathML'],
+ ['element', 'xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'],
+ ['element', 'xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'],
+ ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'],
+ ['element', 'xmlns:ooow', 'http://openoffice.org/2004/writer'],
+ ['element', 'xmlns:oooc', 'http://openoffice.org/2004/calc'],
+ ['element', 'xmlns:dom', 'http://www.w3.org/2001/xml-events'],
+ ['element', 'office:version', '1.0'],
+ ['tag', 'office:font-face-decls',
+ ['tagline', 'style:font-face',
+ ['element', 'style:name', 'DejaVu Sans'],
+ ['element', 'svg:font-family', ''DejaVu Sans''],
+ ['element', 'style:font-pitch', 'variable']],
+ ['tagline', 'style:font-face',
+ ['element', 'style:name', 'Nimbus Sans L'],
+ ['element', 'svg:font-family', ''Nimbus Sans L''],
+ ['element', 'style:font-family-generic', 'swiss'],
+ ['element', 'style:font-pitch', 'variable']]],
+ ['tag', 'office:styles',
+ ['tag', 'style:default-style',
+ ['element', 'style:family', 'table-cell'],
+ ['tagline', 'style:table-cell-properties',
+ ['element', 'style:decimal-places', '2']],
+ ['tagline', 'style:paragraph-properties',
+ ['element', 'style:tab-stop-distance', '0.5in']],
+ ['tagline', 'style:text-properties',
+ ['element', 'style:font-name', 'Nimbus Sans L'],
+ ['element', 'fo:language', 'en'],
+ ['element', 'fo:country', 'US'],
+ ['element', 'style:font-name-asian', 'DejaVu Sans'],
+ ['element', 'style:language-asian', 'none'],
+ ['element', 'style:country-asian', 'none'],
+ ['element', 'style:font-name-complex', 'DejaVu Sans'],
+ ['element', 'style:language-complex', 'none'],
+ ['element', 'style:country-complex', 'none']]],
+ ['tag', 'number:number-style',
+ ['element', 'style:name', 'N0'],
+ ['tagline', 'number:number',
+ ['element', 'number:min-integer-digits', '1']]],
+ ['tag', 'number:currency-style',
+ ['element', 'style:name', 'N104P0'],
+ ['element', 'style:volatile', 'true'],
+ ['tag', 'number:currency-symbol',
+ ['element', 'number:language', 'en'],
+ ['element', 'number:country', 'US'],
+ ['data', '$']],
+ ['tagline', 'number:number',
+ ['element', 'number:decimal-places', '2'],
+ ['element', 'number:min-integer-digits', '1'],
+ ['element', 'number:grouping', 'true']]],
+ ['tag', 'number:currency-style',
+ ['element', 'style:name', 'N104'],
+ ['tagline', 'style:text-properties',
+ ['element', 'fo:color', '#ff0000']],
+ ['tag', 'number:text',
+ ['data', '-']],
+ ['tag', 'number:currency-symbol',
+ ['element', 'number:language', 'en'],
+ ['element', 'number:country', 'US'],
+ ['data', '$']],
+ ['tagline', 'number:number',
+ ['element', 'number:decimal-places', '2'],
+ ['element', 'number:min-integer-digits', '1'],
+ ['element', 'number:grouping', 'true']],
+ ['tagline', 'style:map',
+ ['element', 'style:condition', 'value()>=0'],
+ ['element', 'style:apply-style-name', 'N104P0']]],
+ ['tagline', 'style:style',
+ ['element', 'style:name', 'Default'],
+ ['element', 'style:family', 'table-cell']],
+ ['tag', 'style:style',
+ ['element', 'style:name', 'Result'],
+ ['element', 'style:family', 'table-cell'],
+ ['element', 'style:parent-style-name', 'Default'],
+ ['tagline', 'style:text-properties',
+ ['element', 'fo:font-style', 'italic'],
+ ['element', 'style:text-underline-style', 'solid'],
+ ['element', 'style:text-underline-width', 'auto'],
+ ['element', 'style:text-underline-color', 'font-color'],
+ ['element', 'fo:font-weight', 'bold']]],
+ ['tagline', 'style:style',
+ ['element', 'style:name', 'Result2'],
+ ['element', 'style:family', 'table-cell'],
+ ['element', 'style:parent-style-name', 'Result'],
+ ['element', 'style:data-style-name', 'N104']],
+ ['tag', 'style:style',
+ ['element', 'style:name', 'Heading'],
+ ['element', 'style:family', 'table-cell'],
+ ['element', 'style:parent-style-name', 'Default'],
+ ['tagline', 'style:table-cell-properties',
+ ['element', 'style:text-align-source', 'fix'],
+ ['element', 'style:repeat-content', 'false']],
+ ['tagline', 'style:paragraph-properties',
+ ['element', 'fo:text-align', 'center']],
+ ['tagline', 'style:text-properties',
+ ['element', 'fo:font-size', '16pt'],
+ ['element', 'fo:font-style', 'italic'],
+ ['element', 'fo:font-weight', 'bold']]],
+ ['tag', 'style:style',
+ ['element', 'style:name', 'Heading1'],
+ ['element', 'style:family', 'table-cell'],
+ ['element', 'style:parent-style-name', 'Heading'],
+ ['tagline', 'style:table-cell-properties',
+ ['element', 'style:rotation-angle', '90']]]],
+ ['tag', 'office:automatic-styles',
+ ['tag', 'style:page-layout',
+ ['element', 'style:name', 'pm1'],
+ ['tagline', 'style:page-layout-properties',
+ ['element', 'style:writing-mode', 'lr-tb']],
+ ['tag', 'style:header-style',
+ ['tagline', 'style:header-footer-properties',
+ ['element', 'fo:min-height', '0.2957in'],
+ ['element', 'fo:margin-left', '0in'],
+ ['element', 'fo:margin-right', '0in'],
+ ['element', 'fo:margin-bottom', '0.0984in']]],
+ ['tag', 'style:footer-style',
+ ['tagline', 'style:header-footer-properties',
+ ['element', 'fo:min-height', '0.2957in'],
+ ['element', 'fo:margin-left', '0in'],
+ ['element', 'fo:margin-right', '0in'],
+ ['element', 'fo:margin-top', '0.0984in']]]],
+ ['tag', 'style:page-layout',
+ ['element', 'style:name', 'pm2'],
+ ['tagline', 'style:page-layout-properties',
+ ['element', 'style:writing-mode', 'lr-tb']],
+ ['tag', 'style:header-style',
+ ['tag', 'style:header-footer-properties',
+ ['element', 'fo:min-height', '0.2957in'],
+ ['element', 'fo:margin-left', '0in'],
+ ['element', 'fo:margin-right', '0in'],
+ ['element', 'fo:margin-bottom', '0.0984in'],
+ ['element', 'fo:border', '0.0346in solid #000000'],
+ ['element', 'fo:padding', '0.0071in'],
+ ['element', 'fo:background-color', '#c0c0c0'],
+ ['tagline', 'style:background-image']]],
+ ['tag', 'style:footer-style',
+ ['tag', 'style:header-footer-properties',
+ ['element', 'fo:min-height', '0.2957in'],
+ ['element', 'fo:margin-left', '0in'],
+ ['element', 'fo:margin-right', '0in'],
+ ['element', 'fo:margin-top', '0.0984in'],
+ ['element', 'fo:border', '0.0346in solid #000000'],
+ ['element', 'fo:padding', '0.0071in'],
+ ['element', 'fo:background-color', '#c0c0c0'],
+ ['tagline', 'style:background-image']]]]],
+ ['tag', 'office:master-styles',
+ ['tag', 'style:master-page',
+ ['element', 'style:name', 'Default'],
+ ['element', 'style:page-layout-name', 'pm1'],
+ ['tag', 'style:header',
+ ['tag', 'text:p',
+ ['data', '<text:sheet-name>???</text:sheet-name>']]],
+ ['tagline', 'style:header-left',
+ ['element', 'style:display', 'false']],
+ ['tag', 'style:footer',
+ ['tag', 'text:p',
+ ['data', 'Page <text:page-number>1</text:page-number>']]],
+ ['tagline', 'style:footer-left',
+ ['element', 'style:display', 'false']]],
+ ['tag', 'style:master-page',
+ ['element', 'style:name', 'Report'],
+ ['element', 'style:page-layout-name', 'pm2'],
+ ['tag', 'style:header',
+ ['tag', 'style:region-left',
+ ['tag', 'text:p',
+ ['data', '<text:sheet-name>???</text:sheet-name> (<text:title>???</text:title>)']]],
+ ['tag', 'style:region-right',
+ ['tag', 'text:p',
+ ['data', '<text:date style:data-style-name="N2" text:date-value="2006-09-29">09/29/2006</text:date>, <text:time>13:02:56</text:time>']]]],
+ ['tagline', 'style:header-left',
+ ['element', 'style:display', 'false']],
+ ['tag', 'style:footer',
+ ['tag', 'text:p',
+ ['data', 'Page <text:page-number>1</text:page-number> / <text:page-count>99</text:page-count>']]],
+ ['tagline', 'style:footer-left',
+ ['element', 'style:display', 'false']]]]]
+ # Generate content.xml XML data
+ xml = XML()
+ self.lines = xml.convert(self.data)
+ self.filedata = '\n'.join(self.lines)
+ # Return generated data
+ return self.filedata