xref: /aoo41x/main/odk/examples/java/ToDo/ToDo.java (revision cdf0e10c)
1 /*************************************************************************
2  *
3  *  The Contents of this file are made available subject to the terms of
4  *  the BSD license.
5  *
6  *  Copyright 2000, 2010 Oracle and/or its affiliates.
7  *  All rights reserved.
8  *
9  *  Redistribution and use in source and binary forms, with or without
10  *  modification, are permitted provided that the following conditions
11  *  are met:
12  *  1. Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *  2. Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *  3. Neither the name of Sun Microsystems, Inc. nor the names of its
18  *     contributors may be used to endorse or promote products derived
19  *     from this software without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  *************************************************************************/
34 
35 import com.sun.star.lib.uno.helper.Factory;
36 import com.sun.star.lang.XInitialization;
37 import com.sun.star.lang.XMultiComponentFactory;
38 import com.sun.star.lang.XSingleComponentFactory;
39 import com.sun.star.lang.XMultiServiceFactory;
40 import com.sun.star.lang.XServiceInfo;
41 import com.sun.star.lang.XTypeProvider;
42 import com.sun.star.lib.uno.helper.WeakBase;
43 import com.sun.star.registry.XRegistryKey;
44 import com.sun.star.uno.Type;
45 import com.sun.star.uno.UnoRuntime;
46 import com.sun.star.uno.XInterface;
47 import com.sun.star.uno.XWeak;
48 import com.sun.star.uno.XComponentContext;
49 import org.openoffice.*;
50 
51 // addintional interfaces used by the implementation
52 import com.sun.star.sheet.XSpreadsheetDocument;
53 import com.sun.star.sheet.XSpreadsheet;
54 import com.sun.star.sheet.XCellRangeMovement;
55 import com.sun.star.sheet.XFunctionAccess;
56 import com.sun.star.container.XIndexAccess;
57 import com.sun.star.table.XCellRange;
58 import com.sun.star.table.XCell;
59 import com.sun.star.table.CellAddress;
60 import com.sun.star.table.CellRangeAddress;
61 import com.sun.star.table.XColumnRowRange;
62 import com.sun.star.table.XTableRows;
63 import com.sun.star.beans.XPropertySet;
64 import com.sun.star.text.XTextRange;
65 import com.sun.star.text.XSimpleText;
66 import com.sun.star.text.XTextCursor;
67 import com.sun.star.text.XText;
68 import com.sun.star.text.XTextField;
69 
70 import java.util.GregorianCalendar;
71 import java.util.Calendar;
72 import java.util.Vector;
73 import java.util.Arrays;
74 
75 /** This class capsulates the class, that implements the minimal component, a
76  * factory for creating the service (<CODE>__getServiceFactory</CODE>) and a
77  * method, that writes the information into the given registry key
78  * (<CODE>__writeRegistryServiceInfo</CODE>).
79  */
80 public class ToDo {
81 
82     /** This class implements the component. At least the interfaces
83      * XInterface, XTypeProvider, and XWeak implemented by the helper class
84      * WeakBase and XServiceInfo should be provided by the service.
85      */
86     public static class ToDoImpl extends WeakBase implements XServiceInfo, XToDo {
87 
88         /** The service name, that must be used to get an instance of this service.
89          */
90         private static final String __serviceName = "org.openoffice.ToDo";
91 
92         /** The initial component contextr, that gives access to
93          * the service manager, supported singletons, ...
94          * It's often later used
95          */
96         private XComponentContext m_cmpCtx;
97 
98         /** The service manager, that gives access to all registered services.
99          * It's often later used
100          */
101         private XMultiComponentFactory m_xMCF;
102 
103         // Implementation helper variables
104         static private final int INT_COLUMN_FEATURE = 0;
105         static private final int INT_COLUMN_COMMENT = 1;
106         static private final int INT_COLUMN_NEEDEDDAYS = 2;
107         static private final int INT_COLUMN_STARTDATE = 3;
108         static private final int INT_COLUMN_START_DAY_OF_WEEK = 4;
109         static private final int INT_COLUMN_ENDDATE = 5;
110         static private final int INT_COLUMN_END_DAY_OF_WEEK = 6;
111         static private final int INT_COLUMN_DUEDATE = 7;
112         static private final int INT_COLUMN_STATUS = 8;
113 
114         static private final int INT_ROW_FROM = 14; // 8
115 
116         static private final int INT_ROW_HOLIDAYS_START = 4;
117         static private final int INT_COLUMN_HOLIDAYS_START = 7; // 10
118 
119         static private final String STRING_SEPARATOR = "/";
120 
121 
122         /** The constructor of the inner class has a XComponenContext parameter.
123          * @param xCompContext the initial component context
124          */
125         public ToDoImpl(XComponentContext xCompContext) {
126             try {
127                 m_cmpCtx = xCompContext;
128                 m_xMCF = m_cmpCtx.getServiceManager();
129             }
130             catch( Exception e ) {
131                 e.printStackTrace(System.err);
132             }
133         }
134 
135         /** This method returns an array of all supported service names.
136          * @return Array of supported service names.
137          */
138         public String[] getSupportedServiceNames() {
139             return getServiceNames();
140         }
141 
142         public static String[] getServiceNames() {
143             String[] sSupportedServiceNames = { __serviceName };
144             return sSupportedServiceNames;
145         }
146 
147         /** This method returns true, if the given service will be
148          * supported by the component.
149          * @param sService Service name.
150          * @return True, if the given service name will be supported.
151          */
152         public boolean supportsService(String sServiceName) {
153             return sServiceName.equals( __serviceName );
154         }
155 
156         /** Return the class name of the component.
157          * @return Class name of the component.
158          */
159         public String getImplementationName() {
160             return ToDoImpl.class.getName();
161         }
162 
163         /** For every bug/feature listed in a spreadsheet document this method
164          * calculates the start date, day of week of the start date, the end date
165          * and the day of week of the end date. All calculations are dependent
166          * on the values of "Needed Days", "Due Date" and "Status". The columns
167          * "Needed Days" and "Status" are mandatory. The first feature/bug should
168          * be placed in row nine. The date to start the calculation should be
169          * placed in cell C6. The private holidays should be placed in cell K4/K5
170          * and below. All rows will be calculated up to the first empty cell in
171          * the first column. If a cell in the column "Due Date" will be colored
172          * red, you should take a look at your entries.
173          * @param aInstance Spreadsheet document.
174          * @throws com.sun.star.uno.RuntimeException This exception could occur
175          *                                           at every interface method.
176          */
177         public void recalc( java.lang.Object aInstance )
178             throws com.sun.star.uno.RuntimeException {
179             try {
180                 // Querying for the interface XSpreadsheetDocument
181                 XSpreadsheetDocument xspreadsheetdocument =
182                     ( XSpreadsheetDocument ) UnoRuntime.queryInterface(
183                         XSpreadsheetDocument.class, aInstance );
184 
185                 // Querying for the interface XIndexAccess
186                 XIndexAccess xindexaccess = ( XIndexAccess )
187                     UnoRuntime.queryInterface( XIndexAccess.class,
188                                                xspreadsheetdocument.getSheets() );
189 
190                 // Getting the first XSpreadsheet
191                 XSpreadsheet xspreadsheet = (XSpreadsheet)UnoRuntime.queryInterface(
192                     XSpreadsheet.class, xindexaccess.getByIndex( 0 ));
193 
194                 // Querying for the interface XCellRange on the XSpeadsheet
195                 XCellRange xcellrange = ( XCellRange )
196                 UnoRuntime.queryInterface( XCellRange.class, xspreadsheet );
197 
198                 /* Getting the gregorian calendar with the date on which to start
199                    the calculation */
200                 GregorianCalendar gregCalAbsoluteStartDate =
201                     this.getGregorianCalendarFromString(this.getStringFromCell(
202                                                             xcellrange, 5, 2 ) );
203                 gregCalAbsoluteStartDate.add( Calendar.DATE, -1 );
204 
205                 // Set the start date with the absolute start date
206                 GregorianCalendar gregCalStartDate =
207                 (GregorianCalendar) gregCalAbsoluteStartDate.clone();
208 
209                 /* Creating the service FunctionAccess, which allows generic
210                    access to all spreadsheet functions */
211                 Object objectFunctionAccess =
212                     m_xMCF.createInstanceWithContext(
213                         "com.sun.star.sheet.FunctionAccess", m_cmpCtx );
214 
215                 // Querying for the interface XFunctionAccess on service
216                 // FunctionAccess
217                 XFunctionAccess xfunctionaccess = (XFunctionAccess)
218                     UnoRuntime.queryInterface(XFunctionAccess.class,
219                                               objectFunctionAccess );
220 
221                 // Creating vector for holidays
222                 Vector vectorHolidays = new Vector();
223 
224                 // Get the Official Holidays
225                 this.getOfficialHolidays( vectorHolidays, xcellrange,
226                                           xfunctionaccess,
227                                           gregCalStartDate.get(
228                                               Calendar.YEAR ) );
229 
230                 // Get the private holidays
231                 this.getPrivateHolidays(vectorHolidays, xcellrange,
232                                         xfunctionaccess);
233 
234                 // Getting the object array of holidays
235                 Object[] objectSortedHolidays = vectorHolidays.toArray();
236 
237                 // Sorting the holidays
238                 Arrays.sort( objectSortedHolidays );
239 
240                 // Collect the Official Holidays and the private holidays
241                 Object [][]objectHolidays =
242                 new Object[][] { objectSortedHolidays };
243 
244                 // Row index
245                 int intRowTo = this.INT_ROW_FROM - 1;
246 
247                 // Getting the feature of the first cell
248                 String sFeature = this.getStringFromCell(xcellrange,
249                                                          intRowTo + 1,
250                                                          this.INT_COLUMN_FEATURE);
251 
252                 // Determine the last row with an entry in the first column
253                 while ( ( sFeature != null ) &&
254                         ( !sFeature.equals( "" ) ) ) {
255                     intRowTo++;
256                     sFeature = this.getStringFromCell( xcellrange,
257                     intRowTo + 1, this.INT_COLUMN_FEATURE );
258                 }
259 
260                 // Setting the last row to be calculated
261                 final int INT_ROW_TO = intRowTo + 1;
262 
263                 // Deleting cells which will be recalculated
264                 for ( int intRow = this.INT_ROW_FROM; intRow < INT_ROW_TO + 5;
265                       intRow++ ) {
266                     for ( int intColumn = this.INT_COLUMN_STARTDATE;
267                           intColumn <= this.INT_COLUMN_END_DAY_OF_WEEK;
268                           intColumn++ ) {
269                         this.setStringToCell(xcellrange, intRow, intColumn, "");
270                     }
271                 }
272 
273                 /* Clearing the background color of the due date cells and setting
274                    the hyperlink to the bugtracker */
275                 for (int intRow = this.INT_ROW_FROM; intRow < INT_ROW_TO; intRow++)
276                 {
277                     // Querying for the interface XPropertySet for the cell
278                     // providing the due date
279                     XPropertySet xpropertyset = ( XPropertySet )
280                         UnoRuntime.queryInterface(XPropertySet.class,
281                                                   xcellrange.getCellByPosition(
282                                                       this.INT_COLUMN_DUEDATE,
283                                                       intRow ));
284 
285                     // Changing the background color of the cell to white
286                     xpropertyset.setPropertyValue( "CellBackColor",
287                     new Integer( 16777215 ) );
288 
289                     // Getting the cell of the bug id
290                     XCell xcell = xcellrange.getCellByPosition(
291                     this.INT_COLUMN_FEATURE, intRow );
292 
293                     // Querying for the interface XSimpleText
294                     XSimpleText xsimpletext = ( XSimpleText )
295                     UnoRuntime.queryInterface( XSimpleText.class, xcell );
296 
297                     // Getting the text cursor
298                     XTextCursor xtextcursor = xsimpletext.createTextCursor();
299 
300                     // Querying for the interface XTextRange
301                     XTextRange xtextrange = ( XTextRange )
302                     UnoRuntime.queryInterface( XTextRange.class, xtextcursor );
303 
304                     // Getting the bug ID from the cell
305                     String sBugID = xtextrange.getString();
306                     if ( !sBugID.startsWith(
307                              "http://www.openoffice.org/issues/show_bug.cgi?id=") ) {
308                         String sBugIDLink =
309                             "http://www.openoffice.org/issues/show_bug.cgi?id=" + sBugID;
310 
311                         // Querying for the interface XMultiServiceFactory
312                         XMultiServiceFactory xMSFTextField =
313                             (XMultiServiceFactory)UnoRuntime.queryInterface(
314                                 XMultiServiceFactory.class, aInstance );
315 
316                         // Creating an instance of the text field URL
317                         Object objectTextField =
318                             xMSFTextField.createInstance(
319                                 "com.sun.star.text.TextField.URL" );
320 
321                         // Querying for the interface XTextField
322                         XTextField xtextfield = ( XTextField )
323                             UnoRuntime.queryInterface( XTextField.class,
324                                                        objectTextField );
325 
326                         // Querying for the interface XPropertySet
327                         XPropertySet xpropertysetTextField = ( XPropertySet )
328                             UnoRuntime.queryInterface( XPropertySet.class,
329                                                        xtextfield );
330 
331                         // Setting the URL
332                         xpropertysetTextField.setPropertyValue( "URL",
333                                                                 sBugIDLink );
334 
335                         // Setting the representation of the URL
336                         xpropertysetTextField.setPropertyValue( "Representation",
337                                                                 sBugID );
338 
339                         // Querying for the interface XText
340                         XText xtext = ( XText )UnoRuntime.queryInterface(
341                             XText.class, xcell );
342 
343                         // Delete cell content
344                         xtextrange.setString( "" );
345 
346                         // Inserting the text field URL to the cell
347                         xtext.insertTextContent( xtextrange, xtextfield, false );
348                     }
349                 }
350 
351                 // Processing all features/bugs in the table
352                 for (int intRow = this.INT_ROW_FROM; intRow < INT_ROW_TO; intRow++)
353                 {
354                     // Getting the cell of the column "Needed Days" in the
355                     // current row
356                     XCell xcell = xcellrange.getCellByPosition(
357                         INT_COLUMN_NEEDEDDAYS, intRow );
358 
359                     // Getting the number of needed days to perform the feature
360                     int intNeededDays = (int) Math.round( xcell.getValue() );
361 
362                     // Getting the content of a specified cell
363                     String sStatus = this.getStringFromCell( xcellrange,
364                     intRow, this.INT_COLUMN_STATUS );
365 
366                     /* Testing if the number of needed days is greater than
367                        zero and if
368                        the status is not "done" */
369                     if ( ( intNeededDays > 0 )
370                          && !( sStatus.toLowerCase().trim().equals("done")) ) {
371                         // Getting the start date after a specified number of
372                         // workdays
373                         gregCalStartDate = this.getWorkday(
374                             gregCalStartDate, 1, objectHolidays,
375                             xfunctionaccess );
376 
377                         // Getting a string with the date format jjjj-mm-dd from
378                         // the gregorian calendar
379                         String sDate = this.getStringFromGregorianCalendar(
380                             gregCalStartDate );
381 
382                         // Set the start date in the specified cell of the table
383                         this.setStringToCell(xcellrange, intRow,
384                                              this.INT_COLUMN_STARTDATE, sDate);
385 
386                         // For the start day set the day of week in the specified
387                         // cell of the table
388                         this.setDayOfWeek( gregCalStartDate,
389                                            xcellrange, intRow,
390                                            this.INT_COLUMN_START_DAY_OF_WEEK );
391 
392                         // Getting the end date after a specified number of workdays
393                         GregorianCalendar gregCalEndDate =
394                             this.getWorkday( gregCalStartDate,
395                                              intNeededDays - 1,
396                                              objectHolidays, xfunctionaccess );
397 
398                         // Creating a string with the date format jjjj-mm-dd
399                         sDate = this.getStringFromGregorianCalendar(
400                             gregCalEndDate );
401 
402                         // Set the end date in the specified cell of the table
403                         this.setStringToCell( xcellrange, intRow,
404                                               this.INT_COLUMN_ENDDATE, sDate );
405 
406                         // For the end day set the day of week in the specified
407                         // cell of the table
408                         this.setDayOfWeek(gregCalEndDate, xcellrange,
409                                           intRow, this.INT_COLUMN_END_DAY_OF_WEEK);
410 
411                         // Set the initial date for the next loop
412                         gregCalStartDate = ( GregorianCalendar )
413                             gregCalEndDate.clone();
414 
415                         // Get the due date from the table
416                         String sDueDate = this.getStringFromCell(
417                             xcellrange, intRow, this.INT_COLUMN_DUEDATE );
418 
419                         // Testing if the due date is not empty
420                         if ( !sDueDate.equals( "" ) ) {
421                             GregorianCalendar gregCalDueDate =
422                                 this.getGregorianCalendarFromString(sDueDate);
423 
424                             // Testing if the due date is before the calculated
425                             // end date
426                             if ( gregCalDueDate.before(
427                                      gregCalEndDate ) ) {
428                                 /* Getting the date when the processing of the
429                                    feature/bug should
430                                    be started at the latest */
431                                 GregorianCalendar gregCalLatestDateToStart =
432                                     this.getWorkday(gregCalDueDate,
433                                                     -( intNeededDays - 1 ),
434                                                     objectHolidays,
435                                                     xfunctionaccess);
436 
437                                 // Begin with the current row
438                                 int intRowToInsert = intRow;
439 
440                                 // Get the start date for the feature/bug in the
441                                 // current row
442                                 GregorianCalendar gregCalPreviousStartDate =
443                                     this.getGregorianCalendarFromString(
444                                         this.getStringFromCell(
445                                             xcellrange, intRowToInsert,
446                                             this.INT_COLUMN_STARTDATE ) );
447 
448                                 // Testing if we have to search for an earlier date
449                                 // to begin
450                                 while ((gregCalLatestDateToStart.before(
451                                             gregCalPreviousStartDate)) &&
452                                         (INT_ROW_FROM != intRowToInsert)) {
453                                     // Decrease the row
454                                     intRowToInsert--;
455 
456                                     // Get the start date for the feature/bug in
457                                     // the current row
458                                     String sStartDate = this.getStringFromCell(
459                                         xcellrange, intRowToInsert,
460                                         this.INT_COLUMN_STARTDATE );
461 
462                                     // Search until a valid start date is found
463                                     while ( sStartDate.equals( "" ) ) {
464                                         // Decrease the row
465                                         intRowToInsert--;
466 
467                                         // Get the start date for the feature/bug
468                                         // in the current row
469                                         sStartDate = this.getStringFromCell(
470                                             xcellrange, intRowToInsert,
471                                             this.INT_COLUMN_STARTDATE );
472                                     }
473 
474                                     // Get the GregorianCalender format for the
475                                     // start date
476                                     gregCalPreviousStartDate =
477                                         this.getGregorianCalendarFromString(
478                                             sStartDate );
479                                 }
480 
481                                 // Getting the cell of the column "Needed Days"
482                                 // in the row where to insert
483                                 XCell xcellNeededDaysWhereToInsert =
484                                     xcellrange.getCellByPosition(
485                                         INT_COLUMN_NEEDEDDAYS, intRowToInsert );
486                                 // Getting the number of needed days to perform
487                                 // the feature
488                                 int intNeededDaysWhereToInsert = (int)
489                                     Math.round(
490                                         xcellNeededDaysWhereToInsert.getValue());
491 
492                                 GregorianCalendar gregCalPreviousNewEndDate =
493                                     this.getWorkday(gregCalPreviousStartDate,
494                                                     intNeededDays - 1 +
495                                                     intNeededDaysWhereToInsert,
496                                                     objectHolidays,
497                                                     xfunctionaccess);
498                                 String sPreviousDueDate = this.getStringFromCell(
499                                     xcellrange, intRowToInsert,
500                                     this.INT_COLUMN_DUEDATE );
501 
502                                 GregorianCalendar gregCalPreviousDueDate = null;
503 
504                                 if ( !sPreviousDueDate.equals( "" ) ) {
505                                     gregCalPreviousDueDate =
506                                         this.getGregorianCalendarFromString(
507                                             sPreviousDueDate );
508                                 }
509 
510                                 if ( ( intRowToInsert == intRow ) ||
511                                      ( gregCalPreviousNewEndDate.after(
512                                          gregCalPreviousDueDate ) ) ) {
513                                     // Querying for the interface XPropertySet for
514                                     // the cell providing the due date
515                                     XPropertySet xpropertyset = ( XPropertySet )
516                                         UnoRuntime.queryInterface(
517                                             XPropertySet.class,
518                                             xcellrange.getCellByPosition(
519                                                 this.INT_COLUMN_DUEDATE,
520                                                 intRow ) );
521 
522                                     // Changing the background color of the cell
523                                     // to red
524                                     xpropertyset.setPropertyValue(
525                                         "CellBackColor", new Integer( 16711680 ) );
526                                 } else {
527                                     // Querying for the interface XColumnRowRange
528                                     // on the XCellRange
529                                     XColumnRowRange xcolumnrowrange =
530                                         ( XColumnRowRange)UnoRuntime.queryInterface(
531                                             XColumnRowRange.class, xcellrange );
532                                     // Inserting one row to the table
533                                     XTableRows xTableRows =
534                                         xcolumnrowrange.getRows();
535                                     xTableRows.insertByIndex( intRowToInsert, 1 );
536 
537                                     // Querying for the interface
538                                     // XCellRangeMovement on XCellRange
539                                     XCellRangeMovement xcellrangemovement =
540                                       (XCellRangeMovement)UnoRuntime.queryInterface(
541                                           XCellRangeMovement.class, xcellrange );
542 
543                                     // Creating the cell address of the destination
544                                     CellAddress celladdress = new CellAddress();
545                                     celladdress.Sheet = 0;
546                                     celladdress.Column = 0;
547                                     celladdress.Row = intRowToInsert;
548 
549                                     // Creating the cell range of the source
550                                     CellRangeAddress cellrangeaddress =
551                                     new CellRangeAddress();
552                                     cellrangeaddress.Sheet = 0;
553                                     cellrangeaddress.StartColumn = 0;
554                                     cellrangeaddress.StartRow = intRow + 1;
555                                     cellrangeaddress.EndColumn = 8;
556                                     cellrangeaddress.EndRow = intRow + 1;
557 
558                                     // Moves the cell range to another position in
559                                     // the document
560                                     xcellrangemovement.moveRange(celladdress,
561                                                                  cellrangeaddress);
562 
563                                     // Removing the row not needed anymore
564                                     xcolumnrowrange.getRows().removeByIndex(intRow
565                                                                             + 1, 1);
566 
567                                     // Set the current row, because we want to
568                                     // recalculate all rows below
569                                     intRow = intRowToInsert - 1;
570 
571                                     // Tests at which line we want to insert
572                                     if ( intRow >= this.INT_ROW_FROM ) {
573                                         // Get the start date
574                                         gregCalStartDate =
575                                             this.getGregorianCalendarFromString(
576                                                 this.getStringFromCell( xcellrange,
577                                                    intRow,this.INT_COLUMN_ENDDATE));
578                                     }
579                                     else {
580                                         // Set the start date with the absolute s
581                                         // tart date
582                                         gregCalStartDate = (GregorianCalendar)
583                                             gregCalAbsoluteStartDate.clone();
584                                     }
585                                 }
586                             }
587                         }
588                     }
589                 }
590             }
591             catch( Exception exception ) {
592                 showExceptionMessage( exception );
593             }
594         }
595 
596         /** Getting a string from a gregorian calendar.
597          * @param gregCal Date to be converted.
598          * @return string (converted gregorian calendar).
599          */
600         public String getStringFromGregorianCalendar( GregorianCalendar gregCal ) {
601             String sDate = ( gregCal.get( Calendar.MONTH ) + 1 )
602                 + STRING_SEPARATOR + gregCal.get( Calendar.DATE )
603 //                + STRING_SEPARATOR + ( gregCal.get( Calendar.MONTH ) + 1 )
604                 + STRING_SEPARATOR + gregCal.get( Calendar.YEAR );
605 
606             return  sDate;
607         }
608 
609         /** Getting a GregorianCalendar from a string.
610          * @param sDate String to be converted.
611          * @return The result of the converting of the string.
612          */
613         public GregorianCalendar getGregorianCalendarFromString( String sDate ) {
614             int []intDateValue = this.getDateValuesFromString( sDate );
615 
616             return( new GregorianCalendar( intDateValue[ 2 ], intDateValue[ 0 ],
617                                            intDateValue[ 1 ] ) );
618         }
619 
620         /** Getting the day, month and year from a string.
621          * @param sDate String to be parsed.
622          * @return Returns an array of integer variables.
623          */
624         public int[] getDateValuesFromString( String sDate) {
625             int[] intDateValues = new int[ 3 ];
626 
627             int intPositionFirstTag = sDate.indexOf( STRING_SEPARATOR );
628             int intPositionSecondTag = sDate.indexOf(STRING_SEPARATOR,
629                                                      intPositionFirstTag + 1);
630 
631             // Getting the value of the month
632             intDateValues[ 0 ] = Integer.parseInt(
633                 sDate.substring(0, intPositionFirstTag)) - 1;
634             // Getting the value of the day
635             intDateValues[ 1 ] = Integer.parseInt(
636                 sDate.substring(intPositionFirstTag + 1, intPositionSecondTag));
637             // Getting the value of the year
638             intDateValues[ 2 ] = Integer.parseInt(
639                 sDate.substring(intPositionSecondTag + 1, sDate.length()));
640 
641             return intDateValues;
642         }
643 
644         /** Getting a content from a specified cell.
645          * @param xcellrange Providing access to cells.
646          * @param intRow Number of row.
647          * @param intColumn Number of column.
648          * @return String from the specified cell.
649          */
650         public String getStringFromCell( XCellRange xcellrange, int intRow,
651                                          int intColumn ) {
652             XTextRange xtextrangeStartDate = null;
653 
654             try {
655                 // Getting the cell holding the information about the start date
656                 XCell xcellStartDate = xcellrange.getCellByPosition(intColumn,
657                                                                     intRow);
658                 // Querying for the interface XTextRange on the XCell
659                 xtextrangeStartDate = (XTextRange)
660                     UnoRuntime.queryInterface(XTextRange.class, xcellStartDate);
661             }
662             catch( Exception exception ) {
663                 this.showExceptionMessage( exception );
664             }
665 
666             // Getting the start date
667             return  xtextrangeStartDate.getString().trim();
668         }
669 
670         /** Writing a specified string to a specified cell.
671          * @param xcellrange Providing access to the cells.
672          * @param intRow Number of row.
673          * @param intColumn Number of column.
674          * @param sDate Date to write to the cell.
675          */
676         public void setStringToCell( XCellRange xcellrange, int intRow,
677                                      int intColumn, String sDate ) {
678             try {
679                 // Getting the cell holding the information on the day to start
680                 XCell xcellStartDate = xcellrange.getCellByPosition(intColumn,
681                                                                     intRow);
682                 // Querying for the interface XTextRange on the XCell
683                 XTextRange xtextrange = (XTextRange)
684                     UnoRuntime.queryInterface(XTextRange.class, xcellStartDate);
685                 // Setting the new start date
686                 xtextrange.setString( sDate );
687             }
688             catch( Exception exception ) {
689                 this.showExceptionMessage( exception );
690             }
691         }
692 
693         /** Calculates the week of day and calls the method "setStringToCell".
694          * @param gregCal Day to be written to the cell.
695          * @param xcellrange Providing access to the cells.
696          * @param intRow Number of row.
697          * @param intColumn Number of column.
698          */
699         public void setDayOfWeek( GregorianCalendar gregCal,
700                                   XCellRange xcellrange, int intRow,
701                                   int intColumn) {
702             int intDayOfWeek = gregCal.get( Calendar.DAY_OF_WEEK );
703             String sDayOfWeek = "";
704             if ( intDayOfWeek == Calendar.MONDAY ) {
705                 sDayOfWeek = "MON";
706             } else if ( intDayOfWeek == Calendar.TUESDAY ) {
707                 sDayOfWeek = "TUE";
708             } else if ( intDayOfWeek == Calendar.WEDNESDAY ) {
709                 sDayOfWeek = "WED";
710             } else if ( intDayOfWeek == Calendar.THURSDAY ) {
711                 sDayOfWeek = "THU";
712             } else if ( intDayOfWeek == Calendar.FRIDAY ) {
713                 sDayOfWeek = "FRI";
714             }
715 
716             this.setStringToCell( xcellrange, intRow, intColumn,
717             sDayOfWeek );
718         }
719 
720         /** Calculates the dates of the official holidays with help of Calc
721          * functions.
722          * @param vectorHolidays Holding all holidays.
723          * @param xcellrange Providing the cells.
724          * @param xfunctionaccess Provides access to functions of the Calc.
725          * @param intYear Year to calculate the official holidays.
726          */
727         public void getOfficialHolidays(
728         Vector vectorHolidays,
729         XCellRange xcellrange,
730         XFunctionAccess xfunctionaccess,
731         int intYear ) {
732             try {
733                 // Official Holidays for how many years?
734                 final int intHowManyYears = 2;
735 
736                 // Get the Official Holiday for two years
737                 for ( int intNumberOfYear = 0;
738                       intNumberOfYear <= ( intHowManyYears - 1 );
739                       intNumberOfYear++ ) {
740                     intYear += intNumberOfYear;
741 
742                     // Getting the Easter sunday
743                     Double dEasterSunday = ( Double )
744                         xfunctionaccess.callFunction(
745                             "EASTERSUNDAY", new Object[] { new Integer(intYear) });
746 
747                     int intEasterSunday = (int)Math.round(
748                         dEasterSunday.doubleValue());
749 
750                     // New-year
751                     vectorHolidays.addElement( xfunctionaccess.callFunction(
752                                                    "DATE",
753                                                    new Object[] {
754                                                        new Integer( intYear ),
755                                                        new Integer( 1 ),
756                                                        new Integer( 1 ) } ));
757 
758                     // Good Friday
759                     vectorHolidays.addElement(
760                     new Double( intEasterSunday - 2 ) );
761 
762                     // Easter monday
763                     vectorHolidays.addElement(
764                     new Double( intEasterSunday + 1 ) );
765 
766                     // Labour Day
767                     vectorHolidays.addElement( xfunctionaccess.callFunction(
768                                                    "DATE",
769                                                    new Object[] {
770                                                        new Integer( intYear ),
771                                                        new Integer( 5 ),
772                                                        new Integer( 1 ) } ));
773 
774                     // Ascension Day
775                     vectorHolidays.addElement(new Double(intEasterSunday + 39 ));
776 
777                     // Pentecost monday
778                     vectorHolidays.addElement(new Double(intEasterSunday + 50 ));
779 
780                     // German Unification
781                     vectorHolidays.addElement( xfunctionaccess.callFunction(
782                                                    "DATE",
783                                                    new Object[] {
784                                                        new Integer( intYear ),
785                                                        new Integer( 10 ),
786                                                        new Integer( 3 ) } ));
787 
788                     // Christmas Day First
789                     vectorHolidays.addElement( xfunctionaccess.callFunction(
790                                                    "DATE",
791                                                    new Object[] {
792                                                        new Integer( intYear ),
793                                                        new Integer( 12 ),
794                                                        new Integer( 25 ) } ));
795 
796                     // Christmas Day Second
797                     vectorHolidays.addElement( xfunctionaccess.callFunction(
798                                                    "DATE",
799                                                    new Object[] {
800                                                        new Integer( intYear ),
801                                                        new Integer( 12 ),
802                                                        new Integer( 26 ) } ));
803                 }
804             }
805             catch( Exception exception ) {
806                 this.showExceptionMessage( exception );
807             }
808         }
809 
810         /** Returns the serial number of the date before or after a specified
811          * number of workdays.
812          * @param gregCalStartDate Date to start with the calculation.
813          * @param intDays Number of workdays (e.g. 5 or -3).
814          * @param objectHolidays Private and public holidays to take into account.
815          * @param xfunctionaccess Allows to call functions from the Calc.
816          * @return The gregorian date before or after a specified number of
817          *         workdays.
818          */
819         public GregorianCalendar getWorkday(
820             GregorianCalendar gregCalStartDate,
821             int intDays, Object[][] objectHolidays,
822             XFunctionAccess xfunctionaccess ) {
823             GregorianCalendar gregCalWorkday = null;
824 
825             try {
826                 // Getting the value of the start date
827                 Double dDate = ( Double ) xfunctionaccess.callFunction(
828                     "DATE",
829                     new Object[] {
830                         new Integer( gregCalStartDate.get( Calendar.YEAR ) ),
831                         new Integer( gregCalStartDate.get( Calendar.MONTH ) + 1 ),
832                         new Integer( gregCalStartDate.get( Calendar.DATE ) )
833                     } );
834 
835                 Double dWorkday = ( Double ) xfunctionaccess.callFunction(
836                 "com.sun.star.sheet.addin.Analysis.getWorkday",
837                 new Object[] { dDate, new Integer( intDays ), objectHolidays } );
838 
839                 Double dYear = ( Double ) xfunctionaccess.callFunction(
840                     "YEAR", new Object[] { dWorkday } );
841                 Double dMonth = ( Double ) xfunctionaccess.callFunction(
842                     "MONTH", new Object[] { dWorkday } );
843                 Double dDay = ( Double ) xfunctionaccess.callFunction(
844                     "DAY", new Object[] { dWorkday } );
845 
846                 gregCalWorkday = new GregorianCalendar(
847                 dYear.intValue(),
848                 dMonth.intValue() - 1,
849                 dDay.intValue() );
850             }
851             catch( Exception exception ) {
852                 this.showExceptionMessage( exception );
853             }
854 
855             return gregCalWorkday;
856         }
857 
858         /** Getting the holidays from the spreadsheet.
859          * @param vectorHolidays Holding all holidays.
860          * @param xcellrange Providing the cells.
861          * @param xfunctionaccess Provides the access to functions of the Calc.
862          */
863         public void getPrivateHolidays( Vector vectorHolidays,
864                                         XCellRange xcellrange,
865                                         XFunctionAccess xfunctionaccess ) {
866             try {
867                 int intRow = this.INT_ROW_HOLIDAYS_START;
868                 int intColumn = this.INT_COLUMN_HOLIDAYS_START;
869 
870                 double dHolidayStart = xcellrange.getCellByPosition(
871                     intColumn, intRow ).getValue();
872 
873                 double dHolidayEnd = xcellrange.getCellByPosition(
874                     intColumn + 1, intRow ).getValue();
875 
876                 while ( dHolidayStart != 0 ) {
877                     if ( dHolidayEnd == 0 ) {
878                         vectorHolidays.addElement(
879                             new Integer( (int) Math.round(
880                                              dHolidayStart ) ) );
881                     }
882                     else {
883                         for ( int intHoliday = (int) Math.round(
884                                   dHolidayStart );
885                               intHoliday <= (int) Math.round( dHolidayEnd );
886                               intHoliday++ ) {
887                             vectorHolidays.addElement( new Double( intHoliday ) );
888                         }
889                     }
890 
891                     intRow++;
892                     dHolidayStart = xcellrange.getCellByPosition(
893                         intColumn, intRow).getValue();
894                     dHolidayEnd = xcellrange.getCellByPosition(
895                         intColumn + 1, intRow).getValue();
896                 }
897             }
898             catch( Exception exception ) {
899                 this.showExceptionMessage( exception );
900             }
901         }
902 
903         /** Showing the stack trace in a JOptionPane.
904          * @param sMessage The message to show.
905          */
906         public void showMessage( String sMessage ) {
907             javax.swing.JFrame jframe = new javax.swing.JFrame();
908             jframe.setLocation(100, 100);
909             jframe.setSize(300, 200);
910             jframe.setVisible(true);
911             javax.swing.JOptionPane.showMessageDialog(
912                 jframe, sMessage, "Debugging information",
913                 javax.swing.JOptionPane.INFORMATION_MESSAGE);
914             jframe.dispose();
915         }
916 
917         /** Writing the stack trace from an exception to a string and calling
918          * the method showMessage() with this string.
919          * @param exception The occured exception.
920          * @see showMessage
921          */
922         public void showExceptionMessage( Exception exception ) {
923             java.io.StringWriter swriter = new java.io.StringWriter();
924             java.io.PrintWriter printwriter =
925                 new java.io.PrintWriter( swriter );
926             exception.printStackTrace( printwriter);
927             System.err.println( exception );
928             this.showMessage( swriter.getBuffer().substring(0) );
929         }
930     }
931 
932     /**
933      * Gives a factory for creating the service.
934      * This method is called by the <code>JavaLoader</code>
935      * <p>
936      * @return  returns a <code>XSingleComponentFactory</code> for creating
937      *          the component
938      * @param   sImplName the name of the implementation for which a
939      *          service is desired
940      * @see     com.sun.star.comp.loader.JavaLoader
941      */
942     public static XSingleComponentFactory __getComponentFactory(String sImplName) {
943         XSingleComponentFactory xFactory = null;
944 
945         if ( sImplName.equals( ToDoImpl.class.getName() ) )
946             xFactory = Factory.createComponentFactory(ToDoImpl.class,
947                                                       ToDoImpl.getServiceNames());
948 
949         return xFactory;
950     }
951 
952     /**
953      * Writes the service information into the given registry key.
954      * This method is called by the <code>JavaLoader</code>
955      * <p>
956      * @return  returns true if the operation succeeded
957      * @param   regKey the registryKey
958      * @see     com.sun.star.comp.loader.JavaLoader
959      */
960     // This method not longer necessary since OOo 3.4 where the component registration
961     // was changed to passive component registration. For more details see
962     // http://wiki.services.openoffice.org/wiki/Passive_Component_Registration
963 
964 //     public static boolean __writeRegistryServiceInfo(XRegistryKey regKey) {
965 //         return Factory.writeRegistryServiceInfo(ToDoImpl.class.getName(),
966 //                                                 ToDoImpl.getServiceNames(), regKey);
967 //     }
968 }
969 
970