summaryrefslogtreecommitdiff
path: root/wizards/com/sun/star/wizards/agenda
diff options
context:
space:
mode:
authorOliver Bolte <obo@openoffice.org>2004-09-08 12:58:28 +0000
committerOliver Bolte <obo@openoffice.org>2004-09-08 12:58:28 +0000
commit009b1d22aecc4e7426318ee5710179c79238ca2e (patch)
tree6ae8d14f6838fd055fcc00f683ed607262c172fd /wizards/com/sun/star/wizards/agenda
parent61788feacb1d768de1c0a4d2155f114db55eb7ad (diff)
INTEGRATION: CWS qwizards2 (1.1.2); FILE ADDED
2004/08/20 14:55:46 tv 1.1.2.7: checked in for ron 2004/08/13 10:13:46 rpiterman 1.1.2.6: documentation 2004/07/19 13:55:03 rpiterman 1.1.2.5: removed debug outputs to stdout 2004/06/30 16:21:14 rpiterman 1.1.2.4: fixed a bug which crashed office (focusGained is now called programatically when I set the focus) optimized cell redraw - now only the actuall cell redraws when the topic text changes. (topic list only) 2004/06/25 13:02:08 rpiterman 1.1.2.3: further developement 2004/06/11 16:05:33 rpiterman 1.1.2.2: Further developement 2004/06/02 15:27:52 rpiterman 1.1.2.1: New Agenda Wizard
Diffstat (limited to 'wizards/com/sun/star/wizards/agenda')
-rw-r--r--wizards/com/sun/star/wizards/agenda/AgendaTemplate.java1792
1 files changed, 1792 insertions, 0 deletions
diff --git a/wizards/com/sun/star/wizards/agenda/AgendaTemplate.java b/wizards/com/sun/star/wizards/agenda/AgendaTemplate.java
new file mode 100644
index 000000000000..35119968d3aa
--- /dev/null
+++ b/wizards/com/sun/star/wizards/agenda/AgendaTemplate.java
@@ -0,0 +1,1792 @@
+/*************************************************************************
+ *
+ * $RCSfile: AgendaTemplate.java,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: obo $ $Date: 2004-09-08 13:58:27 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (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.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ */
+
+package com.sun.star.wizards.agenda;
+
+import java.util.Calendar;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+
+import com.sun.star.awt.TextEvent;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.container.NoSuchElementException;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.container.XNamed;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.i18n.NumberFormatIndex;
+import com.sun.star.lang.Locale;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.table.XCell;
+import com.sun.star.table.XTableRows;
+import com.sun.star.text.*;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.XNumberFormatsSupplier;
+import com.sun.star.util.XNumberFormatter;
+import com.sun.star.util.XSearchDescriptor;
+import com.sun.star.util.XSearchable;
+import com.sun.star.wizards.common.Desktop;
+import com.sun.star.wizards.common.FileAccess;
+import com.sun.star.wizards.common.Helper;
+import com.sun.star.wizards.document.OfficeDocument;
+import com.sun.star.wizards.text.TextDocument;
+import com.sun.star.wizards.text.TextSectionHandler;
+import com.sun.star.wizards.ui.UnoDialog2;
+import com.sun.star.wizards.ui.event.DataAware;
+
+
+/**
+ * @author rpiterman
+ * 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/>
+ * Some terminology:<br/>
+ * 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:
+ * 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.
+ * 2.a. arbitrary structure.
+ * 2.b. design is arbitrary.
+ * As result the following limitations:<br/>
+ * No column merge is allowed.<br/>
+ * One compolsary 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, reaplying it after writing the
+ * table.
+ * <br/><br/>
+ * A note about threads:<br/>
+ * Many methods here are synchronized, in order to avoid colission made by
+ * events fired too often.
+ */
+public class AgendaTemplate extends TextDocument implements TemplateConsts, DataAware.Listener
+{
+ /**
+ * resources.
+ */
+ AgendaWizardDialogResources resources;
+ /**
+ * data model. This keeps the status of the agenda document, and
+ * every redraw is done according to this data.
+ * Exception: topic data is written programatically, event-oriented.
+ */
+ CGAgenda agenda;
+
+ /**
+ * the UNO Text Document serrvice
+ */
+ Object document;
+
+ /**
+ * Service Factory
+ */
+ XMultiServiceFactory docMSF;
+
+ /**
+ * The template-filename of the current template.
+ * Since we often re-link section and the break the link,
+ * inorder to restore them, we need a template to link to.
+ * This is practically an identicall copy of the current template.
+ */
+ String template;
+
+ /**
+ * used for common operations on sections.
+ */
+ TextSectionHandler textSectionHandler;
+ /**
+ * a component loader.
+ */
+ XComponentLoader xComponentLoader;
+
+ /**
+ * an array containing all ItemTable object (which control each an Items
+ * Table in the document.
+ */
+ ItemsTable[] itemsTables;
+
+ /**
+ * the controller of the topics table.
+ */
+ Topics topics;
+
+ /**
+ * Stores reusable OOo Placeholder TextFields to insert to the document.
+ */
+ Map itemsCache;
+ /**
+ * This map is used to find which tables contains a certain Item, so
+ * the keys are the different Items, the Objects are the ItemTable controllers.
+ * When an Item must be redrawn (because the user checked or uncheced it),
+ * the controller is retrieved from this Map, and a redraw is issued on this controller.
+ */
+ Map itemsMap = new Hashtable(11);
+
+ /**
+ * A temporary variable used to list all items and map them.
+ */
+ List _allItems = new Vector();
+
+
+ /**
+ * keep a reference on some static items in the document,
+ * so when their content is changed (through the user), we
+ * can just reference them and set their text.
+ */
+ TextElement teTitle, teDate, teTime, teLocation;
+ XTextRange trTitle, trDate, trTime, trLocation;
+
+ /**
+ * used to format the date / time.
+ */
+ int dateFormat, timeFormat;
+ XNumberFormatter dateFormatter, timeFormatter;
+
+ /**
+ * used to transfare time from VCL to UNO.
+ */
+ long docNullTime;
+ Calendar calendar;
+
+ /**
+ * used to set the document title property (step 6).
+ */
+ private Object docInfo;
+
+ /**
+ * loads the given template, and analyze its structure.
+ * @param templateURL
+ * @param topics
+ * @see AgendaTemplate.initialize()
+ * @see AgendaTemplate.initializeData()
+ */
+ public synchronized void load(String templateURL, List topics) {
+ template = calcTemplateName(templateURL);
+ document = loadAsPreview(templateURL,false);
+ docMSF = ((XMultiServiceFactory)UnoRuntime.queryInterface(XMultiServiceFactory.class,document));
+ xFrame.getComponentWindow().setEnable(false);
+ xTextDocument.lockControllers();
+ initialize();
+ initializeData(topics);
+ xTextDocument.unlockControllers();
+ }
+
+
+ /**
+ * The agenda templates are in format of aw-XXX.ott
+ * the templates name is then XXX.ott.
+ * This method calculates it.
+ * @param url
+ * @return the template name without the "aw-" at the beginning.
+ */
+ private String calcTemplateName(String url) {
+ return FileAccess.connectURLs( FileAccess.getParentDir(url) ,FileAccess.getFilename(url).substring(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).
+ * @param topicsData since the model does not contain Topics
+ * information (it is only actualized on save) the given list
+ * supplies this information.
+ */
+ private void initializeData(List topicsData) {
+ for (int i = 0; i < itemsTables.length; i++) {
+ try {
+ itemsTables[i].write("");
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ redrawTitle("txtTitle");
+ redrawTitle("txtDate");
+ redrawTitle("txtTime");
+ redrawTitle("cbLocation");
+
+ topics.writeAll(topicsData);
+
+ setTemplateTitle(agenda.cp_TemplateName);
+
+ }
+
+ /**
+ * 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.
+ * @param itemName
+ */
+ public synchronized void redraw(String itemName) {
+ try {
+ // get the table in which the item is...
+ Object itemsTable =
+ itemsMap.get(itemName);
+ // rewrite the table.
+ ((ItemsTable)itemsTable).write(null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * update the documents title property to the given title
+ * @param newTitle new title.
+ */
+ synchronized void setTemplateTitle(String newTitle) {
+ Helper.setUnoPropertyValue(docInfo, "Title", newTitle );
+ }
+
+ /**
+ * constructor. The document is *not* loaded here.
+ * only some formal members are set.
+ * @param xmsf_ service factory.
+ * @param agenda_ the data model (CGAgenda)
+ * @param resources_ resources.
+ */
+ AgendaTemplate(XMultiServiceFactory xmsf_, CGAgenda agenda_ , AgendaWizardDialogResources resources_) {
+ super(xmsf_);
+
+ agenda = agenda_;
+ resources = resources_;
+
+ if (itemsCache == null)
+ initItemsCache();
+
+ _allItems = null;
+
+ }
+
+ /**
+ * checks the data model if the
+ * item corresponding to the given string should be shown
+ * @param itemName a string representing an Item (name or heading).
+ * @return true if the model specifies that the item should be displayed.
+ */
+ boolean isShowItem(String itemName) {
+ if ( itemName.equals(FILLIN_MEETING_TYPE) )
+ return agenda.cp_ShowMeetingType;
+ else if ( itemName.equals(FILLIN_READ) )
+ return agenda.cp_ShowRead;
+ else if ( itemName.equals(FILLIN_BRING) )
+ return agenda.cp_ShowBring;
+ else if ( itemName.equals(FILLIN_NOTES) )
+ return agenda.cp_ShowNotes;
+
+ else if ( itemName.equals(FILLIN_FACILITATOR) )
+ return agenda.cp_ShowFacilitator;
+ else if ( itemName.equals(FILLIN_TIMEKEEPER) )
+ return agenda.cp_ShowTimekeeper;
+ else if ( itemName.equals(FILLIN_NOTETAKER) )
+ return agenda.cp_ShowNotetaker;
+ else if ( itemName.equals(FILLIN_PARTICIPANTS) )
+ return agenda.cp_ShowAttendees;
+ else if ( itemName.equals(FILLIN_CALLED_BY) )
+ return agenda.cp_ShowCalledBy;
+ else if ( itemName.equals(FILLIN_OBSERVERS) )
+ return agenda.cp_ShowObservers;
+ else if ( itemName.equals(FILLIN_RESOURCE_PERSONS) )
+ return agenda.cp_ShowResourcePersons;
+ else throw new IllegalArgumentException("No such item");
+
+ }
+
+ /**
+ * itemsCache is a Map containing all agenda item. These are object which
+ * "write themselfs" 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).
+ */
+ private void initItemsCache() {
+ itemsCache = new Hashtable(11);
+
+ XMultiServiceFactory xmsf = (XMultiServiceFactory)UnoRuntime.queryInterface(XMultiServiceFactory.class,document);
+ // Headings
+
+ itemsCache.put( FILLIN_MEETING_TYPE ,
+ new AgendaItem(FILLIN_MEETING_TYPE, new TextElement( resources.itemMeetingType , STYLE_MEETING_TYPE ) ,
+ new PlaceholderElement( STYLE_MEETING_TYPE_TEXT , resources.reschkMeetingTitle_value , resources.resPlaceHolderHint, xmsf ) ) );
+
+ itemsCache.put( FILLIN_BRING ,
+ new AgendaItem( FILLIN_BRING,new TextElement( resources.itemBring , STYLE_BRING ) ,
+ new PlaceholderElement( STYLE_BRING_TEXT , resources.reschkBring_value , resources.resPlaceHolderHint, xmsf ) ) );
+
+ itemsCache.put( FILLIN_READ ,
+ new AgendaItem( FILLIN_READ, new TextElement( resources.itemRead , STYLE_READ ) ,
+ new PlaceholderElement( STYLE_READ_TEXT , resources.reschkRead_value , resources.resPlaceHolderHint, xmsf ) ) );
+
+ itemsCache.put( FILLIN_NOTES ,
+ new AgendaItem( FILLIN_NOTES, new TextElement( resources.itemNote , STYLE_NOTES ) ,
+ new PlaceholderElement( STYLE_NOTES_TEXT , resources.reschkNotes_value , resources.resPlaceHolderHint, xmsf ) ) );
+
+ // Names
+
+ itemsCache.put( FILLIN_CALLED_BY ,
+ new AgendaItem( FILLIN_CALLED_BY, new TextElement( resources.itemCalledBy , STYLE_CALLED_BY ) ,
+ new PlaceholderElement( STYLE_CALLED_BY_TEXT , resources.reschkConvenedBy_value , resources.resPlaceHolderHint, xmsf ) ) );
+
+ itemsCache.put( FILLIN_FACILITATOR ,
+ new AgendaItem( FILLIN_FACILITATOR, new TextElement( resources.itemFacilitator , STYLE_FACILITATOR ) ,
+ new PlaceholderElement( STYLE_FACILITATOR_TEXT , resources.reschkPresiding_value , resources.resPlaceHolderHint, xmsf ) ) );
+
+ itemsCache.put( FILLIN_PARTICIPANTS,
+ new AgendaItem( FILLIN_PARTICIPANTS, new TextElement( resources.itemAttendees , STYLE_PARTICIPANTS ) ,
+ new PlaceholderElement( STYLE_PARTICIPANTS_TEXT , resources.reschkAttendees_value , resources.resPlaceHolderHint, xmsf )) );
+
+ itemsCache.put( FILLIN_NOTETAKER ,
+ new AgendaItem( FILLIN_NOTETAKER,new TextElement( resources.itemNotetaker, STYLE_NOTETAKER ) ,
+ new PlaceholderElement( STYLE_NOTETAKER_TEXT , resources.reschkNoteTaker_value , resources.resPlaceHolderHint, xmsf ) ) );
+
+ itemsCache.put( FILLIN_TIMEKEEPER ,
+ new AgendaItem( FILLIN_TIMEKEEPER, new TextElement( resources.itemTimekeeper , STYLE_TIMEKEEPER ) ,
+ new PlaceholderElement( STYLE_TIMEKEEPER_TEXT , resources.reschkTimekeeper_value , resources.resPlaceHolderHint, xmsf ) ) );
+
+ itemsCache.put( FILLIN_OBSERVERS ,
+ new AgendaItem( FILLIN_OBSERVERS,new TextElement( resources.itemObservers , STYLE_OBSERVERS ),
+ new PlaceholderElement( STYLE_OBSERVERS_TEXT , resources.reschkObservers_value , resources.resPlaceHolderHint, xmsf ) ) );
+
+ itemsCache.put( FILLIN_RESOURCE_PERSONS ,
+ new AgendaItem( FILLIN_RESOURCE_PERSONS, new TextElement( resources.itemResource , STYLE_RESOURCE_PERSONS ) ,
+ new PlaceholderElement( STYLE_RESOURCE_PERSONS_TEXT , resources.reschkResourcePersons_value , resources.resPlaceHolderHint, xmsf ) ) );
+
+ }
+
+ /**
+ * 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 "fille-ins" (apear 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
+ */
+ private void initialize()
+ {
+ /*
+ * Get the default locale of the document, and create the date and time formatters.
+ */
+ XMultiServiceFactory docMSF = (XMultiServiceFactory)UnoRuntime.queryInterface(XMultiServiceFactory.class,document);
+ try {
+ Object defaults = docMSF.createInstance("com.sun.star.text.Defaults");
+ Locale l = (Locale) Helper.getUnoStructValue(defaults, "CharLocale");
+
+ java.util.Locale jl = new java.util.Locale(
+ l.Language , l.Country, l.Variant );
+
+ calendar = Calendar.getInstance(jl);
+
+ XNumberFormatsSupplier nfs = (XNumberFormatsSupplier)UnoRuntime.queryInterface(XNumberFormatsSupplier.class,document);
+ Object formatSettings = nfs.getNumberFormatSettings();
+ com.sun.star.util.Date date = (com.sun.star.util.Date)Helper.getUnoPropertyValue( formatSettings, "NullDate");
+
+ calendar.set(date.Year, date.Month - 1 , date.Day);
+
+ docNullTime = calendar.getTimeInMillis();
+
+ dateFormat = Desktop.getNumberFormatterKey( nfs, NumberFormatIndex.DATE_SYSTEM_LONG );
+ timeFormat = Desktop.getNumberFormatterKey( nfs, NumberFormatIndex.TIME_HHMM );
+
+
+ dateFormatter = Desktop.createNumberFormatter(xMSF, nfs );
+ timeFormatter = Desktop.createNumberFormatter(xMSF, nfs );
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ throw new NullPointerException ("Fatal Error: could not initialize locale or date/time formats.");
+ }
+
+ /*
+ * get the document info object.
+ */
+ docInfo = OfficeDocument.getDocumentInfo(document);
+
+ initItemsCache();
+ initializeItems();
+ initializeTitles();
+ initializeItemsSections();
+ XMultiServiceFactory xMultiServiceFactory = (XMultiServiceFactory)UnoRuntime.queryInterface(XMultiServiceFactory.class,document);
+ textSectionHandler = new TextSectionHandler(xMultiServiceFactory, (XTextDocument)UnoRuntime.queryInterface(XTextDocument.class,document));
+ initializeTopics();
+ _allItems.clear();
+ _allItems = null;
+ }
+
+ /**
+ * locates the titles (name, location, date, time) and saves a reference to thier Text ranges.
+ *
+ */
+ private void initializeTitles() {
+ XTextRange item = null;
+
+ XMultiServiceFactory xmsf = (XMultiServiceFactory)UnoRuntime.queryInterface(XMultiServiceFactory.class,document);
+
+ for (int i = 0; i < _allItems.size(); i++) {
+ item = (XTextRange)_allItems.get(i);
+ String text = item.getString().trim().toLowerCase();
+ if (text.equals(FILLIN_TITLE)) {
+
+ teTitle = new PlaceholderTextElement(item, resources.resPlaceHolderTitle, resources.resPlaceHolderHint, xmsf);
+ trTitle = item;
+ _allItems.remove(i--);
+ }
+ else if (text.equals(FILLIN_DATE)) {
+ teDate = new PlaceholderTextElement(item, resources.resPlaceHolderDate, resources.resPlaceHolderHint, xmsf);
+ trDate = item;
+ _allItems.remove(i--);
+ }
+ else if (text.equals(FILLIN_TIME)) {
+ teTime = new PlaceholderTextElement(item, resources.resPlaceHolderTime, resources.resPlaceHolderHint, xmsf);
+ trTime = item;
+ _allItems.remove(i--);
+ }
+ else if (text.equals(FILLIN_LOCATION)) {
+ teLocation = new PlaceholderTextElement(item, resources.resPlaceHolderLocation, resources.resPlaceHolderHint, xmsf);
+ trLocation = item;
+ _allItems.remove(i--);
+ }
+ }
+ }
+
+ private void initializeTopics()
+ {
+ topics = new Topics();
+ }
+
+ private void initializeItems()
+ {
+ _allItems = searchFillInItems();
+ }
+
+ /**
+ * searches the document for items in the format "&gt;*&lt;"
+ * @return a vector containing the XTextRanges of the found items
+ */
+ private List searchFillInItems() {
+ try {
+ XSearchable xSearchable = (XSearchable)UnoRuntime.queryInterface(XSearchable.class,document);
+ XSearchDescriptor sd = xSearchable.createSearchDescriptor();
+ sd.setSearchString("<[^>]+>");
+ sd.setPropertyValue("SearchRegularExpression", Boolean.TRUE);
+ sd.setPropertyValue("SearchWords", Boolean.TRUE);
+
+ XIndexAccess ia = xSearchable.findAll(sd);
+
+ List l = new Vector(ia.getCount());
+ for (int i = 0; i<ia.getCount(); i++) {
+ try {
+ l.add((XTextRange)UnoRuntime.queryInterface(XTextRange.class,ia.getByIndex(i)));
+ } catch (Exception ex) {
+ System.err.println("Nonfatal Error in finding fillins.");
+ }
+ }
+ return l;
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ throw new IllegalArgumentException("Fatal Error: Loading template failed: searching fillins failed");
+ }
+ }
+
+ /**
+ * analyze the item sections in the template. delegates the analyze of each table to the
+ * ItemsTable class.
+ */
+ private void initializeItemsSections()
+ {
+ String[] sections = getSections(document, TemplateConsts.SECTION_ITEMS);
+
+ // for each section - there is a table...
+ itemsTables = new ItemsTable[sections.length];
+
+ for (int i = 0; i < itemsTables.length; i++) {
+ try {
+ itemsTables[i] = new ItemsTable(getSection(sections[i]), getTable(sections[i]));
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ throw new IllegalArgumentException("Fatal Error while initialilzing Template: items table in section " + sections[i]);
+ }
+ }
+
+ }
+
+ private String[] getSections(Object document, String s)
+ {
+ XTextSectionsSupplier xTextSectionsSupplier = (XTextSectionsSupplier) UnoRuntime.queryInterface(XTextSectionsSupplier.class, document);
+ String[] allSections = xTextSectionsSupplier.getTextSections().getElementNames();
+ return getNamesWhichStartWith(allSections, s);
+ }
+
+
+ Object getSection(String name) throws NoSuchElementException, WrappedTargetException
+ {
+ XTextSectionsSupplier xTextSectionsSupplier = (XTextSectionsSupplier) UnoRuntime.queryInterface(XTextSectionsSupplier.class, document);
+ return ((Any)(xTextSectionsSupplier.getTextSections().getByName(name))).getObject();
+ }
+
+ Object getTable(String name) throws NoSuchElementException, WrappedTargetException
+ {
+ XTextTablesSupplier xTextTablesSupplier = (XTextTablesSupplier) UnoRuntime.queryInterface(XTextTablesSupplier.class, document);
+ return ((Any)xTextTablesSupplier.getTextTables().getByName(name)).getObject();
+ }
+
+ /**
+ * implementation of DataAware.Listener, is
+ * called when title/date/time or location are
+ * changed.
+ */
+ public synchronized void eventPerformed(Object param) {
+ TextEvent te = (TextEvent)param;
+ String controlName = (String)Helper.getUnoPropertyValue(
+ UnoDialog2.getModel(te.Source),
+ "Name");
+ redrawTitle(controlName);
+
+ }
+
+ private synchronized void redrawTitle(String controlName) {
+ if (controlName.equals("txtTitle"))
+ writeTitle(teTitle, trTitle, agenda.cp_Title);
+ else if (controlName.equals("txtDate"))
+ writeTitle(teDate, trDate, getDateString(agenda.cp_Date));
+ else if (controlName.equals("txtTime"))
+ writeTitle(teTime, trTime, getTimeString(agenda.cp_Time));
+ else if (controlName.equals("cbLocation"))
+ writeTitle(teLocation, trLocation, agenda.cp_Location);
+ else throw new IllegalArgumentException("No such title control...");
+ }
+
+
+ private void writeTitle( TextElement te, XTextRange tr, String text) {
+ te.text = (text == null ? "" : text);
+ te.write(tr);
+ }
+ private static long DAY_IN_MILLIS = ( 24 * 60 * 60 * 1000 );
+
+ private String getDateString(String d) {
+ if (d == null || d.equals(""))
+ return "";
+
+ int date = new Integer(d).intValue();
+ calendar.clear();
+ calendar.set( date / 10000 ,
+ ( date % 10000 ) / 100 - 1 ,
+ date % 100 ) ;
+
+ long date1 = calendar.getTimeInMillis();
+ /*
+ * docNullTime and date1 are in millis, but
+ * I need a day...
+ */
+ double daysDiff = ( date1 - docNullTime ) / DAY_IN_MILLIS + 1;
+
+ return dateFormatter.convertNumberToString(dateFormat, daysDiff);
+ }
+
+ private String getTimeString(String s) {
+ if (s == null || s.equals(""))
+ return "";
+ int time = new Integer(s).intValue();
+
+ double t = ( (double) ( time / 1000000 ) / 24 ) + ( (double) ( ( time % 1000000 ) / 10000 ) / ( 24 * 60 ) );
+ return timeFormatter.convertNumberToString(timeFormat, t);
+ }
+
+
+ /* *******************************************
+ * F I N I S H
+ *********************************************/
+
+ public synchronized void finish(List topics) {
+ createMinutes(topics);
+ deleteHiddenSections();
+ textSectionHandler.removeAllTextSections();
+ }
+
+ private void deleteHiddenSections() {
+ XTextSectionsSupplier xTextSectionsSupplier = (XTextSectionsSupplier) UnoRuntime.queryInterface(XTextSectionsSupplier.class, document);
+ String[] allSections = xTextSectionsSupplier.getTextSections().getElementNames();
+ try {
+ for (int i = 0; i<allSections.length; i++) {
+ Object section = getSection(allSections[i]);
+ //Try3.showProps(section);
+ boolean visible = ((Boolean)Helper.getUnoPropertyValue(section,"IsVisible")).booleanValue();
+ if ( !visible )
+ ((XTextContent)UnoRuntime.queryInterface(XTextContent.class,section)).getAnchor().setString("");
+
+
+ }
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * create the minutes for the given topics or remove the minues section from the document.
+ * If no topics are supplied, or the user
+ * specified not to create minuts, the minutes section will be removed,
+ * @param topicsData supplies PropertyValue arrays with the values for the topics.
+ */
+ public synchronized void createMinutes(List topicsData) {
+
+ // if the minutes section should be removed (the
+ // user did not check "create minutes")
+ if (!agenda.cp_IncludeMinutes || (topicsData.size() <= 1)) {
+ try {
+ Object minutesAllSection = getSection(SECTION_MINUTES_ALL);
+ XTextSection xTextSection = (XTextSection)UnoRuntime.queryInterface(XTextSection.class,minutesAllSection);
+ xTextSection.getAnchor().setString("");
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ // the user checked "create minutes"
+ else {
+ try {
+ String itemText;
+ XTextRange item;
+ int topicStartTime = 0;
+ try {
+ topicStartTime = new Integer(agenda.cp_Time).intValue();
+ }
+ catch (Exception ex) {}
+
+ String time;
+
+ // first I replace the minutes titles...
+ List items = searchFillInItems();
+ for ( int itemIndex = 0; itemIndex < items.size(); itemIndex++) {
+ item = (XTextRange)items.get(itemIndex);
+ itemText = item.getString().trim().toLowerCase();
+
+ if ( itemText.equals( FILLIN_MINUTES_TITLE ))
+ fillMinutesItem( item , agenda.cp_Title , resources.resPlaceHolderTitle);
+ else if ( itemText.equals( FILLIN_MINUTES_LOCATION))
+ fillMinutesItem( item , agenda.cp_Location , resources.resPlaceHolderLocation);
+ else if ( itemText.equals( FILLIN_MINUTES_DATE ))
+ fillMinutesItem( item , getDateString ( agenda.cp_Date ) , resources.resPlaceHolderDate );
+ else if ( itemText.equals( FILLIN_MINUTES_TIME ))
+ fillMinutesItem( item , getTimeString ( agenda.cp_Time ) , resources.resPlaceHolderTime );
+ }
+
+ 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 new one...
+ *
+ * topics data has *always* an empty topic at the end...
+ */
+ for (int i = 0; i < topicsData.size() - 1; i++) {
+ PropertyValue[] topic = (PropertyValue[])topicsData.get(i);
+
+ items = searchFillInItems();
+ for ( int itemIndex = 0; itemIndex < items.size(); itemIndex++) {
+ item = (XTextRange)items.get(itemIndex);
+ itemText = item.getString().trim().toLowerCase();
+
+ if ( itemText.equals( FILLIN_MINUTE_NUM ))
+ fillMinutesItem( item , topic[0].Value , "");
+ else if ( itemText.equals( FILLIN_MINUTE_TOPIC ))
+ fillMinutesItem( item , topic[1].Value , "" );
+ else if ( itemText.equals( FILLIN_MINUTE_RESPONSIBLE ))
+ fillMinutesItem( item , topic[2].Value , "" );
+ else if ( itemText.equals( FILLIN_MINUTE_TIME )) {
+ int topicTime = 0;
+
+ try {
+ topicTime = (new Integer((String)topic[3].Value)).intValue();
+ }
+ catch (Exception ex) {}
+ // if the topic has no time, we do not display any time here.
+ if (topicTime == 0 || topicStartTime == 0)
+ time = (String)topic[3].Value;
+ else {
+ time = getTimeString( String.valueOf(topicStartTime) ) + " - ";
+ topicStartTime += topicTime * 10000;
+ time += getTimeString( String.valueOf(topicStartTime ) );
+ }
+ fillMinutesItem( item , time , "" );
+ }
+ }
+
+ textSectionHandler.removeTextSectionbyName( SECTION_MINUTES );
+
+ // after the last section we do not insert a new one.
+ if ( i < topicsData.size() - 2 )
+ textSectionHandler.insertTextSection( SECTION_MINUTES , template);
+
+ }
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+
+ private void fillMinutesItem(XTextRange range, Object text, String placeholder) {
+ String paraStyle = (String)Helper.getUnoPropertyValue(range,"ParaStyleName");
+ range.setString((String)text);
+ Helper.setUnoPropertyValue(range,"ParaStyleName",paraStyle);
+ if (text == null || text.equals("")) {
+ if ( placeholder!=null && !placeholder.equals("")) {
+ XTextContent placeHolder = createPlaceHolder(docMSF, placeholder, resources.resPlaceHolderHint);
+ try {
+ range.getStart().getText().insertTextContent(range.getStart(),placeHolder,true);
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ }
+ }
+
+ public static XTextContent createPlaceHolder(XMultiServiceFactory xmsf, String ph, String hint) {
+ Object placeHolder;
+ try {
+ placeHolder = xmsf.createInstance("com.sun.star.text.TextField.JumpEdit");
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ Helper.setUnoPropertyValue(placeHolder, "PlaceHolder", ph);
+ Helper.setUnoPropertyValue(placeHolder, "Hint", hint);
+ Helper.setUnoPropertyValue(placeHolder, "PlaceHolderType", new Short(PlaceholderType.TEXT));
+ return (XTextContent)UnoRuntime.queryInterface(XTextContent.class,placeHolder);
+
+ }
+
+ /*
+ * $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+ * =================================
+ * The ItemTable class
+ * =================================
+ * $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+ */
+
+
+
+ public class ItemsTable {
+
+ Object table;
+ Object section;
+
+ /**
+ * the items in the table.
+ */
+ List items = new Vector(6);
+
+
+ public ItemsTable(Object section_, Object table_) {
+
+ table = table_;
+ section = section_;
+
+ AgendaItem ai;
+ XTextRange item;
+ String iText;
+
+ /* 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.
+ */
+ for (int i = 0; i < _allItems.size(); i++) {
+ item = (XTextRange)_allItems.get(i);
+ Object t = Helper.getUnoPropertyValue(item,"TextTable");
+ if ( ( t instanceof Any ) && ((Any)t).getObject() == table) {
+ iText = item.getString().toLowerCase().trim();
+ ai = (AgendaItem)itemsCache.get(item.getString().toLowerCase().trim());
+ if (ai != null) {
+ items.add(ai);
+ _allItems.remove(i--);
+ itemsMap.put(iText,this);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * 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.
+ * @param dummy we need a param to make this an Implementation of AgendaElement.
+ * @throws Exception
+ */
+ public synchronized void write(Object dummy) throws Exception {
+ synchronized (this) {
+ String name = getName(section);
+
+ // link and unlink the section to the template.
+ textSectionHandler.linkSectiontoTemplate(section,template,name);
+ textSectionHandler.breakLinkOfTextSection(section);
+
+ // we need to get a new instance after linking.
+ table = getTable(name);
+ section = getSection(name);
+
+ XTextTable xTextTable = (XTextTable)UnoRuntime.queryInterface(XTextTable.class,table);
+ XTextTableCursor cursor = xTextTable.createCursorByCellName("A1");
+ AgendaItem ai ;
+ // should this section be visible?
+ boolean visible = false;
+
+ // write items
+ // ===========
+ String cellName = "";
+
+ /* now go through all items that belong to this
+ * table. Check each one agains the model. If it should
+ * be display, call it's 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 (int i = 0; i < items.size(); i++) {
+ ai = (AgendaItem)items.get(i);
+ if (isShowItem(ai.name)) {
+ visible = true;
+ ai.table = table;
+ ai.write(cursor);
+ // I store the cell name which was last written...
+ cellName = cursor.getRangeName();
+
+ cursor.goRight((short)1,false);
+
+ }
+ }
+
+ Helper.setUnoPropertyValue(section,"IsVisible",visible ? Boolean.TRUE : Boolean.FALSE);
+ if (!visible)
+ return;
+
+ /* remove obsolete rows
+ * ====================
+ * 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 its the last cell.
+ */
+ if (cellName.equals(cursor.getRangeName()))
+ return;
+ /*
+ * if not, we continue and clear all cells until we are at the end of the row.
+ */
+ Object cell;
+ while ( ( !cellName.equals(cursor.getRangeName()) && ( ! cursor.getRangeName().startsWith("A"))) ) {
+ cell = xTextTable.getCellByName(cursor.getRangeName());
+ ((XTextRange)UnoRuntime.queryInterface(XTextRange.class,cell)).setString("");
+ cellName = cursor.getRangeName();
+ cursor.goRight((short)1,false);
+ }
+
+ /*
+ * again: if we are at the end of the table, end here.
+ */
+ if (cellName.equals(cursor.getRangeName()))
+ return;
+
+
+ int rowIndex = getRowIndex(cursor);
+ int rowsCount = getRowCount((XTextTable)UnoRuntime.queryInterface(XTextTable.class,table));
+
+ /* now before deleteing i move the cursor up so it
+ * does not disappear, because it will crash office.
+ */
+ cursor.gotoStart(false);
+
+ if (rowsCount >= rowIndex)
+ removeTableRows(table, rowIndex - 1, ( rowsCount - rowIndex ) + 1);
+ }
+ }
+ }
+
+ /*
+ * $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+ * =================================
+ * The Topics class
+ * =================================
+ * $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+ */
+
+
+ /**
+ * 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 programttically.<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 AgendaTemplate class
+ * but for clarity and separation I decided to make a sub class for it.
+ *
+ * @author rp143992
+ */
+ public class Topics {
+ /**
+ * the topics table
+ */
+ XTextTable table;
+
+ /**
+ * A List of Cell Formatters for the first row.
+ */
+ List firstRowFormat = new Vector();
+
+ /**
+ * A List of Cell Formatters for the last row.
+ */
+ List lastRowFormat = new Vector();
+
+ //Map topicItems = new Hashtable(4);
+
+ /**
+ * the format of the cell of each topic cell.
+ */
+ List topicCellFormats = new Vector();
+
+ /**
+ * for each topic cell there is
+ * a member in this vector
+ */
+ List topicCells = new Vector();
+
+ int rowsPerTopic;
+
+ /**
+ * fields which hold the number of the
+ * fillins in the cells vectors.
+ */
+ int numCell = -1;
+ int topicCell = -1;
+ int responsibleCell = -1;
+ int timeCell = -1;
+
+ /**
+ * this is a list which traces which topics were written to the document
+ * and which not. When a cell needs to be actualized, it is checked that the
+ * whole topic is already present in the document, using this vector.
+ * The vector contains nulls for topics which were not written, and
+ * empty strings for topics which were written (though any other
+ * object would also do - i check only if it is a null or not...);
+ */
+ List writtenTopics = new Vector();
+
+
+ /**
+ * 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 seperateley.
+ */
+ public Topics()
+ {
+ Object t;
+
+ Map topicItems = new Hashtable(4);
+
+ // This is the topics table. say hallo :-)
+ try {
+ t = getTable(SECTION_TOPICS);
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ throw new IllegalArgumentException("Fatal error while loading template: table " + SECTION_TOPICS + " could not load.");
+ }
+
+ // and this is the XTable.
+ table = ((XTextTable)UnoRuntime.queryInterface(XTextTable.class,t));
+
+ /* 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.
+ */
+ Hashtable items = new Hashtable();
+
+ XTextRange item;
+ Object cell;
+ for (int i = 0; i < _allItems.size(); i++) {
+ item = (XTextRange)_allItems.get(i);
+ t = Helper.getUnoPropertyValue(item,"TextTable");
+ if ( ( t instanceof Any ) && ((Any)t).getObject() == table) {
+ cell = Helper.getUnoPropertyValue(item,"Cell");
+ items.put(((Any)cell).getObject(),item);
+ }
+ }
+
+ /*
+ * 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.
+ */
+ int rows = getRowCount(table);
+
+ rowsPerTopic= (rows - 1) / 3;
+
+ String firstCell = "A" + (1 + rowsPerTopic + 1);
+ String afterLastCell = "A" + (1 + ( rowsPerTopic * 2 ) + 1);
+
+ // go to the first row of the 2. topic
+ XTextTableCursor cursor = table.createCursorByCellName(firstCell);
+ XTextRange range;
+
+ // analyze the structure of the topic rows.
+ while ( !cursor.getRangeName().equals(afterLastCell) ) {
+ cell = table.getCellByName(cursor.getRangeName());
+ XTextRange xTextRange = (XTextRange)UnoRuntime.queryInterface(XTextRange.class,cell);
+ // first I store the content and para style of the cell
+ AgendaElement ae = new TextElement(xTextRange);
+ // if the cell contains a relevant <...>
+ // i add the text element to the hash,
+ // so it's text can be updated later.
+ range = (XTextRange)items.get(cell);
+ if (range != null) {
+ topicItems.put(xTextRange.getString().toLowerCase().trim() , ae);
+ }
+
+ topicCells.add(ae);
+
+ // and store the format of the cell.
+ topicCellFormats.add( new TableCellFormatter(table.getCellByName(cursor.getRangeName())));
+
+ // goto next cell.
+ cursor.goRight((short)1,false);
+ }
+
+ /*
+ * now - in which cell is every fillin?
+ */
+ numCell = topicCells.indexOf( topicItems.get(FILLIN_TOPIC_NUMBER));
+ topicCell = topicCells.indexOf( topicItems.get(FILLIN_TOPIC_TOPIC));
+ responsibleCell = topicCells.indexOf( topicItems.get(FILLIN_TOPIC_RESPONSIBLE));
+ timeCell = topicCells.indexOf( topicItems.get(FILLIN_TOPIC_TIME));
+
+
+
+ /* now that we know how the topics look like,
+ * we get the format of the first and last rows.
+ */
+
+ // format of first row
+ cursor.gotoStart(false);
+ do {
+ firstRowFormat.add( new TableCellFormatter(table.getCellByName(cursor.getRangeName())) );
+ cursor.goRight((short)1,false);
+ }
+ while (!cursor.getRangeName().startsWith("A"));
+
+ // format of the last row
+ cursor.gotoEnd(false);
+ while (!cursor.getRangeName().startsWith("A"))
+ {
+ lastRowFormat.add( new TableCellFormatter(table.getCellByName(cursor.getRangeName())) );
+ cursor.goLeft((short)1,false);
+ }
+ // we missed the A cell - so we have to add it also..
+ lastRowFormat.add( new TableCellFormatter(table.getCellByName(cursor.getRangeName())) );
+
+ removeTableRows(table, 1 + rowsPerTopic, rows - rowsPerTopic - 1);
+
+ }
+
+ /**
+ * @param topic the topic number to write
+ * @param data the data of the topic.
+ * @return the number of rows that have been added
+ * to the table. 0 or a negative number: no rows added.
+ */
+ private int write2(int topic, PropertyValue[] data) throws Exception {
+ while (topic >= writtenTopics.size())
+ writtenTopics.add(null);
+
+ writtenTopics.set(topic,"");
+
+ // make sure threr are enough rows for me...
+ int rows = getRowCount(table);
+ int reqRows = 1 + ( topic + 1) * rowsPerTopic;
+ int firstRow = reqRows - rowsPerTopic + 1;
+ int diff = reqRows - rows;
+ if (diff > 0)
+ insertTableRows(table,rows,diff);
+
+ // set the item's text...
+ setItemText(numCell, data[0].Value);
+ setItemText(topicCell, data[1].Value);
+ setItemText(responsibleCell, data[2].Value);
+ setItemText(timeCell, data[3].Value);
+
+ // now write !
+ XTextTableCursor cursor = table.createCursorByCellName("A" + firstRow);
+
+ for (int i = 0; i<topicCells.size(); i++) {
+ ((AgendaElement)topicCells.get(i)).write(table.getCellByName(cursor.getRangeName()));
+ cursor.goRight((short)1,false);
+ }
+
+ // now format !
+ cursor.gotoCellByName("A" + firstRow, false);
+
+ formatTable(cursor,topicCellFormats, false);
+
+ return diff;
+
+ }
+
+ /**
+ * check if the topic with the given index is written to the table.
+ * @param topic the topic number (0 base)
+ * @return true if the topic is already written to the table. False if not.
+ * (false would mean new rows must be added to the table in order to
+ * be able to write this topic).
+ */
+ private boolean isWritten(int topic) {
+ return (writtenTopics.size() > topic && writtenTopics.get(topic) != null );
+ }
+
+ /**
+ * 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, we don't reference a cell
+ * number. Rather, we use "what" argument to specify which cell should be redrawn.
+ * The Topics object, which analyzed the structure of the topics table appon
+ * initialization, refreshes the approperiate cell.
+ * @param topic index of the topic (0 based).
+ * @param what 0 for num, 1 for topic, 2 for responsible, 3 for duration
+ * @param data the row's data.
+ * @throws Exception if something goes wrong (thow nothing should)
+ */
+ public void writeCell(int topic, int what, PropertyValue[] data) throws Exception {
+ // if the whole row should be written...
+ if (!isWritten(topic))
+ write(topic,data);
+ // write only the "what" cell.
+ else {
+ // calculate the table row.
+ int firstRow = 1 + ( topic * rowsPerTopic ) + 1;
+ // go to the first cell of this topic.
+ XTextTableCursor cursor = table.createCursorByCellName("A" + firstRow);
+
+ TextElement te = null;
+ int cursorMoves = 0;
+
+ switch (what) {
+ case 0 :
+ te = setItemText(numCell, data[0].Value);
+ cursorMoves = numCell;
+ break;
+ case 1 :
+ te = setItemText(topicCell, data[1].Value);
+ cursorMoves = topicCell;
+ break;
+ case 2 :
+ te = setItemText(responsibleCell, data[2].Value);
+ cursorMoves = responsibleCell;
+ break;
+ case 3 :
+ te = setItemText(timeCell, data[3].Value);
+ cursorMoves = timeCell;
+ break;
+ }
+ // move the cursor to the needed cell...
+ cursor.goRight((short)cursorMoves, false);
+ XCell xc = table.getCellByName(cursor.getRangeName());
+ // and write it !
+ te.write(xc);
+ ((TableCellFormatter)topicCellFormats.get(cursorMoves)).format(xc);
+
+ }
+ }
+
+
+ /**
+ * writes the given topic.
+ * if the first topic was involved, reformat the
+ * first row.
+ * If any rows were added to the table, reformat
+ * the last row.
+ * @param topic the index of the topic to write.
+ * @param data the topic's data. (see TopicsControl
+ * for explanation about the topics data model)
+ * @throws Exception if something goes wrong (though nothing should).
+ */
+ public void write(int topic, PropertyValue[] data) throws Exception {
+ int diff = write2(topic, data);
+ /* if the first topic has been written,
+ * one needs to reformat the first row.
+ */
+ if (topic == 0) {
+ formatFirstRow();
+ }
+ /*
+ * if any rows were added, one needs to format
+ * the whole table again.
+ */
+ if ( diff > 0 ) {
+ formatLastRow();
+ }
+ }
+
+ /**
+ * Writes all the topics to thetopics table.
+ * @param topicsData a List containing all Topic's Data.
+ */
+ public void writeAll(List topicsData){
+ try {
+ for (int i = 0; i < topicsData.size() - 1; i++)
+ write2(i, (PropertyValue[])topicsData.get(i) );
+ formatLastRow();
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+
+ /**
+ * 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 actuall topics it does *not* add
+ * new rows !
+ * Note also that the first topic will never be removed.
+ * If the table contains no topics, the whole section will
+ * be removed uppon 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
+ */
+ public void reduceDocumentTo(int topics) throws Exception {
+ // we never remove the first topic...
+ if (topics <= 0)
+ topics = 1;
+ XTableRows tableRows = table.getRows();
+ int targetNumOfRows = topics * rowsPerTopic + 1;
+ if (tableRows.getCount() > targetNumOfRows)
+ tableRows.removeByIndex(targetNumOfRows , tableRows.getCount() - targetNumOfRows );
+ formatLastRow();
+ while ( writtenTopics.size() > topics )
+ writtenTopics.remove(topics);
+ }
+
+ /**
+ * reapply the format of the first (header) row.
+ */
+ private void formatFirstRow() {
+ XTextTableCursor cursor = table.createCursorByCellName("A1");
+ formatTable(cursor,firstRowFormat, false );
+ }
+
+ /**
+ * reaply the format of the last row.
+ */
+ private void formatLastRow() {
+ XTextTableCursor cursor = table.createCursorByCellName("A1");
+ cursor.gotoEnd(false);
+ formatTable(cursor,lastRowFormat, true);
+ }
+
+ /**
+ * returns a text element for the given cell,
+ * which will write the given text.
+ * @param cell the topics cell number.
+ * @param value the value to write.
+ * @return a TextElement object which will write the given value
+ * to the given cell.
+ */
+ private TextElement setItemText(int cell, Object value) {
+ if (cell >= 0) {
+ TextElement te = ((TextElement)topicCells.get(cell));
+ if (te != null)
+ te.text = value.toString();
+ return te;
+ }
+ return null;
+ }
+
+ /**
+ * formats a series of cells from the given one,
+ * using the given List of TableCellFormatter objects,
+ * in the given order.
+ * This method is used to format the first (header) and the last
+ * rows of the table.
+ * @param cursor a table cursor, pointing to the start cell to format
+ * @param formats a List containing TableCellFormatter objects. Each will format one cell in the direction specified.
+ * @param reverse if true the cursor will move left, formatting in reverse order (used for the last row).
+ */
+ private void formatTable(XTextTableCursor cursor, List formats, boolean reverse) {
+ for ( int i = 0; i < formats.size() ; i++ ) {
+ ((TableCellFormatter)formats.get(i)).format(table.getCellByName(cursor.getRangeName()));
+ if (reverse)
+ cursor.goLeft((short)1,false);
+ else
+ cursor.goRight((short)1,false);
+ }
+ }
+
+
+ }
+
+
+ /*
+ * =================================
+ * Here are some static help methods
+ * =================================
+ */
+
+ public static String[] getNamesWhichStartWith(String[] allNames, String prefix)
+ {
+ Vector v = new Vector();
+ for (int i = 0; i < allNames.length; i++)
+ if (allNames[i].startsWith(prefix))
+ v.add(allNames[i]);
+ String[] s = new String[v.size()];
+ System.arraycopy(v.toArray(), 0, s, 0, s.length);
+ return s;
+ }
+
+ /**
+ * Convenience method, costs the given object to an XNamed, and returnes its name.
+ * @param obj an XNamed object.
+ * @return the name of the given object.
+ */
+ public static String getName(Object obj) {
+ return ((XNamed)UnoRuntime.queryInterface(XNamed.class,obj)).getName();
+ }
+
+ /**
+ * convenience method, for removing a number of cells from a table.
+ * @param table
+ * @param start
+ * @param count
+ */
+ public static void removeTableRows(Object table, int start, int count) {
+ XTableRows rows = ((XTextTable)UnoRuntime.queryInterface(XTextTable.class,table)).getRows();
+ rows.removeByIndex(start, count);
+ }
+
+ /**
+ * Convenience method for inserting some cells into a table.
+ * @param table
+ * @param start
+ * @param count
+ */
+ public static void insertTableRows(Object table, int start, int count) {
+ XTableRows rows = ((XTextTable)UnoRuntime.queryInterface(XTextTable.class,table)).getRows();
+ rows.insertByIndex(start, count);
+ }
+
+ /**
+ * returns the row index for this cursor, assuming
+ * the cursor points to a single cell.
+ * @param cursor
+ * @return the row index in which the cursor is.
+ */
+ public static int getRowIndex(XTextTableCursor cursor) {
+ return getRowIndex(cursor.getRangeName());
+ }
+
+ /**
+ * returns the row index for this cell name.
+ * @param cellName
+ * @return the row index for this cell name.
+ */
+ public static int getRowIndex(String cellName) {
+ return Integer.parseInt(cellName.substring(1));
+ }
+
+ /**
+ * returns the rows count of this table, assuming
+ * there is no vertical merged cells.
+ * @param table
+ * @return the rows count of the given table.
+ */
+ public static int getRowCount(XTextTable table) {
+ String[] cells = table.getCellNames();
+ return getRowIndex(cells[cells.length-1]);
+ }
+
+}
+
+/*
+ * ===========================================================================================
+ *
+ * End of AgendaTempalte class
+ *
+ * ===========================================================================================
+ *
+ */
+
+
+/*
+ * =================================
+ * The AgendaElement interface
+ * =================================
+ */
+
+/**
+ * Interface that is used for writing content to a Uno Text / TextRange
+ * @author rp143992
+ *
+ */
+interface AgendaElement
+{
+ void write(Object any) throws Exception;
+
+}
+
+
+/*
+ * =================================
+ * The ParaStyled class
+ * =================================
+ */
+
+
+/**
+ * Basic implementation of the AgendaElement interface -
+ * writes nothing, but applies a ParaStyle to the given XText/XTextRange
+ * @author rp143992
+ *
+ * TODO To change the template for this generated type comment go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+class ParaStyled implements AgendaElement {
+ String paraStyle;
+
+ ParaStyled(String paraStyle_) {
+ paraStyle = paraStyle_;
+ }
+
+ void format(Object textRange) {
+ XText o;
+ o = ((XText)UnoRuntime.queryInterface(XText.class,textRange));
+ if (o == null)
+ o = ((XTextRange)UnoRuntime.queryInterface(XTextRange.class,textRange)).getText();
+ Object cursor = o.createTextCursor();
+ Helper.setUnoPropertyValue(cursor, "ParaStyleName", paraStyle);
+ }
+
+ public void write(Object textRange) {
+ format(textRange);
+ }
+
+}
+
+/*
+ * =================================
+ * The TextElement class
+ * =================================
+ */
+
+/**
+ * A basic implementation of AgendaElement:
+ * writes a String to the given XText/XTextRange, and applies
+ * a ParaStyle to it (using the parent class).
+ * @author rp143992
+ */
+ class TextElement extends ParaStyled {
+ String text;
+
+ TextElement(XTextRange range) {
+ this( range.getString() , (String) Helper.getUnoPropertyValue( range.getStart(), "ParaStyleName"));
+ }
+
+ TextElement(String text_, String paraStyle_) {
+ super(paraStyle_);
+ text= text_;
+ }
+
+ public void write(Object textRange) {
+ ((XTextRange)UnoRuntime.queryInterface(XTextRange.class,textRange)).setString(text);
+ if (!text.equals(""))
+ super.write(textRange);
+ }
+}
+
+
+/**
+ * A Text element which, if the text to write is empty (null or "")
+ * inserts a placeholder instead.
+ * @author rp143992
+ *
+ * TODO To change the template for this generated type comment go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+class PlaceholderTextElement extends TextElement {
+ String hint;
+ String placeHolderText;
+ XMultiServiceFactory xmsf;
+
+ PlaceholderTextElement(XTextRange textRange, String placeHolderText_, String hint_, XMultiServiceFactory xmsf_) {
+ super(textRange);
+ placeHolderText = placeHolderText_;
+ hint = hint_;
+ xmsf = xmsf_;
+ }
+
+ PlaceholderTextElement(String text, String paraStyle, String placeHolderText_, String hint_, XMultiServiceFactory xmsf_) {
+ super(text,paraStyle);
+ placeHolderText = placeHolderText_;
+ hint = hint_;
+ xmsf = xmsf_;
+ }
+
+ public void write(Object textRange) {
+ super.write(textRange);
+ if (text == null || text.equals("")) {
+ XTextRange xTextRange = (XTextRange)UnoRuntime.queryInterface(XTextRange.class,textRange);
+ try {
+ XTextContent xTextContent = AgendaTemplate.createPlaceHolder(xmsf,placeHolderText, hint);
+ xTextRange.getText().insertTextContent(xTextRange.getStart(), xTextContent, true);
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+}
+
+
+
+/*
+ * =================================
+ * The PlaceHolder class
+ * =================================
+ */
+
+
+/**
+ * An Agenda element which writes no text, but inserts a placeholder, and formats
+ * it using a ParaStyleName.
+ * @author rp143992
+ *
+ */
+class PlaceholderElement extends ParaStyled {
+ String hint;
+ String placeHolderText;
+ XMultiServiceFactory xmsf;
+
+ PlaceholderElement(String paraStyle, String placeHolderText_, String hint_, XMultiServiceFactory xmsf_) {
+ super(paraStyle);
+ placeHolderText = placeHolderText_;
+ hint = hint_;
+ xmsf = xmsf_;
+ }
+
+ public void write(Object textRange) {
+ XTextRange xTextRange = (XTextRange)UnoRuntime.queryInterface(XTextRange.class,textRange);
+ try {
+ XTextContent xTextContent = AgendaTemplate.createPlaceHolder(xmsf,placeHolderText, hint);
+ xTextRange.getText().insertTextContent(xTextRange.getStart(), xTextContent, true);
+ super.write(textRange);
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+}
+
+
+/*
+ * =================================
+ * The AgendaItem class
+ * =================================
+ */
+
+/**
+ * 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.
+ * @author rp143992
+ *
+ * TODO To change the template for this generated type comment go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+
+class AgendaItem implements AgendaElement {
+ TextElement textElement;
+ AgendaElement field;
+ public Object table;
+ String name;
+
+ AgendaItem(String name_, TextElement te, AgendaElement f) {
+ name = name_;
+ field = f;
+ textElement = te;
+ }
+
+ public void write(Object tableCursor) throws Exception {
+ XTextTableCursor xTextTableCursor = (XTextTableCursor)UnoRuntime.queryInterface(XTextTableCursor.class,tableCursor);
+ XTextTable xTextTable = (XTextTable)UnoRuntime.queryInterface(XTextTable.class,table);
+
+ String cellname = xTextTableCursor.getRangeName();
+ Object cell = xTextTable.getCellByName(cellname);
+
+ textElement.write(cell);
+
+ xTextTableCursor.goRight((short)1,false);
+
+ //second field is actually always null...
+ // this is a preparation for adding placeholders.
+ if (field!= null)
+ field.write(xTextTable.getCellByName(xTextTableCursor.getRangeName()));
+
+
+ }
+}
+
+/*
+ * =================================
+ * The TableCellFormatter class
+ * =================================
+ */
+
+/**
+ * reads/write a table cell format from/to a table cell or a group of cells.
+ *
+ */
+class TableCellFormatter {
+ static String[] properties = new String[] {
+ "BackColor",
+ "BackTransparent",
+ "BorderDistance",
+ "BottomBorder",
+ "BottomBorderDistance",
+ "LeftBorder",
+ "LeftBorderDistance",
+ "RightBorder",
+ "RightBorderDistance",
+ "TopBorder",
+ "TopBorderDistance"
+ };
+
+ private Object[] values = new Object[properties.length];
+
+ public TableCellFormatter(Object tableCell) {
+ for (int i = 0; i<properties.length; i++)
+ values[i] = Helper.getUnoPropertyValue(tableCell,properties[i]);
+ }
+
+ public void format(Object tableCell) {
+ Helper.setUnoPropertyValues(tableCell,properties,values);
+ }
+}
+
+
+
+