1 19 20 package org.openide.actions; 21 22 import java.awt.Component ; 23 import java.awt.event.*; 24 import java.beans.*; 25 import java.io.IOException ; 26 import java.lang.ref.WeakReference ; 27 import java.util.*; 28 import java.util.logging.Level ; 29 import java.util.logging.Logger ; 30 import javax.swing.*; 31 import org.openide.awt.*; 32 import org.openide.explorer.view.MenuView; 33 import org.openide.filesystems.*; 34 import org.openide.loaders.*; 35 import org.openide.nodes.*; 36 import org.openide.util.*; 37 import org.openide.util.actions.*; 38 import org.openide.windows.*; 39 40 45 public class NewTemplateAction extends NodeAction { 46 47 private static DataObject selectedTemplate; 48 private static DataFolder targetFolder; 49 50 51 private static int MAX_RECENT_ITEMS = 5; 52 53 57 static TemplateWizard getWizard (Node n) { 58 if (n == null) { 59 Node[] arr = WindowManager.getDefault ().getRegistry ().getActivatedNodes (); 60 if (arr.length == 1) { 61 n = arr[0]; 62 } 63 } 64 65 Node folder = n; 67 targetFolder = null; 69 while (targetFolder == null && folder != null) { 70 targetFolder = folder.getCookie(DataFolder.class); 71 folder = folder.getParentNode (); 72 } 73 74 NewTemplateAction.Cookie c = n == null ? null : n.getCookie(NewTemplateAction.Cookie.class); 75 if (c != null) { 76 TemplateWizard t = c.getTemplateWizard (); 77 if (t != null) { 78 return t; 79 } 80 } 81 82 return new DefaultTemplateWizard(); 83 } 84 85 private boolean active = false; 86 87 protected void performAction (Node[] activatedNodes) { 90 if (active) 91 return; 92 93 active = true; 94 95 Node n = activatedNodes.length == 1 ? activatedNodes[0] : null; 96 TemplateWizard wizard = getWizard (n); 97 if (wizard instanceof DefaultTemplateWizard) { 98 if (targetFolder != null && targetFolder.isValid()) 99 wizard.setTargetFolder(targetFolder); 100 if (selectedTemplate != null && selectedTemplate.isValid()) 101 wizard.setTemplate(selectedTemplate); 102 } 103 boolean instantiated = false; 104 try { 105 wizard.setTargetName(null); 107 instantiated = wizard.instantiate() != null; 109 } catch (IOException e) { 110 Exceptions.attachLocalizedMessage(e, 111 org.openide.util.NbBundle.getMessage(org.openide.loaders.DataObject.class, 112 "EXC_TemplateFailed")); 113 Exceptions.printStackTrace(e); 114 } 115 finally { 116 if (wizard instanceof DefaultTemplateWizard) { 117 try { 118 if (instantiated) { 119 selectedTemplate = wizard.getTemplate(); 120 if (selectedTemplate != null) { 122 recentChanged = addRecent (selectedTemplate); 123 } 124 } 125 targetFolder = wizard.getTargetFolder(); 128 } 129 catch (IOException ignore) { 130 selectedTemplate = null; 131 targetFolder = null; 132 } 133 } 134 active = false; 135 } 136 } 137 138 protected boolean asynchronous() { 139 return false; 140 } 141 142 144 protected boolean enable (Node[] activatedNodes) { 145 if ((activatedNodes == null) || (activatedNodes.length != 1)) 146 return false; 147 148 NewTemplateAction.Cookie c = activatedNodes[0].getCookie(NewTemplateAction.Cookie.class); 149 if (c != null) { 150 return c.getTemplateWizard () != null; 152 } 153 154 DataFolder cookie = activatedNodes[0].getCookie(DataFolder.class); 155 if (cookie != null && cookie.getPrimaryFile ().canWrite ()) { 156 return true; 157 } 158 return false; 159 } 160 161 public String getName() { 162 return NbBundle.getMessage(DataObject.class, "NewTemplate"); 163 } 164 165 public HelpCtx getHelpCtx() { 166 return new HelpCtx (NewTemplateAction.class); 167 } 168 169 public JMenuItem getMenuPresenter () { 170 return new Actions.MenuItem (this, true) { 171 public void setEnabled (boolean e) { 172 super.setEnabled (true); 173 } 174 }; 175 } 176 177 public Component getToolbarPresenter () { 178 return new Actions.ToolbarButton (this) { 179 public void setEnabled (boolean e) { 180 super.setEnabled (true); 181 } 182 }; 183 } 184 185 188 public JMenuItem getPopupPresenter() { 189 return getPopupPresenter (null, this); 190 } 191 192 private JMenuItem getPopupPresenter (final Lookup actionContext, Action action) { 193 Node[] nodes = new Node[0]; 194 if (actionContext != null) { 195 nodes = getNodesFromLookup (actionContext); 196 } 197 final Node n = (nodes.length == 1) ? nodes[0] : null; 198 TemplateWizard tw = getWizard (n); 199 200 if (tw instanceof DefaultTemplateWizard) { 201 return new MenuWithRecent (n, this.isEnabled ()); 202 } else { 203 JMenuItem menu = new MenuView.Menu (null, new TemplateActionListener (actionContext), false) { 205 public JPopupMenu getPopupMenu () { 208 if (node == null) node = getTemplateRoot (n); 209 return super.getPopupMenu (); 210 } 211 }; 212 Actions.connect (menu, action, true); 213 return menu; 214 } 215 } 216 217 218 private class MenuWithRecent extends JMenuPlus { 219 private boolean initialized = false; 220 private Node node; 221 private boolean canWrite; 222 223 public MenuWithRecent(Node n, boolean writable) { 224 super(); Actions.setMenuText(this, NewTemplateAction.this.getName(), false); 226 node = n; 227 canWrite = writable; 228 } 229 230 public JPopupMenu getPopupMenu() { 231 JPopupMenu popup = super.getPopupMenu(); 232 if (!initialized) { 233 popup.add(new Item(null)); 235 List privileged = getPrivilegedList(); 236 if (privileged.size() > 0) popup.add(new JSeparator()); for (Iterator it = privileged.iterator(); it.hasNext(); ) { 239 DataObject dobj = (DataObject)it.next(); 240 if (dobj instanceof DataShadow) 241 dobj = ((DataShadow)dobj).getOriginal(); 242 popup.add(new Item(dobj)); 243 } 244 245 boolean regenerate = false; 247 boolean addSeparator = ! getRecentList ().isEmpty (); 248 for (Iterator it = getRecentList ().iterator(); it.hasNext(); ) { 249 DataObject dobj = (DataObject)it.next (); 250 if (isValidTemplate (dobj)) { 251 if (addSeparator) popup.add (new JSeparator ()); addSeparator = false; 253 popup.add (new Item (dobj)); 254 } else { 255 regenerate = true; 257 } 258 } 259 recentChanged = recentChanged || regenerate; 260 initialized = true; 261 } 262 return popup; 263 } 264 265 private class Item extends JMenuItem implements HelpCtx.Provider, ActionListener { 266 DataObject template; public Item(DataObject template) { 268 super(); 269 this.template = template; 270 271 setText (template == null ? 272 NbBundle.getMessage(DataObject.class, "NewTemplateAction") : 273 template.getNodeDelegate().getDisplayName() 274 ); 275 276 if (template == null) { 277 setIcon (NewTemplateAction.this.getIcon()); 278 } else { 279 setIcon (new ImageIcon(template.getNodeDelegate().getIcon(java.beans.BeanInfo.ICON_COLOR_16x16))); 280 } 281 282 addActionListener(this); 283 setEnabled (canWrite); 285 } 286 287 288 public HelpCtx getHelpCtx() { 289 if (template != null) { 290 return template.getHelpCtx(); 291 } 292 return NewTemplateAction.this.getHelpCtx(); 293 } 294 295 296 public void actionPerformed(ActionEvent e) { 297 doShowWizard(template, node); 298 } 299 } 300 } 301 302 303 private DataFolder privilegedListFolder; 304 305 306 private DataFolder recentListFolder; 307 308 private boolean recentChanged = true; 309 private List<DataObject> recentList = new ArrayList<DataObject> (0); 310 311 private List<DataObject> getPrivilegedList() { 312 if (privilegedListFolder == null) { 313 FileObject fo = Repository.getDefault().getDefaultFileSystem(). 314 findResource("Templates/Privileged"); if (fo != null) privilegedListFolder = DataFolder.findFolder(fo); 316 } 317 if (privilegedListFolder != null) { 318 DataObject[] data = privilegedListFolder.getChildren(); 319 List<DataObject> l2 = new ArrayList<DataObject>(data.length); 320 for (int i=0; i<data.length; i++) { 321 DataObject dobj = data[i]; 322 if (dobj instanceof DataShadow) 323 dobj = ((DataShadow)dobj).getOriginal(); 324 if (isValidTemplate (dobj)) { 325 l2.add(dobj); 326 } 327 } 328 return l2; 329 } else { 330 return new ArrayList<DataObject>(0); 331 } 332 } 333 334 private void doShowWizard(DataObject template, Node node) { 335 targetFolder = null; 336 TemplateWizard wizard = getWizard (node); 337 338 try { 339 wizard.setTargetName (null); 340 Set created = wizard.instantiate (template, targetFolder); 341 if (created != null && wizard instanceof DefaultTemplateWizard) { 342 selectedTemplate = wizard.getTemplate(); 344 if (selectedTemplate != null) { 345 recentChanged = addRecent (selectedTemplate); 347 } 348 } 349 } catch (IOException e) { 350 Exceptions.attachLocalizedMessage(e, 351 org.openide.util.NbBundle.getMessage(org.openide.loaders.DataObject.class, 352 "EXC_TemplateFailed")); 353 Exceptions.printStackTrace(e); 354 } 355 } 356 357 private DataFolder getRecentFolder () { 358 if (recentListFolder == null) { 359 FileObject fo = Repository.getDefault ().getDefaultFileSystem (). 360 findResource ("Templates/Recent"); if (fo != null) { 362 recentListFolder = DataFolder.findFolder(fo); 363 } 364 } 365 366 return recentListFolder; 367 } 368 369 private List<DataObject> getRecentList () { 370 if (!recentChanged) return recentList; 371 if (getRecentFolder () != null) { 372 DataObject[] data = getRecentFolder ().getChildren (); 373 List<DataObject> l2 = new ArrayList<DataObject>(data.length); 374 for (int i=0; i<data.length; i++) { 375 DataObject dobj = data[i]; 376 if (dobj instanceof DataShadow) 377 dobj = ((DataShadow)dobj).getOriginal(); 378 if (isValidTemplate (dobj)) { 379 l2.add(dobj); 380 } else { 381 removeRecent (data[i]); 382 } 383 } 384 recentList = l2; 385 } else { 386 recentList = new ArrayList<DataObject> (0); 387 } 388 389 recentChanged = false; 390 391 return recentList; 392 } 393 394 private boolean isValidTemplate (DataObject template) { 395 return (template != null) && template.isTemplate () && template.isValid (); 396 } 397 398 private boolean addRecent (DataObject template) { 399 DataFolder folder = getRecentFolder (); 400 401 if (folder == null) return false; 403 404 if (getPrivilegedList ().contains (template)) return false; 406 407 if (isRecent (template)) return false; 409 410 DataObject[] templates = folder.getChildren (); 411 412 DataObject[] newOrder = new DataObject[templates.length + 1]; 413 for (int i = 1; i < newOrder.length; i++) { 414 newOrder[i] = templates[i - 1]; 415 } 416 417 try { 418 newOrder[0] = template.createShadow (folder); 419 folder.setOrder (newOrder); 420 } catch (IOException ioe) { 421 Logger.getLogger(NewTemplateAction.class.getName()).log(Level.WARNING, null, ioe); 422 return false; 424 } 425 426 templates = folder.getChildren (); 428 int size = templates.length; 429 430 while (size > MAX_RECENT_ITEMS) { 431 removeRecent (templates[size - 1]); 433 size--; 434 } 435 436 return true; 437 } 438 439 private boolean removeRecent (DataObject template) { 440 DataFolder folder = getRecentFolder (); 441 442 if (folder == null) return false; 444 445 try { 446 template.delete (); 447 return true; 448 } catch (IOException ioe) { 449 Logger.getLogger(NewTemplateAction.class.getName()).log(Level.WARNING, null, ioe); 450 return false; 452 } 453 } 454 455 private boolean isRecent (DataObject template) { 456 return getRecentList ().contains (template); 457 } 458 459 462 public static Node getTemplateRoot () { 463 RootChildren ch = new RootChildren (null); 464 return ch.getRootFolder ().new FolderNode (ch); 466 } 467 468 private static Node getTemplateRoot (Node n) { 469 RootChildren ch = new RootChildren (n); 470 Node help = ch.getRootFolder ().new FolderNode (ch); 472 return help; 473 } 474 475 478 public static interface Cookie extends Node.Cookie { 479 481 public TemplateWizard getTemplateWizard (); 482 } 483 484 486 private static boolean acceptObj (DataObject obj) { 487 if (obj.isTemplate ()) { 488 return true; 489 } 490 491 if (obj instanceof DataFolder) { 492 Object o = obj.getPrimaryFile ().getAttribute ("simple"); return o == null || Boolean.TRUE.equals (o); 494 } 495 496 return false; 497 498 } 499 500 501 502 private static class TemplateActionListener implements NodeAcceptor, DataFilter { 503 static final long serialVersionUID =1214995994333505784L; 504 Lookup actionContext; 505 TemplateActionListener(Lookup context) { 506 actionContext = context; 507 } 508 public boolean acceptNodes (Node[] nodes) { 509 Node[] nodesInContext = null; 510 if (actionContext != null) { 511 nodesInContext = getNodesFromLookup (actionContext); 512 } 513 if ((nodesInContext == null) || (nodesInContext.length != 1)) { 514 Logger.getAnonymousLogger().warning("Wrong count of nodes in context lookup."); return false; 516 } 517 if ((nodes == null) || (nodes.length != 1)) { 518 Logger.getAnonymousLogger().warning("Wrong count of selected nodes in popup menu."); return false; 520 } 521 Node n = nodes[0]; 522 DataObject obj = n.getCookie(DataObject.class); 523 if (obj == null || !obj.isTemplate ()) { 524 Logger.getAnonymousLogger().warning("Selected node in popup menu is not acceptable."); return false; 527 } 528 529 TemplateWizard wizard = getWizard (nodesInContext[0]); 531 532 try { 533 wizard.setTargetName (null); 534 wizard.instantiate (obj, targetFolder); 535 } catch (IOException e) { 536 Exceptions.attachLocalizedMessage(e, 537 org.openide.util.NbBundle.getMessage(org.openide.loaders.DataObject.class, 538 "EXC_TemplateFailed")); 539 Exceptions.printStackTrace(e); 540 } 541 542 return true; 544 } 545 546 548 public boolean acceptDataObject (DataObject obj) { 549 return acceptObj (obj); 550 } 551 } 552 553 555 private static class RootChildren extends Children.Keys<Node> 556 implements NodeListener { 557 558 private TemplateWizard wizard; 559 560 private DataFolder rootFolder; 561 564 private WeakReference <Node> current; 565 566 private NodeListener listener = org.openide.nodes.NodeOp.weakNodeListener (this, null); 567 568 570 public RootChildren (Node n) { 571 TopComponent.Registry reg = WindowManager.getDefault ().getRegistry (); 572 reg.addPropertyChangeListener (org.openide.util.WeakListeners.propertyChange (this, reg)); 573 574 updateWizard (getWizard (n)); 575 } 576 577 public DataFolder getRootFolder () { 578 if (rootFolder == null) { 579 doSetKeys (); 581 } 582 return rootFolder; 583 } 584 585 586 588 protected Node[] createNodes(Node n) { 589 String nodeName = n.getDisplayName(); 590 591 DataObject obj = null; 592 DataShadow shadow = n.getCookie(DataShadow.class); 593 if (shadow != null) { 594 DataNode dn = new DataNode(shadow, Children.LEAF); 597 nodeName = dn.getDisplayName(); 598 obj = shadow.getOriginal(); 599 n = obj.getNodeDelegate(); 600 } 601 602 if (obj == null) 603 obj = n.getCookie(DataObject.class); 604 if (obj != null) { 605 if (obj.isTemplate ()) { 606 return new Node[] { new DataShadowFilterNode (n, LEAF, nodeName) }; 608 } 609 610 if (acceptObj (obj)) { 611 return new Node[] { new DataShadowFilterNode (n, new TemplateChildren (n), nodeName) }; 613 } 614 } 615 616 return null; 617 } 618 619 621 private void updateNode (Node n) { 622 if (current != null && current.get () == n) { 623 return; 624 } 625 626 Node prev = current != null? current.get(): null; 627 if (prev != null) { 628 prev.removeNodeListener (listener); 629 } 630 631 n.addNodeListener (listener); 632 current = new WeakReference <Node> (n); 633 } 634 635 637 private void updateWizard (TemplateWizard w) { 638 if (wizard == w) { 639 return; 640 } 641 642 if (wizard != null) { 643 Node n = wizard.getTemplatesFolder ().getNodeDelegate (); 644 n.removeNodeListener (listener); 645 } 646 647 Node newNode = w.getTemplatesFolder ().getNodeDelegate (); 648 newNode.addNodeListener (listener); 649 wizard = w; 650 651 updateKeys (); 652 } 653 654 656 private void updateKeys () { 657 RequestProcessor.getDefault().post(new Runnable () { 660 public void run() { 661 doSetKeys (); 662 } 663 }); 664 } 665 666 private void doSetKeys () { 668 rootFolder = wizard.getTemplatesFolder (); 669 setKeys (rootFolder.getNodeDelegate ().getChildren ().getNodes (true)); 670 } 671 672 676 public void childrenReordered(NodeReorderEvent ev) { 677 updateKeys (); 678 } 679 680 683 public void childrenRemoved(NodeMemberEvent ev) { 684 updateKeys (); 685 } 686 687 690 public void childrenAdded(NodeMemberEvent ev) { 691 updateKeys (); 692 } 693 694 697 public void nodeDestroyed(NodeEvent ev) { 698 } 699 700 702 public void propertyChange(java.beans.PropertyChangeEvent ev) { 703 String pn = ev.getPropertyName (); 704 705 if (current != null && ev.getSource () == current.get ()) { 706 if (Node.PROP_COOKIE.equals (pn)) { 708 final Node node = current.get(); 709 Mutex.EVENT.readAccess(new Runnable () { 710 public void run() { 711 updateWizard (getWizard (node)); 712 } 713 }); 714 } 715 } else { 716 if (TopComponent.Registry.PROP_ACTIVATED_NODES.equals (pn)) { 718 Node[] arr = WindowManager.getDefault ().getRegistry ().getActivatedNodes (); 720 if (arr.length == 1) { 721 updateNode (arr[0]); 723 } 724 } 725 } 726 } 727 728 } 729 730 732 private static class TemplateChildren extends FilterNode.Children { 733 public TemplateChildren (Node or) { 734 super (or); 735 } 736 737 739 @Override 740 protected Node[] createNodes(Node n) { 741 String nodeName = n.getDisplayName(); 742 743 DataObject obj = null; 744 DataShadow shadow = n.getCookie(DataShadow.class); 745 if (shadow != null) { 746 DataNode dn = new DataNode(shadow, Children.LEAF); 749 nodeName = dn.getDisplayName(); 750 obj = shadow.getOriginal(); 751 n = obj.getNodeDelegate(); 752 } 753 754 if (obj == null) 755 obj = n.getCookie(DataObject.class); 756 if (obj != null) { 757 if (obj.isTemplate ()) { 758 return new Node[] { new DataShadowFilterNode (n, LEAF, nodeName) }; 760 } 761 762 if (acceptObj (obj)) { 763 return new Node[] { new DataShadowFilterNode (n, new TemplateChildren (n), nodeName) }; 765 } 766 } 767 return new Node[] {}; 768 } 769 770 } 771 772 private static class DataShadowFilterNode extends FilterNode { 773 774 private String name; 775 776 public DataShadowFilterNode (Node or, org.openide.nodes.Children children, String name) { 777 super (or, children); 778 this.name = name; 779 disableDelegation(FilterNode.DELEGATE_SET_DISPLAY_NAME); 780 } 781 782 public String getDisplayName() { 783 return name; 784 } 785 786 } 787 788 private static class DefaultTemplateWizard extends TemplateWizard { 789 DefaultTemplateWizard() {} 790 } 791 792 private static final Node[] EMPTY_NODE_ARRAY = new Node[0]; 795 796 private class NodeLookupListener implements LookupListener { 797 798 public void resultChanged (org.openide.util.LookupEvent ev) { 799 updateAction (); 800 } 801 } 802 803 private void updateAction () {} 804 805 static private final synchronized Node[] getNodesFromLookup (Lookup lookup) { 806 if (lookup != null) { 807 return lookup.lookupAll(Node.class).toArray(EMPTY_NODE_ARRAY); 808 } 809 return EMPTY_NODE_ARRAY; 810 } 811 812 813 814 public Action createContextAwareInstance (Lookup actionContext) { 815 return new DelegateAction (this, actionContext); 816 } 817 818 private static final class DelegateAction extends Object 819 implements Action, Presenter.Popup, LookupListener { 820 821 private NewTemplateAction delegate; 822 private Lookup actionContext; 823 private Lookup.Result nodesResult; 824 825 private PropertyChangeSupport support = new PropertyChangeSupport (this); 826 827 public DelegateAction (NewTemplateAction action, Lookup actionContext) { 828 this.delegate = action; 829 this.actionContext = actionContext; 830 this.nodesResult = actionContext.lookupResult(Node.class); 831 nodesResult.addLookupListener (this); 836 resultChanged (null); 837 } 838 839 840 public String toString () { 841 return super.toString () + "[delegate=" + delegate + "]"; } 843 844 public void putValue (String key, Object value) { } 845 846 public boolean isEnabled () { 847 return delegate.enable (getNodesFromLookup (actionContext)); 848 } 849 850 public Object getValue (String key) { 851 return delegate.getValue (key); 852 } 853 854 public void setEnabled (boolean b) { 855 } 856 857 public void actionPerformed (ActionEvent e) { 858 } 859 860 public void addPropertyChangeListener (PropertyChangeListener listener) { 861 support.addPropertyChangeListener (listener); 862 } 863 864 public void removePropertyChangeListener (PropertyChangeListener listener) { 865 support.removePropertyChangeListener (listener); 866 } 867 868 public JMenuItem getPopupPresenter() { 869 return delegate.getPopupPresenter (actionContext, this); 870 } 871 872 public void resultChanged (org.openide.util.LookupEvent ev) { 873 getPopupPresenter (); 874 } 877 878 } 887 } 888 | Popular Tags |