package org.erlide.tracing.core.views; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.debug.ui.IDebugUIConstants; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.RowData; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.ViewPart; import org.erlide.tracing.core.Activator; import org.erlide.tracing.core.ITraceNodeObserver; import org.erlide.tracing.core.TraceBackend; import org.erlide.tracing.core.TracingStatus; import org.erlide.tracing.core.mvc.model.TraceCollections; import org.erlide.tracing.core.mvc.model.treenodes.FunctionNode; import org.erlide.tracing.core.mvc.model.treenodes.ITreeNode; import org.erlide.tracing.core.mvc.model.treenodes.ModuleNode; import org.erlide.tracing.core.mvc.model.treenodes.TracingResultsNode; import org.erlide.tracing.core.mvc.view.TreeContentProvider; import org.erlide.tracing.core.mvc.view.TreeLabelProvider; import org.erlide.tracing.core.preferences.PreferenceNames; import org.erlide.tracing.core.ui.dialogs.RunnableWithProgress; import org.erlide.tracing.core.utils.TracingStatusHandler; import org.erlide.ui.util.ErlModelUtils; import org.erlide.util.ErlLogger; public class TreeViewerView extends ViewPart implements ITraceNodeObserver { private TreeViewer treeViewer; private Long index; private boolean correctInput = false; private Text traceIndexField; private RunnableWithProgress task; private Composite buttonsPanel; private Button previousButton; private Button nextButton; private Button showButton; private Label label; private TracingStatus status; public TreeViewerView() { TraceBackend.getInstance().addListener(this); } @Override public void dispose() { TraceBackend.getInstance().removeListener(this); super.dispose(); } @Override public void createPartControl(final Composite parent) { // layout final GridLayout containerLayout = new GridLayout(1, false); containerLayout.marginWidth = 0; containerLayout.marginHeight = 0; containerLayout.verticalSpacing = 3; parent.setLayout(containerLayout); // children createTreeViewerPanel(parent); createButtonsPanel(parent); } private void createTreeViewerPanel(final Composite parent) { final Composite container = new Composite(parent, SWT.NONE); container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); container.setLayout(new GridLayout()); // treeViewer = new TreeViewer(container, SWT.VIRTUAL); treeViewer = new TreeViewer(container, SWT.SINGLE); treeViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); // providers treeViewer.setContentProvider(new TreeContentProvider(treeViewer, true)); treeViewer.setLabelProvider(new TreeLabelProvider()); // input treeViewer.setInput(TraceCollections.getTracesList()); // listener treeViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(final DoubleClickEvent event) { doDoubleClick(event); } }); } private void createButtonsPanel(final Composite parent) { buttonsPanel = new Composite(parent, SWT.NONE); buttonsPanel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); buttonsPanel.setLayout(new RowLayout()); // "Previous" button previousButton = new Button(buttonsPanel, SWT.PUSH | SWT.CENTER); previousButton.setToolTipText("Show previous trace set"); previousButton.setImage(PlatformUI.getWorkbench().getSharedImages() .getImage(ISharedImages.IMG_TOOL_BACK)); previousButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { task = new RunnableWithProgress("Loading trace results...") { @Override public void doAction() { final int limit = Activator.getDefault().getPreferenceStore() .getInt(PreferenceNames.TRACES_LOAD_LIMIT); final long startIndex = Math.max(1L, index - limit); final long endIndex = startIndex + limit - 1; TraceBackend.getInstance().loadDataFromFile(startIndex, endIndex); } }; executeTask(); } }); // "Next" button nextButton = new Button(buttonsPanel, SWT.PUSH | SWT.CENTER); nextButton.setToolTipText("Show next trace set"); nextButton.setImage(PlatformUI.getWorkbench().getSharedImages() .getImage(ISharedImages.IMG_TOOL_FORWARD)); nextButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { task = new RunnableWithProgress("Loading trace results...") { @Override public void doAction() { final int limit = Activator.getDefault().getPreferenceStore() .getInt(PreferenceNames.TRACES_LOAD_LIMIT); final long endIndex = Math.min(index + limit * 2 - 1, TraceBackend .getInstance().getActiveResultSet().getSize()); final long startIndex = endIndex - limit + 1; TraceBackend.getInstance().loadDataFromFile(startIndex, endIndex); } }; executeTask(); } }); // "Show" button showButton = new Button(buttonsPanel, SWT.PUSH | SWT.CENTER); showButton.setToolTipText("Show selected trace set"); showButton.setImage(DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_LAUNCH_RUN)); showButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { doSelection(); } }); // Text field traceIndexField = new Text(buttonsPanel, SWT.SINGLE | SWT.BORDER); traceIndexField.setToolTipText("Select index of first trace event to display"); traceIndexField.setLayoutData(new RowData(60, SWT.DEFAULT)); traceIndexField.addListener(SWT.Modify, new Listener() { @Override public void handleEvent(final Event event) { try { correctInput = false; final Long value = new Long(traceIndexField.getText()); if (value >= 1 && value <= TraceBackend.getInstance() .getActiveResultSet().getSize()) { index = value; showButton.setEnabled( nextButton.isEnabled() || previousButton.isEnabled()); correctInput = true; } else { showButton.setEnabled(false); } } catch (final Exception e) { showButton.setEnabled(false); } } }); traceIndexField.addKeyListener(new KeyListener() { @Override public void keyReleased(final KeyEvent e) { if (e.keyCode == SWT.CR && correctInput) { doSelection(); } } @Override public void keyPressed(final KeyEvent e) { } }); // label label = new Label(buttonsPanel, SWT.NONE); label.setLayoutData(new RowData(200, SWT.DEFAULT)); updateButtonsPanel(); } private void doSelection() { task = new RunnableWithProgress("Loading trace results...") { @Override public void doAction() { final int limit = Activator.getDefault().getPreferenceStore() .getInt(PreferenceNames.TRACES_LOAD_LIMIT); TraceBackend.getInstance().loadDataFromFile(index, index + limit - 1); } }; executeTask(); } private void executeTask() { try { final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow() .getShell(); new ProgressMonitorDialog(shell).run(true, false, task); doAfterLoadingTraces(); } catch (final Exception exception) { ErlLogger.error(exception); } finally { task = null; } } private void updateButtonsPanel() { final TracingResultsNode resultSet = TraceBackend.getInstance() .getActiveResultSet(); if (resultSet != null) { index = TraceBackend.getInstance().getStartIndex(); final int size = TraceCollections.getTracesList().size(); final boolean previousEnabled = index > 1; final boolean nextEnabled = index + size - 1 < resultSet.getSize(); previousButton.setEnabled(previousEnabled); nextButton.setEnabled(nextEnabled); showButton.setEnabled(previousEnabled || nextEnabled); traceIndexField.setEnabled(previousEnabled || nextEnabled); traceIndexField.setText(String.valueOf(index)); buttonsPanel.setEnabled(true); final StringBuilder stringBuilder = new StringBuilder(" ("); if (resultSet.getSize() == 0) { stringBuilder.append("no traces)"); } else { stringBuilder.append(index).append(" - ").append(index + size - 1) .append(" of ").append(resultSet.getSize()).append(" traces)"); } label.setText(stringBuilder.toString()); } else { traceIndexField.setText(""); label.setText(""); buttonsPanel.setEnabled(false); } } /** * Action performed when user double-clicks on tree element. * * @param event */ private void doDoubleClick(final DoubleClickEvent event) { final IStructuredSelection selection = (IStructuredSelection) event .getSelection(); final ITreeNode treeNode = (ITreeNode) selection.getFirstElement(); try { if (treeNode instanceof FunctionNode) { final FunctionNode functionNode = (FunctionNode) treeNode; ErlModelUtils.openMFA(functionNode.getModuleName(), functionNode.getFunctionName(), functionNode.getArity()); } else if (treeNode instanceof ModuleNode) { final ModuleNode moduleNode = (ModuleNode) treeNode; ErlModelUtils.openModule(moduleNode.getModuleName()); } } catch (final CoreException e) { ErlLogger.error(e); } } private void doAfterLoadingTraces() { if (TracingStatus.OK.equals(status)) { updateButtonsPanel(); treeViewer.refresh(); } if (task != null) { // task was executed from this class so this class is responsible // for handling status TracingStatusHandler.handleStatus(status); } } @Override public void setFocus() { } @Override public void startTracing() { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { buttonsPanel.setEnabled(false); } }); } @Override public void finishLoadingFile(final TracingStatus theStatus) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (TracingStatus.OK.equals(theStatus)) { treeViewer.refresh(); } } }); } @Override public void finishLoadingTraces(final TracingStatus theStatus) { status = theStatus; if (task != null) { // when loading was initialized from this view task.finish(); } else { // when loading was initialized outside this view Display.getDefault().asyncExec(new Runnable() { @Override public void run() { doAfterLoadingTraces(); } }); } } @Override public void removeFile() { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { updateButtonsPanel(); treeViewer.refresh(); } }); } @Override public void updateTracePatterns() { } }