Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/ubermq/chord/ui/ChordDisplayPanel.java


1   package com.ubermq.chord.ui;
2   
3   import com.ubermq.chord.*;
4   import com.ubermq.chord.jms.*;
5   import java.awt.*;
6   import java.awt.event.*;
7   import java.awt.geom.*;
8   import java.net.*;
9   import java.util.*;
10  import javax.swing.*;
11  
12  /**
13   * A panel that draws a chord infrastructure in
14   * a circular fashion, and provides user
15   * feedback to mouse movements.
16   */
17  public class ChordDisplayPanel
18      extends JPanel
19      implements InfrastructureModel.EventListener
20  {
21      private final InfrastructureModel m;
22  
23      private Map nodeComponents;
24  
25      // when we paint, we draw fingers for this guy.
26      private ChordNode drawFingersFor;
27  
28      // icons
29      static final ImageIcon networkIcon =
30          new ImageIcon(Toolkit.getDefaultToolkit().getImage(Class.class.getResource("/images/network.png")));
31  
32      /**
33       * Creates a chord display panel that
34       * renders data from the specified infrastructure
35       * data model.
36       *
37       * @param m an infrastructure data model.
38       */
39      public ChordDisplayPanel(InfrastructureModel m)
40      {
41          super(new MyLayoutManager(), true);
42          this.m = m;
43          this.nodeComponents = new HashMap();
44  
45          // when i initially come up, grok
46          Iterator iter = m.getNodes().iterator();
47          while (iter.hasNext())
48          {
49              ChordNode n = (ChordNode)iter.next();
50              nodeAdded(n);
51          }
52  
53          // add listener for incremental changes
54          m.addListener(this);
55      }
56  
57      public void nodeAdded(final ChordNode x)
58      {
59          assert nodeComponents.get(x) == null;
60  
61          // create the component for this node.
62          final JComponent label = new JLabel(x.identifier().toString(),
63                                              networkIcon,
64                                              JLabel.CENTER);
65          label.addMouseListener(new MouseAdapter() {
66                      public void mouseEntered(MouseEvent e) {
67                          drawFingersFor = x;
68                          label.setToolTipText(x.toHtml());
69                          repaint();
70                      }
71                      public void mouseExited(MouseEvent e) {
72                          drawFingersFor = null;
73                          repaint();
74                      }
75                  });
76          label.setToolTipText(x.toHtml());
77  
78          // associate it with the node
79          nodeComponents.put(x, label);
80  
81          // add to GUI
82          add(label);
83      }
84  
85      public void nodeRemoved(ChordNode x)
86      {
87          // remove from associative table and the GUI
88          JComponent c = (JComponent)nodeComponents.remove(x);
89          remove(c);
90      }
91  
92      public void nodeChanged(ChordNode x)
93      {
94          // what? nodes dont' change.
95      }
96  
97  
98      /**
99       * The core of the display panel involves laying out
100      * node representation components in a circle.
101      */
102     private static class MyLayoutManager
103         implements LayoutManager
104     {
105         private static final Dimension PREFERRED_SIZE = new Dimension(500, 400);
106 
107         MyLayoutManager()
108         {
109         }
110 
111         public void removeLayoutComponent(Component comp)
112         {
113         }
114 
115         public void addLayoutComponent(String name, Component comp)
116         {
117         }
118 
119         /**
120          * Lays out the specified container.
121          * @param parent the container to be laid out
122          */
123         public void layoutContainer(Container parent)
124         {
125             ChordDisplayPanel p = ((ChordDisplayPanel)parent);
126 
127             int r = p.getIdentifierRadius();
128             Point origin = p.getIdentifierOrigin();
129 
130             // go through each node component and set its position on the
131             // circle
132             Iterator iter = p.nodeComponents.keySet().iterator();
133             while (iter.hasNext())
134             {
135                 ChordNode x = (ChordNode)iter.next();
136                 JComponent m = (JComponent)p.nodeComponents.get(x);
137 
138                 Point pt = p.calculateNodeCoordinates(x, r);
139                 m.setLocation(pt.x + origin.x , pt.y + origin.y);
140 
141                 Dimension d = m.getPreferredSize();
142                 m.setSize(d.width, d.height);
143             }
144         }
145 
146         public Dimension preferredLayoutSize(Container parent)
147         {
148             return PREFERRED_SIZE;
149         }
150 
151         public Dimension minimumLayoutSize(Container parent)
152         {
153             return preferredLayoutSize(parent);
154         }
155     }
156 
157     private static final int INSET_X = 50, INSET_Y = 50;
158     private static final Stroke DASH_DASH = new BasicStroke(1.0f,
159                                                             BasicStroke.CAP_ROUND,
160                                                             BasicStroke.JOIN_MITER,
161                                                             1.0f,
162                                                             new float[] {3f, 6f},
163                                                             0f);
164     private static final Stroke BIG_PEN = new BasicStroke(2.0f,
165                                                           BasicStroke.CAP_ROUND,
166                                                           BasicStroke.JOIN_ROUND);
167     private static final Stroke NORMAL_PEN = new BasicStroke(1.0f,
168                                                              BasicStroke.CAP_ROUND,
169                                                              BasicStroke.JOIN_ROUND);
170 
171     public void paint(Graphics g)
172     {
173         super.paint(g);
174 
175         Graphics2D g2d = (Graphics2D)g.create();
176         g2d.setStroke(DASH_DASH);
177         g2d.setColor(Color.BLUE);
178         g2d.drawOval(INSET_X, INSET_Y, getIdentifierRadius()*2, getIdentifierRadius()*2);
179 
180         // set up the graphics for the finger tables,
181         // translated to the origin.
182         Graphics2D fingerG = (Graphics2D)g.create();
183         fingerG.translate(getIdentifierOrigin().x, getIdentifierOrigin().y);
184 
185         // draw the finger table for the guy under the mouse
186         if (drawFingersFor != null)
187             drawFingerFor(fingerG, drawFingersFor);
188     }
189 
190     private void drawFingerFor(Graphics2D g, ChordNode me)
191     {
192         int r = getIdentifierRadius();
193         ChordNode[] f = m.getFingerTable(me);
194 
195         int i=0;
196         while(i < f.length)
197         {
198             // as long as its the same finger, continue
199             int j = i + 1;
200             while(j < f.length && f[i].equals(f[j]))
201                 j++;
202 
203             // draw the finger interval (i, j)
204             drawFinger(g, me, f[i], i, j-1, r);
205             i=j;
206         }
207     }
208 
209     private void drawFinger(Graphics2D g,
210                             ChordNode from,
211                             ChordNode to,
212                             int i,
213                             int j,
214                             int r)
215     {
216         if (!from.equals(to))
217         {
218             Point ptFrom = calculateNodeCoordinates(from, r);
219             Point ptTo = calculateNodeCoordinates(to, r);
220 
221             g.setStroke(BIG_PEN);
222             g.setColor(Color.RED);
223             g.drawLine(ptFrom.x, ptFrom.y, ptTo.x, ptTo.y);
224 
225             // at the midpoint of the line, draw the finger index
226             g.setStroke(NORMAL_PEN);
227             g.setColor(Color.BLACK);
228             g.drawString((i == j) ? String.valueOf(i) : String.valueOf("(" + i + ", " + j + ")"),
229                          ptFrom.x + (ptTo.x - ptFrom.x) / 2,
230                          ptFrom.y + (ptTo.y - ptFrom.y) / 2);
231         }
232     }
233 
234     private Point getIdentifierOrigin()
235     {
236         int r = getIdentifierRadius();
237         return new Point(INSET_X + r, INSET_Y + r);
238     }
239 
240     private int getIdentifierRadius()
241     {
242         return Math.min(getWidth() - 2 * INSET_X, getHeight() - 2 * INSET_Y) / 2;
243     }
244 
245     /**
246      * Calculates the angle representing where the identifier lies on
247      * the identifier circle, in radians. This method relies on
248      * the <code>hashCode</code> method to provide a reasonable
249      * mapping of identifier space onto the 2^32 values provided by
250      * the primitive <code>int</code> Java type.<P>
251      *
252      * @return number of radians, (0, 2pi], representing the theta
253      * coordinate of the identifier's location on the identifier plane.
254      */
255     private double translateIdentifier(ChordIdentifier i)
256     {
257         return 2 * Math.PI * i.normal();
258     }
259 
260     /**
261      * Gets the rectangular location for a node on a circle of radius r,
262      * centered at the origin.
263      */
264     private Point calculateNodeCoordinates(ChordNode n, int r)
265     {
266         // figure out theta
267         double theta =
268             translateIdentifier(n.identifier());
269 
270         // we know (r, theta) for the node.
271         // convert to rectangular and plot
272         int x = (int)Math.round(r * Math.cos(theta)),
273             y = (int)Math.round(r * Math.sin(theta));
274 
275         return new Point(x,y);
276     }
277 
278     /**
279      * Constructs the message viewer application window.
280      */
281     public static void main(String s[])
282     {
283         // connect to the URL specified on the cmd line.
284         try
285         {
286             ChordInfrastructure i = JMSChordInfrastructure.getInfrastructure(LocalChordNode.DEFAULT_IDENTIFIER_FACTORY,
287                                                                              URI.create(s[0]));
288             InfrastructureModel m = new InfrastructureModel();
289             m.connect(i);
290 
291             ChordDisplayPanel p = new ChordDisplayPanel(m);
292 
293             // display
294             JFrame frame = new JFrame("chord");
295             frame.getContentPane().add(p);
296 
297             frame.addWindowListener(new WindowAdapter() {
298                         public void windowClosing(WindowEvent e) {System.exit(0);}
299                     });
300 
301             frame.pack();
302             frame.setVisible(true);
303         }
304         catch (Exception e) {
305             e.printStackTrace();
306         }
307     }
308 
309 }
310 
311