1   /****************************************************************************
2    * This demo file is part of yFiles for Java 2.14.
3    * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4    * 72070 Tuebingen, Germany. All rights reserved.
5    * 
6    * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7    * of demo files in source code or binary form, with or without
8    * modification, is not permitted.
9    * 
10   * Owners of a valid software license for a yFiles for Java version that this
11   * demo is shipped with are allowed to use the demo source code as basis
12   * for their own yFiles for Java powered applications. Use of such programs is
13   * governed by the rights and conditions as set out in the yFiles for Java
14   * license agreement.
15   * 
16   * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19   * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   *
27   ***************************************************************************/
28  package demo.view.entityrelationship;
29  
30  import demo.view.entityrelationship.painters.ErdRealizerFactory;
31  import y.base.Edge;
32  import y.geom.YPoint;
33  import y.option.RealizerCellRenderer;
34  import y.view.Arrow;
35  import y.view.EdgeRealizer;
36  import y.view.Graph2D;
37  import y.view.PopupMode;
38  
39  import javax.swing.DefaultListModel;
40  import javax.swing.Icon;
41  import javax.swing.JList;
42  import javax.swing.JMenu;
43  import javax.swing.JPopupMenu;
44  import java.awt.event.MouseAdapter;
45  import java.awt.event.MouseEvent;
46  import java.awt.event.MouseMotionListener;
47  import java.util.Enumeration;
48  
49  /**
50   * This popup mode creates a menu for arrow selection for an edge's source and target in
51   * entity relationship diagrams (ERD).
52   * There are two lists of <code>Arrows</code>, one to select the source arrow the other
53   * to select the target arrow.
54   */
55  class EntityRelationshipPopupMode extends PopupMode {
56  
57    /**
58     * Creates a popup menu for the given edge that allows selecting arrows for source and target
59     * @param e the edge which arrow shall be set
60     * @return a popup menu
61     */
62    public JPopupMenu getEdgePopup(Edge e) {
63      JPopupMenu pm = new JPopupMenu();
64      if (e != null) {
65        JMenu sourceArrow = new JMenu("Source Arrow");
66        final JList sourceList = createArrowList(true);
67        final MouseHandler sourceHandler = new MouseHandler(pm, e, true);
68        sourceList.addMouseListener(sourceHandler);
69        sourceList.addMouseMotionListener(sourceHandler);
70        sourceArrow.add(sourceList);
71        pm.add(sourceArrow);
72        JMenu targetArrow = new JMenu("Target Arrow");
73        final JList targetList = createArrowList(false);
74        final MouseHandler targetHandler = new MouseHandler(pm, e, false);
75        targetList.addMouseListener(targetHandler);
76        targetList.addMouseMotionListener(targetHandler);
77        targetArrow.add(targetList);
78        pm.add(targetArrow);
79      }
80      return pm;
81    }
82  
83    /**
84     * Creates a list with every arrow that can be used in ERD.
85     * @param source <code>true</code> if the source arrow will be set,
86     *               <code>false</code> if the target arrow will be set
87     * @return a list with every arrow that can be used in ERD
88     */
89    JList createArrowList(boolean source){
90      DefaultListModel listModel = new DefaultListModel();
91      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.NONE));
92      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_ONE));
93      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_MANY));
94      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_ONE_OPTIONAL));
95      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_ONE_MANDATORY));
96      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_MANY_OPTIONAL));
97      listModel.addElement(ErdRealizerFactory.createRelation(Arrow.CROWS_FOOT_MANY_MANDATORY));
98      if(!source){
99        for(Enumeration en = listModel.elements(); en.hasMoreElements(); ){
100         EdgeRealizer realizer = (EdgeRealizer) en.nextElement();
101         realizer.setTargetArrow(realizer.getSourceArrow());
102         realizer.setSourceArrow(Arrow.NONE);
103       }
104     }
105     JList arrowList = new JList(listModel);
106     arrowList.setCellRenderer(new RealizerCellRenderer(40, 20){
107 
108       protected Icon createEdgeRealizerIcon(EdgeRealizer realizer, int iconWidth, int iconHeight) {
109         final EdgeRealizerIcon icon = createIcon(realizer, iconWidth, iconHeight);
110         icon.setDrawingBends(false);
111         return icon;
112       }
113 
114       private EdgeRealizerIcon createIcon(EdgeRealizer realizer, int iconWidth, int iconHeight) {
115         return new EdgeRealizerIcon(realizer, iconWidth, iconHeight){
116           protected YPoint calculateSourceBend(EdgeRealizer realizer, int iconWidth, int iconHeight) {
117             return new YPoint(0.5 * iconWidth, 0.5 * iconHeight);
118           }
119 
120           protected YPoint calculateTargetBend(EdgeRealizer realizer, int iconWidth, int iconHeight) {
121             return new YPoint(0.5 * iconWidth, 0.5 * iconHeight);
122           }
123         };
124       }
125 
126     });
127     arrowList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
128     return arrowList;
129   }
130 
131   /**
132    * This mouse handler selects arrow list items if the mouse is moving above them and sets the appropriate
133    * arrow by clicking on an arrow item.
134    */
135   private static final class MouseHandler extends MouseAdapter implements MouseMotionListener {
136     private JPopupMenu pm;
137     private Edge edge;
138     private boolean source;
139 
140     /**
141      * Creates a new <code>MouseHandler</code>
142      * @param pm the popup menu the handler is registered to
143      * @param edge the selected edge
144      * @param source <code>true</code> if the source arrow will be changed,
145      *               <code>false</code> if the target arrow will be changed.
146      */
147     public MouseHandler(JPopupMenu pm, Edge edge, boolean source) {
148       this.pm = pm;
149       this.edge = edge;
150       this.source = source;
151     }
152 
153     /**
154      * Selects a list item by dragging the mouse.
155      * @param e the mouse event
156      */
157     public void mouseDragged(MouseEvent e) {
158       handleMotionEvent(e);
159     }
160 
161     /**
162      * Selects a list item by moving the mouse.
163      * @param e the mouse event
164      */
165     public void mouseMoved(MouseEvent e) {
166       handleMotionEvent(e);
167     }
168 
169     /**
170      * Selects the list item by the location of the mouse event.
171      * @param e the mouse event
172      */
173     private void handleMotionEvent(MouseEvent e) {
174       final Object source = e.getSource();
175       if(source instanceof JList){
176         JList list = (JList) source;
177         list.setSelectedIndex(list.locationToIndex(e.getPoint()));
178       }
179     }
180 
181     /**
182      * Sets the arrow for the selected edge for a mouse click on an list item.
183      * @param e the mouse event
184      */
185     public void mouseClicked(MouseEvent e) {
186       final Object src = e.getSource();
187       if(src instanceof JList){
188         JList list = (JList) src;
189         final EdgeRealizer er = (EdgeRealizer) list.getModel().getElementAt(list.locationToIndex(e.getPoint()));
190         final Graph2D graph = (Graph2D) edge.getGraph();
191         if (source) {
192           graph.getRealizer(edge).setSourceArrow(er.getSourceArrow());
193         } else {
194           graph.getRealizer(edge).setTargetArrow(er.getTargetArrow());
195         }
196         graph.updateViews();
197         pm.setVisible(false);
198       }
199     }
200   }
201 }
202