com.drgarbage.bytecodevisualizer.view.OperandStackViewPage.java Source code

Java tutorial

Introduction

Here is the source code for com.drgarbage.bytecodevisualizer.view.OperandStackViewPage.java

Source

/**
 * Copyright (c) 2008-2013, Dr. Garbage Community
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.drgarbage.bytecodevisualizer.view;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.part.Page;

import com.drgarbage.asm.Opcodes;
import com.drgarbage.asm.render.intf.IClassFileDocument;
import com.drgarbage.asm.render.intf.IInstructionLine;
import com.drgarbage.asm.render.intf.IMethodSection;
import com.drgarbage.bytecode.ByteCodeConstants;
import com.drgarbage.bytecodevisualizer.BytecodeVisualizerMessages;
import com.drgarbage.bytecodevisualizer.editors.BytecodeDocumentProvider;
import com.drgarbage.bytecodevisualizer.editors.BytecodeEditor;
import com.drgarbage.bytecodevisualizer.editors.IClassFileEditorSelectionListener;
import com.drgarbage.bytecodevisualizer.operandstack.OperandStack;
import com.drgarbage.bytecodevisualizer.operandstack.OperandStack.NodeStackProperty;
import com.drgarbage.bytecodevisualizer.operandstack.OperandStack.OperandStackPropertyConstants;
import com.drgarbage.bytecodevisualizer.operandstack.OperandStack.OpstackRepresenation;
import com.drgarbage.bytecodevisualizer.operandstack.OperandStackAnalysis;
import com.drgarbage.controlflowgraph.ControlFlowGraphUtils;
import com.drgarbage.controlflowgraph.intf.INodeExt;
import com.drgarbage.controlflowgraph.intf.INodeListExt;
import com.drgarbage.controlflowgraph.intf.INodeType;
import com.drgarbage.core.CoreMessages;
import com.drgarbage.core.img.CoreImg;
import com.drgarbage.javasrc.JavaLexicalConstants;

/**
 * The abstract Operand Stack View Page.
 * 
 * @author Sergej Alekseev
 * @version $Revision$
 * $Id$
 */
public abstract class OperandStackViewPage extends Page {

    /**
     * Tree Viewer of the OperandStack view Page.
     */
    private TreeViewer treeViewer;

    /**
     * Tree Column of the OperandStack view.
     */
    private TreeColumn column, column3, column4, column5, column6;

    /**
     * Reference to the selected method instance.
     */
    private IMethodSection methodInput;

    /**
     * reference to the operand stack.
     */
    private OperandStack operandStack;

    /* Menu actions */
    private IAction showTreeViewAction, showBasicBlockViewAction, showInstructioneListViewAction,
            showOSBeforeColumnAction, showOSAfterColumnAction, showDescriptionColumnAction, showOSDepthColumnAction,
            displayAllAction, displaySimpleAction, displayTypesAction, displayValuesAction, showAnalyseReportAction;

    static enum OperandStackView_ID {
        TREE_VIEW, BASICBKLOCK_VIEW, INSTR_LIST_VIEW;
    };

    /**
     * Kind of the view. The value is one of the  REE_VIEW, 
     * BASICBKLOCK_VIEW or INSTR_LIST_VIEW.
     */
    OperandStackView_ID view_ID = OperandStackView_ID.TREE_VIEW;

    static enum OperandStackDisplayFormat_ID {
        DISPLAY_SIMPLE, DISPLAY_TYPES, DISPLAY_VALUES, DISPLAY_ALL
    };

    static enum ColumnIndex {
        OFFSET(0), OPCODEMNEMONIC(1), OPSTACKBEFORE(2), OPSTACKAFTER(3), OPSTACKDEPTH(4), DESCRIPTION(5);

        private final int INDEX;

        private ColumnIndex(int INDEX) {
            this.INDEX = INDEX;
        }

        public int getIndex() {
            return INDEX;
        }

    };

    public static Color RED = new Color(null, 255, 0, 0);
    public static Color ORANGE = new Color(null, 255, 127, 0);
    public static Color GREEN = new Color(null, 50, 205, 50);
    public static Color BLUE = new Color(null, 120, 178, 255);

    /**
     * Default presentation format is SIMPLE
     */
    private OpstackRepresenation opstackRepresenationFormat = OpstackRepresenation.SIMPLE;

    /**
     * The standard value for displaying all information in 2 columns "Operand Stack before" and "Operand Stack after"
     */
    OperandStackDisplayFormat_ID displayFormat_ID = OperandStackDisplayFormat_ID.DISPLAY_ALL;

    /**
     * Map of the tree items to the byte code line numbers in the editor.
     */
    private Map<Integer, Node> treeMap;

    /**
     * Listener for synchronization of lines with the BCV.
     */
    private IClassFileEditorSelectionListener classFileEditorSelectionListener;

    /**
     * Use the mutex variable to avoid call backs from the editor view. 
     */
    private boolean treeViewerSelectionMutex = false;

    /**
     * Reference to the active byte code editor.
     */
    private BytecodeEditor editor;

