/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
 */

package embeddedobj.test;

import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import java.util.Vector;

import javax.swing.JOptionPane;
import javax.swing.Timer;

import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.lang.XSingleServiceFactory;

import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XInterface;
import com.sun.star.uno.AnyConverter;
import com.sun.star.uno.Type;
import com.sun.star.uno.Any;

import com.sun.star.lang.XComponent;

import com.sun.star.util.XCloseable;
import com.sun.star.util.XURLTransformer;
import com.sun.star.util.URL;

import com.sun.star.beans.PropertyValue;
import com.sun.star.beans.NamedValue;

import com.sun.star.datatransfer.DataFlavor;
import com.sun.star.datatransfer.XTransferable;

import com.sun.star.container.XNameAccess;

import com.sun.star.io.XStream;
import com.sun.star.io.XInputStream;
import com.sun.star.io.XOutputStream;
import com.sun.star.io.XTruncate;

import com.sun.star.awt.XWindow;
import com.sun.star.awt.XBitmap;

import com.sun.star.task.XJob;

import com.sun.star.embed.*;


class ActionObject
{
    public byte m_nID;
    public String m_sParam;

    public ActionObject()
    {
        m_nID = 0;
        m_sParam = null;
    }

    public ActionObject( byte nID )
    {
        m_nID = nID;
        m_sParam = null;
    }

    public ActionObject( byte nID, String sParam )
    {
        m_nID = nID;
        m_sParam = sParam;
    }

    public ActionObject( ActionObject aObject )
    {
        m_nID = aObject.m_nID;
        m_sParam = aObject.m_sParam;
    }
};

