/*************************************************************************
*
* $RCSfile: BasicOfficeBean.java,v $
*
* $Revision: 1.4 $
*
* last change: $Author: mi $ $Date: 2003/01/10 13:47:29 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (the "License"); You may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at http://www.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
import java.awt.Component;
import java.awt.Container;
import java.awt.Canvas;
import java.awt.Window;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Rectangle;
import java.io.IOException;
import java.util.List;
import java.util.LinkedList;
import com.sun.star.lang.XEventListener;
import com.sun.star.lang.EventObject;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.awt.XWindow;
import com.sun.star.awt.XWindowPeer;
import com.sun.star.awt.InvalidateStyle;
import com.sun.star.frame.XFrame;
import com.sun.star.frame.XModel;
import com.sun.star.frame.XDispatchProvider;
import com.sun.star.frame.XSynchronousFrameLoader;
import com.sun.star.frame.XStorable;
import com.sun.star.frame.FrameActionEvent;
import com.sun.star.frame.FrameAction;
import com.sun.star.document.XTypeDetection;
import com.sun.star.beans.PropertyValue;
import com.sun.star.beans.PropertyState;
import com.sun.star.beans.PropertyVetoException;
import com.sun.star.beans.OfficeConnection;
import com.sun.star.beans.OfficeWindow;
import com.sun.star.util.XModifiable;
import com.sun.star.util.XURLTransformer;
import com.sun.star.uno.UnoRuntime;
/**
* This class provides a basic functionality of the office bean.
* The application developer can subclass from this class in order
* to provide application specific methods.
*/
public class BasicOfficeBean
extends Container
{
private transient OfficeConnection mConnection;
private transient OfficeWindow mWindow;
private transient CommandConveyor mCommandConveyor;
protected String mDocumentURL;
protected transient XMultiServiceFactory mServiceFactory;
protected transient XFrame mFrame;
protected transient XModifiable mModifiable;
// slot command execution environment
protected transient XDispatchProvider mDispatcher;
protected transient XMultiServiceFactory mFrameLoaderFactory;
protected transient XURLTransformer mURLTransformer;
protected transient XTypeDetection mTypeDetector;
/**
* Constructor.
*
* This constructor sets default layout manager (BorderLayout)
* and creates the command execution conveyor. It also sets the
* default appearance of the bean.
*/
public BasicOfficeBean()
{
setLayout(new BorderLayout());
mCommandConveyor = new CommandConveyor();
mCommandConveyor.start();
add(new PlaceHolder());
}
/**
* Sets the office connection object.
* A subclass can provide own implementation of this method
* in order to set up the ContainerFactory on the connection
* object, but it MUST chain with this method implementation.
*
* @param connection The connection object.
*/
public synchronized void setOfficeConnection(OfficeConnection connection)
throws java.lang.IllegalStateException
{
if (mWindow != null)
throw new java.lang.IllegalStateException(
"The connection is still open.");
mConnection = connection;
mConnection.addEventListener(new ConnectionListener());
}
/**
* Determines is document was loaded or not.
*
* @return <code>true</code> if a document has been loaded.
*/
public boolean isDocumentLoaded()
{
return (mDocumentURL != null);
}
/**
* Loads a document referenced by a URL.
*
* @param url The document's URL string.
* @exception java.io.IOException if the document loading process has
* failed.
*/
public synchronized void load(String url)
throws java.io.IOException
{
try {
if (mWindow == null)
openConnection();
// Determine the document URL.
if (url.equals(""))
url = getDefaultDocumentURL();
// Find out the type of the document.
String type = mTypeDetector.queryTypeByURL(url);
// TypeDetection may have failed, bug Office version 627
if ((type == null) || (type.length() == 0))
type = "writer_Text";
System.out.println(type);
// Get document frame loader factory.
Object object = mFrameLoaderFactory.createInstance(type);
XSynchronousFrameLoader frameLoader;
frameLoader = (XSynchronousFrameLoader)UnoRuntime.queryInterface(
XSynchronousFrameLoader.class, object);
// Create the document descriptor.
PropertyValue[] desc = new PropertyValue[2];
desc[0] = new PropertyValue(
"FileName", 0, url, PropertyState.DIRECT_VALUE);
desc[1] = new PropertyValue(
"TypeName", 0, type, PropertyState.DIRECT_VALUE);
// Avoid Dialog 'Document changed' while reloading
try {
setModified(false);
} catch (java.lang.IllegalStateException exp) {
}
// Load the document.
if (frameLoader.load(desc, mFrame) == false) {
throw new java.io.IOException(
"Can not load a document: \"" + url + "\"");
}
mDocumentURL = url;
// Get document's XModifiable interface if any.
if ((mFrame != null) && (mFrame.getController() != null)) {
XModel model = mFrame.getController().getModel();
mModifiable = (XModifiable)UnoRuntime.queryInterface(
XModifiable.class, model);
} else {
mModifiable = null;
}
// Find top most parent and force it to validate.
Container parent = this;
while(parent.getParent() != null)
parent = parent.getParent();
((Window)parent).validate();
} catch (com.sun.star.uno.Exception exp) {
throw new java.io.IOException(exp.getMessage());
}
}
/**
* Saves the document.
*/
public void save()
throws java.io.IOException
{
if (isDocumentLoaded() == false)
throw new java.io.IOException("The document has not been loaded.");
else if (mDocumentURL.startsWith("private:") == true)
throw new java.io.IOException("The document URL has not been defined.");
XStorable storable = (XStorable)UnoRuntime.queryInterface(
XStorable.class, mFrame.getController().getModel());
try {
storable.store();
} catch (com.sun.star.io.IOException exp) {
throw new java.io.IOException(exp.getMessage());
}
}
/**
* Saves the document.
*
* @param url The location where the document should be stored.
*/
public void save(String url)
throws java.io.IOException
{
// The implementation of this method MUST replace
// the document URL with new value on succesful save.
throw new java.lang.UnsupportedOperationException(
"There is no implementation for this operation.");
}
/**
* Queues an office command for asynchronous execution.
*
* @param command The office command for asynchronous execution.
*/
public void queue(OfficeCommand command)
{
if (command == null)
throw new java.lang.IllegalArgumentException(
"The command may not be null.");
mCommandConveyor.queue(command);
}
/**
* Retrives a URL of the default office document.
*
* This method can be overriden by a subclass in order to customize
* the default document URL.
*
* @return The URL of the default document.
*/
public String getDefaultDocumentURL()
{
return null;
}
/**
* Retrives an office document URL.
*
* @return The URL of the office document.
*/
public String getDocumentURL()
{
return mDocumentURL;
}
/**
* Determines is the office document modifiable.
*
* @return <code>true</code> if the document is modifiable.
*/
public boolean isModifiable()
{
return (mModifiable != null);
}
/**
* Sets the office document modification state.
*
* @param state The new state of document modification.
* @exception java.lang.IllegalStateException if the documnent can not
* accept the new modification state.
*/
public void setModified(boolean state)
throws java.lang.IllegalStateException
{
if (isModifiable() == false) {
throw new java.lang.IllegalStateException(
"The document \"" + mDocumentURL + "\" is not modifiable.");
}
try {
mModifiable.setModified(state);
} catch (com.sun.star.beans.PropertyVetoException exp) {
throw new java.lang.IllegalStateException(exp.getMessage());
}
}
/**
* Retrives the office document modification state.
*
* @return The document modification state.
*/
public boolean isModified()
{
return (isModifiable() != false)? mModifiable.isModified(): false;
}
/**
* Opens the connection.
*/
public synchronized void openConnection()
throws com.sun.star.uno.Exception
{
if (mWindow != null)
return;
// Establishe the connection by request of the ServiceFactory.
XMultiComponentFactory compfactory;
compfactory = mConnection.getComponentContext().getServiceManager();
mServiceFactory = (XMultiServiceFactory)UnoRuntime.queryInterface(
XMultiServiceFactory.class, compfactory);
// Create the OfficeWindow.
removeAll();
mWindow = mConnection.createOfficeWindow(this);
add(mWindow.getAWTComponent());
// Create the office document frame and initialize the bean.
initialize();
}
/**
* Closes the connection.
*/
public synchronized void closeConnection()
{
mConnection.dispose();
}
/**
* Recieves notification of the connection closed event.
*
* If a subclass wants to be notified on connection closed event it
* should add a listener to the connection object.
*/
private synchronized void connectionClosed()
{
if (mWindow != null) {
// Clean up
mFrame.dispose();
mFrame = null;
mModifiable = null;
mDispatcher = null;
mTypeDetector = null;
mFrameLoaderFactory = null;
mURLTransformer = null;
mServiceFactory = null;
remove((Component)mWindow);
mWindow = null;
}
}
/**
* This class is a connection life-cycle event listener.
*/
private class ConnectionListener
implements XEventListener
{
/**
* Receives a notification about the connection has been closed.
*
* @param source The event object.
*/
public void disposing(EventObject source)
{
connectionClosed();
}
}
/**
* Office command execution conveyor.
*/
private class CommandConveyor
extends Thread
{
private final List mQueue = new LinkedList();
/**
* Appends a command to the tail of the queue.
*
* @param command The office command to add to the queue.
*/
public void queue(OfficeCommand command)
{
synchronized (mQueue) {
mQueue.add(command);
mQueue.notify();
}
}
/**
* Executes commands from the queue.
*/
public void run()
{
OfficeCommand command;
while (true) {
try {
synchronized (mQueue) {
if (mQueue.isEmpty() == true) {
mQueue.wait();
}
command = (OfficeCommand)mQueue.remove(0);
}
command.execute(BasicOfficeBean.this);
} catch (java.lang.InterruptedException exp) {
// Wait has been interrupted.
// Do nothing, but do not execute a command which
// does not exist.
}
}
}
}
/**
* Initializes the bean.
*
* @exception com.sun.star.uno.Exception if the frame has not been
* created or the slot command execution environment initialization
* has failed.
*/
private void initialize()
throws com.sun.star.uno.Exception
{
Object object;
// Create the document frame from UNO window. (< 6.1 => Taks, >= 6.1 => Frame)
XWindow window = (XWindow) UnoRuntime.queryInterface(
XWindow.class, mWindow.getUNOWindowPeer());
object = mServiceFactory.createInstance( "com.sun.star.frame.Task");
if ( object == null )
object = mServiceFactory.createInstance( "com.sun.star.frame.Frame");
mFrame = (XFrame)UnoRuntime.queryInterface(
XFrame.class, object);
mFrame.initialize(window);
// Initializes the slot command execution environment.
object = mServiceFactory.createInstance(
"com.sun.star.util.URLTransformer");
mURLTransformer = (XURLTransformer)UnoRuntime.queryInterface(
XURLTransformer.class, object);
object = mServiceFactory.createInstance(
"com.sun.star.frame.FrameLoaderFactory");
mFrameLoaderFactory = (XMultiServiceFactory)UnoRuntime.queryInterface(
XMultiServiceFactory.class, object);
object = mServiceFactory.createInstance(
"com.sun.star.document.TypeDetection");
mTypeDetector = (XTypeDetection)UnoRuntime.queryInterface(
XTypeDetection.class, object);
mDispatcher = (XDispatchProvider)UnoRuntime.queryInterface(
XDispatchProvider.class, mFrame);
}
/**
* Frees up resources.
*/
protected void finalize()
throws Throwable
{
super.finalize();
if (mConnection != null)
mConnection.dispose();
}
/**
* Default appearance of the bean.
*/
private class PlaceHolder
extends Canvas
{
public void paint(Graphics g)
{
g.setColor(Color.white);
Rectangle rect = getBounds();
g.fillRect(rect.x, rect.y, rect.width, rect.height);
g.setColor(new Color(0x666699));
rect.setBounds(rect.x + 1, rect.y + 1,
rect.width - 3, rect.height - 3);
g.drawRect(rect.x, rect.y, rect.width, rect.height);
rect.setBounds(rect.x + 2, rect.y + 2,
rect.width - 4, rect.height - 4);
g.drawRect(rect.x, rect.y, rect.width, rect.height);
g.drawString(BasicOfficeBean.this.getClass().getName(),
rect.x + 10, rect.y + 15);
}
}
}