1 19 20 package org.openide.util.actions; 21 22 import java.awt.Component ; 23 import java.awt.Toolkit ; 24 import java.awt.event.ActionEvent ; 25 import java.beans.PropertyChangeEvent ; 26 import java.beans.PropertyChangeListener ; 27 import java.beans.PropertyChangeSupport ; 28 import java.lang.ref.Reference ; 29 import java.lang.ref.WeakReference ; 30 import java.util.ArrayList ; 31 import java.util.Collection ; 32 import java.util.Collections ; 33 import java.util.List ; 34 import java.util.logging.Level ; 35 import java.util.logging.Logger ; 36 import javax.swing.Action ; 37 import javax.swing.ActionMap ; 38 import org.openide.util.ContextAwareAction; 39 import org.openide.util.Lookup; 40 import org.openide.util.LookupListener; 41 import org.openide.util.Mutex; 42 import org.openide.util.Utilities; 43 import org.openide.util.WeakListeners; 44 import org.openide.util.WeakSet; 45 46 53 public abstract class CallbackSystemAction extends CallableSystemAction implements ContextAwareAction { 54 55 private static final String PROP_ACTION_PERFORMER = "actionPerformer"; 57 58 private static final WeakSet<Class <? extends CallbackSystemAction>> notSurviving = new WeakSet<Class <? extends CallbackSystemAction>>(37); 59 60 61 private static final WeakSet<Class <? extends CallbackSystemAction>> surviving = new WeakSet<Class <? extends CallbackSystemAction>>(37); 62 63 64 private static final Object LISTENER = new Object (); 65 static final long serialVersionUID = -6305817805474624653L; 66 67 68 private static final Logger err = Logger.getLogger( 69 "org.openide.util.actions.CallbackSystemAction" 70 ); 72 74 protected void initialize() { 75 super.initialize(); 76 updateEnabled(); 77 setSurviveFocusChange(false); 78 } 79 80 84 @Deprecated 85 public ActionPerformer getActionPerformer() { 86 return (ActionPerformer) getProperty(PROP_ACTION_PERFORMER); 87 } 88 89 120 @Deprecated 121 public void setActionPerformer(ActionPerformer performer) { 122 putProperty(PROP_ACTION_PERFORMER, performer); 123 updateEnabled(); 124 } 125 126 128 private void updateEnabled() { 129 Action action = GlobalManager.getDefault().findGlobalAction( 130 getActionMapKey(), getSurviveFocusChange() 131 ); 132 133 if (action != null) { 134 setEnabled(action.isEnabled()); 135 136 synchronized (LISTENER) { 137 ActionDelegateListener l = (ActionDelegateListener) getProperty(LISTENER); 138 139 if ((l == null) || (l.get() != this)) { 140 l = new ActionDelegateListener(this, action); 141 putProperty(LISTENER, l); 142 } else { 143 l.attach(action); 144 } 145 } 146 } else { 147 if (getActionPerformer() != null) { 148 setEnabled(true); 150 } else { 151 setEnabled(false); 152 } 153 154 clearListener(); 155 } 156 } 157 158 160 private void clearListener() { 161 synchronized (LISTENER) { 162 ActionDelegateListener l = (ActionDelegateListener) getProperty(LISTENER); 164 165 if (l != null) { 166 l.clear(); 167 putProperty(LISTENER, null); 168 } 169 } 170 } 171 172 175 public void actionPerformed(final ActionEvent ev) { 176 final Action action = GlobalManager.getDefault().findGlobalAction(getActionMapKey(), getSurviveFocusChange()); 178 179 if (action != null) { 180 if (action.isEnabled()) { 181 action.actionPerformed(ev); 182 } else { 183 Toolkit.getDefaultToolkit().beep(); 184 } 185 186 return; 187 } 188 189 final Object ap = getActionPerformer(); 190 191 if (ap != null) { 192 org.netbeans.modules.openide.util.ActionsBridge.doPerformAction( 193 this, 194 new org.netbeans.modules.openide.util.ActionsBridge.ActionRunnable(ev, this, asynchronous ()) { 195 public void run() { 196 if (ap == getActionPerformer()) { 197 getActionPerformer().performAction(CallbackSystemAction.this); 198 } 199 } 200 } 201 ); 202 203 return; 204 } 205 206 Toolkit.getDefaultToolkit().beep(); 207 } 208 209 214 @Deprecated 215 public void performAction() { 216 ActionPerformer ap = getActionPerformer(); 217 218 if (ap != null) { 219 ap.performAction(this); 220 } 221 } 222 223 230 public Object getActionMapKey() { 231 return getClass().getName(); 232 } 233 234 238 public boolean getSurviveFocusChange() { 239 getProperty(null); 241 return !notSurviving.contains(getClass()); 242 } 243 244 245 public Action createContextAwareInstance(Lookup actionContext) { 246 return new DelegateAction(this, actionContext); 247 } 248 249 256 public void setSurviveFocusChange(boolean b) { 257 synchronized (notSurviving) { 258 if (b) { 259 notSurviving.remove(getClass()); 260 surviving.add(getClass()); 261 } else { 262 notSurviving.add(getClass()); 263 surviving.remove(getClass()); 264 } 265 } 266 } 267 268 270 private static List <CallbackSystemAction> toInstances(java.util.Set <Class <? extends CallbackSystemAction>> s) { 271 List <CallbackSystemAction> actions; 272 273 synchronized (notSurviving) { 274 actions = new ArrayList <CallbackSystemAction>(s.size()); 275 276 for (Class <? extends CallbackSystemAction> c : s) { 277 278 CallbackSystemAction a = SystemAction.findObject(c, false); 279 280 if (a != null) { 281 actions.add(a); 282 } 283 } 284 } 285 286 return actions; 287 } 288 289 292 private static void clearActionPerformers() { 293 List <CallbackSystemAction> actions = toInstances(notSurviving); 294 295 for (CallbackSystemAction a : actions) { 297 a.setActionPerformer(null); 298 } 299 300 actions = toInstances(surviving); 301 302 for (CallbackSystemAction a : actions) { 304 305 if (err.isLoggable(Level.FINE)) { 306 err.fine("updateEnabled: " + a); } 308 309 a.updateEnabled(); 310 } 311 } 312 313 315 private static final class GlobalManager implements LookupListener { 316 private static GlobalManager instance; 317 private Lookup.Result<ActionMap > result; 318 private Reference <ActionMap > actionMap = new WeakReference <ActionMap >(null); 319 private final ActionMap survive = new ActionMap (); 320 321 private GlobalManager() { 322 result = Utilities.actionsGlobalContext().lookup(new Lookup.Template<ActionMap >(ActionMap .class)); 323 result.addLookupListener(this); 324 resultChanged(null); 325 } 326 327 public synchronized static GlobalManager getDefault() { 328 if (instance != null) { 329 return instance; 330 } 331 332 instance = new GlobalManager(); 333 334 return instance; 335 } 336 337 public Action findGlobalAction(Object key, boolean surviveFocusChange) { 338 ActionMap map = actionMap.get(); 339 Action a = (map == null) ? null : map.get(key); 340 341 if (surviveFocusChange) { 342 if (a == null) { 343 a = survive.get(key); 344 345 if (a != null) { 346 a = ((WeakAction) a).getDelegate(); 347 } 348 349 if (err.isLoggable(Level.FINE)) { 350 err.fine("No action for key: " + key + " using delegate: " + a); } 352 } else { 353 if (err.isLoggable(Level.FINE)) { 354 err.fine("New action for key: " + key + " put: " + a); 355 } 356 357 survive.put(key, new WeakAction(a)); 358 } 359 } 360 361 if (err.isLoggable(Level.FINE)) { 362 err.fine("Action for key: " + key + " is: " + a); } 364 365 return a; 366 } 367 368 369 public void resultChanged(org.openide.util.LookupEvent ev) { 370 ActionMap a = Utilities.actionsGlobalContext().lookup(ActionMap .class); 371 372 if (err.isLoggable(Level.FINE)) { 373 err.fine("changed map : " + a); err.fine("previous map: " + actionMap.get()); } 376 377 if (a == actionMap.get()) { 378 return; 379 } 380 381 actionMap = new WeakReference <ActionMap >(a); 382 383 if (err.isLoggable(Level.FINE)) { 384 err.fine("clearActionPerformers"); } 386 387 Mutex.EVENT.readAccess(new Runnable () { 388 public void run() { 389 clearActionPerformers(); 390 } 391 }); 392 } 393 } 394 396 398 private static final class WeakAction extends WeakReference <Action > implements Action { 399 public WeakAction(Action delegate) { 400 super(delegate); 401 } 402 403 public Action getDelegate() { 404 return get(); 405 } 406 407 public Object getValue(String key) { 408 throw new UnsupportedOperationException (); 409 } 410 411 public void putValue(String key, Object value) { 412 throw new UnsupportedOperationException (); 413 } 414 415 public void actionPerformed(ActionEvent e) { 416 throw new UnsupportedOperationException (); 417 } 418 419 public void removePropertyChangeListener(PropertyChangeListener listener) { 420 throw new UnsupportedOperationException (); 421 } 422 423 public void addPropertyChangeListener(PropertyChangeListener listener) { 424 throw new UnsupportedOperationException (); 425 } 426 427 public void setEnabled(boolean b) { 428 throw new UnsupportedOperationException (); 429 } 430 431 public boolean isEnabled() { 432 throw new UnsupportedOperationException (); 433 } 434 } 435 436 439 private static final class ActionDelegateListener extends WeakReference <CallbackSystemAction> implements PropertyChangeListener { 440 private Reference <Action > delegate; 441 442 public ActionDelegateListener(CallbackSystemAction c, Action delegate) { 443 super(c); 444 this.delegate = new WeakReference <Action >(delegate); 445 delegate.addPropertyChangeListener(this); 446 } 447 448 public void clear() { 449 Action a; 450 451 Reference <Action > d = delegate; 452 a = d == null ? null : d.get(); 453 454 if (a == null) { 455 return; 456 } 457 458 delegate = null; 459 460 a.removePropertyChangeListener(this); 461 } 462 463 public void attach(Action action) { 464 Reference <Action > d = delegate; 465 466 if ((d != null) && (d.get() == action)) { 467 return; 468 } 469 470 Action prev = d.get(); 471 472 if (prev != null) { 474 prev.removePropertyChangeListener(this); 475 } 476 477 this.delegate = new WeakReference <Action >(action); 478 action.addPropertyChangeListener(this); 479 } 480 481 public void propertyChange(java.beans.PropertyChangeEvent evt) { 482 synchronized (LISTENER) { 483 Reference <Action > d = delegate; 484 485 if ((d == null) || (d.get() == null)) { 486 return; 487 } 488 } 489 490 CallbackSystemAction c = get(); 491 492 if (c != null) { 493 c.updateEnabled(); 494 } 495 } 496 } 497 498 502 private static final class DelegateAction extends Object implements Action , 503 LookupListener, Presenter.Menu, Presenter.Popup, Presenter.Toolbar, PropertyChangeListener { 504 505 private CallbackSystemAction delegate; 506 507 508 private Lookup.Result<ActionMap > result; 509 510 511 private boolean enabled; 512 513 514 private PropertyChangeSupport support = new PropertyChangeSupport (this); 515 516 517 private PropertyChangeListener weakL; 518 519 520 private Reference <Action > lastRef; 521 522 public DelegateAction(CallbackSystemAction a, Lookup actionContext) { 523 this.delegate = a; 524 this.weakL = org.openide.util.WeakListeners.propertyChange(this, null); 525 this.enabled = a.getActionPerformer() != null; 526 527 this.result = actionContext.lookup(new Lookup.Template<ActionMap >(ActionMap .class)); 528 this.result.addLookupListener(WeakListeners.create(LookupListener.class, this, this.result)); 529 resultChanged(null); 530 } 531 532 533 public String toString() { 534 return super.toString() + "[delegate=" + delegate + "]"; } 536 537 539 public void actionPerformed(final java.awt.event.ActionEvent e) { 540 final Action a = findAction(); 541 542 if (a != null) { 543 org.netbeans.modules.openide.util.ActionsBridge.ActionRunnable run; 544 run = new org.netbeans.modules.openide.util.ActionsBridge.ActionRunnable(e, delegate, delegate.asynchronous()) { 545 public void run() { 546 a.actionPerformed(e); 547 } 548 }; 549 550 org.netbeans.modules.openide.util.ActionsBridge.doPerformAction(delegate, run); 551 } else { 552 Object source = e.getSource(); 557 558 if ( 559 source instanceof Component && 560 javax.swing.SwingUtilities.getWindowAncestor((Component ) source) instanceof java.awt.Dialog 561 ) { 562 Object value = delegate.getValue("OpenIDE-Transmodal-Action"); 564 if (!Boolean.TRUE.equals(value)) { 565 return; 566 } 567 } 568 569 delegate.actionPerformed(e); 570 } 571 } 572 573 public boolean isEnabled() { 574 Action a = findAction(); 575 576 if (a == null) { 577 a = delegate; 578 } 579 580 Action last = lastRef == null ? null : lastRef.get(); 582 583 if (a != last) { 584 if (last != null) { 585 last.removePropertyChangeListener(weakL); 586 } 587 588 lastRef = new WeakReference <Action >(a); 589 a.addPropertyChangeListener(weakL); 590 } 591 592 return a.isEnabled(); 593 } 594 595 public void addPropertyChangeListener(PropertyChangeListener listener) { 596 support.addPropertyChangeListener(listener); 597 } 598 599 public void removePropertyChangeListener(PropertyChangeListener listener) { 600 support.removePropertyChangeListener(listener); 601 } 602 603 public void putValue(String key, Object o) { 604 } 605 606 public Object getValue(String key) { 607 return delegate.getValue(key); 608 } 609 610 public void setEnabled(boolean b) { 611 } 612 613 public void resultChanged(org.openide.util.LookupEvent ev) { 614 boolean newEnabled = isEnabled(); 615 616 if (newEnabled != enabled) { 617 support.firePropertyChange(PROP_ENABLED, enabled, newEnabled); 618 enabled = newEnabled; 619 } 620 } 621 622 public void propertyChange(PropertyChangeEvent evt) { 623 resultChanged(null); 624 } 625 626 629 private Action findAction() { 630 Collection <? extends ActionMap > c = result != null ? result.allInstances() : Collections.<ActionMap >emptySet(); 631 632 if (!c.isEmpty()) { 633 Object key = delegate.getActionMapKey(); 634 for (ActionMap map : c) { 635 Action action = map.get(key); 636 if (action != null) { 637 return action; 638 } 639 } 640 } 641 642 return null; 643 } 644 645 public javax.swing.JMenuItem getMenuPresenter() { 646 if (isMethodOverridden(delegate, "getMenuPresenter")) { 648 return delegate.getMenuPresenter(); 649 } else { 650 return org.netbeans.modules.openide.util.AWTBridge.getDefault().createMenuPresenter(this); 651 } 652 } 653 654 public javax.swing.JMenuItem getPopupPresenter() { 655 if (isMethodOverridden(delegate, "getPopupPresenter")) { 657 return delegate.getPopupPresenter(); 658 } else { 659 return org.netbeans.modules.openide.util.AWTBridge.getDefault().createPopupPresenter(this); 660 } 661 } 662 663 public java.awt.Component getToolbarPresenter() { 664 if (isMethodOverridden(delegate, "getToolbarPresenter")) { 666 return delegate.getToolbarPresenter(); 667 } else { 668 return org.netbeans.modules.openide.util.AWTBridge.getDefault().createToolbarPresenter(this); 669 } 670 } 671 672 private boolean isMethodOverridden(CallableSystemAction d, String name) { 673 try { 674 java.lang.reflect.Method m = d.getClass().getMethod(name, new Class [0]); 675 676 return m.getDeclaringClass() != CallableSystemAction.class; 677 } catch (java.lang.NoSuchMethodException ex) { 678 ex.printStackTrace(); 679 throw new IllegalStateException ("Error searching for method " + name + " in " + d); } 681 } 682 683 protected void finalize() { 684 Action last = lastRef == null ? null : lastRef.get(); 685 686 if (last != null) { 687 last.removePropertyChangeListener(weakL); 688 } 689 } 690 } 691 } 693 | Popular Tags |