    private synchronized boolean isTreeViewerSelectionMutex() {
        return treeViewerSelectionMutex;
    }

    private synchronized void setTreeViewerSelectionMutex(boolean b) {
        treeViewerSelectionMutex = b;
    }

    /**
     * Constructs an outline.
     */
    public OperandStackViewPage() {
        super();
    }

    /**
     * Returns the TreeTable view object.
     * @return treeView
     */
    public TreeViewer getTreeView() {
        return treeViewer;

    }

    /**
     * Returns the current view id, one of the REE_VIEW, BASICBKLOCK_VIEW, INSTR_LIST_VIEW. 
     * @return view_ID
     */
    public OperandStackView_ID getView_ID() {
        return view_ID;
    }

    /**
     * Sets the view id, one of the REE_VIEW, BASICBKLOCK_VIEW, INSTR_LIST_VIEW.
     * @param view_ID
     */
    public void setView_ID(OperandStackView_ID view_ID) {
        this.view_ID = view_ID;
    }

    /**
     * Returns the current displayFormat id, one of the 
     * <code>DISPLAY_ALL</code>, 
     * <code>DISPLAY_SIMPLE</code>, 
     * <code>DISPLAY_TYPES</code> or
     * <code>DISPLAY_VALUES</code>
     * 
     * @return displayFormat_ID
     */
    public OperandStackDisplayFormat_ID getDisplayFormat_ID() {
        return displayFormat_ID;
    }

    /**
     * Sets the display format id, one of the 
     * <code>DISPLAY_ALL</code>, 
     * <code>DISPLAY_SIMPLE</code>, 
     * <code>DISPLAY_TYPES</code> or
     * <code>DISPLAY_VALUES</code>
     * 
     * @param displayFormat_ID
     */
    public void setDisplayFormat_ID(OperandStackDisplayFormat_ID displayFormat_ID) {
        this.displayFormat_ID = displayFormat_ID;
    }

