/*******************************************************************************
 * Copyright (c) 2000, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Wind River - Pawel Piech - Busy status while updates in progress (Bug 206822)
 *     Pawel Piech (Wind River) - added a breadcrumb mode to Debug view (Bug 252677)
 *     Andrey Loskutov <loskutov@gmx.de> - fixed memory leak due the breadcrumb (Bug 466789)
 *******************************************************************************/
package org.eclipse.debug.internal.ui.views.launch;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.eclipse.core.commands.IHandler2;
import org.eclipse.core.commands.contexts.ContextManagerEvent;
import org.eclipse.core.commands.contexts.IContextManagerListener;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.commands.IRestartHandler;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.DelegatingModelPresentation;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.actions.AddToFavoritesAction;
import org.eclipse.debug.internal.ui.actions.EditLaunchConfigurationAction;
import org.eclipse.debug.internal.ui.commands.actions.DisconnectCommandAction;
import org.eclipse.debug.internal.ui.commands.actions.DropToFrameCommandAction;
import org.eclipse.debug.internal.ui.commands.actions.RestartCommandAction;
import org.eclipse.debug.internal.ui.commands.actions.ResumeCommandAction;
import org.eclipse.debug.internal.ui.commands.actions.StepIntoCommandAction;
import org.eclipse.debug.internal.ui.commands.actions.StepOverCommandAction;
import org.eclipse.debug.internal.ui.commands.actions.StepReturnCommandAction;
import org.eclipse.debug.internal.ui.commands.actions.SuspendCommandAction;
import org.eclipse.debug.internal.ui.commands.actions.TerminateAllAction;
import org.eclipse.debug.internal.ui.commands.actions.TerminateAndRelaunchAction;
import org.eclipse.debug.internal.ui.commands.actions.TerminateAndRemoveAction;
import org.eclipse.debug.internal.ui.commands.actions.TerminateCommandAction;
import org.eclipse.debug.internal.ui.commands.actions.ToggleStepFiltersAction;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
import org.eclipse.debug.internal.ui.sourcelookup.EditSourceLookupPathAction;
import org.eclipse.debug.internal.ui.sourcelookup.LookupSourceAction;
import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.VirtualFindAction;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.debug.internal.ui.views.DebugModelPresentationContext;
import org.eclipse.debug.internal.ui.views.ViewContextService;
import org.eclipse.debug.ui.AbstractDebugView;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugModelPresentation;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.actions.DebugCommandAction;
import org.eclipse.debug.ui.contexts.AbstractDebugContextProvider;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.debug.ui.contexts.IDebugContextListener;
import org.eclipse.debug.ui.contexts.IDebugContextProvider;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.commands.ActionHandler;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPageListener;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IPerspectiveListener2;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.actions.SelectionListenerAction;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.dialogs.PropertyDialogAction;
import org.eclipse.ui.part.IPageBookViewPage;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.IShowInTarget;
import org.eclipse.ui.part.IShowInTargetList;
import org.eclipse.ui.part.Page;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.texteditor.IUpdate;

