1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.9. 
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2000-2011 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.view.entityrelationship;
15  
16  import demo.view.entityrelationship.painters.ErdRealizerFactory;
17  import y.base.Edge;
18  import y.geom.YPoint;
19  import y.option.RealizerCellRenderer;
20  import y.view.Arrow;
21  import y.view.EdgeRealizer;
22  import y.view.Graph2D;
23  import y.view.PopupMode;
24  
25  import javax.swing.DefaultListModel;
26  import javax.swing.Icon;
27  import javax.swing.JList;
28  import javax.swing.JMenu;
29  import javax.swing.JPopupMenu;
30  import java.awt.event.MouseAdapter;
31  import java.awt.event.MouseEvent;
32  import java.awt.event.MouseMotionListener;
33  import java.util.Enumeration;
34  
35  /**
36   * This popup mode creates a menu for arrow selection for an edge's source and target in
37   * entity relationship diagrams (ERD).
38   * There are two lists of <code>Arrows</code>, one to select the source arrow the other
39   * to select the target arrow.
40   */
41  class EntityRelationshipPopupMode extends PopupMode {
42  
43    /**
44     * Creates a popup menu for the given edge that allows selecting arrows for source and target
45     * @param e the edge which arrow shall be set
46     * @return a popup menu
47     */
48    public JPopupMenu getEdgePopup(Edge e) {
49      JPopupMenu pm = new JPopupMenu();
50      if (e != null) {
51        JMenu sourceArrow = new JMenu("Source Arrow");
52        final JList sourceList = createArrowList(true);
53        final MouseHandler sourceHandler = new MouseHandler(pm, e, true);
54        sourceList.addMouseListener(sourceHandler);
55        sourceList.addMouseMotionListener(sourceHandler);
56        sourceArrow.add(sourceList);
57        pm.add(sourceArrow);
58        JMenu targetArrow = new JMenu("Target Arrow");
59        final JList targetList = createArrowList(false);
60        final MouseHandler targetHandler = new MouseHandler(pm, e, false);
61        targetList.addMouseListener(targetHandler);
62        targetList.addMouseMotionListener(targetHandler);
63        targetArrow.add(targetList);
64        pm.add(targetArrow);
65      }
66      return pm;
67    }
68  
69    /**
70     * Creates a list with every arrow that can be used in ERD.
71     * @param source <code>true</code> if the source arrow will be set,
72     *               <code>false</code> if the target arrow will be set
73     * @return a list with every arrow that can be used in ERD
74     */
75    JList createArrowList(boolean source){
76      DefaultListModel listModel = new DefaultListModel();
77      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.NONE));
78      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_ONE));
79      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_MANY));
80      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_ONE_OPTIONAL));
81      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_ONE_MANDATORY));
82      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_MANY_OPTIONAL));
83      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_MANY_MANDATORY));
84      if(!source){
85        for(Enumeration en = listModel.elements(); en.hasMoreElements(); ){
86          EdgeRealizer realizer = (EdgeRealizer) en.nextElement();
87          realizer.setTargetArrow(realizer.getSourceArrow());
88          realizer.setSourceArrow(Arrow.NONE);
89        }
90      }
91      JList arrowList = new JList(listModel);
92      arrowList.setCellRenderer(new RealizerCellRenderer(40, 20){
93  
94        protected Icon createEdgeRealizerIcon(EdgeRealizer realizer, int iconWidth, int iconHeight) {
95          final EdgeRealizerIcon icon = createIcon(realizer, iconWidth, iconHeight);
96          icon.setDrawingBends(false);
97          return icon;
98        }
99  
100       private EdgeRealizerIcon createIcon(EdgeRealizer realizer, int iconWidth, int iconHeight) {
101         return new EdgeRealizerIcon(realizer, iconWidth, iconHeight){
102           protected YPoint calculateSourceBend(EdgeRealizer realizer, int iconWidth, int iconHeight) {
103             return new YPoint(0.5 * iconWidth, 0.5 * iconHeight);
104           }
105 
106           protected YPoint calculateTargetBend(EdgeRealizer realizer, int iconWidth, int iconHeight) {
107             return new YPoint(0.5 * iconWidth, 0.5 * iconHeight);
108           }
109         };
110       }
111 
112     });
113     arrowList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
114     return arrowList;
115   }
116 
117   /**
118    * This mouse handler selects arrow list items if the mouse is moving above them and sets the appropriate
119    * arrow by clicking on an arrow item.
120    */
121   private static final class MouseHandler extends MouseAdapter implements MouseMotionListener {
122     private JPopupMenu pm;
123     private Edge edge;
124     private boolean source;
125 
126     /**
127      * Creates a new <code>MouseHandler</code>
128      * @param pm the popup menu the handler is registered to
129      * @param edge the selected edge
130      * @param source <code>true</code> if the source arrow will be changed,
131      *               <code>false</code> if the target arrow will be changed.
132      */
133     public MouseHandler(JPopupMenu pm, Edge edge, boolean source) {
134       this.pm = pm;
135       this.edge = edge;
136       this.source = source;
137     }
138 
139     /**
140      * Selects a list item by dragging the mouse.
141      * @param e the mouse event
142      */
143     public void mouseDragged(MouseEvent e) {
144       handleMotionEvent(e);
145     }
146 
147     /**
148      * Selects a list item by moving the mouse.
149      * @param e the mouse event
150      */
151     public void mouseMoved(MouseEvent e) {
152       handleMotionEvent(e);
153     }
154 
155     /**
156      * Selects the list item by the location of the mouse event.
157      * @param e the mouse event
158      */
159     private void handleMotionEvent(MouseEvent e) {
160       final Object source = e.getSource();
161       if(source instanceof JList){
162         JList list = (JList) source;
163         list.setSelectedIndex(list.locationToIndex(e.getPoint()));
164       }
165     }
166 
167     /**
168      * Sets the arrow for the selected edge for a mouse click on an list item.
169      * @param e the mouse event
170      */
171     public void mouseClicked(MouseEvent e) {
172       final Object src = e.getSource();
173       if(src instanceof JList){
174         JList list = (JList) src;
175         final EdgeRealizer er = (EdgeRealizer) list.getModel().getElementAt(list.locationToIndex(e.getPoint()));
176         final Graph2D graph = (Graph2D) edge.getGraph();
177         if (source) {
178           graph.getRealizer(edge).setSourceArrow(er.getSourceArrow());
179         } else {
180           graph.getRealizer(edge).setTargetArrow(er.getTargetArrow());
181         }
182         graph.updateViews();
183         pm.setVisible(false);
184       }
185     }
186   }
187 }
188