1 19 20 package org.openide.actions; 21 22 import java.awt.MenuShortcut ; 23 import java.awt.datatransfer.Clipboard ; 24 import java.awt.datatransfer.ClipboardOwner ; 25 import java.awt.datatransfer.StringSelection ; 26 import java.awt.datatransfer.Transferable ; 27 import java.awt.event.ActionEvent ; 28 import java.beans.PropertyChangeEvent ; 29 import java.beans.PropertyChangeListener ; 30 import java.beans.PropertyVetoException ; 31 import java.util.ArrayList ; 32 import java.util.Arrays ; 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 javax.swing.event.EventListenerList ; 39 import org.openide.awt.Actions; 40 import org.openide.explorer.ExplorerManager; 41 import org.openide.nodes.Node; 42 import org.openide.nodes.NodeEvent; 43 import org.openide.nodes.NodeListener; 44 import org.openide.nodes.NodeMemberEvent; 45 import org.openide.nodes.NodeReorderEvent; 46 import org.openide.util.Exceptions; 47 import org.openide.util.HelpCtx; 48 import org.openide.util.Lookup; 49 import org.openide.util.LookupListener; 50 import org.openide.util.NbBundle; 51 import org.openide.util.UserCancelException; 52 import org.openide.util.WeakListeners; 53 import org.openide.util.actions.CallbackSystemAction; 54 import org.openide.util.actions.Presenter; 55 import org.openide.util.datatransfer.PasteType; 56 import org.openide.windows.TopComponent; 57 58 71 public final class PasteAction extends CallbackSystemAction { 72 73 private static ActSubMenuModel globalModel; 74 75 76 private static PasteType[] types; 77 78 79 private static synchronized ActSubMenuModel model() { 80 if (globalModel == null) { 81 globalModel = new ActSubMenuModel(null); 82 } 83 84 return globalModel; 85 } 86 87 protected void initialize() { 88 super.initialize(); 89 90 setEnabled(false); 91 } 92 93 public String getName() { 94 return NbBundle.getMessage(PasteAction.class, "Paste"); 95 } 96 97 public HelpCtx getHelpCtx() { 98 return new HelpCtx(PasteAction.class); 99 } 100 101 protected String iconResource() { 102 return "org/openide/resources/actions/paste.gif"; } 104 105 public javax.swing.JMenuItem getMenuPresenter() { 106 return new Actions.SubMenu(this, model(), false); 107 } 108 109 public javax.swing.JMenuItem getPopupPresenter() { 110 return new Actions.SubMenu(this, model(), true); 111 } 112 113 public Action createContextAwareInstance(Lookup actionContext) { 114 return new DelegateAction(this, actionContext); 115 } 116 117 public Object getActionMapKey() { 118 return javax.swing.text.DefaultEditorKit.pasteAction; 119 } 120 121 public void actionPerformed(java.awt.event.ActionEvent ev) { 122 PasteType t; 123 124 if (ev.getSource() instanceof PasteType) { 125 t = (PasteType) ev.getSource(); 126 } else { 127 PasteType[] arr = getPasteTypes(); 128 129 if ((arr != null) && (arr.length > 0)) { 130 t = arr[0]; 131 } else { 132 t = null; 133 } 134 } 135 136 if (t == null) { 137 Action ac = findActionFromActivatedTopComponentMap(); 139 140 if (ac != null) { 141 Object obj = ac.getValue("delegates"); 146 if (obj instanceof PasteType []) { 147 PasteType [] arr = (PasteType []) obj; 148 if (arr.length > 0) { 149 t = arr [0]; 150 } 151 } else if (obj instanceof Action []) { 152 Action [] arr = (Action []) obj; 153 if (arr.length > 0) { 154 arr [0].actionPerformed (ev); 155 } 156 } else { 157 ac.actionPerformed(ev); 158 159 return; 160 } 161 } 162 } 163 164 if (t != null) { 165 new ActionPT(t, ev.getActionCommand()); 167 } else { 168 Logger.getLogger(PasteAction.class.getName()).log(Level.WARNING, null, 169 new IllegalStateException ("No paste types available when performing paste action")); } 171 } 172 173 protected boolean asynchronous() { 174 return false; 175 } 176 177 185 public void setPasteTypes(PasteType[] types) { 186 this.types = types; 187 188 if ((types == null) || (types.length == 0)) { 189 setEnabled(false); 190 } else { 191 setEnabled(true); 192 } 193 194 model().checkStateChanged(true); 195 } 196 197 199 public PasteType[] getPasteTypes() { 200 return types; 201 } 202 203 204 private static Action findActionFromActivatedTopComponentMap() { 205 TopComponent tc = TopComponent.getRegistry().getActivated(); 206 207 if (tc != null) { 208 ActionMap map = tc.getActionMap(); 209 210 return findActionFromMap(map); 211 } 212 213 return null; 214 } 215 216 217 private static javax.swing.Action findActionFromMap(ActionMap map) { 218 if (map != null) { 219 return map.get(javax.swing.text.DefaultEditorKit.pasteAction); 220 } 221 222 return null; 223 } 224 225 226 private static Clipboard getClipboard() { 227 Clipboard c = (java.awt.datatransfer.Clipboard ) org.openide.util.Lookup.getDefault().lookup( 228 java.awt.datatransfer.Clipboard .class 229 ); 230 231 if (c == null) { 232 c = java.awt.Toolkit.getDefaultToolkit().getSystemClipboard(); 233 } 234 235 return c; 236 } 237 238 244 static ExplorerManager findExplorerManager() { 245 Throwable t = null; 246 247 try { 248 Class c = Class.forName("org.openide.windows.TopComponent"); 250 java.lang.reflect.Method m = c.getMethod("getRegistry", new Class [0] 253 ); 254 Object o = m.invoke(null, new Object [0]); 255 256 c = Class.forName("org.openide.windows.TopComponent$Registry"); 258 m = c.getMethod("getActivated", new Class [0] 261 ); 262 o = m.invoke(o, new Object [0]); 263 264 if (o instanceof ExplorerManager.Provider) { 265 return ((ExplorerManager.Provider) o).getExplorerManager(); 266 } 267 } 268 catch (ClassNotFoundException x) { 270 } catch (ExceptionInInitializerError x) { 271 } catch (LinkageError x) { 272 } 273 catch (SecurityException x) { 275 t = x; 276 } catch (NoSuchMethodException x) { 277 t = x; 278 } 279 catch (IllegalAccessException x) { 281 t = x; 282 } catch (IllegalArgumentException x) { 283 t = x; 284 } catch (java.lang.reflect.InvocationTargetException x) { 285 t = x; 286 } 287 288 if (t != null) { 289 Logger.getLogger(PasteAction.class.getName()).log(Level.WARNING, null, t); 290 } 291 292 return null; 293 } 294 295 301 private static class ActSubMenuModel extends EventListenerList implements Actions.SubMenuModel, LookupListener, 302 PropertyChangeListener { 303 304 private Lookup.Result result; 305 306 307 private boolean enabled; 308 309 310 private PropertyChangeListener actionWeakL; 311 312 313 private PropertyChangeListener pasteTypeWeakL; 314 315 316 private LookupListener weakLookup; 317 318 319 public ActSubMenuModel(Lookup lookup) { 320 attachListenerToChangesInMap(lookup); 321 } 322 323 326 private ActionMap map() { 327 if (result == null) { 328 org.openide.windows.TopComponent tc = org.openide.windows.TopComponent.getRegistry().getActivated(); 329 330 if (tc != null) { 331 return tc.getActionMap(); 332 } 333 } else { 334 java.util.Iterator it = result.allItems().iterator(); 335 336 while (it.hasNext()) { 337 Object o = ((Lookup.Item) it.next()).getInstance(); 338 339 if (o instanceof ActionMap ) { 340 return (ActionMap ) o; 341 } 342 } 343 } 344 345 return null; 346 } 347 348 354 private void attachListenerToChangesInMap(Lookup lookup) { 355 if (lookup == null) { 356 org.openide.windows.TopComponent.getRegistry().addPropertyChangeListener( 357 org.openide.util.WeakListeners.propertyChange(this, org.openide.windows.TopComponent.getRegistry()) 358 ); 359 } else { 360 result = lookup.lookupResult(ActionMap .class); 361 weakLookup = (LookupListener) WeakListeners.create(LookupListener.class, this, result); 362 result.addLookupListener(weakLookup); 363 } 364 365 checkStateChanged(false); 366 } 367 368 379 private Object [] getPasteTypesOrActions(Action [] actionToWorkWith) { 380 Action x = findActionFromMap(map()); 381 382 if (x == null) { 383 PasteAction a = (PasteAction) findObject(PasteAction.class); 385 386 if (actionToWorkWith != null) { 387 actionToWorkWith[0] = a; 388 } 389 390 Object [] arr = a.getPasteTypes(); 391 392 if (arr != null) { 393 return arr; 394 } else { 395 return new Object [0]; 396 } 397 } 398 399 if (actionToWorkWith != null) { 400 actionToWorkWith[0] = x; 401 } 402 403 Object obj = x.getValue("delegates"); 405 if (obj instanceof Object []) { 406 return (Object []) obj; 407 } else { 408 return new Object [] { x }; 409 } 410 } 411 412 public boolean isEnabled() { 413 Object [] arr = getPasteTypesOrActions(null); 414 415 if ((arr.length == 1) && arr[0] instanceof Action ) { 416 return ((Action ) arr[0]).isEnabled(); 417 } else { 418 return arr.length > 0; 419 } 420 } 421 422 public int getCount() { 423 return getPasteTypesOrActions(null).length; 424 } 425 426 public String getLabel(int index) { 427 Object [] arr = getPasteTypesOrActions(null); 428 429 if (arr.length <= index) { 430 return null; 431 } 432 433 if (arr[index] instanceof PasteType) { 434 return ((PasteType) arr[index]).getName(); 435 } else { 436 return (String ) ((Action ) arr[index]).getValue(Action.NAME); 438 } 439 } 440 441 public HelpCtx getHelpCtx(int index) { 442 Object [] arr = getPasteTypesOrActions(null); 443 444 if (arr.length <= index) { 445 return null; 446 } 447 448 if (arr[index] instanceof PasteType) { 449 return ((PasteType) arr[index]).getHelpCtx(); 450 } else { 451 Object helpID = ((Action ) arr[index]).getValue("helpID"); 454 if (helpID instanceof String ) { 455 return new HelpCtx((String ) helpID); 456 } else { 457 return null; 458 } 459 } 460 } 461 462 public MenuShortcut getMenuShortcut(int index) { 463 return null; 464 } 465 466 public void performActionAt(int index) { 467 performActionAt(index, null); 468 } 469 470 public void performActionAt(int index, ActionEvent ev) { 471 Action [] action = new Action [1]; 472 473 Object [] arr = getPasteTypesOrActions(action); 474 475 if (arr.length <= index) { 476 return; 477 } 478 479 if (arr[index] instanceof PasteType) { 480 PasteType t = (PasteType) arr[index]; 481 482 new ActionPT(t, (ev == null) ? null : ev.getActionCommand()); 484 485 return; 486 } else { 487 Action a = (Action ) arr[index]; 489 a.actionPerformed(new ActionEvent (a, ActionEvent.ACTION_PERFORMED, a.NAME)); 490 491 return; 492 } 493 } 494 495 498 public synchronized void addChangeListener(javax.swing.event.ChangeListener listener) { 499 add(javax.swing.event.ChangeListener .class, listener); 500 } 501 502 505 public synchronized void removeChangeListener(javax.swing.event.ChangeListener listener) { 506 remove(javax.swing.event.ChangeListener .class, listener); 507 } 508 509 513 protected void checkStateChanged(boolean fire) { 514 Action [] listen = new Action [1]; 515 Object [] arr = getPasteTypesOrActions(listen); 516 517 Action a = null; 518 519 if ((arr.length == 1) && arr[0] instanceof Action ) { 520 a = (Action ) arr[0]; 521 a.removePropertyChangeListener(pasteTypeWeakL); 522 pasteTypeWeakL = WeakListeners.propertyChange(this, a); 523 a.addPropertyChangeListener(pasteTypeWeakL); 524 } 525 526 if (listen[0] != a) { 528 listen[0].removePropertyChangeListener(actionWeakL); 529 actionWeakL = WeakListeners.propertyChange(this, listen[0]); 530 listen[0].addPropertyChangeListener(actionWeakL); 531 } 532 533 boolean en = isEnabled(); 534 535 if (en == enabled) { 536 return; 537 } 538 539 enabled = en; 540 541 if (!fire) { 543 return; 544 } 545 546 Object [] listeners = getListenerList(); 547 548 if (listeners.length == 0) { 549 return; 550 } 551 552 javax.swing.event.ChangeEvent e = new javax.swing.event.ChangeEvent (this); 553 554 for (int i = listeners.length - 1; i >= 0; i -= 2) { 555 ((javax.swing.event.ChangeListener ) listeners[i]).stateChanged(e); 556 } 557 } 558 559 public void propertyChange(java.beans.PropertyChangeEvent evt) { 560 checkStateChanged(true); 561 } 562 563 public void resultChanged(org.openide.util.LookupEvent ev) { 564 checkStateChanged(true); 565 } 566 } 567 568 571 static final class NodeSelector extends Object implements NodeListener, Runnable { 572 573 private List added; 574 575 576 private Node node; 577 578 579 private ExplorerManager em; 580 581 582 private Node[] children; 583 584 587 public NodeSelector(ExplorerManager em, Node[] n) { 588 this.em = em; 589 590 if ((n != null) && (n.length > 0)) { 591 this.node = n[0]; 592 } else { 593 Node[] arr = em.getSelectedNodes(); 594 595 if (arr.length != 0) { 596 this.node = arr[0]; 597 } else { 598 return; 600 } 601 } 602 603 this.children = node.getChildren().getNodes(true); 604 605 this.added = new ArrayList (); 606 this.node.addNodeListener(this); 607 } 608 609 610 public void select() { 611 if (added != null) { 612 node.getChildren().getNodes(true); 614 615 org.openide.nodes.Children.MUTEX.readAccess(this); 617 } 618 } 619 620 public void run() { 621 this.node.removeNodeListener(this); 622 623 if (added.isEmpty()) { 624 return; 625 } 626 627 Node[] arr = (Node[]) added.toArray(new Node[added.size()]); 628 629 630 bigloop: 633 for (int i = 0; i < arr.length; i++) { 634 Node node = arr[i]; 635 636 while (node != null) { 637 if (node.equals(em.getRootContext())) { 638 continue bigloop; 639 } 640 641 node = node.getParentNode(); 642 } 643 644 return; 645 } 646 647 try { 648 em.setSelectedNodes(arr); 649 } catch (PropertyVetoException ex) { 650 Logger.getLogger(PasteAction.class.getName()).log(Level.WARNING, null, ex); 651 } catch (IllegalStateException ex) { 652 Logger.getLogger(PasteAction.class.getName()).log(Level.WARNING, null, ex); 653 } 654 } 655 656 659 public void childrenAdded(NodeMemberEvent ev) { 660 added.addAll(Arrays.asList(ev.getDelta())); 661 } 662 663 666 public void childrenRemoved(NodeMemberEvent ev) { 667 } 668 669 672 public void childrenReordered(NodeReorderEvent ev) { 673 } 674 675 678 public void nodeDestroyed(NodeEvent ev) { 679 } 680 681 685 public void propertyChange(PropertyChangeEvent evt) { 686 } 687 } 688 690 694 private static final class DelegateAction extends javax.swing.AbstractAction implements Presenter.Menu, 695 Presenter.Popup, Presenter.Toolbar, javax.swing.event.ChangeListener { 696 697 private PasteAction delegate; 698 699 700 private ActSubMenuModel model; 701 702 public DelegateAction(PasteAction a, Lookup actionContext) { 703 this.delegate = a; 704 this.model = new ActSubMenuModel(actionContext); 705 this.model.addChangeListener(this); 706 } 707 708 709 public String toString() { 710 return super.toString() + "[delegate=" + delegate + "]"; } 712 713 public void putValue(String key, Object value) { 714 } 715 716 718 public void actionPerformed(java.awt.event.ActionEvent e) { 719 if (model != null) { 720 model.performActionAt(0, e); 721 } 722 } 723 724 public boolean isEnabled() { 725 return (model != null) && model.isEnabled(); 726 } 727 728 public Object getValue(String key) { 729 return delegate.getValue(key); 730 } 731 732 public void setEnabled(boolean b) { 733 } 734 735 public javax.swing.JMenuItem getMenuPresenter() { 736 return new org.openide.awt.Actions.SubMenu(this, model, false); 737 } 738 739 public javax.swing.JMenuItem getPopupPresenter() { 740 return new org.openide.awt.Actions.SubMenu(this, model, true); 741 } 742 743 public java.awt.Component getToolbarPresenter() { 744 return new Actions.ToolbarButton(this); 745 } 746 747 public void stateChanged(javax.swing.event.ChangeEvent evt) { 748 super.firePropertyChange("enabled", null, null); 749 } 750 } 751 753 755 private static final class ActionPT extends javax.swing.AbstractAction implements Runnable { 756 private PasteType t; 757 private NodeSelector sel; 758 private boolean secondInvocation; 759 760 public ActionPT(PasteType t, String command) { 761 this.t = t; 762 763 ExplorerManager em = findExplorerManager(); 764 765 if (em != null) { 766 this.sel = new NodeSelector(em, null); 767 } 768 769 if ("waitFinished".equals(command)) { run(); 771 } else { 772 org.openide.util.RequestProcessor.getDefault().post(this); 773 } 774 } 775 776 public void actionPerformed(java.awt.event.ActionEvent ev) { 777 try { 778 Transferable trans = t.paste(); 779 Clipboard clipboard = getClipboard(); 780 781 if (trans != null) { 782 ClipboardOwner owner = (trans instanceof ClipboardOwner ) ? (ClipboardOwner ) trans 783 : new StringSelection (""); clipboard.setContents(trans, owner); 785 } 786 } catch (UserCancelException exc) { 787 } catch (java.io.IOException e) { 789 Exceptions.printStackTrace(e); 790 } finally { 791 javax.swing.SwingUtilities.invokeLater(this); 792 } 793 } 794 795 public void run() { 796 if (secondInvocation) { 797 if (sel != null) { 798 sel.select(); 799 } 800 } else { 801 secondInvocation = true; 802 ActionManager.getDefault().invokeAction( 803 this, new ActionEvent (t, ActionEvent.ACTION_PERFORMED, javax.swing.Action.NAME) 804 ); 805 } 806 } 807 808 public boolean isEnabled() { 809 return ((PasteAction) PasteAction.get(PasteAction.class)).isEnabled(); 810 } 811 812 public Object getValue(String key) { 813 return ((PasteAction) PasteAction.get(PasteAction.class)).getValue(key); 814 } 815 } 816 } 817 | Popular Tags |