    private void setMesssageInStatusLine() {
        if (methodInput == null) {
            return;
        }

        IActionBars bars = getSite().getActionBars();

        IStatusLineManager slm = bars.getStatusLineManager();

        /* 
         * DO NOT DELETE THIS LINE. 
         * This is probably a bug in the StatusLineManeger implementation.
         * The setMessage() is first visible if the error message has 
         * been cleaned by the setErrorMessage(""); 
         */
        slm.setErrorMessage("");

        if (operandStack.getMaxStackSize() > methodInput.getMaxStack()) {

            StringBuffer buf = new StringBuffer();
            buf.append(CoreMessages.Error);
            buf.append(JavaLexicalConstants.COLON);
            buf.append(JavaLexicalConstants.SPACE);
            buf.append(BytecodeVisualizerMessages.OperandStackAnalysis_Error_StackOverflow);
            buf.append(JavaLexicalConstants.COMMA);
            buf.append(JavaLexicalConstants.SPACE);
            buf.append("max_stack is "); //$NON-NLS-1$
            buf.append(methodInput.getMaxStack());
            buf.append(", calculated max stack size is "); //$NON-NLS-1$
            buf.append(operandStack.getMaxStackSize());
            buf.append(JavaLexicalConstants.DOT);

            slm.setErrorMessage(
                    PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK),
                    buf.toString());
        } else if (operandStack.getMaxStackSize() < methodInput.getMaxStack()) {
            StringBuffer buf = new StringBuffer();
            buf.append(CoreMessages.Warning);
            buf.append(JavaLexicalConstants.COLON);
            buf.append(JavaLexicalConstants.SPACE);
            buf.append(BytecodeVisualizerMessages.OperandStackAnalysis_Warning_StackUnderflow);
            buf.append(JavaLexicalConstants.COMMA);
            buf.append(JavaLexicalConstants.SPACE);
            buf.append("max_stack is "); //$NON-NLS-1$
            buf.append(methodInput.getMaxStack());
            buf.append(", calculated max stack size is "); //$NON-NLS-1$
            buf.append(operandStack.getMaxStackSize());
            buf.append(JavaLexicalConstants.DOT);

            slm.setMessage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_WARN_TSK),
                    buf.toString());
        } else {
            StringBuffer buf = new StringBuffer();
            buf.append("max_stack: "); //$NON-NLS-1$
            buf.append(methodInput.getMaxStack());
            buf.append(", max_locals: "); //$NON-NLS-1$
            buf.append(methodInput.getMaxLocals());

            slm.setMessage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_INFO_TSK),
                    buf.toString());
        }

        slm.update(true);
    }

    private void configureToolBar() {

        IActionBars bars = getSite().getActionBars();
        IToolBarManager tbm = bars.getToolBarManager();

        showTreeViewAction = new Action() {
            public void run() {
                activateView(OperandStackView_ID.TREE_VIEW);
            }
        };
        showTreeViewAction.setImageDescriptor(CoreImg.bytecodeViewIcon_16x16);
        tbm.add(showTreeViewAction);
        showTreeViewAction.setText(BytecodeVisualizerMessages.TreeViewAction_Text);
        showTreeViewAction.setToolTipText(BytecodeVisualizerMessages.TreeViewAction_Text);
        showTreeViewAction.setChecked(true);

        showBasicBlockViewAction = new Action() {
            public void run() {
                activateView(OperandStackView_ID.BASICBKLOCK_VIEW);
            }
        };
        showBasicBlockViewAction.setImageDescriptor(CoreImg.basicblockViewIcon_16x16);
        tbm.add(showBasicBlockViewAction);
        showBasicBlockViewAction.setText(BytecodeVisualizerMessages.BasicViewAction_Text);
        showBasicBlockViewAction.setToolTipText(BytecodeVisualizerMessages.BasicViewAction_Text);
        showBasicBlockViewAction.setChecked(false);

        showInstructioneListViewAction = new Action() {
            public void run() {
                activateView(OperandStackView_ID.INSTR_LIST_VIEW);
            }
        };
        showInstructioneListViewAction.setImageDescriptor(CoreImg.bytecode_listview_16x16);
        showInstructioneListViewAction.setText(BytecodeVisualizerMessages.InstructionListView_Text);
        showInstructioneListViewAction.setToolTipText(BytecodeVisualizerMessages.InstructionListView_Text);
        tbm.add(showInstructioneListViewAction);
        showInstructioneListViewAction.setChecked(false);

        enableActions(false);

        showAnalyseReportAction = new Action() {
            public void run() {
                OperandStackReportDialog analyseReport = new OperandStackReportDialog();
                analyseReport.setText(OperandStackAnalysis.executeAll(operandStack, methodInput));
                analyseReport.open();
            }
        };

        showAnalyseReportAction.setImageDescriptor(
                PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FILE));
        showAnalyseReportAction.setText(BytecodeVisualizerMessages.OpenOpstackAnalyseAction_Text);
        showAnalyseReportAction.setToolTipText(BytecodeVisualizerMessages.OpenOpstackAnalyseAction_Tooltip);

        tbm.add(new Separator());
        tbm.add(showAnalyseReportAction);

        tbm.update(true);

        /* menu */
        final IMenuManager imb = bars.getMenuManager();

        /* submenu */
        MenuManager subMenuViewLayout = new MenuManager(BytecodeVisualizerMessages.subMenuViewLayout_Text, null);
        final MenuManager subMenuShowColumn = new MenuManager(BytecodeVisualizerMessages.subMenuShowColumn_Text,
                null);
        final MenuManager subMenuFormat = new MenuManager(BytecodeVisualizerMessages.subMenuFormat_Text, null);

        imb.add(subMenuViewLayout);
        imb.add(subMenuShowColumn);
        imb.add(subMenuFormat);
        imb.add(new Separator());
        imb.add(showAnalyseReportAction);

        subMenuViewLayout.add(showTreeViewAction);
        subMenuViewLayout.add(showBasicBlockViewAction);
        subMenuViewLayout.add(showInstructioneListViewAction);

        showOSBeforeColumnAction = new Action() {
            public void run() {
                if (column3.getWidth() == 0) {
                    column3.setWidth(100);
                    column3.setResizable(true);
                    setChecked(true);
                } else {
                    column3.setWidth(0);
                    column3.setResizable(false);
                    setChecked(false);
                }
                subMenuShowColumn.update(true);
            }
        };
        showOSBeforeColumnAction.setText(BytecodeVisualizerMessages.OpstackBeforeColumnName);

        showOSAfterColumnAction = new Action() {
            public void run() {
                if (column4.getWidth() == 0) {
                    column4.setWidth(100);
                    column4.setResizable(true);
                    setChecked(true);
                } else {
                    column4.setWidth(0);
                    column4.setResizable(false);
                    setChecked(false);
                }
                subMenuShowColumn.update(true);
            }
        };
        showOSAfterColumnAction.setText(BytecodeVisualizerMessages.OpstackAfterColumnName);

        showOSDepthColumnAction = new Action() {
            public void run() {
                if (column5.getWidth() == 0) {
                    column5.setWidth(40);
                    column5.setResizable(true);
                    setChecked(true);
                } else {
                    column5.setWidth(0);
                    column5.setResizable(false);
                    setChecked(false);
                }
                subMenuShowColumn.update(true);
            }
        };
        showOSDepthColumnAction.setText(BytecodeVisualizerMessages.OpstackDepthColumnName);

        showDescriptionColumnAction = new Action() {
            public void run() {
                if (column6.getWidth() == 0) {
                    column6.setWidth(100);
                    column6.setResizable(true);
                    setChecked(true);
                } else {
                    column6.setWidth(0);
                    column6.setResizable(false);
                    setChecked(false);
                }
                subMenuShowColumn.update(true);
            }
        };
        showDescriptionColumnAction.setText(BytecodeVisualizerMessages.OpstackDescriptionColumnName);

        showOSBeforeColumnAction.setChecked(true);
        showOSAfterColumnAction.setChecked(true);
        showOSDepthColumnAction.setChecked(true);

        subMenuShowColumn.add(showOSBeforeColumnAction);
        subMenuShowColumn.add(showOSAfterColumnAction);
        subMenuShowColumn.add(showOSDepthColumnAction);
        subMenuShowColumn.add(showDescriptionColumnAction);

        displaySimpleAction = new Action() {
            public void run() {
                opstackRepresenationFormat = OpstackRepresenation.SIMPLE;
                activateDisplayFormat(OperandStackDisplayFormat_ID.DISPLAY_SIMPLE);
                subMenuFormat.update(true);
            }

            public String getText() {
                return BytecodeVisualizerMessages.DisplayFormatSIMPLE;
            }
        };
        displaySimpleAction.setChecked(true);

        displayAllAction = new Action() {
            public void run() {
                opstackRepresenationFormat = OpstackRepresenation.ALL;
                activateDisplayFormat(OperandStackDisplayFormat_ID.DISPLAY_ALL);
                subMenuFormat.update(true);
            }

            public String getText() {
                return BytecodeVisualizerMessages.DisplayFormatALL;
            }
        };
        displayAllAction.setChecked(false);

        displayValuesAction = new Action() {
            public void run() {
                opstackRepresenationFormat = OpstackRepresenation.VALUES;
                activateDisplayFormat(OperandStackDisplayFormat_ID.DISPLAY_VALUES);
                subMenuFormat.update(true);
            }

            public String getText() {
                return BytecodeVisualizerMessages.DisplayFormatVALUES;
            }
        };
        displayValuesAction.setChecked(false);

        displayTypesAction = new Action() {
            public void run() {
                opstackRepresenationFormat = OpstackRepresenation.TYPES;
                activateDisplayFormat(OperandStackDisplayFormat_ID.DISPLAY_TYPES);
                subMenuFormat.update(true);
            }

            public String getText() {
                return BytecodeVisualizerMessages.DisplayFormatTYPES;
            }
        };
        displayTypesAction.setChecked(false);

        subMenuFormat.add(displaySimpleAction);
        subMenuFormat.add(displayTypesAction);
        subMenuFormat.add(displayValuesAction);
        subMenuFormat.add(displayAllAction);

    }

    /**
     * Enables or disables the actions.
     * @param b true or false
     */
    private void enableActions(boolean b) {
        showTreeViewAction.setEnabled(b);
        showBasicBlockViewAction.setEnabled(b);
        showInstructioneListViewAction.setEnabled(b);
    }

    /**
     * Activates selected view
     * @param id - id of the view
     */
    private void activateView(OperandStackView_ID id) {

        if (id == OperandStackView_ID.TREE_VIEW) {
            showTreeViewAction.setChecked(true);
            showBasicBlockViewAction.setChecked(false);
            showInstructioneListViewAction.setChecked(false);
        } else if (id == OperandStackView_ID.BASICBKLOCK_VIEW) {
            showTreeViewAction.setChecked(false);
            showBasicBlockViewAction.setChecked(true);
            showInstructioneListViewAction.setChecked(false);
        } else if (id == OperandStackView_ID.INSTR_LIST_VIEW) {
            showTreeViewAction.setChecked(false);
            showBasicBlockViewAction.setChecked(false);
            showInstructioneListViewAction.setChecked(true);
        }

        /* update input */
        if (methodInput != null) {
            setView_ID(id);
            setInput(methodInput.getInstructionLines());
        }
    }

    /**
     * Activates selected Display Format
     * @param id - id of the format
     */
    private void activateDisplayFormat(OperandStackDisplayFormat_ID id) {

        if (id == OperandStackDisplayFormat_ID.DISPLAY_ALL) {
            displayAllAction.setChecked(true);
            displaySimpleAction.setChecked(false);
            displayValuesAction.setChecked(false);
            displayTypesAction.setChecked(false);
        } else if (id == OperandStackDisplayFormat_ID.DISPLAY_SIMPLE) {
            displayAllAction.setChecked(false);
            displaySimpleAction.setChecked(true);
            displayValuesAction.setChecked(false);
            displayTypesAction.setChecked(false);
        } else if (id == OperandStackDisplayFormat_ID.DISPLAY_VALUES) {
            displayAllAction.setChecked(false);
            displaySimpleAction.setChecked(false);
            displayValuesAction.setChecked(true);
            displayTypesAction.setChecked(false);
        } else if (id == OperandStackDisplayFormat_ID.DISPLAY_TYPES) {
            displayAllAction.setChecked(false);
            displaySimpleAction.setChecked(false);
            displayValuesAction.setChecked(false);
            displayTypesAction.setChecked(true);
        }

        /* update input */
        if (methodInput != null) {
            setDisplayFormat_ID(id);
            setInput(methodInput.getInstructionLines());
        }
    }

    /**
     * Sets the input - the list of the byte code instructions
     * for the table Viewer. 
     * @param m the method section object
     * @see IMethodSection
     */
    public void setInput(IMethodSection m) {
        if (m == null && methodInput == null) {
            return;
        }

        if (m != null && m.isAbstract()) {
            return;
        }

        if (m != null && m.equals(methodInput)) {
            return;
        }

        methodInput = m;

        if (methodInput == null) {
            enableActions(false);
            getTreeView().setInput(null);
        } else {
            setInput(methodInput.getInstructionLines());
            enableActions(true);
        }

        setMesssageInStatusLine();
    }

    /**
     * Set the reference to the active byte code editor.
     * @param editor byte code editor
     */
    public void setEditor(BytecodeEditor editor) {
        this.editor = editor;

        /* Synchronize tree selection with lines in the editor */
        classFileEditorSelectionListener = new IClassFileEditorSelectionListener() {

            /* (non-Javadoc)
             * @see com.drgarbage.bytecodevisualizer.editors.IClassFileEditorSelectionListener#lineSelectionChanged(int, java.lang.Object)
             */
            public void lineSelectionChanged(int newLine, Object o) {
                if (isTreeViewerSelectionMutex()) {
                    setTreeViewerSelectionMutex(false);
                    return;
                }

                if (treeMap == null) {
                    return;
                }

                Node node = treeMap.get(newLine);
                if (node != null) {
                    treeViewer.expandToLevel(node, 1);
                    Widget w = treeViewer.testFindItem(node);
                    if (w != null) {
                        TreeItem t = (TreeItem) w;
                        treeViewer.getTree().select(t);
                        treeViewer.refresh(true);
                    }
                }
            }
        };
        editor.addtLineSelectionListener(classFileEditorSelectionListener);

    }

    /* (non-Javadoc)
     * Method declared on Page
     */
    public void init(IPageSite pageSite) {
        super.init(pageSite);
        configureToolBar();
    }

    /*
     * @see IPage#createControl
     */
    public void createControl(Composite parent) {
        createTreeViewer(parent);
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.part.Page#dispose()
     */
    public void dispose() {
        super.dispose();
        treeViewer = null;
        editor.removeLineSelectionListener(classFileEditorSelectionListener);
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.part.Page#getControl()
     */
    public Control getControl() {
        if (treeViewer == null) {
            return null;
        }
        return treeViewer.getControl();
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.part.Page#setFocus()
     */
    @Override
    public void setFocus() {
        treeViewer.getTree().setFocus();
    }

    /**
     * Creates the tree viewer of the operand stack view.
     * @param parent composite
     */
    void createTreeViewer(Composite parent) {
        treeViewer = new TreeViewer(parent, SWT.BORDER);

        Tree tree = treeViewer.getTree();
        column = new TreeColumn(tree, SWT.LEFT, 0);
        column.setMoveable(true);
        column.setText(BytecodeVisualizerMessages.OpstackBytecodeInstrColumnName);
        column.setWidth(200);

        column = new TreeColumn(tree, SWT.LEFT, 1);
        column.setMoveable(true);
        column.setText(BytecodeVisualizerMessages.OpstackOffsetColumnName);
        column.setWidth(40);

        column3 = new TreeColumn(tree, SWT.RIGHT);
        column3.setAlignment(SWT.LEFT);
        column3.setText(BytecodeVisualizerMessages.OpstackBeforeColumnName);
        column3.setWidth(100);

        column4 = new TreeColumn(tree, SWT.RIGHT);
        column4.setAlignment(SWT.LEFT);
        column4.setText(BytecodeVisualizerMessages.OpstackAfterColumnName);
        column4.setWidth(100);

        column5 = new TreeColumn(tree, SWT.RIGHT);
        column5.setAlignment(SWT.LEFT);
        column5.setText(BytecodeVisualizerMessages.OpstackDepthColumnName);
        column5.setWidth(100);

        column6 = new TreeColumn(tree, SWT.RIGHT);
        column6.setAlignment(SWT.LEFT);
        column6.setText(BytecodeVisualizerMessages.OpstackDescriptionColumnName);
        column6.setWidth(0); /* Description Column is hidden as default */

        tree.setHeaderVisible(true);
        tree.setLinesVisible(true);

        int order[] = { ColumnIndex.OPCODEMNEMONIC.getIndex(), ColumnIndex.OFFSET.getIndex(),
                ColumnIndex.OPSTACKBEFORE.getIndex(), ColumnIndex.OPSTACKAFTER.getIndex(),
                ColumnIndex.OPSTACKDEPTH.getIndex(), ColumnIndex.DESCRIPTION.getIndex() };
        tree.setColumnOrder(order);

        treeViewer.setContentProvider(new TreeViewContentProvider());
        treeViewer.setLabelProvider(new TreeTableLabelProvider());

        treeViewer.expandAll();

        /* selection listener for line synchronization */
        treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {

            /* (non-Javadoc)
             * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
             */
            public void selectionChanged(SelectionChangedEvent arg0) {
                ISelection sel = arg0.getSelection();
                if (!sel.isEmpty()) {
                    /* set a mutex to avoid the call back from the editor */
                    setTreeViewerSelectionMutex(true);

                    TreeSelection treeSel = (TreeSelection) sel;
                    Node n = (Node) treeSel.getFirstElement();
                    Object o = n.getObject();

                    if (o instanceof IInstructionLine) {
                        IInstructionLine i = (IInstructionLine) o;
                        editor.selectLineAndRevaluate2(i.getLine());
                    }

                    if (o instanceof String) { /* use parent of the true, false or switch value nodes */
                        IInstructionLine i = (IInstructionLine) n.getParent().getObject();
                        if (i != null) {
                            editor.selectLineAndRevaluate2(i.getLine());
                        }
                    }
                }
            }
        });

    }

    /**
     * Content provider for the operand stack view.
     */
    class TreeViewContentProvider implements ITreeContentProvider {

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
         */
        public Object[] getChildren(Object parentElement) {
            if (parentElement instanceof Node) {
                return ((Node) parentElement).getChildren().toArray();
            }

            return new Object[0];
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
         */
        public Object getParent(Object element) {
            if (element instanceof Node) {
                return ((Node) element).getParent();
            }

            return null;
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
         */
        public boolean hasChildren(Object element) {
            if (element instanceof Node) {
                return ((Node) element).hasChildren();
            }

            return false;
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ITreeContentProvider#getElements(java.lang.Object)
         */
        public Object[] getElements(Object nodes) {
            return getChildren(nodes);
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.IContentProvider#dispose()
         */
        public void dispose() {
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
         */
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }
    }

    /**
     * Label provider for the operand stack view
     */
    class TreeTableLabelProvider implements ITableLabelProvider {

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
         */
        public Image getColumnImage(Object element, int columnIndex) {
            if (columnIndex == 0) {
                if (element instanceof Node) {
                    Object o = ((Node) element).getObject();
                    if (o != null && o instanceof IInstructionLine) {
                        IInstructionLine i = (IInstructionLine) o;

                        switch (ControlFlowGraphUtils.getInstructionNodeType(i.getInstruction().getOpcode())) {
                        case INodeType.NODE_TYPE_SIMPLE:
                            return CoreImg.roundedrect_instr_16x16.createImage();
                        case INodeType.NODE_TYPE_IF:
                            return CoreImg.decision_instr_16x16.createImage();
                        case INodeType.NODE_TYPE_RETURN:
                            return CoreImg.return_instr_16x16.createImage();
                        case INodeType.NODE_TYPE_GOTO_JUMP:
                            return CoreImg.goto_instr_16x16.createImage();
                        case INodeType.NODE_TYPE_SWITCH:
                            return CoreImg.switch_instr_16x16.createImage();
                        case INodeType.NODE_TYPE_INVOKE:
                            return CoreImg.invoke_instr_16x16.createImage();
                        case INodeType.NODE_TYPE_GET:
                            return CoreImg.get_instr_16x16.createImage();
                        default:
                            return CoreImg.roundedrect_instr_16x16.createImage();

                        }
                    }
                    if (o instanceof String) {
                        return JavaUI.getSharedImages()
                                .getImage(org.eclipse.jdt.ui.ISharedImages.IMG_OBJS_PROTECTED);
                    }
                }

                return JavaUI.getSharedImages().getImage(org.eclipse.jdt.ui.ISharedImages.IMG_OBJS_LOCAL_VARIABLE);
            }
            return null;
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
         */
        public String getColumnText(Object element, int columnIndex) {

            if (element instanceof Node) {
                Node node = (Node) element;
                Object o = node.getObject();
                if (o != null && o instanceof IInstructionLine) {
                    IInstructionLine i = (IInstructionLine) o;

                    if (columnIndex == ColumnIndex.OFFSET.getIndex()) {
                        return i.getInstruction().getOpcodeMnemonic();
                    } else if (columnIndex == ColumnIndex.OPCODEMNEMONIC.getIndex()) {
                        return String.valueOf(i.getInstruction().getOffset());
                    } else if (columnIndex == ColumnIndex.OPSTACKBEFORE.getIndex()) { /* operand stack before */
                        return node.getOperandStackBefore();
                    } else if (columnIndex == ColumnIndex.OPSTACKAFTER.getIndex()) { /* operand stack after */
                        return node.getOperandStackAfter();
                    } else if (columnIndex == ColumnIndex.OPSTACKDEPTH.getIndex()) { /* stack depth */
                        if (node.getDepth() != null) {
                            int stackSize = OperandStack.UNKNOWN_SIZE;

                            if (node.getDepth().length == 1) {
                                stackSize = node.getDepth()[0];
                            }

                            List<Integer> listOfStacksSizes = new ArrayList<Integer>();
                            if (node.getDepth().length > 1) {
                                for (int s : node.getDepth()) {
                                    if (stackSize != s) {
                                        if (s > stackSize) {
                                            stackSize = s;
                                        }
                                        listOfStacksSizes.add(s);
                                    }
                                }
                            }

                            /* execute some trivial size based checks */
                            if (stackSize > methodInput.getMaxStack() || stackSize == OperandStack.UNKNOWN_SIZE
                                    || listOfStacksSizes.size() > 1) {

                                Widget w = treeViewer.testFindItem(node);
                                if (w != null) {
                                    TreeItem t = (TreeItem) w;
                                    t.setForeground(RED);

                                }
                            }

                            if (stackSize > methodInput.getMaxStack()) {
                                StringBuffer buf = new StringBuffer();
                                buf.append(CoreMessages.Error);
                                buf.append(JavaLexicalConstants.COLON);
                                buf.append(JavaLexicalConstants.SPACE);
                                buf.append(BytecodeVisualizerMessages.OperandStackAnalysis_Error_StackOverflow);
                                buf.append(JavaLexicalConstants.COMMA);
                                buf.append(JavaLexicalConstants.SPACE);
                                String msg = MessageFormat.format(
                                        BytecodeVisualizerMessages.OperandStackAnalysis_CurrentStackSize_Info,
                                        new Object[] { String.valueOf(stackSize) });
                                buf.append(msg);
                                buf.append(JavaLexicalConstants.DOT);
                                return buf.toString();
                            }

                            if (listOfStacksSizes.size() > 1) {
                                StringBuffer buf = new StringBuffer();
                                buf.append(CoreMessages.Error);
                                buf.append(JavaLexicalConstants.COLON);
                                buf.append(JavaLexicalConstants.SPACE);
                                buf.append(
                                        BytecodeVisualizerMessages.OperandStackAnalysis_Error_Different_StackSizes);
                                buf.append(JavaLexicalConstants.SPACE);

                                Iterator<Integer> it = listOfStacksSizes.iterator();
                                buf.append(it.next());
                                while (it.hasNext()) {
                                    buf.append(JavaLexicalConstants.PIPE);
                                    buf.append(it.next());
                                }

                                buf.append(JavaLexicalConstants.SPACE);
                                buf.append(JavaLexicalConstants.DOT);

                                return buf.toString();
                            }

                            /* check if the stack is empty in the return nodes */
                            if (ControlFlowGraphUtils.getInstructionNodeType(
                                    i.getInstruction().getOpcode()) == INodeType.NODE_TYPE_RETURN) {
                                if (stackSize != 0) {
                                    /*
                                     * check if the if the object on stack represents 
                                     * a reference to the Throwable leaving on the 
                                     * stack after the rest of the stack is cleared 
                                     * by the athrow byte code instruction.
                                     */
                                    if (!(stackSize == 1 && i.getInstruction().getOpcode() == Opcodes.ATHROW)) {

                                        Widget w = treeViewer.testFindItem(node);
                                        if (w != null) {
                                            TreeItem t = (TreeItem) w;
                                            t.setForeground(ORANGE);
                                        }

                                        StringBuffer buf = new StringBuffer();
                                        buf.append(CoreMessages.Warning);
                                        buf.append(JavaLexicalConstants.COLON);
                                        buf.append(JavaLexicalConstants.SPACE);
                                        buf.append(
                                                BytecodeVisualizerMessages.OperandStackAnalysis_Warning_StackNonEmpty);
                                        buf.append(JavaLexicalConstants.COMMA);
                                        buf.append(JavaLexicalConstants.SPACE);
                                        String msg = MessageFormat.format(
                                                BytecodeVisualizerMessages.OperandStackAnalysis_CurrentStackSize_Info,
                                                new Object[] { String.valueOf(stackSize) });
                                        buf.append(msg);
                                        buf.append(JavaLexicalConstants.DOT);

                                        return buf.toString();
                                    }
                                }
                            }

                            return String.valueOf(stackSize);
                        }
                    } else if (columnIndex == ColumnIndex.DESCRIPTION.getIndex()) { /* opcode description   */
                        return ByteCodeConstants.OPCODE_OPERANDSTACK_DESCR[i.getInstruction().getOpcode()];
                    }

                } else {
                    if (columnIndex == ColumnIndex.OFFSET.getIndex()) {
                        return o.toString();
                    } else {
                        return "";
                    }
                }
            }

            return BytecodeVisualizerMessages.OperandStackView_Unknown;

        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
         */
        public void addListener(ILabelProviderListener listener) {
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
         */
        public void dispose() {
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
         */
        public boolean isLabelProperty(Object element, String property) {
            return false;
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
         */
        public void removeListener(ILabelProviderListener listener) {
        }
    }

    /**
     * Sets input of the tree viewer.
     * @param instructions list of byte code instructions
     * @param id kind of the view
     */
    private void setInput(List<IInstructionLine> instructions) {
        Object input = generateInput(instructions, view_ID);

        if (input == null) {
            return;
        }

        /* fill tree map for synchronization */
        treeMap = new TreeMap<Integer, Node>();
        fillTreeMap((Node) input);

        BytecodeDocumentProvider byteCodeDocumentProvider = (BytecodeDocumentProvider) editor.getDocumentProvider();
        if (byteCodeDocumentProvider != null) {
            IClassFileDocument ic = byteCodeDocumentProvider.getClassFileDocument();

            /* when the methodInput changes, a new stack is generated */
            /* later, we can add the reference to the previous stack to the new stack */
            operandStack = new OperandStack(instructions, ic.getConstantPool(), methodInput.getLocalVariableTable(),
                    methodInput.getExceptionTable());
            INodeListExt nodeList = operandStack.getOperandStackGraph().getNodeList();
            for (int i = 0; i < nodeList.size(); i++) {
                INodeExt n = nodeList.getNodeExt(i);
                Object o = n.getData();
                if (o instanceof Map) {
                    @SuppressWarnings("unchecked")
                    Map<OperandStackPropertyConstants, Object> nodeMap = (Map<OperandStackPropertyConstants, Object>) o;
                    o = nodeMap.get(OperandStackPropertyConstants.NODE_INSTR_OBJECT);

                    IInstructionLine iLine;
                    if (o != null) {
                        iLine = (IInstructionLine) o;
                        Node node = treeMap.get(iLine.getLine());

                        o = nodeMap.get(OperandStackPropertyConstants.NODE_STACK);
                        if (o != null) {
                            NodeStackProperty nsp = (NodeStackProperty) o;
                            if (opstackRepresenationFormat == OpstackRepresenation.SIMPLE) {
                                node.setOperandStackBefore(
                                        OperandStack.stackToString(operandStack.getStackBefore(n).get(0)));
                                node.setOperandStackAfter(OperandStack.stackToString(nsp.getStackAfter().get(0)));
                            } else if (opstackRepresenationFormat == OpstackRepresenation.ALL) {
                                node.setOperandStackBefore(
                                        OperandStack.stackListToString(operandStack.getStackBefore(n)));
                                node.setOperandStackAfter(OperandStack.stackListToString(nsp.getStackAfter()));
                            } else if (opstackRepresenationFormat == OpstackRepresenation.TYPES) {
                                node.setOperandStackBefore(OperandStack.stackToString(
                                        operandStack.getStackBefore(n).get(0), OpstackRepresenation.TYPES));
                                node.setOperandStackAfter(OperandStack.stackToString(nsp.getStackAfter().get(0),
                                        OpstackRepresenation.TYPES));
                            } else if (opstackRepresenationFormat == OpstackRepresenation.VALUES) {
                                node.setOperandStackBefore(OperandStack.stackToString(
                                        operandStack.getStackBefore(n).get(0), OpstackRepresenation.VALUES));
                                node.setOperandStackAfter(OperandStack.stackToString(nsp.getStackAfter().get(0),
                                        OpstackRepresenation.VALUES));
                            } else {
                                node.setOperandStackBefore(
                                        OperandStack.stackToString(operandStack.getStackBefore(n).get(0)));
                                node.setOperandStackAfter(OperandStack.stackToString(nsp.getStackAfter().get(0)));
                            }

                            node.setDepth(nsp.getStackSize());
                        } else {
                            node.setOperandStackBefore(BytecodeVisualizerMessages.OperandStackView_Unknown);
                            node.setOperandStackAfter(BytecodeVisualizerMessages.OperandStackView_Unknown);
                            node.setDepth(new int[] { OperandStack.UNKNOWN_SIZE });
                        }
                    }
                }
            }
        }

        treeViewer.setInput(input);
        treeViewer.expandAll();

        /* set current selection */
        int newLine = editor.getSelectedLine();
        Node node = treeMap.get(newLine);
        if (node != null) {
            Widget w = treeViewer.testFindItem(node);
            if (w != null) {
                TreeItem t = (TreeItem) w;
                treeViewer.getTree().select(t);
                treeViewer.refresh(true);
            }
        }
    }

    private void fillTreeMap(Node root) {
        for (Node n : root.getChildren()) {
            fillTreeMap(n);
            Object nodeObj = n.getObject();
            if (nodeObj instanceof IInstructionLine) {
                IInstructionLine i = (IInstructionLine) nodeObj;
                treeMap.put(i.getLine(), n);
            }
        }
    }

    /**
     * Creates the tree structure for the operand stack view.
     * @param instructions list of instructions
     * @param id kind of the view
     * @return the tree structure
     */
    protected abstract Object generateInput(List<IInstructionLine> instructions, OperandStackView_ID id);

    /**
     * Element of the operand stack view structure.
     */
    class Node {
        Node parent = null;
        List<Node> children = new ArrayList<Node>();
        Object obj;
        String operandStackBefore, operandStackAfter;
        int depth[];

        public Object getObject() {
            return obj;
        }

        public void setObject(Object obj) {
            this.obj = obj;
        }

        public Node getParent() {
            return parent;
        }

        public void setParent(Node parent) {
            this.parent = parent;
        }

        public boolean hasParent() {
            return parent != null;
        }

        public List<Node> getChildren() {
            return children;
        }

        public int[] getDepth() {
            return depth;
        }

        public void setChildren(List<Node> children) {
            this.children = children;
        }

        public void addhild(Node child) {
            children.add(child);
        }

        public boolean hasChildren() {
            return children.size() > 0;
        }

        public String getOperandStackBefore() {
            return operandStackBefore;
        }

        public String getOperandStackAfter() {
            return operandStackAfter;
        }

        public void setOperandStackBefore(String operandStack) {
            this.operandStackBefore = operandStack;
        }

        public void setOperandStackAfter(String operandStack) {
            this.operandStackAfter = operandStack;
        }

        public void setDepth(int depth[]) {
            this.depth = depth;
        }
    }
}