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