/******************************************************************************* * Copyright (c) 2005, 2012 eBay Inc. * All rights reserved. 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 * *******************************************************************************/ package org.eclipse.vjet.eclipse.internal.debug.ui.views; import java.net.MalformedURLException; import java.net.URI; import java.util.HashMap; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IDebugEventSetListener; import org.eclipse.debug.core.model.ISourceLocator; import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.internal.ui.DelegatingModelPresentation; import org.eclipse.debug.internal.ui.sourcelookup.SourceLookupResult; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.debug.ui.IDebugModelPresentation; import org.eclipse.dltk.mod.core.ModelException; import org.eclipse.dltk.mod.debug.core.DLTKDebugConstants; import org.eclipse.dltk.mod.debug.core.model.IScriptStackFrame; import org.eclipse.dltk.mod.debug.core.model.IScriptThread; import org.eclipse.dltk.mod.internal.core.VjoExternalSourceModule; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorRegistry; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.ISelectionService; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.UIJob; import org.eclipse.vjet.eclipse.debug.ui.VjetDebugUIPlugin; import org.eclipse.vjet.eclipse.internal.debug.command.VjetSourceCommands; import org.eclipse.vjet.eclipse.internal.debug.ui.VjetDebugUIMessages; import org.eclipse.vjet.eclipse.internal.launching.VjoDBGPSourceModule; import org.eclipse.vjet.eclipse.internal.ui.editor.VjoEditor; import org.eclipse.vjet.eclipse.launching.VjetLaunchingPlugin; import org.eclipse.vjet.eclipse.ui.VjetUIImages; /** * View for browsing running scripts in debugger engine * * Ouyang * */ public class RunningScriptView extends ViewPart implements ISelectionListener, IDebugEventSetListener { private class NameSorter extends ViewerSorter { boolean m_order; NameSorter(boolean asc) { this.m_order = asc; } @Override public int compare(Viewer viewer, Object e1, Object e2) { return m_order ? super.compare(viewer, e1, e2) : super.compare( viewer, e2, e1); } } private class RunningScriptViewContentProvider implements IStructuredContentProvider { @Override public void dispose() { // do nothing } @Override public Object[] getElements(Object inputElement) { if (!(inputElement instanceof URI[])) { return new URI[0]; } return (URI[]) inputElement; } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // do nothing } } private class RunningScriptViewLabelProvider extends LabelProvider implements ITableLabelProvider { @Override public Image getColumnImage(Object element, int columnIndex) { Image img = null; switch (columnIndex) { case 0: try { Object sourceElement = getSourceElement((URI) element); img = getElementImage(sourceElement); } catch (Exception e) { VjetLaunchingPlugin.error(e.getLocalizedMessage(), e); } break; default: break; } return img; } @Override public String getColumnText(Object element, int columnIndex) { switch (columnIndex) { case 1: return format(element); } return null; } private String format(Object element) { URI uri = (URI) element; String text = ""; if (DLTKDebugConstants.DBGP_SCHEME.equals(uri.getScheme())) { Object sourceElement; try { sourceElement = getSourceElement(uri); if (sourceElement instanceof VjoExternalSourceModule) { text = ((VjoExternalSourceModule) sourceElement) .getName(); } } catch (Exception e) { VjetLaunchingPlugin.error(e.getLocalizedMessage(), e); } } if (text.isEmpty()) { text = uri.toString(); } return text; } } public static final String ID = "org.eclipse.vjet.eclipse.debug.ui.runningScriptView"; //$NON-NLS-1$ private Map<URI, Object> m_contentsCache; private IScriptThread m_lastSelectedThread; private Action m_openFileAction; private TableViewer m_viewer; private Image m_defaultScriptImg; /* * (non-Javadoc) * * @see * org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets * .Composite) */ @Override public void createPartControl(Composite parent) { m_viewer = new TableViewer(parent, SWT.MULTI | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL); m_viewer.setContentProvider(new RunningScriptViewContentProvider()); m_viewer.setLabelProvider(new RunningScriptViewLabelProvider()); m_viewer.setSorter(new NameSorter(true)); Table table = m_viewer.getTable(); table.setHeaderVisible(true); // column 1 TableColumn column = new TableColumn(table, SWT.LEFT, 0); column.setWidth(20); // column 2 column = new TableColumn(table, SWT.LEFT, 1); column.setText(VjetDebugUIMessages.RunningScriptView_column_name); column.setWidth(600); column.addSelectionListener(new SelectionListener() { @Override public void widgetDefaultSelected(SelectionEvent e) { // do nothing } @Override public void widgetSelected(SelectionEvent e) { NameSorter sorter = (NameSorter) m_viewer.getSorter(); sorter.m_order = !sorter.m_order; m_viewer.setSorter(sorter); m_viewer.refresh(); } }); makeActions(); hookContextMenu(); hookDoubleClickAction(); contributeToActionBars(); } @Override public void dispose() { super.dispose(); // remove listeners getSite().getWorkbenchWindow().getSelectionService() .removePostSelectionListener(this); DebugPlugin.getDefault().removeDebugEventListener(this); // dispose resource if (m_defaultScriptImg != null) { m_defaultScriptImg.dispose(); } if (m_viewer != null) { m_viewer.getTable().dispose(); } } @Override public void handleDebugEvents(DebugEvent[] events) { // fetch the script list only to breakpoint suspend event for (DebugEvent event : events) { Object source = event.getSource(); int kind = event.getKind(); int detail = event.getDetail(); switch (kind) { case DebugEvent.SUSPEND: switch (detail) { case DebugEvent.BREAKPOINT: case DebugEvent.STEP_END: if (source instanceof IScriptThread) { fetchScriptList((IScriptThread) source); } break; default: break; } break; case DebugEvent.TERMINATE: if (source instanceof IScriptThread) { if (source.equals(m_lastSelectedThread)) { clear(); m_lastSelectedThread = null; } } break; default: break; } } } @Override public void init(IViewSite site) throws PartInitException { super.init(site); // create img resource IEditorRegistry editorRegistry = PlatformUI.getWorkbench() .getEditorRegistry(); IEditorDescriptor editorDesc = editorRegistry .findEditor(VjoEditor.EDITOR_ID); ImageDescriptor imageDesc = editorDesc != null ? editorDesc .getImageDescriptor() : null; m_defaultScriptImg = imageDesc != null ? imageDesc.createImage() : null; // add listener ISelectionService selectionService = getSite().getWorkbenchWindow() .getSelectionService(); selectionService.addPostSelectionListener(this); DebugPlugin.getDefault().addDebugEventListener(this); // fill data if there is debug thread selected ISelection selection = selectionService .getSelection("org.eclipse.debug.ui.DebugView"); if (selection != null) { selectionChanged(null, selection); } } @Override public void selectionChanged(IWorkbenchPart part, ISelection selection) { if (!(selection instanceof IStructuredSelection)) { return; } Object sel = ((IStructuredSelection) selection).getFirstElement(); if (!(sel instanceof IScriptThread) && !(sel instanceof IScriptStackFrame)) { return; } IScriptThread currentSelectedThread = (IScriptThread) (sel instanceof IScriptThread ? sel : ((IScriptStackFrame) sel).getThread()); // verify selection is same with last time if (m_lastSelectedThread != null && m_lastSelectedThread.equals(currentSelectedThread)) { return; } // handle event handleSelectionChangedEvent(currentSelectedThread); } /* * (non-Javadoc) * * @see org.eclipse.ui.part.WorkbenchPart#setFocus() */ @Override public void setFocus() { m_viewer.getControl().setFocus(); } protected void openEditor(Object input) { if (!(input instanceof URI)) { return; } URI uri = (URI) input; try { Object sourceElement = getSourceElement(uri); if (sourceElement == null) { return; } IDebugModelPresentation presentation = ((DelegatingModelPresentation) DebugUIPlugin .getModelPresentation()) .getPresentation(m_lastSelectedThread.getModelIdentifier()); IEditorInput editorInput = null; String editorId = null; if (presentation == null) { return; } editorInput = presentation.getEditorInput(sourceElement); editorId = presentation.getEditorId(editorInput, sourceElement); SourceLookupResult result = new SourceLookupResult(uri, sourceElement, editorId, editorInput); DebugUITools.displaySource(result, getViewSite().getPage()); } catch (Exception e) { VjetDebugUIPlugin.error(e.getLocalizedMessage(), e); } } private void clear() { new UIJob(getDisplay(), "") { @Override public IStatus runInUIThread(IProgressMonitor monitor) { m_viewer.setInput(new URI[0]); m_viewer.refresh(); return Status.OK_STATUS; } }.schedule(); } private void contributeToActionBars() { IActionBars bars = getViewSite().getActionBars(); fillLocalPullDown(bars.getMenuManager()); } private void fetchScriptList(final IScriptThread thread) { if (thread.isTerminated()) { return; } m_lastSelectedThread = thread; // clear cached source contents if (m_contentsCache != null) { m_contentsCache.clear(); } new UIJob(getDisplay(), VjetDebugUIMessages.RunningScriptView_refresh_job_name) { @Override public IStatus runInUIThread(IProgressMonitor monitor) { try { VjetSourceCommands vjetSourceCommands = new VjetSourceCommands( thread.getDbgpSession().getCommunicator()); URI[] fileURIs = vjetSourceCommands.list(); m_viewer.setInput(fileURIs); } catch (Exception e) { return new Status(IStatus.ERROR, VjetDebugUIPlugin.PLUGIN_ID, e .getLocalizedMessage(), e); } return Status.OK_STATUS; } }.schedule(); } private void fillContextMenu(IMenuManager manager) { manager.add(m_openFileAction); } private void fillLocalPullDown(IMenuManager manager) { manager.add(m_openFileAction); } private Display getDisplay() { return getViewSite().getShell().getDisplay(); } private Image getElementImage(Object object) { Image img = null; if (object instanceof VjoExternalSourceModule) { img = VjetUIImages.getImage(VjetUIImages.IMAGE_BINARY_EDITOR_TITLE); } else { img = m_defaultScriptImg; } return img; } private Object getSourceElement(URI uri) throws MalformedURLException, ModelException { if (m_contentsCache == null) { m_contentsCache = new HashMap<URI, Object>(); } Object sourceElement = m_contentsCache.get(uri); if (sourceElement != null) { return sourceElement; } if (m_lastSelectedThread == null) { return null; } ISourceLocator sourceLocator = m_lastSelectedThread.getLaunch() .getSourceLocator(); if (sourceLocator != null && sourceLocator instanceof ISourceLookupDirector) { sourceElement = ((ISourceLookupDirector) sourceLocator) .getSourceElement(uri); if (sourceElement instanceof VjoDBGPSourceModule) { VjoDBGPSourceModule sm = (VjoDBGPSourceModule) sourceElement; sm.setDBGPSession(m_lastSelectedThread.getDbgpSession()); } return sourceElement; } m_contentsCache.put(uri, sourceElement); return sourceElement; } private void handleSelectionChangedEvent(IScriptThread selectedThread) { fetchScriptList(selectedThread); } private void hookContextMenu() { MenuManager menuMgr = new MenuManager(); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { RunningScriptView.this.fillContextMenu(manager); } }); Menu menu = menuMgr.createContextMenu(m_viewer.getControl()); m_viewer.getControl().setMenu(menu); getSite().registerContextMenu(menuMgr, m_viewer); } private void hookDoubleClickAction() { m_viewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { m_openFileAction.run(); } }); } private void makeActions() { m_openFileAction = new Action( VjetDebugUIMessages.RunningScriptView_open_file_action_name) { @Override public void run() { ISelection selection = m_viewer.getSelection(); Object element = ((IStructuredSelection) selection) .getFirstElement(); openEditor(element); } }; m_openFileAction .setToolTipText(VjetDebugUIMessages.RunningScriptView_open_file_action_tooltip); } }