com.drgarbage.bytecodevisualizer.editors.BytecodeEditor.java Source code

Java tutorial

Introduction

Here is the source code for com.drgarbage.bytecodevisualizer.editors.BytecodeEditor.java

Source

/**
 * Copyright (c) 2008-2012, 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.editors;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.IInstructionPointerPresentation;
import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageDeclaration;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.IClassFileEditorInput;
import org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider;
import org.eclipse.jdt.internal.ui.javaeditor.InternalClassFileEditorInput;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditorBreadcrumb;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.ui.text.IColorManager;
import org.eclipse.jdt.ui.text.IJavaPartitions;
import org.eclipse.jdt.ui.text.JavaTextTools;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.projection.IProjectionListener;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.custom.ST;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IReusableEditor;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.console.TextConsole;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.internal.PartSite;
import org.eclipse.ui.internal.WorkbenchImages;
import org.eclipse.ui.internal.part.NullEditorInput;
import org.eclipse.ui.internal.texteditor.LineNumberColumn;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.rulers.IColumnSupport;
import org.eclipse.ui.texteditor.rulers.RulerColumnDescriptor;
import org.eclipse.ui.texteditor.rulers.RulerColumnRegistry;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;

import com.drgarbage.asm.render.intf.IClassFileDocument;
import com.drgarbage.asm.render.intf.IDocumentUpdateListener;
import com.drgarbage.asm.render.intf.IFieldSection;
import com.drgarbage.asm.render.intf.IMethodSection;
import com.drgarbage.asm.render.intf.IOutlineElementField;
import com.drgarbage.bytecode.ByteCodeConstants;
import com.drgarbage.bytecodevisualizer.BytecodeVisualizerMessages;
import com.drgarbage.bytecodevisualizer.BytecodeVisualizerPlugin;
import com.drgarbage.bytecodevisualizer.actions.ActivateBasicblockGraphViewAction;
import com.drgarbage.bytecodevisualizer.actions.ActivateBytecodeGraphViewAction;
import com.drgarbage.bytecodevisualizer.actions.BytecodevizualizerActionBarContributor;
import com.drgarbage.bytecodevisualizer.actions.ExportGraphAndOpenWithControlflowgraphFactoryAction;
import com.drgarbage.bytecodevisualizer.actions.ToggleBytecodeBreakpointAction;
import com.drgarbage.bytecodevisualizer.preferences.BytecodeVisualizerPreferenceConstats;
import com.drgarbage.bytecodevisualizer.view.OperandStackView;
import com.drgarbage.bytecodevisualizer.view.OperandStackViewPage;
import com.drgarbage.bytecodevisualizer.view.OperandStackViewPageIml;
import com.drgarbage.core.CoreConstants;
import com.drgarbage.core.CoreMessages;
import com.drgarbage.core.CorePlugin;
import com.drgarbage.core.img.CoreImg;
import com.drgarbage.core.preferences.CorePreferenceConstants;
import com.drgarbage.core.views.ControlFlowGraphView;
import com.drgarbage.core.views.ControlFlowGraphViewPage;
import com.drgarbage.core.views.IControlFlowGraphView;
import com.drgarbage.core.views.IControlFlowGraphViewPage;
import com.drgarbage.javalang.JavaLangUtils;
import com.drgarbage.javasrc.JavaLexicalConstants;
import com.drgarbage.utils.ClassFileDocumentsUtils;
import com.drgarbage.utils.Messages;

/**
  * Byte Code Editor.
  *
  * @author Sergej Alekseev and Peter Palaga
  * @version $Revision$
  * $Id$
  */