public class EmbedContApp extends Applet
    implements MouseListener, XEmbeddedClient, ActionListener, XJob, XInplaceClient, XWindowSupplier
{
    private XMultiServiceFactory m_xServiceFactory;

    private final boolean m_bStoreVisRepl = false;

    private XJob m_xMainThreadExecutor;
    private NamedValue[] m_pValuesForExecutor;

    private XEmbeddedObject m_xEmbedObj;
    private XStorage m_xStorage;
    private float    m_nXScaling;
    private float    m_nYScaling;
    private float    m_nXPixelSize;
    private float    m_nYPixelSize;

    private Frame m_aFrame;
    private Menu m_aFileMenu;
    private Menu m_aObjectMenu;
    private Toolkit m_aToolkit;

    private Image m_aImage;
    private Object m_oImageLock;

    private boolean m_bOwnFile = false;

    private boolean m_bLinkObj = false;
    private String m_aLinkURI;

    private Object m_oActionsNumberLock;

    private Timer m_aTimer;
    private boolean m_bDestroyed = false;

    private Object m_oInHandlerLock;
    private boolean m_bInHandler = false;

    private XURLTransformer m_xTransformer;

    private NativeView m_aNativeView;
    private XWindow m_xVCLWindow;

    private XBitmap m_xBitmap;
    private BitmapPainter m_aBitmapPainter;

// Constants
    private final byte DESTROY                  =  1;
    private final byte ACTIVATE_OUTPLACE        =  2;
    private final byte NEW_DOCUMENT             =  3;
    private final byte SAVE_AS                  =  4;
    private final byte OPEN_FILE                =  5;
    private final byte SAVE                     =  6;
    private final byte NEW_OBJECT               =  7;
    private final byte OBJECT_FROM_FILE         =  8;
    private final byte LINK_FROM_FILE           =  9;
    private final byte CONVERT_LINK_TO_OBJECT   = 10;
    private final byte ACTIVATE_INPLACE         = 11;
    private final byte DEACTIVATE               = 12;

// Methods
    public EmbedContApp( Frame aFrame, XMultiServiceFactory xServiceFactory )
    {
        m_aFrame = aFrame;
        m_xServiceFactory = xServiceFactory;
    }

    public void init()
    {
        resize( 800, 600 );
        setBackground( Color.gray );

        m_aToolkit = Toolkit.getDefaultToolkit();

        try {
            Object oTransformer = m_xServiceFactory.createInstance( "com.sun.star.util.URLTransformer" );
            m_xTransformer = (XURLTransformer)UnoRuntime.queryInterface( XURLTransformer.class, oTransformer );
        } catch( Exception e ) { System.exit( 0 ); }

        m_oActionsNumberLock = new Object();
        m_aActionsList = new ArrayList();

        m_oInHandlerLock = new Object();
        m_oImageLock = new Object();

        try {
            Object oJob = m_xServiceFactory.createInstance( "com.sun.star.comp.thread.MainThreadExecutor" );
            m_xMainThreadExecutor = (XJob)UnoRuntime.queryInterface( XJob.class, oJob );
        } catch( Exception e ) {}

        if ( m_xMainThreadExecutor == null )
        {
            System.out.println( "Can't create MainThreadExecutor! The application is unusable!" );
            System.exit( 0 );
        }

        m_nXScaling = 1;
        m_nYScaling = 1;
        m_nXPixelSize = 1;
        m_nYPixelSize = 1;

        m_pValuesForExecutor = new NamedValue[1];
        m_pValuesForExecutor[0] = new NamedValue( "JobToExecute", (Object)this );

        m_aTimer = new Timer( 100, this );
        m_aTimer.start();

        // Get a menu bar.
        MenuBar aMenuBar = m_aFrame.getMenuBar();
        if( aMenuBar == null )
        {
            aMenuBar = new MenuBar();
            m_aFrame.setMenuBar( aMenuBar );
        }

        // Create menus for the menu bar.

        // File menu
        m_aFileMenu = new Menu( "File", true );
        aMenuBar.add( m_aFileMenu );

        MenuItem aItem = new NewMenuItem();
        m_aFileMenu.add( aItem );

        aItem = new OpenFileMenuItem();
        m_aFileMenu.add( aItem );

        aItem = new SaveMenuItem();
        m_aFileMenu.add( aItem );

        aItem = new SaveAsMenuItem();
        m_aFileMenu.add( aItem );

        // Object menu
        m_aObjectMenu = new Menu( "Object", true );
        aMenuBar.add( m_aObjectMenu );

        aItem = new NewObjectMenuItem();
        m_aObjectMenu.add( aItem );

        aItem = new LoadObjectMenuItem();
        m_aObjectMenu.add( aItem );

        aItem = new LinkObjectMenuItem();
        m_aObjectMenu.add( aItem );

        aItem = new ConvertLinkToEmbedMenuItem();
        m_aObjectMenu.add( aItem );

        // Activation menu
        m_aObjectMenu = new Menu( "Activation", true );
        aMenuBar.add( m_aObjectMenu );

        aItem = new ActivateOutplaceMenuItem();
        m_aObjectMenu.add( aItem );

        aItem = new ActivateInplaceMenuItem();
        m_aObjectMenu.add( aItem );

        aItem = new DeactivateMenuItem();
        m_aObjectMenu.add( aItem );

        m_aNativeView = new NativeView();
        m_aNativeView.resize( 800, 600 );
        this.add( m_aNativeView );


    public void actionPerformed( ActionEvent evt )
    {
        synchronized( m_oInHandlerLock )
        {
            if ( m_bInHandler )
                return;
            m_bInHandler = true;
        }

        synchronized( m_oActionsNumberLock )
        {
            if ( m_aActionsList.size() > 0 )
            {
                try {
                    m_xMainThreadExecutor.execute( m_pValuesForExecutor );
                }
                catch( Exception e )
                {
                    System.out.println( "Exception in actionPerformed() : " + e );
                }
            }
            else
            {
                synchronized( m_oInHandlerLock )
                {
                    m_bInHandler = false;
                }
            }
        }
    }

    // XWindowSupplier
    public XWindow getWindow()
    {
        return m_xVCLWindow;
    }

    // XEmbeddedClient
    public void saveObject()
        throws com.sun.star.uno.Exception
    {
        if ( m_xEmbedObj != null )
        {
            try {
                XEmbedPersist xPersist = (XEmbedPersist)UnoRuntime.queryInterface( XEmbedPersist.class, m_xEmbedObj );
                if ( xPersist != null )
                {
                    xPersist.storeOwn();
                    generateNewImage();
                }
                else
                    JOptionPane.showMessageDialog( m_aFrame, "No XEmbedPersist!", "Error:", JOptionPane.ERROR_MESSAGE );
            }
            catch( Exception e )
            {
                JOptionPane.showMessageDialog( m_aFrame, e, "Exception in saveObject:", JOptionPane.ERROR_MESSAGE );
            }
        }

        generateNewImage();
        repaint();
    }

    public void onShowWindow( boolean bVisible )
    {
        // for now nothing to do
    }

    // XInplaceClient
    public boolean canInplaceActivate()
    {
        return true;
    }

    public void onInplaceActivate()
    {
        // TODO
        // prepare for inplace activation

        // REMOVE
        // workaround for CLIPCHILDREN problem
        if ( m_aBitmapPainter != null )
            m_aBitmapPainter.stopPainting();
    }

    public void onUIActivate()
    {
        // TODO
        // prepare for UI activate
    }

    public void onInplaceDeactivate()
    {
        // TODO
        // inplace deactivation is done

        // REMOVE
        // workaround for CLIPCHILDREN problem
        if ( m_aBitmapPainter != null )
            m_aBitmapPainter.startPainting();
    }

    public void onUIDeactivate()
    {
        // TODO
        // prepare for UI deactivate
    }

    public XIPMainContainerWindow getTopmostWindow()
    {
        // TODO
        // return an implementation of XIPMainContainerWindow
        // mainly required for ui activation
        // dummy implementation is enough for inplace activation

        return null;
    }

    public XInplaceUIWindow getDocumentWindow()
    {
        // TODO
        // return implementation of XInplaceUIWindow
        // mainly required for ui activation
        // dummy implementation is enough for inplace activation

        return null;
    }

    public com.sun.star.awt.Rectangle getPosRect()
    {
        // provide position rectangle to the object
        try {
            // here object bitmap and scaling factor hold the size
            com.sun.star.awt.Size aBitmapSize = m_xBitmap.getSize();
            com.sun.star.awt.Size aVisSize = new com.sun.star.awt.Size(
                                            (int)( aBitmapSize.Width * m_nXScaling ),
                                            (int)( aBitmapSize.Height * m_nYScaling ) );
            return new com.sun.star.awt.Rectangle( 10, 10, aVisSize.Width, aVisSize.Height );
        }
        catch( Exception e )
        {
            System.out.println( "Position rectangle generation failed!" );
        }

        return new com.sun.star.awt.Rectangle( 10, 10, 110, 110 );
    }

    public com.sun.star.awt.Rectangle getClipRect()
    {
        // provide clip rectangle to the object
        // in this application position and clip rectangles are the same

        try {
            // here object bitmap and scaling factor hold the size
            com.sun.star.awt.Size aBitmapSize = m_xBitmap.getSize();
            com.sun.star.awt.Size aVisSize = new com.sun.star.awt.Size(
                                            (int)( aBitmapSize.Width * m_nXScaling ),
                                            (int)( aBitmapSize.Height * m_nYScaling ) );
            return new com.sun.star.awt.Rectangle( 10, 10, aVisSize.Width, aVisSize.Height );
        }
        catch( Exception e )
        {
            System.out.println( "Clip rectangle generation failed!" );
        }

        return new com.sun.star.awt.Rectangle( 10, 10, 110, 110 );
    }

    public void translateAccelerators( com.sun.star.awt.KeyEvent[] aKeys )
    {
        // TODO
        // an accelerator table for object
        // ui activation related
    }

    public void scrollObj( com.sun.star.awt.Size aOffset )
    {
        // TODO
        // scrolls the object to a specified offset
        // not mandatory for the testing application :)
    }

    public void onPosRectChange( com.sun.star.awt.Rectangle aPosRect )
    {
        // object asks to change the position
        if ( m_xEmbedObj != null )
        {
            try {
                int nState = m_xEmbedObj.getCurrentState();
                // such a position change make sense only when object is
                // either inplace or ui active
                if ( nState == EmbedStates.EMBED_INPLACE_ACTIVE
                  || nState == EmbedStates.EMBED_UI_ACTIVE )
                 {
                    XInplaceObject xInplObj = (XInplaceObject)UnoRuntime.queryInterface( XInplaceObject.class, m_xEmbedObj );
                     if ( xInplObj != null )
                    {
                        xInplObj.setObjectRects( aPosRect, aPosRect ); // show the whole object
                        if ( m_aBitmapPainter != null )
                            m_aBitmapPainter.setRect( aPosRect );
                    }
                    else
                         System.out.println( "Why object that does not support inplace activation behave like inplace object?!" );
                 }
                 else
                     System.out.println( "The object is not active but asks to change visual area!" );
            } catch( Exception e )
            {
                 System.out.println( "Exception is thrown in onPosRectChange: " + e );
            }
        }
        else
             System.out.println( "Who asks to change visual area?!!" );
    }

    // XJob
    public Object execute( NamedValue[] pValues )
    {
        for( int nInd = 0; nInd < m_aActionsList.size(); nInd++ )
        {
            ActionObject aAction = m_aActionsList.get( nInd );
            if ( aAction != null )
            {
                if ( aAction.m_nID == DESTROY )
                {
                    // free all resources
                    clearObjectAndStorage();
                    m_bDestroyed = true;
                }
                else if ( aAction.m_nID == ACTIVATE_OUTPLACE )
                {
                    // activate object if exists and not active
                    if ( m_xEmbedObj != null )
                    {
                        try {
                            m_xEmbedObj.changeState( EmbedStates.EMBED_ACTIVE );
                        }
                        catch( Exception ex )
                        {
                            System.out.println( "Exception on mouse click" + ex );
                        }
                    }
                }
                else if ( aAction.m_nID == NEW_DOCUMENT )
                {
                    // clear everything
                    clearObjectAndStorage();

                    repaint();
                }
                else if ( aAction.m_nID == SAVE_AS )
                {
                    // open SaveAs dialog and store

                    if ( m_xStorage != null && m_xEmbedObj != null )
                    {
                        try {
                            /*
                                if ( m_bLinkObj )
                                    storeLinkAsFileURI( aFileURI );
                                else
                            */
                            saveObjectAsFileURI( aAction.m_sParam );
                        }
                        catch( Exception ex )
                        {
                            System.out.println( "Exception in SaveAsMenuItem: " + ex );
                        }
                    }
                }
                else if ( aAction.m_nID == OPEN_FILE )
                {
                    // clear everything
                    clearObjectAndStorage();

                    // load from specified file
                    loadFileURI( aAction.m_sParam );

                    if ( m_xEmbedObj != null )
                    {
                        try {
                            m_xEmbedObj.setClientSite( this );
                        }
                        catch( Exception ex )
                        {
                            System.out.println( "Exception in OpenFileMenuItem: " + ex );
                        }
                    }

                    generateNewImage();
                    repaint();
                }
                else if ( aAction.m_nID == SAVE )
                {
                    if ( m_xStorage != null && m_xEmbedObj != null )
                    {
                        // if has persistence store there
                        // if not it is and error, SaveAs had to be used

                        if ( m_bOwnFile )
                        {
                            if ( m_xStorage != null )
                            {
                                try {
                                    saveObject();

                                    if ( m_bLinkObj )
                                        storeLinkToStorage();

                                    XTransactedObject xTransact = (XTransactedObject)UnoRuntime.queryInterface( XTransactedObject.class,
                                                                                                                m_xStorage );
                                    if ( xTransact != null )
                                        xTransact.commit();
                                }
                                catch( Exception ex )
                                {
                                    System.out.println( "Exception during save operation in SaveMenuItem:" + ex );
                                }
                            }
                            else
                            {
                                System.out.println( "No storage for owned file!" );
                            }
                        }
                        else
                        {
                            System.out.println( "No owned file!" );
                        }
                    }
                }
                else if ( aAction.m_nID == NEW_OBJECT )
                {
                    // remove current object an init a new one
                    clearObjectAndStorage();

                    if ( aAction.m_sParam != null )
                    {
                        m_xStorage = createTempStorage();

                        if ( m_xStorage != null )
                            m_xEmbedObj = createEmbedObject( aAction.m_sParam );
                        else
                            System.out.println( "Can't create temporary storage!" );

                        if ( m_xEmbedObj != null )
                        {
                            try {
                                m_xEmbedObj.setClientSite( this );
                            }
                            catch( Exception ex )
                            {
                                System.out.println( "Exception in NewObjectMenuItem:" + ex );
                            }
                        }
                    }

                    generateNewImage();
                    repaint();
                }
                else if ( aAction.m_nID == OBJECT_FROM_FILE )
                {
                    // first remove current object
                    clearObjectAndStorage();

                    // create object from specified file
                    m_xStorage = createTempStorage();

                    if ( m_xStorage != null )
                        m_xEmbedObj = loadEmbedObject( aAction.m_sParam );

                    if ( m_xEmbedObj != null )
                    {
                        try {
                            m_xEmbedObj.setClientSite( this );
                        }
                        catch( Exception ex )
                        {
                            System.out.println( "Exception in LoadObjectMenuItem: " + ex );
                        }
                    }

                    generateNewImage();
                    repaint();
                }
                else if ( aAction.m_nID == LINK_FROM_FILE )
                {
                    // first remove current object
                    clearObjectAndStorage();

                    m_xStorage = createTempStorage();

                    // create object from specified file
                    m_xEmbedObj = createLinkObject( aAction.m_sParam );

                    if ( m_xEmbedObj != null )
                    {
                        m_aLinkURI = aAction.m_sParam;
                        m_bLinkObj = true;

                        try {
                            m_xEmbedObj.setClientSite( this );
                        }
                        catch( Exception ex )
                        {
                            System.out.println( "Exception in LinkObjectMenuItem:" + ex );
                        }
                    }

                    generateNewImage();
                    repaint();
                }
                else if ( aAction.m_nID == CONVERT_LINK_TO_OBJECT )
                {
                    if ( !m_bLinkObj )
                    {
                        System.out.println( "The object is not a link!" );
                        continue;
                    }

                    if ( m_xEmbedObj != null )
                    {
                        if ( m_xStorage != null )
                        {
                            try {
                                XNameAccess xNameAccess = (XNameAccess)UnoRuntime.queryInterface( XNameAccess.class,
                                                                                                m_xStorage );
                                if ( xNameAccess != null && xNameAccess.hasByName( "LinkName" ) )
                                    m_xStorage.removeElement( "LinkName" );

                                XLinkageSupport xLinkage = (XLinkageSupport)UnoRuntime.queryInterface( XLinkageSupport.class,
                                                                                                        m_xEmbedObj );
                                if ( xLinkage != null )
                                {
                                    xLinkage.breakLink( m_xStorage, "EmbedSub" );
                                    m_bLinkObj = false;
                                    m_aLinkURI = null;
                                }
                                else
                                    System.out.println( "No XLinkageSupport in ConvertLink... !" );
                            }
                            catch( Exception e1 )
                            {
                                System.out.println( "Exception in ConvertLinkToEmbed:try 1 :" + e1 );
                            }
                        }
                    }
                }
                else if ( aAction.m_nID == ACTIVATE_INPLACE )
                {
                    // activate object
                    if ( m_xEmbedObj != null )
                    {
                        // in general it is better to check acceptable states
                        try {
                            m_xEmbedObj.changeState( EmbedStates.EMBED_INPLACE_ACTIVE );
                        }
                        catch( Exception ex )
                        {
                            System.out.println( "Exception on inplace activation " + ex );
                        }
                    }
                }
                else if ( aAction.m_nID == DEACTIVATE )
                {
                    // activate object

                    if ( m_xEmbedObj != null )
                    {
                        int nOldState = -1;
                        try {
                            nOldState = m_xEmbedObj.getCurrentState();
                        } catch( Exception e )
                        {}

                        if ( nOldState == EmbedStates.EMBED_ACTIVE
                          || nOldState == EmbedStates.EMBED_INPLACE_ACTIVE
                          || nOldState == EmbedStates.EMBED_UI_ACTIVE )
                        {
                            try {
                                m_xEmbedObj.changeState( EmbedStates.EMBED_RUNNING );
                            }
                            catch( Exception ex )
                            {
                                System.out.println( "Exception on inplace activation " + ex );
                            }
                        }
                        else
                        {
                            System.out.println( "Deactivation of nonactive object!" );
                        }
                    }
                }
                else
                {
                    System.out.println( "Unknown action is requested: " + aAction.m_nID + "\n" );
                }
            }
        }

        m_aActionsList.clear();

        synchronized( m_oInHandlerLock )
        {
            m_bInHandler = false;
        }

        return Any.VOID;
    }

    public void actionRegister( byte nActionID, String sParam )
    {
        synchronized( m_oActionsNumberLock )
        {
            int nSize = m_aActionsList.size();
            if ( nSize < 199 )
            {
                if ( nSize == 0 )
                    m_aActionsList.add( new ActionObject( nActionID, sParam ) );
                else
                {
                    ActionObject aAction = m_aActionsList.get( nSize - 1 );
                    if ( aAction != null && aAction.m_nID != DESTROY )
                        m_aActionsList.add( new ActionObject( nActionID, sParam ) );
                }
            }
        }
    }

    public void SaveAsOperation()
    {
        if ( m_xStorage != null && m_xEmbedObj != null )
        {
            FileDialog aFileDialog = new FileDialog( m_aFrame, "SaveAs", FileDialog.SAVE );
            aFileDialog.show();
            if ( aFileDialog.getFile() != null )
            {
                String aFileName = aFileDialog.getDirectory() + aFileDialog.getFile();
                File aFile = new File( aFileName );
                if ( aFile != null )
                {
                    // create object from specified file
                    String aFileURI = getValidURL( aFile.toURI().toASCIIString() );
                    actionRegister( SAVE_AS, aFileURI );
                }
            }
        }
        else
            JOptionPane.showMessageDialog( m_aFrame, "No document is embedded!", "Error:", JOptionPane.ERROR_MESSAGE );

    }

    public void destroy()
    {
        // redirect the call through the timer and call super.destroy();
        actionRegister( DESTROY, null );

        for ( int i = 0; i < 3 && !m_bDestroyed; i++ )
        {
            try {
                Thread.sleep( 200 );
            } catch ( Exception e )
            {}
        }

        if ( !m_bDestroyed )
            System.out.println( "The object application can not exit correctly!" );

        m_aTimer.stop();

        super.destroy();
    }

    public void update( Graphics g )
    {
        paint( g );
    }

    public void paint( Graphics g )
    {
        super.paint( g );

        createVclWindow();
    }

    public void createVclWindow()
    {
        synchronized( m_oImageLock )
        {
            if ( m_xVCLWindow == null && m_xServiceFactory != null && m_xEmbedObj != null && m_xBitmap != null )
            {
                java.awt.Rectangle aBounds = getBounds();
                m_xVCLWindow = WindowHelper.createWindow( m_xServiceFactory, m_aNativeView, aBounds );
                m_xVCLWindow.setVisible( true );

                com.sun.star.awt.Size aBitmapSize = new com.sun.star.awt.Size( 200, 100 );

                XVisualObject xVisObj = (XVisualObject)UnoRuntime.queryInterface( XVisualObject.class, m_xEmbedObj );
                try {
                    com.sun.star.awt.Size aVisSize = xVisObj.getVisAreaSize( Aspects.MSASPECT_CONTENT );
                    m_nXPixelSize = aVisSize.Width / aBitmapSize.Width;
                    m_nYPixelSize = aVisSize.Height / aBitmapSize.Height;
                }
                catch( Exception e )
                {
                }

                if ( m_xBitmap != null )
                     aBitmapSize = m_xBitmap.getSize();

                System.out.println( "The visual area is Width = " + aBitmapSize.Width + "; Height = " + aBitmapSize.Height );

                com.sun.star.awt.Rectangle aRect = new com.sun.star.awt.Rectangle(
                                                        10,
                                                        10,
                                                        Math.min( (int)aBounds.getWidth() - 20, aBitmapSize.Width ),
                                                        Math.min( (int)aBounds.getHeight() - 20, aBitmapSize.Height ) );

                m_aBitmapPainter = new BitmapPainter( m_xMainThreadExecutor, m_xVCLWindow, m_xBitmap, aRect );
            }
        }
    }

    public void generateNewImage()
    {
        if ( m_xEmbedObj != null )
        {
            try {
                int nOldState = m_xEmbedObj.getCurrentState();
                int nState = nOldState;
                if ( nOldState == EmbedStates.EMBED_LOADED )
                {
                    m_xEmbedObj.changeState( EmbedStates.EMBED_RUNNING );
                    nState = EmbedStates.EMBED_RUNNING;
                }

                if ( nState == EmbedStates.EMBED_UI_ACTIVE || nState == EmbedStates.EMBED_INPLACE_ACTIVE
                  || nState == EmbedStates.EMBED_ACTIVE || nState == EmbedStates.EMBED_RUNNING )
                {
                    XComponentSupplier xCompProv = (XComponentSupplier)UnoRuntime.queryInterface(
                                                                                    XComponentSupplier.class,
                                                                                    m_xEmbedObj );
                    if ( xCompProv != null )
                    {
                        XCloseable xCloseable = xCompProv.getComponent();
                        XTransferable xTransfer = (XTransferable)UnoRuntime.queryInterface(
                                                                                    XTransferable.class,
                                                                                    xCloseable );
                        if ( xTransfer != null )
                        {
                            DataFlavor aFlavor = new DataFlavor();
                            aFlavor.MimeType = "application/x-openoffice;windows_formatname=\"Bitmap\"";
                            aFlavor.HumanPresentableName = "Bitmap";
                            aFlavor.DataType = new Type( byte[].class );

                            Object aAny = xTransfer.getTransferData( aFlavor );
                            if ( aAny != null && AnyConverter.isArray( aAny ) )
                            {
                                synchronized( m_oImageLock )
                                {
                                    m_xBitmap = WindowHelper.getVCLBitmapFromBytes( m_xServiceFactory, aAny );
                                    if ( m_aBitmapPainter != null )
                                    {
                                        m_aBitmapPainter.setBitmap( m_xBitmap );

                                        if ( m_xBitmap != null )
                                        {
                                            try {
                                                com.sun.star.awt.Size aBitmapSize = m_xBitmap.getSize();
                                                com.sun.star.awt.Size aVisSize = new com.sun.star.awt.Size(
                                                                                (int)( aBitmapSize.Width * m_nXScaling ),
                                                                                (int)( aBitmapSize.Height * m_nYScaling ) );
                                                m_aBitmapPainter.setSize( aVisSize );
                                            }
                                            catch( Exception e )
                                            {
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else
                            System.out.println( "paint() : can not get XTransferable for the component!\n" );
                    }
                    else
                        System.out.println( "paint() : XComponentSupplier is not implemented!\n" );
                }
            }
            catch( com.sun.star.uno.Exception e )
            {
                // dialogs should not be used in paint()
                System.out.println( "Exception in paint(): " + e );
            }
        }
    }

    public void mouseClicked( MouseEvent e )
    {
        if( e.getModifiers() == InputEvent.BUTTON1_MASK )
        {
            actionRegister( ACTIVATE_OUTPLACE, null );
        }
    }

    public void mousePressed( MouseEvent e ){};
    public void mouseEntered( MouseEvent e ){};
    public void mouseExited( MouseEvent e ){};
    public void mouseReleased( MouseEvent e ){};

    class NewMenuItem extends MenuItem implements ActionListener // Menu New
    {
        public NewMenuItem()
        {
            super( "New", new MenuShortcut( KeyEvent.VK_A ));
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            actionRegister( NEW_DOCUMENT, null );
        }
    }

    class SaveAsMenuItem extends MenuItem implements ActionListener // Menu SaveAs...
    {
        public SaveAsMenuItem()
        {
            super( "SaveAs..." );
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            // open SaveAs dialog and store

            SaveAsOperation();
        }
    }

    class OpenFileMenuItem extends MenuItem implements ActionListener // Menu Open
    {
        public OpenFileMenuItem()
        {
            super( "Open", new MenuShortcut( KeyEvent.VK_C ));
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            // open OpenFile dialog and load doc
            FileDialog aFileDialog = new FileDialog( m_aFrame, "Open" );
            aFileDialog.show();
            if ( aFileDialog.getFile() != null )
            {
                String aFileName = aFileDialog.getDirectory() + aFileDialog.getFile();
                File aFile = new File( aFileName );
                if ( aFile != null )
                {
                    // create object from specified file
                    String aFileURI = getValidURL( aFile.toURI().toASCIIString() );
                    actionRegister( OPEN_FILE, aFileURI );
                }
            }
        }
    }

    class SaveMenuItem extends MenuItem implements ActionListener // Menu Save
    {
        public SaveMenuItem()
        {
            super( "Save", new MenuShortcut( KeyEvent.VK_D ));
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            // if has persistence store there
            // if not open SaveAs dialog and store
            if ( m_xStorage != null && m_xEmbedObj != null )
            {
                if ( m_bOwnFile )
                {
                    if ( m_xStorage == null )
                    {
                        JOptionPane.showMessageDialog( m_aFrame,
                                                        "No storage for owned file!",
                                                        "Error:",
                                                        JOptionPane.ERROR_MESSAGE );

                        return;
                    }

                    actionRegister( SAVE, null );
                }
                else
                {
                    SaveAsOperation();
                }
            }
            else
                JOptionPane.showMessageDialog( m_aFrame, "No document is embedded!", "Error:", JOptionPane.ERROR_MESSAGE );
        }
    }

    class NewObjectMenuItem extends MenuItem implements ActionListener // Menu NewObject
    {
        public NewObjectMenuItem()
        {
            super( "Create", new MenuShortcut( KeyEvent.VK_N ));
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            Object[] possibleValues = { "com.sun.star.comp.Writer.TextDocument",
                                        "com.sun.star.comp.Writer.GlobalDocument",
                                        "com.sun.star.comp.Writer.WebDocument",
                                        "com.sun.star.comp.Calc.SpreadsheetDocument",
                                        "com.sun.star.comp.Draw.PresentationDocument",
                                        "com.sun.star.comp.Draw.DrawingDocument",
                                        "com.sun.star.comp.Math.FormulaDocument",
                                        "BitmapImage" };

            String selectedValue = (String)JOptionPane.showInputDialog( null, "DocumentType", "Select",
                                                                           JOptionPane.INFORMATION_MESSAGE, null,
                                                                           possibleValues, possibleValues[0] );

            actionRegister( NEW_OBJECT, selectedValue );
        }
    }

    class LoadObjectMenuItem extends MenuItem implements ActionListener // Menu LoadObject
    {
        public LoadObjectMenuItem()
        {
            super( "Load from file", new MenuShortcut( KeyEvent.VK_L ));
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            // open OpenFile dialog and load doc
            FileDialog aFileDialog = new FileDialog( m_aFrame, "Select sources to use for object init" );
            aFileDialog.show();
            if ( aFileDialog.getFile() != null )
            {
                String aFileName = aFileDialog.getDirectory() + aFileDialog.getFile();
                File aFile = new File( aFileName );
                if ( aFile != null )
                {
                    // create object from specified file
                    String aFileURI = getValidURL( aFile.toURI().toASCIIString() );
                    actionRegister( OBJECT_FROM_FILE, aFileURI );
                }
            }
        }
    }

    class LinkObjectMenuItem extends MenuItem implements ActionListener // Menu LinkObject
    {
        public LinkObjectMenuItem()
        {
            super( "Create link", new MenuShortcut( KeyEvent.VK_M ));
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            // open OpenFile dialog and load doc
            FileDialog aFileDialog = new FileDialog( m_aFrame, "Select sources to use for object init" );
            aFileDialog.show();
            if ( aFileDialog.getFile() != null )
            {
                String aFileName = aFileDialog.getDirectory() + aFileDialog.getFile();
                File aFile = new File( aFileName );
                if ( aFile != null )
                {
                    // create object from specified file
                    String aFileURI = getValidURL( aFile.toURI().toASCIIString() );
                    actionRegister( LINK_FROM_FILE, aFileURI );
                }
            }
        }
    }

    class ConvertLinkToEmbedMenuItem extends MenuItem implements ActionListener // Menu LinkObject
    {
        public ConvertLinkToEmbedMenuItem()
        {
            super( "Convert link to embed", new MenuShortcut( KeyEvent.VK_M ));
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            actionRegister( CONVERT_LINK_TO_OBJECT, null );
        }
    }

    class ActivateOutplaceMenuItem extends MenuItem implements ActionListener // Menu ActiveteOutplace
    {
        public ActivateOutplaceMenuItem()
        {
            super( "Activate outplace", new MenuShortcut( KeyEvent.VK_A ));
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            actionRegister( ACTIVATE_OUTPLACE, null );
        }
    }

    class ActivateInplaceMenuItem extends MenuItem implements ActionListener // Menu ActivateInplace
    {
        public ActivateInplaceMenuItem()
        {
            super( "Activate inplace", new MenuShortcut( KeyEvent.VK_I ));
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            actionRegister( ACTIVATE_INPLACE, null );
        }
    }

    class DeactivateMenuItem extends MenuItem implements ActionListener // Menu Deactivate
    {
        public DeactivateMenuItem()
        {
            super( "Deactivate", new MenuShortcut( KeyEvent.VK_D ));
            addActionListener( this );
        }

        public void actionPerformed( ActionEvent e )
        {
            actionRegister( DEACTIVATE, null );
        }
    }

    // Helper methods
    public XEmbeddedObject createEmbedObject( String aServiceName )
    {
        XEmbeddedObject xEmbObj = null;
        byte[] pClassID = new byte[16];

        if ( aServiceName.equals( "com.sun.star.comp.Writer.TextDocument" ) )
        {
            int[] pTempClassID = { 0x8B, 0xC6, 0xB1, 0x65, 0xB1, 0xB2, 0x4E, 0xDD,
                                    0xAA, 0x47, 0xDA, 0xE2, 0xEE, 0x68, 0x9D, 0xD6 };
            for ( int ind = 0; ind < 16; ind++ )
                pClassID[ind] = (byte)pTempClassID[ind];
        }
        else if ( aServiceName.equals( "com.sun.star.comp.Writer.GlobalDocument" ) )
        {
            int[] pTempClassID = { 0xB2, 0x1A, 0x0A, 0x7C, 0xE4, 0x03, 0x41, 0xFE,
                                    0x95, 0x62, 0xBD, 0x13, 0xEA, 0x6F, 0x15, 0xA0 };
            for ( int ind = 0; ind < 16; ind++ )
                pClassID[ind] = (byte)pTempClassID[ind];
        }
        else if ( aServiceName.equals( "com.sun.star.comp.Writer.WebDocument" ) )
        {
            int[] pTempClassID = { 0xA8, 0xBB, 0xA6, 0x0C, 0x7C, 0x60, 0x45, 0x50,
                                    0x91, 0xCE, 0x39, 0xC3, 0x90, 0x3F, 0xAC, 0x5E };
            for ( int ind = 0; ind < 16; ind++ )
                pClassID[ind] = (byte)pTempClassID[ind];
        }
        else if ( aServiceName.equals( "com.sun.star.comp.Calc.SpreadsheetDocument" ) )
        {
            int[] pTempClassID = { 0x47, 0xBB, 0xB4, 0xCB, 0xCE, 0x4C, 0x4E, 0x80,
                                    0xA5, 0x91, 0x42, 0xD9, 0xAE, 0x74, 0x95, 0x0F };
            for ( int ind = 0; ind < 16; ind++ )
                pClassID[ind] = (byte)pTempClassID[ind];
        }
        else if ( aServiceName.equals( "com.sun.star.comp.Draw.PresentationDocument" ) )
        {
            int[] pTempClassID = { 0x91, 0x76, 0xE4, 0x8A, 0x63, 0x7A, 0x4D, 0x1F,
                                    0x80, 0x3B, 0x99, 0xD9, 0xBF, 0xAC, 0x10, 0x47 };
            for ( int ind = 0; ind < 16; ind++ )
                pClassID[ind] = (byte)pTempClassID[ind];
        }
        else if ( aServiceName.equals( "com.sun.star.comp.Draw.DrawingDocument" ) )
        {
            int[] pTempClassID = { 0x4B, 0xAB, 0x89, 0x70, 0x8A, 0x3B, 0x45, 0xB3,
                                    0x99, 0x1C, 0xCB, 0xEE, 0xAC, 0x6B, 0xD5, 0xE3 };
            for ( int ind = 0; ind < 16; ind++ )
                pClassID[ind] = (byte)pTempClassID[ind];
        }
        else if ( aServiceName.equals( "com.sun.star.comp.Math.FormulaDocument" ) )
        {
            int[] pTempClassID = { 0x07, 0x8B, 0x7A, 0xBA, 0x54, 0xFC, 0x45, 0x7F,
                                    0x85, 0x51, 0x61, 0x47, 0xE7, 0x76, 0xA9, 0x97 };
            for ( int ind = 0; ind < 16; ind++ )
                pClassID[ind] = (byte)pTempClassID[ind];
        }
        else if ( aServiceName.equals( "BitmapImage" ) )
        {
            int[] pTempClassID = { 0xD3, 0xE3, 0x4B, 0x21, 0x9D, 0x75, 0x10, 0x1A,
                                    0x8C, 0x3D, 0x00, 0xAA, 0x00, 0x1A, 0x16, 0x52 };
            for ( int ind = 0; ind < 16; ind++ )
                pClassID[ind] = (byte)pTempClassID[ind];
        }

        if ( pClassID != null )
        {
            // create embedded object based on the class ID
            try {
                Object oEmbedCreator = m_xServiceFactory.createInstance( "com.sun.star.embed.EmbeddedObjectCreator" );
                XEmbedObjectCreator xEmbedCreator = (XEmbedObjectCreator)UnoRuntime.queryInterface(
                                                                                        XEmbedObjectCreator.class,
                                                                                        oEmbedCreator );
                if ( xEmbedCreator != null )
                {
                    Object oEmbObj = xEmbedCreator.createInstanceInitNew( pClassID,
                                                                        "Dummy name",
                                                                        m_xStorage,
                                                                        "EmbedSub",
                                                                        new PropertyValue[0] );
                    xEmbObj = (XEmbeddedObject)UnoRuntime.queryInterface( XEmbeddedObject.class, oEmbObj );
                }
                else
                    JOptionPane.showMessageDialog( m_aFrame,
                                                   "Can't create EmbedCreator!",
                                                   "Error:",
                                                   JOptionPane.ERROR_MESSAGE );
            }
            catch( Exception e )
            {
                JOptionPane.showMessageDialog( m_aFrame, e, "Exception in createInstanceInitNew():", JOptionPane.ERROR_MESSAGE );
            }
        }
        else
            JOptionPane.showMessageDialog( m_aFrame, "Can't retrieve class ID!", "Error:", JOptionPane.ERROR_MESSAGE );

        return xEmbObj;
    }

    public XEmbeddedObject createLinkObject( String aLinkURL )
    {
        XEmbeddedObject xEmbObj = null;

        try {
            Object oLinkCreator = m_xServiceFactory.createInstance( "com.sun.star.embed.EmbeddedObjectCreator" );
            XLinkCreator xLinkCreator = (XLinkCreator)UnoRuntime.queryInterface(
                                                                                    XLinkCreator.class,
                                                                                    oLinkCreator );
            if ( xLinkCreator != null )
            {
                PropertyValue[] aMedDescr = { new PropertyValue(), new PropertyValue() };
                aMedDescr[0].Name = "URL";
                aMedDescr[0].Value = (Object) aLinkURL;
                aMedDescr[1].Name = "ReadOnly";
                aMedDescr[1].Value = (Object) Boolean.FALSE;
                Object oEmbObj = xLinkCreator.createInstanceLink( m_xStorage, "EmbedSub", aMedDescr, new PropertyValue[0] );
                xEmbObj = (XEmbeddedObject)UnoRuntime.queryInterface( XEmbeddedObject.class, oEmbObj );
            }
            else
                JOptionPane.showMessageDialog( m_aFrame,
                                               "Can't create LinkCreator!",
                                               "Error:",
                                               JOptionPane.ERROR_MESSAGE );
        }
        catch( Exception e )
        {
            JOptionPane.showMessageDialog( m_aFrame, e, "Exception in createLinkObject():", JOptionPane.ERROR_MESSAGE );
        }


        return xEmbObj;
    }


    public XEmbeddedObject loadEmbedObject( String aFileURI )
    {
        XEmbeddedObject xEmbObj = null;
        try {
            Object oEmbedCreator = m_xServiceFactory.createInstance( "com.sun.star.embed.EmbeddedObjectCreator" );
            XEmbedObjectCreator xEmbedCreator = (XEmbedObjectCreator)UnoRuntime.queryInterface(
                                                                                    XEmbedObjectCreator.class,
                                                                                    oEmbedCreator );
            if ( xEmbedCreator != null )
            {
                PropertyValue[] aMedDescr = { new PropertyValue(), new PropertyValue() };
                aMedDescr[0].Name = "URL";
                aMedDescr[0].Value = (Object) aFileURI;
                aMedDescr[1].Name = "ReadOnly";
                aMedDescr[1].Value = (Object) Boolean.FALSE;
                Object oEmbObj = xEmbedCreator.createInstanceInitFromMediaDescriptor( m_xStorage,
                                                                                    "EmbedSub",
                                                                                    aMedDescr,
                                                                                    new PropertyValue[0] );
                xEmbObj = (XEmbeddedObject)UnoRuntime.queryInterface( XEmbeddedObject.class, oEmbObj );
            }
            else
                JOptionPane.showMessageDialog( m_aFrame,
                                               "Can't create EmbedFactory!",
                                               "Error:",
                                               JOptionPane.ERROR_MESSAGE );
        }
        catch( Exception e )
        {
            JOptionPane.showMessageDialog( m_aFrame, e, "Exception in loadEmbedObject():", JOptionPane.ERROR_MESSAGE );
        }

        return xEmbObj;
    }

    public void clearObjectAndStorage()
    {
        synchronized( m_oImageLock )
        {
            m_aImage = null;
        }

        m_nXScaling = 1;
        m_nYScaling = 1;
        m_nXPixelSize = 1;
        m_nYPixelSize = 1;

        m_bOwnFile = false;

        m_aLinkURI = null;
        m_bLinkObj = false;

        if ( m_xEmbedObj != null )
        {
            try {
                XCloseable xClose = (XCloseable)UnoRuntime.queryInterface( XCloseable.class, m_xEmbedObj );
                if ( xClose != null )
                    xClose.close( true );
            }
            catch ( Exception ex )
            {}
            m_xEmbedObj = null;
        }

        if ( m_xStorage != null )
        {
            try {
                XComponent xComponent = (XComponent)UnoRuntime.queryInterface( XComponent.class, m_xStorage );
                if ( xComponent != null )
                    xComponent.dispose();
            }
            catch ( Exception ex )
            {}
            m_xStorage = null;
        }
    }

    public XStorage createTempStorage()
    {
        XStorage xTempStorage = null;

        try {
            Object oStorageFactory = m_xServiceFactory.createInstance( "com.sun.star.embed.StorageFactory" );
            XSingleServiceFactory xStorageFactory = (XSingleServiceFactory)UnoRuntime.queryInterface(
                                                                                        XSingleServiceFactory.class,
                                                                                        oStorageFactory );
            if ( xStorageFactory != null )
            {
                Object oStorage = xStorageFactory.createInstance();
                xTempStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oStorage );
            }
            else
                JOptionPane.showMessageDialog( m_aFrame,
                                                "Can't create StorageFactory!",
                                                "Error:",
                                                JOptionPane.ERROR_MESSAGE );
        }
        catch( Exception e )
        {
            JOptionPane.showMessageDialog( m_aFrame, e, "Exception in createTempStorage():", JOptionPane.ERROR_MESSAGE );
        }

        return xTempStorage;
    }

    public void saveObjectAsFileURI( String aFileURI )
    {
        try {
            Object oStorageFactory = m_xServiceFactory.createInstance( "com.sun.star.embed.StorageFactory" );
            XSingleServiceFactory xStorageFactory = (XSingleServiceFactory)UnoRuntime.queryInterface(
                                                                                        XSingleServiceFactory.class,
                                                                                        oStorageFactory );
            if ( xStorageFactory != null )
            {
                XEmbedPersist xPersist = (XEmbedPersist)UnoRuntime.queryInterface( XEmbedPersist.class, m_xEmbedObj );
                if ( xPersist != null )
                {
                    Object aArgs[] = new Object[2];
                    aArgs[0] = aFileURI;
                    aArgs[1] = Integer.valueOf( ElementModes.ELEMENT_READWRITE );

                    Object oStorage = xStorageFactory.createInstanceWithArguments( aArgs );
                    XStorage xTargetStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oStorage );

                    PropertyValue aProps[] = { new PropertyValue() };
                    aProps[0].Name = "StoreVisualReplacement";
                    aProps[0].Value = Boolean.valueOf( m_bStoreVisRepl );

                    xPersist.storeAsEntry( xTargetStorage, "EmbedSub", new PropertyValue[0], aProps );
                    xPersist.saveCompleted( true );

                    // the object must be already based on new storage
                    XComponent xComponent = (XComponent)UnoRuntime.queryInterface( XComponent.class, m_xStorage );
                    xComponent.dispose();

                    m_xStorage = xTargetStorage;
                    m_bOwnFile = true;

                    XTransactedObject xTransact = (XTransactedObject)UnoRuntime.queryInterface( XTransactedObject.class,
                                                                                            m_xStorage );
                    if ( xTransact != null )
                        xTransact.commit();
                }
                else
                    JOptionPane.showMessageDialog( m_aFrame, "No XEmbedPersist!", "Error:", JOptionPane.ERROR_MESSAGE );
            }
            else
                JOptionPane.showMessageDialog( m_aFrame,
                                                "Can't create StorageFactory!",
                                                "Error:",
                                                JOptionPane.ERROR_MESSAGE );
        }
        catch( Exception e )
        {
            JOptionPane.showMessageDialog( m_aFrame, e, "Exception in saveStorageToFileURI():", JOptionPane.ERROR_MESSAGE );
        }

    }

    public void loadFileURI( String aFileURI )
    {
        try
        {
            Object oStorageFactory = m_xServiceFactory.createInstance( "com.sun.star.embed.StorageFactory" );
            XSingleServiceFactory xStorageFactory = (XSingleServiceFactory)UnoRuntime.queryInterface(
                                                                                        XSingleServiceFactory.class,
                                                                                        oStorageFactory );
            Object aArgs[] = new Object[2];
            aArgs[0] = aFileURI;
            aArgs[1] = Integer.valueOf( ElementModes.ELEMENT_READWRITE );

            Object oStorage = xStorageFactory.createInstanceWithArguments( aArgs );
            XStorage xTargetStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oStorage );

            Object oEmbedCreator = m_xServiceFactory.createInstance( "com.sun.star.embed.EmbeddedObjectCreator" );
            XEmbedObjectCreator xEmbedCreator = (XEmbedObjectCreator)UnoRuntime.queryInterface(
                                                                                    XEmbedObjectCreator.class,
                                                                                    oEmbedCreator );

            XNameAccess xNameAccess = (XNameAccess)UnoRuntime.queryInterface( XNameAccess.class,
                                                                            xTargetStorage );
            if ( xNameAccess == null )
            {
                JOptionPane.showMessageDialog( m_aFrame, "No XNameAccess!", "Error:", JOptionPane.ERROR_MESSAGE );
                return;
            }

            Object oEmbObj = null;
            if ( xNameAccess.hasByName( "LinkName" ) && xTargetStorage.isStreamElement( "LinkName" ) )
            {
            }
            else
                oEmbObj = xEmbedCreator.createInstanceInitFromEntry( xTargetStorage,
                                                                    "EmbedSub",
                                                                    false,
                                                                    new PropertyValue[0] );

            m_xEmbedObj = (XEmbeddedObject)UnoRuntime.queryInterface( XEmbeddedObject.class, oEmbObj );

            if ( m_xEmbedObj != null )
            {
                m_xStorage = xTargetStorage;
                m_bOwnFile = true;
            }
            else
                JOptionPane.showMessageDialog( m_aFrame,
                                               "Can't create EmbedObject from storage!",
                                               "Error:",
                                               JOptionPane.ERROR_MESSAGE );
        }
        catch( Exception e )
        {
            JOptionPane.showMessageDialog( m_aFrame, e, "Exception in loadFileURI():", JOptionPane.ERROR_MESSAGE );
        }
    }

    public void storeLinkToStorage()
    {
        if ( m_xStorage != null && m_bLinkObj )
        {
            try {
                XStream xLinkStream = m_xStorage.openStreamElement( "LinkName", ElementModes.ELEMENT_WRITE );

                if ( xLinkStream != null )
                {
                    XOutputStream xLinkOutStream = xLinkStream.getOutputStream();
                    XTruncate xTruncate = (XTruncate) UnoRuntime.queryInterface( XTruncate.class,
                                                                                 xLinkOutStream );
                    if ( xLinkOutStream != null && xTruncate != null )
                    {
                        xTruncate.truncate();

                        char[] aLinkChar = m_aLinkURI.toCharArray();
                        byte[] aLinkBytes = new byte[ aLinkChar.length ];
                        for ( int ind = 0; ind < aLinkChar.length; ind++ )
                            aLinkBytes[ind] = (byte)aLinkChar[ind];

                        xLinkOutStream.writeBytes( aLinkBytes );
                        xLinkOutStream.closeOutput();

                        XComponent xComponent = (XComponent) UnoRuntime.queryInterface( XComponent.class,
                                                                                        xLinkStream );
                        if ( xComponent != null )
                            xComponent.dispose();
                    }
                    else
                        JOptionPane.showMessageDialog( m_aFrame,
                                                        "The substream can not be truncated or written!",
                                                        "Error:",
                                                        JOptionPane.ERROR_MESSAGE );

                }
                else
                    JOptionPane.showMessageDialog( m_aFrame,
                                                    "Can't create/open substream!",
                                                    "Error:",
                                                    JOptionPane.ERROR_MESSAGE );
            }
            catch( Exception e )
            {
                JOptionPane.showMessageDialog( m_aFrame,
                                            e,
                                            "Exception in storeLinkToStorage:",
                                            JOptionPane.ERROR_MESSAGE );

            }
        }
    }

    public void storeLinkAsFileURI( String aFileURI )
    {
        try {
            Object oStorageFactory = m_xServiceFactory.createInstance( "com.sun.star.embed.StorageFactory" );
            XSingleServiceFactory xStorageFactory = (XSingleServiceFactory)UnoRuntime.queryInterface(
                                                                                        XSingleServiceFactory.class,
                                                                                        oStorageFactory );
            if ( xStorageFactory != null )
            {
                Object aArgs[] = new Object[2];
                aArgs[0] = aFileURI;
                aArgs[1] = Integer.valueOf( ElementModes.ELEMENT_READWRITE );

                Object oStorage = xStorageFactory.createInstanceWithArguments( aArgs );
                XStorage xTargetStorage = (XStorage)UnoRuntime.queryInterface( XStorage.class, oStorage );

                XComponent xComponent = (XComponent)UnoRuntime.queryInterface( XComponent.class, m_xStorage );
                xComponent.dispose();

                m_xStorage = xTargetStorage;
                m_bOwnFile = true;

                storeLinkToStorage();

                XTransactedObject xTransact = (XTransactedObject)UnoRuntime.queryInterface( XTransactedObject.class,
                                                                                            m_xStorage );
                if ( xTransact != null )
                    xTransact.commit();
            }
            else
                JOptionPane.showMessageDialog( m_aFrame,
                                                "Can't create StorageFactory!",
                                                "Error:",
                                                JOptionPane.ERROR_MESSAGE );
        }
        catch( Exception e )
        {
            JOptionPane.showMessageDialog( m_aFrame, e, "Exception in saveStorageToFileURI():", JOptionPane.ERROR_MESSAGE );
        }
    }

    public String getValidURL( String sFileURL )
    {
        // m_xTransformer must be set!
        URL[] aURLs = { new URL() };
        aURLs[0].Complete = sFileURL;

        try {
            if ( !m_xTransformer.parseSmart( aURLs, "" ) )
                throw new Exception();
        }
        catch( Exception e )
        {
            JOptionPane.showMessageDialog( m_aFrame, e, "Exception in getValidURL():", JOptionPane.ERROR_MESSAGE );
        }

        return aURLs[0].Complete;
    }

    public void disposeObject()
    {
        // TODO:
        // usage of object, storage and bitmap painter should be locked
        // but since possibility of race condition is very low
        // it is not really required for testing application

        clearObjectAndStorage();

        if ( m_aBitmapPainter != null )
        {
            m_aBitmapPainter.disconnectListener();
            m_aBitmapPainter = null;
        }
    }
}