123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924 |
- #
- # This file is part of the LibreOffice project.
- #
- # This Source Code Form is subject to the terms of the Mozilla Public
- # License, v. 2.0. If a copy of the MPL was not distributed with this
- # file, You can obtain one at http://mozilla.org/MPL/2.0/.
- #
- # This file incorporates work covered by the following license notice:
- #
- # Licensed to the Apache Software Foundation (ASF) under one or more
- # contributor license agreements. See the NOTICE file distributed
- # with this work for additional information regarding copyright
- # ownership. The ASF licenses this file to you under the Apache
- # License, Version 2.0 (the "License"); you may not use this file
- # except in compliance with the License. You may obtain a copy of
- # the License at http://www.apache.org/licenses/LICENSE-2.0 .
- #
- import uno
- import traceback
- from ..text.TextElement import TextElement
- from ..text.TextDocument import TextDocument
- from ..text.TextSectionHandler import TextSectionHandler
- from ..common.FileAccess import FileAccess
- from datetime import datetime
- from com.sun.star.text.PlaceholderType import TEXT
- from com.sun.star.i18n.NumberFormatIndex import TIME_HHMM, DATE_SYSTEM_LONG
- '''
- The classes here implement the whole document-functionality of the agenda wizard:
- the live-preview and the final "creation" of the document,
- when the user clicks "finish". <br/>
- <br/>
- <h2>Some terminology:<h2/>
- items are names or headings. we don't make any distinction.
- <br/>
- The Agenda Template is used as general "controller"
- of the whole document, whereas the two child-classes ItemsTable
- and TopicsTable control the item tables (note plural!) and the
- topics table (note singular).<br/>
- <br/>
- Other small classes are used to abstract the handling of cells and text and we
- try to use them as components.
- <br/><br/>
- We tried to keep the Agenda Template as flexible as possible, though there
- must be many limitations, because it is generated dynamically.<br/><br/>
- To keep the template flexible the following decisions were made:<br/>
- 1. Item tables.<br/>
- 1.a. there might be arbitrary number of Item tables.<br/>
- 1.b. Item tables design (bordewr, background) is arbitrary.<br/>
- 1.c. Items text styles are individual,
- and use stylelist styles with predefined names.<br/>
- As result the following limitations:<br/>
- Pairs of Name->value for each item.<br/>
- Tables contain *only* those pairs.<br/>
- 2. Topics table.<br/>
- 2.a. arbitrary structure.<br/>
- 2.b. design is arbitrary.<br/>
- As result the following limitations:<br/>
- No column merge is allowed.<br/>
- One compulsory Heading row.<br/>
- <br/><br/>
- To let the template be flexible, we use a kind of "detection": we look where
- the items are read the design of each table, re-applying it after writing the
- table.self.xTextDocument
- <br/><br/>
- A note about threads:<br/>
- Many methods here are synchronized, in order to avoid collision made by
- events fired too often.
- '''
- class AgendaDocument(TextDocument):
- '''
- constructor. The document is *not* loaded here.
- only some formal members are set.
- '''
- def __init__(self, xmsf, agenda, resources, templateConsts, listener):
- super(AgendaDocument,self).__init__(xmsf,listener, None,
- "WIZARD_LIVE_PREVIEW")
- self.agenda = agenda
- self.templateConsts = templateConsts
- self.resources = resources
- self.itemsMap = {}
- self.allItems = []
- def load(self, templateURL):
- # Each template is duplicated. aw-XXX.ott is the template itself
- # and XXX.ott is a section link.
- self.template = self.calcTemplateName(templateURL)
- self.loadAsPreview(templateURL, False)
- self.xFrame.ComponentWindow.Enable = False
- self.xTextDocument.lockControllers()
- self.initialize()
- self.initializeData()
- self.xTextDocument.unlockControllers()
- '''
- The agenda templates are in format of aw-XXX.ott
- the templates name is then XXX.ott.
- This method calculates it.
- '''
- def calcTemplateName(self, url):
- return FileAccess.connectURLs(
- FileAccess.getParentDir(url), FileAccess.getFilename(url)[3:])
- '''synchronize the document to the model.<br/>
- this method rewrites all titles, item tables , and the topics table-
- thus synchronizing the document to the data model (CGAgenda).
- information (it is only actualized on save) the given list
- supplies this information.
- '''
- def initializeData(self):
- for i in self.itemsTables:
- try:
- i.write()
- except Exception:
- traceback.print_exc()
- self.redrawTitle("txtTitle")
- self.redrawTitle("txtDate")
- self.redrawTitle("txtTime")
- self.redrawTitle("cbLocation")
- '''
- redraws/rewrites the table which contains the given item
- This method is called when the user checks/unchecks an item.
- The table is being found, in which the item is, and redrawn.
- '''
- def redraw(self, itemName):
- self.xTextDocument.lockControllers()
- try:
- # get the table in which the item is...
- itemsTable = self.itemsMap[itemName]
- # rewrite the table.
- itemsTable.write()
- except Exception:
- traceback.print_exc()
- self.xTextDocument.unlockControllers()
- '''
- checks the data model if the
- item corresponding to the given string should be shown
- '''
- def isShowItem(self, itemName):
- if itemName == self.templateConsts.FILLIN_MEETING_TYPE:
- return self.agenda.cp_ShowMeetingType
- elif itemName == self.templateConsts.FILLIN_READ:
- return self.agenda.cp_ShowRead
- elif itemName == self.templateConsts.FILLIN_BRING:
- return self.agenda.cp_ShowBring
- elif itemName == self.templateConsts.FILLIN_NOTES:
- return self.agenda.cp_ShowNotes
- elif itemName == self.templateConsts.FILLIN_FACILITATOR:
- return self.agenda.cp_ShowFacilitator
- elif itemName == self.templateConsts.FILLIN_TIMEKEEPER:
- return self.agenda.cp_ShowTimekeeper
- elif itemName == self.templateConsts.FILLIN_NOTETAKER:
- return self.agenda.cp_ShowNotetaker
- elif itemName == self.templateConsts.FILLIN_PARTICIPANTS:
- return self.agenda.cp_ShowAttendees
- elif itemName == self.templateConsts.FILLIN_CALLED_BY:
- return self.agenda.cp_ShowCalledBy
- elif itemName == self.templateConsts.FILLIN_OBSERVERS:
- return self.agenda.cp_ShowObservers
- elif itemName == self.templateConsts.FILLIN_RESOURCE_PERSONS:
- return self.agenda.cp_ShowResourcePersons
- else:
- raise ValueError("No such item")
- '''itemsCache is a Map containing all agenda item. These are object which
- "write themselves" to the table, given a table cursor.
- A cache is used in order to reuse the objects, instead of recreate them.
- This method fills the cache will all items objects (names and headings).
- '''
- def initItemsCache(self):
- self.itemsCache = {}
- # Headings
- self.itemsCache[
- self.templateConsts.FILLIN_MEETING_TYPE] = \
- AgendaItem(self.templateConsts.FILLIN_MEETING_TYPE,
- self.resources.itemMeetingType,
- PlaceholderElement(
- self.resources.reschkMeetingTitle_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- self.itemsCache[
- self.templateConsts.FILLIN_BRING] = \
- AgendaItem(self.templateConsts.FILLIN_BRING,
- self.resources.itemBring,
- PlaceholderElement (
- self.resources.reschkBring_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- self.itemsCache[
- self.templateConsts.FILLIN_READ] = \
- AgendaItem (self.templateConsts.FILLIN_READ,
- self.resources.itemRead,
- PlaceholderElement (
- self.resources.reschkRead_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- self.itemsCache[
- self.templateConsts.FILLIN_NOTES] = \
- AgendaItem (self.templateConsts.FILLIN_NOTES,
- self.resources.itemNote,
- PlaceholderElement (
- self.resources.reschkNotes_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- # Names
- self.itemsCache[
- self.templateConsts.FILLIN_CALLED_BY] = \
- AgendaItem(self.templateConsts.FILLIN_CALLED_BY,
- self.resources.itemCalledBy,
- PlaceholderElement (
- self.resources.reschkConvenedBy_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- self.itemsCache[
- self.templateConsts.FILLIN_FACILITATOR] = \
- AgendaItem(self.templateConsts.FILLIN_FACILITATOR,
- self.resources.itemFacilitator,
- PlaceholderElement (
- self.resources.reschkPresiding_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- self.itemsCache[
- self.templateConsts.FILLIN_PARTICIPANTS] = \
- AgendaItem(self.templateConsts.FILLIN_PARTICIPANTS,
- self.resources.itemAttendees,
- PlaceholderElement(
- self.resources.reschkAttendees_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- self.itemsCache[
- self.templateConsts.FILLIN_NOTETAKER] = \
- AgendaItem(self.templateConsts.FILLIN_NOTETAKER,
- self.resources.itemNotetaker,
- PlaceholderElement(
- self.resources.reschkNoteTaker_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- self.itemsCache[
- self.templateConsts.FILLIN_TIMEKEEPER] = \
- AgendaItem(self.templateConsts.FILLIN_TIMEKEEPER,
- self.resources.itemTimekeeper,
- PlaceholderElement(
- self.resources.reschkTimekeeper_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- self.itemsCache[
- self.templateConsts.FILLIN_OBSERVERS] = \
- AgendaItem(self.templateConsts.FILLIN_OBSERVERS,
- self.resources.itemObservers,
- PlaceholderElement(
- self.resources.reschkObservers_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- self.itemsCache[
- self.templateConsts.FILLIN_RESOURCE_PERSONS] = \
- AgendaItem(self.templateConsts.FILLIN_RESOURCE_PERSONS,
- self.resources.itemResource,
- PlaceholderElement(
- self.resources.reschkResourcePersons_value,
- self.resources.resPlaceHolderHint, self.xTextDocument))
- '''Initializes a template.<br/>
- This method does the following tasks:<br/>
- get a Time and Date format for the document, and retrieve the null
- date of the document (which is document-specific).<br/>
- Initializes the Items Cache map.
- Analyses the document:<br/>
- -find all "filled-ins" (appear as >xxx< in the document).
- -analyze all items sections (and the tables in them).
- -locate the titles and actualize them
- -analyze the topics table
- '''
- def initialize(self):
- '''
- Get the default locale of the document,
- and create the date and time formatters.
- '''
- self.dateUtils = self.DateUtils(self.xMSF, self.xTextDocument)
- self.formatter = self.dateUtils.formatter
- self.dateFormat = self.dateUtils.getFormat(DATE_SYSTEM_LONG)
- self.timeFormat = self.dateUtils.getFormat(TIME_HHMM)
- self.initItemsCache()
- self.allItems = self.searchFillInItems(0)
- self.initializeTitles()
- self.initializeItemsSections()
- self.textSectionHandler = TextSectionHandler(
- self.xTextDocument, self.xTextDocument)
- self.topics = Topics(self)
- '''
- locates the titles (name, location, date, time)
- and saves a reference to their Text ranges.
- '''
- def initializeTitles(self):
- auxList = []
- for i in self.allItems:
- text = i.String.lstrip().lower()
- if text == self.templateConsts.FILLIN_TITLE:
- self.teTitle = PlaceholderTextElement(
- i, self.resources.resPlaceHolderTitle,
- self.resources.resPlaceHolderHint, self.xTextDocument)
- self.trTitle = i
- elif text == self.templateConsts.FILLIN_DATE:
- self.teDate = PlaceholderTextElement(
- i, self.resources.resPlaceHolderDate,
- self.resources.resPlaceHolderHint, self.xTextDocument)
- self.trDate = i
- elif text == self.templateConsts.FILLIN_TIME:
- self.teTime = PlaceholderTextElement(
- i, self.resources.resPlaceHolderTime,
- self.resources.resPlaceHolderHint, self.xTextDocument)
- self.trTime = i
- elif text == self.templateConsts.FILLIN_LOCATION:
- self.teLocation = PlaceholderTextElement(
- i, self.resources.resPlaceHolderLocation,
- self.resources.resPlaceHolderHint, self.xTextDocument)
- self.trLocation = i
- else:
- auxList.append(i)
- self.allItems = auxList
- '''
- analyze the item sections in the template.
- delegates the analyze of each table to the ItemsTable class.
- '''
- def initializeItemsSections(self):
- sections = self.getSections(
- self.xTextDocument, self.templateConsts.SECTION_ITEMS)
- # for each section - there is a table...
- self.itemsTables = []
- for i in sections:
- try:
- self.itemsTables.append(
- ItemsTable(self.getSection(i), self.getTable(i), self))
- except Exception:
- traceback.print_exc()
- raise AttributeError (
- "Fatal Error while initializing \
- Template: items table in section " + i)
- def getSections(self, document, s):
- allSections = document.TextSections.ElementNames
- return self.getNamesWhichStartWith(allSections, s)
- def getSection(self, name):
- return self.xTextDocument.TextSections.getByName(name)
- def getTable(self, name):
- return self.xTextDocument.TextTables.getByName(name)
- def redrawTitle(self, controlName):
- try:
- if controlName == "txtTitle":
- self.teTitle.placeHolderText = self.agenda.cp_Title
- self.teTitle.write(self.trTitle)
- elif controlName == "txtDate":
- self.teDate.placeHolderText = \
- self.getDateString(self.agenda.cp_Date)
- self.teDate.write(self.trDate)
- elif controlName == "txtTime":
- self.teTime.placeHolderText = self.agenda.cp_Time
- self.teTime.write(self.trTime)
- elif controlName == "cbLocation":
- self.teLocation.placeHolderText = self.agenda.cp_Location
- self.teLocation.write(self.trLocation)
- else:
- raise Exception("No such title control...")
- except Exception:
- traceback.print_exc()
- def getDateString(self, date):
- if not date:
- return ""
- dateObject = datetime.strptime(date, '%d/%m/%y').date()
- return self.dateUtils.format(self.dateFormat, dateObject)
- def finish(self, topics):
- self.createMinutes(topics)
- self.deleteHiddenSections()
- self.textSectionHandler.removeAllTextSections()
- '''
- hidden sections exist when an item's section is hidden because the
- user specified not to display any items which it contains.
- When finishing the wizard removes this sections
- entirely from the document.
- '''
- def deleteHiddenSections(self):
- allSections = self.xTextDocument.TextSections.ElementNames
- try:
- for i in allSections:
- self.section = self.getSection(i)
- visible = bool(self.section.IsVisible)
- if not visible:
- self.section.Anchor.String = ""
- except Exception:
- traceback.print_exc()
- '''
- create the minutes for the given topics or remove the minutes
- section from the document.
- If no topics are supplied, or the user specified not to create minutes,
- the minutes section will be removed,
- @param topicsData supplies PropertyValue arrays containing
- the values for the topics.
- '''
- def createMinutes(self, topicsData):
- # if the minutes section should be removed (the
- # user did not check "create minutes")
- if not self.agenda.cp_IncludeMinutes \
- or len(topicsData) <= 1:
- try:
- minutesAllSection = self.getSection(
- self.templateConsts.SECTION_MINUTES_ALL)
- minutesAllSection.Anchor.String = ""
- except Exception:
- traceback.print_exc()
- # the user checked "create minutes"
- else:
- try:
- topicStartTime = int(self.agenda.cp_Time)
- # first I replace the minutes titles...
- self.items = self.searchFillInItems()
- itemIndex = 0
- for item in self.items:
- itemText = item.String.lstrip().lower()
- if itemText == \
- self.templateConsts.FILLIN_MINUTES_TITLE:
- self.fillMinutesItem(
- item, self.agenda.cp_Title,
- self.resources.resPlaceHolderTitle)
- elif itemText == \
- self.templateConsts.FILLIN_MINUTES_LOCATION:
- self.fillMinutesItem(
- item, self.agenda.cp_Location,
- self.resources.resPlaceHolderLocation)
- elif itemText == \
- self.templateConsts.FILLIN_MINUTES_DATE:
- self.fillMinutesItem(
- item, getDateString(self.agenda.cp_Date),
- self.resources.resPlaceHolderDate)
- elif itemText == \
- self.templateConsts.FILLIN_MINUTES_TIME:
- self.fillMinutesItem( item, self.agenda.cp_Time,
- self.resources.resPlaceHolderTime)
- self.items.clear()
- '''
- now add minutes for each topic.
- The template contains *one* minutes section, so
- we first use the one available, and then add a one...
- topics data has *always* an empty topic at the end...
- '''
- for i in xrange(len(topicsData) - 1):
- topic = topicsData[i]
- items = self.searchFillInItems()
- itemIndex = 0
- for item in items:
- itemText = item.String.lstrip().lower()
- if itemText == \
- self.templateConsts.FILLIN_MINUTE_NUM:
- self.fillMinutesItem(item, topic[0].Value, "")
- elif itemText == \
- self.templateConsts.FILLIN_MINUTE_TOPIC:
- self.fillMinutesItem(item, topic[1].Value, "")
- elif itemText == \
- self.templateConsts.FILLIN_MINUTE_RESPONSIBLE:
- self.fillMinutesItem(item, topic[2].Value, "")
- elif itemText == \
- self.templateConsts.FILLIN_MINUTE_TIME:
- topicTime = 0
- try:
- topicTime = topic[3].Value
- except Exception:
- pass
- '''
- if the topic has no time, we do not
- display any time here.
- '''
- if topicTime == 0 or topicStartTime == 0:
- time = topic[3].Value
- else:
- time = str(topicStartTime) + " - "
- topicStartTime += topicTime * 1000
- time += str(topicStartTime)
- self.fillMinutesItem(item, time, "")
- self.textSectionHandler.removeTextSectionbyName(
- self.templateConsts.SECTION_MINUTES)
- # after the last section we do not insert a one.
- if i < len(topicsData) - 2:
- self.textSectionHandler.insertTextSection(
- self.templateConsts.SECTION_MINUTES,
- self.template, False)
- except Exception:
- traceback.print_exc()
- '''given a text range and a text, fills the given
- text range with the given text.
- If the given text is empty, uses a placeholder with the given
- placeholder text.
- @param range text range to fill
- @param text the text to fill to the text range object.
- @param placeholder the placeholder text to use, if the
- text argument is empty (null or "")
- '''
- def fillMinutesItem(self, Range, text, placeholder):
- paraStyle = Range.ParaStyleName
- Range.setString(text)
- Range.ParaStyleName = paraStyle
- if text is None or text == "":
- if placeholder is not None and not placeholder == "":
- placeHolder = self.createPlaceHolder(
- self.xTextDocument, placeholder,
- self.resources.resPlaceHolderHint)
- try:
- Range.Start.Text.insertTextContent(
- Range.Start, placeHolder, True)
- except Exception:
- traceback.print_exc()
- '''
- creates a placeholder field with the given text and given hint.
- '''
- @classmethod
- def createPlaceHolder(self, xmsf, ph, hint):
- try:
- placeHolder = xmsf.createInstance(
- "com.sun.star.text.TextField.JumpEdit")
- except Exception:
- traceback.print_exc()
- return None
- placeHolder.PlaceHolder = ph
- placeHolder.Hint = hint
- placeHolder.PlaceHolderType = uno.Any("short",TEXT)
- return placeHolder
- def getNamesWhichStartWith(self, allNames, prefix):
- v = []
- for i in allNames:
- if i.startswith(prefix):
- v.append(i)
- return v
- '''
- Convenience method for inserting some cells into a table.
- '''
- @classmethod
- def insertTableRows(self, table, start, count):
- rows = table.Rows
- rows.insertByIndex(start, count)
- '''
- returns the rows count of this table, assuming
- there is no vertical merged cells.
- '''
- @classmethod
- def getRowCount(self, table):
- cells = table.getCellNames()
- return int(cells[len(cells) - 1][1:])
- class ItemsTable(object):
- '''
- the items in the table.
- '''
- items = []
- table = None
- def __init__(self, section, table, agenda):
- self.agenda = agenda
- ItemsTable.table = table
- self.section = section
- self.items = []
- '''
- go through all <*> items in the document
- and each one if it is in this table.
- If they are, register them to belong here, notice their order
- and remove them from the list of all <*> items, so the next
- search will be faster.
- '''
- aux = []
- for item in self.agenda.allItems:
- t = item.TextTable
- if t == ItemsTable.table:
- iText = item.String.lower().lstrip()
- ai = self.agenda.itemsCache[iText]
- if ai is not None:
- self.items.append(ai)
- self.agenda.itemsMap[iText] = self
- else:
- aux.append(item)
- self.agenda.allItems = aux
- '''
- link the section to the template. this will restore the original table
- with all the items.<br/>
- then break the link, to make the section editable.<br/>
- then, starting at cell one, write all items that should be visible.
- then clear the rest and remove obsolete rows.
- If no items are visible, hide the section.
- '''
- def write(self):
- name = self.section.Name
- # link and unlink the section to the template.
- self.agenda.textSectionHandler.linkSectiontoTemplate(
- self.agenda.template, name, self.section)
- self.agenda.textSectionHandler.breakLinkOfTextSection(
- self.section)
- # we need to get an instance after linking
- ItemsTable.table = self.agenda.getTable(name)
- self.section = self.agenda.getSection(name)
- cursor = ItemsTable.table.createCursorByCellName("A1")
- # should this section be visible?
- visible = False
- # write items
- cellName = ""
- '''
- now go through all items that belong to this
- table. Check each one against the model. If it should
- be displayed, call its write method.
- All items are of type AgendaItem which means they write
- two cells to the table: a title (text) and a placeholder.
- see AgendaItem class below.
- '''
- for i in self.items:
- if self.agenda.isShowItem(i.name):
- visible = True
- i.table = ItemsTable.table
- i.write(cursor)
- # I store the cell name which was last written...
- cellName = cursor.RangeName
- cursor.goRight(1, False)
- if visible:
- boolean = True
- else:
- boolean = False
- self.section.IsVisible = boolean
- if not visible:
- return
- '''
- if the cell that was last written is the current cell,
- it means this is the end of the table, so we end here.
- (because after getting the cellName above,
- I call the goRight method.
- If it did not go right, it means it's the last cell.
- '''
- if cellName == cursor.RangeName:
- return
- '''
- if not, we continue and clear all cells until
- we are at the end of the row.
- '''
- while not cellName == cursor.RangeName and \
- not cursor.RangeName.startswith("A"):
- cell = ItemsTable.table.getCellByName(cursor.RangeName)
- cell.String = ""
- cellName = cursor.RangeName
- cursor.goRight(1, False)
- '''
- again: if we are at the end of the table, end here.
- '''
- if cellName == cursor.RangeName:
- return
- '''
- now before deleting i move the cursor up so it
- does not disappear, because it will crash office.
- '''
- cursor.gotoStart(False)
- '''
- This class handles the preview of the topics table.
- You can call it the controller of the topics table.
- It differs from ItemsTable in that it has no data model -
- the update is done programmatically.<br/>
- <br/>
- The decision to make this class a class by its own
- was done out of logic reasons and not design/functionality reasons,
- since there is anyway only one instance of this class at runtime
- it could have also be implemented in the AgendaDocument class
- but for clarity and separation I decided to make a sub class for it.
- '''
- class Topics(object):
- '''Analyze the structure of the Topics table.
- The structure Must be as follows:<br>
- -One Header Row. <br>
- -arbitrary number of rows per topic <br>
- -arbitrary content in the topics row <br>
- -only soft formatting will be restored. <br>
- -the topic rows must repeat three times. <br>
- -in the topics rows, placeholders for number, topic, responsible,
- and duration must be placed.<br><br>
- A word about table format: to reconstruct the format of the table we hold
- to the following formats: first row (header), topic, and last row.
- We hold the format of the last row, because one might wish to give it
- a special format, other than the one on the bottom of each topic.
- The left and right borders of the whole table are, on the other side,
- part of the topics rows format, and need not be preserved separately.
- '''
- table = None
- lastRowFormat = []
- rowsPerTopic = None
- def __init__(self, agenda):
- self.firstRowFormat = []
- self.agenda = agenda
- self.writtenTopics = -1
- try:
- Topics.table = self.agenda.getTable(
- self.agenda.templateConsts.SECTION_TOPICS)
- except Exception:
- traceback.print_exc()
- raise AttributeError (
- "Fatal error while loading template: table " + \
- self.agenda.templateConsts.SECTION_TOPICS + " could not load.")
- '''
- first I store all <*> ranges
- which are in the topics table.
- I store each <*> range in this - the key
- is the cell it is in. Later when analyzing the topic,
- cell by cell, I check in this map to know
- if a cell contains a <*> or not.
- '''
- try:
- items = {}
- for i in self.agenda.allItems:
- t = i.TextTable
- if t == Topics.table:
- cell = i.Cell
- iText = cell.CellName
- items[iText] = i
- '''
- in the topics table, there are always one
- title row and three topics defined.
- So no mutter how many rows a topic takes - we
- can restore its structure and format.
- '''
- rows = self.agenda.getRowCount(Topics.table)
- Topics.rowsPerTopic = int((rows - 1) / 3)
- firstCell = "A" + str(1 + Topics.rowsPerTopic + 1)
- afterLastCell = "A" + str(1 + (Topics.rowsPerTopic * 2) + 1)
- # go to the first row of the 2. topic
- cursor = Topics.table.createCursorByCellName(firstCell)
- # analyze the structure of the topic rows.
- while not cursor.RangeName == afterLastCell:
- cell = Topics.table.getCellByName(cursor.RangeName)
- # first I store the content and para style of the cell
- ae = TextElement(cell, cell.String)
- ae.write()
- # goto next cell.
- cursor.goRight(1, False)
- except Exception:
- traceback.print_exc()
- '''rewrites a single cell containing.
- This is used in order to refresh the topic/responsible/duration data
- in the preview document, in response to a change in the gui (by the user)
- Since the structure of the topics table is flexible,
- The Topics object, which analyzed the structure of the topics table upon
- initialization, refreshes the appropriate cell.
- '''
- def writeCell(self, row, column, data):
- # if the whole row should be written...
- if self.writtenTopics < row:
- self.writtenTopics += 1
- rows = self.agenda.getRowCount(Topics.table)
- reqRows = 1 + (row + 1) * Topics.rowsPerTopic
- firstRow = reqRows - Topics.rowsPerTopic + 1
- diff = reqRows - rows
- if diff > 0:
- # set the item's text...
- self.agenda.insertTableRows(Topics.table, rows, diff)
- column = 0
- cursor = Topics.table.createCursorByCellName("A" + str(firstRow))
- else:
- # calculate the table row.
- firstRow = 1 + (row * Topics.rowsPerTopic) + 1
- cursor = Topics.table.createCursorByCellName("A" + str(firstRow))
- # move the cursor to the needed cell...
- cursor.goRight(column, False)
- xc = Topics.table.getCellByName(cursor.RangeName)
- # and write it !
- te = TextElement(xc, data[column].Value)
- te.write()
- '''removes obsolete rows, reducing the
- topics table to the given number of topics.
- Note this method does only reducing - if
- the number of topics given is greater than the
- number of actual topics it does *not* add
- rows!
- Note also that the first topic will never be removed.
- If the table contains no topics, the whole section will
- be removed upon finishing.
- The reason for that is a "table-design" one: the first topic is
- maintained in order to be able to add rows with a design of this topic,
- and not of the header row.
- @param topics the number of topics the table should contain.
- @throws Exception
- '''
- def reduceDocumentTo(self, topics):
- # we never remove the first topic...
- if topics <= 0:
- topics = 1
- tableRows = Topics.table.Rows
- targetNumOfRows = topics * Topics.rowsPerTopic + 1
- if tableRows.Count > targetNumOfRows:
- tableRows.removeByIndex(
- targetNumOfRows, tableRows.Count - targetNumOfRows)
- '''
- A Text element which, if the text to write is empty (null or "")
- inserts a placeholder instead.
- '''
- class PlaceholderTextElement(TextElement):
- def __init__(self, textRange, placeHolderText_, hint_, xmsf_):
- super(PlaceholderTextElement,self).__init__(textRange, "")
- self.text = placeHolderText_
- self.hint = hint_
- self.xmsf = xmsf_
- self.xTextContentList = []
- def write(self, textRange):
- textRange.String = self.placeHolderText
- if self.placeHolderText is None or self.placeHolderText == "":
- try:
- xTextContent = AgendaDocument.createPlaceHolder(
- self.xmsf, self.text, self.hint)
- self.xTextContentList.append(xTextContent)
- textRange.Text.insertTextContent(
- textRange.Start, xTextContent, True)
- except Exception:
- traceback.print_exc()
- else:
- if self.xTextContentList:
- for i in self.xTextContentList:
- textRange.Text.removeTextContent(i)
- self.xTextContentList = []
- '''
- An Agenda element which writes no text, but inserts a placeholder, and formats
- it using a ParaStyleName.
- '''
- class PlaceholderElement(object):
- def __init__(self, placeHolderText_, hint_, textDocument):
- self.placeHolderText = placeHolderText_
- self.hint = hint_
- self.textDocument = textDocument
- def write(self, textRange):
- try:
- xTextContent = AgendaDocument.createPlaceHolder(
- self.textDocument, self.placeHolderText, self.hint)
- textRange.Text.insertTextContent(
- textRange.Start, xTextContent, True)
- except Exception:
- traceback.print_exc()
- '''
- An implementation of AgendaElement which
- gets as a parameter a table cursor, and writes
- a text to the cell marked by this table cursor, and
- a place holder to the next cell.
- '''
- class AgendaItem(object):
- def __init__(self, name_, te, f):
- self.name = name_
- self.field = f
- self.textElement = te
- def write(self, tableCursor):
- cellname = tableCursor.RangeName
- cell = ItemsTable.table.getCellByName(cellname)
- cell.String = self.textElement
- tableCursor.goRight(1, False)
- # second field is actually always null...
- # this is a preparation for adding placeholders.
- if self.field is not None:
- self.field.write(ItemsTable.table.getCellByName(
- tableCursor.RangeName))
|