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.layout.withoutview;
29  
30  import java.awt.Color;
31  import java.awt.Dimension;
32  import java.awt.Graphics;
33  import java.awt.Graphics2D;
34  import java.awt.Insets;
35  import java.awt.Rectangle;
36  import java.awt.font.TextLayout;
37  import java.awt.geom.AffineTransform;
38  import java.awt.geom.Line2D;
39  import java.awt.geom.Rectangle2D;
40  import javax.swing.JComponent;
41  import javax.swing.JFrame;
42  
43  import y.base.DataProvider;
44  import y.base.Edge;
45  import y.base.EdgeCursor;
46  import y.base.Node;
47  import y.base.NodeCursor;
48  import y.geom.YPoint;
49  import y.geom.YRectangle;
50  import y.geom.OrientedRectangle;
51  import y.layout.EdgeLabelLayout;
52  import y.layout.EdgeLayout;
53  import y.layout.LayoutGraph;
54  import y.layout.Layouter;
55  import y.layout.NodeLayout;
56  import y.layout.grouping.GroupingKeys;
57  
58  /**
59   * A simple graph viewer component that can be used to
60   * visualize instances of LayoutGraph. This class is meant
61   * as a debugging aid for developers that do not have
62   * the viewer classes of the yFiles Viewer distribution.
63   *
64   */
65  public class LayoutPreviewPanel extends JComponent
66  {
67    private int insets = 5;
68    private Rectangle rect;
69    private LayoutGraph graph;
70    private Layouter layouter;
71  
72    /**
73     * Instantiates a new LayoutPreviewPanel.
74     */
75    public LayoutPreviewPanel(){
76      this(null);
77    }
78  
79    /**
80     * Instantiates a new LayoutPreviewPanel displaying the given LayoutGraph.
81     */
82    public LayoutPreviewPanel(LayoutGraph graph){
83      this(graph, null);
84    }
85  
86  
87    /**
88     * Instantiates a new LayoutPreviewPanel displaying the given LayoutGraph.
89     */
90    public LayoutPreviewPanel(LayoutGraph graph, Layouter layouter){
91      this.graph = graph;
92      this.layouter = layouter;
93      setPreferredSize(new Dimension(500,500));
94    }
95  
96    /**
97     * Creates an new LayoutPreviewPanel for the given graph and shows the frame.
98     */
99    public static void showFrame( LayoutGraph graph){
100     new LayoutPreviewPanel( graph ).createFrame( "" ).setVisible( true );
101   }
102 
103   /**
104    * Returns the LayoutGraph instance displayed by this view.
105    */
106   public LayoutGraph getGraph(){
107     return graph;
108   }
109 
110   /**
111    * Updates the contents of this view. This includes
112    * invoking the set layout algorithm on the graph and adjusting
113    * the zoom and clip of the view. 
114    */
115   public void update(){
116     if (layouter != null && graph != null){
117       layouter.doLayout(graph);
118     }
119     if (graph != null){
120       rect = graph.getBoundingBox();
121     }
122     repaint();
123   }
124 
125   /**
126    * Paint this component. This will paint the associated LayoutGraph. 
127    */
128   public void paintComponent(Graphics g){
129     Graphics2D g2d = (Graphics2D) g;
130     g2d.setColor(this.getBackground());
131     Insets ins = getInsets();
132     g2d.fillRect(ins.left, ins.top, getWidth() - (ins.left + ins.right), getHeight() - (ins.top + ins.bottom));
133     if (graph != null && rect != null){
134       double width = getWidth() - (ins.left + ins.right);
135       double height = getHeight() - (ins.top + ins.bottom);
136       if ((width-2*insets) > 0 && (height-2*insets) > 0){
137         double scaling = Math.min(1, Math.min((width-2 * insets) /rect.width, (height-2 * insets) /rect.height ));
138         AffineTransform tr = g2d.getTransform();
139         AffineTransform af = g2d.getTransform();
140         af.concatenate(AffineTransform.getTranslateInstance(
141           insets + ins.left + 0.5d* ((width - 2 * insets) - rect.width * scaling),
142           insets + ins.top + 0.5d* ((height - 2 * insets) - rect.height * scaling)));
143         af.concatenate(AffineTransform.getScaleInstance(scaling, scaling));
144         af.concatenate(AffineTransform.getTranslateInstance(-rect.x, -rect.y));
145         g2d.setTransform(af);
146         paint(g2d, graph);
147         g2d.setColor(getForeground());
148         for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()){
149           paint(g2d, graph, ec.edge());
150         }
151         g2d.setColor(Color.blue);
152         for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()){
153           paint(g2d, graph, nc.node());
154         }
155         g2d.setTransform(tr);
156       }
157     }
158   }
159 
160   /**
161    * Callback method that allows subclasses to paint miscellaneous non-node
162    * and non-edge related stuff.
163    * @param graphics   the <code>Graphics2D</code> context for painting.
164    * @param graph      the <code>LayoutGraph</code> to paint.
165    */
166   protected void paint(Graphics2D graphics, LayoutGraph graph) {
167   }
168 
169   private Line2D.Double line = new Line2D.Double();
170   protected void paint(Graphics2D g, LayoutGraph lg, Edge e){
171     g.setColor(Color.black);
172     EdgeLayout el = lg.getEdgeLayout(e);
173     YPoint p = lg.getSourcePointAbs(e);
174     double lastX = p.x;
175     double lastY = p.y;
176     for (int i = 0; i < el.pointCount(); i++){
177       YPoint next = el.getPoint(i);
178       line.x1 = lastX;
179       line.y1 = lastY;
180       line.x2 = next.x;
181       line.y2 = next.y;
182       g.draw(line);
183       lastX = next.x;
184       lastY = next.y;
185     }
186     YPoint end = lg.getTargetPointAbs(e);
187     line.x1 = lastX;
188     line.y1 = lastY;
189     line.x2 = end.x;
190     line.y2 = end.y;
191     g.draw(line);
192     
193     EdgeLabelLayout[] ells = lg.getEdgeLabelLayout(e);
194     for(int i = 0; i < ells.length; i++)
195     {
196       YRectangle box = getEdgeLabelLocation(lg, e, ells[i]).getBoundingBox();
197       rectangle.setFrame(box.x, box.y, box.width, box.height);
198       g.draw(rectangle);
199     }
200   }
201 
202   private OrientedRectangle getEdgeLabelLocation(LayoutGraph graph, Edge e, EdgeLabelLayout ell)
203   {
204     return ell.getLabelModel().getLabelPlacement(
205       ell.getOrientedBox().getSize(),
206       graph.getEdgeLayout(e), 
207       graph.getNodeLayout(e.source()),
208       graph.getNodeLayout(e.target()),
209       ell.getModelParameter());
210   }
211   
212   Rectangle2D.Double rectangle = new Rectangle2D.Double();
213   protected void paint(Graphics2D g, LayoutGraph graph, Node node){
214     NodeLayout nl = graph.getNodeLayout(node);
215     rectangle.setFrame(nl.getX(), nl.getY(), nl.getWidth(), nl.getHeight());
216     DataProvider dp = graph.getDataProvider(GroupingKeys.GROUP_DPKEY);
217     if (dp != null && dp.getBool(node)) {
218       g.draw(rectangle);
219     } else {
220       g.fill(rectangle);
221     }
222     Color c = g.getColor();
223     g.setColor(Color.white);
224     TextLayout tl = new TextLayout(Integer.toString(node.index()), g.getFont(), g.getFontRenderContext());
225     Rectangle2D box = tl.getBounds();
226     double tx = nl.getX() + (nl.getWidth() - box.getWidth())/2.0;
227     double ty = nl.getY() + box.getHeight() + (nl.getHeight() - box.getHeight())/2.0;
228     
229     tl.draw(g, (float)(tx), (float)(ty));
230     g.setColor(c);
231   }
232   
233   /**
234    * Sets the graph that is to be displayed.
235    */
236   public void setGraph(LayoutGraph graph)
237   {
238     this.graph = graph;
239   }
240   
241   /**
242    * Returns the layout algorithm to be applied on the graph
243    * when invoking update().
244    */
245   public Layouter getLayouter()
246   {
247     return layouter;
248   }
249 
250   /**
251    * Returns the layout algorithm to be applied on the graph
252    * when invoking update().
253    */
254   public void setLayouter(Layouter layouter)
255   {
256     this.layouter = layouter;
257   }
258   
259   public JFrame createFrame(String title) 
260   {
261     JFrame frame = new JFrame(title);
262     frame.setContentPane(this);
263     frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
264     frame.pack();
265     update();
266     return frame;
267   }
268   
269 }