1 19 20 package org.openide.util.actions; 21 22 import java.awt.event.ActionEvent ; 23 import java.beans.PropertyChangeEvent ; 24 import java.beans.PropertyChangeListener ; 25 import java.io.PrintWriter ; 26 import java.io.StringWriter ; 27 import java.lang.ref.Reference ; 28 import java.lang.ref.WeakReference ; 29 import java.util.ArrayList ; 30 import java.util.Iterator ; 31 import java.util.logging.Level ; 32 import java.util.logging.Logger ; 33 import javax.swing.AbstractAction ; 34 import javax.swing.Action ; 35 import javax.swing.ActionMap ; 36 import javax.swing.text.DefaultEditorKit ; 37 import org.netbeans.junit.NbTestCase; 38 import org.openide.util.HelpCtx; 39 import org.openide.util.Lookup; 40 import org.openide.util.actions.ActionPerformer; 41 import org.openide.util.actions.CallbackSystemAction; 42 import org.openide.util.actions.SystemAction; 43 import org.openide.util.lookup.Lookups; 44 45 48 public class CallbackSystemActionTest extends NbTestCase { 49 private Logger LOG; 50 51 52 public CallbackSystemActionTest(String name) { 53 super(name); 54 } 55 56 protected void setUp() throws Exception { 57 LOG = Logger.getLogger("TEST-" + getName()); 58 59 LOG.info("setUp"); 60 } 61 62 protected void tearDown() throws Exception { 63 LOG.info("tearDown"); 64 super.tearDown(); 65 LOG.info("tearDown super finished"); 66 SimpleCallbackAction.waitInstancesZero(LOG); 67 LOG.info("waiting for zero instances done"); 68 } 69 70 protected Level logLevel() { 71 return Level.FINE; 72 } 73 74 protected int timeOut() { 75 return 5000; 76 } 77 78 protected boolean runInEQ() { 79 return true; 80 } 81 82 public void testPropertyChangeListenersDetachedAtFinalizeIssue58100() throws Exception { 83 84 class MyAction extends AbstractAction 85 implements ActionPerformer { 86 public void actionPerformed(ActionEvent ev) { 87 } 88 public void performAction(SystemAction a) { 89 } 90 } 91 MyAction action = new MyAction(); 92 ActionMap map = new ActionMap (); 93 CallbackSystemAction systemaction = (CallbackSystemAction)SystemAction.get(SimpleCallbackAction.class); 94 map.put(systemaction.getActionMapKey(), action); 95 Lookup context = Lookups.singleton(map); 96 Action delegateaction = systemaction.createContextAwareInstance(context); 97 98 assertTrue("Action is expected to have a PropertyChangeListener attached", action.getPropertyChangeListeners().length > 0); 99 100 Reference actionref = new WeakReference (systemaction); 101 systemaction = null; 102 delegateaction = null; 103 assertGC("CallbackSystemAction is supposed to be GCed", actionref); 104 105 assertEquals("Action is expected to have no PropertyChangeListener attached", 0, action.getPropertyChangeListeners().length); 106 } 107 108 public void testSurviveFocusChangeInTheNewWay() throws Exception { 109 doSurviveFocusChangeInTheNewWay(false); 110 } 111 112 public void testSurviveFocusChangeInTheNewWayEvenActionIsGCed() throws Exception { 113 doSurviveFocusChangeInTheNewWay(true); 114 } 115 116 private void doSurviveFocusChangeInTheNewWay(boolean doGC) throws Exception { 117 class MyAction extends AbstractAction { 118 public int cntEnabled; 119 public int cntPerformed; 120 121 public boolean isEnabled() { 122 cntEnabled++; 123 return true; 124 } 125 126 public void actionPerformed(ActionEvent ev) { 127 cntPerformed++; 128 } 129 } 130 MyAction myAction = new MyAction(); 131 132 ActionMap other = new ActionMap (); 133 ActionMap tc = new ActionMap (); 134 SurviveFocusChgCallbackAction a = (SurviveFocusChgCallbackAction)SurviveFocusChgCallbackAction.get(SurviveFocusChgCallbackAction.class); 135 tc.put(a.getActionMapKey(), myAction); 136 137 ActionsInfraHid.setActionMap(other); 138 try { 139 assertFalse("Disabled on other component", a.isEnabled()); 140 ActionsInfraHid.setActionMap(tc); 141 assertTrue("MyAction is enabled", a.isEnabled()); 142 assertEquals("isEnabled called once", 1, myAction.cntEnabled); 143 144 if (doGC) { 145 WeakReference ref = new WeakReference (a); 146 a = null; 147 assertGC("Action can disappear", ref); 148 a = (SurviveFocusChgCallbackAction)SurviveFocusChgCallbackAction.get(SurviveFocusChgCallbackAction.class); 149 } 150 151 ActionsInfraHid.setActionMap(other); 152 assertTrue("Still enabled", a.isEnabled()); 153 assertEquals("isEnabled called still only once (now it is called twice)", 2, myAction.cntEnabled); 154 } finally { 155 ActionsInfraHid.setActionMap(null); 156 } 157 158 WeakReference ref = new WeakReference (a); 159 WeakReference ref2 = new WeakReference (myAction); 160 WeakReference ref3 = new WeakReference (tc); 161 a = null; 162 myAction = null; 163 tc = null; 164 assertGC("We are able to clear global action", ref); 165 assertGC("Even our action", ref2); 166 assertGC("Even our component", ref3); 167 } 168 169 171 public void testPerformer() throws Exception { 172 CallbackSystemAction a = (CallbackSystemAction)SystemAction.get(SimpleCallbackAction.class); 173 assertFalse(a.isEnabled()); 174 Performer p = new Performer(); 175 assertEquals(0, p.count); 176 a.setActionPerformer(p); 177 assertTrue(a.isEnabled()); 178 a.actionPerformed(null); 179 assertEquals(1, p.count); 180 a.setActionPerformer(null); 181 assertFalse(a.isEnabled()); 182 } 183 184 186 public void testFocusChanges() throws Exception { 187 helperTestFocusChanges(); 188 SimpleCallbackAction.waitInstancesZero(LOG); 195 helperTestFocusChanges(); 196 } 197 private void helperTestFocusChanges() throws Exception { 198 ActionMap t1 = new ActionMap (); 199 ActionMap t2 = new ActionMap (); 200 ActionsInfraHid.setActionMap(t1); 201 try { 202 LOG.info("helperTestFocusChanges1"); 203 CallbackSystemAction a1 = (CallbackSystemAction)SystemAction.get(SurviveFocusChgCallbackAction.class); 204 assertTrue(a1.getSurviveFocusChange()); 205 LOG.info("helperTestFocusChanges2"); 206 CallbackSystemAction a2 = (CallbackSystemAction)SystemAction.get(SimpleCallbackAction.class); 207 assertFalse(a2.getSurviveFocusChange()); 208 LOG.info("helperTestFocusChanges3"); 209 CallbackSystemAction a3 = (CallbackSystemAction)SystemAction.get(DoesNotSurviveFocusChgCallbackAction.class); 210 assertFalse(a3.getSurviveFocusChange()); 211 Performer p = new Performer(); 212 LOG.info("helperTestFocusChanges4"); 213 a1.setActionPerformer(p); 214 a2.setActionPerformer(p); 215 a3.setActionPerformer(p); 216 LOG.info("helperTestFocusChanges5"); 217 assertTrue(a1.isEnabled()); 218 assertTrue(a2.isEnabled()); 219 assertTrue(a3.isEnabled()); 220 LOG.info("helperTestFocusChanges6"); 221 ActionsInfraHid.setActionMap(t2); 222 LOG.info("helperTestFocusChanges7"); 223 assertTrue(a1.isEnabled()); 224 LOG.info("helperTestFocusChanges8"); 225 assertEquals(p, a1.getActionPerformer()); 226 assertFalse(a2.isEnabled()); 227 LOG.info("helperTestFocusChanges9"); 228 assertEquals(null, a2.getActionPerformer()); 229 assertFalse(a3.isEnabled()); 230 LOG.info("helperTestFocusChanges10"); 231 assertEquals(null, a3.getActionPerformer()); 232 } finally { 233 LOG.info("helperTestFocusChanges - finally"); 234 ActionsInfraHid.setActionMap(null); 235 LOG.info("helperTestFocusChanges - done"); 236 } 237 LOG.info("helperTestFocusChanges - done successfully"); 238 } 239 240 public void testGlobalChanges() throws Exception { 241 class MyAction extends AbstractAction { 242 public int cntEnabled; 243 public int cntPerformed; 244 245 public boolean isEnabled() { 246 cntEnabled++; 247 return true; 248 } 249 250 public void actionPerformed(ActionEvent ev) { 251 cntPerformed++; 252 } 253 } 254 MyAction myAction = new MyAction(); 255 256 ActionMap tc = new ActionMap (); 257 tc.put(DefaultEditorKit.copyAction, myAction); 258 CopyAction a = (CopyAction)CopyAction.get(CopyAction.class); 259 260 ActionsInfraHid.setActionMap(tc); 261 try { 262 assertTrue("MyAction is enabled", a.isEnabled()); 263 assertEquals("isEnabled called once", 1, myAction.cntEnabled); 264 a.setActionPerformer(null); 265 assertEquals("An enabled is currentlly called again", 2, myAction.cntEnabled); 266 } finally { 267 ActionsInfraHid.setActionMap(null); 268 } 269 } 270 private static final class CopyAction extends CallbackSystemAction { 271 public Object getActionMapKey() { 272 return DefaultEditorKit.copyAction; 273 } 274 public String getName() { 275 return "Copy"; 276 } 277 public HelpCtx getHelpCtx() { 278 return null; 279 } 280 protected boolean asynchronous() { 281 return false; 282 } 283 } 284 285 286 public static final class Performer implements ActionPerformer { 287 public int count = 0; 288 public void performAction(SystemAction action) { 289 count++; 290 } 291 } 292 293 294 public static final class SimpleCallbackAction extends CallbackSystemAction { 295 public String getName() { 296 return "SimpleCallbackAction"; 297 } 298 public HelpCtx getHelpCtx() { 299 return null; 300 } 301 302 private static ArrayList INSTANCES_WHO = new ArrayList (); 303 private static Object INSTANCES_LOCK = new Object (); 304 public static int INSTANCES = 0; 305 306 public static void waitInstancesZero(Logger l) throws InterruptedException { 307 for (int i = 0; i < 10; i++) { 308 synchronized (INSTANCES_LOCK) { 309 if (INSTANCES == 0) return; 310 311 l.warning("instances still there: " + INSTANCES); 312 } 313 314 ActionsInfraHid.doGC(); 315 316 synchronized (INSTANCES_LOCK) { 317 l.warning("after GC, do wait"); 318 319 INSTANCES_LOCK.wait(1000); 320 l.warning("after waiting"); 321 } 322 } 323 failInstances("Instances are not zero"); 324 } 325 326 private static void failInstances(String msg) { 327 StringWriter w = new StringWriter (); 328 PrintWriter pw = new PrintWriter (w); 329 pw.println(msg + ": " + INSTANCES); 330 for (Iterator it = INSTANCES_WHO.iterator(); it.hasNext();) { 331 Exception elem = (Exception ) it.next(); 332 elem.printStackTrace(pw); 333 } 334 pw.close(); 335 fail(w.toString()); 336 } 337 338 public SimpleCallbackAction() { 339 synchronized (INSTANCES_LOCK) { 340 INSTANCES++; 341 INSTANCES_LOCK.notifyAll(); 342 INSTANCES_WHO.add(new Exception ("Incremented to " + INSTANCES)); 343 344 if (INSTANCES == 2) { 345 failInstances("Incremented to two. That is bad"); 346 } 347 } 348 } 349 protected boolean clearSharedData() { 350 synchronized (INSTANCES_LOCK) { 351 INSTANCES--; 352 INSTANCES_LOCK.notifyAll(); 353 INSTANCES_WHO.add(new Exception ("Decremented to " + INSTANCES)); 354 } 355 return super.clearSharedData(); 356 } 357 protected boolean asynchronous() { 358 return false; 359 } 360 } 361 362 363 public static final class SurviveFocusChgCallbackAction extends CallbackSystemAction { 364 protected void initialize() { 365 super.initialize(); 366 setSurviveFocusChange(true); 367 } 368 public String getName() { 369 return "SurviveFocusChgCallbackAction"; 370 } 371 public HelpCtx getHelpCtx() { 372 return null; 373 } 374 protected boolean asynchronous() { 375 return false; 376 } 377 } 378 379 380 public static final class DoesNotSurviveFocusChgCallbackAction extends CallbackSystemAction { 381 protected void initialize() { 382 super.initialize(); 383 setSurviveFocusChange(false); 384 } 385 public String getName() { 386 return "SurviveFocusChgCallbackAction"; 387 } 388 public HelpCtx getHelpCtx() { 389 return null; 390 } 391 protected boolean asynchronous() { 392 return false; 393 } 394 } 395 396 397 398 399 403 public void testLookupOfStateInActionMap() throws Exception { 404 class MyAction extends AbstractAction 405 implements ActionPerformer { 406 int actionPerformed; 407 int performAction; 408 409 public void actionPerformed(ActionEvent ev) { 410 actionPerformed++; 411 } 412 413 public void performAction(SystemAction a) { 414 performAction++; 415 } 416 } 417 MyAction action = new MyAction(); 418 419 ActionMap map = new ActionMap (); 420 CallbackSystemAction system = (CallbackSystemAction)SystemAction.get(SurviveFocusChgCallbackAction.class); 421 system.setActionPerformer(null); 422 map.put(system.getActionMapKey(), action); 423 424 425 426 Action clone; 427 428 429 433 clone = system.createContextAwareInstance(Lookup.EMPTY); 434 435 assertTrue("Action should not be enabled if no callback provided", !clone.isEnabled()); 436 437 system.setActionPerformer(action); 438 assertTrue("Is enabled, because it has a performer", clone.isEnabled()); 439 system.setActionPerformer(null); 440 assertTrue("Is disabled, because the performer has been unregistered", !clone.isEnabled()); 441 442 action.setEnabled(false); 446 447 Lookup context = Lookups.singleton(map); 448 clone = system.createContextAwareInstance(context); 449 450 CntListener listener = new CntListener(); 451 clone.addPropertyChangeListener(listener); 452 453 assertTrue("Not enabled now", !clone.isEnabled()); 454 action.setEnabled(true); 455 assertTrue("Clone is enabled because the action in ActionMap is", clone.isEnabled()); 456 listener.assertCnt("One change expected", 1); 457 458 system.setActionPerformer(action); 459 clone.actionPerformed(new ActionEvent (this, 0, "")); 460 assertEquals("MyAction.actionPerformed invoked", 1, action.actionPerformed); 461 assertEquals("MyAction.performAction is not invoked", 0, action.performAction); 462 463 464 action.setEnabled(false); 465 assertTrue("Clone is disabled because the action in ActionMap is", !clone.isEnabled()); 466 listener.assertCnt("Another change expected", 1); 467 468 clone.actionPerformed(new ActionEvent (this, 0, "")); 469 assertEquals("MyAction.actionPerformed invoked again", 2, action.actionPerformed); 470 assertEquals("MyAction.performAction is not invoked, remains 0", 0, action.performAction); 471 472 } 473 474 private static final class CntListener extends Object 475 implements PropertyChangeListener { 476 private int cnt; 477 478 public void propertyChange(PropertyChangeEvent evt) { 479 cnt++; 480 } 481 482 public void assertCnt(String msg, int count) { 483 assertEquals(msg, count, this.cnt); 484 this.cnt = 0; 485 } 486 } 488 } 489 | Popular Tags |