blob: c20499e492adcc16f7471e7234412e44e9a75d3a [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// __________ Imports __________
import com.sun.star.uno.UnoRuntime;
import java.lang.String;
import java.awt.Component;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import java.util.Vector;
// __________ 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. Otherwhise 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 automaticly.
*
* Another reason for such extra class for listening:
* Most listener callbacks are asynchronoues [oneay] requests.
* And it's not allowed to call back synchronously there.
* So we must start threads for updating something internaly.
*
* @author Andreas Schlüns
* @created 15.07.2002 12:36
*/
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 neccessary 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 then one way to finish an object of this class - we must know it sometimes
*/
private Component m_rControl ;
private String m_sTrueText ;
private 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 sett all neccessary informations 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 realy.
* 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 automaticly. 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 everytime.
*/
public void startListening()
{
com.sun.star.frame.XFrame xFrame = null;
synchronized(this)
{
if (m_bDead)
return;
if (m_xFrame==null)
return;
if (m_bIsActionListener==true)
return;
xFrame = m_xFrame;
}
xFrame.addFrameActionListener(this);
synchronized(this)
{
m_bIsActionListener=true;
}
}
//_____________________
/**
* In case we got an 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
* funtionality.
*
* @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*/ Vector lParams )
{
synchronized(this)
{
if (m_bDead)
return;
}
// was it frameAction()?
if (nRequest==OnewayExecutor.REQUEST_FRAMEACTION)
{
com.sun.star.frame.FrameActionEvent[] lOutAction = new com.sun.star.frame.FrameActionEvent[1];
Vector[] lInParams = new Vector[1];
lInParams[0] = lParams;
OnewayExecutor.codeFrameAction( OnewayExecutor.DECODE_PARAMS ,
lInParams ,
lOutAction );
impl_frameAction(lOutAction[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 neccessary things there.
* But we shouldn't start such action - if it's not realy neccessary.
* So we check before, if we are intereested on this event realy.
*
* @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;
Vector[] lOutParams = new Vector[1];
com.sun.star.frame.FrameActionEvent[] lInAction = new com.sun.star.frame.FrameActionEvent[1];
lInAction[0] = aEvent;
OnewayExecutor.codeFrameAction( OnewayExecutor.ENCODE_PARAMS ,
lOutParams ,
lInAction );
OnewayExecutor aExecutor = new OnewayExecutor( (IOnewayLink)this ,
OnewayExecutor.REQUEST_FRAMEACTION ,
lOutParams[0] );
aExecutor.start();
}
//_____________________
/**
* This is the callback method for the status we listen for an wish to show it
* on our UI control. Of yourse it's a oneway method ... but we doesn'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 neccessary 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/dsiable th control.
// Means: If the feature isn't available currently - we can't show an status realy 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 ofthe 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. Otherwhise 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 realy 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
*/
public 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 everytime - but registration only, if neccessary!
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 = (com.sun.star.frame.XDispatchProvider)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 neccessary to
* remove listener connections here. Because the broadcaster
* forget us automaticly. 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. Otherwhise
* 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. Otherwhise 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 ;
}
}