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