001: package com.xoetrope.carousel.services.dialog;
002:
003: import java.util.Vector;
004:
005: import java.awt.BorderLayout;
006: import java.awt.Component;
007: import java.awt.event.MouseEvent;
008: import java.awt.event.MouseListener;
009: import javax.swing.JPanel;
010: import javax.swing.JScrollPane;
011: import javax.swing.JTree;
012: import javax.swing.SwingUtilities;
013: import javax.swing.border.EmptyBorder;
014: import javax.swing.event.TreeSelectionEvent;
015: import javax.swing.event.TreeSelectionListener;
016: import javax.swing.tree.DefaultMutableTreeNode;
017: import javax.swing.tree.TreeNode;
018: import javax.swing.tree.TreePath;
019:
020: import net.xoetrope.editor.project.pages.XComponentSizer;
021: import net.xoetrope.editor.project.pages.XPageResource;
022: import net.xoetrope.editor.XEditorDefaults;
023: import net.xoetrope.editor.project.pages.components.PropertyHelper;
024: import net.xoetrope.editor.project.pages.components.proxy.XComponentProxy;
025: import net.xoetrope.optional.data.sql.DatabaseTableModel;
026: import com.xoetrope.carousel.services.StaticDataEditor;
027: import net.xoetrope.editor.project.XEditorProject;
028: import net.xoetrope.editor.project.XEditorProjectManager;
029: import net.xoetrope.editor.project.pages.components.ComponentHelper;
030: import net.xoetrope.xui.data.XBaseModel;
031: import net.xoetrope.xui.data.XModel;
032:
033: /**
034: * Panel which contains the JTree representation of the XModel. The JTree is
035: * contained within a scrollpane. The model is updated as data items are added
036: * from the XLib editor. Whenever a component is seleted the setActiveComponents
037: * fuction is called with a Vector of type XComponentSizer so that the data node
038: * for the component can be selected. Double clicking a node will cause the
039: * currently selected components data property to be set.
040: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
041: * the GNU Public License (GPL), please see license.txt for more details. If
042: * you make commercial use of this software you must purchase a commercial
043: * license from Xoetrope.</p>
044: * <p> $Revision: 1.7 $</p>
045: */
046: public class XLibDataTree extends JPanel implements
047: TreeSelectionListener, MouseListener {
048: private DefaultMutableTreeNode topNode;
049: protected JTree dataTree;
050: private JScrollPane dataPane;
051: Vector currentComponents;
052: boolean debugging = false;
053: XModel tempModel;
054:
055: /**
056: * The owner project and the context in which this object operates.
057: */
058: protected XEditorProject currentProject = (XEditorProject) XEditorProjectManager
059: .getCurrentProject();
060:
061: /**
062: * Setup a BorderLayout manager. Call the function to create the tree with no
063: * selection.
064: */
065: public XLibDataTree(boolean debug) {
066: debugging = debug;
067: tempModel = currentProject.getModel();
068: setLayout(new BorderLayout());
069: createTreeComp("");
070: }
071:
072: public XLibDataTree() {
073: this (false);
074: }
075:
076: /**
077: * Reconstruct the tree. This is called when the model has been updated from
078: * the editor
079: */
080: public void refresh() {
081: createTreeComp("");
082: }
083:
084: /**
085: * If the tree already exists remove it from the panel. Get a reference to the
086: * XModel base node. Contruct a new JTree and call the createTree function
087: * with the selected parameter.
088: * @param selected the path to the seleted XModel node
089: */
090: public void createTreeComp(String selected) {
091: if (dataPane != null)
092: remove(dataPane);
093: XBaseModel model = (XBaseModel) currentProject.getModel();
094: topNode = new DefaultMutableTreeNode("Data");
095: dataTree = new JTree(topNode);
096: dataTree.addMouseListener(this );
097: dataTree.setCellRenderer(new XLibTreeCellRenderer(
098: StaticDataEditor.AMEND_SELECT));
099: dataTree.setFont(XEditorDefaults.defaultFont);
100: dataTree.setScrollsOnExpand(true);
101: createTree(selected);
102: dataTree.addTreeSelectionListener(this );
103: dataPane = new JScrollPane(dataTree);
104: dataPane.setBorder(new EmptyBorder(0, 0, 0, 0));
105: dataTree.setBorder(new EmptyBorder(0, 0, 0, 0));
106: add(dataPane, BorderLayout.CENTER);
107: doLayout();
108: repaint();
109: dataPane.doLayout();
110: dataPane.repaint();
111: }
112:
113: /**
114: * Remove all chidren from the topNode variable. Call createTreeNodes with the
115: * base XModel and the parent node. This in turn calls the addNode function
116: * recursively until all XModel children have been processed. Expand the root
117: * node by default.
118: * @param selected
119: * @return
120: */
121: private DefaultMutableTreeNode createTree(String selected) {
122: topNode.removeAllChildren();
123: createTreeNodes(currentProject.getModel(), topNode);
124: if (!debugging)
125: expandRoot();
126: return topNode;
127: }
128:
129: /**
130: * Loop all of the topNode children calling addNode.
131: * @param model the base XModel
132: * @param topNode the parent node of the JTree
133: */
134: void createTreeNodes(XModel model, DefaultMutableTreeNode topNode) {
135: for (int i = 0; i < model.getNumChildren(); i++) {
136: addNode(model.get(i), topNode);
137: }
138: }
139:
140: /**
141: * Create a new child node to be added to the parentNode parameter.
142: * @param model the XModel whose name will appear in the new treenode. This
143: * XModel's children is in turn passed to this function recursively building
144: * up the tree
145: * @param parentNode the tree node which is to be the parent of the new
146: * Treenode
147: */
148: void addNode(XModel model, DefaultMutableTreeNode parentNode) {
149: DefaultMutableTreeNode root = null;
150: String text;
151: if ((model.getTagName() != null)
152: && ((model.getTagName().compareTo("item") == 0) || (model
153: .getTagName().compareTo("td") == 0))) {
154: text = model.getId() + " ~ '" + model.get() + "'";
155: root = new DefaultMutableTreeNode(text);
156: parentNode.add(root);
157: } else {
158: text = model.getId();
159: if (debugging)
160: text += " ~ '" + model.get() + "'";
161:
162: root = new DefaultMutableTreeNode(text);
163: parentNode.add(root);
164: if (!(model instanceof DatabaseTableModel)) {
165: for (int i = 0; i < model.getNumChildren(); i++) {
166: addNode(model.get(i), root);
167: }
168: }
169: }
170: }
171:
172: public void valueChanged(TreeSelectionEvent evt) {
173:
174: }
175:
176: /**
177: * Get the path of the selected treenode by looping the selected path array
178: * and placing a '/' between each item
179: * @return the path to the selected XModel
180: */
181: String getTreePath() {
182: String modelName = null;
183: if (dataTree.getSelectionPath() != null) {
184: Object path[] = dataTree.getSelectionPath().getPath();
185:
186: modelName = "";
187: for (int i = 1; i < path.length; i++) {
188: modelName += "/" + path[i].toString();
189: }
190: }
191: if (modelName == null)
192: return "";
193: else if (modelName.trim().compareTo("") != 0)
194: return modelName.substring(1);
195: else
196: return "";
197: }
198:
199: /**
200: * Called whenever the components selection within the editor changes. We
201: * assign the passed vector to an object variable so that we can update the
202: * component when the tree is double clicked. First we need to cast the helper
203: * referenced by the XComponentSizer into the relevant type depending on the
204: * type of the selected component. We need then to find the property which
205: * corresponds to the 'data' property. When found we call setSelectedModel
206: * with the path to the XModel.
207: * @param comps Vector of type XComponentSizer. We can only work on this
208: * vector if it contains a single component.
209: */
210: public void setActiveComponents(Vector comps) {
211: currentComponents = comps;
212: setSelectedModel(null);
213: if (currentComponents == null || currentComponents.size() == 0)
214: return;
215:
216: XComponentSizer sizer = (XComponentSizer) currentComponents
217: .elementAt(0);
218:
219: XPageResource pageResource = sizer.getPageResource();
220: Component comp = sizer.getTarget();
221: Component targetComp = comp;
222: if (comp instanceof XComponentProxy) {
223: targetComp = ((XComponentProxy) comp).getProxiedComponent();
224: }
225: PropertyHelper helper = null;
226: if (targetComp.getClass().getName().indexOf("XEdit") > 0) {
227: helper = ComponentHelper.getPropertyHelper(targetComp);
228: //helper = new XEditHelper();
229: } else if (targetComp.getClass().getName().indexOf("XComboBox") > 0) {
230: helper = ComponentHelper.getPropertyHelper(targetComp);
231: //helper = new XComboBoxHelper();
232: }
233:
234: if (helper != null) {
235: for (int i = 0; i < helper.getNumProperties(comp); i++) {
236: String propName = helper.getPropertyName(i).toString();
237: if (propName.toString().compareTo("Data") == 0) {
238: String prop = helper.getPropertyValue(pageResource,
239: comp, propName).toString();
240: setSelectedModel(prop);
241: }
242: }
243: }
244: }
245:
246: /**
247: * Set the selected treenode of the datatree. If the parameter is null set the
248: * selectionPath to null. Otherwise create a new vector of treenodes and set
249: * the selectedpath to the vector.
250: * @param model the XModel which we want to select
251: */
252: public void setSelectedModel(String model) {
253: if (model == null) {
254: dataTree.setSelectionPath(null);
255: } else {
256: Vector nodes = new Vector();
257: nodes.add(topNode);
258: addNodes(nodes, topNode, model);
259: if (nodes.size() > 0) {
260: Object nodeArray[] = nodes.toArray();
261: TreePath path = new TreePath(nodeArray);
262: dataTree.setSelectionPath(path);
263: dataTree.scrollPathToVisible(path);
264: }
265: }
266: }
267:
268: /**
269: * Drill down the modelName using the '/' character as the tokenizer. For each
270: * token found iterate the child treenodes from the passed node until the one
271: * with the same name is found. Add it to the Vector and call recurse until
272: * there are no more childnodes
273: * @param nodes the Vector we want to build up
274: * @param node the TreeNode whose children we want to search for the
275: * corresponding model name
276: * @param modelName the path to the XModel
277: */
278: private void addNodes(Vector nodes, TreeNode node, String modelName) {
279: int pos = modelName.indexOf('/');
280: String subStyle = pos > 0 ? modelName.substring(0, pos)
281: : modelName;
282: int numChildren = node.getChildCount();
283: for (int i = 0; i < numChildren; i++) {
284: TreeNode childNode = node.getChildAt(i);
285: if (childNode.toString().indexOf(subStyle) >= 0) {
286: nodes.add(childNode);
287: if ((pos > 0) && (pos < modelName.length()))
288: addNodes(nodes, childNode, modelName
289: .substring(pos + 1));
290: break;
291: }
292: }
293: }
294:
295: /**
296: * Update the selected component if double clicked. Create a new helper
297: * depending on the type of control selected
298: * @param me
299: */
300: public void mouseClicked(MouseEvent me) {
301: if (me.getClickCount() > 1) {
302: String dataName = getTreePath();
303: if (currentComponents == null)
304: return;
305:
306: XComponentSizer sizer = (XComponentSizer) currentComponents
307: .elementAt(0);
308:
309: XPageResource pageResource = sizer.getPageResource();
310: Component comp = sizer.getTarget();
311: PropertyHelper helper = null;
312: if (comp.getClass().getName().indexOf("XEdit") > 0) {
313: helper = ComponentHelper.getPropertyHelper(comp);
314: //helper = new XEditHelper();
315: } else if (comp.getClass().getName().indexOf("XComboBox") > 0) {
316: helper = ComponentHelper.getPropertyHelper(comp);
317: //helper = new XComboBoxHelper();
318: }
319:
320: if (helper != null) {
321: for (int i = 0; i < helper.getNumProperties(comp); i++) {
322: String propName = helper.getPropertyName(i)
323: .toString();
324: if (propName.compareTo("Data") == 0) {
325: helper.setPropertyValue(pageResource, comp,
326: propName, dataName);
327: /** @todo fix this call */
328: // KalIDEoscope.getPageHolder().componentSized();
329: }
330: }
331: }
332: }
333: }
334:
335: public void mousePressed(MouseEvent me) {
336: }
337:
338: public void mouseReleased(MouseEvent me) {
339: }
340:
341: public void mouseExited(MouseEvent me) {
342: }
343:
344: public void mouseEntered(MouseEvent me) {
345: }
346:
347: /**
348: * expand the root node.
349: */
350: public void expandRoot() {
351: final TreePath path = new TreePath(topNode);
352: SwingUtilities.invokeLater(new Runnable() {
353: public void run() {
354: dataTree.expandPath(path);
355: dataTree.repaint();
356: }
357: });
358: }
359: }
|