123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712 |
- # -*- coding: windows-1252 -*-
- # Record Order in BIFF8
- # Workbook Globals Substream
- # BOF Type = workbook globals
- # Interface Header
- # MMS
- # Interface End
- # WRITEACCESS
- # CODEPAGE
- # DSF
- # TABID
- # FNGROUPCOUNT
- # Workbook Protection Block
- # WINDOWPROTECT
- # PROTECT
- # PASSWORD
- # PROT4REV
- # PROT4REVPASS
- # BACKUP
- # HIDEOBJ
- # WINDOW1
- # DATEMODE
- # PRECISION
- # REFRESHALL
- # BOOKBOOL
- # FONT +
- # FORMAT *
- # XF +
- # STYLE +
- # ? PALETTE
- # USESELFS
- #
- # BOUNDSHEET +
- #
- # COUNTRY
- # ? Link Table
- # SST
- # ExtSST
- # EOF
- from . import BIFFRecords
- from . import Style
- from .compat import unicode_type, int_types, basestring
- class Workbook(object):
- """
- This is a class representing a workbook and all its contents. When creating
- Excel files with xlwt, you will normally start by instantiating an
- object of this class.
- """
- #################################################################
- ## Constructor
- #################################################################
- def __init__(self, encoding='ascii', style_compression=0):
- self.encoding = encoding
- self.__owner = 'None'
- self.__country_code = None # 0x07 is Russia :-)
- self.__wnd_protect = 0
- self.__obj_protect = 0
- self.__protect = 0
- self.__backup_on_save = 0
- # for WINDOW1 record
- self.__hpos_twips = 0x01E0
- self.__vpos_twips = 0x005A
- self.__width_twips = 0x3FCF
- self.__height_twips = 0x2A4E
- self.__custom_palette_b8 = None
- self.__active_sheet = 0
- self.__first_tab_index = 0
- self.__selected_tabs = 0x01
- self.__tab_width_twips = 0x0258
- self.__wnd_hidden = 0
- self.__wnd_mini = 0
- self.__hscroll_visible = 1
- self.__vscroll_visible = 1
- self.__tabs_visible = 1
- self.__styles = Style.StyleCollection(style_compression)
- self.__dates_1904 = 0
- self.__use_cell_values = 1
- self.__sst = BIFFRecords.SharedStringTable(self.encoding)
- self.__worksheets = []
- self.__worksheet_idx_from_name = {}
- self.__sheet_refs = {}
- self._supbook_xref = {}
- self._xcall_xref = {}
- self._ownbook_supbookx = None
- self._ownbook_supbook_ref = None
- self._xcall_supbookx = None
- self._xcall_supbook_ref = None
- #################################################################
- ## Properties, "getters", "setters"
- #################################################################
- def get_style_stats(self):
- return self.__styles.stats[:]
- def set_owner(self, value):
- self.__owner = value
- def get_owner(self):
- return self.__owner
- owner = property(get_owner, set_owner)
- #################################################################
- def set_country_code(self, value):
- self.__country_code = value
- def get_country_code(self):
- return self.__country_code
- country_code = property(get_country_code, set_country_code)
- #################################################################
- def set_wnd_protect(self, value):
- self.__wnd_protect = int(value)
- def get_wnd_protect(self):
- return bool(self.__wnd_protect)
- wnd_protect = property(get_wnd_protect, set_wnd_protect)
- #################################################################
- def set_obj_protect(self, value):
- self.__obj_protect = int(value)
- def get_obj_protect(self):
- return bool(self.__obj_protect)
- obj_protect = property(get_obj_protect, set_obj_protect)
- #################################################################
- def set_protect(self, value):
- self.__protect = int(value)
- def get_protect(self):
- return bool(self.__protect)
- protect = property(get_protect, set_protect)
- #################################################################
- def set_backup_on_save(self, value):
- self.__backup_on_save = int(value)
- def get_backup_on_save(self):
- return bool(self.__backup_on_save)
- backup_on_save = property(get_backup_on_save, set_backup_on_save)
- #################################################################
- def set_hpos(self, value):
- self.__hpos_twips = value & 0xFFFF
- def get_hpos(self):
- return self.__hpos_twips
- hpos = property(get_hpos, set_hpos)
- #################################################################
- def set_vpos(self, value):
- self.__vpos_twips = value & 0xFFFF
- def get_vpos(self):
- return self.__vpos_twips
- vpos = property(get_vpos, set_vpos)
- #################################################################
- def set_width(self, value):
- self.__width_twips = value & 0xFFFF
- def get_width(self):
- return self.__width_twips
- width = property(get_width, set_width)
- #################################################################
- def set_height(self, value):
- self.__height_twips = value & 0xFFFF
- def get_height(self):
- return self.__height_twips
- height = property(get_height, set_height)
- #################################################################
- def set_active_sheet(self, value):
- self.__active_sheet = value & 0xFFFF
- self.__first_tab_index = self.__active_sheet
- def get_active_sheet(self):
- return self.__active_sheet
- active_sheet = property(get_active_sheet, set_active_sheet)
- #################################################################
- def set_tab_width(self, value):
- self.__tab_width_twips = value & 0xFFFF
- def get_tab_width(self):
- return self.__tab_width_twips
- tab_width = property(get_tab_width, set_tab_width)
- #################################################################
- def set_wnd_visible(self, value):
- self.__wnd_hidden = int(not value)
- def get_wnd_visible(self):
- return not bool(self.__wnd_hidden)
- wnd_visible = property(get_wnd_visible, set_wnd_visible)
- #################################################################
- def set_wnd_mini(self, value):
- self.__wnd_mini = int(value)
- def get_wnd_mini(self):
- return bool(self.__wnd_mini)
- wnd_mini = property(get_wnd_mini, set_wnd_mini)
- #################################################################
- def set_hscroll_visible(self, value):
- self.__hscroll_visible = int(value)
- def get_hscroll_visible(self):
- return bool(self.__hscroll_visible)
- hscroll_visible = property(get_hscroll_visible, set_hscroll_visible)
- #################################################################
- def set_vscroll_visible(self, value):
- self.__vscroll_visible = int(value)
- def get_vscroll_visible(self):
- return bool(self.__vscroll_visible)
- vscroll_visible = property(get_vscroll_visible, set_vscroll_visible)
- #################################################################
- def set_tabs_visible(self, value):
- self.__tabs_visible = int(value)
- def get_tabs_visible(self):
- return bool(self.__tabs_visible)
- tabs_visible = property(get_tabs_visible, set_tabs_visible)
- #################################################################
- def set_dates_1904(self, value):
- self.__dates_1904 = int(value)
- def get_dates_1904(self):
- return bool(self.__dates_1904)
- dates_1904 = property(get_dates_1904, set_dates_1904)
- #################################################################
- def set_use_cell_values(self, value):
- self.__use_cell_values = int(value)
- def get_use_cell_values(self):
- return bool(self.__use_cell_values)
- use_cell_values = property(get_use_cell_values, set_use_cell_values)
- #################################################################
- def get_default_style(self):
- return self.__styles.default_style
- default_style = property(get_default_style)
- #################################################################
- def set_colour_RGB(self, colour_index, red, green, blue):
- if not(8 <= colour_index <= 63):
- raise Exception("set_colour_RGB: colour_index (%d) not in range(8, 64)" %
- colour_index)
- if min(red, green, blue) < 0 or max(red, green, blue) > 255:
- raise Exception("set_colour_RGB: colour values (%d,%d,%d) must be in range(0, 256)"
- % (red, green, blue))
- if self.__custom_palette_b8 is None:
- self.__custom_palette_b8 = list(Style.excel_default_palette_b8)
- # User-defined Palette starts at colour index 8,
- # so subtract 8 from colour_index when placing in palette
- palette_index = colour_index - 8
- self.__custom_palette_b8[palette_index] = red << 24 | green << 16 | blue << 8
- ##################################################################
- ## Methods
- ##################################################################
- def add_style(self, style):
- return self.__styles.add(style)
-
- def add_font(self, font):
- return self.__styles.add_font(font)
- def add_str(self, s):
- return self.__sst.add_str(s)
- def del_str(self, sst_idx):
- self.__sst.del_str(sst_idx)
- def str_index(self, s):
- return self.__sst.str_index(s)
-
- def add_rt(self, rt):
- return self.__sst.add_rt(rt)
-
- def rt_index(self, rt):
- return self.__sst.rt_index(rt)
- def add_sheet(self, sheetname, cell_overwrite_ok=False):
- """
- This method is used to create Worksheets in a Workbook.
- :param sheetname:
- The name to use for this sheet, as it will appear in the
- tabs at the bottom of the Excel application.
- :param cell_overwrite_ok:
- If ``True``, cells in the added worksheet will not raise an
- exception if written to more than once.
- :return:
- The :class:`~xlwt.Worksheet.Worksheet` that was added.
- """
- from . import Utils
- from .Worksheet import Worksheet
- if not isinstance(sheetname, unicode_type):
- sheetname = sheetname.decode(self.encoding)
- if not Utils.valid_sheet_name(sheetname):
- raise Exception("invalid worksheet name %r" % sheetname)
- lower_name = sheetname.lower()
- if lower_name in self.__worksheet_idx_from_name:
- raise Exception("duplicate worksheet name %r" % sheetname)
- self.__worksheet_idx_from_name[lower_name] = len(self.__worksheets)
- self.__worksheets.append(Worksheet(sheetname, self, cell_overwrite_ok))
- return self.__worksheets[-1]
- def get_sheet(self, sheet):
- if isinstance(sheet, int_types):
- return self.__worksheets[sheet]
- elif isinstance(sheet, basestring):
- sheetnum = self.sheet_index(sheet)
- return self.__worksheets[sheetnum]
- else:
- raise Exception("sheet must be integer or string")
-
- def sheet_index(self, sheetname):
- try:
- sheetnum = self.__worksheet_idx_from_name[sheetname.lower()]
- except KeyError:
- self.raise_bad_sheetname(sheetname)
-
- return sheetnum
- def raise_bad_sheetname(self, sheetname):
- raise Exception("Formula: unknown sheet name %s" % sheetname)
- def convert_sheetindex(self, strg_ref, n_sheets):
- idx = int(strg_ref)
- if 0 <= idx < n_sheets:
- return idx
- msg = "Formula: sheet index (%s) >= number of sheets (%d)" % (strg_ref, n_sheets)
- raise Exception(msg)
- def _get_supbook_index(self, tag):
- if tag in self._supbook_xref:
- return self._supbook_xref[tag]
- self._supbook_xref[tag] = idx = len(self._supbook_xref)
- return idx
- def setup_ownbook(self):
- self._ownbook_supbookx = self._get_supbook_index(('ownbook', 0))
- self._ownbook_supbook_ref = None
- reference = (self._ownbook_supbookx, 0xFFFE, 0xFFFE)
- if reference in self.__sheet_refs:
- raise Exception("can't happen")
- self.__sheet_refs[reference] = self._ownbook_supbook_ref = len(self.__sheet_refs)
- def setup_xcall(self):
- self._xcall_supbookx = self._get_supbook_index(('xcall', 0))
- self._xcall_supbook_ref = None
- reference = (self._xcall_supbookx, 0xFFFE, 0xFFFE)
- if reference in self.__sheet_refs:
- raise Exception("can't happen")
- self.__sheet_refs[reference] = self._xcall_supbook_ref = len(self.__sheet_refs)
- def add_sheet_reference(self, formula):
- patches = []
- n_sheets = len(self.__worksheets)
- sheet_refs, xcall_refs = formula.get_references()
- for ref0, ref1, offset in sheet_refs:
- if not ref0.isdigit():
- try:
- ref0n = self.__worksheet_idx_from_name[ref0.lower()]
- except KeyError:
- self.raise_bad_sheetname(ref0)
- else:
- ref0n = self.convert_sheetindex(ref0, n_sheets)
- if ref1 == ref0:
- ref1n = ref0n
- elif not ref1.isdigit():
- try:
- ref1n = self.__worksheet_idx_from_name[ref1.lower()]
- except KeyError:
- self.raise_bad_sheetname(ref1)
- else:
- ref1n = self.convert_sheetindex(ref1, n_sheets)
- if ref1n < ref0n:
- msg = "Formula: sheets out of order; %r:%r -> (%d, %d)" \
- % (ref0, ref1, ref0n, ref1n)
- raise Exception(msg)
- if self._ownbook_supbookx is None:
- self.setup_ownbook()
- reference = (self._ownbook_supbookx, ref0n, ref1n)
- if reference in self.__sheet_refs:
- patches.append((offset, self.__sheet_refs[reference]))
- else:
- nrefs = len(self.__sheet_refs)
- if nrefs > 65535:
- raise Exception('More than 65536 inter-sheet references')
- self.__sheet_refs[reference] = nrefs
- patches.append((offset, nrefs))
- for funcname, offset in xcall_refs:
- if self._ownbook_supbookx is None:
- self.setup_ownbook()
- if self._xcall_supbookx is None:
- self.setup_xcall()
- # print funcname, self._supbook_xref
- patches.append((offset, self._xcall_supbook_ref))
- if not isinstance(funcname, unicode_type):
- funcname = funcname.decode(self.encoding)
- if funcname in self._xcall_xref:
- idx = self._xcall_xref[funcname]
- else:
- self._xcall_xref[funcname] = idx = len(self._xcall_xref)
- patches.append((offset + 2, idx + 1))
- formula.patch_references(patches)
- ##################################################################
- ## BIFF records generation
- ##################################################################
- def __bof_rec(self):
- return BIFFRecords.Biff8BOFRecord(BIFFRecords.Biff8BOFRecord.BOOK_GLOBAL).get()
- def __eof_rec(self):
- return BIFFRecords.EOFRecord().get()
- def __intf_hdr_rec(self):
- return BIFFRecords.InteraceHdrRecord().get()
- def __intf_end_rec(self):
- return BIFFRecords.InteraceEndRecord().get()
- def __intf_mms_rec(self):
- return BIFFRecords.MMSRecord().get()
- def __write_access_rec(self):
- return BIFFRecords.WriteAccessRecord(self.__owner).get()
- def __wnd_protect_rec(self):
- return BIFFRecords.WindowProtectRecord(self.__wnd_protect).get()
- def __obj_protect_rec(self):
- return BIFFRecords.ObjectProtectRecord(self.__obj_protect).get()
- def __protect_rec(self):
- return BIFFRecords.ProtectRecord(self.__protect).get()
- def __password_rec(self):
- return BIFFRecords.PasswordRecord().get()
- def __prot4rev_rec(self):
- return BIFFRecords.Prot4RevRecord().get()
- def __prot4rev_pass_rec(self):
- return BIFFRecords.Prot4RevPassRecord().get()
- def __backup_rec(self):
- return BIFFRecords.BackupRecord(self.__backup_on_save).get()
- def __hide_obj_rec(self):
- return BIFFRecords.HideObjRecord().get()
- def __window1_rec(self):
- flags = 0
- flags |= (self.__wnd_hidden) << 0
- flags |= (self.__wnd_mini) << 1
- flags |= (self.__hscroll_visible) << 3
- flags |= (self.__vscroll_visible) << 4
- flags |= (self.__tabs_visible) << 5
- return BIFFRecords.Window1Record(self.__hpos_twips, self.__vpos_twips,
- self.__width_twips, self.__height_twips,
- flags,
- self.__active_sheet, self.__first_tab_index,
- self.__selected_tabs, self.__tab_width_twips).get()
- def __codepage_rec(self):
- return BIFFRecords.CodepageBiff8Record().get()
- def __country_rec(self):
- if not self.__country_code:
- return b''
- return BIFFRecords.CountryRecord(self.__country_code, self.__country_code).get()
- def __dsf_rec(self):
- return BIFFRecords.DSFRecord().get()
- def __tabid_rec(self):
- return BIFFRecords.TabIDRecord(len(self.__worksheets)).get()
- def __fngroupcount_rec(self):
- return BIFFRecords.FnGroupCountRecord().get()
- def __datemode_rec(self):
- return BIFFRecords.DateModeRecord(self.__dates_1904).get()
- def __precision_rec(self):
- return BIFFRecords.PrecisionRecord(self.__use_cell_values).get()
- def __refresh_all_rec(self):
- return BIFFRecords.RefreshAllRecord().get()
- def __bookbool_rec(self):
- return BIFFRecords.BookBoolRecord().get()
- def __all_fonts_num_formats_xf_styles_rec(self):
- return self.__styles.get_biff_data()
- def __palette_rec(self):
- if self.__custom_palette_b8 is None:
- return b''
- info = BIFFRecords.PaletteRecord(self.__custom_palette_b8).get()
- return info
- def __useselfs_rec(self):
- return BIFFRecords.UseSelfsRecord().get()
- def __boundsheets_rec(self, data_len_before, data_len_after, sheet_biff_lens):
- # .................................
- # BOUNDSEHEET0
- # BOUNDSEHEET1
- # BOUNDSEHEET2
- # ..................................
- # WORKSHEET0
- # WORKSHEET1
- # WORKSHEET2
- boundsheets_len = 0
- for sheet in self.__worksheets:
- boundsheets_len += len(BIFFRecords.BoundSheetRecord(
- 0x00, sheet.visibility, sheet.name, self.encoding
- ).get())
- start = data_len_before + boundsheets_len + data_len_after
- result = b''
- for sheet_biff_len, sheet in zip(sheet_biff_lens, self.__worksheets):
- result += BIFFRecords.BoundSheetRecord(
- start, sheet.visibility, sheet.name, self.encoding
- ).get()
- start += sheet_biff_len
- return result
- def __all_links_rec(self):
- pieces = []
- temp = [(idx, tag) for tag, idx in self._supbook_xref.items()]
- temp.sort()
- for idx, tag in temp:
- stype, snum = tag
- if stype == 'ownbook':
- rec = BIFFRecords.InternalReferenceSupBookRecord(len(self.__worksheets)).get()
- pieces.append(rec)
- elif stype == 'xcall':
- rec = BIFFRecords.XcallSupBookRecord().get()
- pieces.append(rec)
- temp = [(idx, name) for name, idx in self._xcall_xref.items()]
- temp.sort()
- for idx, name in temp:
- rec = BIFFRecords.ExternnameRecord(
- options=0, index=0, name=name, fmla='\x02\x00\x1c\x17').get()
- pieces.append(rec)
- else:
- raise Exception('unknown supbook stype %r' % stype)
- if len(self.__sheet_refs) > 0:
- # get references in index order
- temp = [(idx, ref) for ref, idx in self.__sheet_refs.items()]
- temp.sort()
- temp = [ref for idx, ref in temp]
- externsheet_record = BIFFRecords.ExternSheetRecord(temp).get()
- pieces.append(externsheet_record)
- return b''.join(pieces)
- def __sst_rec(self):
- return self.__sst.get_biff_record()
- def __ext_sst_rec(self, abs_stream_pos):
- return b''
- #return BIFFRecords.ExtSSTRecord(abs_stream_pos, self.sst_record.str_placement,
- #self.sst_record.portions_len).get()
- def get_biff_data(self):
- before = b''
- before += self.__bof_rec()
- before += self.__intf_hdr_rec()
- before += self.__intf_mms_rec()
- before += self.__intf_end_rec()
- before += self.__write_access_rec()
- before += self.__codepage_rec()
- before += self.__dsf_rec()
- before += self.__tabid_rec()
- before += self.__fngroupcount_rec()
- before += self.__wnd_protect_rec()
- before += self.__protect_rec()
- before += self.__obj_protect_rec()
- before += self.__password_rec()
- before += self.__prot4rev_rec()
- before += self.__prot4rev_pass_rec()
- before += self.__backup_rec()
- before += self.__hide_obj_rec()
- before += self.__window1_rec()
- before += self.__datemode_rec()
- before += self.__precision_rec()
- before += self.__refresh_all_rec()
- before += self.__bookbool_rec()
- before += self.__all_fonts_num_formats_xf_styles_rec()
- before += self.__palette_rec()
- before += self.__useselfs_rec()
- country = self.__country_rec()
- all_links = self.__all_links_rec()
- shared_str_table = self.__sst_rec()
- after = country + all_links + shared_str_table
- ext_sst = self.__ext_sst_rec(0) # need fake cause we need calc stream pos
- eof = self.__eof_rec()
- self.__worksheets[self.__active_sheet].selected = True
- sheets = b''
- sheet_biff_lens = []
- for sheet in self.__worksheets:
- data = sheet.get_biff_data()
- sheets += data
- sheet_biff_lens.append(len(data))
- bundlesheets = self.__boundsheets_rec(len(before), len(after)+len(ext_sst)+len(eof), sheet_biff_lens)
- sst_stream_pos = len(before) + len(bundlesheets) + len(country) + len(all_links)
- ext_sst = self.__ext_sst_rec(sst_stream_pos)
- return before + bundlesheets + after + ext_sst + eof + sheets
- def save(self, filename_or_stream):
- """
- This method is used to save the Workbook to a file in native Excel
- format.
- :param filename_or_stream:
- This can be a string containing a filename of
- the file, in which case the excel file is saved to disk using the name
- provided. It can also be a stream object with a write method, such as
- a :class:`~io.StringIO`, in which case the data for the excel
- file is written to the stream.
- """
- from . import CompoundDoc
- doc = CompoundDoc.XlsDoc()
- doc.save(filename_or_stream, self.get_biff_data())
|