diff options
Diffstat (limited to 'odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment')
23 files changed, 4837 insertions, 0 deletions
diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/CustomizeView.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/CustomizeView.java new file mode 100644 index 000000000..f19429585 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/CustomizeView.java @@ -0,0 +1,285 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.awt.*; +import javax.swing.*; +import java.awt.event.*; + +/** + * Makes it possible to change some states of currently loaded + * document (e.g. enable/disable menubar, toolbar, objectbar) + * + */ +public class CustomizeView extends JPanel + implements IShutdownListener +{ + /** + * These const URL's describe feature for toggling some properties of loaded document. + * Dispatch it with the corresponding parameter to the frame. + */ + private static final String FEATUREURL_MENUBAR = "slot:6661" ; + private static final String FEATUREURL_TOOLBAR = "slot:5909" ; + private static final String FEATUREURL_OBJECTBAR = "slot:5905" ; + + private static final String FEATUREPROP_MENUBAR = "MenuBarVisible" ; + private static final String FEATUREPROP_TOOLBAR = "ToolBarVisible" ; + private static final String FEATUREPROP_OBJECTBAR = "ObjectBarVisible" ; + + private static final String ACTION_MENUBAR = "toggle_menu" ; + private static final String ACTION_TOOLBAR = "toggle_toolbar" ; + private static final String ACTION_OBJECTBAR = "toggle_objectbar" ; + + private static final String MENUBAR_ON = "menubar on" ; + private static final String TOOLBAR_ON = "toolbar on" ; + private static final String OBJECTBAR_ON = "objectbar on" ; + + private static final String MENUBAR_OFF = "menubar off" ; + private static final String TOOLBAR_OFF = "toolbar off" ; + private static final String OBJECTBAR_OFF = "objectbar off" ; + + + // member + + /** + * @member m_cbMenuBar reference to checkbox for toggling menubar + * @member m_cbToolBar reference to checkbox for toggling toolbar + * @member m_cbObjectBar reference to checkbox for toggling objectbar + * + * @member m_aMenuBarListener listener for status events of the menu bar + * @member m_aToolBarListener listener for status events of the tool bar + * @member m_aObjectBarListener listener for status events of the object bar + */ + private final JCheckBox m_cbMenuBar ; + private final JCheckBox m_cbToolBar ; + private final JCheckBox m_cbObjectBar ; + + private StatusListener m_aMenuBarListener ; + private StatusListener m_aToolBarListener ; + private StatusListener m_aObjectBarListener; + + + + /** + * ctor + * Create view controls on startup and initialize it. + * We don't start listening here. see setFrame()! + */ + CustomizeView() + { + this.setLayout(new GridLayout(3,0)); + + m_cbMenuBar = new JCheckBox(MENUBAR_OFF , false); + m_cbToolBar = new JCheckBox(TOOLBAR_OFF , false); + m_cbObjectBar = new JCheckBox(OBJECTBAR_OFF, false); + + m_cbMenuBar.setEnabled (false); + m_cbToolBar.setEnabled (false); + m_cbObjectBar.setEnabled(false); + + m_cbMenuBar.setActionCommand (ACTION_MENUBAR ); + m_cbToolBar.setActionCommand (ACTION_TOOLBAR ); + m_cbObjectBar.setActionCommand(ACTION_OBJECTBAR); + + this.add(m_cbMenuBar ); + this.add(m_cbToolBar ); + this.add(m_cbObjectBar); + } + + + + /** + * set new frame for this view + * We start listening for frame action/status and click events instandly. + * If an event occurs, we use it to synchronize our controls + * with states of a (maybe) new document view of this frame. + * + * @param xFrame + * the reference to the frame, which provides the + * possibility to get the required status information + * + * Attention: We don't accept new frames here. + * We get one after startup and work with it. + * That's it! + */ + public void setFrame(com.sun.star.frame.XFrame xFrame) + { + if (xFrame==null) + return; + + // be listener for click events + // They will toggle the UI controls. + ClickListener aMenuBarHandler = new ClickListener(FEATUREURL_MENUBAR ,FEATUREPROP_MENUBAR ,xFrame); + ClickListener aToolBarHandler = new ClickListener(FEATUREURL_TOOLBAR ,FEATUREPROP_TOOLBAR ,xFrame); + ClickListener aObjectBarHandler = new ClickListener(FEATUREURL_OBJECTBAR,FEATUREPROP_OBJECTBAR,xFrame); + + m_cbMenuBar.addActionListener (aMenuBarHandler ); + m_cbToolBar.addActionListener (aToolBarHandler ); + m_cbObjectBar.addActionListener(aObjectBarHandler); + + // be frame action listener + // The callback will update listener connections + // for status updates automatically! + m_aMenuBarListener = new StatusListener(m_cbMenuBar ,MENUBAR_ON ,MENUBAR_OFF ,xFrame, FEATUREURL_MENUBAR ); + m_aToolBarListener = new StatusListener(m_cbToolBar ,TOOLBAR_ON ,TOOLBAR_OFF ,xFrame, FEATUREURL_TOOLBAR ); + m_aObjectBarListener = new StatusListener(m_cbObjectBar,OBJECTBAR_ON,OBJECTBAR_OFF,xFrame, FEATUREURL_OBJECTBAR); + + m_aMenuBarListener.startListening(); + m_aToolBarListener.startListening(); + m_aObjectBarListener.startListening(); + } + + + + /* + * react for click events of the used check boxes + * We use our internal set dispatch objects to + * call it. This calls toggle the menu/object- or toolbar. + * Note: Because we are listener status events too - hopefully + * we get a notification, if toggling was successfully or not. + * We use this information to update our check boxes again. + * But such update doesn't force (hopefully) an action event. Otherwise + * we can produce a never ending recursion! + */ + private class ClickListener implements ActionListener, + com.sun.star.lang.XEventListener + { + /// URL, to toggle the requested UI item + private final String m_sURL; + /// name of the property which must be used in combination with the URL + private final String m_sProp; + /// we must use this frame to dispatch a request + private com.sun.star.frame.XFrame m_xFrame; + + + + /** + * ctor + * It initialize an instance of this class only. + */ + private ClickListener( String sURL , + String sProp , + com.sun.star.frame.XFrame xFrame ) + { + m_sURL = sURL ; + m_sProp = sProp ; + m_xFrame = xFrame; + } + + + + /** + * callback for action events + * Such events occur, if someone clicked the + * JCheckBox control, on which we are registered. + * Such events do not occur, if we set it programmatically + * (e.g. if we get status events to -> see class StatusListener too) + * + * @param aEvent + * describes the check box and its state + * we can use to toggle the requested office + * resource. + */ + public void actionPerformed(ActionEvent aEvent) + { + synchronized(this) + { + if (m_xFrame==null) + return; + } + + // define parameters for following dispatch + boolean bState = ((JCheckBox)aEvent.getSource()).isSelected(); + + // prepare the dispatch + com.sun.star.util.URL aURL = FunctionHelper.parseURL(m_sURL); + if (aURL==null) + return; + + com.sun.star.beans.PropertyValue[] lProperties = new com.sun.star.beans.PropertyValue[1]; + lProperties[0] = new com.sun.star.beans.PropertyValue(); + lProperties[0].Name = m_sProp; + lProperties[0].Value = Boolean.valueOf(bState); + + // execute (dispatch) it into the frame + if (m_xFrame==null) + return; + FunctionHelper.execute(m_xFrame,aURL,lProperties,null); + } + + + + /** + * callback for disposing events + * Internally we save a reference to an office frame. + * Of course he can die and inform us then. We should react + * and forget his reference. + * + * @param aEvent + * describes the source which fire this event + * Must be our internal saved frame. Otherwise + * somewhere know us without a registration ... + */ + public void disposing(com.sun.star.lang.EventObject aEvent) + { + synchronized(this) + { + m_xFrame = null; + } + } + } + + + + /** + * If this java application shutdown - we must cancel all current existing + * listener connections. Otherwise the office will run into some + * DisposedExceptions if it tries to use these forgotten listener references. + * And of course it can die doing that. + * We are registered at a central object to be informed if the VM will exit. + * So we can react. + */ + public void shutdown() + { + m_aMenuBarListener.shutdown(); + m_aToolBarListener.shutdown(); + m_aObjectBarListener.shutdown(); + + m_aMenuBarListener = null; + m_aToolBarListener = null; + m_aObjectBarListener = null; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Desk.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Desk.java new file mode 100644 index 000000000..7ce2682fe --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Desk.java @@ -0,0 +1,93 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +// __________ Imports __________ + +// __________ Implementation __________ + +/** + * TODO + * + */ +public class Desk +{ + + + /** + * main + * Establish connection to a remote office and starts the demo application. + * User can overwrite some of necessary start options by using command line parameters. + * + * syntax: Desk [mode={inplace|outplace}] [file=<filename>] + * + * @param lArguments command line arguments + * mode describe using mode of document view {inplace/outplace} + * default=inplace + * file name of first file which should be open + * default="private:factory/swriter" to open empty writer document + */ + public static void main(String[] lArguments) + { + // Analyze command line parameters. + String sMode = "inplace"; + String sFile = "private:factory/swriter"; + + for(int i=0; i<lArguments.length; ++i) + { + lArguments[i] = lArguments[i].toLowerCase(); + if(lArguments[i].startsWith("mode=")) + sMode = lArguments[i].substring(5); + else + if(lArguments[i].startsWith("file=")) + sFile = lArguments[i].substring(5); + } + + ViewContainer.mbInplace = sMode.equals("inplace"); + + // Connect to remote office. + OfficeConnect.createConnection(); + + // Create first document view. + // This one will register himself at the global + // ViewContainer. Further views will be open + // automatically started from this first one. + DocumentView aView = new DocumentView(); + aView.setVisible(true); + aView.createFrame(); + aView.load(sFile); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/DocumentView.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/DocumentView.java new file mode 100644 index 000000000..57ac4e779 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/DocumentView.java @@ -0,0 +1,428 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +// __________ Imports __________ + +import com.sun.star.uno.UnoRuntime; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.border.*; +import java.awt.AWTEvent; +import java.awt.event.WindowEvent; + +// __________ Implementation __________ + +/** + * This implement a java frame which contains + * an office document, shows some status information + * about that, provides simple functionality on it + * (e.g. toggle menubar, save document) and + * react for different situations independent + * (e.g. closing the document from outside). + * Every instance of this class will be a member + * inside the global "ViewContainer" of this java + * demo application which holds all opened views alive. + * + */ +public class DocumentView extends JFrame + implements com.sun.star.lang.XEventListener, // react for Frame::disposing() + IShutdownListener // react for System.exit() +{ + + + /** + * const + * These command strings are used to identify a received action + * of buttons on which we listen for action events. + */ + private static final String COMMAND_OPEN = "open" ; + private static final String COMMAND_SAVE = "save" ; + private static final String COMMAND_EXPORT = "export" ; + private static final String COMMAND_EXIT = "exit" ; + + + + /** + * @member mxFrame office frame which contains the document of this view + * + * @member maStatusView special panel which shows available status information of currently loaded document + * @member maDocumentView use JNI mechanism to plug an office window into our own java UI container (used for inplace mode only!) + * @member maCustomizeView special panel makes it possible to toggle menubar/toolbar or objectbar of loaded document + * @member maInterceptor interceptor thread which intercept "new" menu of office frame to open new frames inside this java application + * + * @member msName unique name of this view (returned by the global ViewContainer during registration) + * + * @member mbOpen button to open documents + * @member mbSave button to save currently loaded document + * @member mbExport button to save currently loaded document in HTML format (if it is possible!) + * @member mbExit button to exit this demo + * + * @member maInterception we try to intercept the file->new menu to open new document inside this java application + */ + private com.sun.star.frame.XFrame mxFrame ; + + private StatusView maStatusView ; + private NativeView maDocumentView ; + private CustomizeView maCustomizeView ; + private Interceptor maInterceptor ; + + private final String msName; + + private final JButton mbtSave; + private final JButton mbtExport; + + private boolean mbDead ; + + + + /** + * ctor + * Create view controls on startup and initialize it with default values. + */ + DocumentView() + { + this.setSize( new Dimension(800,600) ); + + JPanel paMainPanel = (JPanel)this.getContentPane(); + + // create and add command buttons to a panel + // it will be a sub panel of later layouted UI + JButton mbtOpen = new JButton("Open ..." ); + mbtSave = new JButton("Save" ); + mbtExport = new JButton("Save as HTML ..."); + JButton mbtExit = new JButton("Exit" ); + + mbtOpen.setEnabled (true ); + mbtSave.setEnabled (false); + mbtExport.setEnabled(false); + mbtExit.setEnabled (true ); + + mbtOpen.setActionCommand (COMMAND_OPEN ); + mbtSave.setActionCommand (COMMAND_SAVE ); + mbtExport.setActionCommand(COMMAND_EXPORT); + mbtExit.setActionCommand (COMMAND_EXIT ); + + Reactor aListener = new Reactor(); + mbtOpen.addActionListener (aListener); + mbtSave.addActionListener (aListener); + mbtExport.addActionListener(aListener); + mbtExit.addActionListener (aListener); + + JPanel paCommands = new JPanel( new GridLayout(4,0) ); + paCommands.add(mbtOpen); + paCommands.add(mbtSave); + paCommands.add(mbtExport); + paCommands.add(mbtExit); + + // create view to show status information of opened file + maStatusView = new StatusView(); + + // create view for toggle different bar's of document + maCustomizeView = new CustomizeView(); + + paCommands.setBorder ( new TitledBorder(BorderFactory.createEtchedBorder(),"Commands") ); + maStatusView.setBorder ( new TitledBorder(BorderFactory.createEtchedBorder(),"Status Information") ); + maCustomizeView.setBorder( new TitledBorder(BorderFactory.createEtchedBorder(),"Customize Document View") ); + + // layout the whole UI + JPanel paTest = new JPanel(new GridLayout(3,0)); + paTest.add(paCommands ); + paTest.add(maStatusView ); + paTest.add(maCustomizeView); + JScrollPane paScroll = new JScrollPane(); + paScroll.getViewport().add(paTest,null); + + if(ViewContainer.mbInplace) + { + // create view to show opened documents + // This special view is necessary for inplace mode only! + maDocumentView = new NativeView(); + + JSplitPane paSplit = new JSplitPane(); + paSplit.setOneTouchExpandable( true ); + + paSplit.setLeftComponent (maDocumentView); + paSplit.setRightComponent(paScroll ); + + paMainPanel.add(paSplit); + } + else + { + paMainPanel.add(paScroll); + } + + // Register this new view on our global view container. + msName = FunctionHelper.getUniqueFrameName(); + this.setTitle(msName); + ViewContainer.getGlobalContainer().addView(this); + ViewContainer.getGlobalContainer().addListener(this); + // be listener for closing the application + this.enableEvents(AWTEvent.WINDOW_EVENT_MASK); + } + + + + /** + * Create the view frame for showing the office documents on demand. + * Depending on given command line parameter we create + * an office XFrame and initialize it with a window. This + * window can be a pure toolkit window (means toolkit of office!) + * or a plugged java canvas - office window combination. + */ + public void createFrame() + { + // create view frame (as a XFrame!) here + // Look for right view mode set by user command line parameter. + // First try to get a new unambiguous frame name from our global ViewContainer. + if(ViewContainer.mbInplace) + { + // inplace document view can't be initialized without a visible parent window hierarchy! + // So make sure that we are visible in every case! + this.setVisible(true); + mxFrame = FunctionHelper.createViewFrame(msName,maDocumentView); + } + else + mxFrame = FunctionHelper.createViewFrame(msName,null); + + if(mxFrame!=null) + { + // start interception + maInterceptor = new Interceptor(mxFrame); + maInterceptor.startListening(); + + // start listening for status events and actualization + // of our status view + // (of course for our CustomizeView too) + maStatusView.setFrame (mxFrame); + maCustomizeView.setFrame(mxFrame); + + // be listener for closing the remote target view frame + com.sun.star.lang.XComponent xBroadcaster = UnoRuntime.queryInterface( + com.sun.star.lang.XComponent.class, + mxFrame); + + if(xBroadcaster!=null) + xBroadcaster.addEventListener(this); + } + } + + + + /** + * Different ways to load any URL from outside (may be by the command line) + * into this document view or to save it. + */ + public void load(String sURL) + { + load(sURL,new com.sun.star.beans.PropertyValue[0]); + } + + + + public void load(String sURL, com.sun.star.beans.PropertyValue[] lArguments) + { + com.sun.star.lang.XComponent xDocument = FunctionHelper.loadDocument(mxFrame,sURL,lArguments); + if(xDocument!=null) + { + mbtSave.setEnabled (true); + mbtExport.setEnabled(true); + } + else + { + mbtSave.setEnabled (false); + mbtExport.setEnabled(false); + } + } + + + + private void save() + { + com.sun.star.frame.XController xController = mxFrame.getController(); + if (xController==null) + return; + com.sun.star.frame.XModel xDocument = xController.getModel(); + if (xDocument==null) + return; + FunctionHelper.saveDocument(xDocument); + } + + + + private void exportHTML(String sURL) + { + com.sun.star.frame.XController xController = mxFrame.getController(); + if (xController==null) + return; + com.sun.star.frame.XModel xDocument = xController.getModel(); + if (xDocument==null) + return; + FunctionHelper.saveAsHTML(xDocument,sURL); + } + + + + /** + * Overridden so we can react for window closing of this view. + */ + @Override + protected void processWindowEvent(WindowEvent aEvent) + { + if (aEvent.getID()!=WindowEvent.WINDOW_CLOSING) + { + super.processWindowEvent(aEvent); + } + else + if (FunctionHelper.closeFrame(mxFrame)) + { + mxFrame = null; + shutdown(); + super.processWindowEvent(aEvent); + } + } + + + + /** + * Here we can react for System.exit() normally. + * But we use it for disposing() or windowClosing() too. + */ + public void shutdown() + { + if (mbDead) + return; + mbDead=true; + + // force these sub view to release her remote + // references too! + maStatusView.shutdown(); + maCustomizeView.shutdown(); + + maStatusView = null; + maCustomizeView = null; + + // disable all interceptions + maInterceptor.shutdown(); + maInterceptor = null; + + // close the frame and his document + // Releasing of our listener connections for disposing() + // will be forced automatically then. Because the frame + // will call us back ... + if (mxFrame!=null) + FunctionHelper.closeFrame(mxFrame); + + // deregister this view in the global container + // Normally we should die afterwards by garbage collection ... + // In cease this was the last view - it force a system.exit(). + // But then we are no longer a member of the global container + // of possible shutdown listener ... and this method should be + // called again. + ViewContainer.getGlobalContainer().removeView(this); + } + + + + /** + * callback from our internal saved frame + * which wishes to die. It's not necessary to remove listener connections + * here. Because the broadcaster do it automatically. + * We have to release all references to him only. + * + * @param aSource + * describe the broadcaster of this event + * Must be our internal saved frame. + */ + public void disposing(com.sun.star.lang.EventObject aSource) + { + mxFrame = null; + } + + + + /** + * This inner class is used to react for events of our own UI controls. + * So we can start different actions then. + */ + private class Reactor implements ActionListener + { + + + /** + * This method react for pressed buttons or selected check boxes. + */ + public void actionPerformed(ActionEvent aEvent) + { + String sCommand = aEvent.getActionCommand(); + + // open any file from disk + if( sCommand.equals(COMMAND_OPEN) ) + { + String sURL = FunctionHelper.askUserForFileURL(DocumentView.this,true); + if(sURL!=null) + DocumentView.this.load(sURL); + } + else + + // save current document + if( sCommand.equals(COMMAND_SAVE) ) + { + DocumentView.this.save(); + } + else + + // export current document to html + if( sCommand.equals(COMMAND_EXPORT)) + { + String sURL = FunctionHelper.askUserForFileURL(DocumentView.this,false); + if(sURL!=null) + DocumentView.this.exportHTML(sURL); + } + else + + // exit application + if( sCommand.equals(COMMAND_EXIT) ) + { + // This will force deleting of this and + // all other currently opened views automatically! + System.exit(0); + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/FunctionHelper.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/FunctionHelper.java new file mode 100644 index 000000000..fa24cde96 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/FunctionHelper.java @@ -0,0 +1,939 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +// __________ Imports __________ + +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.AnyConverter; + +import java.awt.*; +import javax.swing.*; +import java.io.*; +import java.net.*; + +// __________ Implementation __________ + +/** + * Is a collection of basic features. + * This helper shows different functionality of framework api + * in an example manner. You can use the follow ones: + * (1) parse URL's + * (2) create frames (inside/outside a java application) + * (3) dispatches (with[out] notifications) + * (4) loading/saving documents + * (5) convert documents to HTML (if possible) + * (6) close documents (and her frames) correctly + * + * There exist some other helper functionality too, which + * doesn't use or demonstrate the office api: + * (a) getting file names by using a file chosser + */ +public class FunctionHelper +{ + + + /** + * This convert a URL (formatted as a string) to a struct com.sun.star.util.URL. + * It use a special service to do that: the URLTransformer. + * Because some API calls need it and it's not allowed to set "Complete" + * part of the util struct only. The URL must be parsed. + * + * @param sURL + * URL for parsing in string notation + * + * @return [com.sun.star.util.URL] + * URL in UNO struct notation + */ + public static com.sun.star.util.URL parseURL(String sURL) + { + com.sun.star.util.URL aURL = null; + + if (sURL==null || sURL.equals("")) + { + System.out.println("wrong using of URL parser"); + return null; + } + + try + { + com.sun.star.uno.XComponentContext xOfficeCtx = + OfficeConnect.getOfficeContext(); + + // Create special service for parsing of given URL. + com.sun.star.util.XURLTransformer xParser = + UnoRuntime.queryInterface( + com.sun.star.util.XURLTransformer.class, + xOfficeCtx.getServiceManager().createInstanceWithContext( + "com.sun.star.util.URLTransformer", xOfficeCtx)); + + // Because it's an in/out parameter we must use an array of URL objects. + com.sun.star.util.URL[] aParseURL = new com.sun.star.util.URL[1]; + aParseURL[0] = new com.sun.star.util.URL(); + aParseURL[0].Complete = sURL; + + // Parse the URL + xParser.parseStrict(aParseURL); + + aURL = aParseURL[0]; + } + catch(com.sun.star.uno.RuntimeException exRuntime) + { + // Any UNO method of this scope can throw this exception. + // Reset the return value only. + } + catch(com.sun.star.uno.Exception exUno) + { + // "createInstance()" method of used service manager can throw it. + // Then it wasn't possible to get the URL transformer. + // Return default instead of really parsed URL. + } + + return aURL; + } + + + + /** + * create a new empty target frame + * Attention: Currently we must use special service com.sun.star.frame.Task instead of Frame. + * Because desktop environment accept this special frame type only as direct children. + * Note - This service will be deprecated and must be replaces by com.sun.star.frame.Frame in + * further versions. To feature prove we use both service names. If for new versions + * the deprecated one not exist we get an empty frame, we can try to use the new service. + * + * @param xSMGR + * we need the remote service manager to create this task/frame service + * + * @return [com.sun.star.frame.XFrame] + * the new created frame reference in case of success or null otherwise + */ + private static com.sun.star.frame.XFrame impl_createEmptyFrame( + com.sun.star.uno.XComponentContext xCtx ) + { + com.sun.star.frame.XFrame xFrame = null; + + try{ + xFrame = UnoRuntime.queryInterface( + com.sun.star.frame.XFrame.class, + xCtx.getServiceManager().createInstanceWithContext( + "com.sun.star.frame.Task", xCtx)); + } catch(com.sun.star.uno.Exception ex1) {} + + if (xFrame==null) + { + try{ + xFrame = UnoRuntime.queryInterface( + com.sun.star.frame.XFrame.class, + xCtx.getServiceManager().createInstanceWithContext( + "com.sun.star.frame.Frame", xCtx)); + } catch(com.sun.star.uno.Exception ex2) {} + } + + return xFrame; + } + + + + /** + * create a new window which can be used as container window of an office frame + * We know two modes for creation: + * - the office window will be a child of one of our java windows + * - the office will be a normal system window outside this java application + * This behaviour will be regulated by the second parameter of this operation. + * If a parentview is given the first mode will be activated - otherwise + * the second one. + * + * Note: First mode (creation of a child window) can be reached by two different + * ways. + * - pack the required window handle of our java window inside a UNO object + * to transport it to the remote office toolkit and get a child office + * window. + * This is the old way. It's better to use the second one - but to be + * future prove this old one should be tried too. + * - it's possible to pass the native window handle directly to the toolkit. + * A special interface method was enabled to accept that. + * + * The right way to create an office window should be then: + * - try to use second creation mode (directly using of the window handle) + * - if it failed ... use the old way by packing the handle inside an object + * + * @param xSMGR + * we need a service manager to be able to create remote office + * services + * + * @param aParentView + * the java window as parent for the office window if an inplace office + * is required. If it is set to null the created office window will be + * a normal system window outside of our java application. + * + * @return [com.sun.star.awt.XWindow] + * The new created office window which can be used to set it as + * a ContainerWindow on an empty office frame. + */ + private static com.sun.star.awt.XWindow impl_createWindow( + com.sun.star.uno.XComponentContext xCtx, NativeView aParentView ) + { + com.sun.star.awt.XWindow xWindow = null; + com.sun.star.awt.XWindowPeer xPeer = null; + com.sun.star.awt.XToolkit xToolkit = null; + + // get access to toolkit of remote office to create the container window of + // new target frame + try{ + xToolkit = UnoRuntime.queryInterface( + com.sun.star.awt.XToolkit.class, + xCtx.getServiceManager().createInstanceWithContext( + "com.sun.star.awt.Toolkit", xCtx)); + } + catch(com.sun.star.uno.Exception ex) + { + return null; + } + + // mode 1) create an external system window + if (aParentView==null) + { + // Describe the properties of the container window. + com.sun.star.awt.WindowDescriptor aDescriptor = + new com.sun.star.awt.WindowDescriptor(); + aDescriptor.Type = com.sun.star.awt.WindowClass.TOP; + aDescriptor.WindowServiceName = "window"; + aDescriptor.ParentIndex = -1; + aDescriptor.Parent = null; + aDescriptor.Bounds = new com.sun.star.awt.Rectangle(0,0,0,0); + aDescriptor.WindowAttributes = com.sun.star.awt.WindowAttribute.BORDER | + com.sun.star.awt.WindowAttribute.MOVEABLE | + com.sun.star.awt.WindowAttribute.SIZEABLE | + com.sun.star.awt.WindowAttribute.CLOSEABLE; + + try{ + xPeer = xToolkit.createWindow( aDescriptor ); + } catch(com.sun.star.lang.IllegalArgumentException exIllegal) {} + } + // mode 2) create an internal office window as child of our given java + // parent window + else + { + // try new version of creation first: directly using of the window + // handle. The old implementation of the corresponding toolkit method + // requires a process ID. If this id isn't the right one a null object + // is returned. But normally nobody outside the office knows this id. + // New version of this method ignore the id parameter and creation will + // work. + // Note: You must be sure if your window handle can be really used by + // the remote office. Means if this java client and the remote office + // use the same display! + com.sun.star.awt.XSystemChildFactory xChildFactory = + UnoRuntime.queryInterface( + com.sun.star.awt.XSystemChildFactory.class, xToolkit); + + try + { + Integer nHandle = aParentView.getHWND(); + short nSystem = (short)aParentView.getNativeWindowSystemType(); + byte[] lProcID = new byte[0]; + + xPeer = xChildFactory.createSystemChild(nHandle, + lProcID, nSystem); + + if (xPeer==null) + { + // mode 3) OK - new version doesn't work. It requires the + // process id which we don't have. + // So we must use the old way to get the right window peer. + // Pack the handle inside a wrapper object. + JavaWindowPeerFake aWrapper = new + JavaWindowPeerFake(aParentView); + + com.sun.star.awt.XWindowPeer xParentPeer = + UnoRuntime.queryInterface( + com.sun.star.awt.XWindowPeer.class, aWrapper); + + com.sun.star.awt.WindowDescriptor aDescriptor = + new com.sun.star.awt.WindowDescriptor(); + aDescriptor.Type = com.sun.star.awt.WindowClass.TOP; + aDescriptor.WindowServiceName = "workwindow"; + aDescriptor.ParentIndex = 1; + aDescriptor.Parent = xParentPeer; + aDescriptor.Bounds = new com.sun.star.awt.Rectangle(0,0,0,0); + if (nSystem == com.sun.star.lang.SystemDependent.SYSTEM_WIN32) + aDescriptor.WindowAttributes = + com.sun.star.awt.WindowAttribute.SHOW; + else + aDescriptor.WindowAttributes = + com.sun.star.awt.WindowAttribute.SYSTEMDEPENDENT; + + try{ + xPeer = xToolkit.createWindow( aDescriptor ); + } catch(com.sun.star.lang.IllegalArgumentException exIllegal) {} + } + } + catch(java.lang.RuntimeException exJRun) + { + // This exception is thrown by the native JNI code if it try to get + // the systemw window handle. A possible reason can be an invisible + // java window. In this case it should be enough to set return + // values to null. All other resources (which was created before) + // will be freed automatically if scope will be leaved. + System.out.println("May be the NativeView object wasn't really visible at calling time of getNativeWindow()?"); + xPeer = null; + xWindow = null; + } + } + + // It doesn't matter which way was used to get the window peer. + // Cast it to the right return interface and return it. + xWindow = UnoRuntime.queryInterface( + com.sun.star.awt.XWindow.class, + xPeer); + + return xWindow; + } + + + + /** + * This method create a new empty child frame on desktop instance of remote office. + * It use a special JNI functionality to pass the office XWindow over a java window. + * This java window can be inserted into another java window container for complex layouting. + * If this parent java window isn't used, a top level system window will be created. + * The resulting office frame isn't plugged into this java application. + * + * @param sName + * name to set it on the new created frame + * + * @param aParentView + * java window which should be used as parent window of new created office frame window + * May be set to null. + * + * @return [com.sun.star.frame.XFrame] + * reference to the new created frame for success or null if it failed + */ + public static com.sun.star.frame.XFrame createViewFrame(String sName, NativeView aParentView) + { + com.sun.star.frame.XFrame xFrame = null; + + try + { + com.sun.star.uno.XComponentContext xCtx = + OfficeConnect.getOfficeContext(); + + // create an empty office frame first + xFrame = impl_createEmptyFrame(xCtx); + + // create an office window then + // Depending from the given parameter aParentView it will be a child or a top level + // system window. (see impl method for further information) + // But before we call this helper - prepare the possible parent window: show it. + // JNI calls to get system window handle of java window can't work without that! + if (aParentView!=null) + aParentView.setVisible(true); + com.sun.star.awt.XWindow xWindow = impl_createWindow(xCtx, aParentView); + + // pass the window the frame as his new container window. + // It's necessary to do it first - before you call anything else there. + // Otherwise the frame throws some exceptions for "uninitialized state". + xFrame.initialize( xWindow ); + + // Insert the new frame in desktop hierarchy. + // Use XFrames interface to do so. It provides access to the child frame container of that instance. + com.sun.star.frame.XFramesSupplier xTreeRoot = UnoRuntime.queryInterface( + com.sun.star.frame.XFramesSupplier.class, + xCtx.getServiceManager().createInstanceWithContext( + "com.sun.star.frame.Desktop", xCtx)); + com.sun.star.frame.XFrames xChildContainer = xTreeRoot.getFrames(); + xChildContainer.append(xFrame); + + // Make some further initializations on frame and window. + xWindow.setVisible(true); + xFrame.setName(sName); + } + catch(com.sun.star.uno.RuntimeException exRuntime) + { + // Any UNO method of this scope can throw this exception. + // So the frame can be already created and he must be freed + // correctly. May be he was inserted into the desktop tree too ... + if(xFrame!=null) + { + // Try to dispose the frame. He should deregister himself at the desktop object + // and free all internal used resources (e.g. the container window) automatically. + // It's possible to do that here - because frame has no component inside yet. + // So nobody can disagree with that. + // After the dispose() call forget all references to this frame and let him die. + // If a new exception will occur ... no general solution exist then. + // Nobody can guarantee if next call will work or not. + com.sun.star.lang.XComponent xComponent = UnoRuntime.queryInterface( + com.sun.star.lang.XComponent.class, + xFrame); + xComponent.dispose(); + xComponent = null; + xFrame = null; + } + } + catch(com.sun.star.uno.Exception exUno) + { + // "createInstance()" method of used service manager can throw it. + // If it occurred during creation of desktop service the frame already was created. + // Free it by decreasing his refcount. Changes on the desktop tree couldn't exist. + // Without the desktop service that wasn't possible. So no further rollbacks must follow. + if(xFrame!=null) + { + com.sun.star.lang.XComponent xComponent = UnoRuntime.queryInterface( + com.sun.star.lang.XComponent.class, + xFrame); + xComponent.dispose(); + xComponent = null; + xFrame = null; + } + } + + return xFrame; + } + + + + /** + * Dispatch a URL to given frame. + * Caller can register himself for following status events for dispatched + * URL too. But nobody guarantee that such notifications will occur. + * (see dispatchWithNotification() if you interest on that) + * The returned dispatch object should be hold alive by caller + * till he doesn't need it any longer. Otherwise the dispatcher can(!) + * die by decreasing his refcount. + * + * @param xFrame frame which should be the target of this dispatch + * @param aURL full parsed and converted office URL for dispatch + * @param lProperties optional arguments for dispatch + * @param xListener optional listener which is registered automatically for status events + * (Note: Deregistration is part of this listener himself!) + * + * @return [XDispatch] It's the used dispatch object and can be used for deregistration of an optional listener. + * Otherwise caller can ignore it. + */ + public static com.sun.star.frame.XDispatch execute(com.sun.star.frame.XFrame xFrame , + com.sun.star.util.URL aURL , + com.sun.star.beans.PropertyValue[] lProperties, + com.sun.star.frame.XStatusListener xListener ) + { + com.sun.star.frame.XDispatch xDispatcher = null; + + try + { + // Query the frame for right interface which provides access to all available dispatch objects. + com.sun.star.frame.XDispatchProvider xProvider = UnoRuntime.queryInterface( + com.sun.star.frame.XDispatchProvider.class, + xFrame); + + // Ask him for right dispatch object for given URL. + // Force given frame as target for following dispatch by using "". + // It means the same like "_self". + xDispatcher = xProvider.queryDispatch(aURL,"",0); + + // Dispatch the URL into the frame. + if(xDispatcher!=null) + { + if(xListener!=null) + xDispatcher.addStatusListener(xListener,aURL); + + xDispatcher.dispatch(aURL,lProperties); + } + } + catch(com.sun.star.uno.RuntimeException exUno) + { + // Any UNO method of this scope can throw this exception. + // But there will be nothing to do then - because + // we haven't changed anything inside the remote objects + // except method "addStatusListener(). + // But in this case the source of this exception has to + // rollback all his operations. There is no chance to + // make anything right then. + // Reset the return value to a default - that's it. + exUno.printStackTrace(); + xDispatcher = null; + } + + return xDispatcher; + } + + + + + + + + /** + * Load document specified by a URL into given frame synchronously. + * The result of this operation will be the loaded document for success + * or null if loading failed. + * + * @param xFrame frame which should be the target of this load call + * @param sURL unparsed URL for loading + * @param lProperties optional arguments + * + * @return [XComponent] the loaded document for success or null if it's failed + */ + public static com.sun.star.lang.XComponent loadDocument( + com.sun.star.frame.XFrame xFrame, String sURL, + com.sun.star.beans.PropertyValue[] lProperties) + { + com.sun.star.lang.XComponent xDocument = null; + String sOldName = null; + + try + { + com.sun.star.uno.XComponentContext xCtx = + OfficeConnect.getOfficeContext(); + + // First prepare frame for loading + // We must address it inside the frame tree without any complications. + // So we set an unambiguous (we hope it) name and use it later. + // Don't forget to reset original name after that. + sOldName = xFrame.getName(); + String sTarget = "odk_officedev_desk"; + xFrame.setName(sTarget); + + // Get access to the global component loader of the office + // for synchronous loading the document. + com.sun.star.frame.XComponentLoader xLoader = + UnoRuntime.queryInterface( + com.sun.star.frame.XComponentLoader.class, + xCtx.getServiceManager().createInstanceWithContext( + "com.sun.star.frame.Desktop", xCtx)); + + // Load the document into the target frame by using his name and + // special search flags. + xDocument = xLoader.loadComponentFromURL( + sURL, + sTarget, + com.sun.star.frame.FrameSearchFlag.CHILDREN, + lProperties); + + // don't forget to restore old frame name... + xFrame.setName(sOldName); + } + catch(com.sun.star.io.IOException exIO) + { + // Can be thrown by "loadComponentFromURL()" call. + // The only thing we should do then is to reset changed frame name! + exIO.printStackTrace(); + xDocument = null; + if(sOldName!=null) + xFrame.setName(sOldName); + } + catch(com.sun.star.lang.IllegalArgumentException exIllegal) + { + // Can be thrown by "loadComponentFromURL()" call. + // The only thing we should do then is to reset changed frame name! + exIllegal.printStackTrace(); + xDocument = null; + if(sOldName!=null) + xFrame.setName(sOldName); + } + catch(com.sun.star.uno.RuntimeException exRuntime) + { + // Any UNO method of this scope can throw this exception. + // The only thing we can try(!) is to reset changed frame name. + exRuntime.printStackTrace(); + xDocument = null; + if(sOldName!=null) + xFrame.setName(sOldName); + } + catch(com.sun.star.uno.Exception exUno) + { + // "createInstance()" method of used service manager can throw it. + // The only thing we should do then is to reset changed frame name! + exUno.printStackTrace(); + xDocument = null; + if(sOldName!=null) + xFrame.setName(sOldName); + } + + return xDocument; + } + + + + /** + * Save currently loaded document of given frame. + * + * @param xDocument document for saving changes + */ + public static void saveDocument(com.sun.star.lang.XComponent xDocument) + { + try + { + // Check for supported model functionality. + // Normally the application documents (text, spreadsheet ...) do so + // but some other ones (e.g. db components) doesn't do that. + // They can't be save then. + com.sun.star.frame.XModel xModel = UnoRuntime.queryInterface( + com.sun.star.frame.XModel.class, + xDocument); + if(xModel!=null) + { + // Check for modifications => break save process if there is nothing to do. + com.sun.star.util.XModifiable xModified = UnoRuntime.queryInterface( + com.sun.star.util.XModifiable.class, + xModel); + if(xModified.isModified()) + { + com.sun.star.frame.XStorable xStore = UnoRuntime.queryInterface( + com.sun.star.frame.XStorable.class, + xModel); + + xStore.store(); + } + } + } + catch(com.sun.star.io.IOException exIO) + { + // Can be thrown by "store()" call. + // But there is nothing we can do then. + exIO.printStackTrace(); + } + catch(com.sun.star.uno.RuntimeException exUno) + { + // Any UNO method of this scope can throw this exception. + // But there is nothing we can do then. + exUno.printStackTrace(); + } + } + + + + /** + * It try to export given document in HTML format. + * Current document will be converted to HTML and moved to new place on disk. + * A "new" file will be created by given URL (may be overwritten + * if it already exist). Right filter will be used automatically if factory of + * this document support it. If no valid filter can be found for export, + * nothing will be done here. + * + * @param xDocument document which should be exported + * @param sURL target URL for converted document + */ + public static void saveAsHTML(com.sun.star.lang.XComponent xDocument, + String sURL ) + { + try + { + // First detect factory of this document. + // Ask for the supported service name of this document. + // If information is available it can be used to find out which + // filter exist for HTML export. Normally this filter should be searched + // inside the filter configuration but this little demo doesn't do so. + // (see service com.sun.star.document.FilterFactory for further + // information too) + // Well known filter names are used directly. They must exist in current + // office installation. Otherwise this code will fail. But to prevent + // this code against missing filters it check for existing state of it. + com.sun.star.lang.XServiceInfo xInfo = UnoRuntime.queryInterface(com.sun.star.lang.XServiceInfo.class, + xDocument); + + if(xInfo!=null) + { + // Find out possible filter name. + String sFilter = null; + if(xInfo.supportsService("com.sun.star.text.TextDocument")) + sFilter = "HTML (StarWriter)"; + else + if(xInfo.supportsService("com.sun.star.text.WebDocument")) + sFilter = "HTML"; + else + if(xInfo.supportsService("com.sun.star.sheet.SpreadsheetDocument")) + sFilter = "HTML (StarCalc)"; + + // Check for existing state of this filter. + if(sFilter!=null) + { + com.sun.star.uno.XComponentContext xCtx = + OfficeConnect.getOfficeContext(); + + com.sun.star.container.XNameAccess xFilterContainer = + UnoRuntime.queryInterface( + com.sun.star.container.XNameAccess.class, + xCtx.getServiceManager().createInstanceWithContext( + "com.sun.star.document.FilterFactory", xCtx)); + + if(!xFilterContainer.hasByName(sFilter)) + sFilter=null; + } + + // Use this filter for export. + if(sFilter!=null) + { + // Export can be forced by saving the document and using a + // special filter name which can write needed format. Build + // necessary argument list now. + // Use special flag "Overwrite" too, to prevent operation + // against possible exceptions, if file already exist. + com.sun.star.beans.PropertyValue[] lProperties = + new com.sun.star.beans.PropertyValue[2]; + lProperties[0] = new com.sun.star.beans.PropertyValue(); + lProperties[0].Name = "FilterName"; + lProperties[0].Value = sFilter; + lProperties[1] = new com.sun.star.beans.PropertyValue(); + lProperties[1].Name = "Overwrite"; + lProperties[1].Value = Boolean.TRUE; + + com.sun.star.frame.XStorable xStore = + UnoRuntime.queryInterface( + com.sun.star.frame.XStorable.class, xDocument); + + xStore.storeAsURL(sURL,lProperties); + } + } + } + catch(com.sun.star.io.IOException exIO) + { + // Can be thrown by "store()" call. + // Do nothing then. Saving failed - that's it. + exIO.printStackTrace(); + } + catch(com.sun.star.uno.RuntimeException exRuntime) + { + // Can be thrown by any uno call. + // Do nothing here. Saving failed - that's it. + exRuntime.printStackTrace(); + } + catch(com.sun.star.uno.Exception exUno) + { + // Can be thrown by "createInstance()" call of service manager. + // Do nothing here. Saving failed - that's it. + exUno.printStackTrace(); + } + } + + + + + + + + /* + * Try to close the frame instead of the document. + * It shows the possible interface to do so. + * + * @param xFrame + * frame which should be closed + * + * @return <TRUE/> in case frame could be closed + * <FALSE/> otherwise + */ + public static boolean closeFrame(com.sun.star.frame.XFrame xFrame) + { + boolean bClosed = false; + + try + { + // first try the new way: use new interface XCloseable + // It replace the deprecated XTask::close() and should be preferred ... + // if it can be queried. + com.sun.star.util.XCloseable xCloseable = + UnoRuntime.queryInterface( + com.sun.star.util.XCloseable.class, xFrame); + if (xCloseable!=null) + { + // We deliver the ownership of this frame not to the (possible) + // source which throw a CloseVetoException. We wish to have it + // under our own control. + try + { + xCloseable.close(false); + bClosed = true; + } + catch( com.sun.star.util.CloseVetoException exVeto ) + { + bClosed = false; + } + } + else + { + // OK: the new way isn't possible. Try the old one. + com.sun.star.frame.XTask xTask = UnoRuntime.queryInterface(com.sun.star.frame.XTask.class, + xFrame); + if (xTask!=null) + { + // return value doesn't interest here. Because + // we forget this task ... + bClosed = xTask.close(); + } + } + } + catch (com.sun.star.lang.DisposedException exDisposed) + { + // Of course - this task can be already dead - means disposed. + // But for us it's not important. Because we tried to close it too. + // And "already disposed" or "closed" should be the same ... + bClosed = true; + } + + return bClosed; + } + + + + /** + * Try to find a unique frame name, which isn't currently used inside + * remote office instance. Because we create top level frames + * only, it's enough to check the names of existing child frames on the + * desktop only. + * + * should represent a unique frame name, which currently isn't + * used inside the remote office frame tree + * (Couldn't guaranteed for a real multithreaded environment. + * But we try it ...) + */ + private static final String BASEFRAMENAME = "Desk View "; + + public static String getUniqueFrameName() + { + String sName = null; + + com.sun.star.uno.XComponentContext xCtx = OfficeConnect.getOfficeContext(); + + try + { + com.sun.star.frame.XFramesSupplier xSupplier = + UnoRuntime.queryInterface( + com.sun.star.frame.XFramesSupplier.class, + xCtx.getServiceManager().createInstanceWithContext( + "com.sun.star.frame.Desktop", xCtx)); + + com.sun.star.container.XIndexAccess xContainer = + UnoRuntime.queryInterface( + com.sun.star.container.XIndexAccess.class, + xSupplier.getFrames()); + + int nCount = xContainer.getCount(); + for (int i=0; i<nCount; ++i ) + { + 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)); + sName = BASEFRAMENAME+mnViewCount; + while(sName.equals(xFrame.getName())) + { + ++mnViewCount; + sName = BASEFRAMENAME+mnViewCount; + } + } + } + catch(com.sun.star.uno.Exception exCreateFailed) + { + sName = BASEFRAMENAME; + } + + if (sName==null) + { + System.out.println("invalid name!"); + sName = BASEFRAMENAME; + } + + return sName; + } + + + + /** + * helper to get a file URL selected by user + * This method doesn't show any API concepts... + * but is necessary for this demo application. + * + * @param aParent parent window of this dialog + * @param bOpen If it is set to true => + * dialog is opened in "file open" mode - + * otherwise in "file save" mode. + */ + public static String askUserForFileURL(Component aParent,boolean bOpen) + { + String sFileURL = null; + int nDecision = JFileChooser.CANCEL_OPTION; + JFileChooser aChooser = null; + + // set last visited directory on new file chosser + // (if this information is available) + if( maLastDir==null ) + aChooser = new JFileChooser(); + else + aChooser = new JFileChooser(maLastDir); + + // decide between file open/save dialog + if( bOpen ) + nDecision = aChooser.showOpenDialog(aParent); + else + nDecision = aChooser.showSaveDialog(aParent); + + // react for "OK" result only + if(nDecision == JFileChooser.APPROVE_OPTION) + { + // save current directory as last visited one + maLastDir = aChooser.getCurrentDirectory(); + // get file URL from the dialog + try + { + sFileURL = aChooser.getSelectedFile().toURI().toURL().toExternalForm(); + } + catch( MalformedURLException ex ) + { + ex.printStackTrace(); + sFileURL = null; + } + // problem of java: file URL's are coded with 1 slash instead of 3 ones! + // => correct this problem first, otherwise office can't use these URL's + if( + ( sFileURL !=null ) && + ( sFileURL.startsWith("file:/") ) && + ( !sFileURL.startsWith("file://") ) + ) + { + StringBuffer sWorkBuffer = new StringBuffer(sFileURL); + sWorkBuffer.insert(6,"//"); + sFileURL = sWorkBuffer.toString(); + } + } + + return sFileURL; + } + + + + /** + * @member maLastDir save the last visited directory of used file open/save dialog + * @member mnViewCount we try to set unique names on every frame we create (that's why we must count it) + */ + private static File maLastDir = null; + private static int mnViewCount = 0 ; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/IOnewayLink.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/IOnewayLink.java new file mode 100644 index 000000000..c6732155d --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/IOnewayLink.java @@ -0,0 +1,71 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.util.ArrayList; + +// __________ Implementation __________ + +/** + * We need a generic interface to forward any oneway uno interface method + * by using threads to the original object. Reason: + * It's not allowed to call synchronous back to the office if a java object + * was called in a oneway declared interface method. Then it must be + * executed asynchronous. To do so - a thread can be created which use this + * interface. It get the object, which has to be called back and the type and + * parameter of the original request. + * + */ +public interface IOnewayLink +{ + + + /** + * @param nRequest + * The two user of this callback can define a unique number, + * which identify the type of original interface method. So the called + * interface object can decide, which action will be necessary. + * + * @param lParams + * If the original method used parameters, they will be coded here in + * a generic way. Only the called interface object know (it depends + * from the original request - see nRequest too), how this list must + * be interpreted. + * Note: Atomic types (e.g. int, long) will be transported as objects + * too (Integer, Long)! + */ + void execOneway( int nRequest, ArrayList<Object> lParams ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/IShutdownListener.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/IShutdownListener.java new file mode 100644 index 000000000..753d364d0 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/IShutdownListener.java @@ -0,0 +1,48 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +// __________ Implementation __________ + +/** + * Listener interface to get information about application shutdown + * if java virtual machine dies. + * + */ +public interface IShutdownListener +{ + void shutdown(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Install.txt b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Install.txt new file mode 100644 index 000000000..79a1ee2bf --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Install.txt @@ -0,0 +1,10 @@ +(1) goto "./nativelib/<platform>" directory and build it +(2) build this directory +(3) expand your class path to include all jar files of an office installation + (means all files in path "<officeinst>/program/classes") +(4) goto "api/<platform>/class" +(5) copy from an existing java installation the runtime library "jawt" (e.g. jawt.dll for windows) + into this directory +(6) copy "api/<platform>/bin/nativelib.dll" (for windows) to "api/<platform>/class" +(7) start an office : "soffice --accept=socket,host=localhost,port=2083;urp;" +(8) goto "api/<platform>/class" and start java applet: "java -jar desktop.jar" diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Interceptor.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Interceptor.java new file mode 100644 index 000000000..380f8da3c --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Interceptor.java @@ -0,0 +1,655 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +// Imports + +import java.util.ArrayList; + +import com.sun.star.frame.FrameActionEvent; +import com.sun.star.uno.UnoRuntime; + +// Implementation + +/* + * This class can be used to intercept dispatched URL's + * on any frame used in this demo application. + * It intercept all URL's which try to create a new empty frame. + * (e.g. "private:factory/swriter") + * Nobody can guarantee that this interception will be really used - + * because another interceptor (registered at a later time then this one!) + * will be called before this one. + * Implementation is executed inside a new thread to prevent application + * against possible deadlocks. This deadlocks can occur if + * synchronous/asynchronous ... normal ones and oneway calls are mixed. + * Notifications of listener will be oneway mostly - her reactions can + * be synchronous then. => deadlocks are possible + */ +public class Interceptor implements com.sun.star.frame.XFrameActionListener, + com.sun.star.frame.XDispatchProviderInterceptor, + com.sun.star.frame.XDispatch, + com.sun.star.frame.XInterceptorInfo, + IShutdownListener, + IOnewayLink +{ + + + /** + * const + * All these URL's are intercepted by this implementation. + */ + private static final String[] INTERCEPTED_URLS = { "private:factory/*" , + ".uno:SaveAs" , + "slot:5300" , + ".uno:Quit" }; + + + + /* + * @member m_xMaster use this interceptor if he doesn't handle queried dispatch request + * @member m_xSlave we can forward all unhandled requests to this slave interceptor + * @member m_xFrame intercepted frame + * @member m_bDead there exist more than one way to finish an object of this class - we must know it sometimes + */ + private com.sun.star.frame.XDispatchProvider m_xMaster ; + private com.sun.star.frame.XDispatchProvider m_xSlave ; + private com.sun.star.frame.XFrame m_xFrame ; + private boolean m_bIsActionListener ; + private boolean m_bIsRegistered ; + private boolean m_bDead ; + + + + /* + * ctor + * Initialize the new interceptor. Given frame reference can be used to + * register this interceptor on it automatically later. + * + * @seealso startListening() + * + * @param xFrame + * this interceptor will register himself at this frame to intercept dispatched URLs + */ + Interceptor(/*IN*/ com.sun.star.frame.XFrame xFrame) + { + m_xFrame = xFrame ; + m_xSlave = null ; + m_xMaster = null ; + m_bIsRegistered = false ; + m_bIsActionListener = false ; + m_bDead = false ; + } + + + + /* + * start working as frame action listener really. + * We will be frame action listener here. In case + * we get a frame action which indicates, that we should + * update our interception. Because such using of an interceptor + * isn't guaranteed - in case a newer one was registered... + */ + public void startListening() + { + com.sun.star.frame.XFrame xFrame = null; + synchronized(this) + { + if (m_bDead) + return; + if (m_xFrame==null) + return; + if (m_bIsActionListener) + return; + xFrame = m_xFrame; + } + m_xFrame.addFrameActionListener(this); + synchronized(this) + { + m_bIsActionListener=true; + } + } + + + + /* + * In case we got a oneway listener callback - we had to use the office + * asynchronous then. This method is the callback from the started thread + * (started inside the original oneway method). We found all parameters of + * the original request packed inside a vector. Here we unpack it and + * call the right internal helper method, which implements the right + * functionality. + * + * @seealso frameAction() + * @seealso dispatch() + * + * @param nRequest + * indicates, which was the original request (identifies the + * original called method) + * + * @param lParams + * the vector with all packed parameters of the original request + */ + public void execOneway(/*IN*/ int nRequest,/*IN*/ ArrayList<Object> lParams ) + { + synchronized(this) + { + if (m_bDead) + return; + } + + // was it frameAction()? + if (nRequest==OnewayExecutor.REQUEST_FRAMEACTION) + { + impl_frameAction((FrameActionEvent) lParams.get(0)); + } + else + // was it dispatch()? + if (nRequest==OnewayExecutor.REQUEST_DISPATCH) + { + com.sun.star.util.URL[] lOutURL = new com.sun.star.util.URL[1]; + com.sun.star.beans.PropertyValue[][] lOutProps = new com.sun.star.beans.PropertyValue[1][]; + + OnewayExecutor.decodeDispatch( + lParams , + lOutURL , + lOutProps ); + impl_dispatch(lOutURL[0],lOutProps[0]); + } + } + + + + /* + * callback for frame action events + * We use it to update our interception. Because if a new component was loaded into + * the frame or another interceptor was registered, we should refresh our connection + * to the frame. Otherwise we can't guarantee full functionality here. + * + * Note: Don't react synchronous in an asynchronous listener callback. So use a thread + * here to update anything. + * + * @seealso impl_frameAction() + * + * @param aEvent + * describes the action + */ + public /*ONEWAY*/ void frameAction(/*IN*/ com.sun.star.frame.FrameActionEvent aEvent) + { + synchronized(this) + { + if (m_bDead) + return; + } + + boolean bHandle = false; + switch(aEvent.Action.getValue()) + { + case com.sun.star.frame.FrameAction.COMPONENT_ATTACHED_value : bHandle=true; break; + case com.sun.star.frame.FrameAction.COMPONENT_DETACHING_value : bHandle=true; break; + case com.sun.star.frame.FrameAction.COMPONENT_REATTACHED_value : bHandle=true; break; + // Don't react for CONTEXT_CHANGED here. Ok it indicates, that may another interceptor + // was registered at the frame ... but if we register ourself there - we get a context + // changed too :-( Best way to produce a never ending recursion ... + // May be that somewhere find a safe mechanism to detect own produced frame action events + // and ignore it. + case com.sun.star.frame.FrameAction.CONTEXT_CHANGED_value : + System.out.println("Time to update interception ... but may it will start a recursion. So I let it :-("); + bHandle=false; + break; + } + + // ignore some events + if (! bHandle) + return; + + // pack the event and start thread - which call us back later + ArrayList<Object> lOutParams = new ArrayList<Object>(); + lOutParams.add(aEvent); + + OnewayExecutor aExecutor = new OnewayExecutor( this , + OnewayExecutor.REQUEST_FRAMEACTION , + lOutParams ); + aExecutor.start(); + } + + + + /* + * Indicates using of us as an interceptor. + * Now we have to react for the requests, we are registered. + * That means: load new empty documents - triggered by the new menu of the office. + * Because it's oneway - use thread for loading! + * + * @seealso impl_dispatch() + * + * @param aURL + * describes the document, which should be loaded + * + * @param lArguments + * optional parameters for loading + */ + public /*ONEWAY*/ void dispatch(/*IN*/ com.sun.star.util.URL aURL,/*IN*/ com.sun.star.beans.PropertyValue[] lArguments) + { + synchronized(this) + { + if (m_bDead) + return; + } + + com.sun.star.util.URL[] lInURL = new com.sun.star.util.URL[1]; + com.sun.star.beans.PropertyValue[][] lInArguments = new com.sun.star.beans.PropertyValue[1][]; + lInURL[0] = aURL ; + lInArguments[0] = lArguments; + + ArrayList<Object> lOutParams = OnewayExecutor.encodeDispatch( + lInURL , + lInArguments ); + OnewayExecutor aExecutor = new OnewayExecutor( this , + OnewayExecutor.REQUEST_DISPATCH , + lOutParams ); + aExecutor.start(); + } + + + + + /* + * Internal callback for frame action events, triggered by the used + * OnewayExecutor thread we started in frameAction(). + * We use it to update our interception on the internal saved frame. + * + * @param aEvent + * describes the action + */ + private void impl_frameAction(/*IN*/ com.sun.star.frame.FrameActionEvent aEvent) + { + synchronized(this) + { + if (m_bDead) + return; + } + + // deregistration will be done every time... + // But may it's not necessary to establish a new registration! + // Don't look for ignoring actions - it was done already inside original frameAction() call! + boolean bRegister = false; + + // analyze the event and decide which reaction is useful + switch(aEvent.Action.getValue()) + { + case com.sun.star.frame.FrameAction.COMPONENT_ATTACHED_value : bRegister = true ; break; + case com.sun.star.frame.FrameAction.COMPONENT_REATTACHED_value : bRegister = true ; break; + case com.sun.star.frame.FrameAction.COMPONENT_DETACHING_value : bRegister = false; break; + } + + com.sun.star.frame.XFrame xFrame = null ; + boolean bIsRegistered = false; + synchronized(this) + { + bIsRegistered = m_bIsRegistered; + m_bIsRegistered = false; + xFrame = m_xFrame; + } + + com.sun.star.frame.XDispatchProviderInterception xRegistration = UnoRuntime.queryInterface( + com.sun.star.frame.XDispatchProviderInterception.class, + xFrame); + + if(xRegistration==null) + return; + + if (bIsRegistered) + xRegistration.releaseDispatchProviderInterceptor(this); + + if (! bRegister) + return; + + xRegistration.registerDispatchProviderInterceptor(this); + synchronized(this) + { + m_bIsRegistered = true; + } + } + + + + /* + * Implementation of interface XDispatchProviderInterceptor + * These functions are used to build a list of interceptor objects + * connected in both ways. + * Searching for a right interceptor is made by forwarding any request + * from toppest master to lowest slave of this hierarchy. + * If an interceptor wish to handle the request he can break that + * and return himself as a dispatcher. + */ + public com.sun.star.frame.XDispatchProvider getSlaveDispatchProvider() + { + synchronized(this) + { + return m_xSlave; + } + } + + + + public void setSlaveDispatchProvider(com.sun.star.frame.XDispatchProvider xSlave) + { + synchronized(this) + { + m_xSlave = xSlave; + } + } + + + + public com.sun.star.frame.XDispatchProvider getMasterDispatchProvider() + { + synchronized(this) + { + return m_xMaster; + } + } + + + + public void setMasterDispatchProvider(com.sun.star.frame.XDispatchProvider xMaster) + { + synchronized(this) + { + m_xMaster = xMaster; + } + } + + + + /* + * Implementation of interface XDispatchProvider + * These functions are called from our master if he will not handle the outstanding request. + * Given parameter should be checked if they are right for us. If it's true, the returned + * dispatcher should be this implementation himself; otherwise call should be forwarded + * to the slave. + * + * @param aURL + * describes the request, which should be handled + * + * @param sTarget + * specifies the target frame for this request + * + * @param nSearchFlags + * optional search flags, if sTarget isn't a special one + * + * @return [XDispatch] + * a dispatch object, which can handle the given URL + * May be NULL! + */ + public com.sun.star.frame.XDispatch queryDispatch(/*IN*/ com.sun.star.util.URL aURL,/*IN*/ String sTarget,/*IN*/ int nSearchFlags) + { + synchronized(this) + { + if (m_bDead) + return null; + } + + // intercept loading empty documents into new created frames + if( + (sTarget.compareTo ("_blank" ) == 0 ) && + (aURL.Complete.startsWith("private:factory")) + ) + { + System.out.println("intercept private:factory"); + return this; + } + + // intercept opening the SaveAs dialog + if (aURL.Complete.startsWith(".uno:SaveAs")) + { + System.out.println("intercept SaveAs by returning null!"); + return null; + } + + // intercept "File->Exit" inside the menu + if ( + (aURL.Complete.startsWith("slot:5300")) || + (aURL.Complete.startsWith(".uno:Quit")) + ) + { + System.out.println("intercept File->Exit"); + return this; + } + + synchronized(this) + { + if (m_xSlave!=null) + return m_xSlave.queryDispatch(aURL, sTarget, nSearchFlags); + } + + return null; + } + + + + public com.sun.star.frame.XDispatch[] queryDispatches(/*IN*/ com.sun.star.frame.DispatchDescriptor[] lDescriptor) + { + synchronized(this) + { + if (m_bDead) + return null; + } + // Resolve any request separately by using own "dispatch()" method. + // Note: Don't pack return list if "null" objects occur! + int nCount = lDescriptor.length; + com.sun.star.frame.XDispatch[] lDispatcher = new com.sun.star.frame.XDispatch[nCount]; + for(int i=0; i<nCount; ++i) + { + lDispatcher[i] = queryDispatch(lDescriptor[i].FeatureURL , + lDescriptor[i].FrameName , + lDescriptor[i].SearchFlags); + } + return lDispatcher; + } + + + + /* + * This method is called if this interceptor "wins the request". + * We intercepted creation of new frames and loading of empty documents. + * Do it now. + * + * @param aURL + * describes the document + * + * @param lArguments + * optional arguments for loading + */ + private void impl_dispatch(/*IN*/ com.sun.star.util.URL aURL,/*IN*/ com.sun.star.beans.PropertyValue[] lArguments) + { + synchronized(this) + { + if (m_bDead) + return; + } + + if ( + (aURL.Complete.startsWith("slot:5300")) || + (aURL.Complete.startsWith(".uno:Quit")) + ) + { + System.exit(0); + } + else + if (aURL.Complete.startsWith("private:factory")) + { + // Create view frame for showing loaded documents on demand. + // The visible state is necessary for JNI functionality to get the HWND and plug office + // inside a java window hierarchy! + DocumentView aNewView = new DocumentView(); + aNewView.setVisible(true); + aNewView.createFrame(); + aNewView.load(aURL.Complete,lArguments); + } + } + + + + /* + * Notification of status listener isn't guaranteed (instead of listener on XNotifyingDispatch interface). + * So this interceptor doesn't support that really... + */ + public /*ONEWAY*/ void addStatusListener(/*IN*/ com.sun.star.frame.XStatusListener xListener,/*IN*/ com.sun.star.util.URL aURL) + { +/* if (aURL.Complete.startsWith(".uno:SaveAs")==true) + { + com.sun.star.frame.FeatureStateEvent aEvent = new com.sun.star.frame.FeatureStateEvent( + this, + aURL, + "", + false, + false, + null); + if (xListener!=null) + { + System.out.println("interceptor disable SaveAs by listener notify"); + xListener.statusChanged(aEvent); + } + }*/ + } + + + + public /*ONEWAY*/ void removeStatusListener(/*IN*/ com.sun.star.frame.XStatusListener xListener,/*IN*/ com.sun.star.util.URL aURL) + { + } + + + + /* + * Implements (optional!) optimization for interceptor mechanism. + * Any interceptor which provides this special interface is called automatically + * at registration time on this method. Returned URL's will be used to + * call this interceptor directly without calling his masters before, IF(!) + * following rules will be true: + * (1) every master supports this optional interface too + * (2) nobody of these masters wish to intercept same URL then this one + * This interceptor wish to intercept creation of new documents. + */ + public String[] getInterceptedURLs() + { + return INTERCEPTED_URLS; + } + + + + /* + * This class listen on the intercepted frame to free all used resources on closing. + * We forget the reference to the frame only here. Deregistration + * isn't necessary here - because this frame dies and wish to be forgotten. + * + * @param aSource + * must be our internal saved frame, on which we listen for frame action events + */ + public /*ONEAY*/ void disposing(/*IN*/ com.sun.star.lang.EventObject aSource) + { + synchronized(this) + { + if (m_bDead) + return; + if (m_xFrame!=null && UnoRuntime.areSame(aSource.Source,m_xFrame)) + { + m_bIsActionListener = false; + m_xFrame = null ; + } + } + shutdown(); + } + + + + /* + * If this java application shutdown - we must cancel all current existing + * listener connections. Otherwise the office will run into some + * DisposedExceptions if it tries to use these forgotten listener references. + * And of course it can die doing that. + * We are registered at a central object to be informed if the VM will exit. + * So we can react. + */ + public void shutdown() + { + com.sun.star.frame.XFrame xFrame = null ; + boolean bIsRegistered = false; + boolean bIsActionListener = false; + synchronized(this) + { + // don't react a second time here! + if (m_bDead) + return; + m_bDead = true; + + bIsRegistered = m_bIsRegistered; + m_bIsRegistered = false; + + bIsActionListener = m_bIsActionListener; + m_bIsActionListener = false; + + xFrame = m_xFrame; + m_xFrame = null; + } + + // it's a good idea to cancel listening for frame action events + // before(!) we deregister us as an interceptor. + // Because registration and deregistration of interceptor objects + // will force sending of frame action events...! + if (bIsActionListener) + xFrame.removeFrameActionListener(this); + + if (bIsRegistered) + { + com.sun.star.frame.XDispatchProviderInterception xRegistration = UnoRuntime.queryInterface( + com.sun.star.frame.XDispatchProviderInterception.class, + xFrame); + + if(xRegistration!=null) + xRegistration.releaseDispatchProviderInterceptor(this); + } + + xFrame = null; + + synchronized(this) + { + m_xMaster = null; + m_xSlave = null; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/JavaWindowPeerFake.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/JavaWindowPeerFake.java new file mode 100644 index 000000000..25281ac5f --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/JavaWindowPeerFake.java @@ -0,0 +1,109 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + + + + +/** <p>Class to pass the system window handle to the OpenOffice.org toolkit.</p> + */ +class JavaWindowPeerFake implements com.sun.star.awt.XSystemDependentWindowPeer, + com.sun.star.awt.XWindowPeer +{ + private final NativeView maView; + + public JavaWindowPeerFake(NativeView aNative) + { + maView = aNative; + } + + + /** + * Implementation of XSystemDependentWindowPeer (that's all we really need). + * This method is called back from the Office toolkit to retrieve the system data. + */ + public java.lang.Object getWindowHandle(byte[] aProcessId, short aSystem) + throws com.sun.star.uno.RuntimeException + { + Object aReturn = null; + if(aSystem==maView.maSystem) + aReturn = maView.maHandle; + return aReturn; + } + + /** not really needed. + */ + public com.sun.star.awt.XToolkit getToolkit() + throws com.sun.star.uno.RuntimeException + { + return null; + } + + public void setPointer(com.sun.star.awt.XPointer xPointer) + throws com.sun.star.uno.RuntimeException + { + } + + public void setBackground(int nColor) + throws com.sun.star.uno.RuntimeException + { + } + + public void invalidate(short nFlags) + throws com.sun.star.uno.RuntimeException + { + } + + public void invalidateRect(com.sun.star.awt.Rectangle aRect,short nFlags) + throws com.sun.star.uno.RuntimeException + { + } + + public void dispose() + throws com.sun.star.uno.RuntimeException + { + } + + public void addEventListener(com.sun.star.lang.XEventListener xListener) + throws com.sun.star.uno.RuntimeException + { + } + + public void removeEventListener(com.sun.star.lang.XEventListener xListener) + throws com.sun.star.uno.RuntimeException + { + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Makefile b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Makefile new file mode 100644 index 000000000..5b0462b25 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Makefile @@ -0,0 +1,131 @@ +#************************************************************************* +# +# The Contents of this file are made available subject to the terms of +# the BSD license. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Sun Microsystems, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +#************************************************************************** + +# Builds the OfficeDevDesktopEnvironment example of the Developers Guide. + +PRJ=../../../.. +SETTINGS=$(PRJ)/settings + +include $(SETTINGS)/settings.mk +include $(SETTINGS)/std.mk + +# Define non-platform/compiler specific settings +EXAMPLE_NAME=OfficeDevDesktopEnv +OUT_APP_CLASS = $(OUT_CLASS)/$(EXAMPLE_NAME) + +APP1_NAME=DesktopExample +APP1_JAR=$(OUT_APP_CLASS)/$(APP1_NAME).jar + +APP1_JAVAFILES = \ + CustomizeView.java \ + Desk.java \ + DocumentView.java \ + FunctionHelper.java \ + Interceptor.java \ + IOnewayLink.java \ + IShutdownListener.java \ + JavaWindowPeerFake.java \ + NativeView.java \ + OfficeConnect.java \ + OnewayExecutor.java \ + StatusListener.java \ + StatusView.java \ + ViewContainer.java + +APP1_CLASSFILES = $(patsubst %.java,$(OUT_APP_CLASS)/%.class,$(APP1_JAVAFILES)) +APP1_CLASSNAMES = $(patsubst %.java,%.class,$(APP1_JAVAFILES)) \ + CustomizeView$(QUOTE)$$ClickListener.class \ + DocumentView$(QUOTE)$$*.class + + +SDK_CLASSPATH = $(subst $(EMPTYSTRING) $(PATH_SEPARATOR),$(PATH_SEPARATOR),$(CLASSPATH)\ + $(PATH_SEPARATOR)$(OUT_APP_CLASS)) + +ifeq "$(OS)" "WIN" +SUBDIR= nativelib/windows +else +SUBDIR= nativelib/unix +endif + +# Targets +.PHONY: ALL +ifeq "$(OS)" "MACOSX" +ALL : + @printf 'This example does not work on macOS\n' +else +ALL : $(SUBDIR) \ + $(EXAMPLE_NAME) +endif + +include $(SETTINGS)/stdtarget.mk + +.PHONY : $(SUBDIR) +$(SUBDIR) : + $(MAKE) -C $@ + +$(APP1_CLASSFILES) : $(APP1_JAVAFILES) + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(SDK_JAVAC) $(JAVAC_FLAGS) -classpath "$(SDK_CLASSPATH)" -d $(OUT_APP_CLASS) $(APP1_JAVAFILES) + +$(OUT_APP_CLASS)/$(APP1_NAME).mf : + -$(MKDIR) $(subst /,$(PS),$(@D)) + @echo Main-Class: com.sun.star.lib.loader.Loader> $@ + $(ECHOLINE)>> $@ + @echo Name: com/sun/star/lib/loader/Loader.class>> $@ + @echo Application-Class: Desk>> $@ + +$(APP1_JAR) : $(OUT_APP_CLASS)/$(APP1_NAME).mf $(APP1_CLASSFILES) + -$(DEL) $(subst \\,\,$(subst /,$(PS),$@)) + -$(MKDIR) $(subst /,$(PS),$(@D)) + +cd $(subst /,$(PS),$(OUT_APP_CLASS)) && $(SDK_JAR) cvfm $(@F) $(basename $(@F)).mf $(APP1_CLASSNAMES) + +$(SDK_JAR) uvf $@ $(SDK_JAVA_UNO_BOOTSTRAP_FILES) + +$(EXAMPLE_NAME) : $(APP1_JAR) + @echo -------------------------------------------------------------------------------- + @echo Please use the following command to execute the example! + @echo - + @echo $(MAKE) DesktopExample.run + @echo ------ + @echo If you want to run the $(JAR1_JAR) file please set your + @echo CLASSPATH = $(SDK_CLASSPATH) + @echo Start the example with jar -jar $(JAR1_JAR) + @echo -------------------------------------------------------------------------------- + +%.run: $(OUT_APP_CLASS)/%.jar + $(SDK_JAVA) -Dcom.sun.star.lib.loader.unopath="$(OFFICE_PROGRAM_PATH)" -jar $< + +.PHONY: clean +clean : + $(MAKE) -C $(SUBDIR) clean + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_APP_CLASS)) diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/NativeView.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/NativeView.java new file mode 100644 index 000000000..273290e55 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/NativeView.java @@ -0,0 +1,186 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +// __________ Imports __________ + +import java.awt.*; + +// __________ Implementation __________ + +/** + * Class to pass the system window handle to the OpenOffice.org toolkit. + * It use special JNI methods to get the system handle of used java window. + * + * Attention! + * Use JNI functions on already visible canvas objects only! + * Otherwise they can make some trouble. + * + */ + +public class NativeView extends java.awt.Canvas +{ + + + /** + * ctor + * Does nothing really. + * We can use our JNI mechanism for an already visible + * canvas only. So we override the method for showing ("setVisible()") + * and make our initialization there. But we try to show an empty clean + * window till there. + */ + public NativeView() + { + maHandle = null; + maSystem = 0; + this.setBackground(Color.white); + } + + + + /** + * Override this method to make necessary initializations here. + * (e.g. get the window handle and necessary system information) + * + * Why here? + * Because the handle seems to be available for already visible windows + * only. So it's the best place to get it. Special helper method + * can be called more than ones - but call native code one times only + * and safe the handle and the system type on our members maHandle/maSystem! + */ + @Override + public void setVisible(boolean bState) + { + getHWND(); + } + + + + /** + * to guarantee right resize handling inside a swing container + * (e.g. JSplitPane) we must provide some information about our + * preferred/minimum and maximum size. + */ + @Override + public Dimension getPreferredSize() + { + return new Dimension(500,300); + } + + @Override + public Dimension getMaximumSize() + { + return new Dimension(1024,768); + } + + @Override + public Dimension getMinimumSize() + { + return new Dimension(100,100); + } + + + + /** + * Override paint routine to show provide against + * repaint errors if no office view is really plugged + * into this canvas. + * If handle is present - we shouldn't paint anything further. + * May the remote window is already plugged. In such case we + * shouldn't paint it over. + */ + @Override + public void paint(Graphics aGraphic) + { + if(maHandle==null) + { + Dimension aSize = getSize(); + aGraphic.clearRect(0,0,aSize.width,aSize.height); + } + } + + + + /** + * JNI interface of this class + * These two methods are implemented by using JNI mechanismen. + * The will be used to get the platform dependent window handle + * of a java awt canvas. This handle can be used to create an office + * window as direct child of it. So it's possible to plug Office + * windows in a java UI container. + * + * Note: + * Native code for Windows registers a special function pointer to handle + * window messages... But if it doesn't check for an already-registered + * instance of this handler it will do it twice and produce a stack overflow + * because such method calls itself in a never-ending loop... + * So we try to use the JNI code one time only and save already-obtained + * information inside this class. + */ + public native int getNativeWindowSystemType(); + private native long getNativeWindow(); // private! => use getHWND() with cache mechanism! + + public Integer getHWND() + { + if(maHandle==null) + { + maHandle = Integer.valueOf((int)getNativeWindow()); + maSystem = getNativeWindowSystemType(); + } + return maHandle; + } + + + + /** + * for using of the JNI methods it's necessary to load + * system library which exports it. + */ + static + { + System.loadLibrary("nativeview"); + } + + + + /** + * @member maHandle system window handle + * @member maSystem info about currently used platform + */ + public Integer maHandle ; + public int maSystem ; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/OfficeConnect.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/OfficeConnect.java new file mode 100644 index 000000000..617e38047 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/OfficeConnect.java @@ -0,0 +1,127 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + + + + +// __________ Implementation __________ + +/** + * support ONE singleton uno connection to a running office installation! + * Can be used to open/use/close connection to uno environment of an office. If + * necessary a new office instance is started. + * ctor isn't available from outside. You should call static function + * "getConnection()" to open or use internal set connection which is created one + * times only. + * + */ +public class OfficeConnect +{ + + + /** + * At first call we create static connection object and open connection to an + * office - a new office instance is started if necessary + * Then - and for all further requests we return these static connection member. + */ + public static synchronized void createConnection() + { + if (maConnection == null) + maConnection = new OfficeConnect(); + } + + + + + + + + /** + * ctor + * We try to open the connection in our ctor ... transparently for user. + * After it was successful you will find an internal set member + * m_xRemoteContext which means remote component context of the connected office. + * The context can be used to get the remote service manager from the office. + * We made it private to support singleton pattern of these implementation. + * see getConnection() for further information + */ + private OfficeConnect() + { + try + { + // get the remote office context. If necessary a new office + // process is started + mxOfficeContext = com.sun.star.comp.helper.Bootstrap.bootstrap(); + System.out.println("Connected to a running office ..."); + mxServiceManager = mxOfficeContext.getServiceManager(); + } + catch (java.lang.Exception ex) + { + System.err.println("connection failed" + ex); + ex.printStackTrace(System.err); + System.exit(1); + + } + } + + + + + + + + /** + * returns remote component context of the connected office + */ + public static synchronized com.sun.star.uno.XComponentContext getOfficeContext() + { + return mxOfficeContext; + } + + + + /** + * member + */ + // singleton connection instance + private static OfficeConnect maConnection; + + // reference to the office component context + private static com.sun.star.uno.XComponentContext mxOfficeContext; + // reference to remote service manager of singleton connection object + private static com.sun.star.lang.XMultiComponentFactory mxServiceManager; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/OnewayExecutor.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/OnewayExecutor.java new file mode 100644 index 000000000..4eb7f80a7 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/OnewayExecutor.java @@ -0,0 +1,189 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.util.ArrayList; + +// __________ Implementation __________ + +/** + * It's not allowed to call synchronous back inside a oneway interface call. + * (see IOnewayLink too). So we start a thread (implemented by this class), which + * gets all necessary parameters from the original called object and + * call it back later inside his run() method. So the execution of such oneway call + * will be asynchronous. It works in a generic way and can be used or any type + * of oneway request. Because the source and the target of this call-link knows, + * which method was used and which parameters must be handled. + * + */ +class OnewayExecutor extends Thread +{ + + + /** + * const + * We define some request for some well known oneway interface + * calls here too. So they mustn't be declared more than ones. + * Of course it's not necessary to use it ... but why not :-) + */ + + public static final int REQUEST_FRAMEACTION = 1 ; + + + + public static final int REQUEST_DISPATCH = 5 ; + + + + + + + /** + * @member m_rLink the object, which wishes to be called back by this thread + * @member m_nRequest describes the type of the original request (means the + * called oneway method) + * @member m_lParams list of parameters of the original request + */ + private final IOnewayLink m_rLink ; + private final int m_nRequest ; + private final ArrayList<Object> m_lParams ; + + + + /** + * ctor + * It's initialize this thread with all necessary parameters. + * It gets the object, which wishes to be called back and the type + * and parameters of the original request. + * + * @param nRequest + * The two user of this callback can define a unique number, + * which identify the type of original interface method. + * So the called interface object can decide, which action will be + * necessary. + * + * @param lParams + * If the original method used parameters, they will be coded here in + * a generic way. Only the called interface object know (it depends + * from the original request - see nRequest too), how this list must + * be interpreted. + * Note: Atomic types (e.g. int, long) will be transported as objects + * too (Integer, Long)! + */ + public OnewayExecutor( IOnewayLink rLink , + int nRequest , + ArrayList<Object> lParams ) + { + m_rLink = rLink ; + m_nRequest = nRequest; + m_lParams = lParams ; + + if (m_rLink==null) + System.out.println("ctor ... m_rLink == null"); + if (m_lParams==null) + System.out.println("ctor ... m_lParams == null"); + } + + + + /** + * implements the thread function + * Here we call the internal set link object back and + * give him all necessary parameters. + * After that we die by ourselves ... + */ + @Override + public void run() + { + if (m_rLink==null) + System.out.println("run ... m_rLink == null"); + if (m_lParams==null) + System.out.println("run ... m_lParams == null"); + + if (m_rLink!=null) + m_rLink.execOneway( m_nRequest, m_lParams ); + } + + + + /** + * static helper! + * To make conversion of the generic parameter list to the original + * one easier - you can use this helper methods. They know how such list + * must be coded. It's not a must to use it - but you can ... + */ + + + + public static ArrayList<Object> encodeDispatch( + com.sun.star.util.URL[] aURL, + com.sun.star.beans.PropertyValue[][] lArgs) + { + int nLength = lArgs.length+1; + int nPos = 0; + ArrayList<Object> lParams = new ArrayList<Object>(nLength); + + lParams.add( aURL[0] ); + --nLength; + + while (nLength>0) + { + lParams.add( lArgs[0][nPos] ); + --nLength; + ++nPos ; + } + return lParams; + } + + public static void decodeDispatch( + ArrayList<Object> lParams, + com.sun.star.util.URL[] aURL, + com.sun.star.beans.PropertyValue[][] lArgs) + { + int nLength = lParams.size()-1; + int nPos = 0; + + lArgs[0] = new com.sun.star.beans.PropertyValue[nLength]; + aURL[0] = (com.sun.star.util.URL) lParams.get(0); + + while (nPos<nLength) + { + lArgs[0][nPos] = (com.sun.star.beans.PropertyValue) + (lParams.get(nPos+1)); + ++nPos; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/StatusListener.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/StatusListener.java new file mode 100644 index 000000000..f037949b0 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/StatusListener.java @@ -0,0 +1,469 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +// __________ Imports __________ + +import java.awt.Component; +import java.util.ArrayList; + +import javax.swing.JCheckBox; +import javax.swing.JLabel; + +import com.sun.star.frame.FrameActionEvent; +import com.sun.star.uno.UnoRuntime; + +// __________ Implementation __________ + +/** + * reacts for status events we listen for + * We listen for status events to update our UI. + * To know which event must be used for which UI control + * we use a special class to do that. Otherwise we have + * to guess it ... + * + * Further we are frame action listener too. + * So we can update our status listener connections and + * internal holded dispatch object automatically. + * + * Another reason for such extra class for listening: + * Most listener callbacks are asynchronous [oneay] requests. + * And it's not allowed to call back synchronously there. + * So we must start threads for updating something internally. + * + */ +class StatusListener implements com.sun.star.frame.XStatusListener, + com.sun.star.frame.XFrameActionListener, + IShutdownListener, + IOnewayLink +{ + + + /** + * @member m_rControl reference to the UI control, which should be updated + * @member m_sTrueText this text will be shown at the used UI control as description for an enabled status + * @member m_sFalseText this text will be shown at the used UI control as description for an disabled status + * @member m_xDispatch if we listen for status events, we must hold the dispatch object alive! + * @member m_xFrame reference to the frame, which can provide new dispatch objects if it's necessary to update it + * @member m_aURL and of course we must be registered for a special URL + * @member m_bIsActionListener indicates if we are currently registered as a listener for frame action events or not + * @member m_bIsStatusListener indicates if we are currently registered as a listener for status events or not + * @member m_bDead there exist more than one way to finish an object of this class - we must know it sometimes + */ + private final Component m_rControl ; + private final String m_sTrueText ; + private final String m_sFalseText ; + private com.sun.star.frame.XDispatch m_xDispatch ; + private com.sun.star.frame.XFrame m_xFrame ; + private com.sun.star.util.URL m_aURL ; + private boolean m_bIsActionListener; + private boolean m_bIsStatusListener; + private boolean m_bDead ; + + + + /** + * ctor + * It initialize an instance of this class only. + * We set all necessary information on our internal member - that's it + */ + StatusListener( /*IN*/ Component rControl , + /*IN*/ String sTrueText , + /*IN*/ String sFalseText , + /*IN*/ com.sun.star.frame.XFrame xFrame , + /*IN*/ String sURL ) + { + m_rControl = rControl ; + m_sTrueText = sTrueText ; + m_sFalseText = sFalseText ; + m_xFrame = xFrame ; + m_bIsStatusListener = false ; + m_bIsActionListener = false ; + m_bDead = false ; + // to be perform - we parse the given URL one times only + // and use it till we die ... + m_aURL = FunctionHelper.parseURL(sURL); + } + + + + /** + * start working as frame action listener really. + * In case we get such frame action, it indicates that we should + * update our internal saved dispatch object on which we listen + * for status events. So we can do it automatically. The outside code + * mustn't check such things. We can work with one frame, + * till it die. It doesn't matter if he will be used for different + * load/save or any other requests. We will be up to date every time. + */ + public void startListening() + { + com.sun.star.frame.XFrame xFrame = null; + synchronized(this) + { + if (m_bDead) + return; + if (m_xFrame==null) + return; + if (m_bIsActionListener) + return; + xFrame = m_xFrame; + } + xFrame.addFrameActionListener(this); + synchronized(this) + { + m_bIsActionListener=true; + } + } + + + + /** + * In case we got a oneway listener callback - we had to use the office + * asynchronous then. This method is the callback from the started thread + * (started inside the original oneway method). We found all parameters of + * the original request packed inside a vector. Here we unpack it and + * call the right internal helper method, which implements the right + * functionality. + * + * @seealso frameAction() + * @seealso statusChanged() + * + * @param nRequest + * indicates, which was the original request (identifies the + * original called method) + * + * @param lParams + * the vector with all packed parameters of the original request + */ + public void execOneway(/*IN*/ int nRequest,/*IN*/ ArrayList<Object> lParams ) + { + synchronized(this) + { + if (m_bDead) + return; + } + // was it frameAction()? + if (nRequest==OnewayExecutor.REQUEST_FRAMEACTION) + { + impl_frameAction((FrameActionEvent) lParams.get(0)); + } + } + + + + /** + * This is the callback method for such frame action events, we listen for. + * Because it's a oneway method we start a thread as reaction. This thread call + * us back and we can do necessary things there. + * But we shouldn't start such action - if it's not really necessary. + * So we check before, if we are interested on this event really. + * + * @see #impl_frameAction + * + * @param aEvent + * describes the action, which triggered this event + */ + public /*ONEWAY*/ void frameAction(/*IN*/ com.sun.star.frame.FrameActionEvent aEvent) + { + synchronized(this) + { + if (m_bDead) + return; + } + boolean bHandle = false; + switch(aEvent.Action.getValue()) + { + case com.sun.star.frame.FrameAction.COMPONENT_ATTACHED_value : bHandle=true; break; + case com.sun.star.frame.FrameAction.COMPONENT_DETACHING_value : bHandle=true; break; + case com.sun.star.frame.FrameAction.COMPONENT_REATTACHED_value : bHandle=true; break; + case com.sun.star.frame.FrameAction.CONTEXT_CHANGED_value : bHandle=true; break; + } + + if (! bHandle) + return; + + ArrayList<Object> lOutParams = new ArrayList<Object>(); + lOutParams.add(aEvent); + + OnewayExecutor aExecutor = new OnewayExecutor( this , + OnewayExecutor.REQUEST_FRAMEACTION , + lOutParams ); + aExecutor.start(); + } + + + + /** + * This is the callback method for the status we listen for and wish to show it + * on our UI control. Of course it's a oneway method... but we don't call back + * to the office synchronously here. We update our UI only. So we don't leave this + * java process. In such case it's not necessary to use threads to decouple it. + * Do it here and now... + * + * @param aEvent + * describes the status, we can use to update our UI control + */ + public /*ONEWAY*/ void statusChanged(/*IN*/ com.sun.star.frame.FeatureStateEvent aEvent) + { + synchronized(this) + { + if (m_bDead) + return; + + // enable/disable the control. + // Means: if the feature isn't available currently - we can't show a status really here. + // Then we should colorize it gray... + m_rControl.setEnabled(aEvent.IsEnabled); + + // Only if status is enabled we can look for his value! + if (aEvent.IsEnabled) + { + // look for the right type of the UI control + // Following actions depend on it. + + + // it's a check box + if (m_rControl instanceof JCheckBox) + { + JCheckBox aBox = (JCheckBox)m_rControl; + + // State must be a boolean value too. Otherwise must + // ignore this event. + if ( ! (aEvent.State instanceof Boolean ) ) + return; + + boolean bState = ((Boolean)(aEvent.State)).booleanValue(); + aBox.setSelected(bState); + if (bState) + aBox.setText(m_sTrueText); + else + aBox.setText(m_sFalseText); + } + else + + // it's a label + if (m_rControl instanceof JLabel) + { + JLabel aLabel = (JLabel)m_rControl; + + // Detect type of state value + // and set it on internal well known UI control + // But do it only, if value really change. + if(aEvent.State instanceof String) + { + String sState = (String)aEvent.State; + aLabel.setText(sState); + } + else + if(aEvent.State instanceof Boolean) + { + boolean bState = ((Boolean)aEvent.State).booleanValue(); + if (bState) + aLabel.setText(m_sTrueText); + else + aLabel.setText(m_sFalseText); + } + else + if(aEvent.State instanceof Float) + { + String sState = ((Float)aEvent.State).toString(); + aLabel.setText(sState); + } + } + } + } + } + + + + /** + * Internal call back for frame action events, triggered by the used + * OnewayExecutor thread we started in frameAction(). + * We use it to update internal saved dispatch object and the corresponding + * listener connection for status events. + * + * @param aEvent + * describes the action + */ + private void impl_frameAction(/*IN*/ com.sun.star.frame.FrameActionEvent aEvent) + { + synchronized(this) + { + if (m_bDead) + return; + } + // Don't look for ignoring actions - it was done already inside original frameAction() call! + // deregistration as status listener will be done here every time - but registration only, if necessary! + boolean bRegister = false; + switch(aEvent.Action.getValue()) + { + case com.sun.star.frame.FrameAction.COMPONENT_ATTACHED_value : bRegister=true ; break; + case com.sun.star.frame.FrameAction.COMPONENT_DETACHING_value : bRegister=false; break; + case com.sun.star.frame.FrameAction.COMPONENT_REATTACHED_value : bRegister=true ; break; + case com.sun.star.frame.FrameAction.CONTEXT_CHANGED_value : bRegister=true ; break; + } + + boolean bIsStatusListener = false; + com.sun.star.frame.XFrame xFrame = null ; + com.sun.star.frame.XDispatch xDispatch = null ; + com.sun.star.util.URL aURL = null ; + synchronized(this) + { + bIsStatusListener = m_bIsStatusListener; + m_bIsStatusListener = false; + + xDispatch = m_xDispatch; + m_xDispatch = null; + + aURL = m_aURL; + xFrame = m_xFrame; + } + + if (bIsStatusListener) + xDispatch.removeStatusListener(this,aURL); + xDispatch = null; + + if (! bRegister) + return; + + com.sun.star.frame.XDispatchProvider xProvider = UnoRuntime.queryInterface( + com.sun.star.frame.XDispatchProvider.class, + xFrame); + + if (xProvider==null) + return; + + xDispatch = xProvider.queryDispatch(aURL,"",0); + + if (xDispatch==null) + return; + + xDispatch.addStatusListener(this,aURL); + synchronized(this) + { + m_xDispatch = xDispatch; + m_bIsStatusListener = true; + } + } + + + + /** + * callback for disposing events + * Our dispatch or frame object inform us about his following dead ... + * So we must forget his reference. But it's not necessary to + * remove listener connections here. Because the broadcaster + * forget us automatically. The only thing we have to do: release + * his reference and let him die! + * + * @param aEvent + * describes the source which fire this event + * Must be our internal saved dispatch or frame. Otherwise + * somewhere know us without a registration ... + */ + public /*ONEWAY*/ void disposing(/*IN*/ com.sun.star.lang.EventObject aEvent) + { + synchronized(this) + { + if (m_bDead) + return; + if (m_xFrame!=null && UnoRuntime.areSame(aEvent.Source,m_xFrame)) + { + m_bIsActionListener = false; + m_xFrame = null ; + } + else + if (m_xDispatch!=null && UnoRuntime.areSame(aEvent.Source,m_xDispatch)) + { + m_bIsStatusListener = false; + m_xDispatch = null ; + m_aURL = null ; + } + } + shutdown(); + } + + + + /** + * If this java application shutdown - we must cancel all current existing + * listener connections. Otherwise the office will run into some + * DisposedExceptions if it tries to use these forgotten listener references. + * And of course it can die doing that. + * We are registered at a central object to be informed if the VM will exit. + * So we can react. + */ + public void shutdown() + { + boolean bIsActionListener = false; + boolean bIsStatusListener = false; + com.sun.star.frame.XFrame xFrame = null ; + com.sun.star.frame.XDispatch xDispatch = null ; + com.sun.star.util.URL aURL = null ; + synchronized(this) + { + // don't react a second time here! + if (m_bDead) + return; + m_bDead = true; + + bIsActionListener = m_bIsActionListener; + m_bIsActionListener = false; + + bIsStatusListener = m_bIsStatusListener; + m_bIsStatusListener = false; + + xFrame = m_xFrame; + m_xFrame = null; + + xDispatch = m_xDispatch; + m_xDispatch = null; + + aURL = m_aURL; + m_aURL = null; + } + + if (bIsStatusListener) + xDispatch.removeStatusListener(this,aURL); + xDispatch = null ; + aURL = null ; + + if (bIsActionListener) + xFrame.removeFrameActionListener(this); + xFrame = null ; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/StatusView.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/StatusView.java new file mode 100644 index 000000000..92ae178ad --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/StatusView.java @@ -0,0 +1,264 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +// __________ Imports __________ + +import java.awt.*; +import javax.swing.*; + +// __________ Implementation __________ + +/** + * Implement a view to show status information + * of currently loaded document of a document view. + * It uses separate listener threads to get this information + * and actualize it automatically, if frame broadcast changes of + * his contained document. + * Threads are necessary to prevent this view against deadlocks. + * These deadlocks can occur if a listener will be notified + * by the office in an "oneway" method and try to call back + * to the office by using a synchronous method. + * UNO must guarantee order of all these calls ... and if + * the source of arrived event holds a mutex and our synchronous + * call needs this mutex too => a deadlock occurs. + * Why? UNO had created a new thread for our synchronous call + * inside the office process and so exist different threads + * for this constellation. + * + */ +public class StatusView extends JPanel + implements IShutdownListener +{ + + + /** + * const + * These URL's describe available feature states. + */ + private static final String FEATUREURL_FONT = "slot:10007"; + private static final String FEATUREURL_SIZE = "slot:10015"; + private static final String FEATUREURL_BOLD = "slot:10009"; + private static final String FEATUREURL_ITALIC = "slot:10008"; + private static final String FEATUREURL_UNDERLINE = "slot:10014"; + + + + /** + * const + * These values are used to show current state of showed feature. + */ + private static final String FONT_OFF = "unknown" ; + private static final String SIZE_OFF = "0.0" ; + private static final String BOLD_OFF = "-" ; + private static final String ITALIC_OFF = "-" ; + private static final String UNDERLINE_OFF = "-" ; + + private static final String FONT_ON = "" ; + private static final String SIZE_ON = "" ; + private static final String BOLD_ON = "X" ; + private static final String ITALIC_ON = "X" ; + private static final String UNDERLINE_ON = "X" ; + + + + /** + * @member mlaFontValue shows status of font name + * @member mlaSizeValue shows status of font size + * @member mlaBoldValue shows status of font style bold + * @member mlaUnderlineValue shows status of font style underline + * @member mlaItalicValue shows status of font style italic + * + * @member maFontListener threadsafe(!) helper to listen for status event which describe font name + * @member maSizeListener threadsafe(!) helper to listen for status event which describe font size + * @member maBoldListener threadsafe(!) helper to listen for status event which describe font style bold + * @member maUnderlineListener threadsafe(!) helper to listen for status event which describe font style underline + * @member maItalicListener threadsafe(!) helper to listen for status event which describe font style italic + */ + private final JLabel m_laFontValue ; + private final JLabel m_laSizeValue ; + private final JLabel m_laBoldValue ; + private final JLabel m_laUnderlineValue ; + private final JLabel m_laItalicValue ; + + private StatusListener m_aFontListener ; + private StatusListener m_aSizeListener ; + private StatusListener m_aBoldListener ; + private StatusListener m_aUnderlineListener ; + private StatusListener m_aItalicListener ; + + + + /** + * ctor + * Create view controls on startup and initialize it with default values. + * Filling of view items can be done by special set-methods. + * We don't start listening here! see setFrame() for that ... + */ + StatusView() + { + this.setLayout(new GridBagLayout()); + + GridBagConstraints aConstraint = new GridBagConstraints(); + aConstraint.anchor = GridBagConstraints.NORTHWEST; + aConstraint.insets = new Insets(2,2,2,2); + aConstraint.gridy = 0; + aConstraint.gridx = 0; + + JLabel laFont = new JLabel("Font" ); + JLabel laSize = new JLabel("Size" ); + JLabel laBold = new JLabel("Bold" ); + JLabel laUnderline = new JLabel("Underline"); + JLabel laItalic = new JLabel("Italic" ); + + m_laFontValue = new JLabel(); + m_laSizeValue = new JLabel(); + m_laBoldValue = new JLabel(); + m_laUnderlineValue = new JLabel(); + m_laItalicValue = new JLabel(); + + aConstraint.gridx = 0; + this.add( laFont, aConstraint ); + aConstraint.gridx = 1; + this.add( m_laFontValue, aConstraint ); + + ++aConstraint.gridy; + + aConstraint.gridx = 0; + this.add( laSize, aConstraint ); + aConstraint.gridx = 1; + this.add( m_laSizeValue, aConstraint ); + + ++aConstraint.gridy; + + aConstraint.gridx = 0; + this.add( laSize, aConstraint ); + aConstraint.gridx = 1; + this.add( m_laSizeValue, aConstraint ); + + ++aConstraint.gridy; + + aConstraint.gridx = 0; + this.add( laBold, aConstraint ); + aConstraint.gridx = 1; + this.add( m_laBoldValue, aConstraint ); + + ++aConstraint.gridy; + + aConstraint.gridx = 0; + this.add( laUnderline, aConstraint ); + aConstraint.gridx = 1; + this.add( m_laUnderlineValue, aConstraint ); + + ++aConstraint.gridy; + + aConstraint.gridx = 0; + this.add( laItalic, aConstraint ); + aConstraint.gridx = 1; + this.add( m_laItalicValue, aConstraint ); + + m_laFontValue.setEnabled (false); + m_laSizeValue.setEnabled (false); + m_laBoldValue.setEnabled (false); + m_laItalicValue.setEnabled (false); + m_laUnderlineValue.setEnabled(false); + + m_laFontValue.setText (FONT_OFF ); + m_laSizeValue.setText (SIZE_OFF ); + m_laBoldValue.setText (BOLD_OFF ); + m_laItalicValue.setText (ITALIC_OFF ); + m_laUnderlineValue.setText(UNDERLINE_OFF); + } + + + + /* + * Set new frame for this view and start listening for events immediately. + * We create one status listener for every control we wish to update. + * And because the environment of the frame can be changed - these + * listener refresh himself internally for frame action events too. + * So we register it as such frame action listener only here. + * Rest is done automatically... + * + * @param xFrame + * will be used as source of possible status events + */ + public void setFrame(com.sun.star.frame.XFrame xFrame) + { + if (xFrame==null) + return; + + // create some listener on given frame for available status events + // Created listener instances will register themselves on this frame and + // show it received information automatically on set UI controls. + m_aFontListener = new StatusListener(m_laFontValue ,FONT_ON ,FONT_OFF ,xFrame, FEATUREURL_FONT ); + m_aSizeListener = new StatusListener(m_laSizeValue ,SIZE_ON ,SIZE_OFF ,xFrame, FEATUREURL_SIZE ); + m_aBoldListener = new StatusListener(m_laBoldValue ,BOLD_ON ,BOLD_OFF ,xFrame, FEATUREURL_BOLD ); + m_aItalicListener = new StatusListener(m_laItalicValue ,ITALIC_ON ,ITALIC_OFF ,xFrame, FEATUREURL_ITALIC ); + m_aUnderlineListener = new StatusListener(m_laUnderlineValue,UNDERLINE_ON,UNDERLINE_OFF,xFrame, FEATUREURL_UNDERLINE); + + m_aFontListener.startListening(); + m_aSizeListener.startListening(); + m_aBoldListener.startListening(); + m_aItalicListener.startListening(); + m_aUnderlineListener.startListening(); + } + + + + /** + * If this java application shutdown - we must cancel all current existing + * listener connections. Otherwise the office will run into some + * DisposedExceptions if it tries to use these forgotten listener references. + * And of course it can die doing that. + * We are registered at a central object to be informed if the VM will exit. + * So we can react. + */ + public void shutdown() + { + m_aFontListener.shutdown(); + m_aSizeListener.shutdown(); + m_aBoldListener.shutdown(); + m_aItalicListener.shutdown(); + m_aUnderlineListener.shutdown(); + + m_aFontListener = null; + m_aSizeListener = null; + m_aBoldListener = null; + m_aItalicListener = null; + m_aUnderlineListener = null; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/ViewContainer.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/ViewContainer.java new file mode 100644 index 000000000..d859f2035 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/ViewContainer.java @@ -0,0 +1,260 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +// __________ Imports __________ + +import java.util.*; + +// __________ Implementation __________ + +/** + * It's implement a static container which hold + * all opened documents and her views alive. + * It's possible to register/deregister such views, + * to get information about these and it provides + * some global functionality - like termination of + * this demo application. + * + */ +public class ViewContainer extends Thread +{ + + + /** + * provides a singleton view container + * Necessary for terminate(9 functionality to be able + * to call Runtime.runFinilization(). + * + * @return a reference to the singleton ViewContainer instance + */ + public static synchronized ViewContainer getGlobalContainer() + { + if (maSingleton==null) + maSingleton=new ViewContainer(); + return maSingleton; + } + + + + /** + * ctor + * It's private - because nobody should create any instance + * expect the only global one, which will be created by ourself! + */ + private ViewContainer() + { + mlViews = new ArrayList<Object>(); + mlListener = new ArrayList<IShutdownListener>(); + mbShutdownActive = false ; + Runtime.getRuntime().addShutdownHook(this); + } + + + + /** + * This register a new view inside this global container + * (if it doesn't already exist). + * + * @param aView view which wishes to be registered inside this container + */ + public void addView(Object aView) + { + synchronized(mlViews) + { + if(!mlViews.contains(aView)) + mlViews.add(aView); + } + } + + + + /** + * This deregister a view from this global container. + * Normally it should be the last reference to the view + * and her finalize() method should be called. + * If last view will be closed here - we terminate these + * java application too. Because there is no further + * visible frame anymore. + * + * @param aView + * view object which wishes to be deregistered + */ + public void removeView(Object aView) + { + int nViewCount = 0; + synchronized(mlViews) + { + if(mlViews.contains(aView)) + mlViews.remove(aView); + + nViewCount = mlViews.size(); + + if (nViewCount<1) + mlViews = null; + } + // If this view is a registered shutdown listener on this view container + // too, we must call his interface and forget him as possible listener. + // It's necessary to guarantee his dead ... + boolean bShutdownView = false; + synchronized(mlListener) + { + bShutdownView = mlListener.contains(aView); + if (bShutdownView) + mlListener.remove(aView); + } + if (bShutdownView) + ((IShutdownListener)aView).shutdown(); + + // We use a system.exit() to finish the whole application. + // And further we have registered THIS instance as a possible shutdown + // hook at the runtime class. So our run() method will be called. + // Our view container should be empty - but + // our listener container can include some references. + // These objects will be informed then and release e.g. some + // remote references. + if (nViewCount<1) + { + boolean bNecessary = false; + synchronized(this) + { + bNecessary = ! mbShutdownActive; + } + if (bNecessary) + { + System.out.println("call exit(0)!"); + System.exit(0); + } + } + } + + + + /** + * add/remove listener for possible shutdown events + */ + public void addListener( IShutdownListener rListener ) + { + synchronized(mlListener) + { + if ( ! mlListener.contains(rListener) ) + mlListener.add(rListener); + } + } + + + + private void removeListener( IShutdownListener rListener ) + { + synchronized(mlListener) + { + if ( mlListener.contains(rListener) ) + mlListener.remove(rListener); + } + } + + + + /** + * Is called from current runtime system of the java machine + * on shutdown. We inform all current registered listener and + * views. They should deinitialize her internal things then. + */ + @Override + public void run() + { + synchronized(this) + { + if (mbShutdownActive) + return; + mbShutdownActive=true; + } + + while( true ) + { + IShutdownListener aListener = null; + synchronized(mlListener) + { + if (!mlListener.isEmpty()) + aListener = mlListener.get(0); + } + if (aListener==null) + break; + + aListener.shutdown(); + // May this listener has deregistered himself. + // But if not we must do it for him. Our own + // method "removeListener()" ignore requests for + // already gone listener objects. + removeListener(aListener); + } + + if (mlViews!=null) + { + synchronized(mlViews) + { + mlViews.clear(); + mlViews = null; + } + } + + if (mlListener!=null) + { + synchronized(mlListener) + { + mlListener.clear(); + mlListener = null; + } + } + } + + + + /** + * @member mbInplace indicates using of inplace office frames instead of outplace ones + * @member maSingleton singleton instance of this view container + * @member mlViews list of all currently registered document views + * @member mlListener list of all currently registered shutdown listener + * @member mbShutdownActive if this shutdown hook already was started it's not a good idea to + * call System.exit() again for other conditions. + * We suppress it by using this variable! + */ + public static boolean mbInplace = false ; + private static ViewContainer maSingleton = null ; + private ArrayList<Object> mlViews ; + private ArrayList<IShutdownListener> mlListener ; + private boolean mbShutdownActive ; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/unix/Makefile b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/unix/Makefile new file mode 100644 index 000000000..aa7a158b8 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/unix/Makefile @@ -0,0 +1,72 @@ +#************************************************************************* +# +# The Contents of this file are made available subject to the terms of +# the BSD license. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Sun Microsystems, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +#************************************************************************** + +# Builds the OfficeDevDesktopEnvironment native library of the Developers Guide. + +PRJ=../../../../../.. +SETTINGS=$(PRJ)/settings + +include $(SETTINGS)/settings.mk +include $(SETTINGS)/std.mk + +# Define non-platform/compiler specific settings +SHL_NAME=nativeview +SHL_LIBRARY=$(SHAREDLIB_OUT)/$(SHAREDLIB_PRE)$(SHL_NAME).$(SHAREDLIB_EXT) + +OUT_SHL_SLO=$(OUT_SLO)/nativeview + +CFILES = nativeview.c + +SLOFILES = $(patsubst %.c,$(OUT_SHL_SLO)/%.$(OBJ_EXT),$(CFILES)) + + +# Targets +.PHONY: ALL +ALL : $(SHL_LIBRARY) + +include $(SETTINGS)/stdtarget.mk + +$(OUT_SHL_SLO)/%.$(OBJ_EXT) : %.c + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(CC) $(CC_FLAGS_JNI) $(CC_INCLUDES) $(SDK_JAVA_INCLUDES) $(CC_DEFINES_JNI) $(CC_OUTPUT_SWITCH)$(subst /,$(PS),$@) $< + +$(SHAREDLIB_OUT)/$(SHAREDLIB_PRE)$(SHL_NAME).$(SHAREDLIB_EXT) : $(SLOFILES) + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(LINK) $(LIBRARY_LINK_FLAGS) $(LINK_LIBS) $(LINK_JAVA_LIBS) -o $@ $< \ + -ljawt $(CPPUHELPERLIB) $(CPPULIB) $(SALLIB) $(STDC++LIB) + +.PHONY: clean +clean : + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_SHL_SLO)) + -$(DEL) $(subst /,$(PS),$(SHAREDLIB_OUT))$(PS)*$(SHL_NAME)*.* diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/unix/nativeview.c b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/unix/nativeview.c new file mode 100644 index 000000000..5343f85e9 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/unix/nativeview.c @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Intrinsic.h> + +#include "jawt.h" +#include "jawt_md.h" +#include "nativeview.h" + +#define MY_ASSERT(X,S) if (!X) { fprintf(stderr,S); return 0;} + +#define SYSTEM_WIN32 1 +#define SYSTEM_WIN16 2 +#define SYSTEM_JAVA 3 +#define SYSTEM_OS2 4 +#define SYSTEM_MAC 5 +#define SYSTEM_XWINDOW 6 + +/*****************************************************************************/ +/* + * Class: NativeView + * Method: getNativeWindowSystemType + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_NativeView_getNativeWindowSystemType + (JNIEnv * env, jobject obj_this) +{ + return SYSTEM_XWINDOW; +} + +/*****************************************************************************/ +/* + * Class: NativeView + * Method: getNativeWindow + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_NativeView_getNativeWindow + (JNIEnv * env, jobject obj_this) +{ + jboolean result ; + jint lock ; + JAWT awt ; + JAWT_DrawingSurface* ds ; + JAWT_DrawingSurfaceInfo* dsi ; + JAWT_X11DrawingSurfaceInfo* dsi_x11 ; + Drawable drawable; + + /* Get the AWT */ + awt.version = JAWT_VERSION_1_3; + result = JAWT_GetAWT(env, &awt); + MY_ASSERT(result != JNI_FALSE,"wrong jawt version"); + + /* Get the drawing surface */ + if ((ds = awt.GetDrawingSurface(env, obj_this)) == NULL) + return 0; + + /* Lock the drawing surface */ + lock = ds->Lock(ds); + MY_ASSERT((lock & JAWT_LOCK_ERROR)==0,"can't lock the drawing surface"); + + /* Get the drawing surface info */ + dsi = ds->GetDrawingSurfaceInfo(ds); + + /* Get the platform-specific drawing info */ + dsi_x11 = (JAWT_X11DrawingSurfaceInfo*)dsi->platformInfo; + drawable = dsi_x11->drawable; + + /* Free the drawing surface info */ + ds->FreeDrawingSurfaceInfo(dsi); + /* Unlock the drawing surface */ + ds->Unlock(ds); + /* Free the drawing surface */ + awt.FreeDrawingSurface(ds); + + return (jlong)drawable; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/unix/nativeview.h b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/unix/nativeview.h new file mode 100644 index 000000000..99207192f --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/unix/nativeview.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class org_openoffice_OpenOffice */ + +#ifndef _Included_NativeView +#define _Included_NativeView +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_openoffice_OpenOffice + * Method: getNativeWindowSystemType + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_NativeView_getNativeWindowSystemType(JNIEnv*, jobject); + +/* + * Class: org_openoffice_OpenOffice + * Method: getNativeWindow + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_NativeView_getNativeWindow(JNIEnv*, jobject); + +#ifdef __cplusplus +} +#endif +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/Makefile b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/Makefile new file mode 100644 index 000000000..62980a2ee --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/Makefile @@ -0,0 +1,77 @@ +#************************************************************************* +# +# The Contents of this file are made available subject to the terms of +# the BSD license. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Sun Microsystems, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +#************************************************************************** + +# Builds the OfficeDevDesktopEnvironment native library of the Developers Guide. + +PRJ=../../../../../.. +SETTINGS=$(PRJ)/settings + +include $(SETTINGS)/settings.mk +include $(SETTINGS)/std.mk + +# Define non-platform/compiler specific settings +SHL_NAME=nativeview +SHL_LIBRARY=$(SHAREDLIB_OUT)/$(SHAREDLIB_PRE)$(SHL_NAME).$(SHAREDLIB_EXT) + +OUT_SHL_SLO=$(OUT_SLO)/nativeview +OUT_SHL_MISC=$(OUT_MISC)/nativeview + +CFILES = nativeview.c + +SLOFILES = $(patsubst %.c,$(OUT_SHL_SLO)/%.$(OBJ_EXT),$(CFILES)) + +# Targets +.PHONY: ALL +ALL : \ + $(SHL_LIBRARY) + +include $(SETTINGS)/stdtarget.mk + +$(OUT_SHL_SLO)/%.$(OBJ_EXT) : %.c + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(CC) $(CC_FLAGS_JNI) $(CC_INCLUDES) $(SDK_JAVA_INCLUDES) $(CC_DEFINES_JNI) $(CC_OUTPUT_SWITCH)$(subst /,$(PS),$@) $< + +$(SHAREDLIB_OUT)/$(SHAREDLIB_PRE)$(SHL_NAME).$(SHAREDLIB_EXT) : $(SLOFILES) $(SHL_NAME).def + -$(MKDIR) $(subst /,$(PS),$(@D)) + -$(MKDIR) $(subst /,$(PS),$(OUT_SHL_MISC)) + $(LINK) $(LIBRARY_LINK_FLAGS) /DEF:$(SHL_NAME).def /OUT:$@ \ + /MAP:$(OUT_SHL_MISC)/$(SHL_NAME).map $(LINK_JAVA_LIBS) \ + $(SLOFILES) jawt.lib $(LIBO_SDK_LDFLAGS_STDLIBS) user32.lib + $(LINK_MANIFEST) + +.PHONY: clean +clean : + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_SHL_SLO)) + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_SHL_MISC)) + -$(DEL) $(subst \\,\,$(subst /,$(PS),$(SHAREDLIB_OUT))$(PS)*$(SHL_NAME)*.*) diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/nativeview.c b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/nativeview.c new file mode 100644 index 000000000..2de998c69 --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/nativeview.c @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +#include <windows.h> + +#include "jawt.h" +#include "jawt_md.h" +#include "NativeView.h" + +#define MY_ASSERT(X,S) if (!X) { fprintf(stderr,"%s\n",S); return 0;} + +#define SYSTEM_WIN32 1 +#define SYSTEM_WIN16 2 +#define SYSTEM_JAVA 3 +#define SYSTEM_OS2 4 +#define SYSTEM_MAC 5 +#define SYSTEM_XWINDOW 6 + +// property name to register own window procedure on hwnd +#define OLD_PROC_KEY "oldwindowproc" +// signature of this window procedure +static LRESULT APIENTRY NativeViewWndProc( HWND , UINT , WPARAM , LPARAM ); + +/***************************************************************************** + * + * Class : NativeView + * Method : getNativeWindowSystemType + * Signature : ()I + * Description: returns an identifier for the current operating system + */ +JNIEXPORT jint JNICALL Java_NativeView_getNativeWindowSystemType + (JNIEnv * env, jobject obj_this) +{ + return SYSTEM_WIN32; +} + +/***************************************************************************** + * + * Class : NativeView + * Method : getNativeWindow + * Signature : ()J + * Description: returns the native systemw window handle of this object + */ +JNIEXPORT jlong JNICALL Java_NativeView_getNativeWindow + (JNIEnv * env, jobject obj_this) +{ + jboolean result ; + jint lock ; + JAWT awt ; + JAWT_DrawingSurface* ds ; + JAWT_DrawingSurfaceInfo* dsi ; + JAWT_Win32DrawingSurfaceInfo* dsi_win ; + HDC hdc ; + HWND hWnd ; + LONG hFuncPtr; + + /* Get the AWT */ + awt.version = JAWT_VERSION_1_3; + result = JAWT_GetAWT(env, &awt); + MY_ASSERT(result!=JNI_FALSE,"wrong jawt version"); + + /* Get the drawing surface */ + if ((ds = awt.GetDrawingSurface(env, obj_this)) == NULL) + return 0; + + /* Lock the drawing surface */ + lock = ds->Lock(ds); + MY_ASSERT((lock & JAWT_LOCK_ERROR)==0,"can't lock the drawing surface"); + + /* Get the drawing surface info */ + dsi = ds->GetDrawingSurfaceInfo(ds); + + /* Get the platform-specific drawing info */ + dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo; + hdc = dsi_win->hdc; + hWnd = dsi_win->hwnd; + + /* Free the drawing surface info */ + ds->FreeDrawingSurfaceInfo(dsi); + /* Unlock the drawing surface */ + ds->Unlock(ds); + /* Free the drawing surface */ + awt.FreeDrawingSurface(ds); + + /* Register own window procedure + Do it one times only! Otherwise + multiple instances will be registered + and calls on such construct produce + a stack overflow. + */ + if (GetProp( hWnd, OLD_PROC_KEY )==0) + { + hFuncPtr = SetWindowLongPtr( hWnd, GWLP_WNDPROC, (LONG_PTR)NativeViewWndProc ); + SetProp( hWnd, OLD_PROC_KEY, (HANDLE)hFuncPtr ); + } + + return (jlong)hWnd; +} + +/***************************************************************************** + * + * Class : - + * Method : NativeViewWndProc + * Signature : - + * Description: registered window handler to intercept window messages between + * java and office process + */ +static LRESULT APIENTRY NativeViewWndProc( + HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HANDLE hFuncPtr; + + /* resize new created child window to fill out the java window complete */ + if (uMsg==WM_PARENTNOTIFY) + { + if (wParam == WM_CREATE) + { + RECT rect; + HWND hChild = (HWND) lParam; + + GetClientRect(hWnd, &rect); + + SetWindowPos(hChild, + NULL, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOZORDER); + } + } + /* handle normal resize events */ + else if(uMsg==WM_SIZE) + { + WORD newHeight = HIWORD(lParam); + WORD newWidth = LOWORD(lParam); + HWND hChild = GetWindow(hWnd, GW_CHILD); + + if (hChild != NULL) + SetWindowPos(hChild, NULL, 0, 0, newWidth, newHeight, SWP_NOZORDER); + } + + /* forward request to original handler which is intercepted by this window procedure */ + hFuncPtr = GetProp(hWnd, OLD_PROC_KEY); + MY_ASSERT(hFuncPtr,"lost original window proc handler"); + return CallWindowProc( hFuncPtr, hWnd, uMsg, wParam, lParam); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/nativeview.def b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/nativeview.def new file mode 100644 index 000000000..f9ba2a78b --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/nativeview.def @@ -0,0 +1,3 @@ +EXPORTS
+Java_NativeView_getNativeWindowSystemType
+Java_NativeView_getNativeWindow
diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/nativeview.h b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/nativeview.h new file mode 100644 index 000000000..99207192f --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/nativelib/windows/nativeview.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class org_openoffice_OpenOffice */ + +#ifndef _Included_NativeView +#define _Included_NativeView +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_openoffice_OpenOffice + * Method: getNativeWindowSystemType + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_NativeView_getNativeWindowSystemType(JNIEnv*, jobject); + +/* + * Class: org_openoffice_OpenOffice + * Method: getNativeWindow + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_NativeView_getNativeWindow(JNIEnv*, jobject); + +#ifdef __cplusplus +} +#endif +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |