1 19 20 package org.netbeans.modules.xml.xam.ui.customizer; 21 22 import java.awt.BorderLayout ; 23 import java.awt.event.MouseAdapter ; 24 import java.awt.event.MouseEvent ; 25 import java.beans.PropertyChangeEvent ; 26 import java.beans.PropertyChangeListener ; 27 import java.io.IOException ; 28 import java.lang.reflect.InvocationTargetException ; 29 import java.net.URI ; 30 import java.net.URISyntaxException ; 31 import java.util.ArrayList ; 32 import java.util.Collection ; 33 import java.util.HashMap ; 34 import java.util.LinkedList ; 35 import java.util.List ; 36 import java.util.Map ; 37 import java.util.Set ; 38 import javax.swing.ImageIcon ; 39 import javax.swing.tree.TreePath ; 40 import javax.swing.tree.TreeSelectionModel ; 41 import org.netbeans.api.project.FileOwnerQuery; 42 import org.netbeans.api.project.Project; 43 import org.netbeans.modules.xml.catalogsupport.DefaultProjectCatalogSupport; 44 import org.netbeans.modules.xml.xam.Component; 45 import org.netbeans.modules.xml.xam.Model; 46 import org.netbeans.modules.xml.xam.locator.CatalogModelException; 47 import org.netbeans.modules.xml.xam.ui.ModelCookie; 48 import org.netbeans.spi.project.ui.LogicalViewProvider; 49 import org.openide.ErrorManager; 50 import org.openide.explorer.ExplorerManager; 51 import org.openide.explorer.view.TreeTableView; 52 import org.openide.explorer.view.Visualizer; 53 import org.openide.filesystems.FileObject; 54 import org.openide.loaders.DataObject; 55 import org.openide.nodes.AbstractNode; 56 import org.openide.nodes.Children; 57 import org.openide.nodes.Node; 58 import org.openide.nodes.PropertySupport; 59 import org.openide.util.NbBundle; 60 import org.openide.util.Utilities; 61 62 69 public abstract class ExternalReferenceCreator<T extends Component> 70 extends AbstractReferenceCustomizer<T> 71 implements ExplorerManager.Provider, PropertyChangeListener { 72 73 private static final long serialVersionUID = 1L; 74 75 private Map <DataObject, NodeSet> registeredNodes; 76 77 private transient FileObject sourceFO; 78 79 private transient DefaultProjectCatalogSupport catalogSupport; 80 81 87 public ExternalReferenceCreator(T component, Model model) { 88 super(component); 89 registeredNodes = new HashMap <DataObject, NodeSet>(); 90 initComponents(); 91 sourceFO = (FileObject) component.getModel().getModelSource(). 92 getLookup().lookup(FileObject.class); 93 catalogSupport = DefaultProjectCatalogSupport.getInstance(sourceFO); 94 init(component, model); 95 TreeTableView locationView = new LocationView(); 97 locationView.setDefaultActionAllowed(false); 98 locationView.setPopupAllowed(false); 99 locationView.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 100 locationView.setRootVisible(false); 101 locationView.getAccessibleContext().setAccessibleName(locationLabel.getToolTipText()); 102 locationView.getAccessibleContext().setAccessibleDescription(locationLabel.getToolTipText()); 103 Node.Property[] columns = new Node.Property[] { 104 new Column(ExternalReferenceDataNode.PROP_NAME, String .class, true), 105 new ImportColumn(referenceTypeName()), 106 new Column(ExternalReferenceDataNode.PROP_PREFIX, String .class, false), 107 }; 108 locationView.setProperties(columns); 109 locationView.setTreePreferredWidth(200); 110 locationView.setTableColumnPreferredWidth(0, 25); 111 locationView.setTableColumnPreferredWidth(1, 25); 112 locationPanel.add(locationView, BorderLayout.CENTER); 113 explorerManager = new ExplorerManager(); 114 explorerManager.addPropertyChangeListener(this); 115 explorerManager.setRootContext(createRootNode()); 116 } 117 118 public void applyChanges() throws IOException { 119 List <Node> nodes = getSelectedNodes(); 120 for (Node node : nodes) { 121 if (node instanceof ExternalReferenceNode) { 122 Model model = ((ExternalReferenceNode) node).getModel(); 123 if (model != null && model != getModelComponent().getModel()) { 125 FileObject fileObj = (FileObject) model.getModelSource(). 126 getLookup().lookup(FileObject.class); 127 if (fileObj != null) { 128 try { 129 if (catalogSupport.needsCatalogEntry(sourceFO, fileObj)) { 130 URI uri = catalogSupport.getReferenceURI(sourceFO, fileObj); 132 catalogSupport.removeCatalogEntry(uri); 133 catalogSupport.createCatalogEntry(sourceFO, fileObj); 134 } 135 } catch (URISyntaxException use) { 136 ErrorManager.getDefault().notify(use); 137 } catch (IOException ioe) { 138 ErrorManager.getDefault().notify(ioe); 139 } catch (CatalogModelException cme) { 140 ErrorManager.getDefault().notify(cme); 141 } 142 } 143 } 144 } 145 } 146 } 147 148 154 protected abstract String getTargetNamespace(Model model); 155 156 161 protected List <Node> getSelectedNodes() { 162 List <Node> results = new LinkedList <Node>(); 163 Collection <NodeSet> sets = registeredNodes.values(); 164 for (NodeSet set : sets) { 165 if (set.isSelected()) { 166 List <ExternalReferenceDataNode> nodes = set.getNodes(); 167 if (nodes.size() > 0) { 168 results.add(nodes.get(0)); 171 } 172 } 173 } 174 return results; 175 } 176 177 182 private boolean isValidPrefix(ExternalReferenceDataNode node) { 183 DataObject dobj = (DataObject) node.getLookup().lookup(DataObject.class); 184 NodeSet nodeSet = registeredNodes.get(dobj); 185 Collection <NodeSet> sets = registeredNodes.values(); 186 for (NodeSet set : sets) { 187 if (!set.equals(nodeSet) && set.isSelected()) { 190 ExternalReferenceDataNode other = set.getNodes().get(0); 193 if (node.getPrefix().equals(other.getPrefix())) { 194 return false; 195 } 196 } 197 } 198 return true; 199 } 200 201 207 private int countSelectedNodes() { 208 int results = 0; 209 Collection <NodeSet> sets = registeredNodes.values(); 210 for (NodeSet set : sets) { 211 if (set.isSelected()) { 212 List <ExternalReferenceDataNode> nodes = set.getNodes(); 213 if (nodes.size() > 0) { 214 results++; 215 } 216 } 217 } 218 return results; 219 } 220 221 227 protected abstract Map <String , String > getPrefixes(Model model); 228 229 234 protected abstract ExternalReferenceDecorator getNodeDecorator(); 235 236 244 public abstract boolean mustNamespaceDiffer(); 245 246 254 protected abstract String referenceTypeName(); 255 256 264 protected void init(T component, Model model) { 265 } 268 269 protected void initializeUI() { 270 if (!mustNamespaceDiffer()) { 271 namespaceLabel.setVisible(false); 272 namespaceTextField.setVisible(false); 273 } 274 } 275 276 public ExternalReferenceDataNode createExternalReferenceNode(Node original) { 277 DataObject dobj = (DataObject) original.getLookup().lookup(DataObject.class); 278 NodeSet set = registeredNodes.get(dobj); 279 if (set == null) { 280 set = new NodeSet(this); 281 registeredNodes.put(dobj, set); 282 } 283 ExternalReferenceDataNode erdn = new ExternalReferenceDataNode( 284 original, getNodeDecorator()); 285 set.add(erdn); 286 if (set.isSelected() && erdn.canSelect()) { 287 erdn.setSelected(true); 288 } 289 erdn.addPropertyChangeListener(this); 290 return erdn; 291 } 292 293 301 protected boolean allowEmptySelection() { 302 return false; 304 } 305 306 313 private void validateInput(ExternalReferenceNode node) { 314 String msg = null; 315 if (mustNamespaceDiffer() && node instanceof ExternalReferenceDataNode) { 316 ExternalReferenceDataNode erdn = (ExternalReferenceDataNode) node; 317 Map <String , String > prefixMap = getPrefixes(getModelComponent().getModel()); 318 String ep = erdn.getPrefix(); 319 if (ep.length() == 0 || prefixMap.containsKey(ep) || 322 (!isValidPrefix(erdn) && erdn.isSelected())) { 323 msg = NbBundle.getMessage(ExternalReferenceCreator.class, 324 "LBL_ExternalReferenceCreator_InvalidPrefix"); 325 } 326 } 327 if (node instanceof RetrievedFilesChildren.RetrievedFileNode) { 328 RetrievedFilesChildren.RetrievedFileNode rNode = 329 (RetrievedFilesChildren.RetrievedFileNode) node; 330 if (!rNode.isValid()) { 331 msg = NbBundle.getMessage(ExternalReferenceCreator.class, 332 "LBL_ExternalReferenceCreator_InvalidCatalogEntry"); 333 } 334 } 335 if (msg != null) { 336 showMessage(msg); 337 } 338 int selected = countSelectedNodes(); 339 setSaveEnabled((allowEmptySelection() || selected > 0) && msg == null); 341 } 342 343 protected void showMessage(String msg) { 344 if (msg == null) { 345 messageLabel.setText(" "); 346 messageLabel.setIcon(null); 347 } else { 348 messageLabel.setText(msg); 349 messageLabel.setIcon(new ImageIcon (Utilities.loadImage( 351 "org/openide/resources/error.gif"))); } 353 } 354 355 359 private class LocationView extends TreeTableView { 360 361 private static final long serialVersionUID = 1L; 362 363 366 public LocationView() { 367 super(); 368 tree.addMouseListener(new MouseAdapter () { 369 public void mouseClicked(MouseEvent e) { 370 TreePath path = tree.getPathForLocation(e.getX(), e.getY()); 373 if (path != null) { 374 Object comp = path.getLastPathComponent(); 375 Node node = Visualizer.findNode(comp); 376 if (node instanceof ExternalReferenceDataNode) { 377 ExternalReferenceDataNode erdn = 378 (ExternalReferenceDataNode) node; 379 if (erdn.canSelect()) { 380 boolean selected = !erdn.isSelected(); 381 String ns = null; 382 if (selected) { 383 Model model = erdn.getModel(); 386 if (model != null) { 387 ns = getTargetNamespace(model); 388 } 389 } 390 namespaceTextField.setText(ns); 395 erdn.setSelected(selected); 396 } 397 } 398 } 399 } 400 }); 401 } 402 } 403 404 protected Node createRootNode() { 405 Set refProjects = null; 406 if (catalogSupport.supportsCrossProject()) { 407 refProjects = catalogSupport.getProjectReferences(); 408 } 409 ExternalReferenceDecorator decorator = getNodeDecorator(); 410 Node[] rootNodes = new Node[1 + (refProjects == null ? 0 : refProjects.size())]; 411 Project prj = FileOwnerQuery.getOwner(sourceFO); 412 LogicalViewProvider viewProvider = (LogicalViewProvider) prj.getLookup(). 413 lookup(LogicalViewProvider.class); 414 rootNodes[0] = decorator.createExternalReferenceNode( 415 viewProvider.createLogicalView()); 416 int rootIndex = 1; 417 List <FileObject> projectRoots = new ArrayList <FileObject>(); 418 projectRoots.add(prj.getProjectDirectory()); 419 if (refProjects != null) { 420 for (Object o : refProjects) { 421 Project refPrj = (Project) o; 422 viewProvider = (LogicalViewProvider) refPrj.getLookup(). 423 lookup(LogicalViewProvider.class); 424 rootNodes[rootIndex++] = decorator.createExternalReferenceNode( 425 viewProvider.createLogicalView()); 426 projectRoots.add(refPrj.getProjectDirectory()); 427 } 428 } 429 FileObject[] roots = projectRoots.toArray( 430 new FileObject[projectRoots.size()]); 431 Children fileChildren = new Children.Array(); 432 fileChildren.add(rootNodes); 433 Node byFilesNode = new FolderNode(fileChildren); 434 byFilesNode.setDisplayName(NbBundle.getMessage( 435 ExternalReferenceCreator.class, 436 "LBL_ExternalReferenceCreator_Category_By_File")); 437 438 Children nsChildren = new NamespaceChildren(roots, decorator); 440 Node byNsNode = new FolderNode(nsChildren); 441 byNsNode.setDisplayName(NbBundle.getMessage( 442 ExternalReferenceCreator.class, 443 "LBL_ExternalReferenceCreator_Category_By_Namespace")); 444 Children categories = new Children.Array(); 458 categories.add(new Node[] { byFilesNode, byNsNode }); 460 Node rootNode = new AbstractNode(categories); 461 rootNode.setDisplayName(NbBundle.getMessage(ExternalReferenceCreator.class, 463 "CTL_ExternalReferenceCreator_Column_Name_name")); 464 rootNode.setShortDescription(NbBundle.getMessage(ExternalReferenceCreator.class, 465 "CTL_ExternalReferenceCreator_Column_Desc_name")); 466 return rootNode; 467 } 468 469 481 public void propertyChange(PropertyChangeEvent event) { 482 String pname = event.getPropertyName(); 483 if (ExplorerManager.PROP_SELECTED_NODES.equals(pname)) { 484 showMessage(null); 485 Node[] nodes = (Node[]) event.getNewValue(); 486 if (nodes != null && nodes.length > 0 && 488 nodes[0] instanceof ExternalReferenceNode) { 489 ExternalReferenceNode node = (ExternalReferenceNode) nodes[0]; 490 Model model = node.getModel(); 491 if (model != null) { 493 String msg = getNodeDecorator().validate(node); 495 if (msg != null) { 496 showMessage(msg); 497 } else { 498 validateInput(node); 500 } 501 } 502 } 503 } else if (pname.equals(ExternalReferenceDataNode.PROP_PREFIX)) { 504 ExternalReferenceDataNode erdn = 505 (ExternalReferenceDataNode) event.getSource(); 506 String prefix = (String ) event.getNewValue(); 509 DataObject dobj = (DataObject) erdn.getLookup().lookup(DataObject.class); 510 NodeSet set = registeredNodes.get(dobj); 511 assert set != null : "node not created by customizer"; 513 if (set == null) { 514 set = new NodeSet(this); 515 set.add(erdn); 516 } 517 set.setPrefix(prefix); 518 validateInput(erdn); 519 } else if (pname.equals(ExternalReferenceDataNode.PROP_SELECTED)) { 520 ExternalReferenceDataNode erdn = 521 (ExternalReferenceDataNode) event.getSource(); 522 boolean selected = ((Boolean ) event.getNewValue()).booleanValue(); 525 DataObject dobj = (DataObject) erdn.getLookup().lookup(DataObject.class); 526 NodeSet set = registeredNodes.get(dobj); 527 assert set != null : "node not created by customizer"; 529 if (set == null) { 530 set = new NodeSet(this); 531 set.add(erdn); 532 } 533 set.setSelected(selected); 534 validateInput(erdn); 536 } 537 } 538 539 545 protected String getLocation(Node node) { 546 String location = null; 547 if (node instanceof RetrievedFilesChildren.RetrievedFileNode) { 548 RetrievedFilesChildren.RetrievedFileNode rNode = 549 (RetrievedFilesChildren.RetrievedFileNode) node; 550 if (rNode.isValid()) { 551 String ns = rNode.getNamespace(); 552 if (ns == null || mustNamespaceDiffer() != 553 ns.equals(getTargetNamespace())) { 554 location = rNode.getLocation(); 555 } 556 } 557 } else { 558 DataObject dobj = (DataObject) node.getLookup(). 559 lookup(DataObject.class); 560 if (dobj != null && dobj.isValid()) { 561 FileObject fileObj = dobj.getPrimaryFile(); 562 ModelCookie cookie = (ModelCookie) dobj.getCookie( 563 ModelCookie.class); 564 Model model; 565 try { 566 if (cookie != null && (model = cookie.getModel()) != 567 getModelComponent().getModel()) { 568 String ns = getTargetNamespace(model); 569 if (ns == null || mustNamespaceDiffer() != 570 ns.equals(getTargetNamespace())) { 571 return catalogSupport.getReferenceURI( 572 sourceFO, fileObj).toString(); 573 } 574 } 575 } catch (URISyntaxException urise) { 576 ErrorManager.getDefault().notify(urise); 577 } catch (IOException ioe) { 578 ErrorManager.getDefault().notify(ioe); 579 } 580 } 581 } 582 if (location != null) { 583 try { 584 URI uri = new URI ("file", location, null); 585 uri = uri.normalize(); 586 location = uri.getRawSchemeSpecificPart(); 587 } catch (URISyntaxException use) { 588 showMessage(use.toString()); 589 } 591 } 592 return location; 593 } 594 595 601 protected String getNamespace(Node node) { 602 String ns = null; 603 if (node instanceof RetrievedFilesChildren.RetrievedFileNode) { 604 RetrievedFilesChildren.RetrievedFileNode rNode = 605 (RetrievedFilesChildren.RetrievedFileNode) node; 606 if (!rNode.isValid()) { 607 return null; 608 } 609 ns = rNode.getNamespace(); 610 } else { 611 DataObject dobj = (DataObject) node.getLookup(). 612 lookup(DataObject.class); 613 if (dobj != null && dobj.isValid()) { 614 ModelCookie cookie = (ModelCookie) dobj.getCookie( 615 ModelCookie.class); 616 Model model; 617 try { 618 if (cookie != null && (model = cookie.getModel()) != 619 getModelComponent().getModel()) { 620 ns = getTargetNamespace(model); 621 } 622 } catch (IOException ioe) { 623 } 625 } 626 } 627 return ns; 628 } 629 630 public ExplorerManager getExplorerManager() { 631 return explorerManager; 632 } 633 634 639 protected class Column extends PropertySupport.ReadOnly { 640 641 private String key; 642 643 650 public Column(String key, Class type, boolean tree) { 651 super(key, type, 652 NbBundle.getMessage(Column.class, 653 "CTL_ExternalReferenceCreator_Column_Name_" + key), 654 NbBundle.getMessage(Column.class, 655 "CTL_ExternalReferenceCreator_Column_Desc_" + key)); 656 this.key = key; 657 setValue("TreeColumnTTV", Boolean.valueOf(tree)); 658 } 659 660 public Object getValue() 661 throws IllegalAccessException , InvocationTargetException { 662 return key; 663 } 664 } 665 666 671 protected class ImportColumn extends PropertySupport.ReadOnly { 672 673 private String key; 674 675 680 public ImportColumn(String name) { 681 super("selected", Boolean.TYPE, name, 682 NbBundle.getMessage(Column.class, 683 "CTL_ExternalReferenceCreator_Column_Desc_selected")); 684 this.key = "selected"; 685 setValue("TreeColumnTTV", Boolean.FALSE); 686 } 687 688 public Object getValue() 689 throws IllegalAccessException , InvocationTargetException { 690 return key; 691 } 692 } 693 694 697 private static class NodeSet { 698 699 private PropertyChangeListener listener; 700 701 private List <ExternalReferenceDataNode> nodes; 702 703 private boolean selected; 704 705 710 public NodeSet(PropertyChangeListener listener) { 711 this.listener = listener; 712 } 713 714 719 public void add(ExternalReferenceDataNode node) { 720 if (nodes == null) { 721 nodes = new LinkedList <ExternalReferenceDataNode>(); 722 } 723 nodes.add(node); 724 } 725 726 731 public List <ExternalReferenceDataNode> getNodes() { 732 return nodes; 733 } 734 735 740 public boolean isSelected() { 741 return selected; 742 } 743 744 749 public void setPrefix(String prefix) { 750 for (ExternalReferenceDataNode node : nodes) { 751 if (!node.getPrefix().equals(prefix)) { 752 node.removePropertyChangeListener(listener); 753 node.setPrefix(prefix); 754 node.addPropertyChangeListener(listener); 755 } 756 } 757 } 758 759 764 public void setSelected(boolean select) { 765 selected = select; 766 for (ExternalReferenceDataNode node : nodes) { 767 if (node.canSelect()) { 768 node.removePropertyChangeListener(listener); 769 node.setSelected(select); 770 node.addPropertyChangeListener(listener); 771 } 772 } 773 } 774 } 775 776 782 private void initComponents() { 784 locationLabel = new javax.swing.JLabel (); 785 locationPanel = new javax.swing.JPanel (); 786 namespaceLabel = new javax.swing.JLabel (); 787 namespaceTextField = new javax.swing.JTextField (); 788 messageLabel = new javax.swing.JLabel (); 789 790 locationLabel.setLabelFor(locationPanel); 791 org.openide.awt.Mnemonics.setLocalizedText(locationLabel, java.util.ResourceBundle.getBundle("org/netbeans/modules/xml/xam/ui/customizer/Bundle").getString("LBL_ExternalReferenceCreator_Location")); 792 locationLabel.setToolTipText(java.util.ResourceBundle.getBundle("org/netbeans/modules/xml/xam/ui/customizer/Bundle").getString("TIP_ExternalReferenceCreator_Location")); 793 794 locationPanel.setLayout(new java.awt.BorderLayout ()); 795 796 locationPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); 797 798 namespaceLabel.setLabelFor(namespaceTextField); 799 org.openide.awt.Mnemonics.setLocalizedText(namespaceLabel, java.util.ResourceBundle.getBundle("org/netbeans/modules/xml/xam/ui/customizer/Bundle").getString("LBL_ExternalReferenceCreator_Namespace")); 800 namespaceLabel.setToolTipText(java.util.ResourceBundle.getBundle("org/netbeans/modules/xml/xam/ui/customizer/Bundle").getString("TIP_ExternalReferenceCreator_Namespace")); 801 802 namespaceTextField.setEditable(false); 803 804 messageLabel.setForeground(new java.awt.Color (255, 0, 0)); 805 org.openide.awt.Mnemonics.setLocalizedText(messageLabel, " "); 806 807 org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this); 808 this.setLayout(layout); 809 layout.setHorizontalGroup( 810 layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) 811 .add(layout.createSequentialGroup() 812 .addContainerGap() 813 .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) 814 .add(locationPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE) 815 .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() 816 .add(namespaceLabel) 817 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 818 .add(namespaceTextField, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE)) 819 .add(locationLabel) 820 .add(messageLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE)) 821 .addContainerGap()) 822 ); 823 layout.setVerticalGroup( 824 layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) 825 .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() 826 .addContainerGap() 827 .add(locationLabel) 828 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 829 .add(locationPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 329, Short.MAX_VALUE) 830 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 831 .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) 832 .add(namespaceLabel) 833 .add(namespaceTextField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) 834 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 835 .add(messageLabel) 836 .addContainerGap()) 837 ); 838 } 840 public javax.swing.JLabel locationLabel; 842 public javax.swing.JPanel locationPanel; 843 public javax.swing.JLabel messageLabel; 844 public javax.swing.JLabel namespaceLabel; 845 public javax.swing.JTextField namespaceTextField; 846 } 848 | Popular Tags |