A massive organize imports and formatting of the sources using default Eclipse code...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / JavaOutlineInformationControl.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.text;
12
13 import net.sourceforge.phpdt.core.ICompilationUnit;
14 import net.sourceforge.phpdt.core.IJavaElement;
15 import net.sourceforge.phpdt.core.IParent;
16 import net.sourceforge.phpdt.core.JavaModelException;
17 import net.sourceforge.phpdt.internal.ui.actions.OpenActionUtil;
18 import net.sourceforge.phpdt.internal.ui.util.StringMatcher;
19 import net.sourceforge.phpdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
20 import net.sourceforge.phpdt.internal.ui.viewsupport.DecoratingJavaLabelProvider;
21 import net.sourceforge.phpdt.internal.ui.viewsupport.JavaElementLabels;
22 import net.sourceforge.phpdt.ui.JavaElementSorter;
23 import net.sourceforge.phpdt.ui.StandardJavaElementContentProvider;
24 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
25
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.jface.text.IInformationControl;
28 import org.eclipse.jface.text.IInformationControlExtension;
29 import org.eclipse.jface.text.IInformationControlExtension2;
30 import org.eclipse.jface.viewers.AbstractTreeViewer;
31 import org.eclipse.jface.viewers.IBaseLabelProvider;
32 import org.eclipse.jface.viewers.ILabelProvider;
33 import org.eclipse.jface.viewers.IStructuredSelection;
34 import org.eclipse.jface.viewers.StructuredSelection;
35 import org.eclipse.jface.viewers.StructuredViewer;
36 import org.eclipse.jface.viewers.TreeViewer;
37 import org.eclipse.jface.viewers.Viewer;
38 import org.eclipse.jface.viewers.ViewerFilter;
39 import org.eclipse.swt.SWT;
40 import org.eclipse.swt.events.DisposeListener;
41 import org.eclipse.swt.events.FocusListener;
42 import org.eclipse.swt.events.KeyEvent;
43 import org.eclipse.swt.events.KeyListener;
44 import org.eclipse.swt.events.ModifyEvent;
45 import org.eclipse.swt.events.ModifyListener;
46 import org.eclipse.swt.events.SelectionEvent;
47 import org.eclipse.swt.events.SelectionListener;
48 import org.eclipse.swt.graphics.Color;
49 import org.eclipse.swt.graphics.FontMetrics;
50 import org.eclipse.swt.graphics.GC;
51 import org.eclipse.swt.graphics.Point;
52 import org.eclipse.swt.graphics.Rectangle;
53 import org.eclipse.swt.layout.GridData;
54 import org.eclipse.swt.layout.GridLayout;
55 import org.eclipse.swt.widgets.Composite;
56 import org.eclipse.swt.widgets.Control;
57 import org.eclipse.swt.widgets.Display;
58 import org.eclipse.swt.widgets.Label;
59 import org.eclipse.swt.widgets.Layout;
60 import org.eclipse.swt.widgets.Shell;
61 import org.eclipse.swt.widgets.Text;
62 import org.eclipse.swt.widgets.Tree;
63 import org.eclipse.swt.widgets.TreeItem;
64
65 /**
66  * @author dmegert
67  * 
68  * To change this generated comment edit the template variable "typecomment":
69  * Window>Preferences>Java>Templates. To enable and disable the creation of type
70  * comments go to Window>Preferences>Java>Code Generation.
71  */
72 public class JavaOutlineInformationControl implements IInformationControl,
73                 IInformationControlExtension, IInformationControlExtension2 {
74
75         /**
76          * The NamePatternFilter selects the elements which match the given string
77          * patterns.
78          * <p>
79          * The following characters have special meaning: ? => any character * =>
80          * any string
81          * </p>
82          * 
83          * @since 2.0
84          */
85         private static class NamePatternFilter extends ViewerFilter {
86                 private String fPattern;
87
88                 private StringMatcher fMatcher;
89
90                 private ILabelProvider fLabelProvider;
91
92                 private Viewer fViewer;
93
94                 private StringMatcher getMatcher() {
95                         return fMatcher;
96                 }
97
98                 /*
99                  * (non-Javadoc) Method declared on ViewerFilter.
100                  */
101                 public boolean select(Viewer viewer, Object parentElement,
102                                 Object element) {
103                         if (fMatcher == null)
104                                 return true;
105
106                         ILabelProvider labelProvider = getLabelProvider(viewer);
107
108                         String matchName = null;
109                         if (labelProvider != null)
110                                 matchName = ((ILabelProvider) labelProvider).getText(element);
111                         else if (element instanceof IJavaElement)
112                                 matchName = ((IJavaElement) element).getElementName();
113
114                         if (matchName != null && fMatcher.match(matchName))
115                                 return true;
116
117                         return hasUnfilteredChild(viewer, element);
118                 }
119
120                 private ILabelProvider getLabelProvider(Viewer viewer) {
121                         if (fViewer == viewer)
122                                 return fLabelProvider;
123
124                         fLabelProvider = null;
125                         IBaseLabelProvider baseLabelProvider = null;
126                         if (viewer instanceof StructuredViewer)
127                                 baseLabelProvider = ((StructuredViewer) viewer)
128                                                 .getLabelProvider();
129
130                         if (baseLabelProvider instanceof ILabelProvider)
131                                 fLabelProvider = (ILabelProvider) baseLabelProvider;
132
133                         return fLabelProvider;
134                 }
135
136                 private boolean hasUnfilteredChild(Viewer viewer, Object element) {
137                         IJavaElement[] children;
138                         if (element instanceof IParent) {
139                                 try {
140                                         children = ((IParent) element).getChildren();
141                                 } catch (JavaModelException ex) {
142                                         return false;
143                                 }
144                                 for (int i = 0; i < children.length; i++)
145                                         if (select(viewer, element, children[i]))
146                                                 return true;
147                         }
148                         return false;
149                 }
150
151                 /**
152                  * Sets the patterns to filter out for the receiver.
153                  * <p>
154                  * The following characters have special meaning: ? => any character * =>
155                  * any string
156                  * </p>
157                  */
158                 public void setPattern(String pattern) {
159                         fPattern = pattern;
160                         if (fPattern == null) {
161                                 fMatcher = null;
162                                 return;
163                         }
164                         boolean ignoreCase = pattern.toLowerCase().equals(pattern);
165                         fMatcher = new StringMatcher(pattern, ignoreCase, false);
166                 }
167         }
168
169         private static class BorderFillLayout extends Layout {
170
171                 /** The border widths. */
172                 final int fBorderSize;
173
174                 /**
175                  * Creates a fill layout with a border.
176                  */
177                 public BorderFillLayout(int borderSize) {
178                         if (borderSize < 0)
179                                 throw new IllegalArgumentException();
180                         fBorderSize = borderSize;
181                 }
182
183                 /**
184                  * Returns the border size.
185                  */
186                 public int getBorderSize() {
187                         return fBorderSize;
188                 }
189
190                 /*
191                  * @see org.eclipse.swt.widgets.Layout#computeSize(org.eclipse.swt.widgets.Composite,
192                  *      int, int, boolean)
193                  */
194                 protected Point computeSize(Composite composite, int wHint, int hHint,
195                                 boolean flushCache) {
196
197                         Control[] children = composite.getChildren();
198                         Point minSize = new Point(0, 0);
199
200                         if (children != null) {
201                                 for (int i = 0; i < children.length; i++) {
202                                         Point size = children[i].computeSize(wHint, hHint,
203                                                         flushCache);
204                                         minSize.x = Math.max(minSize.x, size.x);
205                                         minSize.y = Math.max(minSize.y, size.y);
206                                 }
207                         }
208
209                         minSize.x += fBorderSize * 2 + RIGHT_MARGIN;
210                         minSize.y += fBorderSize * 2;
211
212                         return minSize;
213                 }
214
215                 /*
216                  * @see org.eclipse.swt.widgets.Layout#layout(org.eclipse.swt.widgets.Composite,
217                  *      boolean)
218                  */
219                 protected void layout(Composite composite, boolean flushCache) {
220
221                         Control[] children = composite.getChildren();
222                         Point minSize = new Point(composite.getClientArea().width,
223                                         composite.getClientArea().height);
224
225                         if (children != null) {
226                                 for (int i = 0; i < children.length; i++) {
227                                         Control child = children[i];
228                                         child.setSize(minSize.x - fBorderSize * 2, minSize.y
229                                                         - fBorderSize * 2);
230                                         child.setLocation(fBorderSize, fBorderSize);
231                                 }
232                         }
233                 }
234         }
235
236         /** Border thickness in pixels. */
237         private static final int BORDER = 1;
238
239         /** Right margin in pixels. */
240         private static final int RIGHT_MARGIN = 3;
241
242         /** The control's shell */
243         private Shell fShell;
244
245         /** The composite */
246         Composite fComposite;
247
248         /** The control's text widget */
249         private Text fFilterText;
250
251         /** The control's tree widget */
252         private TreeViewer fTreeViewer;
253
254         /** The control width constraint */
255         private int fMaxWidth = -1;
256
257         /** The control height constraint */
258         private int fMaxHeight = -1;
259
260         private StringMatcher fStringMatcher;
261
262         /**
263          * Creates a tree information control with the given shell as parent. The
264          * given style is applied to the tree widget.
265          * 
266          * @param parent
267          *            the parent shell
268          * @param style
269          *            the additional styles for the tree widget
270          */
271         public JavaOutlineInformationControl(Shell parent, int style) {
272                 this(parent, SWT.RESIZE, style);
273         }
274
275         /**
276          * Creates a tree information control with the given shell as parent. No
277          * additional styles are applied.
278          * 
279          * @param parent
280          *            the parent shell
281          */
282         public JavaOutlineInformationControl(Shell parent) {
283                 this(parent, SWT.NONE);
284         }
285
286         /**
287          * Creates a tree information control with the given shell as parent. The
288          * given styles are applied to the shell and the tree widget.
289          * 
290          * @param parent
291          *            the parent shell
292          * @param shellStyle
293          *            the additional styles for the shell
294          * @param treeStyle
295          *            the additional styles for the tree widget
296          */
297         public JavaOutlineInformationControl(Shell parent, int shellStyle,
298                         int treeStyle) {
299                 fShell = new Shell(parent, shellStyle);
300                 Display display = fShell.getDisplay();
301                 fShell.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
302
303                 // Composite for filter text and tree
304                 fComposite = new Composite(fShell, SWT.RESIZE);
305                 GridLayout layout = new GridLayout(1, false);
306                 fComposite.setLayout(layout);
307                 fComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
308
309                 createFilterText(fComposite);
310                 createTreeViewer(fComposite, treeStyle);
311
312                 int border = ((shellStyle & SWT.NO_TRIM) == 0) ? 0 : BORDER;
313                 fShell.setLayout(new BorderFillLayout(border));
314
315                 setInfoSystemColor();
316                 installFilter();
317         }
318
319         private void createTreeViewer(Composite parent, int style) {
320                 Tree tree = new Tree(parent, SWT.SINGLE | (style & ~SWT.MULTI));
321                 GridData data = new GridData(GridData.FILL_BOTH);
322                 tree.setLayoutData(data);
323
324                 fTreeViewer = new TreeViewer(tree);
325
326                 // Hide import declartions but show the container
327                 // fTreeViewer.addFilter(new ViewerFilter() {
328                 // public boolean select(Viewer viewer, Object parentElement, Object
329                 // element) {
330                 // return !(element instanceof IImportDeclaration);
331                 // }
332                 // });
333
334                 fTreeViewer.setContentProvider(new StandardJavaElementContentProvider(
335                                 true, true));
336                 fTreeViewer.setSorter(new JavaElementSorter());
337                 fTreeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
338
339                 AppearanceAwareLabelProvider lprovider = new AppearanceAwareLabelProvider(
340                                 AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS
341                                                 | JavaElementLabels.F_APP_TYPE_SIGNATURE,
342                                 AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS);
343                 fTreeViewer
344                                 .setLabelProvider(new DecoratingJavaLabelProvider(lprovider));
345
346                 fTreeViewer.getTree().addKeyListener(new KeyListener() {
347                         public void keyPressed(KeyEvent e) {
348                                 if (e.character == 0x1B) // ESC
349                                         dispose();
350                         }
351
352                         public void keyReleased(KeyEvent e) {
353                                 // do nothing
354                         }
355                 });
356
357                 fTreeViewer.getTree().addSelectionListener(new SelectionListener() {
358                         public void widgetSelected(SelectionEvent e) {
359                                 // do nothing
360                         }
361
362                         public void widgetDefaultSelected(SelectionEvent e) {
363                                 gotoSelectedElement();
364                         }
365                 });
366         }
367
368         private Text createFilterText(Composite parent) {
369                 fFilterText = new Text(parent, SWT.FLAT);
370
371                 GridData data = new GridData();
372                 GC gc = new GC(parent);
373                 gc.setFont(parent.getFont());
374                 FontMetrics fontMetrics = gc.getFontMetrics();
375                 gc.dispose();
376
377                 data.heightHint = org.eclipse.jface.dialogs.Dialog
378                                 .convertHeightInCharsToPixels(fontMetrics, 1);
379                 data.horizontalAlignment = GridData.FILL;
380                 data.verticalAlignment = GridData.BEGINNING;
381                 fFilterText.setLayoutData(data);
382
383                 fFilterText.addKeyListener(new KeyListener() {
384                         public void keyPressed(KeyEvent e) {
385                                 if (e.keyCode == 0x0D) // return
386                                         gotoSelectedElement();
387                                 if (e.keyCode == SWT.ARROW_DOWN)
388                                         fTreeViewer.getTree().setFocus();
389                                 if (e.keyCode == SWT.ARROW_UP)
390                                         fTreeViewer.getTree().setFocus();
391                                 if (e.character == 0x1B) // ESC
392                                         dispose();
393                         }
394
395                         public void keyReleased(KeyEvent e) {
396                                 // do nothing
397                         }
398                 });
399
400                 // Horizonral separator line
401                 Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL
402                                 | SWT.LINE_DOT);
403                 separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
404
405                 return fFilterText;
406         }
407
408         private void setInfoSystemColor() {
409                 Display display = fShell.getDisplay();
410                 setForegroundColor(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
411                 setBackgroundColor(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
412         }
413
414         private void installFilter() {
415                 final NamePatternFilter viewerFilter = new NamePatternFilter();
416                 fTreeViewer.addFilter(viewerFilter);
417                 fFilterText.setText(""); //$NON-NLS-1$
418
419                 fFilterText.addModifyListener(new ModifyListener() {
420                         public void modifyText(ModifyEvent e) {
421                                 String pattern = fFilterText.getText();
422                                 if (pattern != null) {
423                                         int length = pattern.length();
424                                         if (length == 0)
425                                                 pattern = null;
426                                         else if (pattern.charAt(length - 1) != '*')
427                                                 pattern = pattern + '*';
428                                 } else
429                                         pattern = null;
430                                 viewerFilter.setPattern(pattern);
431                                 fStringMatcher = viewerFilter.getMatcher();
432                                 fTreeViewer.getControl().setRedraw(false);
433                                 fTreeViewer.refresh();
434                                 fTreeViewer.expandAll();
435                                 selectFirstMatch();
436                                 fTreeViewer.getControl().setRedraw(true);
437                         }
438                 });
439         }
440
441         private void gotoSelectedElement() {
442                 Object selectedElement = ((IStructuredSelection) fTreeViewer
443                                 .getSelection()).getFirstElement();
444                 if (selectedElement != null) {
445                         try {
446                                 dispose();
447                                 OpenActionUtil.open(selectedElement, true);
448                         } catch (CoreException ex) {
449                                 PHPeclipsePlugin.log(ex);
450                         }
451                 }
452         }
453
454         /**
455          * Selects the first element in the tree which matches the current filter
456          * pattern.
457          */
458         private void selectFirstMatch() {
459                 Tree tree = fTreeViewer.getTree();
460                 Object element = findElement(tree.getItems());
461                 if (element != null)
462                         fTreeViewer.setSelection(new StructuredSelection(element), true);
463                 else
464                         fTreeViewer.setSelection(StructuredSelection.EMPTY);
465         }
466
467         private IJavaElement findElement(TreeItem[] items) {
468                 ILabelProvider labelProvider = (ILabelProvider) fTreeViewer
469                                 .getLabelProvider();
470                 for (int i = 0; i < items.length; i++) {
471                         IJavaElement element = (IJavaElement) items[i].getData();
472                         if (fStringMatcher == null)
473                                 return element;
474
475                         if (element != null) {
476                                 String label = labelProvider.getText(element);
477                                 if (fStringMatcher.match(label))
478                                         return element;
479                         }
480
481                         element = findElement(items[i].getItems());
482                         if (element != null)
483                                 return element;
484                 }
485                 return null;
486         }
487
488         /*
489          * @see IInformationControl#setInformation(String)
490          */
491         public void setInformation(String information) {
492                 // this method is ignored, see IInformationControlExtension2
493         }
494
495         /*
496          * @see IInformationControlExtension2#setInput(Object)
497          */
498         public void setInput(Object information) {
499                 fFilterText.setText(""); //$NON-NLS-1$
500                 if (information == null || information instanceof String) {
501                         setInput(null);
502                         return;
503                 }
504                 IJavaElement je = (IJavaElement) information;
505                 IJavaElement sel = null;
506                 ICompilationUnit cu = (ICompilationUnit) je
507                                 .getAncestor(IJavaElement.COMPILATION_UNIT);
508                 if (cu != null)
509                         sel = cu;
510                 else
511                         sel = je.getAncestor(IJavaElement.CLASS_FILE);
512                 fTreeViewer.setInput(sel);
513                 fTreeViewer.setSelection(new StructuredSelection(information));
514         }
515
516         /*
517          * @see IInformationControl#setVisible(boolean)
518          */
519         public void setVisible(boolean visible) {
520                 fShell.setVisible(visible);
521         }
522
523         /*
524          * @see IInformationControl#dispose()
525          */
526         public void dispose() {
527                 if (fShell != null) {
528                         if (!fShell.isDisposed())
529                                 fShell.dispose();
530                         fShell = null;
531                         fTreeViewer = null;
532                         fComposite = null;
533                         fFilterText = null;
534                 }
535         }
536
537         /*
538          * @see org.eclipse.jface.text.IInformationControlExtension#hasContents()
539          */
540         public boolean hasContents() {
541                 return fTreeViewer != null && fTreeViewer.getInput() != null;
542         }
543
544         /*
545          * @see org.eclipse.jface.text.IInformationControl#setSizeConstraints(int,
546          *      int)
547          */
548         public void setSizeConstraints(int maxWidth, int maxHeight) {
549                 fMaxWidth = maxWidth;
550                 fMaxHeight = maxHeight;
551         }
552
553         /*
554          * @see org.eclipse.jface.text.IInformationControl#computeSizeHint()
555          */
556         public Point computeSizeHint() {
557                 return fShell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
558         }
559
560         /*
561          * @see IInformationControl#setLocation(Point)
562          */
563         public void setLocation(Point location) {
564                 Rectangle trim = fShell.computeTrim(0, 0, 0, 0);
565                 Point textLocation = fComposite.getLocation();
566                 location.x += trim.x - textLocation.x;
567                 location.y += trim.y - textLocation.y;
568                 fShell.setLocation(location);
569         }
570
571         /*
572          * @see IInformationControl#setSize(int, int)
573          */
574         public void setSize(int width, int height) {
575                 fShell.setSize(width, height);
576         }
577
578         /*
579          * @see IInformationControl#addDisposeListener(DisposeListener)
580          */
581         public void addDisposeListener(DisposeListener listener) {
582                 fShell.addDisposeListener(listener);
583         }
584
585         /*
586          * @see IInformationControl#removeDisposeListener(DisposeListener)
587          */
588         public void removeDisposeListener(DisposeListener listener) {
589                 fShell.removeDisposeListener(listener);
590         }
591
592         /*
593          * @see IInformationControl#setForegroundColor(Color)
594          */
595         public void setForegroundColor(Color foreground) {
596                 fTreeViewer.getTree().setForeground(foreground);
597                 fFilterText.setForeground(foreground);
598                 fComposite.setForeground(foreground);
599         }
600
601         /*
602          * @see IInformationControl#setBackgroundColor(Color)
603          */
604         public void setBackgroundColor(Color background) {
605                 fTreeViewer.getTree().setBackground(background);
606                 fFilterText.setBackground(background);
607                 fComposite.setBackground(background);
608         }
609
610         /*
611          * @see IInformationControl#isFocusControl()
612          */
613         public boolean isFocusControl() {
614                 return fTreeViewer.getControl().isFocusControl()
615                                 || fFilterText.isFocusControl();
616         }
617
618         /*
619          * @see IInformationControl#setFocus()
620          */
621         public void setFocus() {
622                 fShell.forceFocus();
623                 fFilterText.setFocus();
624         }
625
626         /*
627          * @see IInformationControl#addFocusListener(FocusListener)
628          */
629         public void addFocusListener(FocusListener listener) {
630                 fShell.addFocusListener(listener);
631         }
632
633         /*
634          * @see IInformationControl#removeFocusListener(FocusListener)
635          */
636         public void removeFocusListener(FocusListener listener) {
637                 fShell.removeFocusListener(listener);
638         }
639 }