package org.python.pydev.debug.views; 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.ILaunchManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.ProgressBar; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.UIJob; import org.python.pydev.debug.model.PyDebugModelPresentation; import org.python.pydev.shared_ui.utils.RunInUiThread; /** * Base class for some views that are debug-related and have a tree to show contents. */ public abstract class BaseDebugView extends ViewPart { /** * Note: not using a PyFilteredTree because filtering debug views can get recursive as structures in the debugger * may be recursive. */ protected TreeViewer viewer; protected ProgressBar progressBar; protected Composite parent; protected ITreeContentProvider provider; private ILaunchAndDebugListener listener; @Override public void createPartControl(Composite parent) { IViewSite viewSite = getViewSite(); if (viewSite != null) { configureToolBar(viewSite); } parent.setLayout(new GridLayout(1, true)); viewer = new TreeViewer(parent); provider = createContentProvider(); viewer.setContentProvider(provider); viewer.setLabelProvider(new PyDebugModelPresentation(false)); GridDataFactory.fillDefaults().grab(true, true).applyTo(viewer.getTree()); MenuManager menuManager = new MenuManager(); Menu menu = menuManager.createContextMenu(viewer.getTree()); viewer.getTree().setMenu(menu); IWorkbenchPartSite site = getSite(); site.registerContextMenu(menuManager, viewer); site.setSelectionProvider(viewer); this.parent = parent; listener = createListener(); if (listener != null) { DebugPlugin plugin = DebugPlugin.getDefault(); ILaunchManager launchManager = plugin.getLaunchManager(); launchManager.addLaunchListener(listener); plugin.addDebugEventListener(listener); } } /** * The content provider to provide contents for our tree. */ protected abstract ITreeContentProvider createContentProvider(); /** * A listener which will be added when the view is created and will be removed when the view is disposed. * * Usually this listener will be responsible for cleaning things up when the debug launch is terminated. */ protected abstract ILaunchAndDebugListener createListener(); /** * Should be overridden to add actions to the toolbar/menubar. */ protected abstract void configureToolBar(IViewSite viewSite); @Override public void dispose() { super.dispose(); if (listener != null) { DebugPlugin plugin = DebugPlugin.getDefault(); ILaunchManager launchManager = plugin.getLaunchManager(); launchManager.removeLaunchListener(listener); plugin.removeDebugEventListener(listener); } this.clear(); } /** * Set focus to our tree. */ @Override public void setFocus() { if (viewer == null || viewer.getTree().isDisposed()) { return; } viewer.getTree().setFocus(); } public void clear() { updateTreeJob.schedule(); } protected final Job updateTreeJob = new UIJob("Update PyDev Debug view") { @Override public IStatus runInUIThread(IProgressMonitor monitor) { if (viewer.getTree().isDisposed()) { return Status.OK_STATUS; } onSetTreeInput(); RunInUiThread.async(new Runnable() { @Override public void run() { if (viewer != null && viewer.getTree() != null && !viewer.getTree().isDisposed()) { Object input = viewer.getInput(); makeLastVisibleInTree(input); } } }); return Status.OK_STATUS; } }; /** * Subclasses should override to make the last item added in the tree visible. input is the tree input. */ protected abstract void makeLastVisibleInTree(Object input); /** * Subclasses must override to set the input of the tree. */ protected abstract void onSetTreeInput(); // Progress bar handling ------------------------------------------------------------------------------------------- private int inProgress = 0; private Object progressLock = new Object(); /** * Finishes showing the progress bar in the view. */ protected void endProgress() { synchronized (progressLock) { inProgress -= 1; } updateProgressBarJob.schedule(); //Dispose ASAP } /** * Starts to show an 'unknown' progress bar in the view. */ protected void startProgress() { synchronized (progressLock) { inProgress += 1; } updateProgressBarJob.schedule(600); //Wait a bit before creating the progress bar } Job updateProgressBarJob = new UIJob("Update Referrers view") { @Override public IStatus runInUIThread(IProgressMonitor monitor) { synchronized (progressLock) { if (inProgress > 0) { if (progressBar == null || progressBar.isDisposed()) { progressBar = new ProgressBar(parent, SWT.INDETERMINATE | SWT.SMOOTH); GridDataFactory.fillDefaults().grab(true, false).applyTo(progressBar); parent.layout(true); final Display display = Display.getCurrent(); display.timerExec(100, new Runnable() { int i = 0; @Override public void run() { if (progressBar == null || progressBar.isDisposed()) { return; } progressBar.setSelection(i++); display.timerExec(100, this); } }); } } else { if (progressBar != null && !progressBar.isDisposed()) { progressBar.dispose(); progressBar = null; parent.layout(true); } } } return Status.OK_STATUS; } }; }