1 /*******************************************************************************
2  * Copyright (c) 2000, 2020 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 
15 package org.eclipse.jdt.astview.views;
16 
17 import java.text.MessageFormat;
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21 
22 import org.eclipse.jdt.astview.ASTViewImages;
23 import org.eclipse.jdt.astview.ASTViewPlugin;
24 import org.eclipse.jdt.astview.EditorUtility;
25 import org.eclipse.jdt.astview.TreeInfoCollector;
26 
27 import org.eclipse.swt.SWT;
28 import org.eclipse.swt.custom.SashForm;
29 import org.eclipse.swt.custom.ViewForm;
30 import org.eclipse.swt.events.FocusAdapter;
31 import org.eclipse.swt.events.FocusEvent;
32 import org.eclipse.swt.widgets.Composite;
33 import org.eclipse.swt.widgets.Label;
34 import org.eclipse.swt.widgets.Menu;
35 import org.eclipse.swt.widgets.Tree;
36 import org.eclipse.swt.widgets.TreeItem;
37 
38 import org.eclipse.core.runtime.CoreException;
39 import org.eclipse.core.runtime.IPath;
40 import org.eclipse.core.runtime.IStatus;
41 import org.eclipse.core.runtime.ListenerList;
42 import org.eclipse.core.runtime.Status;
43 
44 import org.eclipse.core.filebuffers.FileBuffers;
45 import org.eclipse.core.filebuffers.IFileBuffer;
46 import org.eclipse.core.filebuffers.IFileBufferListener;
47 import org.eclipse.core.filebuffers.ITextFileBuffer;
48 
49 import org.eclipse.jface.action.Action;
50 import org.eclipse.jface.action.IAction;
51 import org.eclipse.jface.action.IMenuListener;
52 import org.eclipse.jface.action.IMenuManager;
53 import org.eclipse.jface.action.IToolBarManager;
54 import org.eclipse.jface.action.MenuManager;
55 import org.eclipse.jface.action.Separator;
56 import org.eclipse.jface.commands.ActionHandler;
57 import org.eclipse.jface.dialogs.ErrorDialog;
58 import org.eclipse.jface.dialogs.IDialogSettings;
59 import org.eclipse.jface.dialogs.InputDialog;
60 import org.eclipse.jface.dialogs.MessageDialog;
61 import org.eclipse.jface.viewers.AbstractTreeViewer;
62 import org.eclipse.jface.viewers.DoubleClickEvent;
63 import org.eclipse.jface.viewers.IDoubleClickListener;
64 import org.eclipse.jface.viewers.ISelection;
65 import org.eclipse.jface.viewers.ISelectionChangedListener;
66 import org.eclipse.jface.viewers.ISelectionProvider;
67 import org.eclipse.jface.viewers.IStructuredSelection;
68 import org.eclipse.jface.viewers.SelectionChangedEvent;
69 import org.eclipse.jface.viewers.StructuredSelection;
70 import org.eclipse.jface.viewers.TreeViewer;
71 import org.eclipse.jface.viewers.Viewer;
72 import org.eclipse.jface.viewers.ViewerFilter;
73 import org.eclipse.jface.window.Window;
74 
75 import org.eclipse.jface.text.DocumentEvent;
76 import org.eclipse.jface.text.IDocument;
77 import org.eclipse.jface.text.IDocumentListener;
78 import org.eclipse.jface.text.ITextSelection;
79 
80 import org.eclipse.ui.IActionBars;
81 import org.eclipse.ui.IEditorPart;
82 import org.eclipse.ui.IPartListener2;
83 import org.eclipse.ui.ISelectionListener;
84 import org.eclipse.ui.ISelectionService;
85 import org.eclipse.ui.ISharedImages;
86 import org.eclipse.ui.IViewPart;
87 import org.eclipse.ui.IViewSite;
88 import org.eclipse.ui.IWorkbenchActionConstants;
89 import org.eclipse.ui.IWorkbenchCommandConstants;
90 import org.eclipse.ui.IWorkbenchPart;
91 import org.eclipse.ui.IWorkbenchPartReference;
92 import org.eclipse.ui.IWorkbenchWindow;
93 import org.eclipse.ui.PartInitException;
94 import org.eclipse.ui.PlatformUI;
95 import org.eclipse.ui.actions.ActionFactory;
96 import org.eclipse.ui.actions.ContributionItemFactory;
97 import org.eclipse.ui.handlers.IHandlerService;
98 import org.eclipse.ui.keys.IBindingService;
99 import org.eclipse.ui.part.DrillDownAdapter;
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.ShowInContext;
104 import org.eclipse.ui.part.ViewPart;
105 
106 import org.eclipse.ui.texteditor.ITextEditor;
107 
108 import org.eclipse.jdt.core.ICompilationUnit;
109 import org.eclipse.jdt.core.IJavaElement;
110 import org.eclipse.jdt.core.IJavaProject;
111 import org.eclipse.jdt.core.IPackageFragment;
112 import org.eclipse.jdt.core.IProblemRequestor;
113 import org.eclipse.jdt.core.ITypeRoot;
114 import org.eclipse.jdt.core.JavaCore;
115 import org.eclipse.jdt.core.JavaModelException;
116 import org.eclipse.jdt.core.WorkingCopyOwner;
117 import org.eclipse.jdt.core.compiler.IProblem;
118 import org.eclipse.jdt.core.dom.AST;
119 import org.eclipse.jdt.core.dom.ASTNode;
120 import org.eclipse.jdt.core.dom.ASTParser;
121 import org.eclipse.jdt.core.dom.ASTRequestor;
122 import org.eclipse.jdt.core.dom.ASTVisitor;
123 import org.eclipse.jdt.core.dom.Block;
124 import org.eclipse.jdt.core.dom.CompilationUnit;
125 import org.eclipse.jdt.core.dom.Expression;
126 import org.eclipse.jdt.core.dom.ExpressionStatement;
127 import org.eclipse.jdt.core.dom.IBinding;
128 import org.eclipse.jdt.core.dom.NodeFinder;
129 import org.eclipse.jdt.core.dom.Statement;
130 import org.eclipse.jdt.core.dom.SwitchExpression;
131 import org.eclipse.jdt.core.dom.YieldStatement;
132 import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
133 
134 import org.eclipse.jdt.ui.JavaUI;
135 
136 
137 public class ASTView extends ViewPart implements IShowInSource, IShowInTargetList {
138 
139 	static final int JLS_LATEST= AST.JLS14;
140 
141 	private static final int JLS14= AST.JLS14;
142 
143 	/**
144 	 * @deprecated to get rid of deprecation warnings in code
145 	 */
146 	@Deprecated
147 	private static final int JLS13= AST.JLS13;
148 
149 	/**
150 	 * @deprecated to get rid of deprecation warnings in code
151 	 */
152 	@Deprecated
153 	private static final int JLS12= AST.JLS12;
154 
155 	/**
156 	 * @deprecated to get rid of deprecation warnings in code
157 	 */
158 	@Deprecated
159 	private static final int JLS11= AST.JLS11;
160 
161 	/**
162 	 * @deprecated to get rid of deprecation warnings in code
163 	 */
164 	@Deprecated
165 	private static final int JLS10= AST.JLS10;
166 
167 	/**
168 	 * @deprecated to get rid of deprecation warnings in code
169 	 */
170 	@Deprecated
171 	private static final int JLS9= AST.JLS9;
172 
173 	/**
174 	 * @deprecated to get rid of deprecation warnings in code
175 	 */
176 	@Deprecated
177 	private static final int JLS8= AST.JLS8;
178 
179 	/**
180 	 * @deprecated to get rid of deprecation warnings in code
181 	 */
182 	@Deprecated
183 	private static final int JLS4= AST.JLS4;
184 	/**
185 	 * @deprecated to get rid of deprecation warnings in code
186 	 */
187 	@Deprecated
188 	private static final int JLS3= AST.JLS3;
189 	/**
190 	 * @deprecated to get rid of deprecation warnings in code
191 	 */
192 	@Deprecated
193 	private static final int JLS2= AST.JLS2;
194 
195 	private class ASTViewSelectionProvider implements ISelectionProvider {
196 		ListenerList<ISelectionChangedListener> fListeners= new ListenerList<>(ListenerList.IDENTITY);
197 
198 		@Override
addSelectionChangedListener(ISelectionChangedListener listener)199 		public void addSelectionChangedListener(ISelectionChangedListener listener) {
200 			fListeners.add(listener);
201 		}
202 
203 		@Override
getSelection()204 		public ISelection getSelection() {
205 			IStructuredSelection selection= (IStructuredSelection) fViewer.getSelection();
206 			ArrayList<Object> externalSelection= new ArrayList<>();
207 			for (Iterator<?> iter= selection.iterator(); iter.hasNext();) {
208 				Object unwrapped= ASTView.unwrapAttribute(iter.next());
209 				if (unwrapped != null)
210 					externalSelection.add(unwrapped);
211 			}
212 			return new StructuredSelection(externalSelection);
213 		}
214 
215 		@Override
removeSelectionChangedListener(ISelectionChangedListener listener)216 		public void removeSelectionChangedListener(ISelectionChangedListener listener) {
217 			fListeners.remove(listener);
218 		}
219 
220 		@Override
setSelection(ISelection selection)221 		public void setSelection(ISelection selection) {
222 			//not supported
223 		}
224 	}
225 
226 	private class ASTLevelToggle extends Action {
227 		private int fLevel;
228 
ASTLevelToggle(String label, int level)229 		public ASTLevelToggle(String label, int level) {
230 			super(label, AS_RADIO_BUTTON);
231 			fLevel= level;
232 			if (level == getCurrentASTLevel()) {
233 				setChecked(true);
234 			}
235 		}
236 
getLevel()237 		public int getLevel() {
238 			return fLevel;
239 		}
240 
241 		@Override
run()242 		public void run() {
243 			setASTLevel(fLevel, true);
244 		}
245 	}
246 
247 	private class ASTInputKindAction extends Action {
248 		public static final int USE_PARSER= 1;
249 		public static final int USE_RECONCILE= 2;
250 		public static final int USE_CACHE= 3;
251 		public static final int USE_FOCAL= 4;
252 
253 		private int fInputKind;
254 
ASTInputKindAction(String label, int inputKind)255 		public ASTInputKindAction(String label, int inputKind) {
256 			super(label, AS_RADIO_BUTTON);
257 			fInputKind= inputKind;
258 			if (inputKind == getCurrentInputKind()) {
259 				setChecked(true);
260 			}
261 		}
262 
getInputKind()263 		public int getInputKind() {
264 			return fInputKind;
265 		}
266 
267 		@Override
run()268 		public void run() {
269 			setASTInputType(fInputKind);
270 		}
271 	}
272 
273 
274 	private static class ListenerMix implements ISelectionListener, IFileBufferListener, IDocumentListener, ISelectionChangedListener, IDoubleClickListener, IPartListener2 {
275 
276 		private boolean fASTViewVisible= true;
277 		private ASTView fView;
278 
ListenerMix(ASTView view)279 		public ListenerMix(ASTView view) {
280 			fView= view;
281 		}
282 
dispose()283 		public void dispose() {
284 			fView= null;
285 		}
286 
287 		@Override
selectionChanged(IWorkbenchPart part, ISelection selection)288 		public void selectionChanged(IWorkbenchPart part, ISelection selection) {
289 			if (fASTViewVisible) {
290 				fView.handleEditorPostSelectionChanged(part, selection);
291 			}
292 		}
293 
294 		@Override
bufferCreated(IFileBuffer buffer)295 		public void bufferCreated(IFileBuffer buffer) {
296 			// not interesting
297 		}
298 
299 		@Override
bufferDisposed(IFileBuffer buffer)300 		public void bufferDisposed(IFileBuffer buffer) {
301 			if (buffer instanceof ITextFileBuffer) {
302 				fView.handleDocumentDisposed();
303 			}
304 		}
305 
306 		@Override
bufferContentAboutToBeReplaced(IFileBuffer buffer)307 		public void bufferContentAboutToBeReplaced(IFileBuffer buffer) {
308 			// not interesting
309 		}
310 
311 		@Override
bufferContentReplaced(IFileBuffer buffer)312 		public void bufferContentReplaced(IFileBuffer buffer) {
313 			// not interesting
314 		}
315 
316 		@Override
stateChanging(IFileBuffer buffer)317 		public void stateChanging(IFileBuffer buffer) {
318 			// not interesting
319 		}
320 
321 		@Override
dirtyStateChanged(IFileBuffer buffer, boolean isDirty)322 		public void dirtyStateChanged(IFileBuffer buffer, boolean isDirty) {
323 			// not interesting
324 		}
325 
326 		@Override
stateValidationChanged(IFileBuffer buffer, boolean isStateValidated)327 		public void stateValidationChanged(IFileBuffer buffer, boolean isStateValidated) {
328 			// not interesting
329 		}
330 
331 		@Override
underlyingFileMoved(IFileBuffer buffer, IPath path)332 		public void underlyingFileMoved(IFileBuffer buffer, IPath path) {
333 			// not interesting
334 		}
335 
336 		@Override
underlyingFileDeleted(IFileBuffer buffer)337 		public void underlyingFileDeleted(IFileBuffer buffer) {
338 			// not interesting
339 		}
340 
341 		@Override
stateChangeFailed(IFileBuffer buffer)342 		public void stateChangeFailed(IFileBuffer buffer) {
343 			// not interesting
344 		}
345 
346 		@Override
documentAboutToBeChanged(DocumentEvent event)347 		public void documentAboutToBeChanged(DocumentEvent event) {
348 			// not interesting
349 		}
350 
351 		@Override
documentChanged(DocumentEvent event)352 		public void documentChanged(DocumentEvent event) {
353 			fView.handleDocumentChanged();
354 		}
355 
356 		@Override
selectionChanged(SelectionChangedEvent event)357 		public void selectionChanged(SelectionChangedEvent event) {
358 			fView.handleSelectionChanged(event.getSelection());
359 		}
360 
361 		@Override
doubleClick(DoubleClickEvent event)362 		public void doubleClick(DoubleClickEvent event) {
363 			fView.handleDoubleClick();
364 		}
365 
366 		@Override
partHidden(IWorkbenchPartReference partRef)367 		public void partHidden(IWorkbenchPartReference partRef) {
368 			IWorkbenchPart part= partRef.getPart(false);
369 			if (part == fView) {
370 				fASTViewVisible= false;
371 			}
372 		}
373 
374 		@Override
partVisible(IWorkbenchPartReference partRef)375 		public void partVisible(IWorkbenchPartReference partRef) {
376 			IWorkbenchPart part= partRef.getPart(false);
377 			if (part == fView) {
378 				fASTViewVisible= true;
379 			}
380 		}
381 
382 		@Override
partActivated(IWorkbenchPartReference partRef)383 		public void partActivated(IWorkbenchPartReference partRef) {
384 			// not interesting
385 		}
386 
387 		@Override
partBroughtToTop(IWorkbenchPartReference partRef)388 		public void partBroughtToTop(IWorkbenchPartReference partRef) {
389 			// not interesting
390 		}
391 
392 		@Override
partClosed(IWorkbenchPartReference partRef)393 		public void partClosed(IWorkbenchPartReference partRef) {
394 			fView.notifyWorkbenchPartClosed(partRef);
395 		}
396 
397 		@Override
partDeactivated(IWorkbenchPartReference partRef)398 		public void partDeactivated(IWorkbenchPartReference partRef) {
399 			// not interesting
400 		}
401 
402 		@Override
partOpened(IWorkbenchPartReference partRef)403 		public void partOpened(IWorkbenchPartReference partRef) {
404 			// not interesting
405 		}
406 
407 		@Override
partInputChanged(IWorkbenchPartReference partRef)408 		public void partInputChanged(IWorkbenchPartReference partRef) {
409 			// not interesting
410 		}
411 	}
412 
413 	private static final class StatementChecker extends ASTVisitor {
414 
415 		@Override
visit(YieldStatement node)416 		public boolean visit(YieldStatement node) {
417 			try {
418 				if (node != null && node.isImplicit() && isInSwitchExpression(node)) {
419 					ASTNode parent= node.getParent();
420 					List<Statement> statements= null;
421 					if (parent instanceof Block) {
422 						statements= ((Block) parent).statements();
423 					} else if (parent instanceof SwitchExpression) {
424 						statements= ((SwitchExpression) parent).statements();
425 					}
426 					if (statements == null) {
427 						return true;
428 					}
429 					Expression exp= node.getExpression();
430 					if (exp == null) {
431 						return true;
432 					} else {
433 						int index= statements.indexOf(node);
434 						statements.remove(node);
435 						node.setExpression(null);
436 						ExpressionStatement exprStmt= node.getAST().newExpressionStatement(exp);
437 						exprStmt.setSourceRange(node.getStartPosition(), node.getLength());
438 						statements.add(index, exprStmt);
439 						exprStmt.accept(this);
440 						return false;
441 					}
442 				}
443 			} catch (UnsupportedOperationException e) {
444 				// do nothing
445 			}
446 			return true;
447 		}
448 
isInSwitchExpression(YieldStatement node)449 		private boolean isInSwitchExpression(YieldStatement node) {
450 			boolean result= false;
451 			ASTNode parent= node;
452 			while (parent != null) {
453 				if (parent instanceof SwitchExpression) {
454 					result= true;
455 					break;
456 				}
457 				parent= parent.getParent();
458 			}
459 			return result;
460 		}
461 	}
462 
463 	private final static String SETTINGS_LINK_WITH_EDITOR= "link_with_editor"; //$NON-NLS-1$
464 	private final static String SETTINGS_INPUT_KIND= "input_kind"; //$NON-NLS-1$
465 	private final static String SETTINGS_NO_BINDINGS= "create_bindings"; //$NON-NLS-1$
466 	private final static String SETTINGS_NO_STATEMENTS_RECOVERY= "no_statements_recovery"; //$NON-NLS-1$
467 	private final static String SETTINGS_NO_BINDINGS_RECOVERY= "no_bindings_recovery"; //$NON-NLS-1$
468 	private final static String SETTINGS_IGNORE_METHOD_BODIES= "ignore_method_bodies"; //$NON-NLS-1$
469 	private final static String SETTINGS_SHOW_NON_RELEVANT="show_non_relevant";//$NON-NLS-1$
470 	private final static String SETTINGS_JLS= "jls"; //$NON-NLS-1$
471 
472 	private SashForm fSash;
473 	private TreeViewer fViewer;
474 	private ASTViewLabelProvider fASTLabelProvider;
475 	private TreeViewer fTray;
476 
477 	private DrillDownAdapter fDrillDownAdapter;
478 	private Action fFocusAction;
479 	private Action fRefreshAction;
480 	private Action fCreateBindingsAction;
481 	private Action fStatementsRecoveryAction;
482 	private Action fBindingsRecoveryAction;
483 	private Action fIgnoreMethodBodiesAction;
484 	private Action fFilterNonRelevantAction;
485 	private Action fFindDeclaringNodeAction;
486 	private Action fParseBindingFromKeyAction;
487 	private Action fParseBindingFromElementAction;
488 	private Action fCollapseAction;
489 	private Action fExpandAction;
490 	private Action fClearAction;
491 	private TreeCopyAction fCopyAction;
492 	private Action fDoubleClickAction;
493 	private Action fLinkWithEditor;
494 	private Action fAddToTrayAction;
495 	private Action fDeleteAction;
496 
497 	private ASTLevelToggle[] fASTVersionToggleActions;
498 	private int fCurrentASTLevel;
499 
500 	private ASTInputKindAction[] fASTInputKindActions;
501 	private int fCurrentInputKind;
502 
503 	private ITextEditor fEditor;
504 	private ITypeRoot fTypeRoot;
505 	private CompilationUnit fRoot;
506 	private IDocument fCurrentDocument;
507 	private ArrayList<Object> fTrayRoots;
508 
509 	private boolean fDoLinkWithEditor;
510 	private boolean fCreateBindings;
511 	private NonRelevantFilter fNonRelevantFilter;
512 	private boolean fStatementsRecovery;
513 	private boolean fBindingsRecovery;
514 	private boolean fIgnoreMethodBodies;
515 
516 	private Object fPreviousDouble;
517 
518 	private ListenerMix fSuperListener;
519 	private ISelectionChangedListener fTrayUpdater;
520 
521 	private IDialogSettings fDialogSettings;
522 
523 
ASTView()524 	public ASTView() {
525 		fSuperListener= null;
526 		fDialogSettings= ASTViewPlugin.getDefault().getDialogSettings();
527 		fDoLinkWithEditor= fDialogSettings.getBoolean(SETTINGS_LINK_WITH_EDITOR);
528 		try {
529 			fCurrentInputKind= fDialogSettings.getInt(SETTINGS_INPUT_KIND);
530 		} catch (NumberFormatException e) {
531 			fCurrentInputKind= ASTInputKindAction.USE_PARSER;
532 		}
533 		fCreateBindings= !fDialogSettings.getBoolean(SETTINGS_NO_BINDINGS); // inverse so that default is to create bindings
534 		fStatementsRecovery= !fDialogSettings.getBoolean(SETTINGS_NO_STATEMENTS_RECOVERY); // inverse so that default is use recovery
535 		fBindingsRecovery= !fDialogSettings.getBoolean(SETTINGS_NO_BINDINGS_RECOVERY); // inverse so that default is use recovery
536 		fIgnoreMethodBodies= fDialogSettings.getBoolean(SETTINGS_IGNORE_METHOD_BODIES);
537 		fCurrentASTLevel= JLS_LATEST;
538 		try {
539 			int level= fDialogSettings.getInt(SETTINGS_JLS);
540 			switch (level) {
541 				case JLS2:
542 				case JLS3:
543 				case JLS4:
544 				case JLS8:
545 				case JLS9:
546 				case JLS10:
547 				case JLS11:
548 				case JLS12:
549 				case JLS13:
550 				case JLS14:
551 					fCurrentASTLevel= level;
552 			}
553 		} catch (NumberFormatException e) {
554 			// ignore
555 		}
556 		fNonRelevantFilter= new NonRelevantFilter();
557 		fNonRelevantFilter.setShowNonRelevant(fDialogSettings.getBoolean(SETTINGS_SHOW_NON_RELEVANT));
558 	}
559 
notifyWorkbenchPartClosed(IWorkbenchPartReference partRef)560 	final void notifyWorkbenchPartClosed(IWorkbenchPartReference partRef) {
561 		if (fEditor != null && fEditor.equals(partRef.getPart(false))) {
562 			try {
563 				setInput(null);
564 			} catch (CoreException e) {
565 				// ignore
566 			}
567 		}
568 	}
569 
570 	@Override
init(IViewSite site)571 	public void init(IViewSite site) throws PartInitException {
572 		super.setSite(site);
573 		if (fSuperListener == null) {
574 			fSuperListener= new ListenerMix(this);
575 
576 			ISelectionService service= site.getWorkbenchWindow().getSelectionService();
577 			service.addPostSelectionListener(fSuperListener);
578 			site.getPage().addPartListener(fSuperListener);
579 			FileBuffers.getTextFileBufferManager().addFileBufferListener(fSuperListener);
580 		}
581 	}
582 
getCurrentASTLevel()583 	public int getCurrentASTLevel() {
584 		return fCurrentASTLevel;
585 	}
586 
getCurrentInputKind()587 	public int getCurrentInputKind() {
588 		return fCurrentInputKind;
589 	}
590 
setInput(ITextEditor editor)591 	public void setInput(ITextEditor editor) throws CoreException {
592 		if (fEditor != null) {
593 			uninstallModificationListener();
594 		}
595 
596 		fEditor= null;
597 		fRoot= null;
598 
599 		if (editor != null) {
600 			ITypeRoot typeRoot= EditorUtility.getJavaInput(editor);
601 			if (typeRoot == null) {
602 				throw new CoreException(getErrorStatus("Editor not showing a CU or class file", null)); //$NON-NLS-1$
603 			}
604 			fTypeRoot= typeRoot;
605 
606 			ISelection selection= editor.getSelectionProvider().getSelection();
607 			if (selection instanceof ITextSelection) {
608 				ITextSelection textSelection= (ITextSelection) selection;
609 				fRoot= internalSetInput(typeRoot, textSelection.getOffset(), textSelection.getLength());
610 				fEditor= editor;
611 			}
612 			installModificationListener();
613 		}
614 
615 	}
616 
internalSetInput(ITypeRoot input, int offset, int length)617 	private CompilationUnit internalSetInput(ITypeRoot input, int offset, int length) throws CoreException {
618 		if (input.getBuffer() == null) {
619 			throw new CoreException(getErrorStatus("Input has no buffer", null)); //$NON-NLS-1$
620 		}
621 
622 		CompilationUnit root;
623 		try {
624 			root= createAST(input, offset);
625 			resetView(root);
626 			if (root == null) {
627 				setContentDescription("AST could not be created."); //$NON-NLS-1$
628 				return null;
629 			}
630 		} catch (RuntimeException e) {
631 			throw new CoreException(getErrorStatus("Could not create AST:\n" + e.getMessage(), e)); //$NON-NLS-1$
632 		}
633 
634 		try {
635 			ASTNode node= NodeFinder.perform(root, offset, length);
636 			if (node != null) {
637 				fViewer.getTree().setRedraw(false);
638 				try {
639 					fASTLabelProvider.setSelectedRange(node.getStartPosition(), node.getLength());
640 					fViewer.setSelection(new StructuredSelection(node), true);
641 				} finally {
642 					fViewer.getTree().setRedraw(true);
643 				}
644 			}
645 		} catch (RuntimeException e) {
646 			showAndLogError("Could not select node for editor selection", e); //$NON-NLS-1$
647 		}
648 
649 		return root;
650 	}
651 
clearView()652 	private void clearView() {
653 		resetView(null);
654 		setContentDescription("Open a Java editor and press the 'Show AST of active editor' toolbar button"); //$NON-NLS-1$
655 	}
656 
657 
resetView(CompilationUnit root)658 	private void resetView(CompilationUnit root) {
659 		fViewer.setInput(root);
660 		fViewer.getTree().setEnabled(root != null);
661 		fSash.setMaximizedControl(fViewer.getTree());
662 		fTrayRoots= new ArrayList<>();
663 		if (fTray != null)
664 			fTray.setInput(fTrayRoots);
665 		setASTUptoDate(root != null);
666 		fClearAction.setEnabled(root != null);
667 		fFindDeclaringNodeAction.setEnabled(root != null);
668 		fPreviousDouble= null; // avoid leaking AST
669 	}
670 
createAST(ITypeRoot input, int offset)671 	private CompilationUnit createAST(ITypeRoot input, int offset) throws JavaModelException, CoreException {
672 		long startTime;
673 		long endTime;
674 		CompilationUnit root;
675 
676 		if ((getCurrentInputKind() == ASTInputKindAction.USE_RECONCILE)) {
677 			final IProblemRequestor problemRequestor= new IProblemRequestor() { //strange: don't get bindings when supplying null as problemRequestor
678 				@Override
679 				public void acceptProblem(IProblem problem) {/*not interested*/}
680 				@Override
681 				public void beginReporting() {/*not interested*/}
682 				@Override
683 				public void endReporting() {/*not interested*/}
684 				@Override
685 				public boolean isActive() {
686 					return true;
687 				}
688 			};
689 			WorkingCopyOwner workingCopyOwner= new WorkingCopyOwner() {
690 				@Override
691 				public IProblemRequestor getProblemRequestor(ICompilationUnit workingCopy) {
692 					return problemRequestor;
693 				}
694 			};
695 			ICompilationUnit wc= input.getWorkingCopy(workingCopyOwner, null);
696 			try {
697 				int reconcileFlags= ICompilationUnit.FORCE_PROBLEM_DETECTION;
698 				if (fStatementsRecovery)
699 					reconcileFlags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
700 				if (fBindingsRecovery)
701 					reconcileFlags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
702 				if (fIgnoreMethodBodies)
703 					reconcileFlags |= ICompilationUnit.IGNORE_METHOD_BODIES;
704 				startTime= System.currentTimeMillis();
705 				root= wc.reconcile(fCurrentASTLevel, reconcileFlags, null, null);
706 				endTime= System.currentTimeMillis();
707 			} finally {
708 				wc.discardWorkingCopy();
709 			}
710 
711 		} else if (input instanceof ICompilationUnit && (getCurrentInputKind() == ASTInputKindAction.USE_CACHE)) {
712 			ICompilationUnit cu= (ICompilationUnit) input;
713 			startTime= System.currentTimeMillis();
714 			root= SharedASTProviderCore.getAST(cu, SharedASTProviderCore.WAIT_NO, null);
715 			endTime= System.currentTimeMillis();
716 
717 		} else {
718 			ASTParser parser= ASTParser.newParser(fCurrentASTLevel);
719 			parser.setResolveBindings(fCreateBindings);
720 			parser.setSource(input);
721 			parser.setStatementsRecovery(fStatementsRecovery);
722 			parser.setBindingsRecovery(fBindingsRecovery);
723 			parser.setIgnoreMethodBodies(fIgnoreMethodBodies);
724 			if (getCurrentInputKind() == ASTInputKindAction.USE_FOCAL) {
725 				parser.setFocalPosition(offset);
726 			}
727 			startTime= System.currentTimeMillis();
728 			root= (CompilationUnit) parser.createAST(null);
729 			endTime= System.currentTimeMillis();
730 		}
731 		if (root != null) {
732 			root.accept(new StatementChecker());
733 			updateContentDescription(input, root, endTime - startTime);
734 		}
735 		return root;
736 	}
737 
refreshASTSettingsActions()738 	protected void refreshASTSettingsActions() {
739 		boolean enabled;
740 		switch (getCurrentInputKind()) {
741 			case ASTInputKindAction.USE_CACHE:
742 				enabled= false;
743 				break;
744 			default:
745 				enabled= true;
746 				break;
747 		}
748 		fCreateBindingsAction.setEnabled(enabled && getCurrentInputKind() != ASTInputKindAction.USE_RECONCILE);
749 		fStatementsRecoveryAction.setEnabled(enabled);
750 		fBindingsRecoveryAction.setEnabled(enabled);
751 		fIgnoreMethodBodiesAction.setEnabled(enabled);
752 		for (ASTView.ASTLevelToggle action : fASTVersionToggleActions) {
753 			action.setEnabled(enabled);
754 		}
755 	}
756 
updateContentDescription(IJavaElement element, CompilationUnit root, long time)757 	private void updateContentDescription(IJavaElement element, CompilationUnit root, long time) {
758 		String version= "AST Level " + root.getAST().apiLevel();
759 		switch (getCurrentInputKind()) {
760 		case ASTInputKindAction.USE_RECONCILE:
761 			version+= ", from reconciler"; //$NON-NLS-1$
762 			break;
763 		case ASTInputKindAction.USE_CACHE:
764 			version+= ", from ASTProvider"; //$NON-NLS-1$
765 			break;
766 		case ASTInputKindAction.USE_FOCAL:
767 			version+= ", using focal position"; //$NON-NLS-1$
768 			break;
769 		default:
770 			break;
771 		}
772 		TreeInfoCollector collector= new TreeInfoCollector(root);
773 
774 		String msg= "{0} ({1}).  Creation time: {2,number} ms.  Size: {3,number} nodes, {4,number} bytes (AST nodes only)."; //$NON-NLS-1$
775 		Object[] args= { element.getElementName(), version, Long.valueOf(time),  Integer.valueOf(collector.getNumberOfNodes()), Integer.valueOf(collector.getSize())};
776 		setContentDescription(MessageFormat.format(msg, args));
777 
778 	}
779 
780 	@Override
dispose()781 	public void dispose() {
782 		if (fSuperListener != null) {
783 			if (fEditor != null) {
784 				uninstallModificationListener();
785 			}
786 			ISelectionService service= getSite().getWorkbenchWindow().getSelectionService();
787 			service.removePostSelectionListener(fSuperListener);
788 			getSite().getPage().removePartListener(fSuperListener);
789 			FileBuffers.getTextFileBufferManager().removeFileBufferListener(fSuperListener);
790 			fSuperListener.dispose(); // removes reference to view
791 			fSuperListener= null;
792 		}
793 		if (fTrayUpdater != null) {
794 			fViewer.removePostSelectionChangedListener(fTrayUpdater);
795 			fTray.removePostSelectionChangedListener(fTrayUpdater);
796 			fTrayUpdater= null;
797 		}
798 		super.dispose();
799 	}
800 
getErrorStatus(String message, Throwable th)801 	private IStatus getErrorStatus(String message, Throwable th) {
802 		return new Status(IStatus.ERROR, ASTViewPlugin.getPluginId(), IStatus.ERROR, message, th);
803 	}
804 
805 	@Override
createPartControl(Composite parent)806 	public void createPartControl(Composite parent) {
807 		fSash= new SashForm(parent, SWT.VERTICAL | SWT.SMOOTH);
808 		fViewer = new TreeViewer(fSash, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
809 		fDrillDownAdapter = new DrillDownAdapter(fViewer);
810 		fViewer.setContentProvider(new ASTViewContentProvider());
811 		fASTLabelProvider= new ASTViewLabelProvider();
812 		fViewer.setLabelProvider(fASTLabelProvider);
813 		fViewer.addSelectionChangedListener(fSuperListener);
814 		fViewer.addDoubleClickListener(fSuperListener);
815 		fViewer.addFilter(new ViewerFilter() {
816 			@Override
817 			public boolean select(Viewer viewer, Object parentElement, Object element) {
818 				if (!fCreateBindings && element instanceof Binding)
819 					return false;
820 				return true;
821 			}
822 		});
823 		fViewer.addFilter(fNonRelevantFilter);
824 
825 
826 		ViewForm trayForm= new ViewForm(fSash, SWT.NONE);
827 		Label label= new Label(trayForm, SWT.NONE);
828 		label.setText(" Comparison Tray (* = selection in the upper tree):"); //$NON-NLS-1$
829 		trayForm.setTopLeft(label);
830 
831 		fTray= new TreeViewer(trayForm, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
832 		trayForm.setContent(fTray.getTree());
833 
834 		fTrayRoots= new ArrayList<>();
835 		fTray.setContentProvider(new TrayContentProvider());
836 		final TrayLabelProvider trayLabelProvider= new TrayLabelProvider();
837 		fTray.setLabelProvider(trayLabelProvider);
838 		fTray.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
839 		fTrayUpdater= new ISelectionChangedListener() {
840 			@Override
841 			public void selectionChanged(SelectionChangedEvent event) {
842 				IStructuredSelection viewerSelection= (IStructuredSelection) fViewer.getSelection();
843 				if (viewerSelection.size() == 1) {
844 					Object first= viewerSelection.getFirstElement();
845 					if (unwrapAttribute(first) != null) {
846 						trayLabelProvider.setViewerElement(first);
847 						return;
848 					}
849 				}
850 				trayLabelProvider.setViewerElement(null);
851 			}
852 		};
853 		fTray.addPostSelectionChangedListener(fTrayUpdater);
854 		fViewer.addPostSelectionChangedListener(fTrayUpdater);
855 		fTray.addDoubleClickListener(new IDoubleClickListener() {
856 			@Override
857 			public void doubleClick(DoubleClickEvent event) {
858 				performTrayDoubleClick();
859 			}
860 		});
861 		fTray.addSelectionChangedListener(new ISelectionChangedListener() {
862 			@Override
863 			public void selectionChanged(SelectionChangedEvent event) {
864 				IStructuredSelection selection= (IStructuredSelection) event.getSelection();
865 				fDeleteAction.setEnabled(selection.size() >= 1 && fTray.getTree().isFocusControl());
866 			}
867 		});
868 		fTray.getTree().addFocusListener(new FocusAdapter() {
869 			@Override
870 			public void focusGained(FocusEvent e) {
871 				IStructuredSelection selection= (IStructuredSelection) fTray.getSelection();
872 				fDeleteAction.setEnabled(selection.size() >= 1);
873 			}
874 			@Override
875 			public void focusLost(FocusEvent e) {
876 				fDeleteAction.setEnabled(false);
877 			}
878 		});
879 
880 		makeActions();
881 		hookContextMenu();
882 		hookTrayContextMenu();
883 		contributeToActionBars();
884 		getSite().setSelectionProvider(new ASTViewSelectionProvider());
885 
886 		try {
887 			IEditorPart part= EditorUtility.getActiveEditor();
888 			if (part instanceof ITextEditor) {
889 				setInput((ITextEditor) part);
890 			}
891 		} catch (CoreException e) {
892 			// ignore
893 		}
894 		if (fTypeRoot == null) {
895 			clearView();
896 		} else {
897 			setASTUptoDate(fTypeRoot != null);
898 		}
899 	}
900 
901 
hookContextMenu()902 	private void hookContextMenu() {
903 		MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
904 		menuMgr.setRemoveAllWhenShown(true);
905 		menuMgr.addMenuListener(new IMenuListener() {
906 			@Override
907 			public void menuAboutToShow(IMenuManager manager) {
908 				ASTView.this.fillContextMenu(manager);
909 			}
910 		});
911 		Menu menu = menuMgr.createContextMenu(fViewer.getControl());
912 		fViewer.getControl().setMenu(menu);
913 		getSite().registerContextMenu(menuMgr, fViewer);
914 	}
915 
hookTrayContextMenu()916 	private void hookTrayContextMenu() {
917 		MenuManager menuMgr = new MenuManager("#TrayPopupMenu"); //$NON-NLS-1$
918 		menuMgr.setRemoveAllWhenShown(true);
919 		menuMgr.addMenuListener(new IMenuListener() {
920 			@Override
921 			public void menuAboutToShow(IMenuManager manager) {
922 				manager.add(fCopyAction);
923 				manager.add(fDeleteAction);
924 				manager.add(new Separator());
925 				manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
926 			}
927 		});
928 		Menu menu = menuMgr.createContextMenu(fTray.getControl());
929 		fTray.getControl().setMenu(menu);
930 		getSite().registerContextMenu("#TrayPopupMenu", menuMgr, fTray); //$NON-NLS-1$
931 	}
932 
contributeToActionBars()933 	private void contributeToActionBars() {
934 		IActionBars bars = getViewSite().getActionBars();
935 		fillLocalPullDown(bars.getMenuManager());
936 		fillLocalToolBar(bars.getToolBarManager());
937 		bars.setGlobalActionHandler(ActionFactory.COPY.getId(), fCopyAction);
938 		bars.setGlobalActionHandler(ActionFactory.REFRESH.getId(), fFocusAction);
939 		bars.setGlobalActionHandler(ActionFactory.DELETE.getId(), fDeleteAction);
940 
941 		IHandlerService handlerService= getViewSite().getService(IHandlerService.class);
942 		handlerService.activateHandler(IWorkbenchCommandConstants.NAVIGATE_TOGGLE_LINK_WITH_EDITOR, new ActionHandler(fLinkWithEditor));
943 	}
944 
fillLocalPullDown(IMenuManager manager)945 	private void fillLocalPullDown(IMenuManager manager) {
946 		for (ASTView.ASTLevelToggle action : fASTVersionToggleActions) {
947 			manager.add(action);
948 		}
949 		manager.add(new Separator());
950 		manager.add(fCreateBindingsAction);
951 		manager.add(fStatementsRecoveryAction);
952 		manager.add(fBindingsRecoveryAction);
953 		manager.add(fIgnoreMethodBodiesAction);
954 		manager.add(new Separator());
955 		for (ASTView.ASTInputKindAction action : fASTInputKindActions) {
956 			manager.add(action);
957 		}
958 		manager.add(new Separator());
959 		manager.add(fFindDeclaringNodeAction);
960 		manager.add(fParseBindingFromKeyAction);
961 		manager.add(fParseBindingFromElementAction);
962 		manager.add(new Separator());
963 		manager.add(fFilterNonRelevantAction);
964 		manager.add(fLinkWithEditor);
965 	}
966 
fillContextMenu(IMenuManager manager)967 	protected void fillContextMenu(IMenuManager manager) {
968 		ISelection selection= getSite().getSelectionProvider().getSelection();
969 		if (!selection.isEmpty() && ((IStructuredSelection) selection).getFirstElement() instanceof IJavaElement) {
970 			MenuManager showInSubMenu= new MenuManager(getShowInMenuLabel());
971 			IWorkbenchWindow workbenchWindow= getSite().getWorkbenchWindow();
972 			showInSubMenu.add(ContributionItemFactory.VIEWS_SHOW_IN.create(workbenchWindow));
973 			manager.add(showInSubMenu);
974 			manager.add(new Separator());
975 		}
976 		manager.add(fFocusAction);
977 		manager.add(fRefreshAction);
978 		manager.add(fClearAction);
979 		manager.add(fCollapseAction);
980 		manager.add(fExpandAction);
981 		manager.add(new Separator());
982 		manager.add(fCopyAction);
983 		if (fAddToTrayAction.isEnabled())
984 			manager.add(fAddToTrayAction);
985 		manager.add(new Separator());
986 
987 		fDrillDownAdapter.addNavigationActions(manager);
988 		// Other plug-ins can contribute there actions here
989 		manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
990 	}
991 
getShowInMenuLabel()992 	private String getShowInMenuLabel() {
993 		String keyBinding= null;
994 
995 		IBindingService bindingService= PlatformUI.getWorkbench().getAdapter(IBindingService.class);
996 		if (bindingService != null)
997 			keyBinding= bindingService.getBestActiveBindingFormattedFor(IWorkbenchCommandConstants.NAVIGATE_SHOW_IN_QUICK_MENU);
998 
999 		if (keyBinding == null)
1000 			keyBinding= ""; //$NON-NLS-1$
1001 
1002 		return "Sho&w In" + '\t' + keyBinding;
1003 	}
1004 
fillLocalToolBar(IToolBarManager manager)1005 	private void fillLocalToolBar(IToolBarManager manager) {
1006 		manager.add(fFocusAction);
1007 		manager.add(fRefreshAction);
1008 		manager.add(fClearAction);
1009 		manager.add(new Separator());
1010 		fDrillDownAdapter.addNavigationActions(manager);
1011 		manager.add(new Separator());
1012 		manager.add(fExpandAction);
1013 		manager.add(fCollapseAction);
1014 		manager.add(fLinkWithEditor);
1015 	}
1016 
setASTUptoDate(boolean isuptoDate)1017 	private void setASTUptoDate(boolean isuptoDate) {
1018 		fRefreshAction.setEnabled(!isuptoDate && fTypeRoot != null);
1019 	}
1020 
makeActions()1021 	private void makeActions() {
1022 		fRefreshAction = new Action() {
1023 			@Override
1024 			public void run() {
1025 				performRefresh();
1026 			}
1027 		};
1028 		fRefreshAction.setText("&Refresh AST"); //$NON-NLS-1$
1029 		fRefreshAction.setToolTipText("Refresh AST"); //$NON-NLS-1$
1030 		fRefreshAction.setEnabled(false);
1031 		ASTViewImages.setImageDescriptors(fRefreshAction, ASTViewImages.REFRESH);
1032 
1033 		fClearAction = new Action() {
1034 			@Override
1035 			public void run() {
1036 				performClear();
1037 			}
1038 		};
1039 		fClearAction.setText("&Clear AST"); //$NON-NLS-1$
1040 		fClearAction.setToolTipText("Clear AST and release memory"); //$NON-NLS-1$
1041 		fClearAction.setEnabled(false);
1042 		ASTViewImages.setImageDescriptors(fClearAction, ASTViewImages.CLEAR);
1043 
1044 		fASTInputKindActions= new ASTInputKindAction[] {
1045 				new ASTInputKindAction("Use ASTParser.&createAST", ASTInputKindAction.USE_PARSER), //$NON-NLS-1$
1046 				new ASTInputKindAction("Use ASTParser with &focal position", ASTInputKindAction.USE_FOCAL), //$NON-NLS-1$
1047 				new ASTInputKindAction("Use ICompilationUnit.&reconcile", ASTInputKindAction.USE_RECONCILE), //$NON-NLS-1$
1048 				new ASTInputKindAction("Use SharedASTProvider.&getAST", ASTInputKindAction.USE_CACHE) //$NON-NLS-1$
1049 		};
1050 
1051 		fCreateBindingsAction = new Action("&Create Bindings", IAction.AS_CHECK_BOX) { //$NON-NLS-1$
1052 			@Override
1053 			public void run() {
1054 				performCreateBindings();
1055 			}
1056 		};
1057 		fCreateBindingsAction.setChecked(fCreateBindings);
1058 		fCreateBindingsAction.setToolTipText("Create Bindings"); //$NON-NLS-1$
1059 		fCreateBindingsAction.setEnabled(true);
1060 
1061 		fStatementsRecoveryAction = new Action("&Statements Recovery", IAction.AS_CHECK_BOX) { //$NON-NLS-1$
1062 			@Override
1063 			public void run() {
1064 				performStatementsRecovery();
1065 			}
1066 		};
1067 		fStatementsRecoveryAction.setChecked(fStatementsRecovery);
1068 		fStatementsRecoveryAction.setEnabled(true);
1069 
1070 		fBindingsRecoveryAction = new Action("&Bindings Recovery", IAction.AS_CHECK_BOX) { //$NON-NLS-1$
1071 			@Override
1072 			public void run() {
1073 				performBindingsRecovery();
1074 			}
1075 		};
1076 		fBindingsRecoveryAction.setChecked(fBindingsRecovery);
1077 		fBindingsRecoveryAction.setEnabled(true);
1078 
1079 		fIgnoreMethodBodiesAction = new Action("&Ignore Method Bodies", IAction.AS_CHECK_BOX) { //$NON-NLS-1$
1080 			@Override
1081 			public void run() {
1082 				performIgnoreMethodBodies();
1083 			}
1084 		};
1085 		fIgnoreMethodBodiesAction.setChecked(fIgnoreMethodBodies);
1086 		fIgnoreMethodBodiesAction.setEnabled(true);
1087 
1088 		fFilterNonRelevantAction = new Action("&Hide Non-Relevant Attributes", IAction.AS_CHECK_BOX) { //$NON-NLS-1$
1089 			@Override
1090 			public void run() {
1091 				performFilterNonRelevant();
1092 			}
1093 		};
1094 		fFilterNonRelevantAction.setChecked(! fNonRelevantFilter.isShowNonRelevant());
1095 		fFilterNonRelevantAction.setToolTipText("Hide non-relevant binding attributes"); //$NON-NLS-1$
1096 		fFilterNonRelevantAction.setEnabled(true);
1097 
1098 		fFindDeclaringNodeAction= new Action("Find &Declaring Node...", IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$
1099 			@Override
1100 			public void run() {
1101 				performFindDeclaringNode();
1102 			}
1103 		};
1104 		fFindDeclaringNodeAction.setToolTipText("Find Declaring Node..."); //$NON-NLS-1$
1105 		fFindDeclaringNodeAction.setEnabled(false);
1106 
1107 		fParseBindingFromElementAction= new Action("&Parse Binding from &Element Handle...", IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$
1108 			@Override
1109 			public void run() {
1110 				performParseBindingFromElement();
1111 			}
1112 		};
1113 		fParseBindingFromElementAction.setToolTipText("Parse Binding from Element Handle..."); //$NON-NLS-1$
1114 		fParseBindingFromElementAction.setEnabled(true);
1115 
1116 		fParseBindingFromKeyAction= new Action("Parse Binding from &Key...", IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$
1117 			@Override
1118 			public void run() {
1119 				performParseBindingFromKey();
1120 			}
1121 		};
1122 		fParseBindingFromKeyAction.setToolTipText("Parse Binding from Key..."); //$NON-NLS-1$
1123 		fParseBindingFromKeyAction.setEnabled(true);
1124 
1125 		fFocusAction = new Action() {
1126 			@Override
1127 			public void run() {
1128 				performSetFocus();
1129 			}
1130 		};
1131 		fFocusAction.setText("&Show AST of active editor"); //$NON-NLS-1$
1132 		fFocusAction.setToolTipText("Show AST of active editor"); //$NON-NLS-1$
1133 		fFocusAction.setActionDefinitionId(IWorkbenchCommandConstants.FILE_REFRESH);
1134 		ASTViewImages.setImageDescriptors(fFocusAction, ASTViewImages.SETFOCUS);
1135 
1136 		fCollapseAction = new Action() {
1137 			@Override
1138 			public void run() {
1139 				performCollapse();
1140 			}
1141 		};
1142 		fCollapseAction.setText("C&ollapse"); //$NON-NLS-1$
1143 		fCollapseAction.setToolTipText("Collapse Selected Node"); //$NON-NLS-1$
1144 		fCollapseAction.setEnabled(false);
1145 		ASTViewImages.setImageDescriptors(fCollapseAction, ASTViewImages.COLLAPSE);
1146 
1147 		fExpandAction = new Action() {
1148 			@Override
1149 			public void run() {
1150 				performExpand();
1151 			}
1152 		};
1153 		fExpandAction.setText("E&xpand"); //$NON-NLS-1$
1154 		fExpandAction.setToolTipText("Expand Selected Node"); //$NON-NLS-1$
1155 		fExpandAction.setEnabled(false);
1156 		ASTViewImages.setImageDescriptors(fExpandAction, ASTViewImages.EXPAND);
1157 
1158 		fCopyAction= new TreeCopyAction(new Tree[] {fViewer.getTree(), fTray.getTree()});
1159 
1160 		fDoubleClickAction = new Action() {
1161 			@Override
1162 			public void run() {
1163 				performDoubleClick();
1164 			}
1165 		};
1166 
1167 		fLinkWithEditor = new Action() {
1168 			@Override
1169 			public void run() {
1170 				performLinkWithEditor();
1171 			}
1172 		};
1173 		fLinkWithEditor.setChecked(fDoLinkWithEditor);
1174 		fLinkWithEditor.setText("&Link with Editor"); //$NON-NLS-1$
1175 		fLinkWithEditor.setToolTipText("Link With Editor"); //$NON-NLS-1$
1176 		fLinkWithEditor.setActionDefinitionId(IWorkbenchCommandConstants.NAVIGATE_TOGGLE_LINK_WITH_EDITOR);
1177 		ASTViewImages.setImageDescriptors(fLinkWithEditor, ASTViewImages.LINK_WITH_EDITOR);
1178 
1179 		fASTVersionToggleActions= new ASTLevelToggle[] {
1180 				new ASTLevelToggle("AST Level &2 (1.2)", JLS2), //$NON-NLS-1$
1181 				new ASTLevelToggle("AST Level &3 (1.5)", JLS3), //$NON-NLS-1$
1182 				new ASTLevelToggle("AST Level &4 (1.7)", JLS4), //$NON-NLS-1$
1183 				new ASTLevelToggle("AST Level &8 (1.8)", JLS8), //$NON-NLS-1$
1184 				new ASTLevelToggle("AST Level &9 (9)", JLS9), //$NON-NLS-1$
1185 				new ASTLevelToggle("AST Level 1&0 (10)", JLS10), //$NON-NLS-1$
1186 				new ASTLevelToggle("AST Level 1&1 (11)", JLS11), //$NON-NLS-1$
1187 				new ASTLevelToggle("AST Level 1&2 (12)", JLS12), //$NON-NLS-1$
1188 				new ASTLevelToggle("AST Level 1&3 (13)", JLS13), //$NON-NLS-1$
1189 				new ASTLevelToggle("AST Level 1&4 (14)", JLS14), //$NON-NLS-1$
1190 		};
1191 
1192 		fAddToTrayAction= new Action() {
1193 			@Override
1194 			public void run() {
1195 				performAddToTray();
1196 			}
1197 		};
1198 		fAddToTrayAction.setText("&Add to Comparison Tray"); //$NON-NLS-1$
1199 		fAddToTrayAction.setToolTipText("Add Selected Node to Comparison Tray"); //$NON-NLS-1$
1200 		fAddToTrayAction.setEnabled(false);
1201 		ASTViewImages.setImageDescriptors(fAddToTrayAction, ASTViewImages.ADD_TO_TRAY);
1202 
1203 		fDeleteAction= new Action() {
1204 			@Override
1205 			public void run() {
1206 				performDelete();
1207 			}
1208 		};
1209 		fDeleteAction.setText("&Delete"); //$NON-NLS-1$
1210 		fDeleteAction.setToolTipText("Delete Binding from Tray"); //$NON-NLS-1$
1211 		fDeleteAction.setEnabled(false);
1212 		fDeleteAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_DELETE));
1213 		fDeleteAction.setId(ActionFactory.DELETE.getId());
1214 		fDeleteAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_DELETE);
1215 
1216 		refreshASTSettingsActions();
1217 	}
1218 
1219 
refreshAST()1220 	private void refreshAST() throws CoreException {
1221 		ASTNode node= getASTNodeNearSelection((IStructuredSelection) fViewer.getSelection());
1222 		int offset= 0;
1223 		int length= 0;
1224 		if (node != null) {
1225 			offset= node.getStartPosition();
1226 			length= node.getLength();
1227 		}
1228 
1229 		internalSetInput(fTypeRoot, offset, length);
1230 	}
1231 
setASTLevel(int level, boolean doRefresh)1232 	protected void setASTLevel(int level, boolean doRefresh) {
1233 		int oldLevel= fCurrentASTLevel;
1234 		fCurrentASTLevel= level;
1235 
1236 		fDialogSettings.put(SETTINGS_JLS, fCurrentASTLevel);
1237 
1238 		if (doRefresh && fTypeRoot != null && oldLevel != fCurrentASTLevel) {
1239 			try {
1240 				refreshAST();
1241 			} catch (CoreException e) {
1242 				showAndLogError("Could not set AST to new level.", e); //$NON-NLS-1$
1243 				// set back to old level
1244 				fCurrentASTLevel= oldLevel;
1245 			}
1246 		}
1247 		// update action state
1248 		for (ASTView.ASTLevelToggle action : fASTVersionToggleActions) {
1249 			action.setChecked(action.getLevel() == fCurrentASTLevel);
1250 		}
1251 	}
1252 
setASTInputType(int inputKind)1253 	protected void setASTInputType(int inputKind) {
1254 		if (inputKind != fCurrentInputKind) {
1255 			fCurrentInputKind= inputKind;
1256 			fDialogSettings.put(SETTINGS_INPUT_KIND, inputKind);
1257 			for (ASTView.ASTInputKindAction action : fASTInputKindActions) {
1258 				action.setChecked(action.getInputKind() == inputKind);
1259 			}
1260 			refreshASTSettingsActions();
1261 			performRefresh();
1262 		}
1263 	}
1264 
getASTNodeNearSelection(IStructuredSelection selection)1265 	private ASTNode getASTNodeNearSelection(IStructuredSelection selection) {
1266 		Object elem= selection.getFirstElement();
1267 		if (elem instanceof ASTAttribute) {
1268 			return ((ASTAttribute) elem).getParentASTNode();
1269 		} else if (elem instanceof ASTNode) {
1270 			return (ASTNode) elem;
1271 		}
1272 		return null;
1273 	}
1274 
installModificationListener()1275 	private void installModificationListener() {
1276 		fCurrentDocument= fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput());
1277 		fCurrentDocument.addDocumentListener(fSuperListener);
1278 	}
1279 
uninstallModificationListener()1280 	private void uninstallModificationListener() {
1281 		if (fCurrentDocument != null) {
1282 			fCurrentDocument.removeDocumentListener(fSuperListener);
1283 			fCurrentDocument= null;
1284 		}
1285 	}
1286 
handleDocumentDisposed()1287 	protected void handleDocumentDisposed() {
1288 		uninstallModificationListener();
1289 	}
1290 
handleDocumentChanged()1291 	protected void handleDocumentChanged() {
1292 		setASTUptoDate(false);
1293 	}
1294 
handleSelectionChanged(ISelection selection)1295 	protected void handleSelectionChanged(ISelection selection) {
1296 		fExpandAction.setEnabled(!selection.isEmpty());
1297 		fCollapseAction.setEnabled(!selection.isEmpty());
1298 		fCopyAction.setEnabled(!selection.isEmpty());
1299 
1300 		boolean addEnabled= false;
1301 		IStructuredSelection structuredSelection= (IStructuredSelection) selection;
1302 		if (structuredSelection.size() == 1 && fViewer.getTree().isFocusControl()) {
1303 			Object first= structuredSelection.getFirstElement();
1304 			Object unwrapped= ASTView.unwrapAttribute(first);
1305 			addEnabled= unwrapped != null;
1306 		}
1307 		fAddToTrayAction.setEnabled(addEnabled);
1308 	}
1309 
handleEditorPostSelectionChanged(IWorkbenchPart part, ISelection selection)1310 	protected void handleEditorPostSelectionChanged(IWorkbenchPart part, ISelection selection) {
1311 		if (!(selection instanceof ITextSelection)) {
1312 			return;
1313 		}
1314 		ITextSelection textSelection= (ITextSelection) selection;
1315 		if (part == fEditor) {
1316 			fViewer.getTree().setRedraw(false);
1317 			try {
1318 				fASTLabelProvider.setSelectedRange(textSelection.getOffset(), textSelection.getLength());
1319 			} finally {
1320 				fViewer.getTree().setRedraw(true);
1321 			}
1322 		}
1323 		if (!fDoLinkWithEditor) {
1324 			return;
1325 		}
1326 		if (fRoot == null || part != fEditor) {
1327 			if (part instanceof ITextEditor && (EditorUtility.getJavaInput((ITextEditor) part) != null)) {
1328 				try {
1329 					setInput((ITextEditor) part);
1330 				} catch (CoreException e) {
1331 					setContentDescription(e.getStatus().getMessage());
1332 				}
1333 			}
1334 
1335 		} else { // fRoot != null && part == fEditor
1336 			doLinkWithEditor(selection);
1337 		}
1338 	}
1339 
doLinkWithEditor(ISelection selection)1340 	private void doLinkWithEditor(ISelection selection) {
1341 		ITextSelection textSelection= (ITextSelection) selection;
1342 		int offset= textSelection.getOffset();
1343 		int length= textSelection.getLength();
1344 
1345 		ASTNode covering= NodeFinder.perform(fRoot, offset, length);
1346 		if (covering != null) {
1347 			fViewer.reveal(covering);
1348 			fViewer.setSelection(new StructuredSelection(covering));
1349 		}
1350 	}
1351 
handleDoubleClick()1352 	protected void handleDoubleClick() {
1353 		fDoubleClickAction.run();
1354 	}
1355 
performLinkWithEditor()1356 	protected void performLinkWithEditor() {
1357 		fDoLinkWithEditor= fLinkWithEditor.isChecked();
1358 		fDialogSettings.put(SETTINGS_LINK_WITH_EDITOR, fDoLinkWithEditor);
1359 
1360 
1361 		if (fDoLinkWithEditor && fEditor != null) {
1362 			ISelectionProvider selectionProvider= fEditor.getSelectionProvider();
1363 			if (selectionProvider != null) { // can be null when editor is closed
1364 				doLinkWithEditor(selectionProvider.getSelection());
1365 			}
1366 		}
1367 	}
1368 
performCollapse()1369 	protected void performCollapse() {
1370 		IStructuredSelection selection= (IStructuredSelection) fViewer.getSelection();
1371 		if (selection.isEmpty()) {
1372 			fViewer.collapseAll();
1373 		} else {
1374 			fViewer.getTree().setRedraw(false);
1375 			for (Object s : selection.toArray()) {
1376 				fViewer.collapseToLevel(s, AbstractTreeViewer.ALL_LEVELS);
1377 			}
1378 			fViewer.getTree().setRedraw(true);
1379 		}
1380 	}
1381 
performExpand()1382 	protected void performExpand() {
1383 		IStructuredSelection selection= (IStructuredSelection) fViewer.getSelection();
1384 		if (selection.isEmpty()) {
1385 			fViewer.expandToLevel(3);
1386 		} else {
1387 			fViewer.getTree().setRedraw(false);
1388 			for (Object s : selection.toArray()) {
1389 				fViewer.expandToLevel(s, 3);
1390 			}
1391 			fViewer.getTree().setRedraw(true);
1392 		}
1393 	}
1394 
performSetFocus()1395 	protected void performSetFocus() {
1396 		IEditorPart part= EditorUtility.getActiveEditor();
1397 		if (part instanceof ITextEditor) {
1398 			try {
1399 				setInput((ITextEditor) part);
1400 			} catch (CoreException e) {
1401 				showAndLogError("Could not set AST view input ", e); //$NON-NLS-1$
1402 			}
1403 		}
1404 	}
1405 
performRefresh()1406 	protected void performRefresh() {
1407 		if (fTypeRoot != null) {
1408 			try {
1409 				refreshAST();
1410 			} catch (CoreException e) {
1411 				showAndLogError("Could not set AST view input ", e); //$NON-NLS-1$
1412 			}
1413 		}
1414 	}
1415 
performClear()1416 	protected void performClear() {
1417 		fTypeRoot= null;
1418 		try {
1419 			setInput(null);
1420 		} catch (CoreException e) {
1421 			showAndLogError("Could not reset AST view ", e); //$NON-NLS-1$
1422 		}
1423 		clearView();
1424 	}
1425 
showAndLogError(String message, CoreException e)1426 	private void showAndLogError(String message, CoreException e) {
1427 		ASTViewPlugin.log(message, e);
1428 		ErrorDialog.openError(getSite().getShell(), "AST View", message, e.getStatus()); //$NON-NLS-1$
1429 	}
1430 
showAndLogError(String message, Throwable e)1431 	private void showAndLogError(String message, Throwable e) {
1432 		IStatus status= new Status(IStatus.ERROR, ASTViewPlugin.getPluginId(), 0, message, e);
1433 		ASTViewPlugin.log(status);
1434 		ErrorDialog.openError(getSite().getShell(), "AST View", null, status); //$NON-NLS-1$
1435 	}
1436 
performCreateBindings()1437 	protected void performCreateBindings() {
1438 		fCreateBindings= fCreateBindingsAction.isChecked();
1439 		fDialogSettings.put(SETTINGS_NO_BINDINGS, !fCreateBindings);
1440 		performRefresh();
1441 	}
1442 
performStatementsRecovery()1443 	protected void performStatementsRecovery() {
1444 		fStatementsRecovery= fStatementsRecoveryAction.isChecked();
1445 		fDialogSettings.put(SETTINGS_NO_STATEMENTS_RECOVERY, !fStatementsRecovery);
1446 		performRefresh();
1447 	}
1448 
performBindingsRecovery()1449 	protected void performBindingsRecovery() {
1450 		fBindingsRecovery= fBindingsRecoveryAction.isChecked();
1451 		fDialogSettings.put(SETTINGS_NO_BINDINGS_RECOVERY, !fBindingsRecovery);
1452 		performRefresh();
1453 	}
1454 
performIgnoreMethodBodies()1455 	protected void performIgnoreMethodBodies() {
1456 		fIgnoreMethodBodies= fIgnoreMethodBodiesAction.isChecked();
1457 		fDialogSettings.put(SETTINGS_IGNORE_METHOD_BODIES, fIgnoreMethodBodies);
1458 		performRefresh();
1459 	}
1460 
performFilterNonRelevant()1461 	protected void performFilterNonRelevant() {
1462 		boolean showNonRelevant= !fFilterNonRelevantAction.isChecked();
1463 		fNonRelevantFilter.setShowNonRelevant(showNonRelevant);
1464 		fDialogSettings.put(SETTINGS_SHOW_NON_RELEVANT, showNonRelevant);
1465 		fViewer.refresh();
1466 	}
1467 
performFindDeclaringNode()1468 	protected void performFindDeclaringNode() {
1469 		String msg= "Find Declaring Node from Key";
1470 		String key= askForKey(msg);
1471 		if (key == null)
1472 			return;
1473 		ASTNode node= fRoot.findDeclaringNode(key);
1474 		if (node != null) {
1475 			fViewer.setSelection(new StructuredSelection(node), true);
1476 		} else {
1477 			MessageDialog.openError(
1478 					getSite().getShell(),
1479 					"Find Declaring Node from Key",
1480 					"The declaring node for key '" + key + "' could not be found");
1481 		}
1482 	}
1483 
askForKey(String dialogTitle)1484 	private String askForKey(String dialogTitle) {
1485 		InputDialog dialog= new InputDialog(getSite().getShell(), dialogTitle, "Key: (optionally surrounded by <KEY: \"> and <\">)", "", null);
1486 		if (dialog.open() != Window.OK)
1487 			return null;
1488 
1489 		String key= dialog.getValue();
1490 		if (key.startsWith("KEY: \"") && key.endsWith("\""))
1491 			key= key.substring(6, key.length() - 1);
1492 		return key;
1493 	}
1494 
performParseBindingFromKey()1495 	protected void performParseBindingFromKey() {
1496 		String msg= "Parse Binding from Key";
1497 		String key= askForKey(msg);
1498 		if (key == null)
1499 			return;
1500 		ASTParser parser= ASTParser.newParser(fCurrentASTLevel);
1501 		parser.setResolveBindings(true);
1502 		parser.setProject(fTypeRoot.getJavaProject());
1503 		class MyASTRequestor extends ASTRequestor {
1504 			String fBindingKey;
1505 			IBinding fBinding;
1506 			@Override
1507 			public void acceptBinding(String bindingKey, IBinding binding) {
1508 				fBindingKey= bindingKey;
1509 				fBinding= binding;
1510 			}
1511 		}
1512 		MyASTRequestor requestor= new MyASTRequestor();
1513 		ASTAttribute item;
1514 		Object viewerInput= fViewer.getInput();
1515 		try {
1516 			parser.createASTs(new ICompilationUnit[0], new String[] { key }, requestor, null);
1517 			if (requestor.fBindingKey != null) {
1518 				String name= requestor.fBindingKey + ": " + Binding.getBindingLabel(requestor.fBinding);
1519 				item= new Binding(viewerInput, name, requestor.fBinding, true);
1520 			} else {
1521 				item= new Error(viewerInput, "Key not resolved: " + key, null);
1522 			}
1523 		} catch (RuntimeException e) {
1524 			item= new Error(viewerInput, "Error resolving key: " + key, e);
1525 		}
1526 		fViewer.add(viewerInput, item);
1527 		fViewer.setSelection(new StructuredSelection(item), true);
1528 	}
1529 
performParseBindingFromElement()1530 	protected void performParseBindingFromElement() {
1531 		InputDialog dialog= new InputDialog(getSite().getShell(), "Parse Binding from Java Element", "IJavaElement#getHandleIdentifier():", "", null);
1532 		if (dialog.open() != Window.OK)
1533 			return;
1534 
1535 		String handleIdentifier= dialog.getValue();
1536 		IJavaElement handle= JavaCore.create(handleIdentifier);
1537 
1538 		Object viewerInput= fViewer.getInput();
1539 		ASTAttribute item;
1540 		if (handle == null) {
1541 			item= new Error(viewerInput, "handleIdentifier not resolved: " + handleIdentifier, null);
1542 		} else if (! handle.exists()) {
1543 			item= new Error(viewerInput, "element does not exist: " + handleIdentifier, null);
1544 		} else if (handle.getJavaProject() == null) {
1545 			item= new Error(viewerInput, "getJavaProject() is null: " + handleIdentifier, null);
1546 		} else {
1547 			IJavaProject project= handle.getJavaProject();
1548 			ASTParser parser= ASTParser.newParser(fCurrentASTLevel);
1549 			parser.setProject(project);
1550 			IBinding[] bindings= parser.createBindings(new IJavaElement[] { handle }, null);
1551 			String name= handleIdentifier + ": " + Binding.getBindingLabel(bindings[0]);
1552 			item= new Binding(viewerInput, name, bindings[0], true);
1553 		}
1554 		fViewer.add(viewerInput, item);
1555 		fViewer.setSelection(new StructuredSelection(item), true);
1556 	}
1557 
performDoubleClick()1558 	protected void performDoubleClick() {
1559 		if (fEditor == null) {
1560 			return;
1561 		}
1562 
1563 		ISelection selection = fViewer.getSelection();
1564 		Object obj = ((IStructuredSelection) selection).getFirstElement();
1565 
1566 		boolean isTripleClick= (obj == fPreviousDouble);
1567 		fPreviousDouble= isTripleClick ? null : obj;
1568 
1569 		if (obj instanceof ExceptionAttribute) {
1570 			Throwable exception= ((ExceptionAttribute) obj).getException();
1571 			if (exception != null) {
1572 				String label= ((ExceptionAttribute) obj).getLabel();
1573 				showAndLogError("An error occurred while calculating an AST View Label:\n" + label, exception); //$NON-NLS-1$
1574 				return;
1575 			}
1576 		}
1577 
1578 		ASTNode node= null, nodeEnd= null;
1579 		if (obj instanceof ASTNode) {
1580 			node= (ASTNode) obj;
1581 
1582 		} else if (obj instanceof NodeProperty) {
1583 			Object val= ((NodeProperty) obj).getNode();
1584 			if (val instanceof ASTNode) {
1585 				node= (ASTNode) val;
1586 			} else if (val instanceof List) {
1587 				List<?> list= (List<?>) val;
1588 				if (list.size() > 0) {
1589 					node= (ASTNode) list.get(0);
1590 					nodeEnd= (ASTNode) list.get(list.size() - 1);
1591 				} else {
1592 					fViewer.getTree().getDisplay().beep();
1593 				}
1594 			}
1595 
1596 		} else if (obj instanceof Binding) {
1597 			IBinding binding= ((Binding) obj).getBinding();
1598 			ASTNode declaring= fRoot.findDeclaringNode(binding);
1599 			if (declaring != null) {
1600 				fViewer.reveal(declaring);
1601 				fViewer.setSelection(new StructuredSelection(declaring));
1602 			} else {
1603 				fViewer.getTree().getDisplay().beep();
1604 			}
1605 			return;
1606 
1607 		} else if (obj instanceof ProblemNode) {
1608 			ProblemNode problemNode= (ProblemNode) obj;
1609 			EditorUtility.selectInEditor(fEditor, problemNode.getOffset(), problemNode.getLength());
1610 			return;
1611 
1612 		} else if (obj instanceof JavaElement) {
1613 			IJavaElement javaElement= ((JavaElement) obj).getJavaElement();
1614 			if (javaElement instanceof IPackageFragment) {
1615 				try {
1616 					IViewPart packageExplorer= getSite().getPage().showView(JavaUI.ID_PACKAGES);
1617 					if (packageExplorer instanceof IShowInTarget) {
1618 						IShowInTarget showInTarget= (IShowInTarget) packageExplorer;
1619 						showInTarget.show(getShowInContext());
1620 					}
1621 				} catch (PartInitException e) {
1622 					showAndLogError("Could not open Package Explorer.", e); //$NON-NLS-1$
1623 				}
1624 			} else {
1625 				try {
1626 					IEditorPart editorPart= JavaUI.openInEditor(javaElement);
1627 					if (editorPart != null)
1628 						JavaUI.revealInEditor(editorPart, javaElement);
1629 				} catch (PartInitException e) {
1630 					showAndLogError("Could not open editor.", e); //$NON-NLS-1$
1631 				} catch (JavaModelException e) {
1632 					showAndLogError("Could not open editor.", e); //$NON-NLS-1$
1633 				}
1634 			}
1635 			return;
1636 		}
1637 
1638 		if (node != null) {
1639 			int offset= isTripleClick ? fRoot.getExtendedStartPosition(node) : node.getStartPosition();
1640 			int length;
1641 			if (nodeEnd == null) {
1642 				length= isTripleClick ? fRoot.getExtendedLength(node) : node.getLength();
1643 			} else {
1644 				length= isTripleClick
1645 						? fRoot.getExtendedStartPosition(nodeEnd) + fRoot.getExtendedLength(nodeEnd) - fRoot.getExtendedStartPosition(node)
1646 						: nodeEnd.getStartPosition() + nodeEnd.getLength() - node.getStartPosition();
1647 			}
1648 			EditorUtility.selectInEditor(fEditor, offset, length);
1649 		}
1650 	}
1651 
performAddToTray()1652 	protected void performAddToTray() {
1653 		IStructuredSelection selection= (IStructuredSelection) fViewer.getSelection();
1654 		Object firstElement= selection.getFirstElement();
1655 		if (! fTrayRoots.contains(firstElement)) {
1656 			fTrayRoots.add(firstElement);
1657 			fTray.setInput(fTrayRoots);
1658 		}
1659 		if (fSash.getMaximizedControl() != null) {
1660 			int trayHeight= fTray.getTree().getItemHeight() * (2 + TrayContentProvider.DEFAULT_CHILDREN_COUNT);
1661 			int sashHeight= fSash.getClientArea().height;
1662 			fSash.setWeights(new int[] { sashHeight - trayHeight, trayHeight });
1663 			fSash.setMaximizedControl(null);
1664 		}
1665 		setTraySelection(selection);
1666 	}
1667 
setTraySelection(IStructuredSelection selection)1668 	private void setTraySelection(IStructuredSelection selection) {
1669 		fTray.setSelection(selection, true);
1670 		TreeItem[] itemSelection= fTray.getTree().getSelection();
1671 		if (itemSelection.length > 0)
1672 			fTray.getTree().setTopItem(itemSelection[0]);
1673 	}
1674 
performTrayDoubleClick()1675 	protected void performTrayDoubleClick() {
1676 		IStructuredSelection selection= (IStructuredSelection) fTray.getSelection();
1677 		if (selection.size() != 1)
1678 			return;
1679 		Object obj = selection.getFirstElement();
1680 		if (obj instanceof ExceptionAttribute) {
1681 			Throwable exception= ((ExceptionAttribute) obj).getException();
1682 			if (exception != null) {
1683 				String label= ((ExceptionAttribute) obj).getLabel();
1684 				showAndLogError("An error occurred while calculating an AST View Label:\n" + label, exception); //$NON-NLS-1$
1685 				return;
1686 			}
1687 		}
1688 		if (obj instanceof Binding) {
1689 			Binding binding= (Binding) obj;
1690 			fViewer.setSelection(new StructuredSelection(binding), true);
1691 		}
1692 	}
1693 
performDelete()1694 	protected void performDelete() {
1695 		boolean removed= false;
1696 		IStructuredSelection selection= (IStructuredSelection) fTray.getSelection();
1697 		for (Iterator<?> iter= selection.iterator(); iter.hasNext();) {
1698 			Object obj= iter.next();
1699 			if (obj instanceof DynamicAttributeProperty)
1700 				obj= ((DynamicAttributeProperty) obj).getParent();
1701 			if (obj instanceof DynamicBindingProperty)
1702 				obj= ((DynamicBindingProperty) obj).getParent();
1703 
1704 			removed|= fTrayRoots.remove(obj);
1705 		}
1706 		if (removed)
1707 			fTray.setInput(fTrayRoots);
1708 	}
1709 
1710 	@Override
setFocus()1711 	public void setFocus() {
1712 		fViewer.getControl().setFocus();
1713 	}
1714 
1715 	@Override
getShowInContext()1716 	public ShowInContext getShowInContext() {
1717 		return new ShowInContext(null, getSite().getSelectionProvider().getSelection());
1718 	}
1719 
1720 	@Override
getShowInTargetIds()1721 	public String[] getShowInTargetIds() {
1722 		return new String[] { "org.eclipse.jdt.jeview.views.JavaElementView", JavaUI.ID_PACKAGES };
1723 	}
1724 
1725 	/**
1726 	 * @param attribute an attribute
1727 	 * @return the object inside the attribute, or <code>null</code> iff none
1728 	 */
unwrapAttribute(Object attribute)1729 	static Object unwrapAttribute(Object attribute) {
1730 		if (attribute instanceof Binding) {
1731 			return ((Binding) attribute).getBinding();
1732 		} else if (attribute instanceof JavaElement) {
1733 			return ((JavaElement) attribute).getJavaElement();
1734 		} else if (attribute instanceof ASTNode) {
1735 			return attribute;
1736 		} else {
1737 			return null;
1738 		}
1739 	}
1740 }
1741