1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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.phpeclipse.phpeditor;
12 
13 import java.util.Enumeration;
14 import java.util.Hashtable;
15 import java.util.List;
16 import java.util.ResourceBundle;
17 import java.util.Vector;
18 
19 import net.sourceforge.phpdt.core.ElementChangedEvent;
20 import net.sourceforge.phpdt.core.ICompilationUnit;
21 import net.sourceforge.phpdt.core.IElementChangedListener;
22 import net.sourceforge.phpdt.core.IField;
23 import net.sourceforge.phpdt.core.IJavaElement;
24 import net.sourceforge.phpdt.core.IJavaElementDelta;
25 import net.sourceforge.phpdt.core.IMember;
26 import net.sourceforge.phpdt.core.IMethod;
27 import net.sourceforge.phpdt.core.IParent;
28 import net.sourceforge.phpdt.core.ISourceRange;
29 import net.sourceforge.phpdt.core.ISourceReference;
30 import net.sourceforge.phpdt.core.IType;
31 import net.sourceforge.phpdt.core.JavaCore;
32 import net.sourceforge.phpdt.core.JavaModelException;
33 import net.sourceforge.phpdt.internal.corext.util.JavaModelUtil;
34 import net.sourceforge.phpdt.internal.ui.IJavaHelpContextIds;
35 import net.sourceforge.phpdt.internal.ui.PHPUiImages;
36 import net.sourceforge.phpdt.internal.ui.actions.AbstractToggleLinkingAction;
37 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
38 import net.sourceforge.phpdt.internal.ui.preferences.MembersOrderPreferenceCache;
39 import net.sourceforge.phpdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
40 import net.sourceforge.phpdt.internal.ui.viewsupport.DecoratingJavaLabelProvider;
41 import net.sourceforge.phpdt.internal.ui.viewsupport.JavaElementLabels;
42 import net.sourceforge.phpdt.internal.ui.viewsupport.StatusBarUpdater;
43 import net.sourceforge.phpdt.ui.JavaElementSorter;
44 import net.sourceforge.phpdt.ui.JavaUI;
45 import net.sourceforge.phpdt.ui.PreferenceConstants;
46 import net.sourceforge.phpdt.ui.ProblemsLabelDecorator.ProblemsLabelChangedEvent;
47 import net.sourceforge.phpdt.ui.actions.CustomFiltersActionGroup;
48 import net.sourceforge.phpdt.ui.actions.GenerateActionGroup;
49 import net.sourceforge.phpdt.ui.actions.MemberFilterActionGroup;
50 import net.sourceforge.phpdt.ui.actions.PHPdtActionConstants;
51 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
52 
53 import org.eclipse.core.resources.IResource;
54 import org.eclipse.core.runtime.IAdaptable;
55 import org.eclipse.core.runtime.ListenerList;
56 import org.eclipse.jface.action.Action;
57 import org.eclipse.jface.action.IAction;
58 import org.eclipse.jface.action.IMenuListener;
59 import org.eclipse.jface.action.IMenuManager;
60 import org.eclipse.jface.action.IStatusLineManager;
61 import org.eclipse.jface.action.IToolBarManager;
62 import org.eclipse.jface.action.MenuManager;
63 import org.eclipse.jface.action.Separator;
64 import org.eclipse.jface.preference.IPreferenceStore;
65 import org.eclipse.jface.text.Assert;
66 import org.eclipse.jface.text.ITextSelection;
67 import org.eclipse.jface.util.IPropertyChangeListener;
68 import org.eclipse.jface.util.PropertyChangeEvent;
69 import org.eclipse.jface.viewers.IBaseLabelProvider;
70 import org.eclipse.jface.viewers.IPostSelectionProvider;
71 import org.eclipse.jface.viewers.ISelection;
72 import org.eclipse.jface.viewers.ISelectionChangedListener;
73 import org.eclipse.jface.viewers.IStructuredSelection;
74 import org.eclipse.jface.viewers.ITreeContentProvider;
75 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
76 import org.eclipse.jface.viewers.SelectionChangedEvent;
77 import org.eclipse.jface.viewers.StructuredSelection;
78 import org.eclipse.jface.viewers.TreeViewer;
79 import org.eclipse.jface.viewers.Viewer;
80 import org.eclipse.jface.viewers.ViewerFilter;
81 import org.eclipse.swt.SWT;
82 import org.eclipse.swt.custom.BusyIndicator;
83 import org.eclipse.swt.dnd.DND;
84 import org.eclipse.swt.dnd.Transfer;
85 import org.eclipse.swt.widgets.Composite;
86 import org.eclipse.swt.widgets.Control;
87 import org.eclipse.swt.widgets.Display;
88 import org.eclipse.swt.widgets.Item;
89 import org.eclipse.swt.widgets.Menu;
90 import org.eclipse.swt.widgets.Tree;
91 import org.eclipse.swt.widgets.Widget;
92 import org.eclipse.ui.IActionBars;
93 import org.eclipse.ui.PlatformUI;
94 import org.eclipse.ui.actions.ActionContext;
95 import org.eclipse.ui.actions.ActionFactory;
96 import org.eclipse.ui.actions.ActionGroup;
97 import org.eclipse.ui.model.IWorkbenchAdapter;
98 import org.eclipse.ui.model.WorkbenchAdapter;
99 import org.eclipse.ui.part.IPageSite;
100 import org.eclipse.ui.part.IShowInSource;
101 import org.eclipse.ui.part.IShowInTarget;
102 import org.eclipse.ui.part.IShowInTargetList;
103 import org.eclipse.ui.part.Page;
104 import org.eclipse.ui.part.ShowInContext;
105 import org.eclipse.ui.texteditor.GotoAnnotationAction;
106 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
107 import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
108 import org.eclipse.ui.texteditor.IUpdate;
109 import org.eclipse.ui.texteditor.TextEditorAction;
110 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
111 import org.eclipse.ui.views.navigator.LocalSelectionTransfer;
112 
113 /**
114  * The content outline page of the Java editor. The viewer implements a
115  * proprietary update mechanism based on Java model deltas. It does not react on
116  * domain changes. It is specified to show the content of ICompilationUnits and
117  * IClassFiles. Publishes its context menu under
118  * <code>PHPeclipsePlugin.getDefault().getPluginId() + ".outline"</code>.
119  */
120 public class JavaOutlinePage extends Page implements IContentOutlinePage,
121 		IAdaptable, IPostSelectionProvider {
122 
123 	static Object[] NO_CHILDREN = new Object[0];
124 
125 	/**
126 	 * The element change listener of the java outline viewer.
127 	 *
128 	 * @see IElementChangedListener
129 	 */
130 	class ElementChangedListener implements IElementChangedListener {
131 
elementChanged(final ElementChangedEvent e)132 		public void elementChanged(final ElementChangedEvent e) {
133 
134 			if (getControl() == null)
135 				return;
136 
137 			Display d = getControl().getDisplay();
138 			if (d != null) {
139 				d.asyncExec(new Runnable() {
140 					public void run() {
141 						ICompilationUnit cu = (ICompilationUnit) fInput;
142 						IJavaElement base = cu;
143 						// if (fTopLevelTypeOnly) {
144 						// base= getMainType(cu);
145 						// if (base == null) {
146 						if (fOutlineViewer != null)
147 							fOutlineViewer.refresh(true);
148 						return;
149 						// }
150 						// }
151 						// IJavaElementDelta delta= findElement(base,
152 						// e.getDelta());
153 						// if (delta != null && fOutlineViewer != null) {
154 						// fOutlineViewer.reconcile(delta);
155 						// }
156 					}
157 				});
158 			}
159 		}
160 
isPossibleStructuralChange(IJavaElementDelta cuDelta)161 		private boolean isPossibleStructuralChange(IJavaElementDelta cuDelta) {
162 			if (cuDelta.getKind() != IJavaElementDelta.CHANGED) {
163 				return true; // add or remove
164 			}
165 			int flags = cuDelta.getFlags();
166 			if ((flags & IJavaElementDelta.F_CHILDREN) != 0) {
167 				return true;
168 			}
169 			return (flags & (IJavaElementDelta.F_CONTENT | IJavaElementDelta.F_FINE_GRAINED)) == IJavaElementDelta.F_CONTENT;
170 		}
171 
findElement(IJavaElement unit, IJavaElementDelta delta)172 		protected IJavaElementDelta findElement(IJavaElement unit,
173 				IJavaElementDelta delta) {
174 
175 			if (delta == null || unit == null)
176 				return null;
177 
178 			IJavaElement element = delta.getElement();
179 
180 			if (unit.equals(element)) {
181 				if (isPossibleStructuralChange(delta)) {
182 					return delta;
183 				}
184 				return null;
185 			}
186 
187 			if (element.getElementType() > IJavaElement.CLASS_FILE)
188 				return null;
189 
190 			IJavaElementDelta[] children = delta.getAffectedChildren();
191 			if (children == null || children.length == 0)
192 				return null;
193 
194 			for (int i = 0; i < children.length; i++) {
195 				IJavaElementDelta d = findElement(unit, children[i]);
196 				if (d != null)
197 					return d;
198 			}
199 
200 			return null;
201 		}
202 	}
203 
204 	static class NoClassElement extends WorkbenchAdapter implements IAdaptable {
205 		/*
206 		 * @see java.lang.Object#toString()
207 		 */
toString()208 		public String toString() {
209 			return PHPEditorMessages
210 					.getString("JavaOutlinePage.error.NoTopLevelType"); //$NON-NLS-1$
211 		}
212 
213 		/*
214 		 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class)
215 		 */
getAdapter(Class clas)216 		public Object getAdapter(Class clas) {
217 			if (clas == IWorkbenchAdapter.class)
218 				return this;
219 			return null;
220 		}
221 	}
222 
223 	/**
224 	 * Content provider for the children of an ICompilationUnit or an IClassFile
225 	 *
226 	 * @see ITreeContentProvider
227 	 */
228 	class ChildrenProvider implements ITreeContentProvider {
229 
230 		private Object[] NO_CLASS = new Object[] { new NoClassElement() };
231 
232 		private ElementChangedListener fListener;
233 
matches(IJavaElement element)234 		protected boolean matches(IJavaElement element) {
235 			if (element.getElementType() == IJavaElement.METHOD) {
236 				String name = element.getElementName();
237 				return (name != null && name.indexOf('<') >= 0);
238 			}
239 			return false;
240 		}
241 
filter(IJavaElement[] children)242 		protected IJavaElement[] filter(IJavaElement[] children) {
243 			boolean initializers = false;
244 			for (int i = 0; i < children.length; i++) {
245 				if (matches(children[i])) {
246 					initializers = true;
247 					break;
248 				}
249 			}
250 
251 			if (!initializers)
252 				return children;
253 
254 			Vector v = new Vector();
255 			for (int i = 0; i < children.length; i++) {
256 				if (matches(children[i]))
257 					continue;
258 				v.addElement(children[i]);
259 			}
260 
261 			IJavaElement[] result = new IJavaElement[v.size()];
262 			v.copyInto(result);
263 			return result;
264 		}
265 
getChildren(Object parent)266 		public Object[] getChildren(Object parent) {
267 			if (parent instanceof IParent) {
268 				IParent c = (IParent) parent;
269 				try {
270 					return filter(c.getChildren());
271 				} catch (JavaModelException x) {
272 					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=38341
273 					// don't log NotExist exceptions as this is a valid case
274 					// since we might have been posted and the element
275 					// removed in the meantime.
276 					if (PHPeclipsePlugin.isDebug() || !x.isDoesNotExist())
277 						PHPeclipsePlugin.log(x);
278 				}
279 			}
280 			return NO_CHILDREN;
281 		}
282 
getElements(Object parent)283 		public Object[] getElements(Object parent) {
284 			if (fTopLevelTypeOnly) {
285 				if (parent instanceof ICompilationUnit) {
286 					try {
287 						IType type = getMainType((ICompilationUnit) parent);
288 						return type != null ? type.getChildren() : NO_CLASS;
289 					} catch (JavaModelException e) {
290 						PHPeclipsePlugin.log(e);
291 					}
292 				}
293 				// else if (parent instanceof IClassFile) {
294 				// try {
295 				// IType type= getMainType((IClassFile) parent);
296 				// return type != null ? type.getChildren() : NO_CLASS;
297 				// } catch (JavaModelException e) {
298 				// PHPeclipsePlugin.log(e);
299 				// }
300 				// }
301 			}
302 			return getChildren(parent);
303 		}
304 
getParent(Object child)305 		public Object getParent(Object child) {
306 			if (child instanceof IJavaElement) {
307 				IJavaElement e = (IJavaElement) child;
308 				return e.getParent();
309 			}
310 			return null;
311 		}
312 
hasChildren(Object parent)313 		public boolean hasChildren(Object parent) {
314 			if (parent instanceof IParent) {
315 				IParent c = (IParent) parent;
316 				try {
317 					IJavaElement[] children = filter(c.getChildren());
318 					return (children != null && children.length > 0);
319 				} catch (JavaModelException x) {
320 					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=38341
321 					// don't log NotExist exceptions as this is a valid case
322 					// since we might have been posted and the element
323 					// removed in the meantime.
324 					if (PHPeclipsePlugin.isDebug() || !x.isDoesNotExist())
325 						PHPeclipsePlugin.log(x);
326 				}
327 			}
328 			return false;
329 		}
330 
isDeleted(Object o)331 		public boolean isDeleted(Object o) {
332 			return false;
333 		}
334 
dispose()335 		public void dispose() {
336 			if (fListener != null) {
337 				JavaCore.removeElementChangedListener(fListener);
338 				fListener = null;
339 			}
340 		}
341 
342 		/*
343 		 * @see IContentProvider#inputChanged(Viewer, Object, Object)
344 		 */
inputChanged(Viewer viewer, Object oldInput, Object newInput)345 		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
346 			boolean isCU = (newInput instanceof ICompilationUnit);
347 
348 			if (isCU && fListener == null) {
349 				fListener = new ElementChangedListener();
350 				JavaCore.addElementChangedListener(fListener);
351 			} else if (!isCU && fListener != null) {
352 				JavaCore.removeElementChangedListener(fListener);
353 				fListener = null;
354 			}
355 		}
356 	}
357 
358 	class JavaOutlineViewer extends TreeViewer {
359 
360 		/**
361 		 * Indicates an item which has been reused. At the point of its reuse it
362 		 * has been expanded. This field is used to communicate between
363 		 * <code>internalExpandToLevel</code> and <code>reuseTreeItem</code>.
364 		 */
365 		private Item fReusedExpandedItem;
366 
367 		private boolean fReorderedMembers;
368 
369 		private boolean fForceFireSelectionChanged;
370 
JavaOutlineViewer(Tree tree)371 		public JavaOutlineViewer(Tree tree) {
372 			super(tree);
373 			setAutoExpandLevel(ALL_LEVELS);
374 			setUseHashlookup(true);
375 		}
376 
377 		/**
378 		 * Investigates the given element change event and if affected
379 		 * incrementally updates the Java outline.
380 		 *
381 		 * @param delta
382 		 *            the Java element delta used to reconcile the Java outline
383 		 */
reconcile(IJavaElementDelta delta)384 		public void reconcile(IJavaElementDelta delta) {
385 			fReorderedMembers = false;
386 			fForceFireSelectionChanged = false;
387 			if (getSorter() == null) {
388 				if (fTopLevelTypeOnly && delta.getElement() instanceof IType
389 						&& (delta.getKind() & IJavaElementDelta.ADDED) != 0) {
390 					refresh(true);
391 
392 				} else {
393 					Widget w = findItem(fInput);
394 					if (w != null && !w.isDisposed())
395 						update(w, delta);
396 					if (fForceFireSelectionChanged)
397 						fireSelectionChanged(new SelectionChangedEvent(
398 								getSite().getSelectionProvider(), this
399 										.getSelection()));
400 					if (fReorderedMembers) {
401 						refresh(false);
402 						fReorderedMembers = false;
403 					}
404 				}
405 			} else {
406 				// just for now
407 				refresh(true);
408 			}
409 		}
410 
411 		/*
412 		 * @see TreeViewer#internalExpandToLevel
413 		 */
internalExpandToLevel(Widget node, int level)414 		protected void internalExpandToLevel(Widget node, int level) {
415 			if (node instanceof Item) {
416 				Item i = (Item) node;
417 				if (i.getData() instanceof IJavaElement) {
418 					IJavaElement je = (IJavaElement) i.getData();
419 					if (je.getElementType() == IJavaElement.IMPORT_CONTAINER
420 							|| isInnerType(je)) {
421 						if (i != fReusedExpandedItem) {
422 							setExpanded(i, false);
423 							return;
424 						}
425 					}
426 				}
427 			}
428 			super.internalExpandToLevel(node, level);
429 		}
430 
reuseTreeItem(Item item, Object element)431 		protected void reuseTreeItem(Item item, Object element) {
432 
433 			// remove children
434 			Item[] c = getChildren(item);
435 			if (c != null && c.length > 0) {
436 
437 				if (getExpanded(item))
438 					fReusedExpandedItem = item;
439 
440 				for (int k = 0; k < c.length; k++) {
441 					if (c[k].getData() != null)
442 						disassociate(c[k]);
443 					c[k].dispose();
444 				}
445 			}
446 
447 			updateItem(item, element);
448 			updatePlus(item, element);
449 			internalExpandToLevel(item, ALL_LEVELS);
450 
451 			fReusedExpandedItem = null;
452 			fForceFireSelectionChanged = true;
453 		}
454 
mustUpdateParent(IJavaElementDelta delta, IJavaElement element)455 		protected boolean mustUpdateParent(IJavaElementDelta delta,
456 				IJavaElement element) {
457 			if (element instanceof IMethod) {
458 				if ((delta.getKind() & IJavaElementDelta.ADDED) != 0) {
459 					try {
460 						return ((IMethod) element).isMainMethod();
461 					} catch (JavaModelException e) {
462 						PHPeclipsePlugin.log(e.getStatus());
463 					}
464 				}
465 				return "main".equals(element.getElementName()); //$NON-NLS-1$
466 			}
467 			return false;
468 		}
469 
470 		/*
471 		 * @see org.eclipse.jface.viewers.AbstractTreeViewer#isExpandable(java.lang.Object)
472 		 */
isExpandable(Object element)473 		public boolean isExpandable(Object element) {
474 			if (hasFilters()) {
475 				return getFilteredChildren(element).length > 0;
476 			}
477 			return super.isExpandable(element);
478 		}
479 
getSourceRange(IJavaElement element)480 		protected ISourceRange getSourceRange(IJavaElement element)
481 				throws JavaModelException {
482 			if (element instanceof ISourceReference)
483 				return ((ISourceReference) element).getSourceRange();
484 			if (element instanceof IMember)// && !(element instanceof
485 											// IInitializer))
486 				return ((IMember) element).getNameRange();
487 			return null;
488 		}
489 
overlaps(ISourceRange range, int start, int end)490 		protected boolean overlaps(ISourceRange range, int start, int end) {
491 			return start <= (range.getOffset() + range.getLength() - 1)
492 					&& range.getOffset() <= end;
493 		}
494 
filtered(IJavaElement parent, IJavaElement child)495 		protected boolean filtered(IJavaElement parent, IJavaElement child) {
496 
497 			Object[] result = new Object[] { child };
498 			ViewerFilter[] filters = getFilters();
499 			for (int i = 0; i < filters.length; i++) {
500 				result = filters[i].filter(this, parent, result);
501 				if (result.length == 0)
502 					return true;
503 			}
504 
505 			return false;
506 		}
507 
update(Widget w, IJavaElementDelta delta)508 		protected void update(Widget w, IJavaElementDelta delta) {
509 
510 			Item item;
511 
512 			IJavaElement parent = delta.getElement();
513 			IJavaElementDelta[] affected = delta.getAffectedChildren();
514 			Item[] children = getChildren(w);
515 
516 			boolean doUpdateParent = false;
517 			boolean doUpdateParentsPlus = false;
518 
519 			Vector deletions = new Vector();
520 			Vector additions = new Vector();
521 
522 			for (int i = 0; i < affected.length; i++) {
523 				IJavaElementDelta affectedDelta = affected[i];
524 				IJavaElement affectedElement = affectedDelta.getElement();
525 				int status = affected[i].getKind();
526 
527 				// find tree item with affected element
528 				int j;
529 				for (j = 0; j < children.length; j++)
530 					if (affectedElement.equals(children[j].getData()))
531 						break;
532 
533 				if (j == children.length) {
534 					// remove from collapsed parent
535 					if ((status & IJavaElementDelta.REMOVED) != 0) {
536 						doUpdateParentsPlus = true;
537 						continue;
538 					}
539 					// addition
540 					if ((status & IJavaElementDelta.CHANGED) != 0
541 							&& (affectedDelta.getFlags() & IJavaElementDelta.F_MODIFIERS) != 0
542 							&& !filtered(parent, affectedElement)) {
543 						additions.addElement(affectedDelta);
544 					}
545 					continue;
546 				}
547 
548 				item = children[j];
549 
550 				// removed
551 				if ((status & IJavaElementDelta.REMOVED) != 0) {
552 					deletions.addElement(item);
553 					doUpdateParent = doUpdateParent
554 							|| mustUpdateParent(affectedDelta, affectedElement);
555 
556 					// changed
557 				} else if ((status & IJavaElementDelta.CHANGED) != 0) {
558 					int change = affectedDelta.getFlags();
559 					doUpdateParent = doUpdateParent
560 							|| mustUpdateParent(affectedDelta, affectedElement);
561 
562 					if ((change & IJavaElementDelta.F_MODIFIERS) != 0) {
563 						if (filtered(parent, affectedElement))
564 							deletions.addElement(item);
565 						else
566 							updateItem(item, affectedElement);
567 					}
568 
569 					if ((change & IJavaElementDelta.F_CONTENT) != 0)
570 						updateItem(item, affectedElement);
571 
572 					if ((change & IJavaElementDelta.F_CHILDREN) != 0)
573 						update(item, affectedDelta);
574 
575 					if ((change & IJavaElementDelta.F_REORDER) != 0)
576 						fReorderedMembers = true;
577 				}
578 			}
579 
580 			// find all elements to add
581 			IJavaElementDelta[] add = delta.getAddedChildren();
582 			if (additions.size() > 0) {
583 				IJavaElementDelta[] tmp = new IJavaElementDelta[add.length
584 						+ additions.size()];
585 				System.arraycopy(add, 0, tmp, 0, add.length);
586 				for (int i = 0; i < additions.size(); i++)
587 					tmp[i + add.length] = (IJavaElementDelta) additions
588 							.elementAt(i);
589 				add = tmp;
590 			}
591 
592 			// add at the right position
593 			go2: for (int i = 0; i < add.length; i++) {
594 
595 				try {
596 
597 					IJavaElement e = add[i].getElement();
598 					if (filtered(parent, e))
599 						continue go2;
600 
601 					doUpdateParent = doUpdateParent
602 							|| mustUpdateParent(add[i], e);
603 					ISourceRange rng = getSourceRange(e);
604 					int start = rng.getOffset();
605 					int end = start + rng.getLength() - 1;
606 					int nameOffset = Integer.MAX_VALUE;
607 					if (e instanceof IField) {
608 						ISourceRange nameRange = ((IField) e).getNameRange();
609 						if (nameRange != null)
610 							nameOffset = nameRange.getOffset();
611 					}
612 
613 					Item last = null;
614 					item = null;
615 					children = getChildren(w);
616 
617 					for (int j = 0; j < children.length; j++) {
618 						item = children[j];
619 						IJavaElement r = (IJavaElement) item.getData();
620 
621 						if (r == null) {
622 							// parent node collapsed and not be opened before ->
623 							// do nothing
624 							continue go2;
625 						}
626 
627 						try {
628 							rng = getSourceRange(r);
629 
630 							// multi-field declarations always start at
631 							// the same offset. They also have the same
632 							// end offset if the field sequence is terminated
633 							// with a semicolon. If not, the source range
634 							// ends behind the identifier / initializer
635 							// see
636 							// https://bugs.eclipse.org/bugs/show_bug.cgi?id=51851
637 							boolean multiFieldDeclaration = r.getElementType() == IJavaElement.FIELD
638 									&& e.getElementType() == IJavaElement.FIELD
639 									&& rng.getOffset() == start;
640 
641 							// elements are inserted by occurrence
642 							// however, multi-field declarations have
643 							// equal source ranges offsets, therefore we
644 							// compare name-range offsets.
645 							boolean multiFieldOrderBefore = false;
646 							if (multiFieldDeclaration) {
647 								if (r instanceof IField) {
648 									ISourceRange nameRange = ((IField) r)
649 											.getNameRange();
650 									if (nameRange != null) {
651 										if (nameRange.getOffset() > nameOffset)
652 											multiFieldOrderBefore = true;
653 									}
654 								}
655 							}
656 
657 							if (!multiFieldDeclaration
658 									&& overlaps(rng, start, end)) {
659 
660 								// be tolerant if the delta is not correct, or
661 								// if
662 								// the tree has been updated other than by a
663 								// delta
664 								reuseTreeItem(item, e);
665 								continue go2;
666 
667 							} else if (multiFieldOrderBefore
668 									|| rng.getOffset() > start) {
669 
670 								if (last != null && deletions.contains(last)) {
671 									// reuse item
672 									deletions.removeElement(last);
673 									reuseTreeItem(last, e);
674 								} else {
675 									// nothing to reuse
676 									createTreeItem(w, e, j);
677 								}
678 								continue go2;
679 							}
680 
681 						} catch (JavaModelException x) {
682 							// stumbled over deleted element
683 						}
684 
685 						last = item;
686 					}
687 
688 					// add at the end of the list
689 					if (last != null && deletions.contains(last)) {
690 						// reuse item
691 						deletions.removeElement(last);
692 						reuseTreeItem(last, e);
693 					} else {
694 						// nothing to reuse
695 						createTreeItem(w, e, -1);
696 					}
697 
698 				} catch (JavaModelException x) {
699 					// the element to be added is not present -> don't add it
700 				}
701 			}
702 
703 			// remove items which haven't been reused
704 			Enumeration e = deletions.elements();
705 			while (e.hasMoreElements()) {
706 				item = (Item) e.nextElement();
707 				disassociate(item);
708 				item.dispose();
709 			}
710 
711 			if (doUpdateParent)
712 				updateItem(w, delta.getElement());
713 			if (!doUpdateParent && doUpdateParentsPlus && w instanceof Item)
714 				updatePlus((Item) w, delta.getElement());
715 		}
716 
717 		/*
718 		 * @see ContentViewer#handleLabelProviderChanged(LabelProviderChangedEvent)
719 		 */
handleLabelProviderChanged( LabelProviderChangedEvent event)720 		protected void handleLabelProviderChanged(
721 				LabelProviderChangedEvent event) {
722 			Object input = getInput();
723 			if (event instanceof ProblemsLabelChangedEvent) {
724 				ProblemsLabelChangedEvent e = (ProblemsLabelChangedEvent) event;
725 				if (e.isMarkerChange() && input instanceof ICompilationUnit) {
726 					return; // marker changes can be ignored
727 				}
728 			}
729 			// look if the underlying resource changed
730 			Object[] changed = event.getElements();
731 			if (changed != null) {
732 				IResource resource = getUnderlyingResource();
733 				if (resource != null) {
734 					for (int i = 0; i < changed.length; i++) {
735 						if (changed[i] != null && changed[i].equals(resource)) {
736 							// change event to a full refresh
737 							event = new LabelProviderChangedEvent(
738 									(IBaseLabelProvider) event.getSource());
739 							break;
740 						}
741 					}
742 				}
743 			}
744 			super.handleLabelProviderChanged(event);
745 		}
746 
getUnderlyingResource()747 		private IResource getUnderlyingResource() {
748 			Object input = getInput();
749 			if (input instanceof ICompilationUnit) {
750 				ICompilationUnit cu = (ICompilationUnit) input;
751 				cu = JavaModelUtil.toOriginal(cu);
752 				return cu.getResource();
753 			}
754 			// else if (input instanceof IClassFile) {
755 			// return ((IClassFile) input).getResource();
756 			// }
757 			return null;
758 		}
759 
760 	}
761 
762 	class LexicalSortingAction extends Action {
763 
764 		private JavaElementSorter fSorter = new JavaElementSorter();
765 
LexicalSortingAction()766 		public LexicalSortingAction() {
767 			super();
768 			PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
769 					IJavaHelpContextIds.LEXICAL_SORTING_OUTLINE_ACTION);
770 			setText(PHPEditorMessages.getString("JavaOutlinePage.Sort.label")); //$NON-NLS-1$
771 			PHPUiImages.setLocalImageDescriptors(this, "alphab_sort_co.gif"); //$NON-NLS-1$
772 			setToolTipText(PHPEditorMessages
773 					.getString("JavaOutlinePage.Sort.tooltip")); //$NON-NLS-1$
774 			setDescription(PHPEditorMessages
775 					.getString("JavaOutlinePage.Sort.description")); //$NON-NLS-1$
776 
777 			boolean checked = PHPeclipsePlugin.getDefault()
778 					.getPreferenceStore().getBoolean(
779 							"LexicalSortingAction.isChecked"); //$NON-NLS-1$
780 			valueChanged(checked, false);
781 		}
782 
run()783 		public void run() {
784 			valueChanged(isChecked(), true);
785 		}
786 
valueChanged(final boolean on, boolean store)787 		private void valueChanged(final boolean on, boolean store) {
788 			setChecked(on);
789 			BusyIndicator.showWhile(fOutlineViewer.getControl().getDisplay(),
790 					new Runnable() {
791 						public void run() {
792 							fOutlineViewer.setSorter(on ? fSorter : null);
793 						}
794 					});
795 
796 			if (store)
797 				PHPeclipsePlugin.getDefault().getPreferenceStore().setValue(
798 						"LexicalSortingAction.isChecked", on); //$NON-NLS-1$
799 		}
800 	}
801 
802 	class ClassOnlyAction extends Action {
803 
ClassOnlyAction()804 		public ClassOnlyAction() {
805 			super();
806 			PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
807 					IJavaHelpContextIds.GO_INTO_TOP_LEVEL_TYPE_ACTION);
808 			setText(PHPEditorMessages
809 					.getString("JavaOutlinePage.GoIntoTopLevelType.label")); //$NON-NLS-1$
810 			setToolTipText(PHPEditorMessages
811 					.getString("JavaOutlinePage.GoIntoTopLevelType.tooltip")); //$NON-NLS-1$
812 			setDescription(PHPEditorMessages
813 					.getString("JavaOutlinePage.GoIntoTopLevelType.description")); //$NON-NLS-1$
814 			PHPUiImages.setLocalImageDescriptors(this,
815 					"gointo_toplevel_type.gif"); //$NON-NLS-1$
816 
817 			IPreferenceStore preferenceStore = PHPeclipsePlugin.getDefault()
818 					.getPreferenceStore();
819 			boolean showclass = preferenceStore
820 					.getBoolean("GoIntoTopLevelTypeAction.isChecked"); //$NON-NLS-1$
821 			setTopLevelTypeOnly(showclass);
822 		}
823 
824 		/*
825 		 * @see org.eclipse.jface.action.Action#run()
826 		 */
run()827 		public void run() {
828 			setTopLevelTypeOnly(!fTopLevelTypeOnly);
829 		}
830 
setTopLevelTypeOnly(boolean show)831 		private void setTopLevelTypeOnly(boolean show) {
832 			fTopLevelTypeOnly = show;
833 			setChecked(show);
834 			fOutlineViewer.refresh(false);
835 
836 			IPreferenceStore preferenceStore = PHPeclipsePlugin.getDefault()
837 					.getPreferenceStore();
838 			preferenceStore
839 					.setValue("GoIntoTopLevelTypeAction.isChecked", show); //$NON-NLS-1$
840 		}
841 	}
842 
843 	/**
844 	 * This action toggles whether this Java Outline page links its selection to
845 	 * the active editor.
846 	 *
847 	 * @since 3.0
848 	 */
849 	public class ToggleLinkingAction extends AbstractToggleLinkingAction {
850 
851 		JavaOutlinePage fJavaOutlinePage;
852 
853 		/**
854 		 * Constructs a new action.
855 		 *
856 		 * @param outlinePage
857 		 *            the Java outline page
858 		 */
ToggleLinkingAction(JavaOutlinePage outlinePage)859 		public ToggleLinkingAction(JavaOutlinePage outlinePage) {
860 			boolean isLinkingEnabled = PreferenceConstants
861 					.getPreferenceStore()
862 					.getBoolean(
863 							PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE);
864 			setChecked(isLinkingEnabled);
865 			fJavaOutlinePage = outlinePage;
866 		}
867 
868 		/**
869 		 * Runs the action.
870 		 */
run()871 		public void run() {
872 			PreferenceConstants.getPreferenceStore().setValue(
873 					PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE,
874 					isChecked());
875 			if (isChecked() && fEditor != null)
876 				fEditor.synchronizeOutlinePage(fEditor
877 						.computeHighlightRangeSourceReference(), false);
878 		}
879 
880 	}
881 
882 	/** A flag to show contents of top level type only */
883 	private boolean fTopLevelTypeOnly;
884 
885 	private IJavaElement fInput;
886 
887 	private String fContextMenuID;
888 
889 	private Menu fMenu;
890 
891 	private JavaOutlineViewer fOutlineViewer;
892 
893 	private PHPEditor fEditor;
894 
895 	private MemberFilterActionGroup fMemberFilterActionGroup;
896 
897 	private ListenerList fSelectionChangedListeners = new ListenerList();
898 
899 	private ListenerList fPostSelectionChangedListeners = new ListenerList();
900 
901 	private Hashtable fActions = new Hashtable();
902 
903 	private TogglePresentationAction fTogglePresentation;
904 
905 	private GotoAnnotationAction fPreviousAnnotation;
906 
907 	private GotoAnnotationAction fNextAnnotation;
908 
909 	private TextEditorAction fShowJavadoc;
910 
911 	private IAction fUndo;
912 
913 	private IAction fRedo;
914 
915 	private ToggleLinkingAction fToggleLinkingAction;
916 
917 	private CompositeActionGroup fActionGroups;
918 
919 	private IPropertyChangeListener fPropertyChangeListener;
920 
921 	/**
922 	 * Custom filter action group.
923 	 *
924 	 * @since 3.0
925 	 */
926 	private CustomFiltersActionGroup fCustomFiltersActionGroup;
927 
JavaOutlinePage(String contextMenuID, PHPEditor editor)928 	public JavaOutlinePage(String contextMenuID, PHPEditor editor) {
929 		super();
930 
931 		Assert.isNotNull(editor);
932 
933 		fContextMenuID = contextMenuID;
934 		fEditor = editor;
935 		fTogglePresentation = new TogglePresentationAction();
936 		ResourceBundle bundle = PHPEditorMessages.getResourceBundle();
937 		fPreviousAnnotation = new GotoAnnotationAction(bundle,
938 				"PreviousAnnotation.", null, false); //$NON-NLS-1$
939 		fNextAnnotation = new GotoAnnotationAction(bundle,
940 				"NextAnnotation.", null, true); //$NON-NLS-1$
941 		fShowJavadoc = (TextEditorAction) fEditor.getAction("ShowJavaDoc"); //$NON-NLS-1$
942 		fUndo = fEditor.getAction(ITextEditorActionConstants.UNDO);
943 		fRedo = fEditor.getAction(ITextEditorActionConstants.REDO);
944 
945 		fTogglePresentation.setEditor(editor);
946 		fPreviousAnnotation.setEditor(editor);
947 		fNextAnnotation.setEditor(editor);
948 
949 		fPropertyChangeListener = new IPropertyChangeListener() {
950 			public void propertyChange(PropertyChangeEvent event) {
951 				doPropertyChange(event);
952 			}
953 		};
954 		PHPeclipsePlugin.getDefault().getPreferenceStore()
955 				.addPropertyChangeListener(fPropertyChangeListener);
956 	}
957 
958 	/**
959 	 * Returns the primary type of a compilation unit (has the same name as the
960 	 * compilation unit).
961 	 *
962 	 * @param compilationUnit
963 	 *            the compilation unit
964 	 * @return returns the primary type of the compilation unit, or
965 	 *         <code>null</code> if is does not have one
966 	 */
getMainType(ICompilationUnit compilationUnit)967 	protected IType getMainType(ICompilationUnit compilationUnit) {
968 
969 		if (compilationUnit == null)
970 			return null;
971 
972 		String name = compilationUnit.getElementName();
973 		int index = name.indexOf('.');
974 		if (index != -1)
975 			name = name.substring(0, index);
976 		IType type = compilationUnit.getType(name);
977 		return type.exists() ? type : null;
978 	}
979 
980 	/**
981 	 * Returns the primary type of a class file.
982 	 *
983 	 * @param classFile
984 	 *            the class file
985 	 * @return returns the primary type of the class file, or <code>null</code>
986 	 *         if is does not have one
987 	 */
988 	// protected IType getMainType(IClassFile classFile) {
989 	// try {
990 	// IType type= classFile.getType();
991 	// return type != null && type.exists() ? type : null;
992 	// } catch (JavaModelException e) {
993 	// return null;
994 	// }
995 	// }
996 	/*
997 	 * (non-Javadoc) Method declared on Page
998 	 */
init(IPageSite pageSite)999 	public void init(IPageSite pageSite) {
1000 		super.init(pageSite);
1001 	}
1002 
doPropertyChange(PropertyChangeEvent event)1003 	private void doPropertyChange(PropertyChangeEvent event) {
1004 		if (fOutlineViewer != null) {
1005 			if (MembersOrderPreferenceCache.isMemberOrderProperty(event
1006 					.getProperty())) {
1007 				fOutlineViewer.refresh(false);
1008 			}
1009 		}
1010 	}
1011 
1012 	/*
1013 	 * @see ISelectionProvider#addSelectionChangedListener(ISelectionChangedListener)
1014 	 */
addSelectionChangedListener(ISelectionChangedListener listener)1015 	public void addSelectionChangedListener(ISelectionChangedListener listener) {
1016 		if (fOutlineViewer != null)
1017 			fOutlineViewer.addSelectionChangedListener(listener);
1018 		else
1019 			fSelectionChangedListeners.add(listener);
1020 	}
1021 
1022 	/*
1023 	 * @see ISelectionProvider#removeSelectionChangedListener(ISelectionChangedListener)
1024 	 */
removeSelectionChangedListener( ISelectionChangedListener listener)1025 	public void removeSelectionChangedListener(
1026 			ISelectionChangedListener listener) {
1027 		if (fOutlineViewer != null)
1028 			fOutlineViewer.removeSelectionChangedListener(listener);
1029 		else
1030 			fSelectionChangedListeners.remove(listener);
1031 	}
1032 
1033 	/*
1034 	 * @see ISelectionProvider#setSelection(ISelection)
1035 	 */
setSelection(ISelection selection)1036 	public void setSelection(ISelection selection) {
1037 		if (fOutlineViewer != null)
1038 			fOutlineViewer.setSelection(selection);
1039 	}
1040 
1041 	/*
1042 	 * @see ISelectionProvider#getSelection()
1043 	 */
getSelection()1044 	public ISelection getSelection() {
1045 		if (fOutlineViewer == null)
1046 			return StructuredSelection.EMPTY;
1047 		return fOutlineViewer.getSelection();
1048 	}
1049 
1050 	/*
1051 	 * @see org.eclipse.jface.text.IPostSelectionProvider#addPostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
1052 	 */
addPostSelectionChangedListener( ISelectionChangedListener listener)1053 	public void addPostSelectionChangedListener(
1054 			ISelectionChangedListener listener) {
1055 		if (fOutlineViewer != null)
1056 			fOutlineViewer.addPostSelectionChangedListener(listener);
1057 		else
1058 			fPostSelectionChangedListeners.add(listener);
1059 	}
1060 
1061 	/*
1062 	 * @see org.eclipse.jface.text.IPostSelectionProvider#removePostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
1063 	 */
removePostSelectionChangedListener( ISelectionChangedListener listener)1064 	public void removePostSelectionChangedListener(
1065 			ISelectionChangedListener listener) {
1066 		if (fOutlineViewer != null)
1067 			fOutlineViewer.removePostSelectionChangedListener(listener);
1068 		else
1069 			fPostSelectionChangedListeners.remove(listener);
1070 	}
1071 
registerToolbarActions(IActionBars actionBars)1072 	private void registerToolbarActions(IActionBars actionBars) {
1073 
1074 		IToolBarManager toolBarManager = actionBars.getToolBarManager();
1075 		if (toolBarManager != null) {
1076 			toolBarManager.add(new LexicalSortingAction());
1077 
1078 			fMemberFilterActionGroup = new MemberFilterActionGroup(
1079 					fOutlineViewer,
1080 					"net.sourceforge.phpeclipse.JavaOutlinePage"); //$NON-NLS-1$
1081 			fMemberFilterActionGroup.contributeToToolBar(toolBarManager);
1082 
1083 			fCustomFiltersActionGroup.fillActionBars(actionBars);
1084 
1085 			IMenuManager menu = actionBars.getMenuManager();
1086 			menu.add(new Separator("EndFilterGroup")); //$NON-NLS-1$
1087 
1088 			fToggleLinkingAction = new ToggleLinkingAction(this);
1089 			menu.add(new ClassOnlyAction());
1090 			menu.add(fToggleLinkingAction);
1091 		}
1092 	}
1093 
1094 	/*
1095 	 * @see IPage#createControl
1096 	 */
createControl(Composite parent)1097 	public void createControl(Composite parent) {
1098 
1099 		Tree tree = new Tree(parent, SWT.MULTI);
1100 
1101 		AppearanceAwareLabelProvider lprovider = new AppearanceAwareLabelProvider(
1102 				AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS
1103 						| JavaElementLabels.F_APP_TYPE_SIGNATURE,
1104 				AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS);
1105 
1106 		fOutlineViewer = new JavaOutlineViewer(tree);
1107 		initDragAndDrop();
1108 		fOutlineViewer.setContentProvider(new ChildrenProvider());
1109 		fOutlineViewer.setLabelProvider(new DecoratingJavaLabelProvider(
1110 				lprovider));
1111 
1112 		Object[] listeners = fSelectionChangedListeners.getListeners();
1113 		for (int i = 0; i < listeners.length; i++) {
1114 			fSelectionChangedListeners.remove(listeners[i]);
1115 			fOutlineViewer
1116 					.addSelectionChangedListener((ISelectionChangedListener) listeners[i]);
1117 		}
1118 
1119 		listeners = fPostSelectionChangedListeners.getListeners();
1120 		for (int i = 0; i < listeners.length; i++) {
1121 			fPostSelectionChangedListeners.remove(listeners[i]);
1122 			fOutlineViewer
1123 					.addPostSelectionChangedListener((ISelectionChangedListener) listeners[i]);
1124 		}
1125 
1126 		MenuManager manager = new MenuManager(fContextMenuID, fContextMenuID);
1127 		manager.setRemoveAllWhenShown(true);
1128 		manager.addMenuListener(new IMenuListener() {
1129 			public void menuAboutToShow(IMenuManager m) {
1130 				contextMenuAboutToShow(m);
1131 			}
1132 		});
1133 		fMenu = manager.createContextMenu(tree);
1134 		tree.setMenu(fMenu);
1135 
1136 		IPageSite site = getSite();
1137 		site
1138 				.registerContextMenu(PHPeclipsePlugin.getPluginId()
1139 						+ ".outline", manager, fOutlineViewer); //$NON-NLS-1$
1140 		site.setSelectionProvider(fOutlineViewer);
1141 
1142 		// we must create the groups after we have set the selection provider to
1143 		// the site
1144 		fActionGroups = new CompositeActionGroup(new ActionGroup[] {
1145 		// new OpenViewActionGroup(this),
1146 				// new CCPActionGroup(this),
1147 				new GenerateActionGroup(this) });
1148 		// new RefactorActionGroup(this),
1149 		// new JavaSearchActionGroup(this)});
1150 
1151 		// register global actions
1152 		IActionBars bars = site.getActionBars();
1153 
1154 		bars.setGlobalActionHandler(ITextEditorActionConstants.UNDO, fUndo);
1155 		bars.setGlobalActionHandler(ITextEditorActionConstants.REDO, fRedo);
1156 		bars.setGlobalActionHandler(ActionFactory.PREVIOUS.getId(),
1157 				fPreviousAnnotation);
1158 		bars
1159 				.setGlobalActionHandler(ActionFactory.NEXT.getId(),
1160 						fNextAnnotation);
1161 		bars.setGlobalActionHandler(PHPdtActionConstants.SHOW_JAVA_DOC,
1162 				fShowJavadoc);
1163 		bars
1164 				.setGlobalActionHandler(
1165 						ITextEditorActionDefinitionIds.TOGGLE_SHOW_SELECTED_ELEMENT_ONLY,
1166 						fTogglePresentation);
1167 		bars.setGlobalActionHandler(
1168 				ITextEditorActionDefinitionIds.GOTO_NEXT_ANNOTATION,
1169 				fNextAnnotation);
1170 		bars.setGlobalActionHandler(
1171 				ITextEditorActionDefinitionIds.GOTO_PREVIOUS_ANNOTATION,
1172 				fPreviousAnnotation);
1173 
1174 		fActionGroups.fillActionBars(bars);
1175 
1176 		IStatusLineManager statusLineManager = bars.getStatusLineManager();
1177 		if (statusLineManager != null) {
1178 			StatusBarUpdater updater = new StatusBarUpdater(statusLineManager);
1179 			fOutlineViewer.addPostSelectionChangedListener(updater);
1180 		}
1181 		// Custom filter group
1182 		fCustomFiltersActionGroup = new CustomFiltersActionGroup(
1183 				"net.sourceforge.phpdt.ui.JavaOutlinePage", fOutlineViewer); //$NON-NLS-1$
1184 
1185 		registerToolbarActions(bars);
1186 
1187 		fOutlineViewer.setInput(fInput);
1188 	}
1189 
dispose()1190 	public void dispose() {
1191 
1192 		if (fEditor == null)
1193 			return;
1194 
1195 		if (fMemberFilterActionGroup != null) {
1196 			fMemberFilterActionGroup.dispose();
1197 			fMemberFilterActionGroup = null;
1198 		}
1199 
1200 		if (fCustomFiltersActionGroup != null) {
1201 			fCustomFiltersActionGroup.dispose();
1202 			fCustomFiltersActionGroup = null;
1203 		}
1204 
1205 		fEditor.outlinePageClosed();
1206 		fEditor = null;
1207 
1208 		fSelectionChangedListeners.clear();
1209 		fSelectionChangedListeners = null;
1210 
1211 		fPostSelectionChangedListeners.clear();
1212 		fPostSelectionChangedListeners = null;
1213 
1214 		if (fPropertyChangeListener != null) {
1215 			PHPeclipsePlugin.getDefault().getPreferenceStore()
1216 					.removePropertyChangeListener(fPropertyChangeListener);
1217 			fPropertyChangeListener = null;
1218 		}
1219 
1220 		if (fMenu != null && !fMenu.isDisposed()) {
1221 			fMenu.dispose();
1222 			fMenu = null;
1223 		}
1224 
1225 		if (fActionGroups != null)
1226 			fActionGroups.dispose();
1227 
1228 		fTogglePresentation.setEditor(null);
1229 		fPreviousAnnotation.setEditor(null);
1230 		fNextAnnotation.setEditor(null);
1231 
1232 		fOutlineViewer = null;
1233 
1234 		super.dispose();
1235 	}
1236 
getControl()1237 	public Control getControl() {
1238 		if (fOutlineViewer != null)
1239 			return fOutlineViewer.getControl();
1240 		return null;
1241 	}
1242 
setInput(IJavaElement inputElement)1243 	public void setInput(IJavaElement inputElement) {
1244 		fInput = inputElement;
1245 		if (fOutlineViewer != null)
1246 			fOutlineViewer.setInput(fInput);
1247 	}
1248 
select(ISourceReference reference)1249 	public void select(ISourceReference reference) {
1250 		if (fOutlineViewer != null) {
1251 
1252 			ISelection s = fOutlineViewer.getSelection();
1253 			if (s instanceof IStructuredSelection) {
1254 				IStructuredSelection ss = (IStructuredSelection) s;
1255 				List elements = ss.toList();
1256 				if (!elements.contains(reference)) {
1257 					s = (reference == null ? StructuredSelection.EMPTY
1258 							: new StructuredSelection(reference));
1259 					fOutlineViewer.setSelection(s, true);
1260 				}
1261 			}
1262 		}
1263 	}
1264 
setAction(String actionID, IAction action)1265 	public void setAction(String actionID, IAction action) {
1266 		Assert.isNotNull(actionID);
1267 		if (action == null)
1268 			fActions.remove(actionID);
1269 		else
1270 			fActions.put(actionID, action);
1271 	}
1272 
getAction(String actionID)1273 	public IAction getAction(String actionID) {
1274 		Assert.isNotNull(actionID);
1275 		return (IAction) fActions.get(actionID);
1276 	}
1277 
1278 	/*
1279 	 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
1280 	 */
getAdapter(Class key)1281 	public Object getAdapter(Class key) {
1282 		if (key == IShowInSource.class) {
1283 			return getShowInSource();
1284 		}
1285 		if (key == IShowInTargetList.class) {
1286 			return new IShowInTargetList() {
1287 				public String[] getShowInTargetIds() {
1288 					return new String[] { JavaUI.ID_PACKAGES };
1289 				}
1290 
1291 			};
1292 		}
1293 		if (key == IShowInTarget.class) {
1294 			return getShowInTarget();
1295 		}
1296 
1297 		return null;
1298 	}
1299 
1300 	/**
1301 	 * Convenience method to add the action installed under the given actionID
1302 	 * to the specified group of the menu.
1303 	 *
1304 	 * @param menu
1305 	 *            the menu manager
1306 	 * @param group
1307 	 *            the group to which to add the action
1308 	 * @param actionID
1309 	 *            the ID of the new action
1310 	 */
1311 	protected void addAction(IMenuManager menu, String group, String actionID) {
1312 		IAction action = getAction(actionID);
1313 		if (action != null) {
1314 			if (action instanceof IUpdate)
1315 				((IUpdate) action).update();
1316 
1317 			if (action.isEnabled()) {
1318 				IMenuManager subMenu = menu.findMenuUsingPath(group);
1319 				if (subMenu != null)
1320 					subMenu.add(action);
1321 				else
1322 					menu.appendToGroup(group, action);
1323 			}
1324 		}
1325 	}
1326 
1327 	protected void contextMenuAboutToShow(IMenuManager menu) {
1328 
1329 		PHPeclipsePlugin.createStandardGroups(menu);
1330 
1331 		IStructuredSelection selection = (IStructuredSelection) getSelection();
1332 		fActionGroups.setContext(new ActionContext(selection));
1333 		fActionGroups.fillContextMenu(menu);
1334 	}
1335 
1336 	/*
1337 	 * @see Page#setFocus()
1338 	 */
1339 	public void setFocus() {
1340 		if (fOutlineViewer != null)
1341 			fOutlineViewer.getControl().setFocus();
1342 	}
1343 
1344 	/**
1345 	 * Checks whether a given Java element is an inner type.
1346 	 *
1347 	 * @param element
1348 	 *            the java element
1349 	 * @return <code>true</code> iff the given element is an inner type
1350 	 */
1351 	private boolean isInnerType(IJavaElement element) {
1352 
1353 		if (element != null && element.getElementType() == IJavaElement.TYPE) {
1354 			IType type = (IType) element;
1355 			try {
1356 				return type.isMember();
1357 			} catch (JavaModelException e) {
1358 				IJavaElement parent = type.getParent();
1359 				if (parent != null) {
1360 					int parentElementType = parent.getElementType();
1361 					return (parentElementType != IJavaElement.COMPILATION_UNIT && parentElementType != IJavaElement.CLASS_FILE);
1362 				}
1363 			}
1364 		}
1365 
1366 		return false;
1367 	}
1368 
1369 	/**
1370 	 * Returns the <code>IShowInSource</code> for this view.
1371 	 *
1372 	 * @return the {@link IShowInSource}
1373 	 */
1374 	protected IShowInSource getShowInSource() {
1375 		return new IShowInSource() {
1376 			public ShowInContext getShowInContext() {
1377 				return new ShowInContext(null, getSite().getSelectionProvider()
1378 						.getSelection());
1379 			}
1380 		};
1381 	}
1382 
1383 	/**
1384 	 * Returns the <code>IShowInTarget</code> for this view.
1385 	 *
1386 	 * @return the {@link IShowInTarget}
1387 	 */
1388 	protected IShowInTarget getShowInTarget() {
1389 		return new IShowInTarget() {
1390 			public boolean show(ShowInContext context) {
1391 				ISelection sel = context.getSelection();
1392 				if (sel instanceof ITextSelection) {
1393 					ITextSelection tsel = (ITextSelection) sel;
1394 					int offset = tsel.getOffset();
1395 					IJavaElement element = fEditor.getElementAt(offset);
1396 					if (element != null) {
1397 						setSelection(new StructuredSelection(element));
1398 						return true;
1399 					}
1400 				}
1401 				return false;
1402 			}
1403 		};
1404 	}
1405 
1406 	private void initDragAndDrop() {
1407 		int ops = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
1408 		Transfer[] transfers = new Transfer[] { LocalSelectionTransfer
1409 				.getInstance() };
1410 
1411 		// Drop Adapter
1412 		// TransferDropTargetListener[] dropListeners= new
1413 		// TransferDropTargetListener[] {
1414 		// new SelectionTransferDropAdapter(fOutlineViewer)
1415 		// };
1416 		// fOutlineViewer.addDropSupport(ops | DND.DROP_DEFAULT, transfers, new
1417 		// DelegatingDropAdapter(dropListeners));
1418 
1419 		// Drag Adapter
1420 		// TransferDragSourceListener[] dragListeners= new
1421 		// TransferDragSourceListener[] {
1422 		// new SelectionTransferDragAdapter(fOutlineViewer)
1423 		// };
1424 		// fOutlineViewer.addDragSupport(ops, transfers, new
1425 		// JdtViewerDragAdapter(fOutlineViewer, dragListeners));
1426 	}
1427 }
1428