0001: /*****************************************************************************************
0002: * Copyright (c) 2004 Andrei Loskutov. All rights reserved. This program and the
0003: * accompanying materials are made available under the terms of the BSD License which
0004: * accompanies this distribution, and is available at
0005: * http://www.opensource.org/licenses/bsd-license.php Contributor: Andrei Loskutov -
0006: * initial API and implementation
0007: ****************************************************************************************/package de.loskutov.bco.views;
0008:
0009: import java.io.IOException;
0010: import java.io.InputStream;
0011: import java.util.ArrayList;
0012: import java.util.BitSet;
0013: import java.util.HashMap;
0014: import java.util.Iterator;
0015: import java.util.List;
0016: import java.util.Map;
0017: import java.util.ResourceBundle;
0018:
0019: import org.eclipse.core.filebuffers.FileBuffers;
0020: import org.eclipse.core.runtime.IStatus;
0021: import org.eclipse.jdt.core.IJavaElement;
0022: import org.eclipse.jdt.core.IType;
0023: import org.eclipse.jdt.core.JavaModelException;
0024: import org.eclipse.jface.action.Action;
0025: import org.eclipse.jface.action.IAction;
0026: import org.eclipse.jface.action.IMenuListener;
0027: import org.eclipse.jface.action.IMenuManager;
0028: import org.eclipse.jface.action.IToolBarManager;
0029: import org.eclipse.jface.action.MenuManager;
0030: import org.eclipse.jface.action.Separator;
0031: import org.eclipse.jface.action.StatusLineManager;
0032: import org.eclipse.jface.preference.IPreferenceStore;
0033: import org.eclipse.jface.text.BadLocationException;
0034: import org.eclipse.jface.text.Document;
0035: import org.eclipse.jface.text.IDocument;
0036: import org.eclipse.jface.text.IFindReplaceTarget;
0037: import org.eclipse.jface.text.IRegion;
0038: import org.eclipse.jface.text.ITextListener;
0039: import org.eclipse.jface.text.ITextOperationTarget;
0040: import org.eclipse.jface.text.ITextSelection;
0041: import org.eclipse.jface.text.TextEvent;
0042: import org.eclipse.jface.text.TextViewer;
0043: import org.eclipse.jface.viewers.ISelection;
0044: import org.eclipse.jface.viewers.ISelectionChangedListener;
0045: import org.eclipse.jface.viewers.SelectionChangedEvent;
0046: import org.eclipse.jface.viewers.TableViewer;
0047: import org.eclipse.swt.SWT;
0048: import org.eclipse.swt.custom.SashForm;
0049: import org.eclipse.swt.custom.StackLayout;
0050: import org.eclipse.swt.custom.StyledText;
0051: import org.eclipse.swt.events.ControlEvent;
0052: import org.eclipse.swt.events.ControlListener;
0053: import org.eclipse.swt.events.KeyEvent;
0054: import org.eclipse.swt.events.KeyListener;
0055: import org.eclipse.swt.events.MouseAdapter;
0056: import org.eclipse.swt.events.MouseEvent;
0057: import org.eclipse.swt.events.SelectionAdapter;
0058: import org.eclipse.swt.events.SelectionEvent;
0059: import org.eclipse.swt.graphics.Color;
0060: import org.eclipse.swt.graphics.Point;
0061: import org.eclipse.swt.layout.GridData;
0062: import org.eclipse.swt.layout.GridLayout;
0063: import org.eclipse.swt.widgets.Composite;
0064: import org.eclipse.swt.widgets.Control;
0065: import org.eclipse.swt.widgets.Menu;
0066: import org.eclipse.swt.widgets.Table;
0067: import org.eclipse.swt.widgets.TableColumn;
0068: import org.eclipse.swt.widgets.TableItem;
0069: import org.eclipse.swt.widgets.Widget;
0070: import org.eclipse.ui.IActionBars;
0071: import org.eclipse.ui.IEditorPart;
0072: import org.eclipse.ui.IEditorReference;
0073: import org.eclipse.ui.ISelectionService;
0074: import org.eclipse.ui.ISharedImages;
0075: import org.eclipse.ui.IViewSite;
0076: import org.eclipse.ui.IWorkbenchActionConstants;
0077: import org.eclipse.ui.IWorkbenchPart;
0078: import org.eclipse.ui.PlatformUI;
0079: import org.eclipse.ui.actions.ActionFactory;
0080: import org.eclipse.ui.console.actions.TextViewerAction;
0081: import org.eclipse.ui.part.ViewPart;
0082: import org.eclipse.ui.plugin.AbstractUIPlugin;
0083: import org.eclipse.ui.texteditor.FindReplaceAction;
0084: import org.eclipse.ui.texteditor.ITextEditor;
0085: import org.eclipse.ui.texteditor.IUpdate;
0086: import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds;
0087:
0088: import de.loskutov.bco.BytecodeOutlinePlugin;
0089: import de.loskutov.bco.asm.DecompiledClass;
0090: import de.loskutov.bco.asm.DecompiledMethod;
0091: import de.loskutov.bco.asm.DecompilerClassVisitor;
0092: import de.loskutov.bco.asm.LineRange;
0093: import de.loskutov.bco.preferences.BCOConstants;
0094: import de.loskutov.bco.ui.EclipseUtils;
0095: import de.loskutov.bco.ui.JdtUtils;
0096: import de.loskutov.bco.ui.actions.DefaultToggleAction;
0097:
0098: /**
0099: * This view shows decompiled java bytecode
0100: * @author Andrei
0101: */
0102: public class BytecodeOutlineView extends ViewPart {
0103:
0104: // orientations
0105: static final int VIEW_ORIENTATION_VERTICAL = 0;
0106: static final int VIEW_ORIENTATION_HORIZONTAL = 1;
0107: static final int VIEW_ORIENTATION_AUTOMATIC = 2;
0108:
0109: /**
0110: * The current orientation; either <code>VIEW_ORIENTATION_HORIZONTAL</code>
0111: * <code>VIEW_ORIENTATION_VERTICAL</code>,
0112: * or <code>VIEW_ORIENTATION_AUTOMATIC</code>.
0113: */
0114: int orientation = VIEW_ORIENTATION_AUTOMATIC;
0115: /**
0116: * The current orientation; either <code>VIEW_ORIENTATION_HORIZONTAL</code>
0117: * <code>VIEW_ORIENTATION_VERTICAL</code>.
0118: */
0119: private int currentOrientation;
0120:
0121: protected ToggleOrientationAction[] toggleOrientationActions;
0122:
0123: protected BitSet modes;
0124:
0125: protected boolean inputChanged;
0126: protected boolean bufferIsDirty;
0127:
0128: private boolean isEnabled;
0129: private boolean isActive;
0130: private boolean isVisible;
0131:
0132: protected Composite stackComposite;
0133: protected StyledText textControl;
0134: protected TextViewer textViewer;
0135: protected SashForm verifyControl;
0136: protected SashForm stackAndLvt;
0137: protected Table tableControl;
0138: protected TableViewer tableControlViewer;
0139: protected Table stackTable;
0140: protected Table lvtTable;
0141:
0142: protected ITextEditor javaEditor;
0143: private IJavaElement javaInput;
0144: protected IJavaElement lastChildElement;
0145: protected ITextSelection currentSelection;
0146: protected EditorListener editorListener;
0147: protected Action selectionChangedAction;
0148: protected Action refreshVarsAndStackAction;
0149: protected Action linkWithEditorAction;
0150: protected Action showSelectedOnlyAction;
0151: protected Action setRawModeAction;
0152: protected Action toggleASMifierModeAction;
0153: protected Action hideLineInfoAction;
0154: protected Action hideLocalsAction;
0155: protected Action hideStackMapAction;
0156: protected Action showHexValuesAction;
0157: protected Action expandStackMapAction;
0158: protected Action toggleVerifierAction;
0159: protected StatusLineManager statusLineManager;
0160: protected BCOViewSelectionProvider viewSelectionProvider;
0161:
0162: protected Color errorColor;
0163:
0164: private DecompiledClass lastDecompiledResult;
0165:
0166: protected Map globalActions;
0167: protected List selectionActions;
0168: private MenuManager contextMenuManager;
0169: /** global class info, without current selection status */
0170: protected String currentStatusMessage;
0171: protected boolean hasAnalyzerError;
0172: /*
0173: * I don't know how to update the state of toolbar and menu managers because it seems
0174: * that if we toggle the action state internally (not by user click) then either the
0175: * managers or contribution items or whatever holds the old state of checked action.
0176: * This flag is a workaround and allows us restore the state after internal toggling.
0177: */
0178: private boolean restoreVerify;
0179: private static final String NLS_PREFIX = "BytecodeOutlineView.";
0180:
0181: // updates the find replace action if the document length is > 0
0182: private ITextListener textListener;
0183:
0184: // see org.eclipse.ui.console.TextConsolePage for the reason to do this ;)
0185: private ISelectionChangedListener textSelectionListener;
0186: private Control statusControl;
0187:
0188: // ------------------------------------------------------------------------
0189:
0190: protected void setJavaInput(IJavaElement javaInput) {
0191: this .javaInput = javaInput;
0192: inputChanged = true;
0193: }
0194:
0195: /**
0196: * The constructor.
0197: */
0198: public BytecodeOutlineView() {
0199: super ();
0200: modes = new BitSet();
0201: globalActions = new HashMap();
0202: selectionActions = new ArrayList();
0203: }
0204:
0205: // ------------------------------------------------------------------------
0206:
0207: /**
0208: * Is this view state changes depending on editor changes?
0209: * @return true if linked with editor
0210: */
0211: protected boolean isLinkedWithEditor() {
0212: return modes.get(BCOConstants.F_LINK_VIEW_TO_EDITOR);
0213: }
0214:
0215: /**
0216: * Are actions on toolbar active?
0217: * @return Returns the isEnabled.
0218: */
0219: private boolean isEnabled() {
0220: return isEnabled;
0221: }
0222:
0223: private void setEnabled(boolean on) {
0224: this .isEnabled = on;
0225: if (tableControl != null && !tableControl.isDisposed()) {
0226: tableControl.setEnabled(on);
0227: }
0228: if (stackTable != null && !stackTable.isDisposed()) {
0229: stackTable.setEnabled(on);
0230: }
0231: if (lvtTable != null && !lvtTable.isDisposed()) {
0232: lvtTable.setEnabled(on);
0233: }
0234: showSelectedOnlyAction.setEnabled(on);
0235: linkWithEditorAction.setEnabled(on);
0236: selectionChangedAction.setEnabled(on);
0237: toggleVerifierAction.setEnabled(on);
0238: hideLocalsAction.setEnabled(on);
0239: hideLineInfoAction.setEnabled(on);
0240: hideStackMapAction.setEnabled(on);
0241: showHexValuesAction.setEnabled(on);
0242: toggleASMifierModeAction.setEnabled(on);
0243: expandStackMapAction.setEnabled(on);
0244: setRawModeAction.setEnabled(on
0245: && !toggleASMifierModeAction.isChecked());
0246: boolean showAnalyzer = on && toggleVerifierAction.isChecked();
0247: for (int i = 0; i < toggleOrientationActions.length; ++i) {
0248: toggleOrientationActions[i].setEnabled(showAnalyzer);
0249: }
0250: }
0251:
0252: /**
0253: * Is this view monitoring workspace changes?
0254: * @return Returns the isActive.
0255: */
0256: private boolean isActive() {
0257: return isActive;
0258: }
0259:
0260: /**
0261: * @param bufferIsDirty The bufferIsDirty to set.
0262: */
0263: private void setBufferIsDirty(boolean bufferIsDirty) {
0264: this .bufferIsDirty = bufferIsDirty;
0265: }
0266:
0267: private void setInput(ITextEditor editor) {
0268: javaEditor = null;
0269: setJavaInput(null);
0270: lastDecompiledResult = null;
0271: if (editor != null) {
0272: IJavaElement javaElem = EclipseUtils.getJavaInput(editor);
0273: if (javaElem == null) {
0274: return;
0275: }
0276: setJavaInput(javaElem);
0277: javaEditor = editor;
0278:
0279: checkVerifyMode();
0280:
0281: updateSelection(EclipseUtils.getSelection(javaEditor
0282: .getSelectionProvider()));
0283: setBufferIsDirty(editor.isDirty());
0284: }
0285: }
0286:
0287: private void checkVerifyMode() {
0288: boolean aoi = JdtUtils.isAbstractOrInterface(javaInput);
0289:
0290: if (!toggleVerifierAction.isChecked()) {
0291: // deactivate verify button, but only if *not* in verify mode
0292: toggleVerifierAction.setEnabled(!aoi);
0293: restoreVerify = false;
0294: } else {
0295: if (aoi) {
0296: // swith verify mode off, because it is not applicable to selected element
0297: inputChanged = true;
0298: toggleVerifyMode(getViewSite().getActionBars()
0299: .getMenuManager(), false);
0300: // remember last state, to match the state of the toolbars and menus
0301: restoreVerify = true;
0302: } else {
0303: if (restoreVerify) {
0304: inputChanged = true;
0305: toggleVerifierAction.setEnabled(true);
0306: toggleVerifyMode(getViewSite().getActionBars()
0307: .getMenuManager(), true);
0308: }
0309: restoreVerify = false;
0310: }
0311: }
0312: }
0313:
0314: private boolean updateSelection(ITextSelection sel) {
0315: if (sel != null
0316: && (sel.equals(currentSelection) || (currentSelection != null
0317: && sel.getStartLine() == currentSelection
0318: .getStartLine() && sel.getEndLine() == currentSelection
0319: .getEndLine()))) {
0320:
0321: /*
0322: * getStartLine/getEndLine is probably not sensitive enough - but in case of
0323: * java classes/methods which fits in one selection but not in the other, then
0324: * I think we can ignore them here - this is not the 99% of use cases.
0325: */
0326: return false;
0327: }
0328:
0329: currentSelection = sel;
0330: return true;
0331: }
0332:
0333: // ------------------------------------------------------------------------
0334:
0335: /**
0336: * @see org.eclipse.ui.IViewPart#init(org.eclipse.ui.IViewSite)
0337: */
0338: public void init(IViewSite site) {
0339: super .setSite(site);
0340: if (editorListener == null) {
0341: editorListener = new EditorListener(this );
0342: getSite().getWorkbenchWindow().getPartService()
0343: .addPartListener(editorListener);
0344: }
0345: }
0346:
0347: /**
0348: * This is a callback that will allow us to create the viewer and initialize it.
0349: * @param parent
0350: */
0351: public void createPartControl(Composite parent) {
0352: errorColor = parent.getDisplay().getSystemColor(SWT.COLOR_RED);
0353: parent.addControlListener(new ControlListener() {
0354:
0355: public void controlMoved(ControlEvent e) {
0356: //
0357: }
0358:
0359: public void controlResized(ControlEvent e) {
0360: computeOrientation();
0361: }
0362: });
0363:
0364: GridLayout parentLayout = new GridLayout();
0365: parentLayout.numColumns = 1;
0366: parentLayout.marginBottom = -5;
0367: parentLayout.marginTop = -5;
0368: parentLayout.marginLeft = -5;
0369: parentLayout.marginRight = -5;
0370:
0371: parent.setLayout(parentLayout);
0372:
0373: stackComposite = new Composite(parent, SWT.NONE);
0374: stackComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
0375: stackComposite.setLayout(new StackLayout());
0376:
0377: statusLineManager = new StatusLineManager();
0378: statusControl = statusLineManager.createControl(parent,
0379: SWT.NONE);
0380: statusControl.setLayoutData(new GridData(
0381: GridData.FILL_HORIZONTAL));
0382:
0383: createTextControl();
0384:
0385: createTextContextMenu();
0386:
0387: createVerifyControl();
0388:
0389: ((StackLayout) stackComposite.getLayout()).topControl = textControl;
0390:
0391: createSelectionProvider();
0392:
0393: initModes();
0394:
0395: createToolbarActions();
0396:
0397: setEnabled(false);
0398: }
0399:
0400: private void initModes() {
0401: IPreferenceStore store = BytecodeOutlinePlugin.getDefault()
0402: .getPreferenceStore();
0403: modes.set(BCOConstants.F_LINK_VIEW_TO_EDITOR, store
0404: .getBoolean(BCOConstants.LINK_VIEW_TO_EDITOR));
0405: modes.set(BCOConstants.F_SHOW_ONLY_SELECTED_ELEMENT, store
0406: .getBoolean(BCOConstants.SHOW_ONLY_SELECTED_ELEMENT));
0407: modes.set(BCOConstants.F_SHOW_RAW_BYTECODE, store
0408: .getBoolean(BCOConstants.SHOW_RAW_BYTECODE));
0409: modes.set(BCOConstants.F_SHOW_LINE_INFO, store
0410: .getBoolean(BCOConstants.SHOW_LINE_INFO));
0411: modes.set(BCOConstants.F_SHOW_VARIABLES, store
0412: .getBoolean(BCOConstants.SHOW_VARIABLES));
0413: modes.set(BCOConstants.F_SHOW_STACKMAP, store
0414: .getBoolean(BCOConstants.SHOW_STACKMAP));
0415: modes.set(BCOConstants.F_EXPAND_STACKMAP, store
0416: .getBoolean(BCOConstants.EXPAND_STACKMAP));
0417: modes.set(BCOConstants.F_SHOW_ASMIFIER_CODE, store
0418: .getBoolean(BCOConstants.SHOW_ASMIFIER_CODE));
0419: modes.set(BCOConstants.F_SHOW_ANALYZER, store
0420: .getBoolean(BCOConstants.SHOW_ANALYZER));
0421: modes.set(BCOConstants.F_SHOW_HEX_VALUES, store
0422: .getBoolean(BCOConstants.SHOW_HEX_VALUES));
0423: }
0424:
0425: private void createToolbarActions() {
0426: createTextActions();
0427:
0428: final IActionBars bars = getViewSite().getActionBars();
0429: final IToolBarManager tmanager = bars.getToolBarManager();
0430: final IMenuManager mmanager = bars.getMenuManager();
0431:
0432: selectionChangedAction = new Action() {
0433:
0434: public void run() {
0435: Point selection = textControl.getSelection();
0436: setSelectionInJavaEditor(selection);
0437: }
0438: };
0439:
0440: refreshVarsAndStackAction = new Action() {
0441:
0442: public void run() {
0443: int decompiledLine = tableControl.getSelectionIndex();
0444: updateVerifierControl(decompiledLine);
0445: }
0446: };
0447:
0448: linkWithEditorAction = new DefaultToggleAction(
0449: BCOConstants.LINK_VIEW_TO_EDITOR) {
0450:
0451: public void run(boolean newState) {
0452: setMode(BCOConstants.F_LINK_VIEW_TO_EDITOR, newState);
0453: if (modes.get(BCOConstants.F_LINK_VIEW_TO_EDITOR)) {
0454: showSelectedOnlyAction.setEnabled(true);
0455: toggleVerifierAction.setEnabled(true);
0456: hideLineInfoAction.setEnabled(true);
0457: hideLocalsAction.setEnabled(true);
0458: toggleASMifierModeAction.setEnabled(true);
0459: if (!toggleASMifierModeAction.isChecked()) {
0460: setRawModeAction.setEnabled(true);
0461: }
0462: checkOpenEditors(true);
0463: // refreshView();
0464: }
0465: }
0466: };
0467:
0468: showSelectedOnlyAction = new DefaultToggleAction(
0469: BCOConstants.SHOW_ONLY_SELECTED_ELEMENT) {
0470:
0471: public void run(boolean newState) {
0472: setMode(BCOConstants.F_SHOW_ONLY_SELECTED_ELEMENT,
0473: newState);
0474: inputChanged = true;
0475: refreshView();
0476: }
0477: };
0478:
0479: setRawModeAction = new DefaultToggleAction(
0480: BCOConstants.SHOW_RAW_BYTECODE) {
0481:
0482: public void run(boolean newState) {
0483: setMode(BCOConstants.F_SHOW_RAW_BYTECODE, newState);
0484: inputChanged = true;
0485: refreshView();
0486: }
0487: };
0488:
0489: hideLineInfoAction = new DefaultToggleAction(
0490: BCOConstants.SHOW_LINE_INFO) {
0491:
0492: public void run(boolean newState) {
0493: setMode(BCOConstants.F_SHOW_LINE_INFO, newState);
0494: inputChanged = true;
0495: refreshView();
0496: }
0497: };
0498:
0499: hideLocalsAction = new DefaultToggleAction(
0500: BCOConstants.SHOW_VARIABLES) {
0501:
0502: public void run(boolean newState) {
0503: setMode(BCOConstants.F_SHOW_VARIABLES, newState);
0504: inputChanged = true;
0505: refreshView();
0506: }
0507: };
0508:
0509: hideStackMapAction = new DefaultToggleAction(
0510: BCOConstants.SHOW_STACKMAP) {
0511:
0512: public void run(boolean newState) {
0513: setMode(BCOConstants.F_SHOW_STACKMAP, newState);
0514: inputChanged = true;
0515: refreshView();
0516: }
0517: };
0518:
0519: expandStackMapAction = new DefaultToggleAction(
0520: BCOConstants.EXPAND_STACKMAP) {
0521:
0522: public void run(boolean newState) {
0523: setMode(BCOConstants.F_EXPAND_STACKMAP, newState);
0524: inputChanged = true;
0525: refreshView();
0526: }
0527: };
0528:
0529: showHexValuesAction = new DefaultToggleAction(
0530: BCOConstants.SHOW_HEX_VALUES) {
0531:
0532: public void run(boolean newState) {
0533: setMode(BCOConstants.F_SHOW_HEX_VALUES, newState);
0534: inputChanged = true;
0535: refreshView();
0536: }
0537: };
0538:
0539: toggleASMifierModeAction = new DefaultToggleAction(
0540: BCOConstants.SHOW_ASMIFIER_CODE) {
0541:
0542: public void run(boolean newState) {
0543: setMode(BCOConstants.F_SHOW_ASMIFIER_CODE, newState);
0544: if (newState) {
0545: setMode(BCOConstants.F_SHOW_RAW_BYTECODE, true);
0546: setRawModeAction.setEnabled(false);
0547: } else {
0548: setRawModeAction.setEnabled(true);
0549: }
0550: inputChanged = true;
0551: refreshView();
0552: }
0553: };
0554:
0555: toggleVerifierAction = new DefaultToggleAction(
0556: BCOConstants.SHOW_ANALYZER) {
0557:
0558: public void run(boolean newState) {
0559: toggleVerifyMode(mmanager, newState);
0560: inputChanged = true;
0561: refreshView();
0562: }
0563: };
0564:
0565: mmanager.add(linkWithEditorAction);
0566: mmanager.add(showSelectedOnlyAction);
0567: mmanager.add(setRawModeAction);
0568: mmanager.add(hideLineInfoAction);
0569: mmanager.add(hideLocalsAction);
0570: mmanager.add(showHexValuesAction);
0571: mmanager.add(hideStackMapAction);
0572: mmanager.add(expandStackMapAction);
0573: mmanager.add(toggleASMifierModeAction);
0574: mmanager.add(toggleVerifierAction);
0575:
0576: mmanager.add(new Separator());
0577:
0578: toggleOrientationActions = new ToggleOrientationAction[] {
0579: new ToggleOrientationAction(this ,
0580: VIEW_ORIENTATION_VERTICAL),
0581: new ToggleOrientationAction(this ,
0582: VIEW_ORIENTATION_HORIZONTAL),
0583: new ToggleOrientationAction(this ,
0584: VIEW_ORIENTATION_AUTOMATIC) };
0585: for (int i = 0; i < toggleOrientationActions.length; ++i) {
0586: mmanager.add(toggleOrientationActions[i]);
0587: }
0588:
0589: tmanager.add(linkWithEditorAction);
0590: tmanager.add(showSelectedOnlyAction);
0591: tmanager.add(setRawModeAction);
0592: // tmanager.add(hideLineInfoAction);
0593: // tmanager.add(hideLocalsAction);
0594: tmanager.add(toggleASMifierModeAction);
0595: tmanager.add(toggleVerifierAction);
0596: }
0597:
0598: private void createVerifyControl() {
0599: verifyControl = new SashForm(stackComposite, SWT.VERTICAL);
0600:
0601: tableControl = new Table(verifyControl, SWT.SINGLE
0602: | SWT.FULL_SELECTION);
0603: tableControlViewer = new TableViewer(tableControl);
0604:
0605: new TableColumn(tableControl, SWT.LEFT)
0606: .setText(BytecodeOutlinePlugin
0607: .getResourceString(NLS_PREFIX + "lvt.header"));
0608: new TableColumn(tableControl, SWT.LEFT)
0609: .setText(BytecodeOutlinePlugin
0610: .getResourceString(NLS_PREFIX + "stack.header"));
0611: new TableColumn(tableControl, SWT.LEFT);
0612: new TableColumn(tableControl, SWT.LEFT);
0613: tableControl.setLinesVisible(false);
0614: tableControl.setHeaderVisible(true);
0615:
0616: stackAndLvt = new SashForm(verifyControl, SWT.HORIZONTAL);
0617:
0618: lvtTable = new Table(stackAndLvt, SWT.SINGLE
0619: | SWT.FULL_SELECTION);
0620: lvtTable.setLinesVisible(false);
0621: lvtTable.setHeaderVisible(true);
0622:
0623: new TableColumn(lvtTable, SWT.LEFT).setText("#");
0624: new TableColumn(lvtTable, SWT.LEFT).setText("Var Type");
0625: new TableColumn(lvtTable, SWT.LEFT).setText("Name");
0626:
0627: stackTable = new Table(stackAndLvt, SWT.SINGLE
0628: | SWT.FULL_SELECTION);
0629: stackTable.setLinesVisible(false);
0630: stackTable.setHeaderVisible(true);
0631: new TableColumn(stackTable, SWT.LEFT).setText("#");
0632: new TableColumn(stackTable, SWT.LEFT).setText("Stack Type");
0633:
0634: stackAndLvt.setWeights(new int[] { 50, 50 });
0635:
0636: verifyControl.setWeights(new int[] { 75, 25 });
0637:
0638: tableControl.addSelectionListener(new SelectionAdapter() {
0639:
0640: public void widgetSelected(SelectionEvent e) {
0641: if (modes.get(BCOConstants.F_LINK_VIEW_TO_EDITOR)) {
0642: selectionChangedAction.run();
0643: }
0644: refreshVarsAndStackAction.run();
0645: }
0646: });
0647:
0648: }
0649:
0650: private void createSelectionProvider() {
0651: viewSelectionProvider = new BCOViewSelectionProvider();
0652: viewSelectionProvider.registerSelectionProvider(textViewer);
0653: viewSelectionProvider
0654: .registerSelectionProvider(tableControlViewer);
0655:
0656: // initially selection provider is the textControl, but this could be changed by
0657: // user
0658: // to the tableControl, if bco will be switched to the verify mode
0659: viewSelectionProvider.setCurrentSelectionProvider(textViewer);
0660: getSite().setSelectionProvider(viewSelectionProvider);
0661: }
0662:
0663: /**
0664: * create/register context menu on text control
0665: */
0666: private void createTextContextMenu() {
0667: String id = "de.loskutov.bco.views.BytecodeOutlineView#ContextMenu"; //$NON-NLS-1$
0668: contextMenuManager = new MenuManager("#ContextMenu", id); //$NON-NLS-1$
0669: contextMenuManager.setRemoveAllWhenShown(true);
0670: contextMenuManager.addMenuListener(new IMenuListener() {
0671:
0672: public void menuAboutToShow(IMenuManager m) {
0673: contextMenuAboutToShow(m);
0674: }
0675: });
0676: Menu menu = contextMenuManager.createContextMenu(textControl);
0677: textControl.setMenu(menu);
0678:
0679: getSite().registerContextMenu(id, contextMenuManager,
0680: textViewer);
0681: }
0682:
0683: private void createTextControl() {
0684: textViewer = new TextViewer(stackComposite, SWT.H_SCROLL
0685: | SWT.V_SCROLL);
0686: textViewer.setEditable(false);
0687: // textViewer.setHoverControlCreator(null)
0688:
0689: textControl = textViewer.getTextWidget();
0690: IDocument document = new Document("");
0691: textViewer.setDocument(document);
0692:
0693: textSelectionListener = new ISelectionChangedListener() {
0694:
0695: public void selectionChanged(SelectionChangedEvent event) {
0696: // Updates selection dependent actions like find/copy.
0697: Iterator iterator = selectionActions.iterator();
0698: while (iterator.hasNext()) {
0699: updateAction((String) iterator.next());
0700: }
0701: }
0702: };
0703:
0704: textListener = new ITextListener() {
0705:
0706: public void textChanged(TextEvent event) {
0707: IUpdate findReplace = (IUpdate) globalActions
0708: .get(ActionFactory.FIND.getId());
0709: if (findReplace != null) {
0710: findReplace.update();
0711: }
0712: }
0713: };
0714:
0715: textViewer.getSelectionProvider().addSelectionChangedListener(
0716: textSelectionListener);
0717: textViewer.addTextListener(textListener);
0718:
0719: textControl.addMouseListener(new MouseAdapter() {
0720:
0721: public void mouseDown(MouseEvent e) {
0722: if (modes.get(BCOConstants.F_LINK_VIEW_TO_EDITOR)) {
0723: selectionChangedAction.run();
0724: }
0725: }
0726:
0727: public void mouseUp(MouseEvent e) {
0728: if (modes.get(BCOConstants.F_LINK_VIEW_TO_EDITOR)) {
0729: selectionChangedAction.run();
0730: }
0731: }
0732: });
0733:
0734: textControl.addKeyListener(new KeyListener() {
0735:
0736: public void keyPressed(KeyEvent e) {
0737: // ignored
0738: }
0739:
0740: public void keyReleased(KeyEvent e) {
0741: if (modes.get(BCOConstants.F_LINK_VIEW_TO_EDITOR)) {
0742: selectionChangedAction.run();
0743: }
0744: }
0745: });
0746: }
0747:
0748: /**
0749: * @see org.eclipse.ui.IWorkbenchPart#dispose()
0750: */
0751: public void dispose() {
0752: deActivateView();
0753: if (editorListener != null) {
0754: getSite().getWorkbenchWindow().getPartService()
0755: .removePartListener(editorListener);
0756: editorListener.dispose();
0757: editorListener = null;
0758: }
0759:
0760: if (contextMenuManager != null) {
0761: contextMenuManager.dispose();
0762: }
0763:
0764: selectionActions.clear();
0765: globalActions.clear();
0766:
0767: textViewer.getSelectionProvider()
0768: .removeSelectionChangedListener(textSelectionListener);
0769: textViewer.removeTextListener(textListener);
0770: textViewer = null;
0771: viewSelectionProvider = null;
0772:
0773: if (textControl != null) {
0774: textControl.dispose();
0775: textControl = null;
0776: }
0777: if (verifyControl != null) {
0778: verifyControl.dispose();
0779: verifyControl = null;
0780: tableControl = null;
0781: stackTable = null;
0782: lvtTable = null;
0783: tableControlViewer = null;
0784: }
0785: currentSelection = null;
0786: javaEditor = null;
0787: setJavaInput(null);
0788: lastChildElement = null;
0789: linkWithEditorAction = null;
0790: selectionChangedAction = null;
0791: refreshVarsAndStackAction = null;
0792: showSelectedOnlyAction = null;
0793: setRawModeAction = null;
0794: toggleASMifierModeAction = null;
0795: hideLineInfoAction = null;
0796: hideLocalsAction = null;
0797: hideStackMapAction = null;
0798: showHexValuesAction = null;
0799: expandStackMapAction = null;
0800: toggleVerifierAction = null;
0801: lastDecompiledResult = null;
0802: super .dispose();
0803: }
0804:
0805: /**
0806: * Fill the context menu
0807: * @param menuManager menu
0808: */
0809: protected void contextMenuAboutToShow(IMenuManager menuManager) {
0810: IDocument doc = textViewer.getDocument();
0811: if (doc == null) {
0812: return;
0813: }
0814:
0815: menuManager.add((IAction) globalActions.get(ActionFactory.COPY
0816: .getId()));
0817: menuManager.add((IAction) globalActions
0818: .get(ActionFactory.SELECT_ALL.getId()));
0819:
0820: menuManager.add(new Separator("FIND")); //$NON-NLS-1$
0821: menuManager.add((IAction) globalActions.get(ActionFactory.FIND
0822: .getId()));
0823:
0824: menuManager.add(new Separator(
0825: IWorkbenchActionConstants.MB_ADDITIONS));
0826: }
0827:
0828: // -----------------------------------------------------------------------
0829:
0830: /**
0831: * Passing the focus request to the viewer's control.
0832: */
0833: public void setFocus() {
0834: if (!modes.get(BCOConstants.F_SHOW_ANALYZER)) {
0835: if (textViewer != null) {
0836: textViewer.getTextWidget().setFocus();
0837: }
0838: } else {
0839: if (tableControl != null) {
0840: tableControl.setFocus();
0841: }
0842: }
0843: }
0844:
0845: protected void handleBufferIsDirty(boolean isDirty) {
0846: if (!modes.get(BCOConstants.F_LINK_VIEW_TO_EDITOR)
0847: || !isActive()) {
0848: return;
0849: }
0850: if (isDirty) {
0851: setBufferIsDirty(isDirty);
0852: } else {
0853: if (!bufferIsDirty) {
0854: // second time calling with same argument -
0855: // cause new bytecode should be written now
0856: inputChanged = true;
0857: refreshView();
0858: } else {
0859: // first time - set the flag only - cause
0860: // bytecode is not yet written
0861: setBufferIsDirty(false);
0862: }
0863: }
0864: }
0865:
0866: protected void handlePartHidden(IWorkbenchPart part) {
0867: if (!modes.get(BCOConstants.F_LINK_VIEW_TO_EDITOR)) {
0868: return;
0869: }
0870: if (this == part) {
0871: isVisible = false;
0872: deActivateView();
0873: } else if (isActive() && (part instanceof IEditorPart)) {
0874: // check if at least one editor is open
0875: checkOpenEditors(false);
0876: }
0877: }
0878:
0879: protected void handlePartVisible(IWorkbenchPart part) {
0880: if (!modes.get(BCOConstants.F_LINK_VIEW_TO_EDITOR)) {
0881: return;
0882: }
0883: if (this == part) {
0884: if (isVisible) {
0885: return;
0886: }
0887: isVisible = true;
0888: // check if java editor is already open
0889: IEditorPart activeEditor = EclipseUtils.getActiveEditor();
0890: if (!(activeEditor instanceof ITextEditor)) {
0891: // start monitoring again, even if current editor is not
0892: // supported - but we at front now
0893: activateView();
0894: return;
0895: }
0896: part = activeEditor;
0897: // continue with setting input
0898: }
0899: if (isVisible && part instanceof ITextEditor) {
0900: if (isActive() && part == javaEditor) {
0901: return;
0902: }
0903: activateView();
0904: setEnabled(true);
0905: setInput((ITextEditor) part);
0906: refreshView();
0907: } else if (part instanceof IEditorPart) {
0908: if (isActive()) {
0909: deActivateView();
0910: }
0911: }
0912: }
0913:
0914: protected void handleSelectionChanged(IWorkbenchPart part,
0915: ISelection selection) {
0916: if (!modes.get(BCOConstants.F_LINK_VIEW_TO_EDITOR)
0917: || !isActive() || !isVisible
0918: || !(part instanceof IEditorPart)) {
0919: return;
0920: }
0921: if (!(part instanceof ITextEditor)) {
0922: deActivateView();
0923: return;
0924: }
0925: if (!isEnabled()) {
0926: setEnabled(true);
0927: }
0928: if (part != javaEditor) {
0929: setInput((ITextEditor) part);
0930: } else {
0931: if (!updateSelection((ITextSelection) selection)) {
0932: return;
0933: }
0934: }
0935: refreshView();
0936: }
0937:
0938: /**
0939: * Does nothing if view is already active
0940: */
0941: private void activateView() {
0942: if (isActive()) {
0943: return;
0944: }
0945: isActive = true;
0946: getSite().getWorkbenchWindow().getSelectionService()
0947: .addPostSelectionListener(editorListener);
0948: FileBuffers.getTextFileBufferManager().addFileBufferListener(
0949: editorListener);
0950: }
0951:
0952: /**
0953: * Does nothing if view is already deactivated
0954: */
0955: private void deActivateView() {
0956: if (!isActive()) {
0957: return;
0958: }
0959: setEnabled(false);
0960: if (editorListener != null) {
0961: ISelectionService service = getSite().getWorkbenchWindow()
0962: .getSelectionService();
0963: if (service != null) {
0964: service.removePostSelectionListener(editorListener);
0965: }
0966: FileBuffers.getTextFileBufferManager()
0967: .removeFileBufferListener(editorListener);
0968:
0969: }
0970: if (textViewer != null && textViewer.getTextWidget() != null
0971: && !textViewer.getTextWidget().isDisposed()) {
0972: IDocument document = new Document("");
0973: textViewer.setDocument(document);
0974: }
0975: if (tableControl != null && !tableControl.isDisposed()) {
0976: setVerifyTableItems(null);
0977: }
0978: /*
0979: * if(stackControl != null && !stackControl.isDisposed()){
0980: * stackControl.setText(""); } if(lvtControl != null && !lvtControl.isDisposed()){
0981: * lvtControl.setText(""); }
0982: */
0983: if (stackTable != null && !stackTable.isDisposed()) {
0984: stackTable.removeAll();
0985: }
0986: if (lvtTable != null && !lvtTable.isDisposed()) {
0987: lvtTable.removeAll();
0988: }
0989: if (statusControl != null && !statusControl.isDisposed()) {
0990: updateStatus(null, -1, -1);
0991: }
0992: currentSelection = null;
0993: lastDecompiledResult = null;
0994: javaEditor = null;
0995: setJavaInput(null);
0996: lastChildElement = null;
0997: setBufferIsDirty(false);
0998: isActive = false;
0999: }
1000:
1001: protected void refreshView() {
1002: if (!isActive()) {
1003: return;
1004: }
1005:
1006: IJavaElement childEl = getCurrentJavaElement();
1007: if (childEl == null && javaInput == null) {
1008: setInput(javaEditor);
1009: childEl = javaInput;
1010: }
1011:
1012: // after getCurrentJavaElement() call it is possible that java type is disappear
1013: // because corresponding type is not more exist in model
1014: if (javaInput == null) {
1015: deActivateView();
1016: return;
1017: }
1018:
1019: boolean clearOutput = false;
1020:
1021: if (inputChanged || isSelectedElementChanged(childEl)) {
1022:
1023: DecompiledClass result = decompileBytecode(childEl);
1024: if (result == null) {
1025: clearOutput = true;
1026: } else {
1027: if (modes.get(BCOConstants.F_SHOW_ANALYZER)
1028: && !result.isAbstractOrInterface()) {
1029: refreshVerifyView(result);
1030: } else {
1031: toggleVerifierAction.setEnabled(!result
1032: .isAbstractOrInterface());
1033: refreshTextView(result);
1034: }
1035: }
1036: lastDecompiledResult = result;
1037: } else if (childEl == null
1038: && modes.get(BCOConstants.F_SHOW_ONLY_SELECTED_ELEMENT)) {
1039: clearOutput = true;
1040: }
1041:
1042: lastChildElement = childEl;
1043: if (clearOutput) {
1044: if (!modes.get(BCOConstants.F_SHOW_ANALYZER)) {
1045: IDocument document = new Document("");
1046: textViewer.setDocument(document);
1047: } else {
1048: setVerifyTableItems(null);
1049: }
1050: }
1051: setSelectionInBytecodeView();
1052: inputChanged = false;
1053: }
1054:
1055: private void refreshTextView(DecompiledClass result) {
1056: IDocument document = new Document(result.getText());
1057: textViewer.setDocument(document);
1058: // we are in verify mode but we can't show content because
1059: // current element is abstract, so we clean table content
1060: if (modes.get(BCOConstants.F_SHOW_ANALYZER)) {
1061: setVerifyTableItems(null);
1062: }
1063: hasAnalyzerError = false;
1064: }
1065:
1066: private void refreshVerifyView(DecompiledClass result) {
1067: setVerifyTableItems(result.getTextTable());
1068: List errors = result.getErrorLines();
1069: if (errors.size() > 0) {
1070: // TODO this only changes color of status line -
1071: // but it is possible also to provide useful info here...
1072: hasAnalyzerError = true;
1073: // currentErrorMessage = ...
1074: }
1075: for (int i = 0; i < errors.size(); ++i) {
1076: int l = ((Integer) errors.get(i)).intValue();
1077: tableControl.getItem(l).setForeground(errorColor);
1078: }
1079: toggleVerifierAction.setEnabled(true);
1080: }
1081:
1082: /**
1083: * @param result
1084: */
1085: private void updateStatus(DecompiledClass result,
1086: int bytecodeOffsetStart, int bytecodeOffsetEnd) {
1087: // clear error messages, if any
1088: statusLineManager.setErrorMessage(null);
1089: if (result != null) {
1090: currentStatusMessage = "Java:"
1091: + result.getAttribute("java.version")
1092: + " | class size:"
1093: + result.getAttribute("class.size");
1094: } else {
1095: currentStatusMessage = "";
1096: }
1097: String selectionInfo = "";
1098: if (bytecodeOffsetStart >= 0) {
1099: selectionInfo = " | offset:" + bytecodeOffsetStart;
1100: if (bytecodeOffsetEnd >= 0) {
1101: selectionInfo += "-" + bytecodeOffsetEnd;
1102: }
1103: }
1104: if (hasAnalyzerError) {
1105: statusLineManager.setErrorMessage(currentStatusMessage
1106: + selectionInfo);
1107: } else {
1108: statusLineManager.setMessage(currentStatusMessage
1109: + selectionInfo);
1110: }
1111: }
1112:
1113: public int getBytecodeInstructionAtLine(int line) {
1114: if (lastDecompiledResult != null) {
1115: return lastDecompiledResult.getBytecodeInsn(line);
1116: }
1117: return -1;
1118: }
1119:
1120: /**
1121: * @return IJavaElement which fits in the current selection in java editor
1122: */
1123: private IJavaElement getCurrentJavaElement() {
1124: IJavaElement childEl = null;
1125: try {
1126: childEl = JdtUtils.getElementAtOffset(javaInput,
1127: currentSelection);
1128: if (childEl != null) {
1129: switch (childEl.getElementType()) {
1130: case IJavaElement.METHOD:
1131: case IJavaElement.FIELD:
1132: case IJavaElement.INITIALIZER:
1133: case IJavaElement.TYPE:
1134: break;
1135: case IJavaElement.LOCAL_VARIABLE:
1136: childEl = childEl.getAncestor(IJavaElement.METHOD);
1137: break;
1138: default:
1139: childEl = null;
1140: break;
1141: }
1142: }
1143: } catch (JavaModelException e) {
1144: // the exception is mostly occured if java structure was
1145: // changed and current element is not more exist in model
1146: // e.g. on rename/delete/move operation.
1147: // so it is not an error for user, but info for us
1148: BytecodeOutlinePlugin.log(e, IStatus.INFO);
1149: setJavaInput(null);
1150: lastChildElement = null;
1151: }
1152: return childEl;
1153: }
1154:
1155: private void setSelectionInBytecodeView() {
1156: if (lastDecompiledResult == null) {
1157: return;
1158: }
1159:
1160: if (currentSelection.getStartLine() != currentSelection
1161: .getEndLine()) {
1162: setMultiLineSelectionInBytecodeView(currentSelection);
1163: return;
1164: }
1165:
1166: int sourceLine = currentSelection.getStartLine() + 1;
1167: int decompiledLine = lastDecompiledResult
1168: .getDecompiledLine(sourceLine);
1169:
1170: if (decompiledLine < 0
1171: && !modes
1172: .get(BCOConstants.F_SHOW_ONLY_SELECTED_ELEMENT)
1173: && lastChildElement != null) {
1174: /*
1175: * May be this is the selection in outline view, if complete class is shown.
1176: * Because there are no bytecode instructions/offset for method name, we need
1177: * to find and select first method line. See cr 306011
1178: */
1179: DecompiledMethod match = lastDecompiledResult
1180: .getBestDecompiledMatch(sourceLine);
1181: if (match != null) {
1182: // this is relative to method start
1183: decompiledLine = match
1184: .getBestDecompiledLine(sourceLine);
1185: if (decompiledLine > 0) {
1186: // convert to class file relative
1187: decompiledLine = lastDecompiledResult
1188: .getDecompiledLine(match, decompiledLine);
1189: }
1190: }
1191: if (decompiledLine < 0) {
1192: String methodName = JdtUtils
1193: .getMethodSignature(lastChildElement);
1194: if (methodName != null) {
1195: decompiledLine = lastDecompiledResult
1196: .getDecompiledLine(methodName) - 1;
1197: }
1198: }
1199: }
1200:
1201: if (decompiledLine > 0) {
1202: try {
1203: if (modes.get(BCOConstants.F_SHOW_ANALYZER)) {
1204: updateVerifierControl(decompiledLine);
1205: } else {
1206: int lineCount = textControl.getLineCount();
1207: if (decompiledLine < lineCount) {
1208: int offsetAtLine = textControl
1209: .getOffsetAtLine(decompiledLine);
1210: int offsetEnd = textControl.getText().indexOf(
1211: '\n', offsetAtLine);
1212: textControl.setSelection(offsetAtLine,
1213: offsetEnd);
1214: }
1215: }
1216: } catch (IllegalArgumentException e) {
1217: BytecodeOutlinePlugin.error(null, e);
1218: }
1219: } else if (modes.get(BCOConstants.F_SHOW_ANALYZER)) {
1220: lvtTable.removeAll();
1221: stackTable.removeAll();
1222: }
1223: int bytecodeOffset = lastDecompiledResult
1224: .getBytecodeOffset(decompiledLine);
1225: updateStatus(lastDecompiledResult, bytecodeOffset, -1);
1226: }
1227:
1228: private void setMultiLineSelectionInBytecodeView(
1229: ITextSelection multiLineSelection) {
1230: LineRange range = lastDecompiledResult
1231: .getDecompiledRange(multiLineSelection);
1232: int firstDecompiledLine = range.startLine;
1233: if (firstDecompiledLine > 0) {
1234: try {
1235: if (modes.get(BCOConstants.F_SHOW_ANALYZER)) {
1236: updateVerifierControl(firstDecompiledLine);
1237: } else {
1238: int lineCount = textControl.getLineCount();
1239: if (firstDecompiledLine < lineCount) {
1240: int offsetAtLine = textControl
1241: .getOffsetAtLine(firstDecompiledLine);
1242: int offsetEnd;
1243: String text = textControl.getText();
1244: if (range.endLine > 0
1245: && range.endLine < lineCount) {
1246: offsetEnd = textControl
1247: .getOffsetAtLine(range.endLine);
1248: offsetEnd = text.indexOf("LINENUMBER", text
1249: .indexOf('\n', offsetEnd));
1250: if (offsetEnd < 0) {
1251: offsetEnd = text.indexOf('\n',
1252: offsetEnd);
1253: }
1254: } else {
1255: offsetEnd = text
1256: .indexOf('\n', offsetAtLine);
1257: }
1258: textControl.setSelection(offsetAtLine,
1259: offsetEnd);
1260: }
1261: }
1262: } catch (IllegalArgumentException e) {
1263: BytecodeOutlinePlugin.error(null, e);
1264: }
1265: } else if (modes.get(BCOConstants.F_SHOW_ANALYZER)) {
1266: lvtTable.removeAll();
1267: stackTable.removeAll();
1268: }
1269: int bytecodeOffsetStart = lastDecompiledResult
1270: .getBytecodeOffset(firstDecompiledLine);
1271: int bytecodeOffsetEnd = lastDecompiledResult
1272: .getBytecodeOffset(range.endLine);
1273: updateStatus(lastDecompiledResult, bytecodeOffsetStart,
1274: bytecodeOffsetEnd);
1275: }
1276:
1277: protected void updateVerifierControl(int decompiledLine) {
1278: lvtTable.removeAll();
1279: stackTable.removeAll();
1280: String[][][] frame = lastDecompiledResult.getFrameTables(
1281: decompiledLine, !modes
1282: .get(BCOConstants.F_SHOW_RAW_BYTECODE));
1283: if (frame != null) {
1284: for (int i = 0; i < frame[0].length; ++i) {
1285: if (frame[0][i] != null) {
1286: new TableItem(lvtTable, SWT.NONE)
1287: .setText(frame[0][i]);
1288: }
1289: }
1290: for (int i = 0; i < frame[1].length; ++i) {
1291: if (frame[1][i] != null) {
1292: new TableItem(stackTable, SWT.NONE)
1293: .setText(frame[1][i]);
1294: }
1295: }
1296:
1297: lvtTable.getColumn(0).pack();
1298: lvtTable.getColumn(1).pack();
1299: lvtTable.getColumn(2).pack();
1300: stackTable.getColumn(0).pack();
1301: stackTable.getColumn(1).pack();
1302:
1303: } else {
1304: // lvtControl.setText("");
1305: // stackControl.setText("");
1306: }
1307: tableControl.setSelection(decompiledLine);
1308: }
1309:
1310: protected void setSelectionInJavaEditor(Point selection) {
1311: if (javaEditor != null && javaEditor.getEditorInput() == null) {
1312: // editor was closed - we should clean the reference
1313: javaEditor = null;
1314: setJavaInput(null);
1315: }
1316: if (javaEditor == null || lastDecompiledResult == null) {
1317: deActivateView();
1318: return;
1319: }
1320:
1321: int startDecLine;
1322: int endDecLine = -1;
1323: if (modes.get(BCOConstants.F_SHOW_ANALYZER)) {
1324: startDecLine = tableControl.getSelectionIndex();
1325: } else {
1326: startDecLine = textControl.getLineAtOffset(selection.x);
1327: endDecLine = textControl.getLineAtOffset(selection.y);
1328: }
1329: int startSourceLine = lastDecompiledResult
1330: .getSourceLine(startDecLine);
1331: int endSourceLine = -1;
1332: if (endDecLine > 0) {
1333: endSourceLine = lastDecompiledResult
1334: .getSourceLine(endDecLine);
1335: }
1336:
1337: if (endSourceLine < startSourceLine) {
1338: int tmp = startSourceLine;
1339: startSourceLine = endSourceLine;
1340: endSourceLine = tmp;
1341: }
1342:
1343: try {
1344: if (startSourceLine > 0) {
1345: IDocument document = javaEditor.getDocumentProvider()
1346: .getDocument(javaEditor.getEditorInput());
1347: try {
1348: IRegion lineInfo = document
1349: .getLineInformation(startSourceLine - 1);
1350:
1351: int startOffset = lineInfo.getOffset();
1352: int length = lineInfo.getLength();
1353: if (endSourceLine > 0) {
1354: IRegion region = document
1355: .getLineInformation(endSourceLine - 1);
1356: length = region.getLength()
1357: + (region.getOffset() - startOffset);
1358: }
1359: EclipseUtils.selectInEditor(javaEditor,
1360: startOffset, length);
1361: } catch (BadLocationException e) {
1362: // do nothing. This could happens e.g. if editor does not contain
1363: // full source code etc, so that line info is not exist in editor
1364: }
1365: }
1366: } catch (Exception e) {
1367: BytecodeOutlinePlugin.log(e, IStatus.ERROR);
1368: }
1369:
1370: int bytecodeOffset = lastDecompiledResult
1371: .getBytecodeOffset(startDecLine);
1372: updateStatus(lastDecompiledResult, bytecodeOffset, -1);
1373: }
1374:
1375: // ------------------------------------------------------------------------
1376:
1377: /**
1378: * check if at least one java editor is open - if not, deactivate me
1379: * @param checkNewSelection
1380: */
1381: protected void checkOpenEditors(boolean checkNewSelection) {
1382: IEditorReference[] editorReferences = getSite().getPage()
1383: .getEditorReferences();
1384: if (editorReferences == null || editorReferences.length == 0) {
1385: deActivateView();
1386: } else if (checkNewSelection) {
1387: IEditorPart activeEditor = EclipseUtils.getActiveEditor();
1388: if (activeEditor instanceof ITextEditor) {
1389: ITextSelection selection = EclipseUtils
1390: .getSelection(((ITextEditor) activeEditor)
1391: .getSelectionProvider());
1392: handleSelectionChanged(activeEditor, selection);
1393: } else {
1394: deActivateView();
1395: }
1396: }
1397: }
1398:
1399: /**
1400: * @param childEl
1401: * @return true if java element selection was changed (means, that previous selection
1402: * do not match to the given element)
1403: */
1404: private boolean isSelectedElementChanged(IJavaElement childEl) {
1405:
1406: if (lastChildElement == null && childEl == null) {
1407: // no selected child before - and no new selection now => no changes
1408: return false;
1409: }
1410:
1411: if (modes.get(BCOConstants.F_SHOW_ONLY_SELECTED_ELEMENT)) {
1412: if (lastChildElement == null
1413: || (lastChildElement != null && !lastChildElement
1414: .equals(childEl))) {
1415: return true;
1416: }
1417: }
1418:
1419: /*
1420: * the check if we changed from inner class to outer class or vice versa
1421: */
1422: if (lastChildElement != null && childEl != null) {
1423: IType newEnclosingType = JdtUtils.getEnclosingType(childEl);
1424: IType oldEnclosingType = JdtUtils
1425: .getEnclosingType(lastChildElement);
1426: return newEnclosingType == null
1427: || !newEnclosingType.equals(oldEnclosingType);
1428: }
1429: return false;
1430: }
1431:
1432: /**
1433: * @param childEl
1434: * @return return null if type is not known or bytecode is not written or cannot be
1435: * found
1436: */
1437: private DecompiledClass decompileBytecode(IJavaElement childEl) {
1438: // check here for inner classes too
1439: IJavaElement type = JdtUtils.getEnclosingType(childEl);
1440: if (type == null) {
1441: type = javaInput;
1442: }
1443: if (type == null) {
1444: return null;
1445: }
1446: InputStream is = JdtUtils.createInputStream(type);
1447: if (is == null) {
1448: return null;
1449: }
1450: DecompiledClass decompiledClass = null;
1451: int available = 0;
1452: try {
1453: ClassLoader cl = null;
1454: if (modes.get(BCOConstants.F_SHOW_ANALYZER)) {
1455: cl = JdtUtils.getClassLoader(type);
1456: }
1457:
1458: String fieldName = null;
1459: String methodName = null;
1460: /*
1461: * find out, which name we should use for selected element
1462: */
1463: if (modes.get(BCOConstants.F_SHOW_ONLY_SELECTED_ELEMENT)
1464: && childEl != null) {
1465: if (childEl.getElementType() == IJavaElement.FIELD) {
1466: fieldName = childEl.getElementName();
1467: } else {
1468: methodName = JdtUtils.getMethodSignature(childEl);
1469: }
1470: }
1471: available = is.available();
1472: decompiledClass = DecompilerClassVisitor
1473: .getDecompiledClass(is, fieldName, methodName,
1474: modes, cl);
1475: } catch (Exception e) {
1476: try {
1477: // check if compilation unit is ok - then this is the user problem
1478: if (type.isStructureKnown()) {
1479: BytecodeOutlinePlugin.error("Cannot decompile: "
1480: + type, e);
1481: } else {
1482: BytecodeOutlinePlugin.log(e, IStatus.ERROR);
1483: }
1484: } catch (JavaModelException e1) {
1485: // this is compilation problem - don't show the message
1486: BytecodeOutlinePlugin.log(e1, IStatus.WARNING);
1487: }
1488: } catch (UnsupportedClassVersionError e) {
1489: BytecodeOutlinePlugin
1490: .error(
1491: "Cannot decompile: "
1492: + type
1493: + ". Error was caused by attempt to "
1494: + "load a class compiled with the Java version which is not "
1495: + "supported by the current JVM. ",
1496: e);
1497: } finally {
1498: try {
1499: is.close();
1500: } catch (IOException e) {
1501: BytecodeOutlinePlugin.log(e, IStatus.WARNING);
1502: }
1503: }
1504: // remember class file size to show it later in UI
1505: if (decompiledClass != null) {
1506: decompiledClass.setAttribute(
1507: DecompiledClass.ATTR_CLAS_SIZE, "" + available);
1508: }
1509: return decompiledClass;
1510: }
1511:
1512: private void setVerifyTableItems(String[][] items) {
1513: tableControl.removeAll();
1514: if (items != null) {
1515: for (int i = 0; i < items.length; ++i) {
1516: TableItem item = new TableItem(tableControl, SWT.NONE);
1517: for (int j = 0; j < items[i].length; ++j) {
1518: String s = items[i][j];
1519: if (s.endsWith("\n")) {
1520: s = s.substring(0, s.length() - 1);
1521: // this is the "cookie" for the bytecode reference, which could be
1522: // mapped later to the sourcecode line on selection event in the
1523: // table
1524: item.setData(new Integer(i));
1525: }
1526: item.setText(j, s);
1527: }
1528: }
1529: tableControl.getColumn(0).pack();
1530: tableControl.getColumn(1).pack();
1531: tableControl.getColumn(2).pack();
1532: tableControl.getColumn(3).pack();
1533: }
1534: }
1535:
1536: public Object getAdapter(Class adapter) {
1537: if (IFindReplaceTarget.class.equals(adapter)) {
1538: return textViewer.getFindReplaceTarget();
1539: }
1540: if (Widget.class.equals(adapter)) {
1541: return textViewer.getTextWidget();
1542: }
1543: if (TextViewer.class.equals(adapter)) {
1544: return textViewer;
1545: }
1546: return super .getAdapter(adapter);
1547: }
1548:
1549: /**
1550: * Configures an action for key bindings.
1551: * @param actionBars action bars for this page
1552: * @param actionID action definition id
1553: * @param action associated action
1554: */
1555: protected void setGlobalAction(IActionBars actionBars,
1556: String actionID, IAction action) {
1557: globalActions.put(actionID, action);
1558: actionBars.setGlobalActionHandler(actionID, action);
1559: }
1560:
1561: /**
1562: * Updates the global action with the given id
1563: * @param actionId action definition id
1564: */
1565: protected void updateAction(String actionId) {
1566: IAction action = (IAction) globalActions.get(actionId);
1567: if (action instanceof IUpdate) {
1568: ((IUpdate) action).update();
1569: }
1570: }
1571:
1572: protected void createTextActions() {
1573: IActionBars actionBars = getViewSite().getActionBars();
1574: TextViewerAction action = new TextViewerAction(textViewer,
1575: ITextOperationTarget.SELECT_ALL);
1576:
1577: action.configureAction(BytecodeOutlinePlugin
1578: .getResourceString(NLS_PREFIX + "select_all.label"),
1579: BytecodeOutlinePlugin.getResourceString(NLS_PREFIX
1580: + "select_all.tooltip"), BytecodeOutlinePlugin
1581: .getResourceString(NLS_PREFIX
1582: + "select_all.description"));
1583: setGlobalAction(actionBars, ActionFactory.SELECT_ALL.getId(),
1584: action);
1585:
1586: action = new TextViewerAction(textViewer,
1587: ITextOperationTarget.COPY);
1588: action.configureAction(BytecodeOutlinePlugin
1589: .getResourceString(NLS_PREFIX + "copy.label"),
1590: BytecodeOutlinePlugin.getResourceString(NLS_PREFIX
1591: + "copy.tooltip"), BytecodeOutlinePlugin
1592: .getResourceString(NLS_PREFIX
1593: + "copy.description"));
1594: action.setImageDescriptor(PlatformUI.getWorkbench()
1595: .getSharedImages().getImageDescriptor(
1596: ISharedImages.IMG_TOOL_COPY));
1597: action
1598: .setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY);
1599: setGlobalAction(actionBars, ActionFactory.COPY.getId(), action);
1600:
1601: ResourceBundle bundle = BytecodeOutlinePlugin.getDefault()
1602: .getResourceBundle();
1603:
1604: setGlobalAction(actionBars, ActionFactory.FIND.getId(),
1605: new FindReplaceAction(bundle, NLS_PREFIX
1606: + "find_replace.", this )); //$NON-NLS-1$
1607:
1608: selectionActions.add(ActionFactory.COPY.getId());
1609: selectionActions.add(ActionFactory.FIND.getId());
1610:
1611: actionBars.updateActionBars();
1612: }
1613:
1614: // orientation
1615:
1616: private void setOrientation(int orientation) {
1617: if (verifyControl == null || verifyControl.isDisposed()) {
1618: return;
1619: }
1620:
1621: boolean horizontal = orientation == VIEW_ORIENTATION_HORIZONTAL;
1622: verifyControl.setOrientation(horizontal ? SWT.HORIZONTAL
1623: : SWT.VERTICAL);
1624:
1625: for (int i = 0; i < toggleOrientationActions.length; ++i) {
1626: toggleOrientationActions[i]
1627: .setChecked(orientation == toggleOrientationActions[i]
1628: .getOrientation());
1629: }
1630:
1631: currentOrientation = orientation;
1632: // GridLayout layout= (GridLayout) fCounterComposite.getLayout();
1633: // setCounterColumns(layout);
1634: stackComposite.getParent().layout();
1635: }
1636:
1637: protected void computeOrientation() {
1638: if (orientation != VIEW_ORIENTATION_AUTOMATIC) {
1639: currentOrientation = orientation;
1640: setOrientation(currentOrientation);
1641: } else {
1642: Point size = stackComposite.getParent().getSize();
1643: if (size.x != 0 && size.y != 0) {
1644: setOrientation(size.x > size.y ? VIEW_ORIENTATION_HORIZONTAL
1645: : VIEW_ORIENTATION_VERTICAL);
1646: }
1647: }
1648: }
1649:
1650: /**
1651: * Set the bit with given index to given value and remembers it in the preferences
1652: * @param bitIndex
1653: * @param value
1654: */
1655: protected void setMode(int bitIndex, boolean value) {
1656: modes.set(bitIndex, value);
1657: }
1658:
1659: protected void toggleVerifyMode(final IMenuManager mmanager,
1660: boolean showAnalyzer) {
1661: setMode(BCOConstants.F_SHOW_ANALYZER, showAnalyzer);
1662: if (modes.get(BCOConstants.F_SHOW_ANALYZER)) {
1663: ((StackLayout) stackComposite.getLayout()).topControl = verifyControl;
1664: viewSelectionProvider
1665: .setCurrentSelectionProvider(tableControlViewer);
1666: } else {
1667: ((StackLayout) stackComposite.getLayout()).topControl = textControl;
1668: viewSelectionProvider
1669: .setCurrentSelectionProvider(textViewer);
1670: }
1671: stackComposite.layout();
1672:
1673: for (int i = 0; i < toggleOrientationActions.length; ++i) {
1674: toggleOrientationActions[i].setEnabled(showAnalyzer);
1675: }
1676: mmanager.markDirty();
1677: mmanager.update();
1678: }
1679:
1680: private class ToggleOrientationAction extends Action {
1681:
1682: private final int actionOrientation;
1683:
1684: public ToggleOrientationAction(BytecodeOutlineView v,
1685: int orientation) {
1686: super ("", AS_RADIO_BUTTON); //$NON-NLS-1$
1687:
1688: String symbolicName = BytecodeOutlinePlugin.getDefault()
1689: .getBundle().getSymbolicName();
1690: if (orientation == VIEW_ORIENTATION_HORIZONTAL) {
1691: setText(BytecodeOutlinePlugin
1692: .getResourceString(NLS_PREFIX
1693: + "toggle.horizontal.label")); //$NON-NLS-1$
1694: setImageDescriptor(AbstractUIPlugin
1695: .imageDescriptorFromPlugin(symbolicName,
1696: "icons/th_horizontal.gif")); //$NON-NLS-1$
1697: } else if (orientation == VIEW_ORIENTATION_VERTICAL) {
1698: setText(BytecodeOutlinePlugin
1699: .getResourceString(NLS_PREFIX
1700: + "toggle.vertical.label")); //$NON-NLS-1$
1701: setImageDescriptor(AbstractUIPlugin
1702: .imageDescriptorFromPlugin(symbolicName,
1703: "icons/th_vertical.gif")); //$NON-NLS-1$
1704: } else if (orientation == VIEW_ORIENTATION_AUTOMATIC) {
1705: setText(BytecodeOutlinePlugin
1706: .getResourceString(NLS_PREFIX
1707: + "toggle.automatic.label")); //$NON-NLS-1$
1708: setImageDescriptor(AbstractUIPlugin
1709: .imageDescriptorFromPlugin(symbolicName,
1710: "icons/th_automatic.gif")); //$NON-NLS-1$
1711: }
1712: actionOrientation = orientation;
1713: // WorkbenchHelp.setHelp(this,
1714: // IJUnitHelpContextIds.RESULTS_VIEW_TOGGLE_ORIENTATION_ACTION);
1715: }
1716:
1717: public int getOrientation() {
1718: return actionOrientation;
1719: }
1720:
1721: public void run() {
1722: if (isChecked()) {
1723: orientation = actionOrientation;
1724: computeOrientation();
1725: }
1726: }
1727: }
1728:
1729: }
|