public class BytecodeEditor extends JavaEditor implements IDocumentUpdateListener, IControlFlowGraphView,
        IClassFileEditor, BytecodeVisualizerPreferenceConstats {

    /** Key constants */
    private static final int ARROW_DOWN = SWT.KEYCODE_BIT + 2; //keyCode=16777218 (KeyEvent KeyDown)

    private static final int ARROW_UP = SWT.KEYCODE_BIT + 1; //keyCode=16777217 (KeyEvent KeyUp)

    public static final int TAB_INDEX_BYTECODE = 0;
    public static final int TAB_INDEX_SOURCE = 1;

    /**
     * Returns true if the bytecode visualizer is a default editor for 
     * *.class files otherwise false.
     * @return true or false
     */
    public static boolean isBytecodeVisualizerDefault() {

        try {
            IEditorDescriptor editor = IDE.getEditorDescriptor("x.class"); /* just a class file name */

            if (editor.getId().equals(CoreConstants.BYTECODE_VISUALIZER_EDITOR_ID)) {
                return true;
            }
        } catch (PartInitException e) {
            BytecodeVisualizerPlugin.getDefault().getLog()
                    .log(new Status(IStatus.ERROR, BytecodeVisualizerPlugin.PLUGIN_ID, e.getMessage(), e));
        }

        return false;
    }

    /**
     * Resolves the source code number into the bytecode line.
     * @param methods
     * @param sourceLine
     * @return bytecode number
     */
    protected static int resolveLineNumberIntoBytecode(List<IMethodSection> methods, int sourceLine) {
        int byteCodeLine = ByteCodeConstants.INVALID_OFFSET;
        for (IMethodSection m : methods) {
            if (!m.hasLineNumberTable()) {
                break;
            }

            byteCodeLine = m.getBytecodeLine(sourceLine);
            if (byteCodeLine != ByteCodeConstants.INVALID_OFFSET) {
                return byteCodeLine;
            }
        }

        return IClassFileEditor.INVALID_LINE;
    }

    /**
     * Document provider.
     */
    protected BytecodeDocumentProvider byteCodeDocumentProvider = new BytecodeDocumentProvider(this);

    /**
     * Canvas if the control flow graph figure.
     */
    private ControlFlowGraphCanvas canvasControlFlowGraph = null;

    /**
     * Menu provider.
     */
    private MenuManager cmProvider;

    /**
     * Outline page of the class file editor.
     */
    protected BytecodeOutlinePage fOutlinePage = null;

    /**
     * Operand Stack View reference
     */
    private OperandStackViewPage operandStackViewPage = null;

    /**
     * Used to generate annotations for stack frames
     */
    //   protected IInstructionPointerPresentation fPresentation = (IInstructionPointerPresentation) DebugUITools.newDebugModelPresentation();   

    /**
      * Whether to re-use editors when displaying source during debugging.
      */
    private boolean fReuseEditor = DebugUIPlugin.getDefault().getPreferenceStore()
            .getBoolean(IDebugUIConstants.PREF_REUSE_EDITOR);
    /**
     * Open in control flow factory.
     */
    private ExportGraphAndOpenWithControlflowgraphFactoryAction graphFactoryAction = null;

    /**
     * The flag which indicates if the cursor update handler 
     * is enabled or disabled.
     */
    private boolean handleCursorPositionChanged = true;

    /**
     * Reference to the action contributor. 
     */
    private BytecodevizualizerActionBarContributor actionContributor = null;

    /**
     * List of the line selection listeners.
     */
    protected List<IClassFileEditorSelectionListener> lineSelectionListener = new ArrayList<IClassFileEditorSelectionListener>();

    private ISelectionChangedListener outlineListener = new ISelectionChangedListener() {

        public void selectionChanged(SelectionChangedEvent event) {
            TreeSelection sel = (TreeSelection) event.getSelection();
            Object o = sel.getFirstElement();

            if (o instanceof IJavaElement) {
                IJavaElement element = (IJavaElement) o;

                switch (element.getElementType()) {
                case IJavaElement.PACKAGE_DECLARATION:
                    IType t0 = sourceCodeViewer.getPrimaryType();
                    if (!t0.isBinary()) { /*  Doesn't work for binary class files */

                        ICompilationUnit cu = t0.getCompilationUnit();
                        IPackageFragment p = t0.getPackageFragment();
                        if (cu != null && p != null) {
                            IPackageDeclaration d = t0.getCompilationUnit()
                                    .getPackageDeclaration(p.getElementName());

                            sourceCodeViewer.setSelection(d);
                        }
                    }
                    break;

                case IJavaElement.TYPE:
                    sourceCodeViewer.setSelection(sourceCodeViewer.getPrimaryType());
                    break;

                case IJavaElement.FIELD:
                    IOutlineElementField f = (IOutlineElementField) o;
                    String fieldName = f.getFieldSection().getName();
                    IType t = sourceCodeViewer.getPrimaryType();
                    if (t != null && fieldName != null) {
                        IField field = t.getField(fieldName);
                        sourceCodeViewer.setSelection(field);
                    }
                    break;

                case IJavaElement.METHOD:
                    IMethod method = (IMethod) o;

                    IType t2 = sourceCodeViewer.getPrimaryType();
                    try {
                        IMethod m = ClassFileDocumentsUtils.findMethod(t2, method.getElementName(),
                                method.getSignature());
                        if (m != null) {
                            sourceCodeViewer.setSelection(m);
                            return;
                        } else {
                            if (method.isConstructor()) {
                                sourceCodeViewer.setSelection(t2);
                                return;
                            }
                        }

                    } catch (JavaModelException e) {
                        BytecodeVisualizerPlugin.getDefault().getLog().log(
                                new Status(IStatus.ERROR, BytecodeVisualizerPlugin.PLUGIN_ID, e.getMessage(), e));
                    }
                    break;
                }
            }
        }
    };

    /**
     * Parent composite. 
     */
    protected Composite parent;

    /**
     * Preference property change listener.
     */
    private IPropertyChangeListener preferenceListener = null;

    /**
     * Modify property: reuse editor during debugging.
     */
    private IPropertyChangeListener reuseDebugPropertyChangeListener = new IPropertyChangeListener() {

        /* (non-Javadoc)
         * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
         */
        public void propertyChange(PropertyChangeEvent event) {
            String property = event.getProperty();
            if (property.equals(IDebugUIConstants.PREF_REUSE_EDITOR)) {
                fReuseEditor = DebugUIPlugin.getDefault().getPreferenceStore()
                        .getBoolean(IDebugUIConstants.PREF_REUSE_EDITOR);
            }
        }

    };

    /**
     * Flag if the graph has to be shown in the outline.
     */
    protected boolean showGraphInSeparateView = false;

    /**
     * Sourcecode Viewer.
     */
    private ISourceCodeViewer sourceCodeViewer;

    /**
     * Source code view container.
     */
    protected Composite sourceCodeViewerComposite;

    /**
     * Editor's preference store.
     */
    private IPreferenceStore store = null;

    /**
     * The container widget.
     */
    private CTabFolder tabFolder;

    private ToggleBytecodeBreakpointAction toggleBytecodeBreakpointAction;

    /**
     * The standard constructor of the text editor for file resources.
     */
    public BytecodeEditor() {
        super();
        setDocumentProvider(byteCodeDocumentProvider);

        /* reuse editor during debugging */
        BytecodeVisualizerPlugin.getDefault().getPreferenceStore()
                .addPropertyChangeListener(reuseDebugPropertyChangeListener);
    }

    /**
     * Set the reference to the action contributor. 
     * @param contributor action contributor
     */
    public void setActionContributor(BytecodevizualizerActionBarContributor contributor) {
        actionContributor = contributor;
    }

    /**
     * Sets active the source code view.
     */
    public void activateBytecodeTab() {
        setActivePage(TAB_INDEX_BYTECODE);

        updateOutlineGraphView();
    }

    /**
     * Activate graph factory action, if the selector 
     * location is within the method area
     * 
     * @param line 0-based line index
     */
    private void activateGraphFactoryAction(int line/* changed to 0-based */) {
        IClassFileDocument doc = byteCodeDocumentProvider.getClassFileDocument();
        if (doc != null) {
            graphFactoryAction.setEnabled(doc.isLineInMethod(line/* changed to 0-based */));
        }
    }

    /**
     * Sets active the byte code view.
     */
    public void activateSourceCodeTab() {
        setActivePage(TAB_INDEX_SOURCE);

        updateOutlineGraphView();
    }

    /**
     * Creates and adds a new page containing the given control to this
     * multi-page editor. The control may be <code>null</code>, allowing it
     * to be created and set later using <code>setControl</code>.
     * 
     * @param control
     *            the control, or <code>null</code>
     * @return the index of the new page
     * 
     * @see MultiPageEditorPart#setControl(int, Control)
     */
    public int addPage(Control control) {
        int index = getPageCount();
        addPage(index, control);
        return index;
    }

    /**
     * Creates and adds a new page containing the given control to this
     * multi-page editor. The page is added at the given index. The control may
     * be <code>null</code>, allowing it to be created and set later using
     * <code>setControl</code>.
     * 
     * @param index
     *            the index at which to add the page (0-based)
     * @param control
     *            the control, or <code>null</code>
     * 
     * @see MultiPageEditorPart#setControl(int, Control)
     */
    public void addPage(int index, Control control) {
        createItem(index, control);
    }

    /**
     * Adds Line Selection change listener.
     * @param listener line selection listener
     */
    public void addtLineSelectionListener(IClassFileEditorSelectionListener listener) {
        lineSelectionListener.add(listener);
    }

    /*
     * @see AbstractTextEditor#affectsTextPresentation(PropertyChangeEvent)
     */
    protected boolean affectsTextPresentation(PropertyChangeEvent event) {
        return false;
    }

    /**
      * Creates this editor's standard actions and connects them with the global
      * workbench actions for context, toplevel menu and toolbar.
      * <p>
      * Subclasses may extend.</p>
      */
    protected void createActions() {
        super.createActions();

        /* radio action bytecode/basicblock view */
        IAction a = new ActivateBytecodeGraphViewAction(this);
        a.setChecked(true);
        setAction(ActivateBytecodeGraphViewAction.ID, a);
        IAction a2 = new ActivateBasicblockGraphViewAction(this);
        setAction(ActivateBasicblockGraphViewAction.ID, a2);

        /* open graph in the control flow factory action */
        graphFactoryAction = new ExportGraphAndOpenWithControlflowgraphFactoryAction(this,
                byteCodeDocumentProvider.getClassFileDocument());
        setAction(ExportGraphAndOpenWithControlflowgraphFactoryAction.ID, graphFactoryAction);

        /* About Action */
        /* not desired anymore */

        /* Create ruler context menu */
        IVerticalRuler ruler = getVerticalRuler();

        MenuManager mm = new MenuManager();

        mm.add(getToggleBytecodeBreakpointAction());

        IAction action = getAction(ITextEditorActionConstants.LINENUMBERS_TOGGLE);
        mm.add(action);

        mm.add(new Separator());
        action = getAction(ITextEditorActionConstants.RULER_PREFERENCES);
        mm.add(action);

        Menu m = mm.createContextMenu(ruler.getControl());
        ruler.getControl().setMenu(m);
    }

    /**
     * Creates and initialize control flow graph canvas
     */
    private void createAndInitializeControlFlowGraphCanvas() {

        StyledText textWidget = getSourceViewer().getTextWidget();
        canvasControlFlowGraph = new ControlFlowGraphCanvas(parent, this);
        canvasControlFlowGraph.init(textWidget.getLineHeight(), byteCodeDocumentProvider.getClassFileDocument());

        /* initialize control flow graph view */
        setControlFlowViewBackGround();

        /* set menu for control flow graph*/
        Menu menu = getSourceViewer().getTextWidget().getMenu();
        /* 
         * NOTE: menu is disposed if the control flow graph view 
         * is closed. The menu is cloned.
         */
        Menu menu2 = new Menu(canvasControlFlowGraph);
        menu2.setData(menu.getData());
        canvasControlFlowGraph.setMenu(menu2);

        /* Synchronize scroll bars in the left and right views */
        synchronizeScrollBars(textWidget, canvasControlFlowGraph);

        /* Synchronize line selection in the left and right views */
        synchronizeLineSelection(textWidget, canvasControlFlowGraph);

        /* synchronize current line color */
        synchronizeCurrentLineColor(canvasControlFlowGraph);

        /* deactivate export graph action */
        IAction a = getAction(ExportGraphAndOpenWithControlflowgraphFactoryAction.ID);
        a.setEnabled(false);

        final IAction a1 = getAction(ActivateBytecodeGraphViewAction.ID);
        final IAction a2 = getAction(ActivateBasicblockGraphViewAction.ID);

        /* set status of action to true if the view is visible */
        if (isControlFlowgraphViewVisible()) {
            a1.setEnabled(true);
            a2.setEnabled(true);
        } else {
            a1.setEnabled(false);
            a2.setEnabled(false);
        }

        /* 
         * activate actions only if focus in the editor or separate view
         * is set and the control flow graph view is visible. 
         * add listener to control flow graph panel and the 
         * text editor 
         */
        canvasControlFlowGraph.addFocusListener(new FocusListener() {
            public void focusGained(FocusEvent e) {
                a1.setEnabled(true);
                a2.setEnabled(true);
            }

            public void focusLost(FocusEvent e) {
                a1.setEnabled(false);
                a2.setEnabled(false);
            }
        });

        textWidget.addFocusListener(new FocusListener() {
            public void focusGained(FocusEvent e) {
                if (canvasControlFlowGraph.isDisposed())
                    return;

                if (isControlFlowgraphViewVisible()) {
                    a1.setEnabled(true);
                    a2.setEnabled(true);
                } else {
                    a1.setEnabled(false);
                    a2.setEnabled(false);
                }
            }

            public void focusLost(FocusEvent e) {
                if (canvasControlFlowGraph.isDisposed())
                    return;

                if (!isControlFlowgraphViewVisible()) {
                    a1.setEnabled(false);
                    a2.setEnabled(false);
                }
            }
        });

        /* deactivate actions if the view is closed*/
        canvasControlFlowGraph.addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                a1.setEnabled(false);
                a2.setEnabled(false);
            }
        });

    }

    /**
     * Creates page 0 of the multi-page editor,
     * which contains a text editor.
     */
    private void createBytecodeTab() {

        /* initialize preferences */
        String s = CorePlugin.getDefault().getPreferenceStore()
                .getString(CorePreferenceConstants.GRAPH_PANEL_LOCATION);
        if (s.equals(CorePreferenceConstants.GRAPH_PANEL_LOCATION_SEPARATE_VIEW)) {
            showGraphInSeparateView = true;
        } else if (s.equals(CorePreferenceConstants.GRAPH_PANEL_LOCATION_EDITOR)) {
            showGraphInSeparateView = false;
        } else {
            showGraphInSeparateView = false;
        }

        /* create content*/
        Composite c = null;
        if (showGraphInSeparateView) {
            c = createPartControlWithGraphOutline(getTabFolder());
        } else {
            c = createPartControlWithSach(getTabFolder());
        }

        /* disable folding */
        final ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
        if (viewer != null) {
            if (viewer.isProjectionMode()) {
                viewer.doOperation(ProjectionViewer.TOGGLE);
            }

            viewer.addProjectionListener(new IProjectionListener() {
                public void projectionDisabled() {
                    /* nothing to do */
                }

                public void projectionEnabled() {
                    if (viewer.isProjectionMode()) {
                        viewer.doOperation(ProjectionViewer.TOGGLE);
                    }
                }
            });
        }

        int index = addPage(c);

        setPageText(index, BytecodeVisualizerMessages.BytecodeEditor_tab_Bytecode);
        setPartName(getTitle());
        CTabItem item = getItem(index);
        item.setImage(CoreImg.bytecodeViewer_16x16.createImage());

    }

    /**
     * Creates the outline page used with this editor.
     * @return the created Java outline page
     */
    protected BytecodeOutlinePage createBytecodeVisualizerOutlinePage() {
        BytecodeOutlinePage page = new BytecodeOutlinePage(this);
        page.setInput(byteCodeDocumentProvider.getClassFileOutlineElement());
        return page;
    }

    /**
     * Creates and returns the preference store for this Java editor with the given input.
     *
     * @param input The editor input for which to create the preference store
     * @return the preference store for this editor
     */
    private IPreferenceStore createCombinedPreferenceStore(IEditorInput input) {
        List<IPreferenceStore> stores = new ArrayList<IPreferenceStore>(3);

        /* own bytecode visualizer preferences */
        stores.add(BytecodeVisualizerPlugin.getDefault().getPreferenceStore());

        /* fond and color preferences */
        stores.add(JavaPlugin.getDefault().getPreferenceStore());

        /* background and current line color preferences */
        stores.add(EditorsUI.getPreferenceStore());

        return new ChainedPreferenceStore((IPreferenceStore[]) stores.toArray(new IPreferenceStore[stores.size()]));
    }

    /**
     * Creates a control flow graph page.
     * @return the control flow graph page
     */
    protected ControlFlowGraphViewPage createGraphControlFlowViewPage() {
        if (!showGraphInSeparateView) {
            return null;
        }

        if (canvasControlFlowGraph == null || canvasControlFlowGraph.isDisposed()) {
            /* recreate control flow graph viewer */
            createAndInitializeControlFlowGraphCanvas();
        }

        ControlFlowGraphViewPage page = new ControlFlowGraphViewPage(canvasControlFlowGraph);
        return page;
    }

    /**
     * Creates a tab item at the given index and places the given control in the
     * new item. The item is a CTabItem with no style bits set.
     * 
     * @param index
     *            the index at which to add the control
     * @param control
     *            is the control to be placed in an item
     * @return a new item
     */
    private CTabItem createItem(int index, Control control) {
        CTabItem item = new CTabItem(getTabFolder(), SWT.NONE, index);
        item.setControl(control);
        return item;
    }

    /**
     * Creates the pages of the multi-page editor.
     */
    protected void createPages() {
        createBytecodeTab();
        createSourceCodeTab();

    }

    /* (non-Javadoc)
     * @see com.drgarbage.bytecodevisualizer.core.editors.ClassFileEditor#createPartControl(org.eclipse.swt.widgets.Composite)
     */
    public final void createPartControl(final Composite parent) {
        this.parent = parent;

        parent.setLayout(new FillLayout());
        this.tabFolder = createTabFolder(parent);

        createPages();

        String showTab = BytecodeVisualizerPlugin.getDefault().getPreferenceStore()
                .getString(BytecodeVisualizerPreferenceConstats.SHOW_TAB);
        if (showTab.equals(BytecodeVisualizerPreferenceConstats.SHOW_ALWAYS_BYTECODE_TAB)) {
            activateBytecodeTab(); /* byte code tab */
        } else if (showTab.equals(BytecodeVisualizerPreferenceConstats.SHOW_ALWAYS_SOURCECODE_TAB)) {
            activateSourceCodeTab(); /* source code tab */
        }
        /* default s.equals(SourceCodePreferences.SHOW_SOURCECODE_IF_AVALIABLE) */
        else {
            if (sourceCodeViewer.isSourceCodeLoaded()) {
                /* source code tab */
                activateSourceCodeTab();
            } else {
                /* byte code tab */
                activateBytecodeTab();
            }
        }

        /*  set the active page (page 0 by default), unless it has already been done */
        if (getActiveTabIndex() == -1) {
            setActivePage(0);
        }

        addtLineSelectionListener(new IClassFileEditorSelectionListener() {

            public void lineSelectionChanged(int newLine, Object o) {
                if (o instanceof IMethodSection) {
                    IMethodSection method = (IMethodSection) o;

                    if (method != null) {
                        if (method.getFirstLine() == newLine) {
                            IType t = sourceCodeViewer.getPrimaryType();
                            try {
                                IMethod m = ClassFileDocumentsUtils.findMethod(t, method.getName(),
                                        method.getDescriptor());
                                if (m != null) {
                                    sourceCodeViewer.setSelection(m);
                                    return;
                                } else {
                                    if (method.isConstructor()) {
                                        sourceCodeViewer.setSelection(t);
                                        return;
                                    }
                                }
                            } catch (JavaModelException e) {
                                BytecodeVisualizerPlugin.getDefault().getLog().log(new Status(IStatus.ERROR,
                                        BytecodeVisualizerPlugin.PLUGIN_ID, e.getMessage(), e));
                            }
                        }

                        int line = method.getSourceCodeLine(newLine - 1/* changed to 0-based */);
                        if (line != ByteCodeConstants.INVALID_LINE) {
                            sourceCodeViewer.selectSourceCodeLine(line - 1 /* changed to 0-based */, false);
                        }
                    }

                    return;
                }

                if (o instanceof IFieldSection) {
                    IFieldSection f = (IFieldSection) o;
                    String fieldName = f.getName();
                    IType t = sourceCodeViewer.getPrimaryType();
                    if (t != null && fieldName != null) {
                        IField field = t.getField(fieldName);
                        sourceCodeViewer.setSelection(field);
                    }

                    return;
                }

                if (o instanceof IClassFileDocument) {
                    IType t = sourceCodeViewer.getPrimaryType();
                    if (t != null) {
                        sourceCodeViewer.setSelection(t);
                    }

                    return;
                }

            }

        });

        /* FIX: bug#84 Recursive attempt to create itself */
        ///* called only the first time */
        //selectAndRevealX(0, IClassFileEditor.INVALID_LINE);

        /* DON'T USE selectAndreval Method directly from createPart
         * to avoid RECURSIVE WARNING: bug#84 Recursive attempt to create itself
         * Instead overwrite the follwing methods
         * @see org.eclipse.ui.texteditor.AbstractTextEditor#selectAndReveal(int, int)
         * or 
         * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#doSetSelection(org.eclipse.jface.viewers.ISelection)
         */

    }

    /**
     * Creates the SWT controls for this editor.
     */
    public Composite createPartControlWithGraphOutline(final Composite parent) {

        final StackLayout layout = new StackLayout();
        parent.setLayout(layout);

        /* create the control for the Byte Code Editor */
        Composite editorParent = new Composite(parent, SWT.NONE);
        editorParent.setLayout(new FillLayout());
        super.createPartControl(editorParent);
        layout.topControl = editorParent;

        /* install context menu */
        cmProvider = new BytecodevizualizerContexMenuManager(this);
        Menu menu = cmProvider.createContextMenu(editorParent);
        getSourceViewer().getTextWidget().setMenu(menu);
        getSite().registerContextMenu(cmProvider, getSite().getSelectionProvider());

        /* add update listener */
        byteCodeDocumentProvider.addDocumentUpdateListener(this);

        /* create and initialize control flow graph canvas */
        //createAndInitializeControlFlowGraphCanvas();

        return editorParent;
    }

    /**
     * Creates the SWT controls for this editor.
     */
    public Composite createPartControlWithSach(final Composite parent0) {

        final Composite parent = new Composite(parent0, SWT.NONE);
        parent.setLayout(new FillLayout());

        /* set parent Layout */
        final FormLayout form = new FormLayout();
        parent.setLayout(form);

        /* Create sash and set its layout */
        final Sash sash = new Sash(parent, SWT.VERTICAL);

        /* Wrap the first view: Byte Code Editor */
        Composite editorParent = new Composite(parent, SWT.NONE);
        FormData editorParentFormData = new FormData();
        editorParentFormData.left = new FormAttachment(0, 0);
        editorParentFormData.right = new FormAttachment(sash, 0);
        editorParentFormData.top = new FormAttachment(0, 0);
        editorParentFormData.bottom = new FormAttachment(100, 0);
        editorParent.setLayoutData(editorParentFormData);
        editorParent.setLayout(new FillLayout());

        /* create the control for the Byte Code Editor */
        super.createPartControl(editorParent);

        /* create the control flow graph viewer */
        StyledText textWidget = getSourceViewer().getTextWidget();

        /* create and initialize control flow graph canvas */
        canvasControlFlowGraph = new ControlFlowGraphCanvas(parent, this);
        canvasControlFlowGraph.init(textWidget.getLineHeight(), byteCodeDocumentProvider.getClassFileDocument());

        /* add update listener */
        byteCodeDocumentProvider.addDocumentUpdateListener(this);

        /* Wrap the second view: Control Flow Graph Viewer */
        FormData editorParentFormData2 = new FormData();
        editorParentFormData2.left = new FormAttachment(sash, 0);
        editorParentFormData2.right = new FormAttachment(100, 0);
        editorParentFormData2.top = new FormAttachment(0, 0);
        editorParentFormData2.bottom = new FormAttachment(100, 0);
        canvasControlFlowGraph.setLayoutData(editorParentFormData2);

        /* init control flow graph view */
        setControlFlowViewBackGround();

        /* install context menu */
        MenuManager cmProvider = new BytecodevizualizerContexMenuManager(this);
        Menu menu = cmProvider.createContextMenu(editorParent);
        getSite().registerContextMenu(cmProvider, getSite().getSelectionProvider());

        this.getSourceViewer().getTextWidget().setMenu(menu);
        canvasControlFlowGraph.setMenu(menu);

        /* Synchronize scroll bars in the left and right views */
        synchronizeScrollBars(textWidget, canvasControlFlowGraph);

        /* Synchronize line selection in the left and right views */
        synchronizeLineSelection(textWidget, canvasControlFlowGraph);

        /* synchronize current line color */
        synchronizeCurrentLineColor(canvasControlFlowGraph);

        /* default form data for the sash */
        final FormData sashFormData = new FormData();
        sashFormData.left = new FormAttachment(0, 0);
        sashFormData.top = new FormAttachment(0, 0);
        sashFormData.bottom = new FormAttachment(100, 0);
        sash.setLayoutData(sashFormData);

        final int graphAreaWidht = canvasControlFlowGraph.getFigureWidth();
        final int sashWidthoffset = 24; /* sash + balks */

        /* resize of the editor shell */
        parent.addControlListener(new ControlListener() {
            public void controlMoved(ControlEvent e) {
                /* nothing to do */
            }

            /* set the left are = size of the graph view, but maximal 50% of the whole view */
            public void controlResized(ControlEvent e) {
                Rectangle shellRect = parent.getClientArea();
                int right = shellRect.width - graphAreaWidht - sashWidthoffset;
                right = Math.max(right, shellRect.width / 2);
                sashFormData.left.offset = right;
                parent.layout();
            }
        });

        /* dynamic resizing of the sash area */
        final int limit = 40;
        sash.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event e) {
                Rectangle sashRect = sash.getBounds();
                Rectangle shellRect = parent.getClientArea();
                int right = shellRect.width - sashRect.width - limit;
                e.x = Math.max(Math.min(e.x, right), limit);

                if ((shellRect.width - e.x - sashWidthoffset) < 0) {/*check the minimum size*/
                    e.x = shellRect.width - graphAreaWidht - sashWidthoffset;
                }

                if (e.x != sashRect.x) {
                    sashFormData.left.offset = e.x;
                    parent.layout();
                }
            }
        });

        return parent;
    }

    /**
     * Creates page: SourceCode View
     */
    protected void createSourceCodeTab() {
        try {
            sourceCodeViewerComposite = new Composite(getTabFolder(), SWT.NONE);
            sourceCodeViewerComposite.setLayout(new FillLayout());

            IEditorInput sourceCodeViewerInput = getSourceCodeViewerInput();

            if (sourceCodeViewerInput instanceof IFileEditorInput) {

                /* a local class file */
                IFileEditorInput fileEditorInput = (IFileEditorInput) sourceCodeViewerInput;
                IFile file = fileEditorInput.getFile();
                IProject project = file.getProject();

                /* create java project */
                IJavaProject javaProject = JavaCore.create(project);

                try {
                    IPath wspacePath = file.getFullPath();
                    IPath outputDir = javaProject.getOutputLocation();

                    IPath classToFind = null;
                    if (outputDir.matchingFirstSegments(wspacePath) == outputDir.segmentCount()) {
                        /* if we are in the output directory
                         * strip the output directory 
                         * as we want the project relative path */
                        classToFind = wspacePath.removeFirstSegments(outputDir.segmentCount());
                    }

                    if (classToFind != null) {
                        classToFind = classToFind.removeFileExtension();
                        String typeToFind = classToFind.toString();

                        int indx = typeToFind.indexOf('$');
                        if (indx != -1) {
                            typeToFind = typeToFind.substring(0, indx);
                        }

                        typeToFind = typeToFind.replace(IPath.SEPARATOR, '.');

                        sourceCodeViewer = new JavaSourceCodeViewer();

                        IType t = javaProject.findType(typeToFind);
                        if (t != null) {

                            /* create file input */
                            IFile sourceFile = (IFile) t.getCompilationUnit().getResource();
                            IEditorInput input = new FileEditorInput(sourceFile);

                            sourceCodeViewer.init(getEditorSite(), input);
                        }
                    } else {
                        /* try with class file viewer */
                        sourceCodeViewer = new ClassFileSourcecodeViewer();
                        sourceCodeViewer.init(getEditorSite(), sourceCodeViewerInput);
                    }

                } catch (JavaModelException e) {

                    String msg = MessageFormat.format(CoreMessages.ERROR_Cannot_get_Sourcecode,
                            new Object[] { fileEditorInput.getName() });

                    BytecodeVisualizerPlugin
                            .log(new Status(IStatus.WARNING, BytecodeVisualizerPlugin.PLUGIN_ID, msg, e));

                    /* try with class file viewer */
                    sourceCodeViewer = new ClassFileSourcecodeViewer();
                    sourceCodeViewer.init(getEditorSite(), sourceCodeViewerInput);
                }

            } else {
                sourceCodeViewer = new ClassFileSourcecodeViewer();
                sourceCodeViewer.init(getEditorSite(), sourceCodeViewerInput);
            }

            sourceCodeViewer.addClassFileEditorReference(this);

            /* 
             * hook the editor part. It is necessary for initialization of
             * actions: Toggle Breakpoint, Enable Breakpoint ...
             */
            PartSite p = (PartSite) getSite();
            p.setPart((IWorkbenchPart) sourceCodeViewer);

            sourceCodeViewer.createPartControl(sourceCodeViewerComposite);

            p.setPart(this); /* set the bytecode visualzer part */

            /* create item for page only after createPartControl has succeeded */
            int i = addPage(sourceCodeViewerComposite);
            setPageText(i, BytecodeVisualizerMessages.BytecodeEditor_tab_Source);

            CTabItem item = getItem(i);
            Image img = WorkbenchImages.getImage(ISharedImages.IMG_OBJ_FILE);
            item.setImage(img);

        } catch (PartInitException e) {
            Messages.error(CoreMessages.ERROR_CreateNested_Editor + CoreMessages.ExceptionAdditionalMessage);
            BytecodeVisualizerPlugin.log(BytecodeVisualizerPlugin.createErrorStatus(e.getMessage(), e));
        }
    }

    /**
    * Creates the SWT controls for this editor.
    * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
    */
    public void createSuperPartControl(final Composite parent) {
        this.parent = parent;

        /* init preferences */
        String s = CorePlugin.getDefault().getPreferenceStore()
                .getString(CorePreferenceConstants.GRAPH_PANEL_LOCATION);
        if (s.equals(CorePreferenceConstants.GRAPH_PANEL_LOCATION_SEPARATE_VIEW)) {
            showGraphInSeparateView = true;
        } else if (s.equals(CorePreferenceConstants.GRAPH_PANEL_LOCATION_EDITOR)) {
            showGraphInSeparateView = false;
        } else {
            showGraphInSeparateView = false;
        }

        /* create content*/
        if (showGraphInSeparateView) {
            createPartControlWithGraphOutline(parent);
        } else {
            createPartControlWithSach(parent);
        }

        /* disable folding */
        final ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
        if (viewer != null) {
            if (viewer.isProjectionMode())
                viewer.doOperation(ProjectionViewer.TOGGLE);

            viewer.addProjectionListener(new IProjectionListener() {
                public void projectionDisabled() {
                    /* nothing to do */
                }

                public void projectionEnabled() {
                    viewer.doOperation(ProjectionViewer.TOGGLE);
                }
            });
        }

    }

    /**
     * Creates an empty container. Creates a CTabFolder with no style bits set,
     * and hooks a selection listener which calls <code>pageChange()</code>
     * whenever the selected tab changes.
     * 
     * @param parent
     *            The composite in which the container tab folder should be
     *            created; must not be <code>null</code>.
     * @return a new container
     */
    private CTabFolder createTabFolder(Composite parent) {
        /* 
         * use SWT.FLAT style so that an extra 1 pixel border is not reserved
         * inside the folder 
         */
        final CTabFolder result = new CTabFolder(parent, SWT.BOTTOM | SWT.FLAT);
        result.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                int newPageIndex = result.indexOf((CTabItem) e.item);
                pageChange(newPageIndex);
            }
        });
        return result;
    }

    /*
     * @see IWorkbenchPart#dispose()
     * @since 2.0
     */
    public void dispose() {
        super.dispose();

        BytecodeVisualizerPlugin.getDefault().getPreferenceStore()
                .removePropertyChangeListener(reuseDebugPropertyChangeListener);

        /* remove preference store listener */
        if (store != null) {
            store.removePropertyChangeListener(preferenceListener);
        }

        JFaceResources.getFontRegistry().removeListener(preferenceListener);

    }

    /* (non-Javadoc)
     * @see com.drgarbage.classfile.render.intf.IDocumentUpdateListener#documentUpdated(com.drgarbage.classfile.render.intf.IClassFileDocument)
     */
    public void documentUpdated(IClassFileDocument classFileDocument) {
        if (canvasControlFlowGraph == null) {
            /* should never happen */
            return;
        }

        canvasControlFlowGraph.documentUpdated(classFileDocument);

        if (fOutlinePage != null) {
            fOutlinePage.setInput(byteCodeDocumentProvider.getClassFileOutlineElement());
        }

        if (operandStackViewPage != null) {
            operandStackViewPage.setInput(null);
        }
    }

    private void doHandleCursorPositionChanged() {
        IClassFileDocument doc = byteCodeDocumentProvider.getClassFileDocument();
        if (doc != null) {
            /* set selection in the outline*/
            int line = getSelectedLine();

            if (doc.isLineInMethod(line/* changed to 0-based */)) {
                IMethodSection m = byteCodeDocumentProvider.getClassFileDocument()
                        .findMethodSection(line/* changed to 0-based */);
                if (m != null) {
                    if (fOutlinePage != null) {
                        fOutlinePage.setSelection(m);
                    }

                    if (operandStackViewPage != null) {
                        operandStackViewPage.setInput(m);
                    }

                    updateLineSectionListener(line/* changed to 0-based */, m);
                    return;
                }
            }

            if (doc.isLineInField(line/* changed to 0-based */)) {
                IFieldSection f = byteCodeDocumentProvider.getClassFileDocument()
                        .findFieldSection(line /* changed to 0-based */);
                if (f != null) {
                    if (fOutlinePage != null) {
                        fOutlinePage.setSelection(f);
                    }

                    /* set input null for operand stack if the line not in the method */
                    if (operandStackViewPage != null) {
                        operandStackViewPage.setInput(null);
                    }

                    updateLineSectionListener(line/* changed to 0-based */, f);
                    return;
                }
            }

            /* select class */
            if (fOutlinePage != null) {
                fOutlinePage.setSelection(doc);
            }

            /* set input null for operand stack if the line not in the method */
            if (operandStackViewPage != null) {
                operandStackViewPage.setInput(null);
            }

            updateLineSectionListener(line/* changed to 0-based */, doc);
        }

    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.texteditor.AbstractTextEditor#doRestoreState(org.eclipse.ui.IMemento)
     */
    protected void doRestoreState(IMemento memento) {
        /* FIX: initialization after restoring the workspace */
        activateBytecodeTab();

        setHandleCursorPositionChanged(true);
        super.doRestoreState(memento);
    }

    private boolean setNewInput(IEditorInput input) {
        if (input instanceof IFileEditorInput) {

            /* a local class file */
            IFileEditorInput fileEditorInput = (IFileEditorInput) input;
            IFile file = fileEditorInput.getFile();
            IProject project = file.getProject();

            /* create java project */
            IJavaProject javaProject = JavaCore.create(project);

            /* get class path */
            try {

                IPath projectPath = file.getProjectRelativePath();

                /* remove the source folder segment */
                IPath sourceFolder = projectPath.removeFirstSegments(1);

                IJavaElement javaElement = javaProject.findElement(sourceFolder);
                if (javaElement instanceof ICompilationUnit) {
                    ICompilationUnit unit = (ICompilationUnit) javaElement;

                    List<String> classList = new ArrayList<String>();

                    IType[] types = unit.getTypes();
                    for (IType t : types) {
                        ClassFileDocumentsUtils.collectNestedClasses(t, classList);
                    }

                    /* 
                     * If the compilation unit includes more than one class 
                     * declaration, ask the user to select a class to be opened.
                     */
                    String className = "";
                    if (classList.size() > 1) {
                        StringBuffer msg = new StringBuffer(
                                BytecodeVisualizerMessages.SourceContainsSeveralClassDefinitions);
                        msg.append(JavaLexicalConstants.NEWLINE);
                        msg.append(BytecodeVisualizerMessages.SelectClassToVisualize);
                        className = Messages.openSelectDialog(msg.toString(),
                                JavaPluginImages.get(JavaPluginImages.IMG_OBJS_CLASS), classList);
                        if (className == null) {
                            return false;
                        }
                    } else {
                        if (classList.size() == 1) {
                            className = classList.get(0);
                        } else {
                            return false;
                        }
                    }

                    String[] classPath = JavaRuntime.computeDefaultRuntimeClassPath(javaProject);

                    String packageName = ClassFileDocumentsUtils.getPackageNameFromCompilationUnit(unit);
                    File f = JavaLangUtils.findFileResource(classPath, packageName, className);
                    IPath classFilePath = new Path(f.getAbsolutePath());

                    /* make path relative /<project>/<bin folder>/<package>/<class> */
                    IPath workspace = project.getWorkspace().getRoot().getLocation();
                    classFilePath = classFilePath.removeFirstSegments(workspace.segmentCount());

                    /* Find the resource and set the new editor input */
                    final IFile classFile = ResourcesPlugin.getWorkspace().getRoot().getFile(classFilePath);
                    doSetInput(new FileEditorInput(classFile));
                }

                return true;

            } catch (CoreException e) {
                BytecodeVisualizerPlugin.log(e);
                return false;

            } catch (IOException e) {
                BytecodeVisualizerPlugin.log(e);
                return false;
            }

        }

        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#doSetInput(org.eclipse.ui.IEditorInput)
     */
    @SuppressWarnings("restriction")
    protected void doSetInput(IEditorInput input) throws CoreException {

        /* 
         * Check if the user has selected a source file (*.java).
         * If the source is a compilation unit look for the 
         * corresponding classes in the 'bin' folder of the 
         * project and create a new input to open a class file
         * instead of the source.
         */
        if (input.getName().toLowerCase().endsWith(".java")) {
            String msg = MessageFormat.format(BytecodeVisualizerMessages.OpenClassfileInsteadOfSource,
                    new Object[] { input.getName() });

            if (Messages.openConfirm(msg)) {
                if (!setNewInput(input)) {
                    /* 
                     * If the user has rejected the action, 
                     * create a NullEditorInput.
                     */
                    super.doSetInput(new NullEditorInput());
                }
            } else {
                super.doSetInput(new NullEditorInput());
            }
            return;
        }

        super.doSetInput(input);

        if (sourceCodeViewer != null) {
            if (input instanceof IFileEditorInput) {
                //TODO: implement for local class file
                //The code may copied from createPageSourceView method
                //This case may probably only occur if the 
                //local source code of the class file is changed. 
            }
            if (input instanceof JDIEditorInput) {
                JDIEditorInput jdiEditorInput = (JDIEditorInput) input;
                sourceCodeViewer.doSetInputInternal(jdiEditorInput.getDelegate());
            } else {
                sourceCodeViewer.doSetInputInternal(input);
            }
        }

        if (sourceCodeViewer != null) {
            selectAndReveal(0, IClassFileEditor.INVALID_LINE);
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#doSetSelection(org.eclipse.jface.viewers.ISelection)
     */
    /* FIX: bug#84 Recursive attempt to create itself
     * FIX: restore selection */
    protected void doSetSelection(ISelection selection) {
        if (selection instanceof ITextSelection) {
            ITextSelection textSelection = (ITextSelection) selection;
            super.selectAndReveal(textSelection.getOffset(), textSelection.getLength());
            doHandleCursorPositionChanged();
        }
    }

    /**
     * Returns the index of the currently active page, or -1 if there is no
     * active page.
     * <p>
     * Subclasses should not override this method
     * </p>
     * 
     * @return the index of the active page, or -1 if there is no active page
     */
    public int getActiveTabIndex() {
        CTabFolder tabFolder = getTabFolder();
        if (tabFolder != null && !tabFolder.isDisposed()) {
            return tabFolder.getSelectionIndex();
        }
        return -1;
    }

    /* (non-Javadoc)
     * @see com.drgarbage.bytecodevisualizer.core.editors.ClassFileEditor#getAdapter(java.lang.Class)
     */
    public Object getAdapter(Class required) {
        if (IContentOutlinePage.class.equals(required)) {
            if (fOutlinePage == null) {
                fOutlinePage = createBytecodeVisualizerOutlinePage();
                fOutlinePage.addSelectionChangedListener(outlineListener);
            }
            return fOutlinePage;
        } else if (IControlFlowGraphViewPage.class.equals(required)) {
            Object o = createGraphControlFlowViewPage();
            updateOutlineGraphView();
            return o;
        } else if (IToggleBreakpointsTarget.class.equals(required)) {
            if (getActiveTabIndex() == TAB_INDEX_BYTECODE) {
                return new ToggleBytecodeBreakpointAdapter(isBytecodeDebugSupported());
            } else if (getActiveTabIndex() == TAB_INDEX_SOURCE) {
                return new ToggleBytecodeSourceBreakpointAdapter();
            }
        } else if (OperandStackViewPage.class.equals(required)) {
            if (operandStackViewPage == null) {
                operandStackViewPage = new OperandStackViewPageIml();
                operandStackViewPage.setEditor(this);
            }
            return operandStackViewPage;
        }

        return super.getAdapter(required);
    }

    public IEditorInput getBytecodeEditorInput() {
        return super.getEditorInput();
    }

    /**
     * Return canvas of the control flow graph.
     * @return the canvasControlFlowGraph
     */
    public ControlFlowGraphCanvas getCanvasControlFlowGraph() {
        return canvasControlFlowGraph;
    }

    /* (non-Javadoc)
     * @see com.drgarbage.bytecodevisualizer.core.editors.IClassFileEditor#getClassFileEditor()
     */
    public BytecodeEditor getClassFileEditor() {
        return this;
    }

    /**
     * @param textSelection
     * @return class name as a string
     */
    protected String getClassName(TextSelection textSelection) {

        String text = null;

        IWorkbenchPage page = getEditorSite().getPage();
        IViewPart view = page.findView("org.eclipse.ui.console.ConsoleView");

        if (view instanceof IConsoleView) {
            IConsoleView cView = (IConsoleView) view;
            IConsole console = cView.getConsole();

            if (console instanceof TextConsole) {
                TextConsole textConsole = (TextConsole) console;
                text = textConsole.getDocument().get();

            }
        }

        /* Get class.method string */

        /* find end */
        int endIndex = 0;
        for (int i = textSelection.getOffset(); i > 0; i--) {
            if (text.charAt(i) == '(') {
                endIndex = i;
                break;
            }
        }

        /* find start */
        int beginIndex = 0;
        char ch[] = new char[3];
        for (int i = endIndex; i > 2; i--) {
            text.getChars(i - 3, i, ch, 0);
            if (ch[0] == 'a' && ch[1] == 't' && ch[2] == ' ') {
                beginIndex = i;
                break;
            }
        }

        text = text.substring(beginIndex, endIndex);

        /* separate class name and method name */
        endIndex = text.lastIndexOf('.');

        String className = text.substring(0, endIndex);

        if (className != null) {
            return className.trim();
        }

        BytecodeVisualizerPlugin.log(new Status(IStatus.ERROR, BytecodeVisualizerPlugin.PLUGIN_ID,
                CoreMessages.CLASS_NAME_NOT_RESOLVED));

        return null;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#getCorrespondingElement(org.eclipse.jdt.core.IJavaElement)
     */
    @Override
    protected IJavaElement getCorrespondingElement(IJavaElement element) {
        /* nothing to do */
        return null;
    }

    /* bug#91 NullPointerException if license has been expired. */
    private JavaEditor getEditor() {
        return this;
    }

    @Override
    public IEditorInput getEditorInput() {
        return getBytecodeEditorInput();
    }

    /* (non-Javadoc)
     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#getElementAt(int)
     */
    @Override
    protected IJavaElement getElementAt(int offset) {
        /* nothing to do */
        return null;
    }

    private int getIndexOfSelectedFrame(IJavaStackFrame selectedFrame) throws DebugException {
        IThread thread = selectedFrame.getThread();
        if (thread.hasStackFrames()) {
            IStackFrame s[] = thread.getStackFrames();
            for (int i = 0; i < s.length; i++) {
                if (s[i].equals(selectedFrame)) {
                    return i;
                }
            }
        }

        return -1;
    }

    /**
     * Returns the tab item for the given page index (page index is 0-based).
     * The page index must be valid.
     * 
     * @param pageIndex
     *            the index of the page
     * @return the tab item for the given page index
     */
    private CTabItem getItem(int pageIndex) {
        return getTabFolder().getItem(pageIndex);
    }

    /**
     * Returns the outline page of the editor.
     * @return outline
     */
    public BytecodeOutlinePage getOutlinePage() {
        return fOutlinePage;
    }

    /**
     * Returns the number of pages in this multi-page editor.
     * 
     * @return the number of pages
     */
    protected int getPageCount() {
        CTabFolder folder = getTabFolder();
        /* May not have been created yet, or may have been disposed. */
        if (folder != null && !folder.isDisposed()) {
            return folder.getItemCount();
        }
        return 0;
    }

    /**
     * Returns parent composite.
     * @return the parent
     */
    public Composite getParent() {
        return parent;
    }

    /**
     * Returns the 0-based number of the line currently selected
     * in the text editor.
     * @return the 0-based selected line
     */
    public int getSelectedLine() {
        ISourceViewer sourceViewer = this.getSourceViewer();
        if (sourceViewer == null) {
            return ByteCodeConstants.INVALID_LINE;
        }

        /* point.x is offset */
        org.eclipse.swt.graphics.Point selectedRange = sourceViewer.getSelectedRange();

        int line = ByteCodeConstants.INVALID_LINE;

        IDocument document = byteCodeDocumentProvider.getDocument(getEditorInput());
        if (document != null) {
            try {
                /* changed to 0-based */
                line = document.getLineOfOffset(selectedRange.x);

            } catch (BadLocationException e) {
                BytecodeVisualizerPlugin
                        .log(new Status(IStatus.ERROR, BytecodeVisualizerPlugin.PLUGIN_ID, e.getMessage(), e));
            }
        }

        activateGraphFactoryAction(line);

        return line;
    }

    /**
     * Returns the source line number.
     * @param textSelection
     * @return source line number
     */
    protected int getSourceCodeLine(TextSelection textSelection) {

        String text = null;

        IWorkbenchPage page = getEditorSite().getPage();
        IViewPart view = page.findView("org.eclipse.ui.console.ConsoleView");

        if (view instanceof IConsoleView) {
            IConsoleView cView = (IConsoleView) view;
            IConsole console = cView.getConsole();

            if (console instanceof TextConsole) {
                TextConsole textConsole = (TextConsole) console;
                text = textConsole.getDocument().get();

            }
        }

        /* find start */
        int beginIndex = 0;
        for (int i = textSelection.getOffset(); i > 0; i--) {
            if (text.charAt(i) == '(') {
                beginIndex = i;
                break;
            }
        }

        /* find end */
        int endIndex = text.length();
        for (int i = textSelection.getOffset(); i < text.length(); i++) {
            if (text.charAt(i) == ')') {
                endIndex = i;
                break;
            }
        }

        String linkText = text.substring(beginIndex, endIndex);

        /* Get Line Number from the link string */
        int index = linkText.lastIndexOf(':');
        if (index >= 0) {
            String numText = linkText.substring(index + 1);
            index = numText.indexOf(')');
            if (index >= 0) {
                numText = numText.substring(0, index);
            }
            try {
                return Integer.parseInt(numText);
            } catch (NumberFormatException e) {
                BytecodeVisualizerPlugin
                        .log(new Status(IStatus.ERROR, BytecodeVisualizerPlugin.PLUGIN_ID, e.getMessage(), e));
            }
        }

        BytecodeVisualizerPlugin.log(new Status(IStatus.ERROR, BytecodeVisualizerPlugin.PLUGIN_ID,
                CoreMessages.ERROR_LINE_NUMBER_NOT_FOUND_IN_SELECTED_TEXT));

        return IClassFileEditor.INVALID_LINE;
    }

    /**
     * Returns a reference to the sourcecode viwer interface.
     * @return  sourceCodeViewer
     */
    public ISourceCodeViewer getSourceCodeViewer() {
        return sourceCodeViewer;
    }

    public IEditorInput getSourceCodeViewerInput() {
        IEditorInput result = super.getEditorInput();
        if (result instanceof JDIEditorInput) {
            return ((JDIEditorInput) result).getDelegate();
        } else {
            return result;
        }
    }

    /**
     * Returns the tab folder containing this multi-page editor's pages.
     * 
     * @return the tab folder, or <code>null</code> if
     *         <code>createPartControl</code> has not been called yet
     */
    private CTabFolder getTabFolder() {
        return tabFolder;
    }

    public ToggleBytecodeBreakpointAction getToggleBytecodeBreakpointAction() {
        if (toggleBytecodeBreakpointAction == null) {
            toggleBytecodeBreakpointAction = new ToggleBytecodeBreakpointAction(this, null, getVerticalRuler());
        }
        return toggleBytecodeBreakpointAction;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#gotoMarker(org.eclipse.core.resources.IMarker)
     */
    /** @deprecated visibility will be reduced, use <code>getAdapter(IGotoMarker.class) for accessing this method</code> */
    public void gotoMarker(IMarker marker) {//TODO: use getAdapter instead of this method 
        /* synchronize source code view */
        if (sourceCodeViewer != null) {
            sourceCodeViewer.gotoMarker(marker);
            /* activate source code view */
            if (getActiveTabIndex() != TAB_INDEX_SOURCE) {
                activateSourceCodeTab();
            }
        } else {
            super.gotoMarker(marker);
        }
    }

    /* (non-Javadoc)
     * @see com.drgarbage.bytecodevisualizer.core.editors.ClassFileEditor#handleCursorPositionChanged()
     */
    protected void handleCursorPositionChanged() {
        if (handleCursorPositionChanged) {
            super.handleCursorPositionChanged();
            doHandleCursorPositionChanged();
        }
    }

    /*
     * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
     */
    protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
        /* disable default handling because of ClassCast Exception 
         * JavaEditor.handlePreferenceStoreChanged() uses cast
         * ((JavaSourceViewerConfiguration)getSourceViewerConfiguration()).handlePropertyChangeEvent(event);
         */

        handlePreferenceStoreChangedX(event);
    }

    /**
     * A wrapper for handling of property changes.
     * @param event
     */
    private void handlePreferenceStoreChangedX(PropertyChangeEvent event) {

        if (AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER.equals(event.getProperty())) {
            IColumnSupport columnSupport = (IColumnSupport) getAdapter(IColumnSupport.class);
            RulerColumnDescriptor lineNumberColumnDescriptor = RulerColumnRegistry.getDefault()
                    .getColumnDescriptor(LineNumberColumn.ID);
            if (isLineNumberRulerVisible()) {
                if (lineNumberColumnDescriptor != null) {
                    columnSupport.setColumnVisible(lineNumberColumnDescriptor, true);
                }
            } else if (!isLineNumberRulerVisible()) {
                if (lineNumberColumnDescriptor != null) {
                    columnSupport.setColumnVisible(lineNumberColumnDescriptor, true);
                }
            }
        }
    }

    /*
     * @see IEditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
     */
    public void init(final IEditorSite site, final IEditorInput input) throws PartInitException {
        super.init(site, input);

        store = createCombinedPreferenceStore(input);
        setPreferenceStore(store);
        JavaTextTools textTools = JavaPlugin.getDefault().getJavaTextTools();
        final IColorManager colorManager = textTools.getColorManager();
        final ClassFileConfiguration classFileConfiguration = new ClassFileConfiguration(colorManager, store, this,
                IJavaPartitions.JAVA_PARTITIONING);
        setSourceViewerConfiguration(classFileConfiguration);

        /* create preference property listener */
        preferenceListener = new IPropertyChangeListener() {

            public void propertyChange(PropertyChangeEvent event) {
                //System.out.println("event=" + event.getProperty()); //TODO: log for debuging

                /* Text Editor current line selector */
                if (event.getProperty()
                        .equals(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR)) {
                    RGB rgb = PreferenceConverter.getColor(getPreferenceStore(),
                            AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR);
                    Color c = getSharedColors().getColor(rgb);
                    if (!canvasControlFlowGraph.getLineSelectorColor().equals(c)) {
                        canvasControlFlowGraph.setLineSelectorColor(c);
                    }
                }
                /* Text Editor background */
                else if (event.getProperty().startsWith(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND)) {
                    setControlFlowViewBackGround();
                }
                /* figure colors */
                else if (event.getProperty().startsWith(CorePreferenceConstants.GRAPH_COLOR_PREFIX)) {
                    canvasControlFlowGraph.documentUpdated(byteCodeDocumentProvider.getClassFileDocument());
                }
                /* text fond has been changed (size and Fonts)*/
                else if (event.getProperty().equals(JFaceResources.TEXT_FONT)) {
                    /*
                     * Hack: The default handler has a bug.
                     * The JavaPlugin.getDefault().getPreferenceStore() is not updated synchronously.
                     * This code copy the new font value to the default preference store.  
                     */
                    Font f = JFaceResources.getTextFont();
                    FontData data = f.getFontData()[0];
                    //System.out.println(data); //TODO: Log for debuging
                    JavaPlugin.getDefault().getPreferenceStore().setValue(event.getProperty(), data.toString());

                    /* 
                     * Set new font in the text widget. The font will be overwriten later with
                     * the same value. But we have to set font to calculate the line heght.
                     */
                    getSourceViewer().getTextWidget().setFont(f);
                    int h = getSourceViewer().getTextWidget().getLineHeight();
                    canvasControlFlowGraph.setLineHight(h);

                    /* update control flow graph figure */
                    canvasControlFlowGraph.documentUpdated(byteCodeDocumentProvider.getClassFileDocument());
                }
                /* Bytecode Mnemonics */
                else if (event.getProperty().startsWith(bytecodeMnemonicPreferencesPrefix)) {
                    classFileConfiguration.adaptToPreferenceChange(event);
                    getSourceViewer().invalidateTextPresentation();

                }
                /* Syntax and Coloring */
                else if (event.getProperty().startsWith("java_")) {
                    classFileConfiguration.adaptToPreferenceChange(event);
                    getSourceViewer().invalidateTextPresentation();
                }
                /* classfile attributes */
                //            else if(event.getProperty().startsWith(BytecodeVizualizerPreferenceConstants.classFileAttributePreferencesPrefix)){            
                //               //Do not support. The document has to be reloaded.
                //            }            
                else {
                    /* other references which are not matched befor */
                    //System.out.println("event=" + event.getProperty());//TODO: log
                }
            }
        };

        /* add preference store listener */
        store.addPropertyChangeListener(preferenceListener);

        /* add listener */
        JFaceResources.getFontRegistry().addListener(preferenceListener);
    }

    /*
     * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#initializeEditor()
     */
    protected void initializeEditor() {
        /* deactivate default initialization */
        //super.initializeEditor();
    }

    public boolean isBytecodeDebugSupported() {
        IEditorInput input = getBytecodeEditorInput();

        if (input instanceof IClassFileEditorInput) {
            return true;
        } else {
            return false;
        }

    }

    /**
     * Returns true if the control flow graph view is visible,
     * otherwise false.
     * @return true or false
     */
    private boolean isControlFlowgraphViewVisible() {
        IWorkbenchWindow workbench = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
        if (workbench == null) {
            return false;
        }
        IWorkbenchPage page = workbench.getActivePage();
        if (page != null) {
            IViewReference[] views = page.getViewReferences();
            for (IViewReference ref : views) {
                if (ref.getId().equals(CoreConstants.CONTROL_FLOW_VIEW_ID)) {
                    IViewPart viewPart = ref.getView(false);
                    if (viewPart instanceof ControlFlowGraphView) {
                        ControlFlowGraphView cfgView = (ControlFlowGraphView) viewPart;
                        return cfgView.getCurrentPage().getControl().isVisible();
                    }
                }
            }
        }

        return false;
    }

    /* (non-Javadoc)
     * @see com.drgarbage.bytecodevisualizer.core.editors.ClassFileEditor#isGraphViewVisible()
     */
    public boolean isGraphViewVisible() {
        if (getActiveTabIndex() == TAB_INDEX_BYTECODE) {
            return true;
        } else if (getActiveTabIndex() == TAB_INDEX_SOURCE) {
            return false;
        }

        /* default */
        return false;
    }

    /* (non-Javadoc)
     * @see com.drgarbage.bytecodevisualizer.editors.ISynchronizable#isHandleCursorPositionChanged()
     */
    public boolean isHandleCursorPositionChanged() {
        return handleCursorPositionChanged;
    }

    /**
     * Returns whether quick diff info should be visible upon opening an editor. 
     * Always returns <code>false</code> in this implementation 
     *
     * @return always <code>false</code>
     */
    protected boolean isPrefQuickDiffAlwaysOn() {
        return false;
    }

    /**
     * Flag if the control flow graph panel has to be shown in the outline view.
     * @return the showGraphInOutline
     */
    public boolean isShowGraphInSeparateView() {
        return showGraphInSeparateView;
    }

    /**
     * Returns true if the source code is displayed by this viewer, 
     * otherwise false. 
     * @return true or false
     */
    public boolean isSourceCodeLoaded() {
        return sourceCodeViewer != null && sourceCodeViewer.isSourceCodeLoaded();
    }

    /**
     * Page changed by mouse click.
     */
    protected void pageChange(int newPageIndex) {

        if (newPageIndex == TAB_INDEX_BYTECODE) {

            updateOutlineGraphView();

            sourceCodeViewer.setHandleCursorPositionChanged(false);
            setHandleCursorPositionChanged(true);

        } else if (newPageIndex == TAB_INDEX_SOURCE) {

            updateOutlineGraphView();

            sourceCodeViewer.setHandleCursorPositionChanged(true);
            setHandleCursorPositionChanged(false);

            //TODO: the following probably needs to be fixed
            /* if the debugger is active */
            if (DebugUITools.getDebugContext() != null) {
                Object o = DebugUITools.getDebugContext();

                /* the object is null if the debugger is not active */
                if (o instanceof JDIStackFrame) {
                    JDIStackFrame stackFrame = (JDIStackFrame) o;
                    int line = -1;
                    try {
                        line = stackFrame.getLineNumber() - 1;
                    } catch (DebugException e) {

                        e.printStackTrace();
                        BytecodeVisualizerPlugin.log(e);
                    }
                    sourceCodeViewer.selectSourceCodeLine(line, false); /* adapted to 0-based */
                }
            }

        }

        if (actionContributor != null)
            actionContributor.pageChanged(newPageIndex);

    }

    /**
     * Removes changed line selection listener. 
     */
    public void removeLineSelectionListener(IClassFileEditorSelectionListener listener) {
        lineSelectionListener.remove(listener);
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.texteditor.AbstractTextEditor#selectAndReveal(int, int)
     */
    public void selectAndReveal(int start, int length) {
        selectAndRevealBytecode(start, length);
    }

    public void selectAndRevealBytecode(int start, int length) {
        super.selectAndReveal(start, length);
    }

    /**
     * Selects and reveals the specified ranges in this text editor.
     * The original method is used for debugging.
     * @deprecated
     */
    public void selectAndRevealOrigLine(int start, int length) {
        super.selectAndReveal(start, length);
    }

    public void selectAndRevealSourceCode(int start, int length) {
        if (sourceCodeViewer != null) {
            sourceCodeViewer.selectAndReveal(start, length);
        }
    }

    /**
     * Select a line from the stack trace.
     * @param start
     * @param length
     */
    public boolean selectAndRevealStackTrace(int start, int length) {

        /* TODO: Select JAva Stack not supported if debugging is running */
        if (DebugUITools.getDebugContext() == null && length != IClassFileEditor.INVALID_LINE) {

            /* 
             * FIX: bug#56
             * Check if the StackTrace has been selected.  
             */
            IWorkbenchPage page = getEditorSite().getPage();
            ISelection pageSel = page.getSelection("org.eclipse.ui.console.ConsoleView");

            /* if pageSel not null then the StackTrace selection is running */
            if (pageSel instanceof TextSelection) {
                TextSelection textPagesel = (TextSelection) pageSel;

                /* check class name */
                String className = getClassName(textPagesel);
                String typeName = byteCodeDocumentProvider.getClassFileDocument().getClassName();
                if (!className.equals(typeName)) {
                    startEditorForAnonymousClassAndReval(className);

                    /* OK return method */
                    return true;
                }

                int line = getSourceCodeLine(textPagesel) - 1; /* 0-based line number */

                if (line == IClassFileEditor.INVALID_LINE) {
                    BytecodeVisualizerPlugin.log(new Status(IStatus.ERROR, BytecodeVisualizerPlugin.PLUGIN_ID,
                            BytecodeVisualizerMessages.Error_not_find_line));
                    return false;
                }

                if (sourceCodeViewer.isSourceCodeLoaded()) {
                    sourceCodeViewer.selectSourceCodeLine(line, true);

                    IJavaElement element = sourceCodeViewer.getCurrentSelectedElement();
                    if (element != null) {
                        setSelection(element, line + 1, true);
                    }
                } else {
                    /* selects the byte code line if the lineNumberTable is available */
                    int sourceCodeLine = line;

                    /* resolve sourceCodeLine into the ByteCodeLine */
                    List<IMethodSection> methods = byteCodeDocumentProvider.getClassFileDocument()
                            .getMethodSections();

                    int bytecodeLine = resolveLineNumberIntoBytecode(methods, sourceCodeLine + 1);
                    if (bytecodeLine != ByteCodeConstants.INVALID_OFFSET) {
                        selectLineAndReveal(bytecodeLine - 1); /* convert to 0-based lines */
                    } else {
                        //TODO: implement handler.
                    }

                    return true;
                }
            } else { /* simple selection, should never happen */
                sourceCodeViewer.selectAndReveal(start, length);
            }

        }

        return false;
    }

    /**
     * Selects the given line and revaluate visible position.
     * @param bytecodeDocumentLine the line number of the bytecode document
     * @param elementName 
     * @param elementType the element type one of {@link IJavaElement IJavaElement.CLASS_FILE},
     *       {@link IJavaElement IJavaElement.FIELD} or {@link IJavaElement IJavaElement.METHOD}.
     * @see IJavaElement
     */
    public void selectBytecodeLineAndReveal(int bytecodeDocumentLine, String elementName, int elementType) {
        IDocument document = byteCodeDocumentProvider.getBytecodeDocument(getBytecodeEditorInput());
        try {
            /* get line information */
            IRegion region = document.getLineInformation(bytecodeDocumentLine);
            int lineStartOffset = region.getOffset();
            int lineLenght = region.getLength();
            String lineString = document.get(lineStartOffset, lineLenght);

            if (elementName == null) {
                super.selectAndReveal(lineStartOffset, 0);
            }

            int elementIndex, elementLength;
            switch (elementType) {
            case IJavaElement.CLASS_FILE:
                elementIndex = lineString.indexOf(" " + elementName + " {") + 1;
                break;
            case IJavaElement.FIELD:
                elementIndex = lineString.indexOf(" " + elementName + ";") + 1;
                break;
            case IJavaElement.METHOD:
                elementIndex = lineString.indexOf(" " + elementName + "(") + 1;
                break;
            default:
                elementIndex = 0;
                elementLength = 0;
            }

            /* name not found */
            if (elementIndex == 0) {
                elementLength = 0;
            } else {
                elementLength = elementName.length();
            }

            super.selectAndReveal(lineStartOffset + elementIndex, elementLength);

        } catch (BadLocationException e) {
            /*nothing to do */}
    }

    /**
     * Selects the given line.
     * @param line a 0-based number of the line to be selected. 
     */
    public void selectLine(int line) {

        ISourceViewer sourceViewer = this.getSourceViewer();
        if (sourceViewer == null) {
            return;
        }

        IDocument document = byteCodeDocumentProvider.getDocument(getEditorInput());
        try {
            int offset = document.getLineOffset(line);
            sourceViewer.setSelectedRange(offset, 0);

        } catch (BadLocationException e) {
            /*nothing to do */}
    }

    /**
     * Selects the line in the byte code document. 
     * @param line
     */
    public void selectLineAndRevaluate2(int line) {
        selectLineAndRevaluate2(line, false);
    }

    /**
     * Selects the line in the byte code document.
     * @param bytecodeLine
     * @param b true if the line has to be marked
     */
    public void selectLineAndRevaluate2(int bytecodeLine, boolean b) {
        IDocument document = byteCodeDocumentProvider.getBytecodeDocument(getBytecodeEditorInput());
        try {
            int offset = document.getLineOffset(bytecodeLine);
            ISourceViewer sourceViewer = this.getSourceViewer();

            if (sourceViewer == null)
                return;

            int len = 0;
            if (b) {
                len = document.getLineLength(bytecodeLine) - 1;
            }

            super.selectAndReveal(offset, len);

        } catch (BadLocationException e) {
            /*nothing to do */}
    }

    /**
     * Selects the given line and reval
     * @param bytecodeLine a 0-based number of the line to be selected. 
     */
    public void selectLineAndReveal(int bytecodeLine) {

        ISourceViewer sourceViewer = this.getSourceViewer();
        if (sourceViewer == null) {
            return;
        }

        IDocument document = byteCodeDocumentProvider.getBytecodeDocument(getBytecodeEditorInput());
        try {
            int offset = document.getLineOffset(bytecodeLine);
            int len = document.getLineLength(bytecodeLine);
            sourceViewer.revealRange(offset, len);
            sourceViewer.setSelectedRange(offset, len);

        } catch (BadLocationException e) {
            /*nothing to do */}
    }

    /**
     * Sets the currently active page.
     * 
     * @param pageIndex
     *            the index of the page to be activated; the index must be valid
     */
    protected void setActivePage(int pageIndex) {
        Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());
        getTabFolder().setSelection(pageIndex);
        pageChange(pageIndex);
    }

    /**
     * Gets the backroud color from preferencies and
     * sets it in the control flow graph view.
     */
    private void setControlFlowViewBackGround() {
        RGB rgb = PreferenceConverter.getColor(getPreferenceStore(),
                AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND);
        Color c = getSharedColors().getColor(rgb);
        canvasControlFlowGraph.setBackground(c);
    }

    /* (non-Javadoc)
     * @see com.drgarbage.bytecodevisualizer.editors.ISynchronizable#setHandleCursorPositionChanged(boolean)
     */
    public void setHandleCursorPositionChanged(boolean b) {
        handleCursorPositionChanged = b;
    }

    /**
     * Sets the text label for the page with the given index. The page index
     * must be valid. The text label must not be null.
     * 
     * @param pageIndex
     *            the index of the page
     * @param text
     *            the text label
     */
    protected void setPageText(int pageIndex, String text) {
        getItem(pageIndex).setText(text);
    }

    /* (non-Javadoc)
     * @see com.drgarbage.bytecodevisualizer.core.editors.ClassFileEditor#setSelection(org.eclipse.jdt.core.IJavaElement)
     */
    public void setSelection(IJavaElement element) {
        setSelection(element, IClassFileEditor.INVALID_LINE, false);

        /* synchronize source code view */
        if (sourceCodeViewer != null) {
            sourceCodeViewer.setSelection(element);
        }
    }

    /**
     * Selects the line for the given element:
     * - ClassFileSection
     * - MethodSection
     * - Variable
     * 
     * @param element
     * @param line
     * @param markLine true if the line has to be marked
     */
    public void setSelection(IJavaElement element, int line, boolean markLine) {

        if (element == null) {
            return;
        }

        switch (element.getElementType()) {
        case IJavaElement.FIELD: /* select field */
            String fieldName = element.getElementName();
            IFieldSection fieldSection = byteCodeDocumentProvider.getClassFileDocument()
                    .findFieldSection(fieldName);
            if (fieldSection != null) {
                selectBytecodeLineAndReveal(fieldSection.getBytecodeDocumentLine(), fieldName, IJavaElement.FIELD);
            }
            break;
        case IJavaElement.METHOD: /* select method */
            IMethod method = (IMethod) element;
            try {
                String methodName;
                if (method.isConstructor()) {
                    methodName = "<init>";
                } else {
                    methodName = method.getElementName();
                }

                String methodSignature = ClassFileDocumentsUtils.resolveMethodSignature(method);
                IMethodSection methodSection = byteCodeDocumentProvider.getClassFileDocument()
                        .findMethodSection(methodName, methodSignature);

                if (methodSection != null) {
                    if (line == IClassFileEditor.INVALID_LINE || line == IClassFileEditor.METHOD_DECLARATION_LINE) {

                        if (method.isConstructor()) {
                            methodName = method.getElementName();
                        }
                        selectBytecodeLineAndReveal(methodSection.getFirstLine(), methodName, IJavaElement.METHOD);
                    } else {
                        selectLineAndRevaluate2(methodSection.getBytecodeLine(line) - 1, markLine);
                    }
                    break;
                }

            } catch (JavaModelException e) {
                BytecodeVisualizerPlugin
                        .log(new Status(IStatus.ERROR, BytecodeVisualizerPlugin.PLUGIN_ID, e.getMessage(), e));
            }

        default:
            /* select class */
            IClassFileDocument doc = byteCodeDocumentProvider.getClassFileDocument();
            if (doc != null) {
                int docLine = doc.getClassSignatureDocumentLine();
                selectBytecodeLineAndReveal(docLine, element.getElementName(), IJavaElement.CLASS_FILE);
            }
        }

        /* call cursor hook */
        doHandleCursorPositionChanged();
    }

    /**
     * Starts an editor for the given nested or anonymous class 
     * of the current loaded class. The class name is a fully 
     * qualified name separated by '.'. For example: java.lang.String 
     * @param annonymousClassName
     */
    protected IEditorPart startEditorForAnonymousClassAndReval(String annonymousClassName) {

        IEditorPart result = null;

        IClassFileEditorInput classFileEditorInput = (IClassFileEditorInput) getEditorInput();

        /* get main class file from the edtor input */
        IClassFile origFile = classFileEditorInput.getClassFile();

        /* get package element*/
        IJavaElement packageElement = origFile.getParent();
        if (packageElement instanceof IPackageFragment) {
            IPackageFragment packageFragment = (IPackageFragment) packageElement;

            /* calculate the anonymous class name */
            String packageString = packageFragment.getElementName();
            String className = annonymousClassName
                    .subSequence(packageString.length() + 1, annonymousClassName.length()).toString() + ".class";

            /* get class from the package */
            IClassFile f = packageFragment.getClassFile(className);

            /* Open editor */
            try {

                if (fReuseEditor) {
                    IWorkbenchPage page = getEditorSite().getPage();

                    result = EditorUtility.isOpenInEditor(f);

                    /* activate the editor we want to reuse */
                    if (result != null) {
                        page.bringToTop(result);
                    } else { /* no editor open*/
                        if (isDirty() || page.isEditorPinned(this)) {
                            /* open a new editor */
                            result = EditorUtility.openInEditor(f, true);
                        } else if (this instanceof IReusableEditor) {
                            /* re-use editor */
                            page.reuseEditor((IReusableEditor) this, new InternalClassFileEditorInput(f));
                            if (!page.isPartVisible(result)) {
                                page.bringToTop(result);
                            }

                            return this;

                        } else {
                            // close editor, open a new one
                            result = EditorUtility.openInEditor(f, true);
                            page.closeEditor(this, false);
                        }

                    }
                } else {
                    result = EditorUtility.openInEditor(f, true);
                }

            } catch (PartInitException e) {
                BytecodeVisualizerPlugin
                        .log(new Status(IStatus.ERROR, BytecodeVisualizerPlugin.PLUGIN_ID, e.getMessage(), e));
            }
        }

        return result;
    }

    /**
     * Gets current line color from preferences and sets the it in the
     * control flow graph viewer.
     * @param the control flow graph viewer.
     */
    private void synchronizeCurrentLineColor(ControlFlowGraphCanvas controlFlowGraphCanvas) {
        RGB rgb = PreferenceConverter.getColor(getPreferenceStore(),
                AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR);
        Color c = getSharedColors().getColor(rgb);
        controlFlowGraphCanvas.setLineSelectorColor(c);
    }

    /**
     * Synchronisation of the line selection in the text editor and
     * the control flow graph view.
     * The following table represents the implementation of listeners.
     * 
     * <p><code>  Text Editor             |    Control Flow Graph Viewer </code></p>
     * <p><code>  ------------------------+----------------------------- </code></p>                      
     * <p><code>  update line selection  <---  Key Listener              </code></p>
     * <p><code>  update line selection  <---  Mouse Listener          </code></p>
     * <p><code>  SWT.Paint Listener     ---->  update line selection     </code></p>
     *  
     * @param the control object of the first view. (text editor)
     * @param the control object of the second view. (control flow graph view)
     * @param the control flow graph viewer.
     * @param the canvas of the control flow graph viewer.
     */
    private void synchronizeLineSelection(final StyledText textWidget,
            final ControlFlowGraphCanvas canvasControlFlowGraph) {

        final ScrollBar vBar1 = textWidget.getVerticalBar();
        //      final ScrollBar vBar2 = canvasControlFlowGraph.getVerticalBar();

        /* paint listener for the text editor view */
        textWidget.addPaintListener(new PaintListener() {

            public void paintControl(PaintEvent e) {
                if (canvasControlFlowGraph.isDisposed())
                    return;

                canvasControlFlowGraph.selectLine(getSelectedLine()/* changed to 0-based */);

                int y = vBar1.getSelection();

                /* 
                 * FIX: bug52 Graph View does not focus the proper row
                 * 
                 * Scroll and check if the line selection is visible 
                 * 
                 *    A    (A)+----------------+/\                                                    
                 *    |       |                |||                          
                 *    |       |                |==  - Scroll bar Position    
                 *   (H)      |                |||                          
                 *    |       (B)              |||                          
                 *    |   (h) |IIIIIIIIIIIIIIII|||  - Selected line         
                 *    |       |                |||                          
                 *    V       +----------------+\/                          
                 * 
                 *  (A) - ViewPort Position P_vp = (vp_x, vp_y), vp_x is always 0
                 *  (B) - Selected Line Position P_sl = (sl_x, sl_y)
                 *  (H) - Height of the ViewPort vp_h
                 *  (h) - Height of the line selector sl_h
                 */

                //            int vp_y = canvasControlFlowGraph.getViewport().getViewLocation().y ;
                //            int vp_h = canvasControlFlowGraph.getViewport().getClientArea().height;
                //            int sl_y = canvasControlFlowGraph.getSelectedLineLocation().y;
                //            int sl_h = canvasControlFlowGraph.getLineHight();
                //
                //            int viewPortBottom = vp_y + vp_h;
                //                        
                //            if(viewPortBottom - sl_h <  sl_y ){
                //               canvasControlFlowGraph.scrollSmoothTo(canvasControlFlowGraph.getHorizontalBar().getSelection(), sl_y - vp_h + sl_h );            
                //            }
                //            else{
                //               canvasControlFlowGraph.scrollSmoothTo(canvasControlFlowGraph.getHorizontalBar().getSelection(), y);
                //
                //               /* check after scroll if the line selector is visible */
                //               vp_y = canvasControlFlowGraph.getViewport().getViewLocation().y ;
                //               vp_h = canvasControlFlowGraph.getViewport().getClientArea().height;
                //               viewPortBottom = vp_y + vp_h;   
                //               sl_y = canvasControlFlowGraph.getSelectedLineLocation().y;
                //               if(viewPortBottom - sl_h <  sl_y){
                //                  canvasControlFlowGraph.scrollSmoothTo(canvasControlFlowGraph.getHorizontalBar().getSelection(), sl_y - vp_h + sl_h );                  
                //               }               
                //            }

                canvasControlFlowGraph.scrollSmoothTo(canvasControlFlowGraph.getHorizontalBar().getSelection(), y);

                /* by scrolling in the left window the canvas is not updated. 
                 * MAC OS specific correction. Not need for SWT 3.5 */
                canvasControlFlowGraph.getViewport().repaint();
            }

        });

        /* key listener for the control flow graph view */
        canvasControlFlowGraph.addKeyListener(new KeyListener() {

            public void keyPressed(KeyEvent e) {
                switch (e.keyCode) {
                case ARROW_UP: /* Up */
                {
                    StyledText widget = getSourceViewer().getTextWidget();
                    widget.invokeAction(ST.LINE_UP);
                    widget.redraw();
                    selectLine(getSelectedLine());
                    break;
                }
                case ARROW_DOWN: /* Down */
                {
                    StyledText widget = getSourceViewer().getTextWidget();
                    widget.invokeAction(ST.LINE_DOWN);
                    widget.redraw();
                    selectLine(getSelectedLine());
                    break;
                }
                }
            }

            public void keyReleased(KeyEvent e) {
                /* nothing to do */
            }

        });

        /* mouse listener for the control flow graph view */
        canvasControlFlowGraph.getRootFigure().addMouseListener(new MouseListener() {
            public void mouseDoubleClicked(MouseEvent me) {
                /* nothing to do */
            }

            public void mousePressed(MouseEvent me) {
                Point p = me.getLocation();
                int line = p.y / textWidget.getLineHeight();
                selectLine(line); /*  the line is 0-based */
            }

            public void mouseReleased(MouseEvent me) {
                /* nothing to do */
            }
        });
    }

    /**
     * Synchronization of scroll bars in the left and right views.
     * @param the control object of the first view. (text editor)
     * @param the control object of the second view. (control flow graph view)
     */
    private void synchronizeScrollBars(final StyledText textWidget, final FigureCanvas controlFlowGraphCanvas) {
        /* Synchronize scroll bars */
        //final ScrollBar vBar1 = textWidget.getVerticalBar();
        final ScrollBar vBar2 = controlFlowGraphCanvas.getVerticalBar();

        /* 
         * The listener for left scroll bar. 
         * The right scroll bar is synchronized by the paint listener. 
         */
        SelectionListener listener2 = new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                //int y =  vBar2.getSelection() * (vBar1.getMaximum() - vBar1.getThumb()) / Math.max(1, vBar2.getMaximum() - vBar2.getThumb());
                int y = vBar2.getSelection();

                textWidget.setTopPixel(y);

                /* FIX: bug#41 Synchronization of Debug Current Instruction Pointer and Graph is broken */
                getVerticalRuler().update();
            }
        };

        vBar2.addSelectionListener(listener2);
    }

    /* (non-Javadoc)
     * @see com.drgarbage.bytecodevisualizer.core.editors.ClassFileEditor#updateLineSectionListener(int, java.lang.Object)
     */
    protected void updateLineSectionListener(int line, Object o) {
        if (handleCursorPositionChanged) {
            for (IClassFileEditorSelectionListener listener : lineSelectionListener) {
                listener.lineSelectionChanged(line/* changed to 0-based */, o);
            }
        }
    }

    /**
     * Updates Graph Outline.
     * Disable the graph outline if the source code 
     * view is active or enable if the byte code view
     * is active. 
     */
    private void updateOutlineGraphView() {
        int index = getActiveTabIndex();
        switch (index) {
        case TAB_INDEX_BYTECODE:
            /* enable graph view in the outline  */
            if (getCanvasControlFlowGraph() != null) {
                getCanvasControlFlowGraph().setVisible(true);
            }
            break;
        case TAB_INDEX_SOURCE:
            /* disable graph view in the outline  */
            if (getCanvasControlFlowGraph() != null) {
                getCanvasControlFlowGraph().setVisible(false);
            }
            break;
        default:
            /* other views */
            BytecodeVisualizerPlugin.log(new Status(IStatus.WARNING, CoreConstants.BYTECODE_VISUALIZER_PLUGIN_ID,
                    "Uncovered tab index " + index));
            break;
        }
    }
}