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

Quick Search    Search Deep

Source code: com/port80/eclipse/jdt/graph/views/GraphViewer.java


1   package com.port80.eclipse.jdt.graph.views;
2   
3   import java.awt.image.BufferedImage;
4   import java.io.File;
5   import java.io.FileInputStream;
6   import java.io.FileNotFoundException;
7   import java.io.FileOutputStream;
8   import java.io.IOException;
9   import java.io.InputStream;
10  import java.io.PrintWriter;
11  import java.util.ArrayList;
12  import java.util.Comparator;
13  import java.util.HashMap;
14  import java.util.Iterator;
15  import java.util.List;
16  import java.util.Map;
17  import java.util.Set;
18  
19  import org.eclipse.core.resources.IMarker;
20  import org.eclipse.core.runtime.IProgressMonitor;
21  import org.eclipse.jface.action.IStatusLineManager;
22  import org.eclipse.jface.viewers.ILabelProvider;
23  import org.eclipse.jface.viewers.ILabelProviderListener;
24  import org.eclipse.jface.viewers.ISelection;
25  import org.eclipse.jface.viewers.ISelectionChangedListener;
26  import org.eclipse.jface.viewers.ISelectionProvider;
27  import org.eclipse.jface.viewers.IStructuredContentProvider;
28  import org.eclipse.jface.viewers.IStructuredSelection;
29  import org.eclipse.jface.viewers.SelectionChangedEvent;
30  import org.eclipse.jface.viewers.StructuredSelection;
31  import org.eclipse.jface.viewers.Viewer;
32  import org.eclipse.swt.SWT;
33  import org.eclipse.swt.events.DisposeEvent;
34  import org.eclipse.swt.events.DisposeListener;
35  import org.eclipse.swt.events.KeyEvent;
36  import org.eclipse.swt.events.KeyListener;
37  import org.eclipse.swt.events.MenuAdapter;
38  import org.eclipse.swt.events.MenuEvent;
39  import org.eclipse.swt.events.MouseAdapter;
40  import org.eclipse.swt.events.MouseEvent;
41  import org.eclipse.swt.events.SelectionAdapter;
42  import org.eclipse.swt.events.SelectionEvent;
43  import org.eclipse.swt.graphics.GC;
44  import org.eclipse.swt.graphics.Image;
45  import org.eclipse.swt.graphics.ImageData;
46  import org.eclipse.swt.graphics.PaletteData;
47  import org.eclipse.swt.graphics.Point;
48  import org.eclipse.swt.graphics.custom.DirtyRectangle;
49  import org.eclipse.swt.widgets.Composite;
50  import org.eclipse.swt.widgets.Control;
51  import org.eclipse.swt.widgets.Menu;
52  import org.eclipse.swt.widgets.MenuItem;
53  import org.eclipse.ui.IEditorInput;
54  import org.eclipse.ui.IEditorSite;
55  import org.eclipse.ui.PartInitException;
56  import org.eclipse.ui.internal.WorkbenchWindow;
57  import org.eclipse.ui.part.EditorPart;
58  import org.eclipse.ui.part.FileEditorInput;
59  
60  import com.port80.eclipse.util.ColorFactory;
61  import com.port80.eclipse.util.GraphEditorInput;
62  import com.port80.eclipse.util.ImageFactory;
63  import com.port80.graph.IGraph;
64  import com.port80.graph.IVertex;
65  import com.port80.graph.dot.impl.Dot;
66  import com.port80.graph.dot.parser.DotParser;
67  import com.port80.graph.impl.GraphPanel;
68  import com.port80.swt.widgets.GraphViewIncrementalFinder;
69  import com.port80.swt.widgets.IGraphViewer;
70  import com.port80.swt.widgets.IStatusLine;
71  import com.port80.swt.widgets.ImageRegionInfo;
72  import com.port80.swt.widgets.ScrolledCanvas;
73  import com.port80.util.Msg;
74  
75  /**
76   * A graph viewer in eclipse to view graph rendered in a BufferedImage.
77   * 
78   * @author chrisl
79   */
80  public class GraphViewer extends EditorPart implements IGraphViewer, ISelectionProvider, KeyListener {
81  
82    ////////////////////////////////////////////////////////////////////////
83  
84    private static final String NAME = "GraphViewer";
85    private static final boolean DEBUG = true;
86    private static final int SEED = -7;
87    private static final int PASSES = -7;
88  
89    private static final int ALPHA_HIGHLIGHT = 0x18;
90    private static final int COLOR_HIGHLIGHT = 0x000000;
91  
92    ////////////////////////////////////////////////////////////////////////
93  
94    private IGraph fGraph;
95    private String fFilepath;
96    private Image fImage;
97    private Menu fPopup;
98    private IStatusLine fStatusLine;
99    private ScrolledCanvas fCanvas;
100   private GraphContentProvider fContentProvider;
101   private GraphLabelProvider fLabelProvider;
102   private GraphLabelComparator fLabelComparator;
103   private List fSelection;
104   private List fSelectionListeners;
105   private boolean fDirty;
106   private boolean fBeginFindSession;
107   private boolean fForwardFind;
108   /** 
109    * The list of ImageRegionInfo of the selected regions in the back buffer.
110    * When region is deselected, image is restore into the back buffer.
111    */
112   private List fSelectedRegions;
113 
114   ////////////////////////////////////////////////////////////////////////
115 
116   /**
117    * @see org.eclipse.ui.IEditorPart#doSave(IProgressMonitor)
118    */
119   public void doSave(IProgressMonitor monitor) {
120     if (fFilepath != null && fFilepath.length() > 0) {
121       Msg.println(NAME + ".saveGraph(): filename=" + fFilepath);
122       fGraph.saveImage(fFilepath, 1.0f);
123       if (!fFilepath.endsWith(".dot"))
124         fFilepath += ".dot";
125       File ifile = Msg.createFile(fFilepath);
126       if (ifile != null) {
127         try {
128           PrintWriter writer = new PrintWriter(new FileOutputStream(ifile));
129           writer.println(fGraph.sprintGraph());
130           writer.close();
131         } catch (FileNotFoundException e) {
132           Msg.println(NAME + ".saveGraph(): Can't open output .dot file: " + fFilepath);
133         }
134       }
135     }
136     fDirty = false;
137   }
138 
139   /**
140    * @see org.eclipse.ui.IEditorPart#doSaveAs()
141    */
142   public void doSaveAs() {
143   }
144 
145   /**
146    * @see org.eclipse.ui.IEditorPart#gotoMarker(IMarker)
147    */
148   public void gotoMarker(IMarker marker) {
149   }
150 
151   /**
152    * @see org.eclipse.ui.IEditorPart#init(IEditorSite, IEditorInput)
153    */
154   public void init(IEditorSite site, IEditorInput input) throws PartInitException {
155     if (!(input instanceof FileEditorInput) && !(input instanceof GraphEditorInput)) {
156       throw new PartInitException("Input=" + input.getName());
157     }
158     fSelection = new ArrayList();
159     fSelectionListeners = new ArrayList();
160     fSelectedRegions = new ArrayList();
161     fLabelComparator = new GraphLabelComparator();
162     setInput(input);
163     setSite(site);
164     setTitle(input.getName());
165     setTitleToolTip(input.getToolTipText());
166   }
167 
168   public void setInput(IEditorInput input) {
169     super.setInput(input);
170     //
171     fGraph = loadGraph(input);
172     if (fGraph == null)
173       return;
174     //
175     fContentProvider = new GraphContentProvider(fGraph);
176     fLabelProvider = new GraphLabelProvider(fGraph);
177     fSelection.clear();
178     fSelectedRegions.clear();
179   }
180 
181   /**
182    * @see org.eclipse.ui.IEditorPart#isDirty()
183    */
184   public boolean isDirty() {
185     return fDirty;
186   }
187 
188   /**
189    * @see org.eclipse.ui.IEditorPart#isSaveAsAllowed()
190    */
191   public boolean isSaveAsAllowed() {
192     return false;
193   }
194 
195   /**
196    * @see org.eclipse.ui.IWorkbenchPart#createPartControl(Composite)
197    */
198   public void createPartControl(Composite parent) {
199     fCanvas =
200       new ScrolledCanvas(
201         parent,
202         SWT.H_SCROLL | SWT.V_SCROLL );
203     fPopup = createPopup();
204     fCanvas.setMenu(fPopup);
205     fCanvas.setBackground(ColorFactory.getDefault().create(0xffffff));
206     fPopup.addMenuListener(new MenuAdapter() {
207       public void menuShown(MenuEvent e) {
208         showPopup(e);
209       }
210     });
211     //
212     BufferedImage image = new GraphPanel(fGraph, 1.0).getImage();
213     int w = image.getWidth();
214     int h = image.getHeight();
215     ImageData data = new ImageData(w, h, 24, new PaletteData(0xff0000, 0xff00, 0xff));
216     int[] pixels = new int[w];
217     for (int y = 0; y < h; ++y) {
218       image.getRGB(0, y, w, 1, pixels, 0, w);
219       data.setPixels(0, y, w, pixels, 0);
220     }
221     //data=ImageFactory.deriveIndexed(data);
222     fImage = new Image(parent.getDisplay(), data);
223     //
224     fCanvas.setImage(fImage);
225     //
226     fCanvas.addKeyListener(this);
227     fCanvas.addMouseListener(new MouseAdapter() {
228       public void mouseDown(MouseEvent e) {
229         if (e.button == 2) {
230           Point p = getCanvas().getViewOffset();
231           getCanvas().centerAt(e.x - p.x, e.y - p.y);
232         }
233       }
234       public void mouseDoubleClick(MouseEvent e) {
235         Point p = getCanvas().getViewOffset();
236         getCanvas().centerAt(e.x - p.x, e.y - p.y);
237       }
238     });
239     //
240     parent.addDisposeListener(new DisposeListener() {
241       public void widgetDisposed(DisposeEvent e) {
242         Image image=getImage();
243         if (image != null && !image.isDisposed())
244           image.dispose();
245       }
246     });
247     //
248     WorkbenchWindow window = (WorkbenchWindow) getSite().getWorkbenchWindow();
249     fStatusLine=new StatusLine(window.getActionBars().getStatusLineManager());    
250   }
251 
252   /**
253    * @see org.eclipse.ui.IWorkbenchPart#setFocus()
254    */
255   public void setFocus() {
256   }
257 
258   /**
259    * @see org.eclipse.ui.IEditorPart#isSaveOnCloseNeeded()
260    */
261   public boolean isSaveOnCloseNeeded() {
262     return true;
263   }
264 
265   ////////////////////////////////////////////////////////////////////////
266 
267   public IStructuredContentProvider getContentProvider() {
268     return fContentProvider;
269   }
270 
271   public ILabelProvider getLabelProvider() {
272     return fLabelProvider;
273   }
274 
275   public Comparator getLabelComparator() {
276     return fLabelComparator;
277   }
278 
279   public Control getControl() {
280     return fCanvas;
281   }
282 
283   public void refresh() {
284     fCanvas.redraw();
285   }
286 
287   ScrolledCanvas getCanvas() {
288     return fCanvas;
289   }
290   
291   Image getImage() {
292     return fImage;
293   }
294   
295   // ISelectionProvider interface ////////////////////////////////////////
296   //
297 
298   public void setSelection(ISelection selection) {
299     if (selection == null || !(selection instanceof IStructuredSelection))
300       return;
301     setSelection((IStructuredSelection) selection, false);
302   }
303 
304   public void setSelection(IStructuredSelection selection, boolean reveal) {
305     deHighlightSelection();
306     fSelection.clear();
307     for (Iterator it = selection.iterator(); it.hasNext();) {
308       Object a = it.next();
309       if (a instanceof IVertex) {
310         fSelection.add(a);
311       }
312     }
313     for (int i = 0; i < fSelectionListeners.size(); ++i) {
314       ISelectionChangedListener listener = (ISelectionChangedListener) fSelectionListeners.get(i);
315       listener.selectionChanged(new SelectionChangedEvent(this, new StructuredSelection(fSelection)));
316     }
317     highlightSelection();
318     if (reveal) {
319       IVertex a = (IVertex) fSelection.get(fSelection.size() - 1);
320       java.awt.geom.Rectangle2D bounds = (java.awt.geom.Rectangle2D) a.getAttr("-bounds");
321       fCanvas.centerAt(
322         (int) (bounds.getX() + bounds.getWidth() / 2),
323         (int) (bounds.getY() + bounds.getHeight() / 2));
324     } else
325       fCanvas.redraw();
326   }
327 
328   public ISelection getSelection() {
329     return new StructuredSelection(fSelection);
330   }
331 
332   public void addSelectionChangedListener(ISelectionChangedListener listener) {
333     fSelectionListeners.add(listener);
334   }
335 
336   public void removeSelectionChangedListener(ISelectionChangedListener listener) {
337     fSelectionListeners.remove(listener);
338   }
339 
340   private void deHighlightSelection() {
341     if (fSelectedRegions.size() == 0)
342       return;
343     GC gc = new GC(fImage);
344     ImageRegionInfo info;
345     for (int i = 0; i < fSelectedRegions.size(); ++i) {
346       info = (ImageRegionInfo) fSelectedRegions.get(i);
347       gc.drawImage(info.image, info.x, info.y);
348       info.image.dispose();
349     }
350     gc.dispose();
351     fSelectedRegions.clear();
352   }
353 
354   private void highlightSelection() {
355     if (fSelection.size() == 0)
356       return;
357     DirtyRectangle dirtyrect = new DirtyRectangle(0, 0, 0, 0);
358     IVertex v;
359     java.awt.geom.Rectangle2D bounds;
360     ImageRegionInfo info;
361     for (int i = 0; i < fSelection.size(); ++i) {
362       v = (IVertex) fSelection.get(i);
363       bounds = (java.awt.geom.Rectangle2D) v.getAttr("-bounds");
364       info = new ImageRegionInfo(bounds);
365       fSelectedRegions.add(info);
366       dirtyrect.add(0, 0, info.width, info.height);
367     }
368     Image fog =
369       ImageFactory.getDefault().createFog(
370         ALPHA_HIGHLIGHT,
371         COLOR_HIGHLIGHT,
372         dirtyrect.width,
373         dirtyrect.height,
374         null);
375     GC gc = new GC(fImage);
376     for (int i = 0; i < fSelectedRegions.size(); ++i) {
377       info = (ImageRegionInfo) fSelectedRegions.get(i);
378       gc.copyArea(info.image, info.x, info.y);
379       gc.drawImage(fog, 0, 0, info.width, info.height, info.x, info.y, info.width, info.height);
380     }
381     fog.dispose();
382     gc.dispose();
383   }
384 
385   ////////////////////////////////////////////////////////////////////////
386 
387   /**
388    * @see org.eclipse.swt.events.KeyListener#keyPressed(KeyEvent)
389    */
390   public void keyPressed(KeyEvent e) {
391     if (DEBUG)
392       Msg.println(
393         NAME
394           + ".keyPressed(): character="
395           + e.character
396           + ", keycode="
397           + e.keyCode
398           + ", modifier="
399           + e.stateMask);
400     if (e.character == 's' || e.character == 'r') {
401       fBeginFindSession = true;
402       fForwardFind = (e.character == 's');
403     }
404   }
405 
406   /**
407    * @see org.eclipse.swt.events.KeyListener#keyReleased(KeyEvent)
408    */
409   public void keyReleased(KeyEvent e) {
410     if (fBeginFindSession) {
411       fBeginFindSession = false;
412       beginIncrementalFind(fForwardFind);
413     }
414   }
415 
416   ////////////////////////////////////////////////////////////////////////
417 
418   private IGraph loadGraph(IEditorInput input) {
419     IGraph ret = null;
420     String filepath = null;
421     if (input instanceof GraphEditorInput) {
422       ret = (IGraph) input.getAdapter(IGraph.class);
423       if (ret != null)
424         return ret;
425       filepath = ((GraphEditorInput) input).getFilepath();
426     } else if (input instanceof FileEditorInput)
427       filepath = ((FileEditorInput) input).getFile().getLocation().toString();
428     if (filepath == null)
429       return null;
430     InputStream istream = null;
431     try {
432       istream = new FileInputStream(filepath);
433     } catch (FileNotFoundException e) {
434       Msg.err("filepath=" + filepath, e);
435       return null;
436     }
437     DotParser parser = new DotParser(istream, filepath);
438     ret = parser.parse();
439     try {
440       istream.close();
441     } catch (IOException e) {
442     }
443     //
444     if (ret.getAttr("bb") == null) {
445       Dot.dot(ret, SEED, PASSES);
446     }
447     return ret;
448   }
449 
450   private Menu createPopup() {
451     Menu ret = new Menu(fCanvas);
452     MenuItem item = new MenuItem(ret, SWT.PUSH);
453     item.setText("GraphViewer Menu");
454     item.setEnabled(false);
455     new MenuItem(ret, SWT.SEPARATOR);
456     item = new MenuItem(ret, SWT.PUSH);
457     item.setText("&Incremental Find");
458     item.addSelectionListener(new SelectionAdapter() {
459       public void widgetSelected(SelectionEvent e) {
460         beginIncrementalFind(true);
461       }
462     });
463     return ret;
464   }
465 
466   void showPopup(MenuEvent e) {
467   }
468 
469   void beginIncrementalFind(boolean forward) {
470     GraphViewIncrementalFinder finder =
471       new GraphViewIncrementalFinder(this, fStatusLine, this);
472     String defaultString = null;
473     //    if (fSelection.size() > 0) {
474     //      IVertex selected = (IVertex) fSelection.get(0);
475     //      defaultString = fLabelProvider.getText(selected);
476     //    }
477     finder.beginSession(forward, defaultString);
478   }
479 
480   ////////////////////////////////////////////////////////////////////////
481 
482   static class GraphContentProvider implements IStructuredContentProvider {
483     IGraph fGraph;
484     public GraphContentProvider(IGraph graph) {
485       fGraph = graph;
486     }
487     public Object[] getElements(Object inputElement) {
488       if (fGraph == null)
489         return null;
490       Set vts = fGraph.allVertices();
491       return vts.toArray(new IVertex[vts.size()]);
492     }
493     public void dispose() {
494     }
495     public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
496     }
497   }
498 
499   static class GraphLabelProvider implements ILabelProvider {
500     private Map fLabelTable = new HashMap();
501     public GraphLabelProvider(IGraph graph) {
502       Set vts = graph.allVertices();
503       for (Iterator it = vts.iterator(); it.hasNext();) {
504         IVertex v = (IVertex) it.next();
505         fLabelTable.put(v, internalGetText(v));
506       }
507     }
508     public Image getImage(Object element) {
509       return null;
510     }
511     public String getText(Object element) {
512       return (String) fLabelTable.get(element);
513     }
514     public void addListener(ILabelProviderListener listener) {
515     }
516     public void dispose() {
517     }
518     public boolean isLabelProperty(Object element, String property) {
519       return false;
520     }
521     public void removeListener(ILabelProviderListener listener) {
522     }
523     private String internalGetText(Object element) {
524       if (!(element instanceof IVertex))
525         return null;
526       String ret = ((IVertex) element).getAttrString("label");
527       if (ret != null) {
528         return stripTags(ret);
529       }
530       return ((IVertex) element).getName();
531     }
532     /** Strip HTML like tags. */
533     private String stripTags(String s) {
534       char c;
535       StringBuffer ret = new StringBuffer();
536       for (int i = 0; i < s.length(); ++i) {
537         c = s.charAt(i);
538         if (c == '<')
539           i = skipTag(s, i + 1);
540         else
541           ret.append(c);
542       }
543       return ret.toString();
544     }
545     /** Increment index to the next '>' */
546     private int skipTag(String s, int index) {
547       int len = s.length();
548       while (index < len && s.charAt(index) != '>')
549         ++index;
550       return index;
551     }
552   }
553 
554   class GraphLabelComparator implements Comparator {
555     public int compare(Object a, Object b) {
556       String name1 = getLabelProvider().getText((IVertex) a);
557       String name2 = getLabelProvider().getText((IVertex) b);
558       if (name1 == null && name2 != null)
559         return -1;
560       if (name1 == null && name2 == null)
561         return 0;
562       if (name1 != null && name2 == null)
563         return 1;
564       return name1.compareTo(name2);
565     }
566   }
567 
568   class StatusLine implements IStatusLine {
569     IStatusLineManager fManager;
570     public StatusLine(IStatusLineManager manager) {
571       fManager=manager;
572     }
573     public void setMessage(String message) {
574       fManager.setMessage(message);
575     }
576     public void setErrorMessage(String message) {
577       fManager.setErrorMessage(message);
578     }
579   }
580   
581   ////////////////////////////////////////////////////////////////////////
582 
583 }