org.eclipse.ptp.debug.ui.views.ParallelDebugView.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ptp.debug.ui.views.ParallelDebugView.java

Source

/*******************************************************************************
 * Copyright (c) 2005 The Regents of the University of California. 
 * This material was produced under U.S. Government contract W-7405-ENG-36 
 * for Los Alamos National Laboratory, which is operated by the University 
 * of California for the U.S. Department of Energy. The U.S. Government has 
 * rights to use, reproduce, and distribute this software. NEITHER THE 
 * GOVERNMENT NOR THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR 
 * ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified 
 * to produce derivative works, such modified software should be clearly marked, 
 * so as not to confuse it with the version available from LANL.
 * 
 * Additionally, this program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * LA-CC 04-115
 *******************************************************************************/
package org.eclipse.ptp.debug.ui.views;

import org.eclipse.core.runtime.CoreException;
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.DebugException;
import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer;
import org.eclipse.debug.ui.AbstractDebugView;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.ptp.core.elements.IPJob;
import org.eclipse.ptp.core.elements.attributes.JobAttributes;
import org.eclipse.ptp.debug.core.IPSession;
import org.eclipse.ptp.debug.core.TaskSet;
import org.eclipse.ptp.debug.core.model.IPDebugElement;
import org.eclipse.ptp.debug.core.model.IPDebugTarget;
import org.eclipse.ptp.debug.internal.ui.actions.RegisterAction;
import org.eclipse.ptp.debug.internal.ui.actions.ResumeAction;
import org.eclipse.ptp.debug.internal.ui.actions.StepIntoAction;
import org.eclipse.ptp.debug.internal.ui.actions.StepOverAction;
import org.eclipse.ptp.debug.internal.ui.actions.StepReturnAction;
import org.eclipse.ptp.debug.internal.ui.actions.SuspendAction;
import org.eclipse.ptp.debug.internal.ui.actions.TerminateAction;
import org.eclipse.ptp.debug.internal.ui.actions.UnregisterAction;
import org.eclipse.ptp.debug.internal.ui.views.AbstractPDebugViewEventHandler;
import org.eclipse.ptp.debug.ui.IPTPDebugUIConstants;
import org.eclipse.ptp.debug.ui.PTPDebugUIPlugin;
import org.eclipse.ptp.debug.ui.UIDebugManager;
import org.eclipse.ptp.debug.ui.messages.Messages;
import org.eclipse.ptp.internal.ui.model.PProcessUI;
import org.eclipse.ptp.ui.IElementManager;
import org.eclipse.ptp.ui.actions.ParallelAction;
import org.eclipse.ptp.ui.model.IElement;
import org.eclipse.ptp.ui.model.IElementHandler;
import org.eclipse.ptp.ui.model.IElementSet;
import org.eclipse.ptp.ui.views.IIconCanvasActionListener;
import org.eclipse.ptp.ui.views.ParallelJobsView;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.progress.WorkbenchJob;

/**
 * @author clement chu
 * 
 */
public class ParallelDebugView extends ParallelJobsView {
    // actions
    protected ParallelAction resumeAction = null;
    protected ParallelAction suspendAction = null;
    protected ParallelAction terminateAction = null;
    protected ParallelAction stepIntoAction = null;
    protected ParallelAction stepOverAction = null;
    protected ParallelAction stepReturnAction = null;
    protected ParallelAction registerAction = null;
    protected ParallelAction unregisterAction = null;
    protected AbstractPDebugViewEventHandler fEventHandler = null;
    protected Viewer launchViewer = null;

    protected ISelectionChangedListener debugViewSelectChangedListener = new ISelectionChangedListener() {
        public void selectionChanged(SelectionChangedEvent event) {
            ISelection selection = event.getSelection();
            if (!selection.isEmpty()) {
                if (selection instanceof IStructuredSelection) {
                    Object element = ((IStructuredSelection) selection).getFirstElement();
                    if (element instanceof IPDebugElement) {
                        if (canvas != null && !canvas.isDisposed()) {
                            if (getCurrentSet() != null) {
                                int index = getCurrentSet()
                                        .findIndexByName(String.valueOf(((IPDebugElement) element).getID()));
                                if (index > -1) {
                                    canvas.unselectAllElements();
                                    canvas.selectElement(index);
                                    canvas.setCurrentSelection(false);
                                    refresh(false);
                                }
                            }
                        }
                    }
                }
            }
        }
    };

