[ooo-build-commit] 2 commits - scratch/mso-dumper
Kohei Yoshida
kohei at kemper.freedesktop.org
Mon Jan 4 10:27:36 PST 2010
scratch/mso-dumper/src/formula.py | 72 +++++++++++++---------
scratch/mso-dumper/src/xlsmodel.py | 113 ++++++++++++++++++++++++++++++++----
scratch/mso-dumper/src/xlsrecord.py | 30 ++++++++-
3 files changed, 171 insertions(+), 44 deletions(-)
New commits:
commit eb0b331416df0d9e27f600d2e6f312f9bbd53f22
Author: Kohei Yoshida <kyoshida at novell.com>
Date: Mon Jan 4 13:25:19 2010 -0500
[xls-dump] Display active autofilter info in cXML mode.
The actual autofilter state can be complex, but let's just handle
simple string equality cases for now.
* scratch/mso-dumper/src/xlsmodel.py:
* scratch/mso-dumper/src/xlsrecord.py:
diff --git a/scratch/mso-dumper/src/xlsmodel.py b/scratch/mso-dumper/src/xlsmodel.py
index 51e2356..17fe776 100644
--- a/scratch/mso-dumper/src/xlsmodel.py
+++ b/scratch/mso-dumper/src/xlsmodel.py
@@ -176,6 +176,9 @@ class Worksheet(SheetBase):
# Swap with the new and empty list.
self.__autoFilterArrows = arrows
+ def setAutoFilterArrow (self, filterID, obj):
+ self.__autoFilterArrows[filterID] = obj
+
def setCell (self, col, row, cell):
if not self.__rows.has_key(row):
self.__rows[row] = {}
@@ -206,6 +209,7 @@ class Worksheet(SheetBase):
def __appendAutoFilterNode (self, wb, baseNode):
if len(self.__autoFilterArrows) <= 0:
+ # No autofilter in this sheet.
return
wbg = wb.getWorkbookGlobal()
@@ -214,19 +218,24 @@ class Worksheet(SheetBase):
parser.parse()
tokens = parser.getTokens()
if len(tokens) != 1 or tokens[0].tokenType != formula.TokenType.Area3d:
+ # We assume that the database range only has one range token, otherwise
+ # we bail out.
return
-
tk = tokens[0]
cellRange = tk.cellRange
elem = baseNode.appendElement('autofilter')
elem.setAttr('range', "(col=%d,row=%d)-(col=%d,row=%d)"%(cellRange.firstCol, cellRange.firstRow, cellRange.lastCol, cellRange.lastRow))
- for col in xrange(cellRange.firstCol, cellRange.lastCol+1):
- arrow = elem.appendElement('arrow')
- arrow.setAttr('col', col)
- arrow.setAttr('row', cellRange.firstRow)
+ for i in xrange(0, len(self.__autoFilterArrows)):
+ arrowObj = self.__autoFilterArrows[i]
+ if arrowObj == None:
+ arrow = elem.appendElement('arrow')
+ arrow.setAttr('pos', "(col=%d,row=%d)"%(cellRange.firstCol+i,cellRange.firstRow))
+ else:
+ elem.appendChild(arrowObj.createDOM(wb, cellRange))
+
class CellBase(object):
@@ -276,3 +285,26 @@ class FormulaCell(CellBase):
s = globals.getRawBytes(self.tokens, True, False)
nd.setAttr('token-bytes', s)
return nd
+
+
+class AutoFilterArrow(object):
+
+ def __init__ (self, filterID):
+ self.filterID = filterID
+ self.isActive = False
+ self.equalString1 = None
+ self.equalString2 = None
+
+ def createDOM (self, wb, filterRange):
+ nd = node.Element('arrow')
+ col = self.filterID + filterRange.firstCol
+ row = filterRange.firstRow
+ nd.setAttr('pos', "(col=%d,row=%d)"%(col,row))
+ nd.setAttr('active', self.isActive)
+ eqStr = ''
+ if self.equalString1 != None:
+ eqStr = self.equalString1
+ if self.equalString2 != None:
+ eqStr += ',' + self.equalString2
+ nd.setAttr('equals', eqStr)
+ return nd
diff --git a/scratch/mso-dumper/src/xlsrecord.py b/scratch/mso-dumper/src/xlsrecord.py
index dc79c76..9dc3a25 100644
--- a/scratch/mso-dumper/src/xlsrecord.py
+++ b/scratch/mso-dumper/src/xlsrecord.py
@@ -316,6 +316,15 @@ class Autofilter(BaseRecordHandler):
def fillModel (self, model):
self.__parseBytes()
+ sh = model.getCurrentSheet()
+ obj = xlsmodel.AutoFilterArrow(self.filterIndex)
+ obj.isActive = True
+ if self.simple1:
+ obj.equalString1 = self.string1
+
+ if self.simple2:
+ obj.equalString1 = self.string2
+ sh.setAutoFilterArrow(self.filterIndex, obj)
class BOF(BaseRecordHandler):
commit b665c298b05e1839420358027d96e98ff16df1d3
Author: Kohei Yoshida <kyoshida at novell.com>
Date: Mon Jan 4 12:54:34 2010 -0500
[xls-dump] More work on handling autofilter in cXML (canonical XML) mode.
Pick up necessary bits from the BIFF parser, and display autofilter range
and arrow positions in cXML structure.
* scratch/mso-dumper/src/formula.py:
* scratch/mso-dumper/src/xlsmodel.py:
* scratch/mso-dumper/src/xlsrecord.py:
diff --git a/scratch/mso-dumper/src/formula.py b/scratch/mso-dumper/src/formula.py
index 42fd82c..7f422d3 100644
--- a/scratch/mso-dumper/src/formula.py
+++ b/scratch/mso-dumper/src/formula.py
@@ -345,42 +345,51 @@ which is usually the first 2 bytes.
def getText (self):
return self.text
-class FormulaParser2(object):
- """This is a new formula parser that will eventually replace the old one.
+# ============================================================================
-Once replaced, I'll change the name to FormulaParser and the names of the
-nested classes will be without the leading underscore (_)."""
+class TokenType:
+ Area3d = 0
+ Unknown = 9999
- class _TokenBase(object):
- def __init__ (self, strm, opcode1, opcode2=None):
- self.opcode1 = opcode1
- self.opcode2 = opcode2
- self.strm = strm
+class _TokenBase(object):
+ def __init__ (self, strm, opcode1, opcode2=None):
+ self.opcode1 = opcode1
+ self.opcode2 = opcode2
+ self.strm = strm
+ self.tokenType = TokenType.Unknown
- def parse (self):
- self.parseBytes()
- self.strm = None # no need to hold reference to the stream.
+ def parse (self):
+ self.parseBytes()
+ self.strm = None # no need to hold reference to the stream.
- def parseBytes (self):
- # derived class should overwrite this method.
- pass
+ def parseBytes (self):
+ # derived class should overwrite this method.
+ pass
- def getText (self):
- return ''
+ def getText (self):
+ return ''
- class _Area3d(_TokenBase):
- def parseBytes (self):
- self.xti = self.strm.readUnsignedInt(2)
- self.cellRange = parseCellRangeAddress(self.strm.readBytes(8))
+class _Area3d(_TokenBase):
+ def parseBytes (self):
+ self.xti = self.strm.readUnsignedInt(2)
+ self.cellRange = parseCellRangeAddress(self.strm.readBytes(8))
+ self.tokenType = TokenType.Area3d
- def getText (self):
- return "(xti=%d,"%self.xti + self.cellRange.getName() + ")"
+ def getText (self):
+ return "(xti=%d,"%self.xti + self.cellRange.getName() + ")"
+
+_tokenMap = {
+ 0x3B: _Area3d,
+ 0x5B: _Area3d,
+ 0x7B: _Area3d
+}
+
+class FormulaParser2(object):
+ """This is a new formula parser that will eventually replace the old one.
+
+Once replaced, I'll change the name to FormulaParser and the names of the
+associated token classes will be without the leading underscore (_)."""
- tokenMap = {
- 0x3B: _Area3d,
- 0x5B: _Area3d,
- 0x7B: _Area3d
- }
def __init__ (self, header, bytes, sizeField=True):
self.header = header
@@ -395,10 +404,10 @@ nested classes will be without the leading underscore (_)."""
def parse (self):
while not self.strm.isEndOfRecord():
b = self.strm.readUnsignedInt(1)
- if not FormulaParser2.tokenMap.has_key(b):
+ if not _tokenMap.has_key(b):
return
- token = FormulaParser2.tokenMap[b](self.strm, b)
+ token = _tokenMap[b](self.strm, b)
token.parse()
self.tokens.append(token)
@@ -407,3 +416,6 @@ nested classes will be without the leading underscore (_)."""
for tk in self.tokens:
s += tk.getText()
return s
+
+ def getTokens (self):
+ return self.tokens
diff --git a/scratch/mso-dumper/src/xlsmodel.py b/scratch/mso-dumper/src/xlsmodel.py
index d1b8a78..51e2356 100644
--- a/scratch/mso-dumper/src/xlsmodel.py
+++ b/scratch/mso-dumper/src/xlsmodel.py
@@ -1,5 +1,5 @@
-import globals, node
+import globals, node, formula
class ModelType:
@@ -24,10 +24,11 @@ class Workbook(ModelBase):
self.__sheets = []
def appendSheet (self):
- if len(self.__sheets) == 0:
+ n = len(self.__sheets)
+ if n == 0:
self.__sheets.append(WorkbookGlobal())
else:
- self.__sheets.append(Worksheet())
+ self.__sheets.append(Worksheet(n-1))
return self.getCurrentSheet()
@@ -112,6 +113,8 @@ class WorkbookGlobal(SheetBase):
self.__sheetData = []
self.__sharedStrings = []
self.__supbooks = []
+ self.__externSheets = [] # tuple (book ID, sheet begin ID, sheet end ID)
+ self.__dbRanges = {} # key: sheet ID (0-based), value: range tokens
def createDOM (self, wb):
nd = node.Element('workbook-global')
@@ -139,35 +142,91 @@ class WorkbookGlobal(SheetBase):
return None
return self.__supbooks[sbID]
+ def appendExternSheet (self, bookID, sheetBeginID, sheetEndID):
+ self.__externSheets.append((bookID, sheetBeginID, sheetEndID))
+
+ def getExternSheet (self, xtiID):
+ if len(self.__externSheets) <= xtiID:
+ return None
+ return self.__externSheets[xtiID]
+
+ def setFilterRange (self, sheetID, tokens):
+ self.__dbRanges[sheetID] = tokens
+
+ def getFilterRange (self, sheetID):
+ if not self.__dbRanges.has_key(sheetID):
+ return None
+
+ return self.__dbRanges[sheetID]
+
class Worksheet(SheetBase):
- def __init__ (self):
+ def __init__ (self, sheetID):
SheetBase.__init__(self, SheetBase.Type.Worksheet)
- self.rows = {}
+ self.__rows = {}
+ self.__autoFilterArrows = []
+ self.sheetID = sheetID
+
+ def setAutoFilterArrowSize (self, arrowSize):
+ arrows = []
+ for i in xrange(0, arrowSize):
+ arrows.append(None)
+
+ # Swap with the new and empty list.
+ self.__autoFilterArrows = arrows
def setCell (self, col, row, cell):
- if not self.rows.has_key(row):
- self.rows[row] = {}
+ if not self.__rows.has_key(row):
+ self.__rows[row] = {}
- self.rows[row][col] = cell
+ self.__rows[row][col] = cell
def createDOM (self, wb):
nd = node.Element('worksheet')
nd.setAttr('version', self.version)
- rows = self.rows.keys()
+
+ # cells
+ rows = self.__rows.keys()
rows.sort()
for row in rows:
rowNode = nd.appendElement('row')
rowNode.setAttr('id', row)
- cols = self.rows[row].keys()
+ cols = self.__rows[row].keys()
for col in cols:
- cell = self.rows[row][col]
+ cell = self.__rows[row][col]
cellNode = cell.createDOM(wb)
rowNode.appendChild(cellNode)
cellNode.setAttr('col', col)
+
+ # autofilter (if exists)
+ self.__appendAutoFilterNode(wb, nd)
+
return nd
+ def __appendAutoFilterNode (self, wb, baseNode):
+ if len(self.__autoFilterArrows) <= 0:
+ return
+
+ wbg = wb.getWorkbookGlobal()
+ tokens = wbg.getFilterRange(self.sheetID)
+ parser = formula.FormulaParser2(None, tokens, False)
+ parser.parse()
+ tokens = parser.getTokens()
+ if len(tokens) != 1 or tokens[0].tokenType != formula.TokenType.Area3d:
+ return
+
+
+ tk = tokens[0]
+ cellRange = tk.cellRange
+
+ elem = baseNode.appendElement('autofilter')
+ elem.setAttr('range', "(col=%d,row=%d)-(col=%d,row=%d)"%(cellRange.firstCol, cellRange.firstRow, cellRange.lastCol, cellRange.lastRow))
+
+ for col in xrange(cellRange.firstCol, cellRange.lastCol+1):
+ arrow = elem.appendElement('arrow')
+ arrow.setAttr('col', col)
+ arrow.setAttr('row', cellRange.firstRow)
class CellBase(object):
diff --git a/scratch/mso-dumper/src/xlsrecord.py b/scratch/mso-dumper/src/xlsrecord.py
index c07aaba..dc79c76 100644
--- a/scratch/mso-dumper/src/xlsrecord.py
+++ b/scratch/mso-dumper/src/xlsrecord.py
@@ -122,9 +122,18 @@ Like parseBytes(), the derived classes must overwrite this method."""
class AutofilterInfo(BaseRecordHandler):
+ def __parseBytes (self):
+ self.arrowCount = self.readUnsignedInt(2)
+
def parseBytes (self):
- arrowCount = self.readUnsignedInt(2)
- self.appendLine("number of autofilter arrows: %d"%arrowCount)
+ self.__parseBytes()
+ self.appendLine("number of autofilter arrows: %d"%self.arrowCount)
+
+ def fillModel (self, model):
+ self.__parseBytes()
+ sh = model.getCurrentSheet()
+ sh.setAutoFilterArrowSize(self.arrowCount)
+
class Autofilter(BaseRecordHandler):
@@ -1063,8 +1072,11 @@ class Name(BaseRecordHandler):
def fillModel (self, model):
self.__parseBytes()
-
+ wbg = model.getWorkbookGlobal()
+ if self.isBuiltinName and len(self.name) == 1 and ord(self.name[0]) == 0x0D:
+ # Pick up a database range for autofilter.
+ wbg.setFilterRange(self.sheetId-1, self.tokenBytes)
class SupBook(BaseRecordHandler):
@@ -1144,6 +1156,9 @@ class ExternSheet(BaseRecordHandler):
def fillModel (self, model):
self.__parseBytes()
+ wbg = model.getWorkbookGlobal()
+ for sh in self.sheets:
+ wbg.appendExternSheet(sh[0], sh[1], sh[2])
class ExternName(BaseRecordHandler):
More information about the ooo-build-commit
mailing list