/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.mappingsplugin.ui.xml; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultTreeSelectionModel; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import org.eclipse.persistence.tools.workbench.framework.context.WorkbenchContext; import org.eclipse.persistence.tools.workbench.framework.resources.ResourceRepository; import org.eclipse.persistence.tools.workbench.framework.ui.dialog.AbstractDialog; import org.eclipse.persistence.tools.workbench.framework.uitools.SwingComponentFactory; import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWElementDeclaration; import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWNamespace; import org.eclipse.persistence.tools.workbench.mappingsmodel.schema.MWXmlSchema; import org.eclipse.persistence.tools.workbench.uitools.Displayable; import org.eclipse.persistence.tools.workbench.uitools.app.AbstractTreeNodeValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.ListValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.NullListValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.PropertyValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.SimpleListValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.SimplePropertyValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.SortedListValueModelAdapter; import org.eclipse.persistence.tools.workbench.uitools.app.TransformationListValueModelAdapter; import org.eclipse.persistence.tools.workbench.uitools.app.TreeNodeValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.swing.TreeModelAdapter; import org.eclipse.persistence.tools.workbench.uitools.cell.DisplayableTreeCellRenderer; import org.eclipse.persistence.tools.workbench.utility.CollectionTools; /** * This dialog presents a tree of the available root elements * within the provided schema. * This dialog is pretty much only a tree to make it similar to * other schema component choosers. * If the dialog is confirmed, the value of the passed in element * holder will be set with the value of the selected element. * <p> * Here is the layout of the dialog: * <pre> * ________________________________________ * | | * | Title | * |______________________________________| * | ____________________________________ | * | | element1 |^| | * | | element2 | | | * | | element3 | | | * | | | | | * | | | | | * | | | | | * | | |v| | * | ------------------------------------ | * |______________________________________| * | ________ ________ | * | | OK | |Cancel| | * | -------- -------- | * ----------------------------------------</pre> * */ final class SchemaRootElementChooserDialog extends AbstractDialog { /** Schema passed to this dialog */ private MWXmlSchema schema; /** PropertyValueModel passed to this dialog within which the root element is set */ private PropertyValueModel rootElementHolder; /** PropertyValueModel used internally to keep track of selected root element */ private PropertyValueModel selectedRootElementHolder; /** The tree selection model */ private TreeSelectionModel treeSelectionModel; //***************** Constructors ****************************************** SchemaRootElementChooserDialog(WorkbenchContext context, MWXmlSchema schema, PropertyValueModel rootElementHolder) { super(context); this.initialize(schema, rootElementHolder); } //***************** Initialization **************************************** protected void initialize() { super.initialize(); // initialize dialog settings this.setTitle(this.resourceRepository().getString("SCHEMA_ROOT_ELEMENT_CHOOSER_DIALOG.TITLE")); this.getOKAction().setEnabled(false); } private void initialize(MWXmlSchema schema, PropertyValueModel rootElementHolder) { this.schema = schema; this.rootElementHolder = rootElementHolder; this.selectedRootElementHolder = this.buildSelectedRootElementHolder(); this.treeSelectionModel = this.buildTreeSelectionModel(); } private PropertyValueModel buildSelectedRootElementHolder() { PropertyValueModel selectedRootElementHolder = new SimplePropertyValueModel(null); selectedRootElementHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.buildSelectedRootElementListener()); return selectedRootElementHolder; } private PropertyChangeListener buildSelectedRootElementListener() { return new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { SchemaRootElementChooserDialog.this.getOKAction().setEnabled(evt.getNewValue() != null); } }; } private TreeSelectionModel buildTreeSelectionModel() { TreeSelectionModel treeSelectionModel = new DefaultTreeSelectionModel(); treeSelectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); treeSelectionModel.addTreeSelectionListener(this.buildTreeSelectionListener()); return treeSelectionModel; } private TreeSelectionListener buildTreeSelectionListener() { return new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent tse) { SchemaRootElementChooserDialog.this.treeSelectionChanged(); } }; } protected Component buildMainPanel() { JPanel panel = new JPanel(new BorderLayout()); panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); panel.setPreferredSize(new Dimension(350, 350)); // build the tree panel.add(this.buildTreePane(), BorderLayout.CENTER); return panel; } private JScrollPane buildTreePane() { return new JScrollPane(this.buildTree()); } private JTree buildTree() { JTree tree = SwingComponentFactory.buildTree(this.buildTreeModel()); tree.setSelectionModel(this.treeSelectionModel); tree.setCellRenderer(this.buildTreeCellRenderer()); tree.setRootVisible(false); tree.setShowsRootHandles(true); tree.setRowHeight(20); tree.setDoubleBuffered(true); tree.expandRow(0); return tree; } private TreeModelAdapter buildTreeModel() { return new TreeModelAdapter(this.buildTreeRoot()); } private SchemaNode buildTreeRoot() { return new SchemaNode(this.schema); } private TreeCellRenderer buildTreeCellRenderer() { return new DisplayableTreeCellRenderer(); } // **************** Internal ********************************************** private void treeSelectionChanged() { TreePath selectedPath = this.treeSelectionModel.getSelectionPath(); Object newElement = null; if (selectedPath != null) { newElement = ((RootElementNode) this.treeSelectionModel.getSelectionPath().getLastPathComponent()).getValue(); } this.selectedRootElementHolder.setValue(newElement); } public MWElementDeclaration selectedRootElement() { return (MWElementDeclaration) this.selectedRootElementHolder.getValue(); } // **************** AbstractDialog contract ******************************* protected void okConfirmed() { this.rootElementHolder.setValue(this.selectedRootElementHolder.getValue()); super.okConfirmed(); } protected String helpTopicId() { return "dialog.schemaRootElementChooser"; } // **************** Behavior ********************************************** public void show() { if (this.schema == null) { this.showErrorDialog(); } else { super.show(); } } private void showErrorDialog() { Component currentWindow = this.currentWindow(); ResourceRepository repo = this.resourceRepository(); String errorTitle = repo.getString("SCHEMA_ROOT_ELEMENT_CHOOSER_DIALOG.NO_CONTEXT_SPECIFIED_TITLE"); String errorMessage = repo.getString("SCHEMA_ROOT_ELEMENT_CHOOSER_DIALOG.NO_CONTEXT_SPECIFIED_MESSAGE"); JOptionPane.showMessageDialog(currentWindow, errorMessage, errorTitle, JOptionPane.WARNING_MESSAGE); } // **************** Member classes **************************************** private final static class SchemaNode extends AbstractTreeNodeValueModel implements Displayable { // **************** Instance variables ************************************ /** The schema for this node. */ private MWXmlSchema schema; /** The children of this node. */ private ListValueModel childrenModel; // **************** Constructors ****************************************** public SchemaNode(MWXmlSchema schema) { super(); this.initialize(schema); } // **************** Initialization **************************************** private void initialize(MWXmlSchema schema) { this.schema = schema; this.childrenModel = this.buildChildrenModel(); } private ListValueModel buildChildrenModel() { return new SortedListValueModelAdapter(this.buildRootElementNodesAdapter()); } private ListValueModel buildRootElementNodesAdapter() { return new TransformationListValueModelAdapter(this.buildRootElementsAdapter()) { protected Object transformItem(Object item) { return SchemaNode.this.buildRootElementNode((MWElementDeclaration) item); } }; } private ListValueModel buildRootElementsAdapter() { return new SimpleListValueModel(CollectionTools.list(this.schema.rootElements())); } private RootElementNode buildRootElementNode(MWElementDeclaration element) { return new RootElementNode(this, element); } // **************** ValueModel contract *********************************** public Object getValue() { return this.schema; } // **************** TreeNodeValueModel contract *************************** public TreeNodeValueModel getParent() { return null; } public ListValueModel getChildrenModel() { return this.childrenModel; } // ********** AbstractTreeNodeValueModel implementation ********** protected void engageValue() {} protected void disengageValue() {} // **************** Comparable contract *********************************** public int compareTo(Object o) { return DEFAULT_COMPARATOR.compare(this, o); } // **************** Displayable contract ********************************** public String displayString() { return null; } public Icon icon() { return null; } } private final static class RootElementNode extends AbstractTreeNodeValueModel implements Displayable { // **************** Instance Variables ************************************ /** The parent of this node */ private AbstractTreeNodeValueModel parent; /** The element for this node. */ private MWElementDeclaration element; // **************** Constructors ****************************************** RootElementNode(AbstractTreeNodeValueModel parent, MWElementDeclaration element) { super(); this.initialize(parent, element); } // **************** Initialization **************************************** private void initialize(AbstractTreeNodeValueModel parent, MWElementDeclaration element) { this.parent = parent; this.element = element; } // **************** ValueModel contract *********************************** public Object getValue() { return this.element; } // **************** TreeNodeValueModel contract *************************** public TreeNodeValueModel getParent() { return this.parent; } public ListValueModel getChildrenModel() { return NullListValueModel.instance(); } // ********** AbstractTreeNodeValueModel implementation ********** protected void engageValue() {} protected void disengageValue() {} // **************** Comparable contract *********************************** public int compareTo(Object o) { return RootElementNodeComparator.compare(this, o); } // **************** Displayable contract ********************************** public String displayString() { return this.element.qName(); } public Icon icon() { return null; } // **************** Member classes **************************************** private static class RootElementNodeComparator { /** * Sort nodes first by namespace (root namespace first, then alphabetically by prefix), * then by prefixed name. */ public static int compare(Object o1, Object o2) { RootElementNode node1 = (RootElementNode) o1; RootElementNode node2 = (RootElementNode) o2; MWElementDeclaration element1 = node1.element; MWElementDeclaration element2 = node2.element; int comparison = compare(element1.getTargetNamespace(), element2.getTargetNamespace()); if (comparison == 0) { comparison = element1.qName().compareTo(element2.qName()); } return comparison; } private static int compare(MWNamespace thisNamespace, MWNamespace otherNamespace) { if (thisNamespace.isTargetNamespace() && ! otherNamespace.isTargetNamespace()) { return -1; } else if (! thisNamespace.isTargetNamespace() && otherNamespace.isTargetNamespace()) { return 1; } else if(thisNamespace.getNamespacePrefix() != otherNamespace.getNamespacePrefix()) { return thisNamespace.getNamespacePrefix().compareToIgnoreCase(otherNamespace.getNamespacePrefix()); } else { return 0; } } } } }