View Javadoc

1   package de.matthias_burbach.mosaique4eclipse.views;
2   
3   import java.util.ArrayList;
4   import java.util.Iterator;
5   import java.util.LinkedList;
6   import java.util.List;
7   
8   import org.eclipse.core.resources.IWorkspaceRoot;
9   import org.eclipse.jface.viewers.TreeViewer;
10  import org.eclipse.swt.SWT;
11  import org.eclipse.swt.events.MouseAdapter;
12  import org.eclipse.swt.events.MouseEvent;
13  import org.eclipse.swt.events.MouseTrackAdapter;
14  import org.eclipse.swt.graphics.Point;
15  import org.eclipse.swt.graphics.Rectangle;
16  import org.eclipse.swt.layout.GridData;
17  import org.eclipse.swt.layout.GridLayout;
18  import org.eclipse.swt.widgets.Composite;
19  import org.eclipse.swt.widgets.Control;
20  import org.eclipse.swt.widgets.Display;
21  import org.eclipse.swt.widgets.Label;
22  import org.eclipse.swt.widgets.Shell;
23  import org.eclipse.swt.widgets.TreeItem;
24  
25  import de.matthias_burbach.mosaique.swing.AbstractFileItemNode;
26  import de.matthias_burbach.mosaique.swing.DefinitionNode;
27  import de.matthias_burbach.mosaique.swing.InsertNode;
28  import de.matthias_burbach.mosaique.swing.JspNode;
29  import de.matthias_burbach.mosaique.swing.PutNode;
30  
31  /***
32   * Displays the tree of Struts configs, logical pages, Tiles definitions,
33   * JSPs etc. within the Mosaique Eclipse view.
34   *
35   * @author Matthias Burbach
36   */
37  public class MosaiqueTreeViewer extends TreeViewer {
38      /***
39       * Intercepts construction to set up the tool tip handler.
40       *
41       * @param parent The parent composite.
42       */
43      public MosaiqueTreeViewer(final Composite parent) {
44          super(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
45          ToolTipHandler toolTipHandler = new ToolTipHandler(parent.getShell());
46          toolTipHandler.activateHoverHelp(getTree());
47      }
48  
49      /***
50       * This tool tip solution is an adapted version of source code from
51       * Andrei Loskutov's JDepend plugin.
52       *
53       * Emulated tooltip handler
54       * Notice that we could display anything in a tooltip besides text and
55       * images.
56       */
57      private final class ToolTipHandler {
58          /***
59           * The shell used to display the tip.
60           */
61          private Shell tipShell;
62  
63          /***
64           * The label to display an image as tool tip. Not really used currently.
65           */
66          private Label tipLabelImage;
67  
68          /***
69           * The label to display a text as tool tip.
70           */
71          private Label tipLabelText;
72  
73          /***
74           * The position being hovered over.
75           */
76          private Point tipPosition;
77  
78          /***
79           * Creates a new tooltip handler
80           *
81           * @param parent the parent Shell
82           */
83          public ToolTipHandler(final Shell parent) {
84              final Display display = parent.getDisplay();
85  
86              tipShell = new Shell(parent, SWT.ON_TOP);
87              GridLayout gridLayout = new GridLayout();
88              gridLayout.numColumns = 2;
89              gridLayout.marginWidth = 2;
90              gridLayout.marginHeight = 2;
91              tipShell.setLayout(gridLayout);
92  
93              tipShell.setBackground(
94                      display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
95  
96              tipLabelImage = new Label(tipShell, SWT.NONE);
97              tipLabelImage.setForeground(
98                      display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
99              tipLabelImage.setBackground(
100                     display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
101             tipLabelImage.setLayoutData(
102                     new GridData(GridData.FILL_HORIZONTAL
103                                     | GridData.VERTICAL_ALIGN_CENTER));
104 
105             tipLabelText = new Label(tipShell, SWT.NONE);
106             tipLabelText.setForeground(
107                     display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
108             tipLabelText.setBackground(
109                     display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
110             tipLabelText.setLayoutData(
111                     new GridData(GridData.FILL_HORIZONTAL
112                                     | GridData.VERTICAL_ALIGN_CENTER));
113         }
114 
115         /***
116          * Enables customized hover help for a specified control
117          *
118          * @param control the control on which to enable hoverhelp
119          */
120         public void activateHoverHelp(final Control control) {
121             /*
122              * Get out of the way if we attempt to activate the control
123              * underneath the tooltip
124              */
125             control.addMouseListener(new MouseAdapter () {
126                 public void mouseDown(final MouseEvent e) {
127                     if (tipShell.isVisible()) {
128                         tipShell.setVisible(false);
129                     }
130                 }
131             });
132 
133             /*
134              * Trap hover events to pop-up tooltip
135              */
136             control.addMouseTrackListener(new MouseTrackAdapter () {
137                 public void mouseExit(final MouseEvent e) {
138                     if (tipShell.isVisible()) {
139                         tipShell.setVisible(false);
140                     }
141                 }
142                 public void mouseHover(final MouseEvent event) {
143                     Point pt = new Point (event.x, event.y);
144                     TreeItem ti = MosaiqueTreeViewer.this.getTree().getItem(pt);
145                     if (ti == null || ti.getText() == null) {
146                         return;
147                     }
148                     String toolTipText = getToolTipText(ti);
149                     if (toolTipText == null || toolTipText.length() == 0) {
150                         tipShell.setVisible(false);
151                         return;
152                     }
153                     tipPosition = control.toDisplay(pt);
154 
155                     tipLabelText.setText(toolTipText);
156                     //tipLabelImage.setImage(image); // accepts null
157                     tipShell.pack();
158                     setHoverLocation(tipShell, tipPosition);
159                     tipShell.setVisible(true);
160                 }
161             });
162         }
163 
164         /***
165          * @param treeItem The tree item to get the tool tip text for.
166          * @return The tool tip text.
167          */
168         protected String getToolTipText(final TreeItem treeItem) {
169             String result = null;
170             Object data = treeItem.getData();
171             if (data instanceof AbstractFileItemNode) {
172                 AbstractFileItemNode node = (AbstractFileItemNode) data;
173                 result = node.getMessage();
174             }
175             if (result == null) {
176                 if (data instanceof PutNode) {
177                     PutNode node = (PutNode) data;
178                     result = "value='" + node.getPut().getValue() + "'";
179                 } else if (data instanceof JspNode) {
180                     JspNode node = (JspNode) data;
181                     result = node.getFileItem().getFilePath();
182                 } else if (data instanceof DefinitionNode) {
183                     DefinitionNode node = (DefinitionNode) data;
184                     result =
185                         "Defined in '"
186                         + node.getFileItem().getFilePath()
187                         + "'";
188                 } else if (data instanceof InsertNode) {
189                     //InsertNode node = (InsertNode) data;
190                     result = null;
191                 }
192             }
193             return result;
194         }
195 
196         /***
197          * Sets the location for a hovering shell
198          * @param shell the object that is to hover
199          * @param position the position of a widget to hover over
200          */
201         protected void setHoverLocation(
202                 final Shell shell, final Point position) {
203             Rectangle displayBounds = shell.getDisplay().getBounds();
204             Rectangle shellBounds = shell.getBounds();
205             final int maxWidth = 8;
206             final int maxHeight = 16;
207             shellBounds.x = Math.max(
208                     Math.min(
209                             position.x + maxWidth,
210                             displayBounds.width - shellBounds.width),
211                     0);
212             shellBounds.y = Math.max(
213                     Math.min(
214                             position.y + maxHeight,
215                             displayBounds.height - shellBounds.height),
216                     0);
217             shell.setBounds(shellBounds);
218         }
219     }
220 
221     /***
222      * @return The list of paths of all elements being currently expanded in the
223      *         tree. The paths are of type {@link String}.
224      */
225     public List getExpandedElementPaths() {
226         List result = new ArrayList();
227         Object[] expandedElements = getExpandedElements();
228         for (int i = 0; i < expandedElements.length; i++) {
229             List path = getElementPath(expandedElements[i]);
230             result.add(path);
231         }
232         return result;
233     }
234 
235     /***
236      * @param expandedElementPaths The list of paths of all elements to be
237      *                             expanded in the tree. The paths must be of
238      *                             type {@link List} of elements of type
239      *                             {@link String}. The strings are the segments
240      *                             of the path.
241      */
242     public void setExpandedElementPaths(final List expandedElementPaths) {
243         List expandedElements = new ArrayList();
244         for (Iterator iter = expandedElementPaths.iterator(); iter.hasNext();) {
245             List path = (List) iter.next();
246             Object element = getElementForPath(null, path);
247             if (element != null) {
248                 expandedElements.add(element);
249             }
250         }
251         setExpandedElements(expandedElements.toArray());
252     }
253 
254     /***
255      * Maps an element displayed in the tree to its path.
256      *
257      * @param element The element to map.
258      * @return The path as list of list of path segments of type {@link String}.
259      */
260     private List getElementPath(final Object element) {
261         LinkedList result = new LinkedList();
262         result.add(element.toString());
263         MosaiqueTreeContentProvider provider = getMosaiqueContentProvider();
264         Object parent = provider.getParent(element);
265         while (parent != null && !(parent instanceof IWorkspaceRoot)) {
266             result.addFirst(parent.toString());
267             parent = provider.getParent(parent);
268         }
269         return result;
270     }
271 
272     /***
273      * Maps a path to an element in the tree.
274      *
275      * @param aRoot The ancestor of the element which is the root of the given
276      *             path. Defaults to the very root of the tree.
277      * @param path The path as list of segments of type {@link String}.
278      * @return The element found under the path or <code>null</code>.
279      */
280     private Object getElementForPath(final Object aRoot, final List path) {
281         Object result = null;
282         MosaiqueTreeContentProvider provider = getMosaiqueContentProvider();
283         Object root = aRoot;
284         if (root == null) {
285             root = provider.getRoot();
286         }
287         if (path.size() > 0) {
288             String nextChildName = (String) path.get(0);
289             Object nextChild = getChildForName(root, nextChildName);
290             if (nextChild != null && path.size() > 1) {
291                 result = getElementForPath(
292                         nextChild, path.subList(1, path.size()));
293             } else {
294                 result = nextChild;
295             }
296         }
297         return result;
298     }
299 
300     /***
301      * Scans all children of the given parent for the child matching the given
302      * name.
303      *
304      * @param parent The parent whose children to scan.
305      * @param childName The name of the child to find.
306      * @return The child with the given name or <code>null</code>.
307      */
308     private Object getChildForName(
309             final Object parent, final String childName) {
310         Object result = null;
311         MosaiqueTreeContentProvider provider = getMosaiqueContentProvider();
312         Object[] children = provider.getChildren(parent);
313         for (int i = 0; i < children.length; i++) {
314             if (children[i].toString().equals(childName)) {
315                 result = children[i];
316                 break;
317             }
318         }
319         return result;
320     }
321 
322     /***
323      * Gives typed access to this tree viewer's content provider.
324      *
325      * @return The MosaiqueTreeContentProvider.
326      */
327     private MosaiqueTreeContentProvider getMosaiqueContentProvider() {
328         MosaiqueTreeContentProvider provider =
329             (MosaiqueTreeContentProvider) getContentProvider();
330         return provider;
331     }
332 }