    /*
     * private MouseAdapter debugViewMouseAdapter = new MouseAdapter() { public void mouseUp(MouseEvent event) { Object test =
     * event.getSource(); if (test instanceof Tree) { TreeItem[] items = ((Tree)test).getSelection(); Object[] targets = new
     * Object[items.length]; for (int i=0; i<items.length; i++) { targets[i] = items[i].getData(); } selectElements(targets); } } };
     */
    public ParallelDebugView(IElementManager manager) {
        super(manager);
    }

    public ParallelDebugView() {
        this(PTPDebugUIPlugin.getUIDebugManager());
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.IWorkbenchPart#dispose()
     */
    @Override
    public void dispose() {
        Viewer viewer = getDebugViewer();
        if (viewer != null) {
            viewer.removeSelectionChangedListener(debugViewSelectChangedListener);
        }
        if (getEventHandler() != null) {
            getEventHandler().dispose();
        }
        super.dispose();
    }

    /**
     * @return
     */
    protected Viewer getDebugViewer() {
        if (launchViewer == null) {
            IWorkbenchPage page = getViewSite().getPage();
            if (page == null) {
                return null;
            }
            IViewPart part = page.findView(IDebugUIConstants.ID_DEBUG_VIEW);
            if (part == null) {
                try {
                    part = page.showView(IDebugUIConstants.ID_DEBUG_VIEW);
                } catch (PartInitException e) {
                    return null;
                }
            }
            if (part != null && part instanceof AbstractDebugView) {
                launchViewer = ((AbstractDebugView) part).getViewer();
                if (launchViewer != null) {
                    launchViewer.addSelectionChangedListener(debugViewSelectChangedListener);
                }
            }
        }
        return launchViewer;
    }

    /*
     * FIXME does not work if create a new set. Currently we can task id to identify icon, but viewer is using order private void
     * selectElements(final Object[] objects) { SafeRunnable.run(new SafeRunnable() { public void run() { if (!canvas.isDisposed())
     * { canvas.unselectAllElements(); for (int i=0; i<objects.length; i++) { Object obj = objects[i]; int id = ((UIDebugManager)
     * manager).getSelectedRegisteredTasks(obj); if (id > -1) { if (!canvas.isSelected(id)) canvas.selectElement(id); } }
     * canvas.redraw(); canvas.setCurrentSelection(false); } } }); }
     */

    /**
     * Sets the event handler for this view
     * 
     * @param eventHandler
     *            event handler
     */
    protected void setEventHandler(AbstractPDebugViewEventHandler eventHandler) {
        this.fEventHandler = eventHandler;
    }

    /**
     * Returns the event handler for this view
     * 
     * @return The event handler for this view
     */
    protected AbstractPDebugViewEventHandler getEventHandler() {
        return this.fEventHandler;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ptp.ui.views.ParallelJobView#createView(org.eclipse.swt.widgets .Composite)
     */
    @Override
    public void createView(Composite parent) {
        super.createView(parent);
        setEventHandler(new ParallelDebugViewEventHandler(this));
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ptp.ui.views.AbstractParallelSetView#fillContextMenu(org. eclipse.jface.action.IMenuManager)
     */
    @Override
    protected void fillContextMenu(IMenuManager manager) {
        super.fillContextMenu(manager);
        manager.add(new Separator(IPTPDebugUIConstants.THREAD_GROUP));
        manager.add(new Separator(IPTPDebugUIConstants.STEP_GROUP));
        manager.add(new GroupMarker(IPTPDebugUIConstants.STEP_INTO_GROUP));
        manager.add(new GroupMarker(IPTPDebugUIConstants.STEP_OVER_GROUP));
        manager.add(new GroupMarker(IPTPDebugUIConstants.STEP_RETURN_GROUP));
        manager.add(new GroupMarker(IPTPDebugUIConstants.EMPTY_STEP_GROUP));
        manager.add(new Separator(IPTPDebugUIConstants.REG_GROUP));

        manager.appendToGroup(IPTPDebugUIConstants.THREAD_GROUP, resumeAction);
        manager.appendToGroup(IPTPDebugUIConstants.THREAD_GROUP, suspendAction);
        manager.appendToGroup(IPTPDebugUIConstants.THREAD_GROUP, terminateAction);
        manager.appendToGroup(IPTPDebugUIConstants.STEP_INTO_GROUP, stepIntoAction);
        manager.appendToGroup(IPTPDebugUIConstants.STEP_OVER_GROUP, stepOverAction);
        manager.appendToGroup(IPTPDebugUIConstants.EMPTY_STEP_GROUP, stepReturnAction);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ptp.ui.views.AbstractParallelSetView#createToolBarActionGroup (org.eclipse.jface.action.IToolBarManager)
     */
    @Override
    protected void createToolBarActionGroup(IToolBarManager toolBarMgr) {
        toolBarMgr.add(new Separator(IPTPDebugUIConstants.THREAD_GROUP));
        toolBarMgr.add(new Separator(IPTPDebugUIConstants.STEP_GROUP));
        toolBarMgr.add(new GroupMarker(IPTPDebugUIConstants.STEP_INTO_GROUP));
        toolBarMgr.add(new GroupMarker(IPTPDebugUIConstants.STEP_OVER_GROUP));
        toolBarMgr.add(new GroupMarker(IPTPDebugUIConstants.STEP_RETURN_GROUP));
        toolBarMgr.add(new GroupMarker(IPTPDebugUIConstants.EMPTY_STEP_GROUP));
        toolBarMgr.add(new Separator(IPTPDebugUIConstants.REG_GROUP));
        super.createToolBarActionGroup(toolBarMgr);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ptp.ui.views.AbstractParallelSetView#createToolBarActions (org.eclipse.jface.action.IToolBarManager)
     */
    @Override
    protected void createToolBarActions(IToolBarManager toolBarMgr) {
        resumeAction = new ResumeAction(this);
        suspendAction = new SuspendAction(this);
        terminateAction = new TerminateAction(this);
        stepIntoAction = new StepIntoAction(this);
        stepOverAction = new StepOverAction(this);
        stepReturnAction = new StepReturnAction(this);
        registerAction = new RegisterAction(this);
        unregisterAction = new UnregisterAction(this);

        toolBarMgr.appendToGroup(IPTPDebugUIConstants.THREAD_GROUP, resumeAction);
        toolBarMgr.appendToGroup(IPTPDebugUIConstants.THREAD_GROUP, suspendAction);
        toolBarMgr.appendToGroup(IPTPDebugUIConstants.THREAD_GROUP, terminateAction);
        toolBarMgr.appendToGroup(IPTPDebugUIConstants.STEP_INTO_GROUP, stepIntoAction);
        toolBarMgr.appendToGroup(IPTPDebugUIConstants.STEP_OVER_GROUP, stepOverAction);
        toolBarMgr.appendToGroup(IPTPDebugUIConstants.STEP_RETURN_GROUP, stepReturnAction);
        toolBarMgr.appendToGroup(IPTPDebugUIConstants.REG_GROUP, registerAction);
        toolBarMgr.appendToGroup(IPTPDebugUIConstants.REG_GROUP, unregisterAction);

        super.buildInToolBarActions(toolBarMgr);
        // createOrientationActions();
    }

    /**
     * Create orientation actions
     * 
     */
    protected void createOrientationActions() {
        IActionBars actionBars = getViewSite().getActionBars();
        IMenuManager viewMenu = actionBars.getMenuManager();
        viewMenu.add(new Separator());
    }

    /*******************************************************************************************************************************************************************************************************************************************************************************************************
     * IIconCanvasActionListener
     ******************************************************************************************************************************************************************************************************************************************************************************************************/
    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ptp.ui.views.IIconCanvasActionListener#handleAction(int, int)
     */
    @Override
    public void handleAction(int type, int index) {
        IElement element = canvas.getElement(index);
        if (type == IIconCanvasActionListener.DOUBLE_CLICK_ACTION) {
            doubleClick(element);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ptp.ui.views.AbstractParallelElementView#doubleClick(org. eclipse.ptp.ui.model.IElement)
     */
    @Override
    public void doubleClick(IElement element) {
        try {
            registerElement(element);
        } catch (CoreException e) {
            PTPDebugUIPlugin.errorDialog(getViewSite().getShell(), Messages.ParallelDebugView_0, e.getStatus());
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ptp.ui.views.AbstractParallelElementView#getToolTipText(java .lang.Object)
     */
    @Override
    public String[] getToolTipText(Object obj) {
        if (obj == null) {
            return new String[] { "", "" }; //$NON-NLS-1$ //$NON-NLS-2$
        }
        String[] header = super.getToolTipText(obj);
        // FIXME PProcessUI goes away when we address UI scalability. See Bug
        // 311057
        PProcessUI proc = (PProcessUI) obj;
        String variableText = ((UIDebugManager) manager).getValueText(proc.getJobRank(), this);
        if (variableText != null && variableText.length() > 0) {
            return new String[] { header[0], variableText };
        }
        return header;
    }

    /**
     * Register element
     * 
     * @param element
     * @throws CoreException
     */
    public void registerElement(IElement element) throws CoreException {
        if (element.isRegistered()) {
            ((UIDebugManager) manager).unregisterElements(new IElement[] { element });
        } else {
            ((UIDebugManager) manager).registerElements(new IElement[] { element });
        }
    }

    /**
     * Register selected elements
     * 
     * @throws CoreException
     */
    public void registerSelectedElements() throws CoreException {
        if (cur_element_set != null) {
            ((UIDebugManager) manager).registerElements(canvas.getSelectedElements());
        }
    }

    /**
     * Unregister selected elements
     * 
     * @throws CoreException
     */
    public void unregisterSelectedElements() throws CoreException {
        if (cur_element_set != null) {
            ((UIDebugManager) manager).unregisterElements(canvas.getSelectedElements());
        }
    }

    // Update button
    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ptp.ui.views.AbstractParallelSetView#updateAction()
     */
    @Override
    public void updateAction() {
        super.updateAction();
        IPJob job = ((UIDebugManager) manager).findJobById(getCurrentID());
        boolean isDebugMode = ((UIDebugManager) manager).isDebugMode(job);
        boolean isRunning = ((UIDebugManager) manager).isRunning(job);
        registerAction.setEnabled(isRunning && isDebugMode);
        unregisterAction.setEnabled(isRunning && isDebugMode);
        suspendAction.setEnabled(isRunning && isDebugMode);
        terminateAction.setEnabled(isRunning);
        if (isRunning && isDebugMode) {
            IElementHandler elementHandler = getCurrentElementHandler();
            if (elementHandler != null) {
                updateDebugButtons(getCurrentID());
            }
        } else {
            resumeAction.setEnabled(false);
            stepIntoAction.setEnabled(false);
            stepOverAction.setEnabled(false);
            stepReturnAction.setEnabled(false);
            suspendAction.setEnabled(false);
        }
    }

    /**
     * Update debug button
     * 
     * @since 4.0
     */
    private void updateDebugButtons(String jobId) {
        IPSession session = ((UIDebugManager) manager).getDebugSession(jobId);
        if (session == null) {
            return;
        }
        IElementSet set = getCurrentSet();
        if (set == null) {
            return;
        }

        TaskSet terminatedTasks = session.getPDISession().getTaskManager().getTerminatedTasks();
        TaskSet suspendedTasks = session.getPDISession().getTaskManager().getSuspendedTasks();
        TaskSet stepReturnTasks = session.getPDISession().getTaskManager().getCanStepReturnTasks();
        if (terminatedTasks == null || suspendedTasks == null || stepReturnTasks == null) {
            return;
        }

        int setSize = set.size();
        int totalTerminatedSize = 0;
        int totalSuspendedSize = 0;
        int totalStepReturnSize = 0;
        if (set.isRootSet()) {
            totalTerminatedSize = terminatedTasks.cardinality();
            totalSuspendedSize = suspendedTasks.isEmpty() ? 0 : suspendedTasks.cardinality();
            totalStepReturnSize = stepReturnTasks.isEmpty() ? 0 : stepReturnTasks.cardinality();
        } else {
            try {
                TaskSet setTasks = ((UIDebugManager) manager).getTasks(set.getID());
                if (setTasks == null) {
                    return;
                }
                setSize = setTasks.cardinality();
                TaskSet setTerminatedTasks = session.getPDISession().getTaskManager()
                        .getTerminatedTasks(setTasks.copy());
                totalTerminatedSize = setTerminatedTasks.cardinality();
                // size equals: the set contains all terminated processes
                if (setSize != totalTerminatedSize) {
                    TaskSet setSuspendedTasks = session.getPDISession().getTaskManager()
                            .getSuspendedTasks(setTasks.copy());
                    totalSuspendedSize = setSuspendedTasks.cardinality();
                    TaskSet setCanStepReturnTasks = session.getPDISession().getTaskManager()
                            .getCanStepReturnTasks(setTasks.copy());
                    totalStepReturnSize = setCanStepReturnTasks.cardinality();
                }
            } catch (CoreException e) {
                PTPDebugUIPlugin.log(e);
            }
        }
        // System.err.println("Set size: " + setSize + ", T: " +
        // totalTerminatedSize + ", S: "+ totalSuspendedSize + ", Return: " +
        // totalStepReturnSize);
        boolean enabledTerminatedButton = (setSize != totalTerminatedSize);
        terminateAction.setEnabled(enabledTerminatedButton);
        if (enabledTerminatedButton) {// not all processes terminated
            resumeAction.setEnabled(totalSuspendedSize > 0);
            boolean enableStepButtons = (setSize == totalSuspendedSize + totalTerminatedSize);
            stepIntoAction.setEnabled(enableStepButtons);
            stepOverAction.setEnabled(enableStepButtons);
            suspendAction.setEnabled(!enableStepButtons);
            stepReturnAction.setEnabled(enableStepButtons && totalStepReturnSize > 0);
        } else {// all process terminated
            resumeAction.setEnabled(false);
            stepIntoAction.setEnabled(false);
            stepOverAction.setEnabled(false);
            stepReturnAction.setEnabled(false);
            suspendAction.setEnabled(false);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ptp.ui.views.AbstractParallelElementView#selectionChanged (org.eclipse.jface.viewers.SelectionChangedEvent)
     */
    @Override
    public void selectionChanged(SelectionChangedEvent event) {
        super.selectionChanged(event);
        ISelection selection = event.getSelection();
        if (!selection.isEmpty() && selection instanceof IStructuredSelection) {
            IStructuredSelection structSelection = (IStructuredSelection) selection;
            if (structSelection.size() == 1 && structSelection.getFirstElement() instanceof IElement) {
                IElement element = (IElement) structSelection.getFirstElement();
                if (element.isRegistered()) {
                    try {
                        focusOnDebugTarget(getJobManager().getJob().getID(), Integer.parseInt(element.getName()));
                    } catch (NumberFormatException e) {
                        // The element name had better be the process number
                    }
                }
            }
        }
    }

    /*
     * public void drawSpecial(Object obj, GC gc, int x_loc, int y_loc, int width, int height) { super.drawSpecial(obj, gc, x_loc,
     * y_loc, width, height); if (cur_element_set != null && obj instanceof DebugElement) { DebugElement element =
     * (DebugElement)obj; switch(element.getType()) { case DebugElement.VALUE_DIFF:
     * gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_BLUE)); gc.drawLine(x_loc, y_loc, x_loc+width, y_loc+height);
     * gc.drawLine(x_loc, y_loc+height, x_loc+width, y_loc); break; } } }
     */

    /******************************************************
     * focus on debug target on debug view
     ******************************************************/
    private IDebugElement getDebugElement(String jobId, int task_id) {
        IPSession session = ((UIDebugManager) manager).getDebugSession(jobId);
        if (session != null) {
            return session.getLaunch().getDebugTarget(task_id);
        }
        return null;
    }

    /**
     * @since 4.0
     */
    public void focusOnDebugTarget(final String jobId, final int task_id) {
        WorkbenchJob wjob = new WorkbenchJob(Messages.ParallelDebugView_3) {
            @Override
            public IStatus runInUIThread(IProgressMonitor monitor) {
                Viewer viewer = getDebugViewer();
                if (viewer != null) {
                    ISelection selection = viewer.getSelection();
                    // ISelection selection =
                    // getViewSite().getPage().getSelection(IDebugUIConstants.ID_DEBUG_VIEW);
                    if (selection instanceof IStructuredSelection) {
                        Object element = ((IStructuredSelection) selection).getFirstElement();
                        if (element instanceof IPDebugElement) {
                            if (((IPDebugElement) element).getID() != task_id) {
                                // FIXME: only work if all elements are collapse
                                // ((TreeViewer)viewer).collapseAll();

                                IDebugElement focusElement = getDebugElement(jobId, task_id);
                                if (focusElement == null) {
                                    // do nothing if cannot find debug target
                                    return Status.CANCEL_STATUS;
                                }
                                selectOnViewer(viewer, focusElement);
                                // set focus element to selected element
                                element = focusElement;
                            }
                        } else {
                            IDebugElement focusElement = getDebugElement(jobId, task_id);
                            if (focusElement == null) {
                                // do nothing if cannot find debug target
                                return Status.CANCEL_STATUS;
                            }
                            selectOnViewer(viewer, focusElement);
                            // set focus element to selected element
                            element = focusElement;
                        }

                        if (element instanceof IStackFrame) {
                            // do nothing if selected element is stack frame
                            return Status.CANCEL_STATUS;
                        }
                        if (element instanceof IThread) {
                            // expand thread this thread
                            expandOnViewer(viewer, (IThread) element);
                            return Status.OK_STATUS;
                        }
                        if (element instanceof IDebugTarget) {
                            // expand debug target this thread
                            expandOnViewer(viewer, (IDebugTarget) element);
                            return Status.OK_STATUS;
                        }
                    }
                }
                return Status.CANCEL_STATUS;
            }
        };
        // set job priority very low to make sure it is executed at last
        wjob.setPriority(Job.DECORATE);
        wjob.schedule(500);
    }

    private void expandOnViewer(final Viewer viewer, final IDebugElement element) {
        WorkbenchJob wjob = new WorkbenchJob(Messages.ParallelDebugView_4) {
            @Override
            public IStatus runInUIThread(IProgressMonitor monitor) {
                ((TreeViewer) viewer).setExpandedState(element, true);
                try {
                    if (element instanceof IThread) {
                        selectOnViewer(viewer, ((IThread) element).getTopStackFrame());
                        return Status.OK_STATUS;
                    }
                    if (element instanceof IDebugTarget) {
                        IThread[] threads = ((IPDebugTarget) element).getThreads();
                        if (threads.length > 0) {
                            expandOnViewer(viewer, threads[0]);
                            return Status.OK_STATUS;
                        }
                        return Status.CANCEL_STATUS;
                    }
                } catch (DebugException e) {
                    return Status.CANCEL_STATUS;
                }
                return Status.OK_STATUS;
            }
        };
        // set job priority very low to make sure it is executed at last
        wjob.setPriority(Job.DECORATE);
        wjob.schedule();
    }

    private void selectOnViewer(final Viewer viewer, final IDebugElement element) {
        if (element != null) {
            WorkbenchJob wjob = new WorkbenchJob(Messages.ParallelDebugView_5) {
                @Override
                public IStatus runInUIThread(IProgressMonitor monitor) {
                    /*
                     * FIXME In Debug View, there is a Selection Policy. If current selected element is stack frame and its status
                     * is suspended, then it cannot allow to change selection to others. Now I used internal class to avoid policy
                     * checking
                     */
                    if (viewer instanceof InternalTreeModelViewer) {
                        ((InternalTreeModelViewer) viewer).setSelection(new StructuredSelection(element), true,
                                true);
                    } else {
                        viewer.setSelection(new StructuredSelection(element), true);
                    }
                    return Status.OK_STATUS;
                }
            };
            // set job priority very low to make sure it is executed at last
            wjob.setPriority(Job.DECORATE);
            wjob.schedule();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ptp.ui.views.ParallelJobsView#changeJobRefresh(org.eclipse .ptp.core.elements.IPJob, boolean)
     */
    @Override
    public void changeJobRefresh(IPJob job, boolean force) {
        if (job != null && job.getState() == JobAttributes.State.COMPLETED) {
            IPSession session = ((UIDebugManager) manager).getDebugSession(job.getID());
            if (session != null) {
                TaskSet tasks = session.getTasks();
                if (!session.getPDISession().getTaskManager().isAllTerminated(tasks)) {
                    session.forceStoppedDebugger(true);
                }
            }
        }
        super.changeJobRefresh(job, force);
    }
}