diff options
author | Oliver Bolte <obo@openoffice.org> | 2004-09-08 12:58:28 +0000 |
---|---|---|
committer | Oliver Bolte <obo@openoffice.org> | 2004-09-08 12:58:28 +0000 |
commit | 009b1d22aecc4e7426318ee5710179c79238ca2e (patch) | |
tree | 6ae8d14f6838fd055fcc00f683ed607262c172fd /wizards/com/sun/star/wizards/agenda | |
parent | 61788feacb1d768de1c0a4d2155f114db55eb7ad (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.java | 1792 |
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 >xxx< 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 ">*<" + * @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); + } +} + + + + |