KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > antlr > works > visualization > graphics > panel > GView


1 /*
2
3 [The "BSD licence"]
4 Copyright (c) 2005 Jean Bovet
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. The name of the author may not be used to endorse or promote products
17 derived from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 */

31
32 package org.antlr.works.visualization.graphics.panel;
33
34 import org.antlr.works.visualization.graphics.GContext;
35 import org.antlr.works.visualization.graphics.graph.GGraphAbstract;
36 import org.antlr.works.visualization.graphics.graph.GGraphGroup;
37 import org.antlr.works.visualization.graphics.path.GPath;
38 import org.antlr.works.visualization.graphics.path.GPathGroup;
39 import org.antlr.xjlib.appkit.menu.XJMenu;
40 import org.antlr.xjlib.appkit.menu.XJMenuItem;
41 import org.antlr.xjlib.appkit.menu.XJMenuItemDelegate;
42 import org.antlr.xjlib.appkit.utils.XJSmoothScrolling;
43
44 import javax.swing.*;
45 import java.awt.*;
46 import java.awt.event.*;
47 import java.awt.image.BufferedImage JavaDoc;
48 import java.util.ArrayList JavaDoc;
49 import java.util.List JavaDoc;
50
51 public class GView extends JPanel implements XJMenuItemDelegate {
52
53     protected boolean useCachedImage = true;
54     protected boolean cachedImageRerender = false;
55     protected boolean cachedImageResize = false;
56
57     protected String JavaDoc placeholder;
58     protected BufferedImage JavaDoc cachedImage = null;
59     protected Dimension outOfMemoryDimension = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
60
61     protected List JavaDoc graphs = new ArrayList JavaDoc();
62     protected int currentGraphIndex = 0;
63     protected GPanel panel;
64     protected GContext context;
65     protected XJSmoothScrolling smoothScrolling;
66                               
67     protected Point lastMouse;
68
69     protected static final Font DEFAULT_FONT = new Font("Courier", Font.BOLD, 18);
70
71     public int offset_x = 10;
72     public int offset_y = 10;
73
74     public int prev_offset_x = 0;
75     public int prev_offset_y = 0;
76
77     public GView(GPanel panel, GContext context) {
78         this.panel = panel;
79         this.context = context;
80         this.context.setContainer(this);
81
82         smoothScrolling = new XJSmoothScrolling(this, null);
83
84         setFocusable(true);
85
86         setBackground(Color.white);
87         adjustSize();
88
89         addMouseMotionListener(new DefaultMouseMotionListener());
90         addMouseListener(new DefaultMouseListener());
91         addKeyListener(new DefaultKeyListener());
92     }
93
94     public void setEnable(boolean flag) {
95         for (Object JavaDoc graph1 : graphs) {
96             GGraphAbstract graph = (GGraphAbstract) graph1;
97             graph.setEnable(flag);
98         }
99     }
100
101     public void setPlaceholder(String JavaDoc placeholder) {
102         this.placeholder = placeholder;
103     }
104
105     public void setGraphs(List JavaDoc graphs) {
106         this.graphs.clear();
107
108         if(graphs == null)
109             return;
110
111         this.graphs.addAll(graphs);
112
113         if(currentGraphIndex >= graphs.size())
114             currentGraphIndex = graphs.size()-1;
115
116         applyContext();
117     }
118
119     public List JavaDoc getGraphs() {
120         return graphs;
121     }
122
123     public void applyContext() {
124         for (Object JavaDoc graph1 : graphs) {
125             GGraphAbstract graph = (GGraphAbstract) graph1;
126             graph.setContext(context);
127         }
128     }
129
130     public void setCacheEnabled(boolean flag) {
131         if(useCachedImage != flag) {
132             useCachedImage = flag;
133             cacheInvalidate();
134         }
135     }
136
137     public boolean isCachedEnabled() {
138         return useCachedImage;
139     }
140
141     public void cacheInvalidate() {
142         cachedImage = null;
143     }
144
145     public void cacheRerender() {
146         cachedImageRerender = true;
147     }
148
149     public void setCacheResizeImage(boolean flag) {
150         cachedImageResize = flag;
151     }
152
153     public BufferedImage JavaDoc getCachedImage() {
154         return cachedImage;
155     }
156
157     public boolean setNextGraph() {
158         currentGraphIndex++;
159         if(currentGraphIndex>=graphs.size()) {
160             currentGraphIndex = graphs.size()-1;
161             return false;
162         } else
163             return true;
164     }
165
166     public boolean setPrevGraph() {
167         currentGraphIndex--;
168         if(currentGraphIndex<0) {
169             currentGraphIndex = 0;
170             return false;
171         } else
172             return true;
173     }
174
175     public int getCurrentGraphIndex() {
176         return currentGraphIndex;
177     }
178
179     public GGraphAbstract getCurrentGraph() {
180         if(graphs.size()>0)
181             return (GGraphAbstract)graphs.get(currentGraphIndex);
182         else
183             return null;
184     }
185
186     public GGraphGroup getCurrentGraphGroup() {
187         return (GGraphGroup)getCurrentGraph();
188     }
189
190     public GPathGroup getCurrentPathGroup() {
191         return getCurrentGraphGroup().pathGroup;
192     }
193
194     public GPath getCurrentPath() {
195         return getCurrentPathGroup().getCurrentPath();
196     }
197
198     public void refresh() {
199         if(getCurrentGraph() != null)
200             getCurrentGraph().render(0, 0);
201
202         cacheInvalidate();
203         adjustSize();
204         repaint();
205     }
206
207     public void refreshSizeChanged(boolean useCacheImageResize) {
208         if(useCachedImage) {
209             setCacheResizeImage(useCacheImageResize);
210             if(!useCacheImageResize) {
211                 if(getCurrentGraph() != null)
212                     getCurrentGraph().render(0, 0);
213                 cacheInvalidate();
214             }
215             adjustSize();
216             repaint();
217         } else {
218             refresh();
219         }
220     }
221
222     public void adjustSize() {
223         if(getCurrentGraph() == null || context == null)
224             return;
225
226         Dimension dimension = new Dimension(getGraphWidth()+2*offset_x, getGraphHeight()+2*offset_y);
227         setPreferredSize(dimension);
228         revalidate();
229     }
230
231     public int getGraphWidth() {
232         if(getCurrentGraph().getDimension() == null)
233             return 400;
234         else
235             return (int)getCurrentGraph().getWidth()+20;
236     }
237
238     public int getGraphHeight() {
239         if(getCurrentGraph().getDimension() == null)
240             return 200;
241         else
242             return (int)getCurrentGraph().getHeight()+20;
243     }
244
245     public void addMenuItem(JPopupMenu menu, String JavaDoc title, int tag, Object JavaDoc object) {
246         XJMenuItem item = new XJMenuItem();
247         item.setTitle(title);
248         item.setTag(tag);
249         item.setObject(object);
250         item.setDelegate(this);
251
252         menu.add(item.getSwingComponent());
253     }
254
255     public JPopupMenu getContextualMenu() {
256         return null;
257     }
258
259     public void handleMenuEvent(XJMenu menu, XJMenuItem item) {
260     }
261
262     public void processMouseEvent(MouseEvent e) {
263         if(e.isPopupTrigger()) {
264             JPopupMenu menu = getContextualMenu();
265             if(menu != null)
266                 menu.show(this, e.getX(), e.getY());
267         } else
268             super.processMouseEvent(e);
269     }
270
271     public void pathCurrentElementDidChange() {
272         GPath path = getCurrentPath();
273         Rectangle rect = path.getBoundsOfSelectedElement();
274         if(!rect.isEmpty()) {
275             // Expand the rectangle a little bit so the rectangle is "more" visible
276
rect.x -= 50;
277             rect.y -= 50;
278             rect.width += 100;
279             rect.height += 100;
280             smoothScrolling.scrollTo(rect);
281         }
282     }
283
284     public boolean canDraw() {
285         return getCurrentGraph() != null && getCurrentGraph().getDimension() != null && getCurrentGraph().isRendered();
286     }
287
288     public void render(Graphics2D g2d) {
289         context.offsetX = offset_x;
290         context.offsetY = offset_y;
291         context.setGraphics2D(g2d);
292         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
293         g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
294         getCurrentGraph().draw();
295     }
296
297     public void paintComponent(Graphics g) {
298         super.paintComponent(g);
299
300         if(!canDraw()) {
301             paintPlaceholder(g);
302             return;
303         }
304
305         int width = getGraphWidth()+offset_x;
306         int height = getGraphHeight()+offset_y+1;
307
308         if(useCachedImage) {
309             boolean sizeChanged = cachedImage != null && (cachedImage.getWidth() != width || cachedImage.getHeight() != height);
310
311             if(sizeChanged) {
312                 // Discard the cache image only if it already exists and if the cachedImageResize flag is false.
313
// The cachedImageResize flag indicates, if true, that we should use the cachedImage
314
// instead of re-creating a new one (useful for fast live resize).
315
if(!cachedImageResize && cachedImage != null) {
316                     cachedImage.flush();
317                     cachedImage = null;
318                 }
319             }
320
321             if(cachedImage == null) {
322                 // Create a new cache image.
323
// @todo See what to do with this memory problem (leak somewhere)
324
if(width<outOfMemoryDimension.width && height<outOfMemoryDimension.height) {
325                     try {
326                         cachedImage = new BufferedImage JavaDoc(width, height, BufferedImage.TYPE_3BYTE_BGR);
327                         Graphics2D gCache = (Graphics2D)cachedImage.getGraphics();
328                         gCache.setColor(Color.white);
329                         gCache.fillRect(0, 0, width, height);
330                         render(gCache);
331                         gCache.dispose();
332                     } catch(OutOfMemoryError JavaDoc e) {
333                         outOfMemoryDimension.width = width;
334                         outOfMemoryDimension.height = height;
335                         cachedImage = null;
336                         System.err.println("Out of memory, disabling cache ("+(int)(width*height*3.0/(1024*1024))+" Mb)");
337                     }
338                 }
339             } else if(cachedImageRerender) {
340                 // Only render the cachedImage without re-creating it again
341
Graphics2D gCache = (Graphics2D)cachedImage.getGraphics();
342                 gCache.setColor(Color.white);
343                 gCache.fillRect(0, 0, width, height);
344                 render(gCache);
345                 gCache.dispose();
346                 cachedImageRerender = false;
347             }
348         }
349
350         if(cachedImage == null)
351             render((Graphics2D)g);
352         else
353             g.drawImage(cachedImage, 0, 0, width, height, null);
354
355         if(!cachedImageResize && getCurrentGraph() instanceof GGraphGroup) {
356             // Draw the selected segment of a path (and only if we are not resizing using only the cached image)
357
Graphics2D g2d = (Graphics2D)g;
358             context.offsetX = offset_x;
359             context.offsetY = offset_y;
360             context.setGraphics2D(g2d);
361             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
362             g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
363
364             getCurrentPathGroup().drawSelectedElement();
365         }
366     }
367
368     public void paintPlaceholder(Graphics g) {
369         if(placeholder == null)
370             return;
371
372         g.setFont(DEFAULT_FONT);
373
374         FontMetrics fm = g.getFontMetrics();
375         Rectangle r = getVisibleRect();
376         int x = r.x+r.width/2-fm.stringWidth(placeholder)/2;
377         int y = r.y+r.height/2+fm.getHeight()/2;
378
379         g.setColor(Color.gray);
380         g.drawString(placeholder, x, y);
381     }
382
383     public class DefaultMouseMotionListener extends MouseMotionAdapter {
384
385         public void mouseDragged(MouseEvent e) {
386             if(lastMouse == null)
387                 return;
388
389             Point mouse = e.getPoint();
390             int dx = mouse.x - lastMouse.x;
391             int dy = mouse.y - lastMouse.y;
392             offset_x = prev_offset_x+dx;
393             offset_y = prev_offset_y+dy;
394             refresh();
395         }
396
397         public void mouseMoved(MouseEvent e) {
398         }
399     }
400
401     public class DefaultMouseListener extends MouseAdapter {
402
403         public void mousePressed(MouseEvent e) {
404             if(!isFocusOwner())
405                 requestFocusInWindow();
406
407             setCacheEnabled(false);
408             prev_offset_x = offset_x;
409             prev_offset_y = offset_y;
410             lastMouse = e.getPoint();
411
412             if(getCurrentGraph() instanceof GGraphGroup)
413                 handleMousePressedInGraphGroup(e);
414
415             /** In the future, if someone wants to know which link
416              * is under the mouse location, use the following code:
417              * GGraph g = (GGraph)getCurrentGraph();
418                 GLink link = g.findLinkAtPosition(e.getX(), e.getY());
419                 if(link != null) {
420                     // Do something with link
421                 }
422              */

423         }
424
425         public void mouseReleased(MouseEvent e) {
426             lastMouse = null;
427             setCacheEnabled(true);
428             // FIX AW-76. Need to trigger a repaint so the cache is created again. Otherwise
429
// it is null and will prevent exporting the image into the bitmap
430
repaint();
431         }
432
433         public void handleMousePressedInGraphGroup(MouseEvent e) {
434             getCurrentPathGroup().selectPath(e.getPoint());
435         }
436     }
437
438     public class DefaultKeyListener extends KeyAdapter {
439
440         public void keyPressed(KeyEvent e) {
441             if(getCurrentGraph() instanceof GGraphGroup)
442                 handleKeyPressedInGraphGroup(e);
443         }
444
445         public void handleKeyPressedInGraphGroup(KeyEvent e) {
446             GPath path = getCurrentPath();
447             switch(e.getKeyCode()) {
448                 case KeyEvent.VK_RIGHT:
449                     path.nextElement();
450                     pathCurrentElementDidChange();
451                     e.consume();
452                     break;
453                 case KeyEvent.VK_LEFT:
454                     path.previousElement();
455                     pathCurrentElementDidChange();
456                     e.consume();
457                     break;
458                 case KeyEvent.VK_UP:
459                     path.lastElement();
460                     pathCurrentElementDidChange();
461                     e.consume();
462                     break;
463                 case KeyEvent.VK_DOWN:
464                     path.firstElement();
465                     pathCurrentElementDidChange();
466                     e.consume();
467                     break;
468
469                 case KeyEvent.VK_A:
470                     getCurrentPathGroup().toggleShowRuleLinks();
471                     cacheRerender();
472                     e.consume();
473                     break;
474             }
475
476             if(e.isConsumed())
477                 repaint();
478         }
479     }
480 }
481
Popular Tags