summaryrefslogtreecommitdiffstats
path: root/wizards/com/sun/star/wizards/agenda
diff options
context:
space:
mode:
Diffstat (limited to 'wizards/com/sun/star/wizards/agenda')
-rw-r--r--wizards/com/sun/star/wizards/agenda/AgendaDocument.py924
-rw-r--r--wizards/com/sun/star/wizards/agenda/AgendaWizardDialog.py320
-rw-r--r--wizards/com/sun/star/wizards/agenda/AgendaWizardDialogConst.py77
-rw-r--r--wizards/com/sun/star/wizards/agenda/AgendaWizardDialogImpl.py384
-rw-r--r--wizards/com/sun/star/wizards/agenda/AgendaWizardDialogResources.py161
-rw-r--r--wizards/com/sun/star/wizards/agenda/CGAgenda.py46
-rw-r--r--wizards/com/sun/star/wizards/agenda/CGTopic.py60
-rw-r--r--wizards/com/sun/star/wizards/agenda/CallWizard.py75
-rw-r--r--wizards/com/sun/star/wizards/agenda/TemplateConsts.py83
-rw-r--r--wizards/com/sun/star/wizards/agenda/TopicsControl.py857
-rw-r--r--wizards/com/sun/star/wizards/agenda/__init__.py0
-rw-r--r--wizards/com/sun/star/wizards/agenda/agenda.component24
12 files changed, 3011 insertions, 0 deletions
diff --git a/wizards/com/sun/star/wizards/agenda/AgendaDocument.py b/wizards/com/sun/star/wizards/agenda/AgendaDocument.py
new file mode 100644
index 000000000..b96fe44cf
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/AgendaDocument.py
@@ -0,0 +1,924 @@
+#
+# 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 &gt;xxx&lt; 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))
diff --git a/wizards/com/sun/star/wizards/agenda/AgendaWizardDialog.py b/wizards/com/sun/star/wizards/agenda/AgendaWizardDialog.py
new file mode 100644
index 000000000..991b05f04
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/AgendaWizardDialog.py
@@ -0,0 +1,320 @@
+#
+# 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 .
+#
+from ..ui.WizardDialog import WizardDialog, uno, UIConsts, PropertyNames
+from .AgendaWizardDialogConst import AgendaWizardDialogConst, HID
+from .AgendaWizardDialogResources import AgendaWizardDialogResources
+
+from com.sun.star.awt.FontUnderline import SINGLE
+
+class AgendaWizardDialog(WizardDialog):
+
+ def __init__(self, xmsf):
+ super(AgendaWizardDialog,self).__init__(xmsf, HID )
+
+ #Load Resources
+ self.resources = AgendaWizardDialogResources()
+
+ #set dialog properties...
+ self.setDialogProperties(True, 210, True, 200, 52, 1, 1,
+ self.resources.resAgendaWizardDialog_title, 310)
+
+ self.PROPS_LIST = ("Dropdown",
+ PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_HELPURL,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP,
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH)
+ self.PROPS_LABEL_B = ("FontDescriptor",
+ PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_LABEL,
+ PropertyNames.PROPERTY_MULTILINE,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP,
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH)
+ self.PROPS_CHECK = (PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_HELPURL,
+ PropertyNames.PROPERTY_LABEL,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STATE,
+ PropertyNames.PROPERTY_STEP,
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH)
+ self.PROPS_BUTTON = (PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_HELPURL,
+ PropertyNames.PROPERTY_LABEL,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP,
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH)
+ self.PROPS_X = (PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_HELPURL,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP,
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH)
+ self.PROPS_TEXTAREA = (PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_LABEL,
+ PropertyNames.PROPERTY_MULTILINE,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP,
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH)
+ self.PROPS_TEXT = (PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_LABEL,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP,
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH)
+ self.PROPS_IMAGE = ("Border",
+ PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_HELPURL,
+ PropertyNames.PROPERTY_IMAGEURL,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ "ScaleImage", PropertyNames.PROPERTY_STEP,
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH)
+
+ self.fontDescriptor4 = \
+ uno.createUnoStruct('com.sun.star.awt.FontDescriptor')
+ self.fontDescriptor4.Weight = 150
+
+ def buildStep1(self):
+ self.insertLabel("lblTitle1", self.PROPS_LABEL_B,
+ (self.fontDescriptor4, 16, self.resources.reslblTitle1_value,
+ True, 91, 8, 1, 100,212))
+ self.insertLabel("lblPageDesign", self.PROPS_TEXT,
+ (8, self.resources.reslblPageDesign_value, 97, 32, 1, 101, 66))
+ self.listPageDesign = self.insertListBox("listPageDesign",
+ None, AgendaWizardDialogConst.LISTPAGEDESIGN_ACTION_PERFORMED,
+ self.PROPS_LIST,
+ (True, 12, AgendaWizardDialogConst.LISTPAGEDESIGN_HID,
+ 166, 30, 1, 102, 70), self)
+ self.chkMinutes = self.insertCheckBox("chkMinutes", None,
+ self.PROPS_CHECK, (9, AgendaWizardDialogConst.CHKMINUTES_HID,
+ self.resources.reschkMinutes_value, 97, 50, 0, 1, 103, 203), self)
+ self.insertImage("imgHelp1", self.PROPS_IMAGE,
+ (0, 10, "", UIConsts.INFOIMAGEURL, 92, 145, False, 1, 104, 10))
+ self.insertLabel("lblHelp1", self.PROPS_TEXTAREA,
+ (39, self.resources.reslblHelp1_value,
+ True, 104, 145, 1, 105, 199))
+
+ def buildStep2(self):
+ self.insertLabel("lblTitle2", self.PROPS_LABEL_B,
+ (self.fontDescriptor4, 16, self.resources.reslblTitle2_value,
+ True, 91, 8, 2, 200, 212))
+ self.insertLabel("lblDate", self.PROPS_TEXT,
+ (8, self.resources.reslblDate_value, 97, 32, 2, 201,66))
+ self.txtDate = self.insertDateField(
+ "txtDate", AgendaWizardDialogConst.TXTDATE_TEXT_CHANGED,
+ self.PROPS_LIST,
+ (True, 12, AgendaWizardDialogConst.TXTDATE_HID,
+ 166,30, 2, 202, 70), self)
+ self.insertLabel("lblTime", self.PROPS_TEXT,
+ (8, self.resources.reslblTime_value, 97, 50, 2, 203, 66))
+ self.txtTime = self.insertTimeField("txtTime",
+ AgendaWizardDialogConst.TXTTIME_TEXT_CHANGED,
+ (PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_HELPURL,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP,
+ "StrictFormat",
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH),
+ (12, AgendaWizardDialogConst.TXTTIME_HID,
+ 166, 48, 2, True, 204, 70), self)
+ self.insertLabel("lblTitle", self.PROPS_TEXT,
+ (8, self.resources.reslblTitle_value, 97, 68, 2, 205, 66))
+ self.txtTitle = self.insertTextField(
+ "txtTitle", AgendaWizardDialogConst.TXTTITLE_TEXT_CHANGED,
+ (PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_HELPURL,
+ PropertyNames.PROPERTY_MULTILINE,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP,
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH),
+ (26, AgendaWizardDialogConst.TXTTITLE_HID,
+ True, 166, 66, 2, 206, 138), self)
+ self.insertLabel("lblLocation", self.PROPS_TEXT,
+ (8, self.resources.reslblLocation_value, 97, 100, 2, 207, 66))
+ self.cbLocation = self.insertTextField(
+ "cbLocation", AgendaWizardDialogConst.TXTLOCATION_TEXT_CHANGED,
+ (PropertyNames.PROPERTY_HEIGHT,
+ PropertyNames.PROPERTY_HELPURL,
+ PropertyNames.PROPERTY_MULTILINE,
+ PropertyNames.PROPERTY_POSITION_X,
+ PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP,
+ PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH),
+ (34, AgendaWizardDialogConst.CBLOCATION_HID,
+ True, 166,98, 2, 208, 138), self)
+ self.insertImage("imgHelp2", self.PROPS_IMAGE,
+ (0, 10, "", UIConsts.INFOIMAGEURL, 92, 145, False, 2, 209, 10))
+ self.insertLabel("lblHelp2", self.PROPS_TEXTAREA,
+ (39, self.resources.reslblHelp2_value,
+ True, 104, 145, 2, 210, 199))
+
+ def buildStep3(self):
+ self.insertLabel("lblTitle3", self.PROPS_LABEL_B,
+ (self.fontDescriptor4, 16, self.resources.reslblTitle3_value,
+ True, 91, 8, 3, 300,212))
+ self.chkMeetingTitle = self.insertCheckBox("chkMeetingTitle",
+ AgendaWizardDialogConst.CHKUSEMEETINGTYPE_ITEM_CHANGED,
+ self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKMEETINGTITLE_HID,
+ self.resources.reschkMeetingTitle_value,
+ 97, 32, 1, 3, 301, 69), self)
+ self.chkRead = self.insertCheckBox("chkRead",
+ AgendaWizardDialogConst.CHKUSEREAD_ITEM_CHANGED, self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKREAD_HID,
+ self.resources.reschkRead_value, 97, 46, 0, 3, 302, 162), self)
+ self.chkBring = self.insertCheckBox("chkBring",
+ AgendaWizardDialogConst.CHKUSEBRING_ITEM_CHANGED, self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKBRING_HID,
+ self.resources.reschkBring_value,
+ 97, 60, 0, 3, 303, 162), self)
+ self.chkNotes = self.insertCheckBox("chkNotes",
+ AgendaWizardDialogConst.CHKUSENOTES_ITEM_CHANGED, self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKNOTES_HID,
+ self.resources.reschkNotes_value,
+ 97, 74, 1, 3, 304, 160), self)
+ self.insertImage("imgHelp3", self.PROPS_IMAGE, (0, 10,
+ "", UIConsts.INFOIMAGEURL, 92, 145, False, 3, 305, 10))
+ self.insertLabel("lblHelp3", self.PROPS_TEXTAREA,
+ (39, self.resources.reslblHelp3_value, True,104, 145, 3, 306, 199))
+
+ def buildStep4(self):
+ self.insertLabel("lblTitle5", self.PROPS_LABEL_B,
+ (self.fontDescriptor4, 16, self.resources.reslblTitle5_value,
+ True, 91, 8, 4, 400, 212))
+ self.chkConvenedBy = self.insertCheckBox("chkConvenedBy",
+ AgendaWizardDialogConst.CHKUSECALLEDBYNAME_ITEM_CHANGED,
+ self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKCONVENEDBY_HID,
+ self.resources.reschkConvenedBy_value,
+ 97, 32, 1, 4, 401, 150), self)
+ self.chkPresiding = self.insertCheckBox("chkPresiding",
+ AgendaWizardDialogConst.CHKUSEFACILITATOR_ITEM_CHANGED,
+ self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKPRESIDING_HID,
+ self.resources.reschkPresiding_value,
+ 97, 46, 0, 4, 402, 150), self)
+ self.chkNoteTaker = self.insertCheckBox("chkNoteTaker",
+ AgendaWizardDialogConst.CHKUSENOTETAKER_ITEM_CHANGED,
+ self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKNOTETAKER_HID,
+ self.resources.reschkNoteTaker_value,
+ 97, 60, 0, 4, 403, 150), self)
+ self.chkTimekeeper = self.insertCheckBox("chkTimekeeper",
+ AgendaWizardDialogConst.CHKUSETIMEKEEPER_ITEM_CHANGED,
+ self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKTIMEKEEPER_HID,
+ self.resources.reschkTimekeeper_value,
+ 97, 74, 0, 4, 404, 150), self)
+ self.chkAttendees = self.insertCheckBox("chkAttendees",
+ AgendaWizardDialogConst.CHKUSEATTENDEES_ITEM_CHANGED,
+ self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKATTENDEES_HID,
+ self.resources.reschkAttendees_value,
+ 97, 88, 1, 4, 405, 150), self)
+ self.chkObservers = self.insertCheckBox("chkObservers",
+ AgendaWizardDialogConst.CHKUSEOBSERVERS_ITEM_CHANGED,
+ self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKOBSERVERS_HID,
+ self.resources.reschkObservers_value,
+ 97, 102, 0, 4, 406, 150), self)
+ self.chkResourcePersons = self.insertCheckBox("chkResourcePersons",
+ AgendaWizardDialogConst.CHKUSERESOURCEPERSONS_ITEM_CHANGED,
+ self.PROPS_CHECK,
+ (8, AgendaWizardDialogConst.CHKRESOURCEPERSONS_HID,
+ self.resources.reschkResourcePersons_value,
+ 97, 116, 0, 4, 407, 150), self)
+ self.insertImage("imgHelp4", self.PROPS_IMAGE,
+ (0, 10, "", UIConsts.INFOIMAGEURL,
+ 92, 145, False, 4, 408, 10))
+ self.insertLabel("lblHelp4", self.PROPS_TEXTAREA,
+ (39, self.resources.reslblHelp4_value, True, 104, 145, 4, 409, 199))
+
+ def buildStep5(self):
+ self.insertLabel("lblTitle4", self.PROPS_LABEL_B,
+ (self.fontDescriptor4, 16, self.resources.reslblTitle4_value,
+ True, 91, 8, 5, 500, 212))
+ self.insertLabel("lblTopic", self.PROPS_TEXT,
+ (8, self.resources.reslblTopic_value, 107, 28, 5, 71, 501))
+ self.insertLabel("lblResponsible", self.PROPS_TEXT,
+ (8, self.resources.reslblResponsible_value, 195, 28, 5, 72, 502))
+ self.insertLabel("lblDuration", self.PROPS_TEXT,
+ (8, self.resources.reslblDuration_value, 267, 28, 5, 73, 503))
+ self.btnInsert = self.insertButton("btnInsert",
+ AgendaWizardDialogConst.BTNINSERT_ACTION_PERFORMED,
+ self.PROPS_BUTTON, (14, AgendaWizardDialogConst.BTNINSERT_HID,
+ self.resources.resButtonInsert, 92, 136, 5, 580, 40), self)
+ self.btnRemove = self.insertButton("btnRemove",
+ AgendaWizardDialogConst.BTNREMOVE_ACTION_PERFORMED,
+ self.PROPS_BUTTON, (14, AgendaWizardDialogConst.BTNREMOVE_HID,
+ self.resources.resButtonRemove, 134, 136, 5, 581, 40), self)
+ self.btnUp = self.insertButton("btnUp",
+ AgendaWizardDialogConst.BTNUP_ACTION_PERFORMED,
+ self.PROPS_BUTTON, (14, AgendaWizardDialogConst.BTNUP_HID,
+ self.resources.resButtonUp, 180, 136, 5, 582, 60), self)
+ self.btnDown = self.insertButton("btnDown",
+ AgendaWizardDialogConst.BTNDOWN_ACTION_PERFORMED,
+ self.PROPS_BUTTON, (14, AgendaWizardDialogConst.BTNDOWN_HID,
+ self.resources.resButtonDown, 244, 136, 5, 583, 60), self)
+
+ def buildStep6(self):
+ self.insertLabel("lblTitle6", self.PROPS_LABEL_B,
+ (self.fontDescriptor4, 16, self.resources.reslblTitle6_value,
+ True, 91, 8, 6, 600, 212))
+ self.insertLabel("lblHelpPg6", self.PROPS_TEXTAREA,
+ (24, self.resources.reslblHelpPg6_value, True,
+ 97, 32, 6, 601,204))
+ self.insertLabel("lblTemplateName", self.PROPS_TEXT,
+ (8, self.resources.reslblTemplateName_value,
+ 97, 62, 6, 602, 101))
+ self.txtTemplateName = self.insertTextField("txtTemplateName",
+ None, self.PROPS_X,
+ (12, AgendaWizardDialogConst.TXTTEMPLATENAME_HID,
+ 202, 60, 6, 603, 100), self)
+ self.insertLabel("lblProceed", self.PROPS_TEXT,
+ (8, self.resources.reslblProceed_value, 97, 101, 6, 607,204))
+ self.optCreateAgenda = self.insertRadioButton("optCreateAgenda", None,
+ self.PROPS_CHECK, (8, AgendaWizardDialogConst.OPTCREATEAGENDA_HID,
+ self.resources.resoptCreateAgenda_value,
+ 103, 113, 1, 6, 608, 198), self)
+ self.optMakeChanges = self.insertRadioButton("optMakeChanges", None,
+ self.PROPS_BUTTON, (8, AgendaWizardDialogConst.OPTMAKECHANGES_HID,
+ self.resources.resoptMakeChanges_value,
+ 103, 125, 6, 609, 198), self)
+ self.insertImage("imgHelp6", self.PROPS_IMAGE, (0, 10, "",
+ UIConsts.INFOIMAGEURL, 92, 145, False, 6, 610, 10))
+ self.insertLabel("lblHelp6", self.PROPS_TEXTAREA,
+ (39, self.resources.reslblHelp6_value, True, 104, 145, 6, 611, 199))
diff --git a/wizards/com/sun/star/wizards/agenda/AgendaWizardDialogConst.py b/wizards/com/sun/star/wizards/agenda/AgendaWizardDialogConst.py
new file mode 100644
index 000000000..e4370a416
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/AgendaWizardDialogConst.py
@@ -0,0 +1,77 @@
+#
+# 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 .
+#
+from ..common.HelpIds import HelpIds
+
+HID = 41051
+
+class AgendaWizardDialogConst:
+
+ TXTTITLE_TEXT_CHANGED = "txtTitleTextChanged"
+ TXTDATE_TEXT_CHANGED = "txtDateTextChanged"
+ TXTTIME_TEXT_CHANGED = "txtTimeTextChanged"
+ TXTLOCATION_TEXT_CHANGED = "txtLocationTextChanged"
+ CHKMINUTES_ITEM_CHANGED = "chkMinutesItemChanged"
+ CHKUSEMEETINGTYPE_ITEM_CHANGED = "chkUseMeetingTypeItemChanged"
+ CHKUSEREAD_ITEM_CHANGED = "chkUseReadItemChanged"
+ CHKUSEBRING_ITEM_CHANGED = "chkUseBringItemChanged"
+ CHKUSENOTES_ITEM_CHANGED = "chkUseNotesItemChanged"
+ CHKUSECALLEDBYNAME_ITEM_CHANGED = "chkUseCalledByItemChanged"
+ CHKUSEFACILITATOR_ITEM_CHANGED = "chkUseFacilitatorItemChanged"
+ CHKUSENOTETAKER_ITEM_CHANGED = "chkUseNoteTakerItemChanged"
+ CHKUSETIMEKEEPER_ITEM_CHANGED = "chkUseTimeKeeperItemChanged"
+ CHKUSEATTENDEES_ITEM_CHANGED = "chkUseAttendeesItemChanged"
+ CHKUSEOBSERVERS_ITEM_CHANGED = "chkUseObserversItemChanged"
+ CHKUSERESOURCEPERSONS_ITEM_CHANGED = "chkUseResourcePersonsItemChanged"
+ LISTPAGEDESIGN_ACTION_PERFORMED = "pageDesignChanged"
+ BTNTEMPLATEPATH_ACTION_PERFORMED = "saveAs"
+ BTNINSERT_ACTION_PERFORMED = "insertRow"
+ BTNREMOVE_ACTION_PERFORMED = "removeRow"
+ BTNUP_ACTION_PERFORMED = "rowUp"
+ BTNDOWN_ACTION_PERFORMED = "rowDown"
+
+ LISTPAGEDESIGN_HID = HelpIds.getHelpIdString(HID + 6)
+ CHKMINUTES_HID = HelpIds.getHelpIdString(HID + 7)
+ TXTTIME_HID = HelpIds.getHelpIdString(HID + 8)
+ TXTDATE_HID = HelpIds.getHelpIdString(HID + 9)
+ TXTTITLE_HID = HelpIds.getHelpIdString(HID + 10)
+ CBLOCATION_HID = HelpIds.getHelpIdString(HID + 11)
+
+ CHKMEETINGTITLE_HID = HelpIds.getHelpIdString(HID + 12)
+ CHKREAD_HID = HelpIds.getHelpIdString(HID + 13)
+ CHKBRING_HID = HelpIds.getHelpIdString(HID + 14)
+ CHKNOTES_HID = HelpIds.getHelpIdString(HID + 15)
+
+ CHKCONVENEDBY_HID = HelpIds.getHelpIdString(HID + 16)
+ CHKPRESIDING_HID = HelpIds.getHelpIdString(HID + 17)
+ CHKNOTETAKER_HID = HelpIds.getHelpIdString(HID + 18)
+ CHKTIMEKEEPER_HID = HelpIds.getHelpIdString(HID + 19)
+ CHKATTENDEES_HID = HelpIds.getHelpIdString(HID + 20)
+ CHKOBSERVERS_HID = HelpIds.getHelpIdString(HID + 21)
+ CHKRESOURCEPERSONS_HID = HelpIds.getHelpIdString(HID + 22)
+
+ TXTTEMPLATENAME_HID = HelpIds.getHelpIdString(HID + 23)
+ TXTTEMPLATEPATH_HID = HelpIds.getHelpIdString(HID + 24)
+ BTNTEMPLATEPATH_HID = HelpIds.getHelpIdString(HID + 25)
+
+ OPTCREATEAGENDA_HID = HelpIds.getHelpIdString(HID + 26)
+ OPTMAKECHANGES_HID = HelpIds.getHelpIdString(HID + 27)
+
+ BTNINSERT_HID = HelpIds.getHelpIdString(HID + 28)
+ BTNREMOVE_HID = HelpIds.getHelpIdString(HID + 29)
+ BTNUP_HID = HelpIds.getHelpIdString(HID + 30)
+ BTNDOWN_HID = HelpIds.getHelpIdString(HID + 31)
diff --git a/wizards/com/sun/star/wizards/agenda/AgendaWizardDialogImpl.py b/wizards/com/sun/star/wizards/agenda/AgendaWizardDialogImpl.py
new file mode 100644
index 000000000..372dad055
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/AgendaWizardDialogImpl.py
@@ -0,0 +1,384 @@
+#
+# 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 traceback
+import os.path
+from .AgendaWizardDialog import AgendaWizardDialog, uno
+from .AgendaWizardDialogConst import HID
+from .AgendaDocument import AgendaDocument, TextElement
+from .TemplateConsts import TemplateConsts
+from .TopicsControl import TopicsControl
+from .CGAgenda import CGAgenda
+from ..ui.PathSelection import PathSelection
+from ..ui.event.UnoDataAware import UnoDataAware
+from ..ui.event.RadioDataAware import RadioDataAware
+from ..ui.event.CommonListener import TerminateListenerProcAdapter
+from ..common.NoValidPathException import NoValidPathException
+from ..common.SystemDialog import SystemDialog
+from ..common.Desktop import Desktop
+from ..common.HelpIds import HelpIds
+from ..common.Configuration import Configuration
+from ..common.FileAccess import FileAccess
+from ..document.OfficeDocument import OfficeDocument
+
+from com.sun.star.util import CloseVetoException
+from com.sun.star.view.DocumentZoomType import OPTIMAL
+from com.sun.star.awt.VclWindowPeerAttribute import YES_NO, DEF_NO
+
+class AgendaWizardDialogImpl(AgendaWizardDialog):
+
+ def __init__(self, xmsf):
+ super(AgendaWizardDialogImpl, self).__init__(xmsf)
+ self.filenameChanged = False
+ self.pageDesign = -1
+
+ def enterStep(self, OldStep, NewStep):
+ pass
+
+ def leaveStep(self, OldStep, NewStep):
+ pass
+
+ def startWizard(self, xMSF):
+ self.running = True
+ try:
+ #Number of steps on WizardDialog
+ self.nMaxStep = 6
+
+ self.agenda = CGAgenda()
+
+ # read configuration data before we initialize the topics
+ root = Configuration.getConfigurationRoot(
+ self.xMSF, "/org.openoffice.Office.Writer/Wizards/Agenda",
+ False)
+ self.agenda.readConfiguration(root, "cp_")
+
+ self.templateConsts = TemplateConsts
+
+ self.initializePaths()
+ # initialize the agenda template
+ self.terminateListener = TerminateListenerProcAdapter(self.queryTermination)
+ self.myAgendaDoc = AgendaDocument(
+ self.xMSF, self.agenda, self.resources,
+ self.templateConsts, self.terminateListener)
+ self.initializeTemplates()
+
+ self.myAgendaDoc.load(
+ self.agendaTemplates[1][self.agenda.cp_AgendaType])
+ self.drawConstants()
+
+ # build the dialog.
+ self.drawNaviBar()
+
+ self.buildStep1()
+ self.buildStep2()
+ self.buildStep3()
+ self.buildStep4()
+ self.buildStep5()
+ self.buildStep6()
+
+ self.topicsControl = TopicsControl(self, self.xMSF, self.agenda)
+
+ #special Control for setting the save Path:
+ self.insertPathSelectionControl()
+
+ # synchronize GUI and CGAgenda object.
+ self.initConfiguration()
+
+ if self.myPathSelection.xSaveTextBox.Text.lower() == "":
+ self.myPathSelection.initializePath()
+
+ # create the peer
+ xContainerWindow = self.myAgendaDoc.xFrame.ContainerWindow
+ self.createWindowPeer(xContainerWindow)
+
+ # initialize roadmap
+ self.insertRoadmap()
+
+ self.executeDialogFromComponent(self.myAgendaDoc.xFrame)
+ self.removeTerminateListener()
+ self.closeDocument()
+ self.running = False
+ except Exception:
+ self.removeTerminateListener()
+ traceback.print_exc()
+ self.running = False
+ return
+
+ def insertPathSelectionControl(self):
+ self.myPathSelection = PathSelection(
+ self.xMSF, self, PathSelection.TransferMode.SAVE,
+ PathSelection.DialogTypes.FILE)
+ self.myPathSelection.insert(6, 97, 70, 205, 45,
+ self.resources.reslblTemplatePath_value, True,
+ HelpIds.getHelpIdString(HID + 24),
+ HelpIds.getHelpIdString(HID + 25))
+ self.myPathSelection.sDefaultDirectory = self.sUserTemplatePath
+ self.myPathSelection.sDefaultName = "myAgendaTemplate.ott"
+ self.myPathSelection.sDefaultFilter = "writer8_template"
+ self.myPathSelection.addSelectionListener(self)
+
+ '''
+ bind controls to the agenda member (DataAware model)
+ '''
+
+ def initConfiguration(self):
+ self.xDialogModel.listPageDesign.StringItemList = \
+ tuple(self.agendaTemplates[0])
+ UnoDataAware.attachListBox(
+ self.agenda, "cp_AgendaType", self.listPageDesign, True).updateUI()
+ self.pageDesign = self.agenda.cp_AgendaType
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_IncludeMinutes", self.chkMinutes, True).updateUI()
+ UnoDataAware.attachEditControl(
+ self.agenda, "cp_Title", self.txtTitle, True).updateUI()
+ UnoDataAware.attachDateControl(
+ self.agenda, "cp_Date", self.txtDate, True).updateUI()
+ UnoDataAware.attachTimeControl(
+ self.agenda, "cp_Time", self.txtTime, True).updateUI()
+ UnoDataAware.attachEditControl(
+ self.agenda, "cp_Location", self.cbLocation, True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowMeetingType", self.chkMeetingTitle,
+ True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowRead", self.chkRead, True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowBring", self.chkBring, True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowNotes", self.chkNotes, True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowCalledBy", self.chkConvenedBy,
+ True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowFacilitator", self.chkPresiding,
+ True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowNotetaker", self.chkNoteTaker,
+ True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowTimekeeper", self.chkTimekeeper,
+ True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowAttendees", self.chkAttendees,
+ True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowObservers", self.chkObservers,
+ True).updateUI()
+ UnoDataAware.attachCheckBox(
+ self.agenda, "cp_ShowResourcePersons",self.chkResourcePersons,
+ True).updateUI()
+ UnoDataAware.attachEditControl(
+ self.agenda, "cp_TemplateName", self.txtTemplateName,
+ True).updateUI()
+ RadioDataAware.attachRadioButtons(
+ self.agenda, "cp_ProceedMethod",
+ (self.optCreateAgenda, self.optMakeChanges), True).updateUI()
+
+ def insertRoadmap(self):
+ self.addRoadmap()
+ self.insertRoadMapItems(
+ self.resources.RoadmapLabels, [True, True, True, True, True, True])
+ self.setRoadmapInteractive(True)
+ self.setRoadmapComplete(True)
+ self.setCurrentRoadmapItemID(1)
+
+ '''
+ read the available agenda wizard templates.
+ '''
+
+ def initializeTemplates(self):
+ try:
+ sAgendaPath = self.sTemplatePath + "/wizard/agenda"
+ self.agendaTemplates = FileAccess.getFolderTitles(
+ self.xMSF, "aw", sAgendaPath, self.resources.dictPageDesign)
+ return True
+ except NoValidPathException:
+ traceback.print_exc()
+ return False
+
+ '''
+ first page, page design listbox changed.
+ '''
+
+ def pageDesignChanged(self):
+ try:
+ SelectedItemPos = self.listPageDesign.SelectedItemPos
+ #avoid to load the same item again
+ if self.pageDesign is not SelectedItemPos:
+ self.pageDesign = SelectedItemPos
+ self.myAgendaDoc.load(
+ self.agendaTemplates[1][SelectedItemPos])
+ self.drawConstants()
+ except Exception:
+ traceback.print_exc()
+
+ #textFields listeners
+ def txtTitleTextChanged(self):
+ self.myAgendaDoc.redrawTitle("txtTitle")
+
+ def txtDateTextChanged(self):
+ self.myAgendaDoc.redrawTitle("txtDate")
+
+ def txtTimeTextChanged(self):
+ self.myAgendaDoc.redrawTitle("txtTime")
+
+ def txtLocationTextChanged(self):
+ self.myAgendaDoc.redrawTitle("cbLocation")
+
+ #checkbox listeners
+ def chkUseMeetingTypeItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_MEETING_TYPE)
+
+ def chkUseReadItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_READ)
+
+ def chkUseBringItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_BRING)
+
+ def chkUseNotesItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_NOTES)
+
+ def chkUseCalledByItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_CALLED_BY)
+
+ def chkUseFacilitatorItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_FACILITATOR)
+
+ def chkUseNoteTakerItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_NOTETAKER)
+
+ def chkUseTimeKeeperItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_TIMEKEEPER)
+
+ def chkUseAttendeesItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_PARTICIPANTS)
+
+ def chkUseObserversItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_OBSERVERS)
+
+ def chkUseResourcePersonsItemChanged(self):
+ self.myAgendaDoc.redraw(self.templateConsts.FILLIN_RESOURCE_PERSONS)
+
+ def insertRow(self):
+ self.topicsControl.insertRow()
+
+ def removeRow(self):
+ self.topicsControl.removeRow()
+
+ def rowUp(self):
+ self.topicsControl.rowUp()
+
+ def rowDown(self):
+ self.topicsControl.rowDown()
+
+ def cancelWizard(self):
+ self.xUnoDialog.endExecute()
+ self.running = False
+
+ def finishWizard(self):
+ self.switchToStep(self.getCurrentStep(), self.nMaxStep)
+ bSaveSuccess = False
+ endWizard = True
+ try:
+ self.sPath = self.myPathSelection.getSelectedPath()
+ if not self.sPath or not os.path.exists(self.sPath):
+ self.myPathSelection.triggerPathPicker()
+ self.sPath = self.myPathSelection.getSelectedPath()
+
+ #first, if the filename was not changed, thus
+ #it is coming from a saved session, check if the
+ # file exists and warn the user.
+ if not self.filenameChanged:
+ answer = SystemDialog.showMessageBox(
+ self.xMSF, "MessBox", YES_NO + DEF_NO,
+ self.resources.resOverwriteWarning,
+ self.xUnoDialog.Peer)
+ if answer == 3:
+ # user said: no, do not overwrite
+ endWizard = False
+ return False
+
+ xDocProps = self.myAgendaDoc.xTextDocument.DocumentProperties
+ xDocProps.Title = self.txtTemplateName.Text
+ self.myAgendaDoc.setWizardTemplateDocInfo( \
+ self.resources.resAgendaWizardDialog_title,
+ self.resources.resTemplateDescription)
+ bSaveSuccess = OfficeDocument.store(
+ self.xMSF, self.myAgendaDoc.xTextDocument, self.sPath,
+ "writer8_template")
+
+ if bSaveSuccess:
+ self.topicsControl.saveTopics(self.agenda)
+ root = Configuration.getConfigurationRoot(
+ self.xMSF, "/org.openoffice.Office.Writer/Wizards/Agenda",
+ True)
+ self.agenda.writeConfiguration(root, "cp_")
+ root.commitChanges()
+
+ self.myAgendaDoc.finish(self.topicsControl.scrollfields)
+
+ loadValues = list(range(2))
+ loadValues[0] = uno.createUnoStruct( \
+ 'com.sun.star.beans.PropertyValue')
+ loadValues[0].Name = "AsTemplate"
+ if self.agenda.cp_ProceedMethod == 1:
+ loadValues[0].Value = True
+ else:
+ loadValues[0].Value = False
+
+ loadValues[1] = uno.createUnoStruct( \
+ 'com.sun.star.beans.PropertyValue')
+ loadValues[1].Name = "InteractionHandler"
+
+ xIH = self.xMSF.createInstance(
+ "com.sun.star.comp.uui.UUIInteractionHandler")
+ loadValues[1].Value = xIH
+
+ oDoc = OfficeDocument.load(
+ Desktop.getDesktop(self.xMSF),
+ self.sPath, "_default", loadValues)
+ oDoc.CurrentController.ViewSettings.ZoomType = OPTIMAL
+ else:
+ pass
+
+ except Exception:
+ traceback.print_exc()
+ finally:
+ if endWizard:
+ self.xUnoDialog.endExecute()
+ self.running = False
+ return True
+
+ def closeDocument(self):
+ try:
+ self.myAgendaDoc.xFrame.close(False)
+ except CloseVetoException:
+ traceback.print_exc()
+
+ def drawConstants(self):
+ '''Localise the template'''
+ constRangeList = self.myAgendaDoc.searchFillInItems(1)
+
+ for i in constRangeList:
+ text = i.String.lower()
+ aux = TextElement(i, self.resources.dictConstants[text])
+ aux.write()
+
+ def validatePath(self):
+ if self.myPathSelection.usedPathPicker:
+ self.filenameChanged = True
+ self.myPathSelection.usedPathPicker = False
diff --git a/wizards/com/sun/star/wizards/agenda/AgendaWizardDialogResources.py b/wizards/com/sun/star/wizards/agenda/AgendaWizardDialogResources.py
new file mode 100644
index 000000000..9d42e6317
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/AgendaWizardDialogResources.py
@@ -0,0 +1,161 @@
+#
+# 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 .
+#
+
+class AgendaWizardDialogResources(object):
+
+ SECTION_ITEMS = "AGENDA_ITEMS"
+ SECTION_TOPICS = "AGENDA_TOPICS"
+ SECTION_MINUTES_ALL = "MINUTES_ALL"
+ SECTION_MINUTES = "MINUTES"
+
+ def __init__(self):
+ import sys, os
+
+ if sys.version_info < (3,4):
+ import imp
+ imp.load_source('strings', os.path.join(os.path.dirname(__file__), '../common/strings.hrc'))
+ import strings
+ elif sys.version_info < (3,7):
+ # imp is deprecated since Python v.3.4
+ from importlib.machinery import SourceFileLoader
+ SourceFileLoader('strings', os.path.join(os.path.dirname(__file__), '../common/strings.hrc')).load_module()
+ import strings
+ else:
+ # have to jump through hoops since 3.7, partly because python does not like loading modules that do have a .py extension
+ import importlib
+ import importlib.util
+ import importlib.machinery
+ module_name = 'strings'
+ path = os.path.join(os.path.dirname(__file__), '../common/strings.hrc')
+ spec = importlib.util.spec_from_loader(
+ module_name,
+ importlib.machinery.SourceFileLoader(module_name, path)
+ )
+ module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(module)
+ sys.modules[module_name] = module
+ strings = module
+
+
+ self.resAgendaWizardDialog_title = strings.RID_AGENDAWIZARDDIALOG_START_1
+ self.resoptMakeChanges_value = strings.RID_AGENDAWIZARDDIALOG_START_2
+ self.reslblTemplateName_value = strings.RID_AGENDAWIZARDDIALOG_START_3
+ self.reslblTemplatePath_value = strings.RID_AGENDAWIZARDDIALOG_START_4
+ self.reslblProceed_value = strings.RID_AGENDAWIZARDDIALOG_START_5
+ self.reslblTitle1_value = strings.RID_AGENDAWIZARDDIALOG_START_6
+ self.reslblTitle3_value = strings.RID_AGENDAWIZARDDIALOG_START_7
+ self.reslblTitle2_value = strings.RID_AGENDAWIZARDDIALOG_START_8
+ self.reslblTitle4_value = strings.RID_AGENDAWIZARDDIALOG_START_9
+ self.reslblTitle5_value = strings.RID_AGENDAWIZARDDIALOG_START_10
+ self.reslblTitle6_value = strings.RID_AGENDAWIZARDDIALOG_START_11
+ self.reschkMinutes_value = strings.RID_AGENDAWIZARDDIALOG_START_12
+ self.reslblHelp1_value = strings.RID_AGENDAWIZARDDIALOG_START_13
+ self.reslblTime_value = strings.RID_AGENDAWIZARDDIALOG_START_14
+ self.reslblTitle_value = strings.RID_AGENDAWIZARDDIALOG_START_15
+ self.reslblLocation_value = strings.RID_AGENDAWIZARDDIALOG_START_16
+ self.reslblHelp2_value = strings.RID_AGENDAWIZARDDIALOG_START_17
+ self.resbtnTemplatePath_value = strings.RID_AGENDAWIZARDDIALOG_START_18
+ self.resoptCreateAgenda_value = strings.RID_AGENDAWIZARDDIALOG_START_19
+ self.reslblHelp6_value = strings.RID_AGENDAWIZARDDIALOG_START_20
+ self.reslblTopic_value = strings.RID_AGENDAWIZARDDIALOG_START_21
+ self.reslblResponsible_value = strings.RID_AGENDAWIZARDDIALOG_START_22
+ self.reslblDuration_value = strings.RID_AGENDAWIZARDDIALOG_START_23
+ self.reschkConvenedBy_value = strings.RID_AGENDAWIZARDDIALOG_START_24
+ self.reschkPresiding_value = strings.RID_AGENDAWIZARDDIALOG_START_25
+ self.reschkNoteTaker_value = strings.RID_AGENDAWIZARDDIALOG_START_26
+ self.reschkTimekeeper_value = strings.RID_AGENDAWIZARDDIALOG_START_27
+ self.reschkAttendees_value = strings.RID_AGENDAWIZARDDIALOG_START_28
+ self.reschkObservers_value = strings.RID_AGENDAWIZARDDIALOG_START_29
+ self.reschkResourcePersons_value = strings.RID_AGENDAWIZARDDIALOG_START_30
+ self.reslblHelp4_value = strings.RID_AGENDAWIZARDDIALOG_START_31
+ self.reschkMeetingTitle_value = strings.RID_AGENDAWIZARDDIALOG_START_32
+ self.reschkRead_value = strings.RID_AGENDAWIZARDDIALOG_START_33
+ self.reschkBring_value = strings.RID_AGENDAWIZARDDIALOG_START_34
+ self.reschkNotes_value = strings.RID_AGENDAWIZARDDIALOG_START_35
+ self.reslblHelp3_value = strings.RID_AGENDAWIZARDDIALOG_START_36
+ self.reslblDate_value = strings.RID_AGENDAWIZARDDIALOG_START_38
+ self.reslblHelpPg6_value = strings.RID_AGENDAWIZARDDIALOG_START_39
+ self.reslblPageDesign_value = strings.RID_AGENDAWIZARDDIALOG_START_40
+ self.resDefaultFilename = strings.RID_AGENDAWIZARDDIALOG_START_41
+ self.resDefaultFilename = self.resDefaultFilename[:-4] + ".ott"
+ self.resDefaultTitle = strings.RID_AGENDAWIZARDDIALOG_START_42
+ self.resErrSaveTemplate = strings.RID_AGENDAWIZARDDIALOG_START_43
+ self.resPlaceHolderTitle = strings.RID_AGENDAWIZARDDIALOG_START_44
+ self.resPlaceHolderDate = strings.RID_AGENDAWIZARDDIALOG_START_45
+ self.resPlaceHolderTime = strings.RID_AGENDAWIZARDDIALOG_START_46
+ self.resPlaceHolderLocation = strings.RID_AGENDAWIZARDDIALOG_START_47
+ self.resPlaceHolderHint = strings.RID_AGENDAWIZARDDIALOG_START_48
+ self.resErrOpenTemplate = strings.RID_AGENDAWIZARDDIALOG_START_56
+ self.itemMeetingType = strings.RID_AGENDAWIZARDDIALOG_START_57
+ self.itemBring = strings.RID_AGENDAWIZARDDIALOG_START_58
+ self.itemRead = strings.RID_AGENDAWIZARDDIALOG_START_59
+ self.itemNote = strings.RID_AGENDAWIZARDDIALOG_START_60
+ self.itemCalledBy = strings.RID_AGENDAWIZARDDIALOG_START_61
+ self.itemFacilitator = strings.RID_AGENDAWIZARDDIALOG_START_62
+ self.itemAttendees = strings.RID_AGENDAWIZARDDIALOG_START_63
+ self.itemNotetaker = strings.RID_AGENDAWIZARDDIALOG_START_64
+ self.itemTimekeeper = strings.RID_AGENDAWIZARDDIALOG_START_65
+ self.itemObservers = strings.RID_AGENDAWIZARDDIALOG_START_66
+ self.itemResource = strings.RID_AGENDAWIZARDDIALOG_START_67
+ self.resButtonInsert = strings.RID_AGENDAWIZARDDIALOG_START_68
+ self.resButtonRemove = strings.RID_AGENDAWIZARDDIALOG_START_69
+ self.resButtonUp = strings.RID_AGENDAWIZARDDIALOG_START_70
+ self.resButtonDown = strings.RID_AGENDAWIZARDDIALOG_START_71
+
+ #Create a dictionary for localised string in the template
+ self.dictConstants = {
+ "#datetitle#" : strings.RID_AGENDAWIZARDDIALOG_START_72,
+ "#timetitle#" : strings.RID_AGENDAWIZARDDIALOG_START_73,
+ "#locationtitle#" : strings.RID_AGENDAWIZARDDIALOG_START_74,
+ "#topics#" : strings.RID_AGENDAWIZARDDIALOG_START_75,
+ "#num.#" : strings.RID_AGENDAWIZARDDIALOG_START_76,
+ "#topicheader#" : strings.RID_AGENDAWIZARDDIALOG_START_77,
+ "#responsibleheader#" : strings.RID_AGENDAWIZARDDIALOG_START_78,
+ "#timeheader#" : strings.RID_AGENDAWIZARDDIALOG_START_79,
+ "#additional-information#" : strings.RID_AGENDAWIZARDDIALOG_START_80,
+ "#minutes-for#" : strings.RID_AGENDAWIZARDDIALOG_START_81,
+ "#discussion#" : strings.RID_AGENDAWIZARDDIALOG_START_82,
+ "#conclusion#" : strings.RID_AGENDAWIZARDDIALOG_START_83,
+ "#to-do#" : strings.RID_AGENDAWIZARDDIALOG_START_84,
+ "#responsible-party#" : strings.RID_AGENDAWIZARDDIALOG_START_85,
+ "#deadline#" : strings.RID_AGENDAWIZARDDIALOG_START_86}
+
+ #Create a dictionary for localising the page design
+ self.dictPageDesign = {
+ "Blue" : strings.RID_AGENDAWIZARDDIALOG_START_87,
+ "Classic" : strings.RID_AGENDAWIZARDDIALOG_START_88,
+ "Colorful" : strings.RID_AGENDAWIZARDDIALOG_START_89,
+ "Elegant" : strings.RID_AGENDAWIZARDDIALOG_START_90,
+ "Green" : strings.RID_AGENDAWIZARDDIALOG_START_91,
+ "Grey" : strings.RID_AGENDAWIZARDDIALOG_START_92,
+ "Modern" : strings.RID_AGENDAWIZARDDIALOG_START_93,
+ "Orange" : strings.RID_AGENDAWIZARDDIALOG_START_94,
+ "Red" : strings.RID_AGENDAWIZARDDIALOG_START_95,
+ "Simple" : strings.RID_AGENDAWIZARDDIALOG_START_96}
+
+ #Common Resources
+ self.resOverwriteWarning = strings.RID_COMMON_START_19
+ self.resTemplateDescription = strings.RID_COMMON_START_20
+
+ self.RoadmapLabels = []
+ self.RoadmapLabels.append(strings.RID_AGENDAWIZARDDIALOG_START_50)
+ self.RoadmapLabels.append(strings.RID_AGENDAWIZARDDIALOG_START_51)
+ self.RoadmapLabels.append(strings.RID_AGENDAWIZARDDIALOG_START_52)
+ self.RoadmapLabels.append(strings.RID_AGENDAWIZARDDIALOG_START_53)
+ self.RoadmapLabels.append(strings.RID_AGENDAWIZARDDIALOG_START_54)
+ self.RoadmapLabels.append(strings.RID_AGENDAWIZARDDIALOG_START_55)
diff --git a/wizards/com/sun/star/wizards/agenda/CGAgenda.py b/wizards/com/sun/star/wizards/agenda/CGAgenda.py
new file mode 100644
index 000000000..ee8435ba1
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/CGAgenda.py
@@ -0,0 +1,46 @@
+#
+# 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 .
+#
+from ..common.ConfigGroup import ConfigGroup
+from ..common.ConfigSet import ConfigSet
+from .CGTopic import CGTopic
+
+class CGAgenda(ConfigGroup):
+
+ def __init__(self):
+ self.cp_AgendaType = int()
+ self.cp_IncludeMinutes = bool()
+ self.cp_Title = ""
+ self.cp_Date = str()
+ self.cp_Time = str()
+ self.cp_Location = ""
+ self.cp_ShowMeetingType = bool()
+ self.cp_ShowRead = bool()
+ self.cp_ShowBring = bool()
+ self.cp_ShowNotes = bool()
+ self.cp_ShowCalledBy = bool()
+ self.cp_ShowFacilitator = bool()
+ self.cp_ShowNotetaker = bool()
+ self.cp_ShowTimekeeper = bool()
+ self.cp_ShowAttendees = bool()
+ self.cp_ShowObservers = bool()
+ self.cp_ShowResourcePersons = bool()
+ self.cp_TemplateName = str()
+ self.cp_TemplatePath = str()
+ self.cp_ProceedMethod = int()
+
+ self.cp_Topics = ConfigSet(CGTopic)
diff --git a/wizards/com/sun/star/wizards/agenda/CGTopic.py b/wizards/com/sun/star/wizards/agenda/CGTopic.py
new file mode 100644
index 000000000..e99f770b2
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/CGTopic.py
@@ -0,0 +1,60 @@
+#
+# 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 .
+#
+from ..common.ConfigGroup import ConfigGroup
+
+'''
+CGTopic means: Configuration Group Topic.
+This object encapsulates a configuration group with topic information.
+Since the topic's gui control uses its own data model, there is
+also code here to convert from the data model to CGTopic object (the constructor)
+and vice versa (setDataToRow method - used when loading the last session...)
+'''
+
+class CGTopic(ConfigGroup):
+
+ '''
+ create a new CGTopic object with data from the given row.
+ the row object is a PropertyValue array, as used
+ by the TopicsControl's data model.
+ @param row PropertyValue array as used by the TopicsControl's data model.
+ '''
+
+ def __init__(self, row=None):
+ if row is None:
+ self.cp_Index = int()
+ self.cp_Topic = str()
+ self.cp_Responsible = str()
+ self.cp_Time = str()
+ else:
+ self.cp_Index = int(row[0].Value[:-1])
+ self.cp_Topic = row[1].Value
+ self.cp_Responsible = row[2].Value
+ self.cp_Time = row[3].Value
+
+ '''
+ copies the data in this CGTopic object
+ to the given row.
+ @param row the row object (PropertyValue array) to
+ copy the data to.
+ '''
+
+ def setDataToRow(self, row):
+ row[0].Value = "" + str(self.cp_Index) + "."
+ row[1].Value = self.cp_Topic
+ row[2].Value = self.cp_Responsible
+ row[3].Value = self.cp_Time
diff --git a/wizards/com/sun/star/wizards/agenda/CallWizard.py b/wizards/com/sun/star/wizards/agenda/CallWizard.py
new file mode 100644
index 000000000..2b784e2fe
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/CallWizard.py
@@ -0,0 +1,75 @@
+#
+# 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 unohelper
+import traceback
+
+from .AgendaWizardDialogImpl import AgendaWizardDialogImpl, Desktop
+
+from com.sun.star.lang import XServiceInfo
+from com.sun.star.task import XJobExecutor
+
+# pythonloader looks for a static g_ImplementationHelper variable
+g_ImplementationHelper = unohelper.ImplementationHelper()
+g_implName = "com.sun.star.wizards.agenda.CallWizard"
+
+# implement a UNO component by deriving from the standard unohelper.Base class
+# and from the interface(s) you want to implement.
+class CallWizard(unohelper.Base, XJobExecutor, XServiceInfo):
+ def __init__(self, ctx):
+ # store the component context for later use
+ self.ctx = ctx
+
+ def trigger(self, args):
+ try:
+ fw = AgendaWizardDialogImpl(self.ctx.ServiceManager)
+ fw.startWizard(self.ctx.ServiceManager)
+ except Exception as e:
+ print ("Wizard failure exception " + str(type(e)) +
+ " message " + str(e) + " args " + str(e.args) +
+ traceback.format_exc())
+
+ @classmethod
+ def callRemote(self):
+ #Call the wizard remotely(see README)
+ try:
+ ConnectStr = \
+ "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext"
+ xLocMSF = Desktop.connect(ConnectStr)
+ lw = AgendaWizardDialogImpl(xLocMSF)
+ lw.startWizard(xLocMSF)
+ except Exception as e:
+ print ("Wizard failure exception " + str(type(e)) +
+ " message " + str(e) + " args " + str(e.args) +
+ traceback.format_exc())
+
+ def getImplementationName(self):
+ return g_implName
+
+ def supportsService(self, ServiceName):
+ return g_ImplementationHelper.supportsService(g_implName, ServiceName)
+
+ def getSupportedServiceNames(self):
+ return g_ImplementationHelper.getSupportedServiceNames(g_implName)
+
+g_ImplementationHelper.addImplementation( \
+ CallWizard, # UNO object class
+ g_implName, # implementation name
+ ("com.sun.star.task.Job",),) # list of implemented services
+ # (the only service)
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/wizards/com/sun/star/wizards/agenda/TemplateConsts.py b/wizards/com/sun/star/wizards/agenda/TemplateConsts.py
new file mode 100644
index 000000000..2593c2ce3
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/TemplateConsts.py
@@ -0,0 +1,83 @@
+#
+# 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 .
+#
+
+class TemplateConsts:
+ FILLIN_TITLE = "<title>"
+ FILLIN_TITLE = "<title>"
+ FILLIN_DATE = "<date>"
+ FILLIN_TIME = "<time>"
+ FILLIN_LOCATION = "<location>"
+ '''
+ section name <b>prefix</b> for sections that contain items.
+ this is also used as table name prefix, since each items section
+ must contain a table whose name is identical name to the section's name.
+ '''
+ SECTION_ITEMS = "AGENDA_ITEMS"
+ '''
+ the name of the section which contains the topics.
+ '''
+ SECTION_TOPICS = "AGENDA_TOPICS"
+ '''
+ the name of the parent minutes section.
+ '''
+ SECTION_MINUTES_ALL = "MINUTES_ALL"
+ '''
+ the name of the child minutes section.
+ This section will be duplicated for each topic.
+ '''
+ SECTION_MINUTES = "MINUTES"
+ '''
+ tagged headings and names.
+ These will be searched in item tables (in the template) and will be
+ replaced with resource strings.
+
+ headings...
+ '''
+ FILLIN_MEETING_TYPE = "<meeting-type>"
+ FILLIN_BRING = "<bring>"
+ FILLIN_READ = "<read>"
+ FILLIN_NOTES = "<notes>"
+ '''
+ names...
+ '''
+ FILLIN_CALLED_BY = "<called-by>"
+ FILLIN_FACILITATOR = "<facilitator>"
+ FILLIN_PARTICIPANTS = "<attendees>"
+ FILLIN_NOTETAKER = "<notetaker>"
+ FILLIN_TIMEKEEPER = "<timekeeper>"
+ FILLIN_OBSERVERS = "<observers>"
+ FILLIN_RESOURCE_PERSONS = "<resource-persons>"
+
+ '''
+ fillins for minutes.
+ These will be searched in the minutes section and will be replaced
+ with the appropriate data.
+ '''
+ FILLIN_MINUTES_TITLE = "<minutes-title>"
+ FILLIN_MINUTES_LOCATION = "<minutes-location>"
+ FILLIN_MINUTES_DATE = "<minutes-date>"
+ FILLIN_MINUTES_TIME = "<minutes-time>"
+ '''
+ Minutes-topic fillins
+ These will be searched in the minutes-child-section, and
+ will be replaced with topic data.
+ '''
+ FILLIN_MINUTE_NUM = "<mnum>"
+ FILLIN_MINUTE_TOPIC = "<mtopic>"
+ FILLIN_MINUTE_RESPONSIBLE = "<mresponsible>"
+ FILLIN_MINUTE_TIME = "<mtime>"
diff --git a/wizards/com/sun/star/wizards/agenda/TopicsControl.py b/wizards/com/sun/star/wizards/agenda/TopicsControl.py
new file mode 100644
index 000000000..6e269f6bf
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/TopicsControl.py
@@ -0,0 +1,857 @@
+#
+# 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
+from ..ui.ControlScroller import ControlScroller, PropertyNames, traceback, \
+ HelpIds
+from .AgendaWizardDialogConst import HID
+from ..common.Properties import Properties
+from ..ui.event.CommonListener import FocusListenerProcAdapter, \
+ KeyListenerProcAdapter
+
+from com.sun.star.awt.Key import DOWN, UP, TAB
+from com.sun.star.awt.KeyModifier import SHIFT, MOD1
+
+'''
+This class implements the UI functionality of the topics scroller control.
+<br/>
+During development, there has been a few changes which were not *fully* done
+mainly in converting the topics and time boxes
+from combobox and time box to normal textboxes,
+so in the code they might be referenced as combobox or timebox. This should be
+rather understood as topicstextbox and timetextbox.<br/><br/>
+Important behaviour of this control is that there is always a
+blank row at the end, in which the user can enter data.<br/>
+Once the row is not blank (thus, the user entered data...),
+a new blank row is added.<br/>
+Once the user removes the last *unempty* row, binsertRowy deleting its data, it becomes
+the *last empty row* and the one after is being automatically removed.<br/><br/>
+The control shows 5 rows at a time.<br/>
+If, for example, only 2 rows exist (from which the 2ed one is empty...)
+then the other three rows, which do not exist in the data model, are disabled.
+<br/>
+The following other functionality is implemented:
+<br/>
+0. synchronizing data between controls, data model and live preview.
+1. Tab scrolling.<br/>
+2. Keyboard scrolling.<br/>
+3. Removing rows and adding new rows.<br/>
+4. Moving rows up and down. <br/>
+<br/>
+This control relays on the ControlScroller control which uses the following
+Data model:<br/>
+1. It uses a vector, whose members are arrays of PropertyValue.<br/>
+2. Each array represents a row.<br/>
+(Note: the Name and Value members of the PropertyValue object are being used)
+3. Each property Value represents a value
+for a single control with the following rules:<br/>
+3. a. the Value of the property is used for as value
+of the controls (usually text).<br/>
+3. b. the Name of the property is used to map values
+to UI controls in the following manner:<br/>
+3. b. 1. only the Name of the first X Rows is regarded,
+where X is the number of visible rows (in the ainsertRowgenda wizard this would be 5,
+since 5 topic rows are visible on the dialog).<br/>
+3. b. 2. The Names of the first X (or 5...) rows are the names
+of the UI Controls to hold values. When the control scroller scrolls,
+it looks at the first 5 rows and uses the names specified there to map the
+current values to the specified controls. <br/>
+This data model makes the following limitations on the implementation:
+When moving rows, only the values should be moved. The Rows objects,
+which contain also the Names of the controls should not be switched. <br/>
+also when deleting or inserting rows, attention should be paid that no rows
+should be removed or inserted. Instead, only the Values should rotate. <br/><br/>
+To save the topics in the registry a ConfigSet of objects of type CGTopic is
+being used.
+This one is not synchronized "live", since it is unnecessary... instead, it is
+synchronized on call, before the settings should be saved.
+'''
+
+class TopicsControl(ControlScroller):
+
+ LABEL = "lblTopicCnt_"
+ TOPIC = "txtTopicTopic_"
+ RESP = "cbTopicResp_"
+ TIME = "txtTopicTime_"
+ LABEL_PROPS = (PropertyNames.PROPERTY_HEIGHT, PropertyNames.PROPERTY_LABEL,
+ PropertyNames.PROPERTY_POSITION_X, PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP, PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH)
+ TEXT_PROPS = (PropertyNames.PROPERTY_HEIGHT, PropertyNames.PROPERTY_HELPURL,
+ PropertyNames.PROPERTY_POSITION_X, PropertyNames.PROPERTY_POSITION_Y,
+ PropertyNames.PROPERTY_STEP, PropertyNames.PROPERTY_TABINDEX,
+ PropertyNames.PROPERTY_WIDTH)
+
+ def __init__(self, dialog, xmsf, agenda):
+ try:
+ super(TopicsControl, self).__init__(
+ dialog, xmsf, 5, 92, 38, 212, 5, 18, HID + 32)
+ self.dialog = dialog
+ #fill preview's table
+ self.initializeScrollFields(agenda)
+ #fill gui's table
+ self.fillupControls(True)
+ self.nscrollvalue = 0
+ self.lastFocusRow = 0
+ self.lastFocusControl = None
+ # set some focus listeners for TAB scroll down and up...
+ # prepare scroll down on tab press...
+ self.lastTime = \
+ self.ControlGroupVector[self.nblockincrement - 1].timebox
+
+ self.lastTime.addKeyListener(KeyListenerProcAdapter(
+ self.lastControlKeyPressed))
+ #prepare scroll up on tab press...
+ self.firstTopic = self.ControlGroupVector[0].textbox
+ self.firstTopic.addKeyListener(KeyListenerProcAdapter(
+ self.firstControlKeyPressed))
+ self.enableButtons()
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ initializes the data of the control.
+ '''
+
+ def initializeScrollFields(self, agenda):
+ # create a row for each topic with the given values...
+ for index,item in enumerate(agenda.cp_Topics.childrenList):
+ row = self.newRow(index)
+ item.setDataToRow(row)
+ # a parent class method
+ self.registerControlGroup(row, index)
+ self.updateDocumentRow(index)
+ # inserts a blank row at the end...
+ self.insertRowAtEnd()
+
+ '''
+ Insert a blank (empty) row
+ as last row of the control.
+ The control has always a blank row at the
+ end, which enables the user to enter data...
+ '''
+
+ def insertRowAtEnd(self):
+ l = len(self.scrollfields)
+ self.registerControlGroup(self.newRow(l), l)
+ self.setTotalFieldCount(l + 1)
+ # if the new row is visible, it must have been disabled
+ # so it should be now enabled...
+ if l - self.nscrollvalue < self.nblockincrement:
+ self.ControlGroupVector[l - self.nscrollvalue].\
+ setEnabled(True)
+
+ def saveTopics(self, agenda):
+ # last row is always empty
+ agenda.cp_Topics.childrenList = self.scrollfields[:-1]
+
+ '''
+ remove the last row
+ '''
+
+ def removeLastRow(self):
+ l = len(self.scrollfields)
+ # if we should scroll up...
+ if (l - self.nscrollvalue) >= 1 \
+ and (l - self.nscrollvalue) <= self.nblockincrement \
+ and self.nscrollvalue > 0:
+ while (l - self.nscrollvalue >= 1) \
+ and l - self.nscrollvalue <= self.nblockincrement \
+ and self.nscrollvalue > 0:
+ self.setScrollValue(self.nscrollvalue - 1)
+ # if we should disable a row...
+ elif self.nscrollvalue == 0 and l - 1 < self.nblockincrement:
+ self.ControlGroupVector[l - 1].setEnabled(False)
+
+ self.unregisterControlGroup(l - 1)
+ self.setTotalFieldCount(l - 1)
+
+ '''
+ in order to use the "move up", "down" "insert" and "remove" buttons,
+ we track the last control the gained focus, in order to know which
+ row should be handled.
+ @param fe
+ '''
+
+ def focusGained(self, fe):
+ xc = fe.Source
+ self.focusGained2(xc)
+
+ '''
+ Sometimes I set the focus programmatically to a control
+ (for example when moving a row up or down, the focus should move
+ with it).
+ In such cases, no VCL event is being triggered so it must
+ be called programmatically.
+ This is done by this method.
+ @param control
+ '''
+
+ def focusGained2(self, control):
+ try:
+ #calculate in which row we are...
+ name = control.Model.Name
+ num = name[name.index("_") + 1:]
+ self.lastFocusRow = int(num) + self.nscrollvalue
+ self.lastFocusControl = control
+ # enable/disable the buttons...
+ self.enableButtons()
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ enable or disable the buttons according to the
+ current row we are in.
+ '''
+
+ def enableButtons(self):
+ self.CurUnoDialog.btnInsert.Model.Enabled = \
+ self.lastFocusRow < len(self.scrollfields)
+ self.CurUnoDialog.btnRemove.Model.Enabled = \
+ self.lastFocusRow < len(self.scrollfields) - 1
+ if self.lastFocusControl is not None:
+ self.CurUnoDialog.btnUp.Model.Enabled = self.lastFocusRow > 0
+ self.CurUnoDialog.btnDown.Model.Enabled = \
+ self.lastFocusRow < len(self.scrollfields) - 1
+ else:
+ self.CurUnoDialog.btnUp.Model.Enabled = False
+ self.CurUnoDialog.btnDown.Model.Enabled = False
+
+ '''
+ Removes the current row.
+ See general class documentation explanation about the
+ data model used and the limitations which explain the implementation here.
+ '''
+
+ def removeRow(self):
+ try:
+ for i in range(self.lastFocusRow,
+ len(self.scrollfields) - 1):
+ pv1 = self.scrollfields[i]
+ pv2 = self.scrollfields[i + 1]
+ pv1[1].Value = pv2[1].Value
+ pv1[2].Value = pv2[2].Value
+ pv1[3].Value = pv2[3].Value
+ self.updateDocumentRow(i)
+ if i - self.nscrollvalue < self.nblockincrement:
+ self.fillupControl(i - self.nscrollvalue)
+
+ self.removeLastRow()
+ # update the live preview background document
+ self.reduceDocumentToTopics()
+ self.enableButtons()
+ if self.lastFocusControl is not None:
+ # the focus should return to the edit control
+ self.focus(self.lastFocusControl)
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ Inserts a row before the current row.
+ See general class documentation explanation about the
+ data model used and the limitations which explain the implementation here.
+ '''
+
+ def insertRow(self):
+ try:
+ self.insertRowAtEnd()
+ for i in range(len(self.scrollfields) - 2,
+ self.lastFocusRow, -1):
+ pv1 = self.scrollfields[i]
+ pv2 = self.scrollfields[i - 1]
+ pv1[1].Value = pv2[1].Value
+ pv1[2].Value = pv2[2].Value
+ pv1[3].Value = pv2[3].Value
+ self.updateDocumentRow(i)
+ if i - self.nscrollvalue < self.nblockincrement:
+ self.fillupControl(i - self.nscrollvalue)
+
+ # after rotating all the properties from this row on,
+ # we clear the row, so it is practically a new one...
+ pv1 = self.scrollfields[self.lastFocusRow]
+ pv1[1].Value = ""
+ pv1[2].Value = ""
+ pv1[3].Value = ""
+ # update the preview document.
+ self.updateDocumentRow(self.lastFocusRow)
+ self.fillupControl(
+ self.lastFocusRow - self.nscrollvalue)
+ self.enableButtons()
+
+ if self.lastFocusControl is not None:
+ self.focus(self.lastFocusControl)
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ create a new row with the given index.
+ The index is important because it is used in the
+ Name member of the PropertyValue objects.
+ To know why see general class documentation above (data model explanation)
+ @param i the index of the new row
+ @return
+ '''
+
+ def newRow(self, i):
+ pv = list(range(4))
+ pv[0] = Properties.createProperty(
+ TopicsControl.LABEL + str(i), "" + str(i + 1) + ".")
+ pv[1] = Properties.createProperty(TopicsControl.TOPIC + str(i), "")
+ pv[2] = Properties.createProperty(TopicsControl.RESP + str(i), "")
+ pv[3] = Properties.createProperty(TopicsControl.TIME + str(i), "")
+ return pv
+
+ '''
+ Implementation of ControlScroller
+ This is a UI method which inserts a new row to the control.
+ It uses the child-class ControlRow. (see below).
+ '''
+
+ def insertControlGroup(self, _index, npos):
+ oControlRow = ControlRow(
+ self.CurUnoDialog, self.iCompPosX, npos, _index,
+ ControlRow.tabIndex, self)
+ self.ControlGroupVector.append(oControlRow)
+ ControlRow.tabIndex += 4
+
+ '''
+ Checks if a row is empty.
+ This is used when the last row is changed.
+ If it is empty, the next row (which is always blank) is removed.
+ If it is not empty, a next row must exist.
+ @param row the index number of the row to check.
+ @return true if empty. false if not.
+ '''
+
+ def isRowEmpty(self, row):
+ data = self.getTopicData(row)
+ # now - is this row empty?
+ return not data[1].Value and not data[2].Value and not data[3].Value
+
+ '''
+ update the preview document and
+ remove/insert rows if needed.
+ @param guiRow
+ @param column
+ '''
+
+ def fieldChanged(self, guiRow, column):
+ try:
+ # First, I update the document
+ data = self.getTopicData(guiRow + self.nscrollvalue)
+ if data is None:
+ return
+ self.updateDocumentCell(
+ guiRow + self.nscrollvalue, column, data)
+ if self.isRowEmpty(guiRow + self.nscrollvalue):
+ '''
+ if this is the row before the last one
+ (the last row is always empty)
+ delete the last row...
+ '''
+ if (guiRow + self.nscrollvalue) \
+ == len(self.scrollfields) - 2:
+ self.removeLastRow()
+ '''now consequently check the last two rows,
+ and remove the last one if they are both empty.
+ (actually I check always the "before last" row,
+ because the last one is always empty...
+ '''
+ while len(self.scrollfields) > 1 \
+ and self.isRowEmpty(
+ len(self.scrollfields) - 2):
+ self.removeLastRow()
+ cr = self.ControlGroupVector[
+ len(self.scrollfields) - \
+ self.nscrollvalue - 1]
+ # if a remove was performed, set focus
+ #to the last row with some data in it...
+ self.focus(self.getControlByIndex(cr, column))
+ # update the preview document.
+ self.reduceDocumentToTopics()
+ else:
+ # row contains data
+ # is this the last row?
+ if (guiRow + self.nscrollvalue + 1) \
+ == len(self.scrollfields):
+ self.insertRowAtEnd()
+
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ return the corresponding row data for the given index.
+ @param topic index of the topic to get.
+ @return a PropertyValue array with the data for the given topic.
+ '''
+
+ def getTopicData(self, topic):
+ if topic < len(self.scrollfields):
+ return self.scrollfields[topic]
+ else:
+ return None
+
+ '''
+ If the user presses tab on the last control, and
+ there *are* more rows in the model, scroll down.
+ @param event
+ '''
+
+ def lastControlKeyPressed(self, event):
+ # if tab without shift was pressed...
+ try:
+ if event.KeyCode == TAB and event.Modifiers == 0:
+ # if there is another row...
+ if (self.nblockincrement + self.nscrollvalue) \
+ < len(self.scrollfields):
+ self.setScrollValue(self.nscrollvalue + 1)
+ self.focus(self.getControlByIndex(self.ControlGroupVector[4], 1))
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ If the user presses shift-tab on the first control, and
+ there *are* more rows in the model, scroll up.
+ @param event
+ '''
+
+ def firstControlKeyPressed(self, event):
+ # if tab with shift was pressed...
+ if (event.KeyCode == TAB) and \
+ (event.Modifiers == SHIFT):
+ if self.nscrollvalue > 0:
+ self.setScrollValue(self.nscrollvalue - 1)
+ self.focus(self.lastTime)
+
+ '''
+ sets focus to the given control.
+ @param textControl
+ '''
+
+ def focus(self, textControl):
+ textControl.setFocus()
+ text = textControl.Text
+ textControl.Selection = uno.createUnoStruct( \
+ 'com.sun.star.awt.Selection', 0, len(text))
+ self.focusGained2(textControl)
+
+ '''
+ moves the given row one row down.
+ @param guiRow the gui index of the row to move.
+ @param control the control to gain focus after moving.
+ '''
+
+ def rowDown(self, guiRow=None, control=None):
+ try:
+ if guiRow is None:
+ guiRow = self.lastFocusRow - self.nscrollvalue
+ if control is None:
+ control = self.lastFocusControl
+ # only perform if this is not the last row.
+ actuallRow = guiRow + self.nscrollvalue
+ if actuallRow + 1 < len(self.scrollfields):
+ # get the current selection
+ selection = control.Selection
+ # the last row should scroll...
+ scroll = (guiRow == self.nblockincrement - 1)
+ if scroll:
+ self.setScrollValue(self.nscrollvalue + 1)
+
+ scroll1 = self.nscrollvalue
+ if scroll:
+ aux = -1
+ else:
+ aux = 1
+ self.switchRows(guiRow, guiRow + aux)
+ if self.nscrollvalue != scroll1:
+ guiRow += (self.nscrollvalue - scroll1)
+
+ self.setSelection(guiRow + (not scroll), control, selection)
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ move the current row up
+ '''
+
+ def rowUp(self, guiRow=None, control=None):
+ try:
+ if guiRow is None:
+ guiRow = self.lastFocusRow - self.nscrollvalue
+ if control is None:
+ control = self.lastFocusControl
+ # only perform if this is not the first row
+ actuallRow = guiRow + self.nscrollvalue
+ if actuallRow > 0:
+ # get the current selection
+ selection = control.Selection
+ # the last row should scroll...
+ scroll = (guiRow == 0)
+ if scroll:
+ self.setScrollValue(self.nscrollvalue - 1)
+ if scroll:
+ aux = 1
+ else:
+ aux = -1
+ self.switchRows(guiRow, guiRow + aux)
+ self.setSelection(guiRow - (not scroll), control, selection)
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ moves the cursor up.
+ @param guiRow
+ @param control
+ '''
+
+ def cursorUp(self, guiRow, control):
+ # is this the last full row ?
+ actuallRow = guiRow + self.nscrollvalue
+ #if this is the first row
+ if actuallRow == 0:
+ return
+ # the first row should scroll...
+
+ scroll = (guiRow == 0)
+ if scroll:
+ self.setScrollValue(self.nscrollvalue - 1)
+ upperRow = self.ControlGroupVector[guiRow]
+ else:
+ upperRow = self.ControlGroupVector[guiRow - 1]
+
+ self.focus(self.getControl(upperRow, control))
+
+ '''
+ moves the cursor down
+ @param guiRow
+ @param control
+ '''
+
+ def cursorDown(self, guiRow, control):
+ # is this the last full row ?
+ actuallRow = guiRow + self.nscrollvalue
+ #if this is the last row, exit
+ if actuallRow == len(self.scrollfields) - 1:
+ return
+ # the first row should scroll...
+
+ scroll = (guiRow == self.nblockincrement - 1)
+ if scroll:
+ self.setScrollValue(self.nscrollvalue + 1)
+ lowerRow = self.ControlGroupVector[guiRow]
+ else:
+ # if we scrolled we are done...
+ #otherwise...
+ lowerRow = self.ControlGroupVector[guiRow + 1]
+
+ self.focus(self.getControl(lowerRow, control))
+
+ '''
+ changes the values of the given rows with each other
+ @param row1 one can figure out what this parameter is...
+ @param row2 one can figure out what this parameter is...
+ '''
+
+ def switchRows(self, row1, row2):
+ o1 = self.scrollfields[row1 + self.nscrollvalue]
+ o2 = self.scrollfields[row2 + self.nscrollvalue]
+ temp = None
+ for i in range(1, len(o1)):
+ temp = o1[i].Value
+ o1[i].Value = o2[i].Value
+ o2[i].Value = temp
+ self.fillupControl(row1)
+ self.fillupControl(row2)
+ self.updateDocumentRow(row1 + self.nscrollvalue, o1)
+ self.updateDocumentRow(row2 + self.nscrollvalue, o2)
+
+ '''
+ if we changed the last row, add another one...
+ '''
+ if (row1 + self.nscrollvalue + 1 == \
+ len(self.scrollfields)) \
+ or (row2 + self.nscrollvalue + 1 == \
+ len(self.scrollfields)):
+
+ self.insertRowAtEnd()
+ '''
+ if we did not change the last row but
+ we did change the one before - check if we
+ have two empty rows at the end.
+ If so, delete the last one...
+ '''
+ elif (row1 + self.nscrollvalue) + \
+ (row2 + self.nscrollvalue) \
+ == (len(self.scrollfields) * 2 - 5):
+ if self.isRowEmpty(len(self.scrollfields) - 2) \
+ and self.isRowEmpty(
+ len(self.scrollfields) - 1):
+ self.removeLastRow()
+ self.reduceDocumentToTopics()
+
+ '''
+ sets a text selection to a given control.
+ This is used when one moves a row up or down.
+ After moving row X to X+/-1, the selection (or cursor position) of the
+ last focused control should be restored.
+ The control's row is the given guiRow.
+ The control's column is detected according to the given event.
+ This method is called as subsequent to different events,
+ thus it is comfortable to use the event here to detect the column,
+ rather than in the different event methods.
+ @param guiRow the row of the control to set the selection to.
+ @param eventSource helps to detect
+ the control's column to set the selection to.
+ @param s the selection object to set.
+ '''
+
+ def setSelection(self, guiRow, eventSource, s):
+ cr = self.ControlGroupVector[guiRow]
+ control = self.getControl(cr, eventSource)
+ control.setFocus()
+ control.setSelection(s)
+
+ '''
+ returns a control out of the given row, according to a column number.
+ @param cr control row object.
+ @param column the column number.
+ @return the control...
+ '''
+
+ def getControlByIndex(self, cr, column):
+ tmp_switch_var1 = column
+ if tmp_switch_var1 == 0:
+ return cr.label
+ elif tmp_switch_var1 == 1:
+ return cr.textbox
+ elif tmp_switch_var1 == 2:
+ return cr.combobox
+ elif tmp_switch_var1 == 3:
+ return cr.timebox
+ else:
+ raise Exception("No such column");
+
+ '''getControl
+ returns a control out of the given row, which is
+ in the same column as the given control.
+ @param cr control row object
+ @param control a control indicating a column.
+ @return
+ '''
+
+ def getControl(self, cr, control):
+ column = self.getColumn(control)
+ return self.getControlByIndex(cr, column)
+
+ '''
+ returns the column number of the given control.
+ @param control
+ @return
+ '''
+
+ def getColumn(self, control):
+ name = control.Model.Name
+ if name.startswith(TopicsControl.TOPIC):
+ return 1
+ if name.startswith(TopicsControl.RESP):
+ return 2
+ if name.startswith(TopicsControl.TIME):
+ return 3
+ if name.startswith(TopicsControl.LABEL):
+ return 0
+ return -1
+
+ '''
+ update the given row in the preview document with the given data.
+ @param row
+ @param data
+ '''
+
+ def updateDocumentRow(self, row, data=None):
+ if data is None:
+ data = self.scrollfields[row]
+ try:
+ for i in range(len(data)):
+ self.CurUnoDialog.myAgendaDoc.topics.writeCell(
+ row, i, data)
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ updates a single cell in the preview document.
+ Is called when a single value is changed, since we really
+ don't have to update the whole row for one small change...
+ @param row the data row to update (topic number).
+ @param column the column to update (a gui column, not a document column).
+ @param data the data of the entire row.
+ '''
+
+ def updateDocumentCell(self, row, column, data):
+ try:
+ self.CurUnoDialog.myAgendaDoc.topics.writeCell(
+ row, column, data)
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ when removing rows, this method updates
+ the preview document to show the number of rows
+ according to the data model.
+ '''
+
+ def reduceDocumentToTopics(self):
+ try:
+ self.CurUnoDialog.myAgendaDoc.topics.reduceDocumentTo(
+ len(self.scrollfields) - 1)
+ except Exception:
+ traceback.print_exc()
+
+'''
+A class represting a single GUI row.
+Note that the instance methods of this class
+are being called and handle controls of
+a single row.
+'''
+
+class ControlRow(object):
+
+ tabIndex = 520
+ '''
+ constructor. Create the row in the given dialog given coordinates,
+ with the given offset (row number) and tabindex.
+ Note that since I use this specifically for the agenda wizard,
+ the step and all control coordinates inside the
+ row are constant (5).
+ '''
+
+ def __init__(self, dialog, x, y, i, tabindex, topicsControl):
+ self.offset = i
+ self.dialog = dialog
+ self.topicsControl = topicsControl
+ self.label = self.dialog.insertLabel(
+ self.topicsControl.LABEL + str(i),
+ self.topicsControl.LABEL_PROPS,
+ (8, "" + str(i + 1) + ".",
+ x + 4, y + 2, self.topicsControl.iStep, tabindex, 10))
+ self.textbox = self.dialog.insertTextField(
+ self.topicsControl.TOPIC + str(i), "topicTextChanged",
+ self.topicsControl.TEXT_PROPS,
+ (12, HelpIds.getHelpIdString(self.topicsControl.curHelpIndex + i * 3 + 1),
+ x + 15, y, self.topicsControl.iStep, tabindex + 1, 84), self)
+ self.combobox = self.dialog.insertTextField(
+ self.topicsControl.RESP + str(i), "responsibleTextChanged",
+ self.topicsControl.TEXT_PROPS,
+ (12, HelpIds.getHelpIdString(self.topicsControl.curHelpIndex + i * 3 + 2),
+ x + 103, y, self.topicsControl.iStep, tabindex + 2, 68), self)
+ self.timebox = self.dialog.insertTextField(
+ self.topicsControl.TIME + str(i), "timeTextChanged",
+ self.topicsControl.TEXT_PROPS,
+ (12, HelpIds.getHelpIdString(self.topicsControl.curHelpIndex + i * 3 + 3),
+ x + 175, y, self.topicsControl.iStep, tabindex + 3, 20), self)
+ self.setEnabled(False)
+ self.textbox.addKeyListener(KeyListenerProcAdapter(self.keyPressed))
+ self.combobox.addKeyListener(KeyListenerProcAdapter(self.keyPressed))
+ self.timebox.addKeyListener(KeyListenerProcAdapter(self.keyPressed))
+ self.textbox.addFocusListener(FocusListenerProcAdapter(
+ self.topicsControl.focusGained))
+ self.combobox.addFocusListener(FocusListenerProcAdapter(
+ self.topicsControl.focusGained))
+ self.timebox.addFocusListener(FocusListenerProcAdapter(
+ self.topicsControl.focusGained))
+
+ def topicTextChanged(self):
+ try:
+ # update the data model
+ self.topicsControl.fieldInfo(self.offset, 1)
+ # update the preview document
+ self.topicsControl.fieldChanged(self.offset, 1)
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ called through an event listener when the
+ responsible text is changed by the user.
+ updates the data model and the preview document.
+ '''
+
+ def responsibleTextChanged(self):
+ try:
+ # update the data model
+ self.topicsControl.fieldInfo(self.offset, 2)
+ # update the preview document
+ self.topicsControl.fieldChanged(self.offset, 2)
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ called through an event listener when the
+ time text is changed by the user.
+ updates the data model and the preview document.
+ '''
+
+ def timeTextChanged(self):
+ try:
+ # update the data model
+ self.topicsControl.fieldInfo(self.offset, 3)
+ # update the preview document
+ self.topicsControl.fieldChanged(self.offset, 3)
+ except Exception:
+ traceback.print_exc()
+
+ '''
+ enables/disables the row.
+ @param enabled true for enable, false for disable.
+ '''
+
+ def setEnabled(self, enabled):
+ self.label.Model.Enabled = enabled
+ self.textbox.Model.Enabled = enabled
+ self.combobox.Model.Enabled = enabled
+ self.timebox.Model.Enabled = enabled
+
+ '''
+ Implementation of XKeyListener.
+ Optionally performs the one of the following:
+ cursor up, or down, row up or down
+ '''
+
+ def keyPressed(self, event):
+ try:
+ if self.isMoveDown(event):
+ self.topicsControl.rowDown(self.offset, event.Source)
+ elif self.isMoveUp(event):
+ self.topicsControl.rowUp(self.offset, event.Source)
+ elif self.isDown(event):
+ self.topicsControl.cursorDown(self.offset, event.Source)
+ elif self.isUp(event):
+ self.topicsControl.cursorUp(self.offset, event.Source)
+
+ self.topicsControl.enableButtons()
+ except Exception:
+ traceback.print_exc()
+
+ def isMoveDown(self, e):
+ return (e.KeyCode == DOWN) and (e.Modifiers == MOD1)
+
+ def isMoveUp(self, e):
+ return (e.KeyCode == UP) and (e.Modifiers == MOD1)
+
+ def isDown(self, e):
+ return (e.KeyCode == DOWN) and (e.Modifiers == 0)
+
+ def isUp(self, e):
+ return (e.KeyCode == UP) and (e.Modifiers == 0)
diff --git a/wizards/com/sun/star/wizards/agenda/__init__.py b/wizards/com/sun/star/wizards/agenda/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/__init__.py
diff --git a/wizards/com/sun/star/wizards/agenda/agenda.component b/wizards/com/sun/star/wizards/agenda/agenda.component
new file mode 100644
index 000000000..5778ae32f
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/agenda.component
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+ -->
+<component loader="com.sun.star.loader.Python"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.wizards.agenda.CallWizard">
+ <service name="com.sun.star.task.Job"/>
+ </implementation>
+</component>