1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // __________ Imports __________ 25 26 import com.sun.star.uno.UnoRuntime; 27 28 import java.lang.String; 29 import java.awt.Component; 30 import javax.swing.JCheckBox; 31 import javax.swing.JLabel; 32 import java.util.Vector; 33 34 // __________ Implementation __________ 35 36 /** 37 * reacts for status events we listen for 38 * We listen for status events to update our UI. 39 * To know which event must be used for which UI control 40 * we use a special class to do that. Otherwhise we have 41 * to guess it ... 42 * 43 * Further we are frame action listener too. 44 * So we can update our status listener connections and 45 * internal holded dispatch object automaticly. 46 * 47 * Another reason for such extra class for listening: 48 * Most listener callbacks are asynchronoues [oneay] requests. 49 * And it's not allowed to call back synchronously there. 50 * So we must start threads for updating something internaly. 51 * 52 * @author Andreas Schlüns 53 * @created 15.07.2002 12:36 54 */ 55 class StatusListener implements com.sun.star.frame.XStatusListener, 56 com.sun.star.frame.XFrameActionListener, 57 IShutdownListener, 58 IOnewayLink 59 { 60 //_____________________ 61 62 /** 63 * @member m_rControl reference to the UI control, which should be updated 64 * @member m_sTrueText this text will be shown at the used UI control as description for an enabled status 65 * @member m_sFalseText this text will be shown at the used UI control as description for an disabled status 66 * @member m_xDispatch if we listen for status events, we must hold the dispatch object alive! 67 * @member m_xFrame reference to the frame, which can provide new dispatch objects if it's neccessary to update it 68 * @member m_aURL and of course we must be registered for a special URL 69 * @member m_bIsActionListener indicates if we are currently registered as a listener for frame action events or not 70 * @member m_bIsStatusListener indicates if we are currently registered as a listener for status events or not 71 * @member m_bDead there exist more then one way to finish an object of this class - we must know it sometimes 72 */ 73 private Component m_rControl ; 74 private String m_sTrueText ; 75 private String m_sFalseText ; 76 private com.sun.star.frame.XDispatch m_xDispatch ; 77 private com.sun.star.frame.XFrame m_xFrame ; 78 private com.sun.star.util.URL m_aURL ; 79 private boolean m_bIsActionListener; 80 private boolean m_bIsStatusListener; 81 private boolean m_bDead ; 82 83 //_____________________ 84 85 /** 86 * ctor 87 * It initialize an instance of this class only. 88 * We sett all neccessary informations on our internal member - that's it 89 */ 90 StatusListener( /*IN*/ Component rControl , 91 /*IN*/ String sTrueText , 92 /*IN*/ String sFalseText , 93 /*IN*/ com.sun.star.frame.XFrame xFrame , 94 /*IN*/ String sURL ) 95 { 96 m_rControl = rControl ; 97 m_sTrueText = sTrueText ; 98 m_sFalseText = sFalseText ; 99 m_xFrame = xFrame ; 100 m_bIsStatusListener = false ; 101 m_bIsActionListener = false ; 102 m_bDead = false ; 103 // to be perform - we parse the given URL one times only 104 // and use it till we die ... 105 m_aURL = FunctionHelper.parseURL(sURL); 106 } 107 108 //_____________________ 109 110 /** 111 * start working as frame action listener realy. 112 * In case we get such frame action, it indicates that we should 113 * update our internal saved dispatch object on which we listen 114 * for status events. So we can do it automaticly. The outside code 115 * mustn't check such things. We can work with one frame, 116 * till it die. It doesn't matter if he will be used for different 117 * load/save or any other requests. We will be up to date everytime. 118 */ 119 public void startListening() 120 { 121 com.sun.star.frame.XFrame xFrame = null; 122 synchronized(this) 123 { 124 if (m_bDead) 125 return; 126 if (m_xFrame==null) 127 return; 128 if (m_bIsActionListener==true) 129 return; 130 xFrame = m_xFrame; 131 } 132 xFrame.addFrameActionListener(this); 133 synchronized(this) 134 { 135 m_bIsActionListener=true; 136 } 137 } 138 139 //_____________________ 140 141 /** 142 * In case we got an oneway listener callback - we had to use the office 143 * asynchronous then. This method is the callback from the started thread 144 * (started inside the original oneway method). We found all parameters of 145 * the original request packed inside a vector. Here we unpack it and 146 * call the right internal helper method, which implements the right 147 * funtionality. 148 * 149 * @seealso frameAction() 150 * @seealso statusChanged() 151 * 152 * @param nRequest 153 * indicates, which was the original request (identifies the 154 * original called method) 155 * 156 * @param lParams 157 * the vector with all packed parameters of the original request 158 */ 159 public void execOneway(/*IN*/ int nRequest,/*IN*/ Vector lParams ) 160 { 161 synchronized(this) 162 { 163 if (m_bDead) 164 return; 165 } 166 // was it frameAction()? 167 if (nRequest==OnewayExecutor.REQUEST_FRAMEACTION) 168 { 169 com.sun.star.frame.FrameActionEvent[] lOutAction = new com.sun.star.frame.FrameActionEvent[1]; 170 Vector[] lInParams = new Vector[1]; 171 lInParams[0] = lParams; 172 173 OnewayExecutor.codeFrameAction( OnewayExecutor.DECODE_PARAMS , 174 lInParams , 175 lOutAction ); 176 impl_frameAction(lOutAction[0]); 177 } 178 } 179 180 //_____________________ 181 182 /** 183 * This is the callback method for such frame action events, we listen for. 184 * Because it's a oneway method we start a thread as reaction. This thread call 185 * us back and we can do neccessary things there. 186 * But we shouldn't start such action - if it's not realy neccessary. 187 * So we check before, if we are intereested on this event realy. 188 * 189 * @see impl_frameAction() 190 * 191 * @param aEvent 192 * describes the action, which triggered this event 193 */ 194 public /*ONEWAY*/ void frameAction(/*IN*/ com.sun.star.frame.FrameActionEvent aEvent) 195 { 196 synchronized(this) 197 { 198 if (m_bDead) 199 return; 200 } 201 boolean bHandle = false; 202 switch(aEvent.Action.getValue()) 203 { 204 case com.sun.star.frame.FrameAction.COMPONENT_ATTACHED_value : bHandle=true; break; 205 case com.sun.star.frame.FrameAction.COMPONENT_DETACHING_value : bHandle=true; break; 206 case com.sun.star.frame.FrameAction.COMPONENT_REATTACHED_value : bHandle=true; break; 207 case com.sun.star.frame.FrameAction.CONTEXT_CHANGED_value : bHandle=true; break; 208 } 209 210 if (! bHandle) 211 return; 212 213 Vector[] lOutParams = new Vector[1]; 214 com.sun.star.frame.FrameActionEvent[] lInAction = new com.sun.star.frame.FrameActionEvent[1]; 215 lInAction[0] = aEvent; 216 217 OnewayExecutor.codeFrameAction( OnewayExecutor.ENCODE_PARAMS , 218 lOutParams , 219 lInAction ); 220 OnewayExecutor aExecutor = new OnewayExecutor( (IOnewayLink)this , 221 OnewayExecutor.REQUEST_FRAMEACTION , 222 lOutParams[0] ); 223 aExecutor.start(); 224 } 225 226 //_____________________ 227 228 /** 229 * This is the callback method for the status we listen for an wish to show it 230 * on our UI control. Of yourse it's a oneway method ... but we doesn't call back 231 * to the office synchronously here. We update our UI only. So we don't leave this 232 * java process. In such case it's not neccessary to use threads to decouple it. 233 * Do it here and now ... 234 * 235 * @param aEvent 236 * describes the status, we can use to update our UI control 237 */ 238 public /*ONEWAY*/ void statusChanged(/*IN*/ com.sun.star.frame.FeatureStateEvent aEvent) 239 { 240 synchronized(this) 241 { 242 if (m_bDead) 243 return; 244 245 // enable/dsiable th control. 246 // Means: If the feature isn't available currently - we can't show an status realy here. 247 // Then we should colorize it gray ... 248 m_rControl.setEnabled(aEvent.IsEnabled); 249 250 // Only if status is enabled we can look for his value! 251 if (aEvent.IsEnabled) 252 { 253 // look for the right type ofthe UI control 254 // Following actions depend on it. 255 256 //............................................................. 257 // it's a check box 258 if (m_rControl instanceof JCheckBox) 259 { 260 JCheckBox aBox = (JCheckBox)m_rControl; 261 262 // State must be a boolean value too. Otherwhise must 263 // ignore this event. 264 if ( ! (aEvent.State instanceof Boolean ) ) 265 return; 266 267 boolean bState = ((Boolean)(aEvent.State)).booleanValue(); 268 aBox.setSelected(bState); 269 if (bState) 270 aBox.setText(m_sTrueText); 271 else 272 aBox.setText(m_sFalseText); 273 } 274 else 275 //............................................................. 276 // it's a label 277 if (m_rControl instanceof JLabel) 278 { 279 JLabel aLabel = (JLabel)m_rControl; 280 281 // Detect type of state value 282 // and set it on internal well known UI control 283 // But do it only, if value realy change. 284 if(aEvent.State instanceof String) 285 { 286 String sState = (String)aEvent.State; 287 aLabel.setText(sState); 288 } 289 else 290 if(aEvent.State instanceof Boolean) 291 { 292 boolean bState = ((Boolean)aEvent.State).booleanValue(); 293 if (bState) 294 aLabel.setText(m_sTrueText); 295 else 296 aLabel.setText(m_sFalseText); 297 } 298 else 299 if(aEvent.State instanceof Float) 300 { 301 String sState = ((Float)aEvent.State).toString(); 302 aLabel.setText(sState); 303 } 304 } 305 } 306 } 307 } 308 309 //_____________________ 310 311 /** 312 * Internal call back for frame action events, triggered by the used 313 * OnewayExecutor thread we started in frameAction(). 314 * We use it to update internal saved dispatch object and the corresponding 315 * listener connection for status events. 316 * 317 * @param aEvent 318 * describes the action 319 */ 320 public void impl_frameAction(/*IN*/ com.sun.star.frame.FrameActionEvent aEvent) 321 { 322 synchronized(this) 323 { 324 if (m_bDead) 325 return; 326 } 327 // Don't look for ignoring actions - it was done already inside original frameAction() call! 328 // deregistration as status listener will be done here everytime - but registration only, if neccessary! 329 boolean bRegister = false; 330 switch(aEvent.Action.getValue()) 331 { 332 case com.sun.star.frame.FrameAction.COMPONENT_ATTACHED_value : bRegister=true ; break; 333 case com.sun.star.frame.FrameAction.COMPONENT_DETACHING_value : bRegister=false; break; 334 case com.sun.star.frame.FrameAction.COMPONENT_REATTACHED_value : bRegister=true ; break; 335 case com.sun.star.frame.FrameAction.CONTEXT_CHANGED_value : bRegister=true ; break; 336 } 337 338 boolean bIsStatusListener = false; 339 com.sun.star.frame.XFrame xFrame = null ; 340 com.sun.star.frame.XDispatch xDispatch = null ; 341 com.sun.star.util.URL aURL = null ; 342 synchronized(this) 343 { 344 bIsStatusListener = m_bIsStatusListener; 345 m_bIsStatusListener = false; 346 347 xDispatch = m_xDispatch; 348 m_xDispatch = null; 349 350 aURL = m_aURL; 351 xFrame = m_xFrame; 352 } 353 354 if (bIsStatusListener) 355 xDispatch.removeStatusListener(this,aURL); 356 xDispatch = null; 357 358 if (! bRegister) 359 return; 360 361 com.sun.star.frame.XDispatchProvider xProvider = (com.sun.star.frame.XDispatchProvider)UnoRuntime.queryInterface( 362 com.sun.star.frame.XDispatchProvider.class, 363 xFrame); 364 365 if (xProvider==null) 366 return; 367 368 xDispatch = xProvider.queryDispatch(aURL,"",0); 369 370 if (xDispatch==null) 371 return; 372 373 xDispatch.addStatusListener(this,aURL); 374 synchronized(this) 375 { 376 m_xDispatch = xDispatch; 377 m_bIsStatusListener = true; 378 } 379 } 380 381 // ____________________ 382 383 /** 384 * callback for disposing events 385 * Our dispatch or frame object inform us about his following dead ... 386 * So we must forget his reference. But it's not neccessary to 387 * remove listener connections here. Because the broadcaster 388 * forget us automaticly. The only thing we have to do: release 389 * his reference and let him die! 390 * 391 * @param aEvent 392 * describes the source which fire this event 393 * Must be our internal saved dispatch or frame. Otherwhise 394 * somewhere know us without a registration ... 395 */ 396 public /*ONEWAY*/ void disposing(/*IN*/ com.sun.star.lang.EventObject aEvent) 397 { 398 synchronized(this) 399 { 400 if (m_bDead) 401 return; 402 if (m_xFrame!=null && UnoRuntime.areSame(aEvent.Source,m_xFrame)) 403 { 404 m_bIsActionListener = false; 405 m_xFrame = null ; 406 } 407 else 408 if (m_xDispatch!=null && UnoRuntime.areSame(aEvent.Source,m_xDispatch)) 409 { 410 m_bIsStatusListener = false; 411 m_xDispatch = null ; 412 m_aURL = null ; 413 } 414 } 415 shutdown(); 416 } 417 418 // ____________________ 419 420 /** 421 * If this java application shutdown - we must cancel all current existing 422 * listener connections. Otherwhise the office will run into some 423 * DisposedExceptions if it tries to use these forgotten listener references. 424 * And of course it can die doing that. 425 * We are registered at a central object to be informed if the VM will exit. 426 * So we can react. 427 */ 428 public void shutdown() 429 { 430 boolean bIsActionListener = false; 431 boolean bIsStatusListener = false; 432 com.sun.star.frame.XFrame xFrame = null ; 433 com.sun.star.frame.XDispatch xDispatch = null ; 434 com.sun.star.util.URL aURL = null ; 435 synchronized(this) 436 { 437 // don't react a second time here! 438 if (m_bDead) 439 return; 440 m_bDead = true; 441 442 bIsActionListener = m_bIsActionListener; 443 m_bIsActionListener = false; 444 445 bIsStatusListener = m_bIsStatusListener; 446 m_bIsStatusListener = false; 447 448 xFrame = m_xFrame; 449 m_xFrame = null; 450 451 xDispatch = m_xDispatch; 452 m_xDispatch = null; 453 454 aURL = m_aURL; 455 m_aURL = null; 456 } 457 458 if (bIsStatusListener) 459 xDispatch.removeStatusListener(this,aURL); 460 xDispatch = null ; 461 aURL = null ; 462 463 if (bIsActionListener) 464 xFrame.removeFrameActionListener(this); 465 xFrame = null ; 466 } 467 } 468