public class LaunchView extends AbstractDebugView
    implements ISelectionChangedListener, IPerspectiveListener2, IPageListener, IShowInTarget, IShowInSource,
    IShowInTargetList, IPartListener2, IViewerUpdateListener, IContextManagerListener, IModelChangedListener
{

	public static final String ID_CONTEXT_ACTIVITY_BINDINGS = "contextActivityBindings"; //$NON-NLS-1$

    private static final String TERMINATE = "terminate"; //$NON-NLS-1$

    private static final String DISCONNECT = "disconnect"; //$NON-NLS-1$

    private static final String SUSPEND = "suspend"; //$NON-NLS-1$

    private static final String RESUME = "resume"; //$NON-NLS-1$

    private static final String STEP_RETURN = "step_return"; //$NON-NLS-1$

    private static final String STEP_OVER = "step_over"; //$NON-NLS-1$

    private static final String DROP_TO_FRAME = "drop_to_frame"; //$NON-NLS-1$

    private static final String STEP_INTO = "step_into"; //$NON-NLS-1$

    public static final String TERMINATE_AND_REMOVE = "terminate_and_remove"; //$NON-NLS-1$

    private static final String TERMINATE_ALL = "terminate_all"; //$NON-NLS-1$

    public static final String TERMINATE_AND_RELAUNCH = "terminate_relaunch"; //$NON-NLS-1$

    private static final String TOGGLE_STEP_FILTERS = "toggle_step_filters"; //$NON-NLS-1$

    private static final String RESTART = "restart"; //$NON-NLS-1$

    private static final int BREADCRUMB_TRIGGER_HEIGHT_DEFAULT = 30; // pixels

    private static final int BREADCRUMB_TRIGGER_RANGE = 5; // pixels

    private static final int BREADCRUMB_STICKY_RANGE = 20; // pixels

	/**
	 * Whether this view is in the active page of a perspective.
	 */
	private boolean fIsActive = true;

	/**
	 * Model presentation or <code>null</code> if none
	 */
	private IDebugModelPresentation fPresentation;

	private IPresentationContext fPresentationContext;

	private EditLaunchConfigurationAction fEditConfigAction;
	private AddToFavoritesAction fAddToFavoritesAction;
	private EditSourceLookupPathAction fEditSourceAction;
	private LookupSourceAction fLookupAction;

	/**
	 * Current view mode (auto vs. breadcrumb, vs. tree view).
	 *
	 * @since 3.5
	 */
    private String fCurrentViewMode = IDebugPreferenceConstants.DEBUG_VIEW_MODE_AUTO;

    /**
     * Actions for selecting the view mode (auto vs. breadcrumb, vs. tree view).
     *
     * @since 3.5
     */
    private DebugViewModeAction[] fDebugViewModeActions;

    /**
     * Action which shows or hides the Debug view toolbar.
     */
    private DebugToolBarAction fDebugToolBarAction;

    /**
     * Action that controls the breadcrumb drop-down auto-expand behavior.
     *
     * @since 3.5
     */
    private BreadcrumbDropDownAutoExpandAction fBreadcrumbDropDownAutoExpandAction;

    /**
     * Context service for this view.  Used to track whether debug toolbar
     * action set is active.
     *
     * @since 3.8
     */
    private IContextService fContextService;

    /**
     * Preference name for the view's memento.
     *
     * @since 3.5
     */
    private String PREF_STATE_MEMENTO = "pref_state_memento."; //$NON-NLS-1$

    /**
     * Key for a view preference for whether the elements in breadcrumb's
     * drop-down viewer should be automatically expanded.
     *
     * @since 3.5
     */
    private static final String BREADCRUMB_DROPDOWN_AUTO_EXPAND = DebugUIPlugin.getUniqueIdentifier() + ".BREADCRUMB_DROPDOWN_AUTO_EXPAND"; //$NON-NLS-1$

    /**
     * Preference for whether the elements in breadcrumb's
     * drop-down viewer should be automatically expanded.
     *
     * @since 3.5
     */
	private boolean fBreadcrumbDropDownAutoExpand;

    /**
     * Action handlers. Maps action identifiers to IHandler's.
     *
     * @since 3.6
     */
	private Map<String, IHandler2> fHandlers = new HashMap<>();

    private boolean fDebugToolbarInView = true;

	private Set<String> fDebugToolbarPerspectives = new TreeSet<>();

	/**
	 * Page-book page for the breadcrumb viewer.  This page is activated in
	 * Debug view when the height of the view is reduced to just one line.
     *
     * @since 3.5
	 */
	private class BreadcrumbPage extends Page {

	    LaunchViewBreadcrumb fCrumb;
	    Control fControl;

	    @Override
		public void createControl(Composite parent) {
	        fCrumb = new LaunchViewBreadcrumb(LaunchView.this, (TreeModelViewer)getViewer(), fTreeViewerDebugContextProvider);
	        fControl = fCrumb.createContent(parent);
	    }

	    @Override
		public void init(IPageSite pageSite) {
	        super.init(pageSite);
            pageSite.setSelectionProvider(fCrumb.getSelectionProvider());
	    }

	    @Override
		public Control getControl() {
	        return fControl;
	    }

	    @Override
		public void setFocus() {
	        fCrumb.activate();
	    }

	    IDebugContextProvider getContextProvider() {
	        return fCrumb.getContextProvider();
	    }

	    int getHeight() {
	        return fCrumb.getHeight();
	    }

	    @Override
		public void dispose() {
	        fCrumb.dispose();
	    }
	}

	private BreadcrumbPage fBreadcrumbPage;

	class TreeViewerContextProvider extends AbstractDebugContextProvider implements IModelChangedListener {

		private ISelection fContext = null;
		private TreeModelViewer fViewer = null;
		private Visitor fVisitor = new Visitor();

		class Visitor implements IModelDeltaVisitor {
			@Override
			public boolean visit(IModelDelta delta, int depth) {
				if ((delta.getFlags() & (IModelDelta.STATE | IModelDelta.CONTENT)) > 0) {
					// state and/or content change
					if ((delta.getFlags() & IModelDelta.SELECT) == 0) {
						// no select flag
						if ((delta.getFlags() & IModelDelta.CONTENT) > 0) {
							// content has changed without select >> possible re-activation
							possibleChange(getViewerTreePath(delta), DebugContextEvent.ACTIVATED);
						} else if ((delta.getFlags() & IModelDelta.STATE) > 0) {
							// state has changed without select >> possible state change of active context
							possibleChange(getViewerTreePath(delta), DebugContextEvent.STATE);
						}
					}
				}
				return true;
			}
		}

		/**
		 * Returns a tree path for the node, *not* including the root element.
		 *
		 * @param node
		 *            model delta
		 * @return corresponding tree path
		 */
		private TreePath getViewerTreePath(IModelDelta node) {
			ArrayList<Object> list = new ArrayList<>();
			IModelDelta parentDelta = node.getParentDelta();
			while (parentDelta != null) {
				list.add(0, node.getElement());
				node = parentDelta;
				parentDelta = node.getParentDelta();
			}
			return new TreePath(list.toArray());
		}

		public TreeViewerContextProvider(TreeModelViewer viewer) {
			super(LaunchView.this);
			fViewer = viewer;
			fViewer.addModelChangedListener(this);
		}

		protected void dispose() {
			fContext = null;
			fViewer.removeModelChangedListener(this);
		}

		@Override
		public synchronized ISelection getActiveContext() {
			return fContext;
		}

		protected void activate(ISelection selection) {
			synchronized (this) {
				fContext = selection;
			}
			fire(new DebugContextEvent(this, selection, DebugContextEvent.ACTIVATED));
		}

        protected void possibleChange(TreePath element, int type) {
            DebugContextEvent event = null;
            synchronized (this) {
                if (fContext instanceof ITreeSelection) {
                    ITreeSelection ss = (ITreeSelection) fContext;
                    TreePath[] ssPaths = ss.getPaths();
                    for (int i = 0; i < ssPaths.length; i++) {
                        if (ssPaths[i].startsWith(element, null)) {
                            if (ssPaths[i].getSegmentCount() == element.getSegmentCount()) {
                                event = new DebugContextEvent(this, fContext, type);
                            } else {
                                // if parent of the currently selected element
                                // changes, issue event to update STATE only
                                event = new DebugContextEvent(this, fContext, DebugContextEvent.STATE);
							}
						}
					}
				}
			}
			if (event == null) {
				return;
			}
			if (getControl().getDisplay().getThread() == Thread.currentThread()) {
				fire(event);
			} else {
				final DebugContextEvent finalEvent = event;
				Job job = new UIJob("context change") { //$NON-NLS-1$
					@Override
					public IStatus runInUIThread(IProgressMonitor monitor) {
						// verify selection is still the same context since job was scheduled
						synchronized (TreeViewerContextProvider.this) {
							if (fContext instanceof IStructuredSelection) {
								IStructuredSelection ss = (IStructuredSelection) fContext;
								Object changed = ((IStructuredSelection)finalEvent.getContext()).getFirstElement();
								if (!(ss.size() == 1 && ss.getFirstElement().equals(changed))) {
									return Status.OK_STATUS;
								}
							}
						}
						fire(finalEvent);
						return Status.OK_STATUS;
					}
				};
				job.setSystem(true);
				job.schedule();
			}
		}

		@Override
		public void modelChanged(IModelDelta delta, IModelProxy proxy) {
			delta.accept(fVisitor);
		}

	}

	/**
	 * Context provider
	 */
	private TreeViewerContextProvider fTreeViewerDebugContextProvider;

	/**
	 * The PageBookView, which is a base class of this class does not make it
	 * easy to control which page is currently active.  It is intended that the
	 * page book pages are associated with workbench parts, and the parts are
	 * in turn associated with PageRec records.
	 * <p>
	 * PageRec is needed in order to properly active a page book page, by
	 * calling showPageRec(), so in this class we need to add some hooks in
	 * order to obtain the page record for the tree viewer page and the
	 * breadcrumb page.</p><p>
	 * For the default page, we override the showPageRec()
	 * to determine if the default page is being shown and if it is, we save
	 * its record for later use.  showPageRec() is always called for the default
	 * page after it is created.  For the breadcrumb page, we use the page book
	 * view mechanism to create the page based on a workbench part, but we have
	 * to create a dummy part in order for this to work.
	 * </p>
	 * <p>
	 * See bug 262845 and 262870.
	 * </p>
	 *
	 * @see #createPartControl(Composite)
	 * @see BreadcrumbWorkbenchPart
	 * @eee #doCreatePage(IWorkbenchPart)
	 * @see #isImportant(IWorkbenchPart)
	 * @see #autoSelectViewPage(Composite)
	 * @see #showTreeViewerPage()
	 * @see #showBreadcrumbPage()
	 */
	private PageRec fDefaultPageRec = null;

	private ISelectionChangedListener fTreeViewerSelectionChangedListener = new ISelectionChangedListener() {
	    @Override
		public void selectionChanged(SelectionChangedEvent event) {
	        fTreeViewerDebugContextProvider.activate(event.getSelection());
	    }
	};

	private class ContextProviderProxy extends AbstractDebugContextProvider implements IDebugContextListener {
	    private IDebugContextProvider fActiveProvider;
	    private IDebugContextProvider[] fProviders;

	    ContextProviderProxy(IDebugContextProvider[] providers) {
	        super(LaunchView.this);
	        fProviders = providers;
	        fActiveProvider = providers[0];
	        for (int i = 0; i < fProviders.length; i++) {
	            fProviders[i].addDebugContextListener(this);
	        }
	    }

	    void setActiveProvider(IDebugContextProvider provider) {
            if (!provider.equals(fActiveProvider)) {
    	        ISelection activeContext = getActiveContext();
                fActiveProvider = provider;
                ISelection newActiveContext = getActiveContext();
    	        if (!activeContext.equals(newActiveContext)) {
        	        fire(new DebugContextEvent(this, getActiveContext(), DebugContextEvent.ACTIVATED));
    	        }
            }
	    }

        @Override
		public ISelection getActiveContext() {
            ISelection activeContext = fActiveProvider.getActiveContext();
            if (activeContext != null) {
                return activeContext;
            }
            return TreeSelection.EMPTY;
        }

        @Override
		public void debugContextChanged(DebugContextEvent event) {
	        if (event.getSource().equals(fActiveProvider)) {
	            fire(new DebugContextEvent(this, event.getContext(), event.getFlags()));
	        }
	    }

        void dispose() {
            for (int i = 0; i < fProviders.length; i++) {
                fProviders[i].removeDebugContextListener(this);
            }
            fProviders = null;
            fActiveProvider = null;
        }
	}

	private ContextProviderProxy fContextProviderProxy;

	@Override
	protected String getHelpContextId() {
		return IDebugHelpContextIds.DEBUG_VIEW;
	}

	@Override
	protected void createActions() {
		setAction("Properties", new PropertyDialogAction(getSite(), getSite().getSelectionProvider())); //$NON-NLS-1$
		fEditConfigAction = new EditLaunchConfigurationAction();
		fAddToFavoritesAction = new AddToFavoritesAction();
		fEditSourceAction = new EditSourceLookupPathAction(this);
		fLookupAction = new LookupSourceAction(this);
		setAction(FIND_ACTION, new VirtualFindAction((TreeModelViewer) getViewer()));

        addCapabilityAction(new TerminateCommandAction(), TERMINATE);
        addCapabilityAction(new DisconnectCommandAction(), DISCONNECT);
        addCapabilityAction(new SuspendCommandAction(), SUSPEND);
        addCapabilityAction(new ResumeCommandAction(), RESUME);
        addCapabilityAction(new StepReturnCommandAction(), STEP_RETURN);
        addCapabilityAction(new StepOverCommandAction(), STEP_OVER);
        addCapabilityAction(new StepIntoCommandAction(), STEP_INTO);
        addCapabilityAction(new DropToFrameCommandAction(), DROP_TO_FRAME);
        DebugCommandAction action = new TerminateAndRemoveAction();
        addCapabilityAction(action, TERMINATE_AND_REMOVE);
        setHandler(TERMINATE_AND_REMOVE, new ActionHandler(action));
        action = new TerminateAndRelaunchAction();
        addCapabilityAction(action, TERMINATE_AND_RELAUNCH);
        setHandler(TERMINATE_AND_RELAUNCH, new ActionHandler(action));
        addCapabilityAction(new RestartCommandAction(), RESTART);
        addCapabilityAction(new TerminateAllAction(), TERMINATE_ALL);
        addCapabilityAction(new ToggleStepFiltersAction(), TOGGLE_STEP_FILTERS);
	}

	/**
	 * Sets the handler associated with the given action identifier.
	 *
	 * @param id action identifier
	 * @param handler handler
	 */
	private void setHandler(String id, IHandler2 handler) {
		fHandlers.put(id, handler);
	}

	/**
	 * Returns the handler associated with the given action identifier or <code>null</code>.
	 *
	 * @param id action identifier
	 * @return handler or <code>null</code>
	 */
	public IHandler2 getHandler(String id) {
		return fHandlers.get(id);
	}

	/**
	 * Initializes the action and associates it with the given id.
	 *
	 * @param capability
	 * @param actionID
	 */
	private void addCapabilityAction(DebugCommandAction capability, String actionID) {
		capability.init(this);
		setAction(actionID, capability);
	}

	/**
	 * Disposes the given action.
	 *
	 * @param actionID
	 */
	private void disposeCommandAction(String actionID) {
		DebugCommandAction action = (DebugCommandAction) getAction(actionID);
		action.dispose();
	}

	/**
 	 * Override the default implementation to create the breadcrumb page.
	 *
	 * @since 3.5
	 * @see #fDefaultPageRec
	 */
	@Override
	public void createPartControl(final Composite parent) {
	    super.createPartControl(parent);

	    // Copy the global action handlers to the default page.
	    setGlobalActionBarsToPage((IPageBookViewPage)getDefaultPage());

	    // Add view as a selection listener to the site.
	    getSite().getSelectionProvider().addSelectionChangedListener(this);

	    // Set the tree viewer as the selection provider to the default page.
	    // The page book view handles switching the between page selection
	    // providers as needed.
	    ((IPageBookViewPage)getDefaultPage()).getSite().setSelectionProvider(getViewer());

	    // Call the PageBookView part listener to indirectly create the breadcrumb page.
	    // This call eventually calls doCreatePage() implemented below.
	    partActivated(new BreadcrumbWorkbenchPart(getSite()));

        fContextProviderProxy = new ContextProviderProxy(
            new IDebugContextProvider[] {fTreeViewerDebugContextProvider, fBreadcrumbPage.getContextProvider()});
        DebugUITools.getDebugContextManager().getContextService(getSite().getWorkbenchWindow()).addDebugContextProvider(fContextProviderProxy);

	    // Create and configure actions for selecting view mode.
        createViewModeActions(parent);
        IPreferenceStore prefStore = DebugUIPlugin.getDefault().getPreferenceStore();
        String mode = prefStore.getString(IDebugPreferenceConstants.DEBUG_VIEW_MODE);
        setViewMode(mode, parent);
        for (int i = 0; i < fDebugViewModeActions.length; i++) {
            fDebugViewModeActions[i].setChecked(fDebugViewModeActions[i].getMode().equals(mode));
        }

        createDebugToolBarInViewActions(parent);

        // Add a resize listener for the view to activate breadcrumb as needed.
        parent.addControlListener(new ControlListener() {
            @Override
			public void controlMoved(ControlEvent e) {
            }
            @Override
			public void controlResized(ControlEvent e) {
                if (parent.isDisposed()) {
                    return;
                }
                if (IDebugPreferenceConstants.DEBUG_VIEW_MODE_AUTO.equals(fCurrentViewMode)) {
                    autoSelectViewPage(parent);
                }
            }
        });

        fContextService.addContextManagerListener(this);
	}

	/**
	 * Copies the view's global action handlers created by createActions(),
	 * into the page site's action bars.  This is necessary because the page
	 * book view resets the view site's global actions after each page switch
	 * (see bug 264618).
	 *
	 * @param page Page to copy the global actions into.
	 *
	 * @since 3.5
	 */
	private void setGlobalActionBarsToPage(IPageBookViewPage page) {
	    IActionBars pageActionBars = page.getSite().getActionBars();
        // Set the view site action bars created by createActions() to the
        // default page site.
        IActionBars bars = getViewSite().getActionBars();
        pageActionBars.setGlobalActionHandler(FIND_ACTION, bars.getGlobalActionHandler(FIND_ACTION));
        pageActionBars.setGlobalActionHandler(COPY_ACTION, bars.getGlobalActionHandler(COPY_ACTION));
	}

    /**
     * Override the default implementation to create the breadcrumb page.
     *
     * @since 3.5
     * @see #fDefaultPageRec
     */
	@Override
	protected PageRec doCreatePage(IWorkbenchPart part) {
	    if (part instanceof BreadcrumbWorkbenchPart) {
	        fBreadcrumbPage = new BreadcrumbPage();
	        fBreadcrumbPage.createControl(getPageBook());
	        initPage(fBreadcrumbPage);
	        setGlobalActionBarsToPage(fBreadcrumbPage);
	        return new PageRec(part, fBreadcrumbPage);
	    }
	    return null;
	}

    /**
     * Override the default implementation to create the breadcrumb page.
     *
     * @since 3.5
     * @see #fDefaultPageRec
     */
	@Override
	protected boolean isImportant(IWorkbenchPart part) {
	    return part instanceof BreadcrumbWorkbenchPart;
	}

    /**
     * Override the default implementation to gain access at the default
     * page record.
     *
     * @since 3.5
     * @see #fDefaultPageRec
     */
	@Override
	protected void showPageRec(PageRec pageRec) {
	    if (pageRec.page == getDefaultPage()) {
	        fDefaultPageRec = pageRec;
	    }

	    super.showPageRec(pageRec);
	}

	/**
	 * Creates actions for controlling view mode.
	 *
	 * @param parent The view's parent control used to calculate view size
     * in auto mode.
	 */
    private void createViewModeActions(final Composite parent) {
        IActionBars actionBars = getViewSite().getActionBars();
        IMenuManager viewMenu = actionBars.getMenuManager();

        fDebugViewModeActions = new DebugViewModeAction[3];
        fDebugViewModeActions[0] = new DebugViewModeAction(this, IDebugPreferenceConstants.DEBUG_VIEW_MODE_AUTO, parent);
        fDebugViewModeActions[1] = new DebugViewModeAction(this, IDebugPreferenceConstants.DEBUG_VIEW_MODE_FULL, parent);
        fDebugViewModeActions[2] = new DebugViewModeAction(this, IDebugPreferenceConstants.DEBUG_VIEW_MODE_COMPACT, parent);
        fBreadcrumbDropDownAutoExpandAction = new BreadcrumbDropDownAutoExpandAction(this);
        viewMenu.add(new Separator());

        final MenuManager modeSubmenu = new MenuManager(LaunchViewMessages.LaunchView_ViewModeMenu_label);
        modeSubmenu.setRemoveAllWhenShown(true);
        modeSubmenu.add(fDebugViewModeActions[0]);
        modeSubmenu.add(fDebugViewModeActions[1]);
        modeSubmenu.add(fDebugViewModeActions[2]);
        modeSubmenu.add(new Separator());
        modeSubmenu.add(fBreadcrumbDropDownAutoExpandAction);
        viewMenu.add(modeSubmenu);

        modeSubmenu.addMenuListener(new IMenuListener() {
            @Override
			public void menuAboutToShow(IMenuManager manager) {
                modeSubmenu.add(fDebugViewModeActions[0]);
                modeSubmenu.add(fDebugViewModeActions[1]);
                modeSubmenu.add(fDebugViewModeActions[2]);
                modeSubmenu.add(new Separator());
                modeSubmenu.add(fBreadcrumbDropDownAutoExpandAction);
           }
        });
    }

    /**
     * Creates actions for controlling view mode.
     *
     * @param parent The view's parent control used to calculate view size
     * in auto mode.
     */
    private void createDebugToolBarInViewActions(final Composite parent) {
        IActionBars actionBars = getViewSite().getActionBars();
        IMenuManager viewMenu = actionBars.getMenuManager();

        fDebugToolBarAction = new DebugToolBarAction(this);
        viewMenu.add(fDebugToolBarAction);
        updateCheckedDebugToolBarAction();
    }


    /**
     * Sets the current view mode.  If needed, the active view page is changed.
     *
     * @param mode New mode to set.
     * @param parent The view's parent control used to calculate view size
     * in auto mode.
     *
     * @since 3.5
     */
    void setViewMode(String mode, Composite parent) {
        if (fCurrentViewMode.equals(mode)) {
            return;
        }

        fCurrentViewMode = mode;
        if (IDebugPreferenceConstants.DEBUG_VIEW_MODE_COMPACT.equals(mode)) {
            showBreadcrumbPage();
        } else if (IDebugPreferenceConstants.DEBUG_VIEW_MODE_FULL.equals(mode)) {
            showTreeViewerPage();
        } else {
            autoSelectViewPage(parent);
        }
        DebugUIPlugin.getDefault().getPreferenceStore().setValue(IDebugPreferenceConstants.DEBUG_VIEW_MODE, mode);
    }

   /**
    * Based on the current view size, select the active view page
    * (tree viewer vs. breadcrumb).
    *
    * @param parent View pane control.
    *
    * @since 3.5
    */
   private void autoSelectViewPage(Composite parent) {
       int breadcrumbHeight = fBreadcrumbPage.getHeight();
       // Breadcrumb may report size 0 if it hasn't been shown yet.
       // Bug 335536.
       if (breadcrumbHeight == 0) {
           breadcrumbHeight = BREADCRUMB_TRIGGER_HEIGHT_DEFAULT;
       }
       if (parent.getClientArea().height < breadcrumbHeight + BREADCRUMB_TRIGGER_RANGE) {
           showBreadcrumbPage();
       }
       else if (parent.getClientArea().height > breadcrumbHeight + BREADCRUMB_STICKY_RANGE)
       {
           showTreeViewerPage();
       }
   }


    /**
     * Shows the tree viewer in the Debug view.
     *
     * @since 3.5
     */
	void showTreeViewerPage() {
	    if (fDefaultPageRec != null && !getDefaultPage().equals(getCurrentPage())) {
            showPageRec(fDefaultPageRec);
            fContextProviderProxy.setActiveProvider(fTreeViewerDebugContextProvider);
            // Clear the selection in the breadcrumb to avoid having it re-selected
            // when the breadcrumb is activated again (bug 268124).
            fBreadcrumbPage.fCrumb.clearSelection();
	    }
	}

	/**
 	 * Shows the breadcrumb in the Debug view.
 	 *
 	 * @since 3.5
	 */
	void showBreadcrumbPage() {
        PageRec rec = getPageRec(fBreadcrumbPage);
        if (rec != null && !fBreadcrumbPage.equals(getCurrentPage())) {
            showPageRec(rec);
            // Ask the breadcrumb to take focus if we're the active part.
            if (getSite().getPage().getActivePart() == this) {
                setFocus();
            }
            ISelection activeContext = fTreeViewerDebugContextProvider.getActiveContext();
			if (activeContext == null) {
				activeContext = StructuredSelection.EMPTY;
			}
			fBreadcrumbPage.fCrumb.debugContextChanged(new DebugContextEvent(
                fTreeViewerDebugContextProvider,
                activeContext,
                DebugContextEvent.ACTIVATED));
            fContextProviderProxy.setActiveProvider(fBreadcrumbPage.getContextProvider());
        }
	}

	@Override
	protected Viewer createViewer(Composite parent) {
		fPresentation = new DelegatingModelPresentation();
		fPresentationContext = new DebugModelPresentationContext(IDebugUIConstants.ID_DEBUG_VIEW, this, fPresentation);
		TreeModelViewer viewer = new TreeModelViewer(parent,
				SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL,
				fPresentationContext);

        viewer.addSelectionChangedListener(fTreeViewerSelectionChangedListener);
        viewer.addViewerUpdateListener(this);
        viewer.addModelChangedListener(this);

		viewer.setInput(DebugPlugin.getDefault().getLaunchManager());
		//setEventHandler(new LaunchViewEventHandler(this));
		fTreeViewerDebugContextProvider = new TreeViewerContextProvider(viewer);

		return viewer;
	}

	private void commonInit(IViewSite site) {
		site.getPage().addPartListener((IPartListener2) this);
		site.getWorkbenchWindow().addPageListener(this);
		site.getWorkbenchWindow().addPerspectiveListener(this);
	}

	private void preferenceInit(IViewSite site) {
        PREF_STATE_MEMENTO = PREF_STATE_MEMENTO + site.getId();
        IPreferenceStore store = DebugUIPlugin.getDefault().getPreferenceStore();
        String string = store.getString(PREF_STATE_MEMENTO);
        if(string.length() > 0) {
			try (ByteArrayInputStream bin = new ByteArrayInputStream(string.getBytes()); InputStreamReader reader = new InputStreamReader(bin)) {
                XMLMemento stateMemento = XMLMemento.createReadRoot(reader);
                setMemento(stateMemento);
            } catch (WorkbenchException e) {
			} catch (IOException e1) {
			}
        }
        IMemento mem = getMemento();

        if (mem != null) {
            Boolean auto = mem.getBoolean(BREADCRUMB_DROPDOWN_AUTO_EXPAND);
            if(auto != null) {
                setBreadcrumbDropDownAutoExpand(auto.booleanValue());
            }
        }

        String preference = DebugUIPlugin.getDefault().getPreferenceStore().getString(
            IDebugPreferenceConstants.DEBUG_VIEW_TOOLBAR_HIDDEN_PERSPECTIVES);
        if (preference != null) {
            fDebugToolbarPerspectives = ViewContextService.parseList(preference);
        }
        IPerspectiveDescriptor perspective = getSite().getPage().getPerspective();
        fDebugToolbarInView = isDebugToolbarShownInPerspective(perspective);
	}

	@Override
	public void init(IViewSite site) throws PartInitException {
		super.init(site);
		commonInit(site);
		preferenceInit(site);
		fContextService = site.getService(IContextService.class);
	}

	@Override
	public void init(IViewSite site, IMemento memento) throws PartInitException {
		super.init(site, memento);
		commonInit(site);
        preferenceInit(site);
        fContextService = site.getService(IContextService.class);
	}

    @Override
	public void partDeactivated(IWorkbenchPart part) {
        String id = part.getSite().getId();
        if (id.equals(getSite().getId())) {
			try (ByteArrayOutputStream bout = new ByteArrayOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(bout);) {
                XMLMemento memento = XMLMemento.createWriteRoot("DebugViewMemento"); //$NON-NLS-1$
                saveViewerState(memento);
                memento.save(writer);

                IPreferenceStore store = DebugUIPlugin.getDefault().getPreferenceStore();
                String xmlString = bout.toString();
                store.putValue(PREF_STATE_MEMENTO, xmlString);
            } catch (IOException e) {
            }
        }

        StringBuffer buffer= new StringBuffer();
		for (Iterator<String> itr = fDebugToolbarPerspectives.iterator(); itr.hasNext();) {
            buffer.append(itr.next()).append(',');
        }
        getPreferenceStore().setValue(IDebugPreferenceConstants.DEBUG_VIEW_TOOLBAR_HIDDEN_PERSPECTIVES, buffer.toString());

        super.partDeactivated(part);
    }

    /**
     * Saves the current state of the viewer
     * @param memento the memento to write the viewer state into
     */
    public void saveViewerState(IMemento memento) {
        memento.putBoolean(BREADCRUMB_DROPDOWN_AUTO_EXPAND, getBreadcrumbDropDownAutoExpand());
    }

	@Override
	protected void configureToolBar(IToolBarManager tbm) {
		tbm.add(new Separator(IDebugUIConstants.THREAD_GROUP));
		tbm.add(new Separator(IDebugUIConstants.STEP_GROUP));
		tbm.add(new GroupMarker(IDebugUIConstants.STEP_INTO_GROUP));
		tbm.add(new GroupMarker(IDebugUIConstants.STEP_OVER_GROUP));
		tbm.add(new GroupMarker(IDebugUIConstants.STEP_RETURN_GROUP));
		tbm.add(new GroupMarker(IDebugUIConstants.EMPTY_STEP_GROUP));
		tbm.add(new Separator(IDebugUIConstants.RENDER_GROUP));

		if (fDebugToolbarInView) {
		    addDebugToolbarActions(tbm);
		}
	}

   protected void addDebugToolbarActions(IToolBarManager tbm) {
        tbm.appendToGroup(IDebugUIConstants.THREAD_GROUP, getAction(RESUME));
        tbm.appendToGroup(IDebugUIConstants.THREAD_GROUP, getAction(SUSPEND));
        tbm.appendToGroup(IDebugUIConstants.THREAD_GROUP, getAction(TERMINATE));
        tbm.appendToGroup(IDebugUIConstants.THREAD_GROUP, getAction(DISCONNECT));

        tbm.appendToGroup(IDebugUIConstants.STEP_INTO_GROUP, getAction(STEP_INTO));
        tbm.appendToGroup(IDebugUIConstants.STEP_OVER_GROUP, getAction(STEP_OVER));
        tbm.appendToGroup(IDebugUIConstants.STEP_RETURN_GROUP, getAction(STEP_RETURN));

        tbm.appendToGroup(IDebugUIConstants.EMPTY_STEP_GROUP, getAction(DROP_TO_FRAME));

        tbm.appendToGroup(IDebugUIConstants.RENDER_GROUP, getAction(TOGGLE_STEP_FILTERS));
   }

   /**
    * Removes the toolbar actions contributed by this view from the toolbar
    * manager.
    * @param tbm
    */
   protected void removeDebugToolbarActions(IToolBarManager tbm) {
       tbm.remove(new ActionContributionItem(getAction(RESUME)));
       tbm.remove(new ActionContributionItem(getAction(SUSPEND)));
       tbm.remove(new ActionContributionItem(getAction(TERMINATE)));
       tbm.remove(new ActionContributionItem(getAction(DISCONNECT)));

       tbm.remove(new ActionContributionItem(getAction(STEP_INTO)));
       tbm.remove(new ActionContributionItem(getAction(STEP_OVER)));
       tbm.remove(new ActionContributionItem(getAction(STEP_RETURN)));

       tbm.remove(new ActionContributionItem(getAction(DROP_TO_FRAME)));

       tbm.remove(new ActionContributionItem(getAction(TOGGLE_STEP_FILTERS)));
   }

   public boolean isDebugToolbarInView() {
       return fDebugToolbarInView;
   }

   public boolean isDebugToolbarShownInPerspective(IPerspectiveDescriptor perspective) {
       return perspective == null || fDebugToolbarPerspectives.contains(perspective.getId());
   }

   public void setDebugToolbarInView(boolean show) {
       if (show == isDebugToolbarInView()) {
           return;
       }
       fDebugToolbarInView = show;

       // Update the perspectives set.
       IPerspectiveDescriptor perspective = getSite().getPage().getPerspective();
       if (perspective != null) {
           if (show) {
               fDebugToolbarPerspectives.add(perspective.getId());
           } else {
               fDebugToolbarPerspectives.remove(perspective.getId());
           }
       }

       // Update the toolbar manager.
       IToolBarManager tbm = getViewSite().getActionBars().getToolBarManager();
       if (show) {
           addDebugToolbarActions(tbm);
       } else {
           removeDebugToolbarActions(tbm);
       }
       getViewSite().getActionBars().updateActionBars();

       // Update system property used by contributed actions.
       System.setProperty(IDebugUIConstants.DEBUG_VIEW_TOOBAR_VISIBLE, Boolean.toString(show));
   }

	@Override
	public void dispose() {
	    fContextService.removeContextManagerListener(this);
	    getSite().getSelectionProvider().removeSelectionChangedListener(this);
		DebugUITools.getDebugContextManager().getContextService(getSite().getWorkbenchWindow()).removeDebugContextProvider(fContextProviderProxy);
        fContextProviderProxy.dispose();
        fTreeViewerDebugContextProvider.dispose();
        disposeActions();
	    Viewer viewer = getViewer();
		if (viewer != null) {
			viewer.removeSelectionChangedListener(fTreeViewerSelectionChangedListener);
            ((TreeModelViewer)viewer).removeViewerUpdateListener(this);
            ((TreeModelViewer)viewer).removeModelChangedListener(this);
		}
		if (fPresentationContext != null) {
		    fPresentationContext.dispose();
		}
		IWorkbenchPage page = getSite().getPage();
		page.removePartListener((IPartListener2) this);
		IWorkbenchWindow window = getSite().getWorkbenchWindow();
		window.removePerspectiveListener(this);
		window.removePageListener(this);
		for (IHandler2 handler : fHandlers.values()) {
			handler.dispose();
		}
		fHandlers.clear();
		if (fBreadcrumbPage != null) {
			fBreadcrumbPage.dispose();
			fBreadcrumbPage = null;
		}
		super.dispose();
	}

	private void disposeActions() {
        PropertyDialogAction properties = (PropertyDialogAction) getAction("Properties"); //$NON-NLS-1$
        properties.dispose();

        disposeCommandAction(TERMINATE);
        disposeCommandAction(DISCONNECT);
        disposeCommandAction(SUSPEND);
        disposeCommandAction(RESUME);
        disposeCommandAction(STEP_RETURN);
        disposeCommandAction(STEP_OVER);
        disposeCommandAction(STEP_INTO);
        disposeCommandAction(DROP_TO_FRAME);
        disposeCommandAction(TERMINATE_AND_REMOVE);
        disposeCommandAction(TERMINATE_AND_RELAUNCH);
        disposeCommandAction(RESTART);
        disposeCommandAction(TERMINATE_ALL);
        disposeCommandAction(TOGGLE_STEP_FILTERS);
    }

    /**
	 * The selection has changed in the viewer. Show the
	 * associated source code if it is a stack frame.
	 *
	 * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
	 */
	@Override
	public void selectionChanged(SelectionChangedEvent event) {
		updateObjects();
	}

	@Override
	public void doubleClick(DoubleClickEvent event) {
		ISelection selection= event.getSelection();
		if (!(selection instanceof IStructuredSelection)) {
			return;
		}
		IStructuredSelection ss= (IStructuredSelection)selection;
		Object o= ss.getFirstElement();
		if (o == null || o instanceof IStackFrame) {
			return;
		}
		StructuredViewer viewer = (StructuredViewer) getViewer();
		viewer.refresh(o);
	}

	@Override
	public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
		setActive(page.findView(getSite().getId()) != null);
		updateObjects();
		setDebugToolbarInView( isDebugToolbarShownInPerspective(getSite().getPage().getPerspective()) );
        updateCheckedDebugToolBarAction();
	}

	@Override
	public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, String changeId) {
		setActive(page.findView(getSite().getId()) != null);
	}

	@Override
	public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, IWorkbenchPartReference partRef, String changeId) {
	}

	@Override
	public void pageActivated(IWorkbenchPage page) {
		if (getSite().getPage().equals(page)) {
			setActive(true);
			updateObjects();
		}
	}

	@Override
	public void pageClosed(IWorkbenchPage page) {
	}

	@Override
	public void pageOpened(IWorkbenchPage page) {
	}

	@Override
	public IDebugModelPresentation getPresentation(String id) {
		return ((DelegatingModelPresentation)fPresentation).getPresentation(id);
	}

	@Override
	protected void fillContextMenu(IMenuManager menu) {
        TreeSelection sel = (TreeSelection) fTreeViewerDebugContextProvider.getActiveContext();
        Object element = sel != null && sel.size() > 0 ? sel.getFirstElement() : null;

		menu.add(new Separator(IDebugUIConstants.EMPTY_EDIT_GROUP));
		menu.add(new Separator(IDebugUIConstants.EDIT_GROUP));
		menu.add(getAction(FIND_ACTION));
		menu.add(new Separator(IDebugUIConstants.EMPTY_STEP_GROUP));
		menu.add(new Separator(IDebugUIConstants.STEP_GROUP));
		menu.add(new GroupMarker(IDebugUIConstants.STEP_INTO_GROUP));
		menu.add(new GroupMarker(IDebugUIConstants.STEP_OVER_GROUP));
		menu.add(new GroupMarker(IDebugUIConstants.STEP_RETURN_GROUP));
		menu.add(new Separator(IDebugUIConstants.RENDER_GROUP));
		menu.add(new Separator(IDebugUIConstants.EMPTY_THREAD_GROUP));
		menu.add(new Separator(IDebugUIConstants.THREAD_GROUP));
		menu.add(new Separator(IDebugUIConstants.EMPTY_LAUNCH_GROUP));
		menu.add(new Separator(IDebugUIConstants.LAUNCH_GROUP));
		IStructuredSelection selection = (IStructuredSelection) getSite().getSelectionProvider().getSelection();
		updateAndAdd(menu, fEditConfigAction, selection);
		updateAndAdd(menu, fAddToFavoritesAction, selection);
		updateAndAdd(menu, fEditSourceAction, selection);
		updateAndAdd(menu, fLookupAction, selection);
		menu.add(new Separator(IDebugUIConstants.EMPTY_RENDER_GROUP));
		menu.add(new Separator(IDebugUIConstants.RENDER_GROUP));
		menu.add(new Separator(IDebugUIConstants.PROPERTY_GROUP));
		PropertyDialogAction action = (PropertyDialogAction)getAction("Properties"); //$NON-NLS-1$
		/**
		 * TODO hack to get around bug 148424, remove if UI ever fixes the PropertyDialogAction to respect enablesWhen conditions
		 */
		action.setEnabled(action.isApplicableForSelection() && !(element instanceof ILaunch));
		menu.add(action);
		menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));

        menu.appendToGroup(IDebugUIConstants.LAUNCH_GROUP, getAction(TERMINATE_AND_REMOVE));
        menu.appendToGroup(IDebugUIConstants.LAUNCH_GROUP, getAction(TERMINATE_ALL));

        menu.appendToGroup(IDebugUIConstants.THREAD_GROUP, getAction(RESUME));
        menu.appendToGroup(IDebugUIConstants.THREAD_GROUP, getAction(SUSPEND));
        menu.appendToGroup(IDebugUIConstants.THREAD_GROUP, getAction(TERMINATE));
        menu.appendToGroup(IDebugUIConstants.THREAD_GROUP, getAction(TERMINATE_AND_RELAUNCH));
        if (element instanceof IAdaptable && ((IAdaptable)element).getAdapter(IRestartHandler.class) != null) {
            menu.appendToGroup(IDebugUIConstants.THREAD_GROUP, getAction(RESTART));
        }
        menu.appendToGroup(IDebugUIConstants.THREAD_GROUP, getAction(DISCONNECT));

        menu.appendToGroup(IDebugUIConstants.STEP_INTO_GROUP, getAction(STEP_INTO));
        menu.appendToGroup(IDebugUIConstants.STEP_OVER_GROUP, getAction(STEP_OVER));
        menu.appendToGroup(IDebugUIConstants.STEP_RETURN_GROUP, getAction(STEP_RETURN));

        menu.appendToGroup(IDebugUIConstants.EMPTY_STEP_GROUP, getAction(DROP_TO_FRAME));

        menu.appendToGroup(IDebugUIConstants.RENDER_GROUP, getAction(TOGGLE_STEP_FILTERS));
    }

	@Override
	public void contextManagerChanged(ContextManagerEvent event) {
	    if (event.isActiveContextsChanged()) {
			Set<?> oldContexts = event.getPreviouslyActiveContextIds();
			Set<?> newContexts = event.getContextManager().getActiveContextIds();
	        if (oldContexts.contains(IDebugUIConstants.DEBUG_TOOLBAR_ACTION_SET) !=
	            newContexts.contains(IDebugUIConstants.DEBUG_TOOLBAR_ACTION_SET))
	        {
	            updateCheckedDebugToolBarAction();
	        }
	    }
	}

	private void updateCheckedDebugToolBarAction() {
	    fDebugToolBarAction.setChecked(isDebugToolbarInView());
	}

	/**
	 * Updates the enabled state of the given action based on the selection
	 * and adds to the menu if enabled.
	 *
	 * @param menu menu to add the action to
	 * @param action action to add if enabled
	 * @param selection selection to update enabled state for
	 */
	private void updateAndAdd(IMenuManager menu, SelectionListenerAction action, IStructuredSelection selection) {
		action.selectionChanged(selection);
		if (action.isEnabled()) {
			menu.add(action);
		}
	}

	/**
	 * Sets whether this view is in the active page of a
	 * perspective. Since a page can have more than one
	 * perspective, this view only show's source when in
	 * the active perspective/page.
	 *
	 * @param active whether this view is in the active page of a
	 * perspective
	 */
	protected void setActive(boolean active) {
		fIsActive = active;
	}

	/**
	 * Returns whether this view is in the active page of
	 * the active perspective and has been fully created.
	 *
	 * @return whether this view is in the active page of
	 * the active perspective and has been fully created.
	 */
	protected boolean isActive() {
		return fIsActive && getViewer() != null;
	}

	@Override
	public boolean show(ShowInContext context) {
		ISelection selection = context.getSelection();
		if (selection != null) {
			if (selection instanceof IStructuredSelection) {
				IStructuredSelection ss = (IStructuredSelection)selection;
				if (ss.size() == 1) {
					Object obj = ss.getFirstElement();
					if (obj instanceof IDebugTarget || obj instanceof IProcess) {
						Viewer viewer = getViewer();
						if (viewer instanceof InternalTreeModelViewer) {
							InternalTreeModelViewer tv = (InternalTreeModelViewer) viewer;
							tv.setSelection(selection, true, true);
						} else {
							viewer.setSelection(selection, true);
						}
						return true;
					}
				}
			}
		}
		return false;
	}

	@Override
	public ShowInContext getShowInContext() {
		if (isActive()) {
			IStructuredSelection selection = (IStructuredSelection)getViewer().getSelection();
			if (selection.size() == 1) {
				Object object = selection.getFirstElement();
				if (object instanceof IAdaptable) {
					IAdaptable adaptable = (IAdaptable) object;
					IShowInSource show = adaptable.getAdapter(IShowInSource.class);
					if (show != null) {
						return show.getShowInContext();
					}
				}
			}
		}
		return null;
	}

	@Override
	public String[] getShowInTargetIds() {
		if (isActive()) {
			IStructuredSelection selection = (IStructuredSelection)getViewer().getSelection();
			if (selection.size() == 1) {
				Object object = selection.getFirstElement();
				if (object instanceof IAdaptable) {
					IAdaptable adaptable = (IAdaptable) object;
					IShowInTargetList show = adaptable.getAdapter(IShowInTargetList.class);
					if (show != null) {
						return show.getShowInTargetIds();
					}
				}
			}
		}
		return new String[0];
	}

	@Override
	public void partClosed(IWorkbenchPartReference partRef) {
	}

	@Override
	public void partVisible(IWorkbenchPartReference partRef) {
		IWorkbenchPart part = partRef.getPart(false);
		if (part == this) {
			setActive(true);
// TODO: Workaround for Bug #63332. Reexamine after M9.
//			updateContextListener();
			// When the launch view becomes visible, turn on the
			// debug action set. Note that the workbench will handle the
			// case where the user really doesn't want the action set
			// enabled - showActionSet(String) will do nothing for an
			// action set that's been manually disabled.
			getSite().getPage().showActionSet(IDebugUIConstants.DEBUG_ACTION_SET);
		}
	}

	@Override
	public void partOpened(IWorkbenchPartReference partRef) {
	}

	@Override
	public void partActivated(IWorkbenchPartReference partRef) {
		// Ensure that the system property matches the debug toolbar state.
		// Bug 385400
		System.setProperty(IDebugUIConstants.DEBUG_VIEW_TOOBAR_VISIBLE,
				Boolean.toString(isDebugToolbarShownInPerspective(getSite().getPage().getPerspective())) );
	}

	@Override
	public void partBroughtToTop(IWorkbenchPartReference partRef) {
	}

	@Override
	public void partDeactivated(IWorkbenchPartReference partRef) {
	}

	@Override
	public void partHidden(IWorkbenchPartReference partRef) {
	}

	@Override
	public void partInputChanged(IWorkbenchPartReference partRef) {
	}

	@Override
	protected void becomesVisible() {
		super.becomesVisible();
		getViewer().refresh();
	}

    @Override
	public void updateComplete(IViewerUpdate update) {
        if (!update.isCanceled()) {
            if (TreePath.EMPTY.equals(update.getElementPath())) {
                updateFindAction();
            }
        }
    }

    @Override
	public void updateStarted(IViewerUpdate update) {
    }

    @Override
	public synchronized void viewerUpdatesBegin() {
        IWorkbenchSiteProgressService progressService =
            getSite().getAdapter(IWorkbenchSiteProgressService.class);
        if (progressService != null) {
            progressService.incrementBusy();
        }
    }

    @Override
	public synchronized void viewerUpdatesComplete() {
        IWorkbenchSiteProgressService progressService =
            getSite().getAdapter(IWorkbenchSiteProgressService.class);
        if (progressService != null) {
            progressService.decrementBusy();
        }
    }

    @Override
	public void modelChanged(IModelDelta delta, IModelProxy proxy) {
        updateFindAction();
    }

    private void updateFindAction() {
        IAction action= getAction(FIND_ACTION);
        if (action instanceof IUpdate) {
            ((IUpdate) action).update();
        }
    }

    /**
     * Returns whether the breadcrumb viewer is currently visible in the view.
     *
     * @since 3.5
     */
    boolean isBreadcrumbVisible() {
        return fBreadcrumbPage.equals(getCurrentPage());
    }

    /**
     * Returns whether the elements in breadcrumb's drop-down viewer should be
     * automatically expanded.
     *
     * @since 3.5
     */
    boolean getBreadcrumbDropDownAutoExpand() {
        return fBreadcrumbDropDownAutoExpand;
    }

    /**
     * Sets whether the elements in breadcrumb's drop-down viewer should be
     * automatically expanded.
     *
     * @since 3.5
     */
    void setBreadcrumbDropDownAutoExpand(boolean expand) {
        fBreadcrumbDropDownAutoExpand = expand;
    }

}
