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 // __________ Imports __________
36 
37 import com.sun.star.uno.UnoRuntime;
38 import com.sun.star.uno.AnyConverter;
39 
40 import java.lang.*;
41 import java.awt.*;
42 import javax.swing.*;
43 import java.io.*;
44 import java.net.*;
45 
46 // __________ Implementation __________
47 
48 /**
49  * Is a collection of basic features.
50  * This helper shows different functionality of framework api
51  * in an example manner. You can use the follow ones:
52  *      (1) parse URL's
53  *      (2) create frames (inside/outside a java application)
54  *      (3) dispatches (with[out] notifications)
55  *      (4) loading/saving documents
56  *      (5) convert documents to HTML (if possible)
57  *      (6) close documents (and her frames) correctly
58  *
59  * There exist some other helper functionality too, which
60  * doesn't use or demonstrate the office api:
61  *      (a) getting file names by using a file chosser
62  *
63  * @author     Andreas Schlüns
64  * @created    28.02.2002 15:31
65  */
66 public class FunctionHelper
67 {
68     // ____________________
69 
70     /**
71      * This convert an URL (formated as a string) to a struct com.sun.star.util.URL.
72      * It use a special service to do that: the URLTransformer.
73      * Because some API calls need it and it's not allowed to set "Complete"
74      * part of the util struct only. The URL must be parsed.
75      *
76      * @param sURL
77      *          URL for parsing in string notation
78      *
79      * @return [com.sun.star.util.URL]
80      *              URL in UNO struct notation
81      */
82     public static com.sun.star.util.URL parseURL(String sURL)
83     {
84         com.sun.star.util.URL aURL = null;
85 
86         if (sURL==null || sURL.equals(""))
87         {
88             System.out.println("wrong using of URL parser");
89             return null;
90         }
91 
92         try
93         {
94             com.sun.star.uno.XComponentContext xOfficeCtx =
95                 OfficeConnect.getOfficeContext();
96 
97             // Create special service for parsing of given URL.
98             com.sun.star.util.XURLTransformer xParser =
99                 (com.sun.star.util.XURLTransformer)UnoRuntime.queryInterface(
100                     com.sun.star.util.XURLTransformer.class,
101                     xOfficeCtx.getServiceManager().createInstanceWithContext(
102                         "com.sun.star.util.URLTransformer", xOfficeCtx));
103 
104             // Because it's an in/out parameter we must use an array of URL objects.
105             com.sun.star.util.URL[] aParseURL = new com.sun.star.util.URL[1];
106             aParseURL[0] = new com.sun.star.util.URL();
107             aParseURL[0].Complete = sURL;
108 
109             // Parse the URL
110             xParser.parseStrict(aParseURL);
111 
112             aURL = aParseURL[0];
113         }
114         catch(com.sun.star.uno.RuntimeException exRuntime)
115         {
116             // Any UNO method of this scope can throw this exception.
117             // Reset the return value only.
118             aURL = null;
119         }
120         catch(com.sun.star.uno.Exception exUno)
121         {
122             // "createInstance()" method of used service manager can throw it.
123             // Then it wasn't possible to get the URL transformer.
124             // Return default instead of realy parsed URL.
125             aURL = null;
126         }
127 
128         return aURL;
129     }
130 
131     // ____________________
132 
133     /**
134      * create a new empty target frame
135      * Attention: Currently we must use special service com.sun.star.frame.Task instead of Frame.
136      * Because desktop environment accept this special frame type only as direct children.
137      * Note - This service will be deprecated and must be replaces by com.sun.star.frame.Frame in
138      * further versions. To feature prove we use both service names. If for new versions
139      * the deprecated one not exist we get an empty frame, we can try to use the new service.
140      *
141      * @param xSMGR
142      *          we nee the remote service manager to create this task/frame service
143      *
144      * @return [com.sun.star.frame.XFrame]
145      *          the new created frame reference in case of success or null otherwhise
146      */
147     private static com.sun.star.frame.XFrame impl_createEmptyFrame(
148         com.sun.star.uno.XComponentContext xCtx )
149     {
150         com.sun.star.frame.XFrame xFrame = null;
151 
152         try{
153             xFrame = (com.sun.star.frame.XFrame)UnoRuntime.queryInterface(
154                 com.sun.star.frame.XFrame.class,
155                 xCtx.getServiceManager().createInstanceWithContext(
156                     "com.sun.star.frame.Task", xCtx));
157         } catch(com.sun.star.uno.Exception ex1) {}
158 
159         if (xFrame==null)
160         {
161             try{
162                 xFrame = (com.sun.star.frame.XFrame)UnoRuntime.queryInterface(
163                     com.sun.star.frame.XFrame.class,
164                     xCtx.getServiceManager().createInstanceWithContext(
165                         "com.sun.star.frame.Frame", xCtx));
166             } catch(com.sun.star.uno.Exception ex2) {}
167         }
168 
169         return xFrame;
170     }
171 
172     // ____________________
173 
174     /**
175      * create a new window which can be used as container window of an office frame
176      * We know two modes for creation:
177      *   - the office window will be a child of one of our java windows
178      *   - the office will be a normal system window outside this java application
179      * This behaviour will be regulated by the second parameter of this operation.
180      * If a parentview is given the first mode will be activated - otherwhise
181      * the second one.
182      *
183      * Note: First mode (creation of a child window) can be reached by two different
184      *       ways.
185      *   - pack the required window handle of our java window inside an UNO object
186      *     to transport it to the remote office toolkit and get a child office
187      *     window.
188      *     This is the old way. It's better to use the second one - but to be
189      *     future prove this old one should be tried too.
190      *   - it's possible to pass the native window handle directly to the toolkit.
191      *     A special interface method was enabled to accept that.
192      *
193      *   The right way to create an office window should be then:
194      *   - try to use second creation mode (directly using of the window handle)
195      *   - if it failed ... use the old way by packing the handle inside an object
196      *
197      * @param xSMGR
198      *          we need a service manager to be able to create remote office
199      *          services
200      *
201      * @param aParentView
202      *          the java window as parent for the office window if an inplace office
203      *          is required. If it is set to null the created office window will be
204      *          a normal system window outside of our java application.
205      *
206      * @return [com.sun.star.awt.XWindow]
207      *          The new created office window which can be used to set it as
208      *          a ContainerWindow on an empty office frame.
209      */
210     private static com.sun.star.awt.XWindow impl_createWindow(
211         com.sun.star.uno.XComponentContext xCtx, NativeView aParentView )
212     {
213         com.sun.star.awt.XWindow     xWindow  = null;
214         com.sun.star.awt.XWindowPeer xPeer    = null;
215         com.sun.star.awt.XToolkit    xToolkit = null;
216 
217         // get access to toolkit of remote office to create the container window of
218         // new target frame
219         try{
220             xToolkit = (com.sun.star.awt.XToolkit)UnoRuntime.queryInterface(
221                 com.sun.star.awt.XToolkit.class,
222                 xCtx.getServiceManager().createInstanceWithContext(
223                     "com.sun.star.awt.Toolkit", xCtx));
224         }
225         catch(com.sun.star.uno.Exception ex)
226         {
227             return null;
228         }
229 
230         // mode 1) create an external system window
231         if (aParentView==null)
232         {
233             // Describe the properties of the container window.
234             com.sun.star.awt.WindowDescriptor aDescriptor =
235                 new com.sun.star.awt.WindowDescriptor();
236             aDescriptor.Type =   com.sun.star.awt.WindowClass.TOP;
237             aDescriptor.WindowServiceName = "window";
238             aDescriptor.ParentIndex = -1;
239             aDescriptor.Parent = null;
240             aDescriptor.Bounds = new com.sun.star.awt.Rectangle(0,0,0,0);
241             aDescriptor.WindowAttributes = com.sun.star.awt.WindowAttribute.BORDER |
242                 com.sun.star.awt.WindowAttribute.MOVEABLE |
243                 com.sun.star.awt.WindowAttribute.SIZEABLE |
244                 com.sun.star.awt.WindowAttribute.CLOSEABLE;
245 
246             try{
247                 xPeer = xToolkit.createWindow( aDescriptor );
248             } catch(com.sun.star.lang.IllegalArgumentException exIllegal) {}
249         }
250         // mode 2) create an internal office window as child of our given java
251         // parent window
252         else
253         {
254             // try new version of creation first: directly using of the window
255             // handle. The old implementation of the corresponding toolkit method
256             // requires a process ID. If this id isn't the right one a null object
257             // is returned. But normaly nobody outside the office knows this id.
258             // New version of this method ignore the id parameter and creation will
259             // work.
260             // Note: You must be shure if your window handle can be realy used by
261             // the remote office. Means if this java client and the remote office
262             // use the same display!
263             com.sun.star.awt.XSystemChildFactory xChildFactory =
264                 (com.sun.star.awt.XSystemChildFactory)UnoRuntime.queryInterface(
265                     com.sun.star.awt.XSystemChildFactory.class, xToolkit);
266 
267             try
268             {
269                 Integer nHandle = aParentView.getHWND();
270                 short   nSystem = (short)aParentView.getNativeWindowSystemType();
271                 byte[]  lProcID = new byte[0];
272 
273                 xPeer = xChildFactory.createSystemChild((Object)nHandle,
274                                                         lProcID, nSystem);
275 
276                 if (xPeer==null)
277                 {
278                     // mode 3) OK - new version doesn't work. It requires the
279                     // process id which we doesn't have.
280                     // So we must use the old way to get the right window peer.
281                     // Pack the handle inside a wrapper object.
282                     JavaWindowPeerFake aWrapper = new
283                         JavaWindowPeerFake(aParentView);
284 
285                     com.sun.star.awt.XWindowPeer xParentPeer =
286                         (com.sun.star.awt.XWindowPeer)UnoRuntime.queryInterface(
287                             com.sun.star.awt.XWindowPeer.class, aWrapper);
288 
289                     com.sun.star.awt.WindowDescriptor aDescriptor =
290                         new com.sun.star.awt.WindowDescriptor();
291                     aDescriptor.Type = com.sun.star.awt.WindowClass.TOP;
292                     aDescriptor.WindowServiceName = "workwindow";
293                     aDescriptor.ParentIndex = 1;
294                     aDescriptor.Parent = xParentPeer;
295                     aDescriptor.Bounds = new com.sun.star.awt.Rectangle(0,0,0,0);
296                     if (nSystem == com.sun.star.lang.SystemDependent.SYSTEM_WIN32)
297                         aDescriptor.WindowAttributes =
298                             com.sun.star.awt.WindowAttribute.SHOW;
299                     else
300                         aDescriptor.WindowAttributes =
301                             com.sun.star.awt.WindowAttribute.SYSTEMDEPENDENT;
302 
303                     try{
304                         xPeer = xToolkit.createWindow( aDescriptor );
305                     } catch(com.sun.star.lang.IllegalArgumentException exIllegal) {}
306                 }
307             }
308             catch(java.lang.RuntimeException exJRun)
309             {
310                 // This exception is thrown by the native JNI code if it try to get
311                 // the systemw window handle. A possible reason can be an invisible
312                 // java window. In this case it should be enough to set return
313                 // values to null. All other ressources (which was created before)
314                 // will be freed automaticly if scope wil be leaved.
315                 System.out.println("May be the NativeView object wasn't realy visible at calling time of getNativeWindow()?");
316                 xPeer   = null;
317                 xWindow = null;
318             }
319         }
320 
321         // It doesn't matter which way was used to get the window peer.
322         // Cast it to the right return interface and return it.
323         xWindow = (com.sun.star.awt.XWindow)UnoRuntime.queryInterface(
324             com.sun.star.awt.XWindow.class,
325             xPeer);
326 
327         return xWindow;
328     }
329 
330     // ____________________
331 
332     /**
333      * This method create a new empty child frame on desktop instance of remote office.
334      * It use a special JNI functionality to pass the office XWindow over a java window.
335      * This java window can be inserted into another java window container for complex layouting.
336      * If this parent java window isn't used, a top level system window will be created.
337      * The the resulting office frame isn't plugged into this java application.
338      *
339      * @param sName
340      *          name to set it on the new created frame
341      *
342      * @param aParentView
343      *          java window which should be used as parent window of new created office frame window
344      *          May be set to null.
345      *
346      * @return [com.sun.star.frame.XFrame]
347      *          reference to the new created frame for success or null if it failed
348      */
349     public static com.sun.star.frame.XFrame createViewFrame(String sName, NativeView aParentView)
350     {
351         com.sun.star.frame.XFrame xFrame = null;
352 
353         try
354         {
355             com.sun.star.uno.XComponentContext xCtx =
356                 OfficeConnect.getOfficeContext();
357 
358             // create an empty office frame first
359             xFrame = impl_createEmptyFrame(xCtx);
360 
361             // create an office window then
362             // Depending from the given parameter aParentView it will be a child or a top level
363             // system window. (see impl method for further informations)
364             // But before we call this helper - prepare the possible parent window: show it.
365             // JNI calls to get system window handle of java window can't work without that!
366             if (aParentView!=null)
367                 aParentView.setVisible(true);
368             com.sun.star.awt.XWindow xWindow = impl_createWindow(xCtx, aParentView);
369 
370             // pass the window the frame as his new container window.
371             // It's neccessary to do it first  - before you call anything else there.
372             // Otherwhise the frame throws some exceptions for "uninitialized state".
373             xFrame.initialize( xWindow );
374 
375             // Insert the new frame in desktop hierarchy.
376             // Use XFrames interface to do so. It provides access to the child frame container of that instance.
377             com.sun.star.frame.XFramesSupplier xTreeRoot = (com.sun.star.frame.XFramesSupplier)UnoRuntime.queryInterface(
378                 com.sun.star.frame.XFramesSupplier.class,
379                 xCtx.getServiceManager().createInstanceWithContext(
380                     "com.sun.star.frame.Desktop", xCtx));
381             com.sun.star.frame.XFrames xChildContainer = xTreeRoot.getFrames();
382             xChildContainer.append(xFrame);
383 
384             // Make some further initializations on frame and window.
385             xWindow.setVisible(true);
386             xFrame.setName(sName);
387         }
388         catch(com.sun.star.uno.RuntimeException exRuntime)
389         {
390             // Any UNO method of this scope can throw this exception.
391             // So the frame can be already created and he must be freed
392             // correctly. May be he was inserted into the desktop tree too ...
393             if(xFrame!=null)
394             {
395                 // Try to dispose the frame. He should deregister himself at the desktop object
396                 // and free all internal used ressources (e.g. the container window) automaticly.
397                 // It's possible to do that here - because frame has no component inside yet.
398                 // So nobody can disagree with that.
399                 // After the dispose() call forget all references to this frame and let him die.
400                 // If a new exception will occure ... no generell solution exist then.
401                 // Nobody can guarantee if next call will work or not.
402                 com.sun.star.lang.XComponent xComponent = (com.sun.star.lang.XComponent)UnoRuntime.queryInterface(
403                     com.sun.star.lang.XComponent.class,
404                     xFrame);
405                 xComponent.dispose();
406                 xComponent = null;
407                 xFrame     = null;
408             }
409         }
410         catch(com.sun.star.uno.Exception exUno)
411         {
412             // "createInstance()" method of used service manager can throw it.
413             // If it occured during creation of desktop service the frame already was created.
414             // Free it by decresing his refcount. Changes on the desktop tree couldn't exist.
415             // Without the desktop service that wasn't possible. So no further rollbacks must follow.
416             if(xFrame!=null)
417             {
418                 com.sun.star.lang.XComponent xComponent = (com.sun.star.lang.XComponent)UnoRuntime.queryInterface(
419                     com.sun.star.lang.XComponent.class,
420                     xFrame);
421                 xComponent.dispose();
422                 xComponent = null;
423                 xFrame     = null;
424             }
425         }
426 
427         return xFrame;
428     }
429 
430     // ____________________
431 
432     /**
433      * Dispatch an URL to given frame.
434      * Caller can register himself for following status events for dispatched
435      * URL too. But nobody guarantee that such notifications will occure.
436      * (see dispatchWithNotification() if you interest on that)
437      * The returned dispatch object should be hold alive by caller
438      * till he deosn't need it any longer. Otherwise the dispatcher can(!)
439      * die by decreasing his refcount.
440      *
441      * @param   xFrame      frame wich should be the target of this dispatch
442      * @param   aURL        full parsed and converted office URL for dispatch
443      * @param   lProperties optional arguments for dispatch
444      * @param   xListener   optional listener which is registered automaticly for status events
445      *                      (Note: Deregistration is part of this listener himself!)
446      *
447      * @return  [XDispatch] It's the used dispatch object and can be used for deregistration of an optional listener.
448      *                      Otherwhise caller can ignore it.
449      */
450     public static com.sun.star.frame.XDispatch execute(com.sun.star.frame.XFrame          xFrame     ,
451                                                        com.sun.star.util.URL              aURL       ,
452                                                        com.sun.star.beans.PropertyValue[] lProperties,
453                                                        com.sun.star.frame.XStatusListener xListener  )
454     {
455         com.sun.star.frame.XDispatch xDispatcher = null;
456 
457         try
458         {
459             // Query the frame for right interface which provides access to all available dispatch objects.
460             com.sun.star.frame.XDispatchProvider xProvider = (com.sun.star.frame.XDispatchProvider)UnoRuntime.queryInterface(
461                 com.sun.star.frame.XDispatchProvider.class,
462                 xFrame);
463 
464             // Ask himn for right dispatch object for given URL.
465             // Force given frame as target for following dispatch by using "".
466             // It means the same like "_self".
467             xDispatcher = xProvider.queryDispatch(aURL,"",0);
468 
469             // Dispatch the URL into the frame.
470             if(xDispatcher!=null)
471             {
472                 if(xListener!=null)
473                     xDispatcher.addStatusListener(xListener,aURL);
474 
475                 xDispatcher.dispatch(aURL,lProperties);
476             }
477         }
478         catch(com.sun.star.uno.RuntimeException exUno)
479         {
480             // Any UNO method of this scope can throw this exception.
481             // But there will be nothing to do then - because
482             // we haven't changed anything inside the remote objects
483             // except method "addStatusListener().
484             // But in this case the source of this exception has to
485             // rollback all his operations. There is no chance to
486             // make anything right then.
487             // Reset the return value to a default - that's it.
488             exUno.printStackTrace();
489             xDispatcher = null;
490         }
491 
492         return xDispatcher;
493     }
494 
495     // ____________________
496 
497     /**
498      * Dispatch an URL to given frame.
499      * Caller can register himself for following result events for dispatched
500      * URL too. Notifications are guaranteed (instead of dispatch())
501      * Returning of the dispatch object isn't neccessary.
502      * Nobody must hold it alive longer the dispatch needs.
503      *
504      * @param   xFrame      frame wich should be the target of this dispatch
505      * @param   aURL        full parsed and converted office URL for dispatch
506      * @param   lProperties optional arguments for dispatch
507      * @param   xListener   optional listener which is registered automaticly for status events
508      *                      (Note: Deregistration is not supported. Dispatcher does it automaticly.)
509      */
510     public static void executeWithNotification(com.sun.star.frame.XFrame                  xFrame     ,
511                                                com.sun.star.util.URL                      aURL       ,
512                                                com.sun.star.beans.PropertyValue[]         lProperties,
513                                                com.sun.star.frame.XDispatchResultListener xListener  )
514     {
515         try
516         {
517             // Query the frame for right interface which provides access to all available dispatch objects.
518             com.sun.star.frame.XDispatchProvider xProvider = (com.sun.star.frame.XDispatchProvider)UnoRuntime.queryInterface(
519                 com.sun.star.frame.XDispatchProvider.class,
520                 xFrame);
521 
522             // Ask himn for right dispatch object for given URL.
523             // Force THIS frame as target for following dispatch.
524             // Attention: The interface XNotifyingDispatch is an optional one!
525             com.sun.star.frame.XDispatch xDispatcher = xProvider.queryDispatch(aURL,"",0);
526             com.sun.star.frame.XNotifyingDispatch xNotifyingDispatcher = (com.sun.star.frame.XNotifyingDispatch)UnoRuntime.queryInterface(
527                 com.sun.star.frame.XNotifyingDispatch.class,
528                 xDispatcher);
529 
530             // Dispatch the URL.
531             if(xNotifyingDispatcher!=null)
532                 xNotifyingDispatcher.dispatchWithNotification(aURL,lProperties,xListener);
533         }
534         catch(com.sun.star.uno.RuntimeException exUno)
535         {
536             // Any UNO method of this scope can throw this exception.
537             // But there is nothing we can do then.
538             exUno.printStackTrace();
539         }
540     }
541 
542     // ____________________
543 
544     /**
545      * Load document specified by an URL into given frame synchronously.
546      * The result of this operation will be the loaded document for success
547      * or null if loading failed.
548      *
549      * @param   xFrame          frame wich should be the target of this load call
550      * @param   sURL            unparsed URL for loading
551      * @param   lProperties     optional arguments
552      *
553      * @return  [XComponent]    the loaded document for success or null if it's failed
554      */
555     public static com.sun.star.lang.XComponent loadDocument(
556         com.sun.star.frame.XFrame xFrame, String sURL,
557         com.sun.star.beans.PropertyValue[] lProperties)
558     {
559         com.sun.star.lang.XComponent xDocument = null;
560         String                       sOldName  = null;
561 
562         try
563         {
564             com.sun.star.uno.XComponentContext xCtx =
565                 OfficeConnect.getOfficeContext();
566 
567             // First prepare frame for loading
568             // We must adress it inside the frame tree without any complications.
569             // So we set an unambigous (we hope it) name and use it later.
570             // Don't forget to reset original name after that.
571                    sOldName = xFrame.getName();
572             String sTarget  = "odk_officedev_desk";
573             xFrame.setName(sTarget);
574 
575             // Get access to the global component loader of the office
576             // for synchronous loading the document.
577             com.sun.star.frame.XComponentLoader xLoader =
578                 (com.sun.star.frame.XComponentLoader)UnoRuntime.queryInterface(
579                     com.sun.star.frame.XComponentLoader.class,
580                     xCtx.getServiceManager().createInstanceWithContext(
581                         "com.sun.star.frame.Desktop", xCtx));
582 
583             // Load the document into the target frame by using his name and
584             // special search flags.
585             xDocument = xLoader.loadComponentFromURL(
586                 sURL,
587                 sTarget,
588                 com.sun.star.frame.FrameSearchFlag.CHILDREN,
589                 lProperties);
590 
591             // dont forget to restore old frame name ...
592             xFrame.setName(sOldName);
593         }
594         catch(com.sun.star.io.IOException exIO)
595         {
596             // Can be thrown by "loadComponentFromURL()" call.
597             // The only thing we should do then is to reset changed frame name!
598             exIO.printStackTrace();
599             xDocument = null;
600             if(sOldName!=null)
601                 xFrame.setName(sOldName);
602         }
603         catch(com.sun.star.lang.IllegalArgumentException exIllegal)
604         {
605             // Can be thrown by "loadComponentFromURL()" call.
606             // The only thing we should do then is to reset changed frame name!
607             exIllegal.printStackTrace();
608             xDocument = null;
609             if(sOldName!=null)
610                 xFrame.setName(sOldName);
611         }
612         catch(com.sun.star.uno.RuntimeException exRuntime)
613         {
614             // Any UNO method of this scope can throw this exception.
615             // The only thing we can try(!) is to reset changed frame name.
616             exRuntime.printStackTrace();
617             xDocument = null;
618             if(sOldName!=null)
619                 xFrame.setName(sOldName);
620         }
621         catch(com.sun.star.uno.Exception exUno)
622         {
623             // "createInstance()" method of used service manager can throw it.
624             // The only thing we should do then is to reset changed frame name!
625             exUno.printStackTrace();
626             xDocument = null;
627             if(sOldName!=null)
628                 xFrame.setName(sOldName);
629         }
630 
631         return xDocument;
632     }
633 
634     // ____________________
635 
636     /**
637      * Save currently loaded document of given frame.
638      *
639      * @param   xDocument   document for saving changes
640      */
641     public static void saveDocument(com.sun.star.lang.XComponent xDocument)
642     {
643         try
644         {
645             // Check for supported model functionality.
646             // Normaly the application documents (text, spreadsheet ...) do so
647             // but some other ones (e.g. db components) doesn't do that.
648             // They can't be save then.
649             com.sun.star.frame.XModel xModel = (com.sun.star.frame.XModel)UnoRuntime.queryInterface(
650                 com.sun.star.frame.XModel.class,
651                 xDocument);
652             if(xModel!=null)
653             {
654                 // Check for modifications => break save process if there is nothing to do.
655                 com.sun.star.util.XModifiable xModified = (com.sun.star.util.XModifiable)UnoRuntime.queryInterface(
656                     com.sun.star.util.XModifiable.class,
657                     xModel);
658                 if(xModified.isModified()==true)
659                 {
660                     com.sun.star.frame.XStorable xStore = (com.sun.star.frame.XStorable)UnoRuntime.queryInterface(
661                         com.sun.star.frame.XStorable.class,
662                         xModel);
663 
664                     xStore.store();
665                 }
666             }
667         }
668         catch(com.sun.star.io.IOException exIO)
669         {
670             // Can be thrown by "store()" call.
671             // But there is nothing we can do then.
672             exIO.printStackTrace();
673         }
674         catch(com.sun.star.uno.RuntimeException exUno)
675         {
676             // Any UNO method of this scope can throw this exception.
677             // But there is nothing we can do then.
678             exUno.printStackTrace();
679         }
680     }
681 
682     // ____________________
683 
684     /**
685      * It try to export given document in HTML format.
686      * Current document will be converted to HTML and moved to new place on disk.
687      * A "new" file will be created by given URL (may be overwritten
688      * if it already exist). Right filter will be used automaticly if factory of
689      * this document support it. If no valid filter can be found for export,
690      * nothing will be done here.
691      *
692      * @param   xDocument   document which should be exported
693      * @param   sURL        target URL for converted document
694      */
695     public static void saveAsHTML(com.sun.star.lang.XComponent xDocument,
696                                   String                       sURL     )
697     {
698         try
699         {
700             // First detect factory of this document.
701             // Ask for the supported service name of this document.
702             // If information is available it can be used to find out wich
703             // filter exist for HTML export. Normaly this filter should be searched
704             // inside the filter configuration but this little demo doesn't do so.
705             // (see service com.sun.star.document.FilterFactory for further
706             // informations too)
707             // Well known filter names are used directly. They must exist in current
708             // office installation. Otherwise this code will fail. But to prevent
709             // this code against missing filters it check for existing state of it.
710             com.sun.star.lang.XServiceInfo xInfo = (com.sun.star.lang.XServiceInfo)
711                 UnoRuntime.queryInterface(com.sun.star.lang.XServiceInfo.class,
712                                           xDocument);
713 
714             if(xInfo!=null)
715             {
716                 // Find out possible filter name.
717                 String sFilter = null;
718                 if(xInfo.supportsService("com.sun.star.text.TextDocument")==true)
719                     sFilter = new String("HTML (StarWriter)");
720                 else
721                 if(xInfo.supportsService("com.sun.star.text.WebDocument")==true)
722                     sFilter = new String("HTML");
723                 else
724                 if(xInfo.supportsService("com.sun.star.sheet.SpreadsheetDocument")==true)
725                     sFilter = new String("HTML (StarCalc)");
726 
727                 // Check for existing state of this filter.
728                 if(sFilter!=null)
729                 {
730                     com.sun.star.uno.XComponentContext xCtx =
731                         OfficeConnect.getOfficeContext();
732 
733                     com.sun.star.container.XNameAccess xFilterContainer =
734                         (com.sun.star.container.XNameAccess)
735                         UnoRuntime.queryInterface(
736                             com.sun.star.container.XNameAccess.class,
737                             xCtx.getServiceManager().createInstanceWithContext(
738                                 "com.sun.star.document.FilterFactory", xCtx));
739 
740                     if(xFilterContainer.hasByName(sFilter)==false)
741                         sFilter=null;
742                 }
743 
744                 // Use this filter for export.
745                 if(sFilter!=null)
746                 {
747                     // Export can be forced by saving the document and using a
748                     // special filter name which can write needed format. Build
749                     // neccessary argument list now.
750                     // Use special flag "Overwrite" too, to prevent operation
751                     // against possible exceptions, if file already exist.
752                     com.sun.star.beans.PropertyValue[] lProperties =
753                         new com.sun.star.beans.PropertyValue[2];
754                     lProperties[0] = new com.sun.star.beans.PropertyValue();
755                     lProperties[0].Name = "FilterName";
756                     lProperties[0].Value = sFilter;
757                     lProperties[1] = new com.sun.star.beans.PropertyValue();
758                     lProperties[1].Name = "Overwrite";
759                     lProperties[1].Value = Boolean.TRUE;
760 
761                     com.sun.star.frame.XStorable xStore =
762                         (com.sun.star.frame.XStorable)UnoRuntime.queryInterface(
763                             com.sun.star.frame.XStorable.class, xDocument);
764 
765                     xStore.storeAsURL(sURL,lProperties);
766                 }
767             }
768         }
769         catch(com.sun.star.io.IOException exIO)
770         {
771             // Can be thrown by "store()" call.
772             // Do nothing then. Saving failed - that's it.
773             exIO.printStackTrace();
774         }
775         catch(com.sun.star.uno.RuntimeException exRuntime)
776         {
777             // Can be thrown by any uno call.
778             // Do nothing here. Saving failed - that's it.
779             exRuntime.printStackTrace();
780         }
781         catch(com.sun.star.uno.Exception exUno)
782         {
783             // Can be thrown by "createInstance()" call of service manager.
784             // Do nothing here. Saving failed - that's it.
785             exUno.printStackTrace();
786         }
787     }
788 
789     // ____________________
790 
791     /**
792      * Try to close the document without any saving of modifications.
793      * We can try it only! Controller and/or model of this document
794      * can disagree with that. But mostly they doesn't do so.
795      *
796      * @param   xDocument   document which should be clcosed
797      */
798     public static void closeDocument(com.sun.star.lang.XComponent xDocument)
799     {
800         try
801         {
802             // Check supported functionality of the document (model or controller).
803             com.sun.star.frame.XModel xModel =
804                 (com.sun.star.frame.XModel)UnoRuntime.queryInterface(
805                     com.sun.star.frame.XModel.class, xDocument);
806 
807             if(xModel!=null)
808             {
809                 // It's a full featured office document.
810                 // Reset the modify state of it and close it.
811                 // Note: Model can disgree by throwing a veto exception.
812                 com.sun.star.util.XModifiable xModify =
813                     (com.sun.star.util.XModifiable)UnoRuntime.queryInterface(
814                         com.sun.star.util.XModifiable.class, xModel);
815 
816                 xModify.setModified(false);
817                 xDocument.dispose();
818             }
819             else
820             {
821                 // It's a document which supports a controller .. or may by a pure
822                 // window only. If it's at least a controller - we can try to
823                 // suspend him. But - he can disagree with that!
824                 com.sun.star.frame.XController xController =
825                     (com.sun.star.frame.XController)UnoRuntime.queryInterface(
826                         com.sun.star.frame.XController.class, xDocument);
827 
828                 if(xController!=null)
829                 {
830                     if(xController.suspend(true)==true)
831                     {
832                         // Note: Don't dispose the controller - destroy the frame
833                         // to make it right!
834                         com.sun.star.frame.XFrame xFrame = xController.getFrame();
835                         xFrame.dispose();
836                     }
837                 }
838             }
839         }
840         catch(com.sun.star.beans.PropertyVetoException exVeto)
841         {
842             // Can be thrown by "setModified()" call on model.
843             // He disagree with our request.
844             // But there is nothing to do then. Following "dispose()" call wasn't
845             // never called (because we catch it before). Closing failed -that's it.
846             exVeto.printStackTrace();
847         }
848         catch(com.sun.star.lang.DisposedException exDisposed)
849         {
850             // If an UNO object was already disposed before - he throw this special
851             // runtime exception. Of course every UNO call must be look for that -
852             // but it's a question of error handling.
853             // For demonstration this exception is handled here.
854             exDisposed.printStackTrace();
855         }
856         catch(com.sun.star.uno.RuntimeException exRuntime)
857         {
858             // Every uno call can throw that.
859             // Do nothing - closing failed - that's it.
860             exRuntime.printStackTrace();
861         }
862     }
863 
864     // ____________________
865 
866     /**
867      * Try to close the frame instead of the document.
868      * It shows the possible interface to do so.
869      *
870      * @param xFrame
871      *          frame which should be clcosed
872      *
873      * @return  <TRUE/> in case frame could be closed
874      *          <FALSE/> otherwise
875      */
876     public static boolean closeFrame(com.sun.star.frame.XFrame xFrame)
877     {
878         boolean bClosed = false;
879 
880         try
881         {
882             // first try the new way: use new interface XCloseable
883             // It replace the deprecated XTask::close() and should be preferred ...
884             // if it can be queried.
885             com.sun.star.util.XCloseable xCloseable =
886                 (com.sun.star.util.XCloseable)UnoRuntime.queryInterface(
887                     com.sun.star.util.XCloseable.class, xFrame);
888             if (xCloseable!=null)
889             {
890                 // We deliver the owner ship of this frame not to the (possible)
891                 // source which throw a CloseVetoException. We whishto have it
892                 // under our own control.
893                 try
894                 {
895                     xCloseable.close(false);
896                     bClosed = true;
897                 }
898                 catch( com.sun.star.util.CloseVetoException exVeto )
899                 {
900                     bClosed = false;
901                 }
902             }
903             else
904             {
905                 // OK: the new way isn't possible. Try the old one.
906                 com.sun.star.frame.XTask xTask = (com.sun.star.frame.XTask)
907                     UnoRuntime.queryInterface(com.sun.star.frame.XTask.class,
908                                               xFrame);
909                 if (xTask!=null)
910                 {
911                     // return value doesn't interest here. Because
912                     // we forget this task ...
913                     bClosed = xTask.close();
914                 }
915             }
916         }
917         catch (com.sun.star.lang.DisposedException exDisposed)
918         {
919             // Of course - this task can be already dead - means disposed.
920             // But for us it's not important. Because we tried to close it too.
921             // And "already disposed" or "closed" should be the same ...
922             bClosed = true;
923         }
924 
925         return bClosed;
926     }
927 
928     // ____________________
929 
930     /**
931      * Try to find an unique frame name, which isn't currently used inside
932      * remote office instance. Because we create top level frames
933      * only, it's enough to check the names of existing child frames on the
934      * desktop only.
935      *
936      * @return [String]
937      *          should represent an unique frame name, which currently isn't
938      *          used inside the remote office frame tree
939      *          (Couldn't guaranteed for a real multithreaded environment.
940      *           But we try it ...)
941      */
942     private static final String BASEFRAMENAME = "Desk View ";
943 
944     public static String getUniqueFrameName()
945     {
946         String sName = null;
947 
948         com.sun.star.uno.XComponentContext xCtx = OfficeConnect.getOfficeContext();
949 
950         try
951         {
952             com.sun.star.frame.XFramesSupplier xSupplier =
953                 (com.sun.star.frame.XFramesSupplier)UnoRuntime.queryInterface(
954                     com.sun.star.frame.XFramesSupplier.class,
955                     xCtx.getServiceManager().createInstanceWithContext(
956                         "com.sun.star.frame.Desktop", xCtx));
957 
958             com.sun.star.container.XIndexAccess xContainer =
959                 (com.sun.star.container.XIndexAccess)UnoRuntime.queryInterface(
960                     com.sun.star.container.XIndexAccess.class,
961                     xSupplier.getFrames());
962 
963             int nCount = xContainer.getCount();
964             for (int i=0; i<nCount; ++i )
965             {
966                 com.sun.star.frame.XFrame xFrame = (com.sun.star.frame.XFrame)AnyConverter.toObject(new com.sun.star.uno.Type(com.sun.star.frame.XFrame.class), xContainer.getByIndex(i));
967                                         sName  = new String(BASEFRAMENAME+mnViewCount);
968                 while(sName.compareTo(xFrame.getName())==0)
969                 {
970                     ++mnViewCount;
971                     sName = new String(BASEFRAMENAME+mnViewCount);
972                 }
973             }
974         }
975         catch(com.sun.star.uno.Exception exCreateFailed)
976         {
977             sName = new String(BASEFRAMENAME);
978         }
979 
980         if (sName==null)
981         {
982             System.out.println("invalid name!");
983             sName = new String(BASEFRAMENAME);
984         }
985 
986         return sName;
987     }
988 
989     // ____________________
990 
991     /**
992      * helper to get a file URL selected by user
993      * This method doesn't show any API concepts ...
994      * but is neccessary rof this demo application.
995      *
996      * @param   aParent parent window of this dialog
997      * @param   bOpen   If it is set to true =>
998      *                  dialog is opend in "file open" mode -
999      *                  otherwise in "file save" mode.
1000      */
1001     public static String askUserForFileURL(Component aParent,boolean bOpen)
1002     {
1003         String        sFileURL  = null;
1004         int           nDecision = JFileChooser.CANCEL_OPTION;
1005         JFileChooser  aChooser  = null;
1006 
1007         // set last visited directory on new file chosser
1008         // (if this information is available)
1009         if( maLastDir==null )
1010             aChooser = new JFileChooser();
1011         else
1012             aChooser = new JFileChooser(maLastDir);
1013 
1014         // decide between file open/save dialog
1015         if( bOpen==true )
1016             nDecision = aChooser.showOpenDialog(aParent);
1017         else
1018             nDecision = aChooser.showSaveDialog(aParent);
1019 
1020         // react for "OK" result only
1021         if(nDecision == JFileChooser.APPROVE_OPTION)
1022         {
1023             // save current directory as last visited one
1024             maLastDir = aChooser.getCurrentDirectory();
1025             // get file URL from the dialog
1026             try
1027             {
1028                 sFileURL = aChooser.getSelectedFile().toURL().toExternalForm();
1029             }
1030             catch( MalformedURLException ex )
1031             {
1032                 ex.printStackTrace();
1033                 sFileURL = null;
1034             }
1035             // problem of java: file URL's are coded with 1 slash instead of 3 ones!
1036             // => correct this problem first, otherwise office can't use these URL's
1037             if(
1038                 ( sFileURL                      !=null  ) &&
1039                 ( sFileURL.startsWith("file:/") ==true  ) &&
1040                 ( sFileURL.startsWith("file://")==false )
1041               )
1042             {
1043                 StringBuffer sWorkBuffer = new StringBuffer(sFileURL);
1044                 sWorkBuffer.insert(6,"//");
1045                 sFileURL = sWorkBuffer.toString();
1046             }
1047         }
1048 
1049         return sFileURL;
1050     }
1051 
1052     // ____________________
1053 
1054     /**
1055      * @member  maLastDir   save the last visited directory of used file open/save dialog
1056      * @member  mnViewCount we try to set unique names on every frame we create (that's why we must count it)
1057      */
1058     private static File maLastDir   = null;
1059     private static int  mnViewCount = 0   ;
1060 }
1061