View Javadoc

1   /*
2   
3   nextobjects Copyright (C) 2001-2005 Emmanuel Florent
4   
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by the
7   Free Software Foundation; either version 2 of the License, or (at your
8   option) any later version.
9   
10  This program is distributed in the hope that it will
11  be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12  of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13  PURPOSE. See the GNU General Public License for more details.
14  
15  You should have received a copy of the GNU General Public License along
16  with this program; if not, write to the Free Software Foundation, Inc., 59
17  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  
19  */
20  package org.devaki.nextobjects.ui.main;
21  
22  import java.awt.Component;
23  import java.awt.GridBagConstraints;
24  import java.awt.GridBagLayout;
25  import java.awt.Insets;
26  import java.awt.event.MouseEvent;
27  import javax.swing.JPanel;
28  import javax.swing.JScrollPane;
29  import javax.swing.JTree;
30  import javax.swing.event.MouseInputAdapter;
31  import javax.swing.tree.DefaultMutableTreeNode;
32  import javax.swing.tree.DefaultTreeCellEditor;
33  import javax.swing.tree.DefaultTreeCellRenderer;
34  import javax.swing.tree.DefaultTreeModel;
35  import javax.swing.tree.TreeNode;
36  import javax.swing.tree.TreePath;
37  import javax.swing.tree.TreeSelectionModel;
38  import org.devaki.nextobjects.constants.CstImages;
39  import org.devaki.nextobjects.ui.components.CustomTreeNode;
40  import org.devaki.nextobjects.ui.menus.TreePopupMenu;
41  import org.devaki.nextobjects.ui.workspace.models.EditorFactory;
42  import org.devaki.nextobjects.util.ModelMan;
43  import org.devaki.nextobjects.workspace.models.ConceptualModel;
44  import org.devaki.nextobjects.workspace.models.PhysicalModel;
45  import org.devaki.nextobjects.workspace.models.columns.Column;
46  import org.devaki.nextobjects.workspace.models.objects.Association;
47  import org.devaki.nextobjects.workspace.models.objects.BaseClass;
48  import org.devaki.nextobjects.workspace.models.objects.BaseObject;
49  import org.devaki.nextobjects.workspace.models.objects.Constraint;
50  import org.devaki.nextobjects.workspace.models.objects.Entity;
51  import org.devaki.nextobjects.workspace.models.objects.Table;
52  import org.devaki.nextobjects.workspace.models.objects.InheritanceLink;
53  
54  /***
55   * The tree containing the hierarchy of the objects in the current
56   * workspace (project
57   */
58  public class NOTreeView extends JPanel
59  {
60      /*** 
61      *Local reference of the object
62      */
63      private NOTreeView me;
64  
65      /***
66       * Node objects
67       */
68      private Object object;
69  
70      /***
71       * A parent node
72       */
73      private Object objectParent;
74  
75      /*** 
76       * the tree model 
77       **/
78      private static NOTreeModel treeModel;
79  
80      /***
81       * The cell renderer to edit name of classes and fields
82       */
83      private NOTreeCellRenderer jTreeRenderer= new NOTreeCellRenderer();
84  
85      /***
86       * Another node
87       */
88      private DefaultMutableTreeNode root;
89  
90      /***
91       * The JTree
92       */
93      private static JTree jTree;
94  
95      /***
96       * Reference to the popup menu
97       */
98      private TreePopupMenu pop= new TreePopupMenu();
99  
100     /***
101      * Construct a new 'NOTreeView' object
102      */
103     public NOTreeView()
104     {
105         super(new GridBagLayout());
106 
107         // Initialization
108         this.me= this;
109         // Components 
110         // Define the root node
111         root= new CustomTreeNode("Workspace");
112         // Set the tree model
113         treeModel= new NOTreeModel(root);
114         // Create a 'JTree' object based on this model
115         jTree= new JTree(treeModel);
116         // Set the 'JTree' line style to 'Angled'
117         jTree.putClientProperty("JTree.lineStyle", "Angled");
118         // Specify the cell renderer and the cell editor for the 'JTree' object
119         jTree.setCellRenderer(this.jTreeRenderer);
120         jTree.setCellEditor(new NOTreeCellEditor());
121 
122         // Specify the selection mode for this 'JTree' object
123         jTree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
124         // Specify that the 'JTree' object can be edited
125         jTree.setEditable(true);
126 
127         //Listeners
128         jTree.addMouseListener(new MouseInputAdapter()
129         {
130             // Actions to perform when clicking in the tree
131             public void mouseClicked(MouseEvent e)
132             {
133                 if (jTree.getSelectionPath() != null)
134                 {
135                     // Get the objet associated to the node that has been clicked
136                     object= ((CustomTreeNode) jTree.getSelectionPath().getLastPathComponent()).getUserObject();
137 
138                     // Get the parent objet associated to the node that has been clicked
139                     if (((CustomTreeNode) jTree.getSelectionPath().getLastPathComponent()).getParent() != null)
140                     {
141                         objectParent=
142                             ((CustomTreeNode) ((CustomTreeNode) jTree.getSelectionPath().getLastPathComponent())
143                                 .getParent())
144                                 .getUserObject();
145                     }
146                     // set the selected object
147                     //if (!(object instanceof Column)&&!(object instanceof String)) {
148                     if (object instanceof BaseObject)
149                     {
150                         if (e.isControlDown())
151                         {
152                             ModelMan.addCurrentObject((BaseObject) object);
153                         }
154                         else
155                         {
156                             ModelMan.setCurrentObject((BaseObject) object);
157                         }
158                     }
159 
160                     //Editor Factory
161 
162                     // If the clicked node is an Entity from a Conceptual Data Model
163                     if (object instanceof Entity)
164                     {
165                         if (e.getClickCount() == 2)
166                         {
167                             EditorFactory.getEntityEdit((Entity) ModelMan.getCurrentObject());
168                         }
169                     }
170 
171                     // If the clicked node is an Association from a Conceptual Data Model
172                     else if (object instanceof Association)
173                     {
174                         if (e.getClickCount() == 2)
175                         {
176                             EditorFactory.getAssociationEdit((Association) ModelMan.getCurrentObject());
177                         }
178                     }
179 
180                     // If the clicked node is a Table from a Physical Data Model
181                     else if (object instanceof Table)
182                     {
183                         if (e.getClickCount() == 2)
184                         {
185                             EditorFactory.getTableEdit((Table) ModelMan.getCurrentObject());
186                         }
187                     }
188 
189                     // If the clicked node is a Constraint from a Physical Data Model
190                     else if (object instanceof Constraint)
191                     {
192                         if (e.getClickCount() == 2)
193                         {
194                             EditorFactory.getConstraintEdit((Constraint) ModelMan.getCurrentObject());
195                         }
196                     }
197 
198                     // If the clicked node is a Conceptual Data Model
199                     else if (object instanceof ConceptualModel)
200                     {
201                         if (e.getClickCount() == 2)
202                         {
203                             EditorFactory.getModelEdit();
204                         }
205                     }
206 
207                     // If the clicked node is a Physical Data Model
208                     else if (object instanceof PhysicalModel)
209                     {
210                         if (e.getClickCount() == 2)
211                         {
212                             EditorFactory.getModelEdit();
213                         }
214                     }
215                     if (ModelMan.getCurrentModel() != null)
216                     {
217                         ModelMan.getCurrentModel().getPanel().repaint();
218                     }
219 
220                 }
221             }
222 
223             // When mouse has been pressed or released, call evaluatePopup to check
224             // if a pop up menu has been triggered
225             public void mousePressed(MouseEvent e)
226             {
227                 evaluatePopup(e);
228             }
229 
230             public void mouseReleased(MouseEvent e)
231             {
232                 evaluatePopup(e);
233             }
234 
235             /***
236              * Evaluate if popup menu has been requested
237              * This function is needed because of the difference to get a popup menu
238              * on Mac OS X (mousePressed instead of mouseReleased)
239              * @param e
240              */
241             private void evaluatePopup(MouseEvent e)
242             {
243                 if (e.isPopupTrigger())
244                 {
245                     // Get the closest tree row to the mouse location and select it
246                     jTree.setSelectionRow(jTree.getClosestRowForLocation(e.getX(), e.getY()));
247                     // Get the object corresponding to the selected row
248                     object= ((CustomTreeNode) jTree.getSelectionPath().getLastPathComponent()).getUserObject();
249                     // Search for a parent to the current selected row
250                     if (((CustomTreeNode) jTree.getSelectionPath().getLastPathComponent()).getParent() != null)
251                     {
252                         objectParent=
253                             ((CustomTreeNode) ((CustomTreeNode) jTree.getSelectionPath().getLastPathComponent())
254                                 .getParent())
255                                 .getUserObject();
256                         pop.setData(object, objectParent);
257                     }
258                     else
259                     {
260                         pop.setData(object, null);
261                     }
262                     // Make the pop up appears
263                     // We had 5 to the coordinates in order to prevent the automatic
264                     // selection of the first element of the popup menu
265                     pop.show(me, e.getX() + 5, e.getY() + 5);
266                 }
267             }
268         });
269 
270         /*** Assembling components **/
271 
272         // Content panel
273         this.add(
274             new JScrollPane(jTree),
275             new GridBagConstraints(
276                 0,
277                 0,
278                 1,
279                 1,
280                 1.0,
281                 1.0,
282                 GridBagConstraints.CENTER,
283                 GridBagConstraints.BOTH,
284                 new Insets(3, 3, 3, 3),
285                 0,
286                 0));
287     } // End of 'NOTreeView()'
288 
289     /***
290      * Set the selected node in the tree
291      * @param pNode
292      */
293     public static void setSelectedNode(CustomTreeNode pNode)
294     {
295         TreePath path= new TreePath(pNode.getPath());
296         jTree.setSelectionPath(path);
297         jTree.scrollPathToVisible(path);
298     }
299 
300     /***
301      * Add the node as selected in the tree
302      * @param pNode
303      */
304     public static void addSelectedNode(CustomTreeNode pNode)
305     {
306         TreePath path= new TreePath(pNode.getPath());
307         jTree.addSelectionPath(path);
308         jTree.scrollPathToVisible(path);
309     }
310 
311     /***
312      * Reset the selection in the tree
313      */
314     public static void resetSelectedNode()
315     {
316         jTree.setSelectionPath(jTree.getPathForRow(0));
317     }
318 
319     /***
320      * Add a node to the root node in the tree
321      * @param newNode
322      */
323     public static void addNode(CustomTreeNode newNode)
324     {
325         treeModel.insertNodeInto(newNode, (CustomTreeNode) treeModel.getRoot(), ModelMan.getModels().size() - 1);
326     }
327 
328     /***
329      * Add a node to another node in the tree
330      * @param newNode
331      * @param parentNode
332      * @param i
333      */
334     public static void addNode(CustomTreeNode newNode, CustomTreeNode parentNode, int i)
335     {
336         treeModel.insertNodeInto(newNode, parentNode, i);
337         // Expand the path of the node given as parameter
338         jTree.expandPath(new TreePath(parentNode.getPath()));
339     }
340 
341     /***
342      * Remove a node in the tree
343      * @param pNode
344      */
345     public static void removeNode(CustomTreeNode pNode)
346     {
347         treeModel.removeNodeFromParent(pNode);
348     }
349 
350     /***
351      * Rename the current selected node
352      */
353     public static void renameNode()
354     {
355         jTree.startEditingAtPath(jTree.getSelectionPath());
356     }
357 
358     /***
359      * Reload childrens of the given node from a BaseClass object
360      * @param pNode the node where to start a recursive reload
361      */
362     public static void reloadBaseClassChildrens(CustomTreeNode pNode)
363     {
364         BaseClass baseClass= (BaseClass) pNode.getUserObject();
365         Column tmpColumn= null;
366 
367         // Remove all childrens
368         baseClass.getDynamicTreeNode().removeAllChildren();
369 
370         // Recreate all childrens
371         for (int i= 0; i < baseClass.getData().size(); i++)
372         {
373             tmpColumn= (Column) baseClass.getData().elementAt(i);
374             if (tmpColumn.getDynamicTreeNode() == null)
375             {
376                 tmpColumn.setDynamicTreeNode(new CustomTreeNode(tmpColumn));
377             }
378             addNode(tmpColumn.getDynamicTreeNode(), pNode, i);
379         }
380 
381         // Expand the path of the node given as parameter
382         treeModel.reload();
383         jTree.expandPath(new TreePath(pNode.getPath()));
384     }
385 
386     /***
387      * NOTreeCellRenderer render a tree cell
388      */
389     private class NOTreeCellRenderer extends DefaultTreeCellRenderer
390     {
391         public Component getTreeCellRendererComponent(
392             JTree tree,
393             Object value,
394             boolean isSelected,
395             boolean expanded,
396             boolean leaf,
397             int row,
398             boolean hasFocus)
399         {
400             super.getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, hasFocus);
401             Object object= ((CustomTreeNode) value).getUserObject();
402             if (object instanceof Column)
403             {
404                 if (((Column) object).isPk())
405                 {
406                     this.setIcon(CstImages.ICN_FIELD_PK);
407                 }
408                 else
409                 {
410                     this.setIcon(CstImages.ICN_FIELD);
411                 }
412             }
413             else if (object instanceof Entity || object instanceof Table)
414             {
415                 this.setIcon(CstImages.ICN_TABLE);
416             }
417             else if (object instanceof Association)
418             {
419                 this.setIcon(CstImages.ICN_ASSOCIATION);
420             }
421             else if (object instanceof Constraint)
422             {
423                 this.setIcon(CstImages.ICN_CONSTRAINT);
424             }
425             else if (object instanceof InheritanceLink)
426             {
427                 this.setIcon(CstImages.ICN_INHERITANCE);
428             }
429             else if (object instanceof ConceptualModel)
430             {
431                 this.setIcon(CstImages.ICN_CDM);
432             }
433             else if (object instanceof PhysicalModel)
434             {
435                 this.setIcon(CstImages.ICN_PDM);
436             }
437             else
438             {
439                 this.setIcon(CstImages.ICN_WORKSPACE);
440             }
441             return this;
442         }
443     } // End of class 'NOTreeCellRenderer'
444 
445     /***
446      * NOTreeCellEditor is responsible for editing a tree node
447      */
448     private class NOTreeCellEditor extends DefaultTreeCellEditor
449     {
450         public NOTreeCellEditor()
451         {
452             super(jTree, jTreeRenderer);
453         }
454 
455         protected void determineOffset(
456             JTree tree,
457             Object value,
458             boolean isSelected,
459             boolean expanded,
460             boolean leaf,
461             int row)
462         {
463             Object object= ((CustomTreeNode) value).getUserObject();
464             if (object instanceof Column)
465             {
466                 if (((Column) object).isPk())
467                 {
468                     this.editingIcon= CstImages.ICN_FIELD_PK;
469                 }
470                 else
471                 {
472                     this.editingIcon= CstImages.ICN_FIELD;
473                 }
474             }
475             else if (object instanceof Entity || object instanceof Table)
476             {
477                 this.editingIcon= CstImages.ICN_TABLE;
478             }
479             else if (object instanceof Association)
480             {
481                 this.editingIcon= CstImages.ICN_ASSOCIATION;
482             }
483             else if (object instanceof Constraint)
484             {
485                 this.editingIcon= CstImages.ICN_CONSTRAINT;
486             }
487             else if (object instanceof ConceptualModel)
488             {
489                 this.editingIcon= CstImages.ICN_CDM;
490             }
491             else if (object instanceof PhysicalModel)
492             {
493                 this.editingIcon= CstImages.ICN_PDM;
494             }
495             else
496             {
497                 this.editingIcon= CstImages.ICN_WORKSPACE;
498             }
499             // Set the offset of the text field in order to not bypass the tree icon
500             this.offset= this.renderer.getIconTextGap() + this.editingIcon.getIconWidth();
501         }
502     } // End of class 'NOTreeCellEditor'
503 
504     /***
505      * The tree model
506      */
507     private class NOTreeModel extends DefaultTreeModel
508     {
509         public NOTreeModel(TreeNode newRoot)
510         {
511             super(newRoot);
512         }
513 
514         /***
515          * Actions to be executed when a node edition is over
516          * @param path
517          * @param newValue
518          */
519         public void valueForPathChanged(TreePath path, Object newValue)
520         {
521             if (object instanceof Column)
522             {
523                 int index= ((BaseObject) objectParent).getData().indexOf((Column) object);
524                 ((Column) ((BaseObject) objectParent).getData().elementAt(index)).setName(newValue.toString());
525             }
526             else if (object instanceof Entity)
527             {
528                 ((Entity) object).setName(newValue.toString());
529             }
530             else if (object instanceof Table)
531             {
532                 ((Table) object).setName(newValue.toString());
533             }
534             else if (object instanceof Association)
535             {
536                 ((Association) object).setName(newValue.toString());
537             }
538             else if (object instanceof Constraint)
539             {
540                 ((Constraint) object).setName(newValue.toString());
541             }
542             else if (object instanceof PhysicalModel)
543             {
544                 ((PhysicalModel) object).setName(newValue.toString());
545             }
546             else if (object instanceof ConceptualModel)
547             {
548                 ((ConceptualModel) object).setName(newValue.toString());
549             }
550         }
551     } // End of class 'NOTreeModel'
552 
553 }