/******************************************************************************* * Copyright (c) 2010, 2016 Ericsson and others. * 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 * * Contributors: * Ericsson - Initial API and implementation * Dmitry Kozlov (Mentor Graphics) - Trace control view enhancements (Bug 390827) *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.internal.ui.tracepoints; import java.text.DateFormat; import java.util.Date; import java.util.concurrent.TimeUnit; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceStatusDMData2; import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.STOP_REASON_ENUM; 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.jface.action.Action; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Slider; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IMemento; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.UIJob; /** * TraceControlView Part * * This view is used to control Tracing. * * @since 2.1 */ public class TraceControlView extends ViewPart implements IViewPart { private static final int ACTION_BUTTON_INDENTATION = 10; private static final String EMPTY_STRING = ""; //$NON-NLS-1$ protected static final int UI_REFRESH_DELAY = 1000; // milliseconds public static class FailedTraceVariableCreationException extends Exception { private static final long serialVersionUID = -3042693455630687285L; FailedTraceVariableCreationException() {} FailedTraceVariableCreationException(String errorMessage) { super(errorMessage); } } /** * Action to refresh the content of the view. */ private final class RefreshViewAction extends Action { public RefreshViewAction() { setText(TracepointsMessages.TraceControlView_action_Refresh_label); setImageDescriptor(TracepointImageRegistry.getImageDescriptor(TracepointImageRegistry.ICON_Refresh_enabled)); setDisabledImageDescriptor(TracepointImageRegistry.getImageDescriptor(TracepointImageRegistry.ICON_Refresh_disabled)); } @Override public void run() { fLastRefreshTime = System.currentTimeMillis(); fTraceControlModel.updateContent(); } } /** * Action to automatically refresh the content of the view by polling trace-status. */ protected final class AutoRefreshAction extends Action { public AutoRefreshAction() { super(TracepointsMessages.TraceControlView_auto_refresh_action_label, AS_CHECK_BOX); setImageDescriptor(TracepointImageRegistry.getImageDescriptor(TracepointImageRegistry.ICON_Refresh_Auto)); } @Override public void run() { if (isChecked()) { // Call to updateContent which starts refreshUI job only if necessary // (when tracing is running) fAutoRefreshEnabled = true; fRefreshViewAction.setEnabled(false); fTraceControlModel.updateContent(); } else { fAutoRefreshEnabled = false; fRefreshViewAction.setEnabled(true); } } } /** * Action to refresh the content of the view. */ protected final class DisconnectedTracingAction extends Action { public DisconnectedTracingAction() { super(TracepointsMessages.TraceControlView_action_Disconnected_tracing_label, AS_CHECK_BOX); setImageDescriptor(TracepointImageRegistry.getImageDescriptor(TracepointImageRegistry.ICON_Disconnected_Tracing)); } @Override public void run() { fTraceControlModel.setDisconnectedTracing(isChecked()); } } protected final class OpenTraceVarDetailsAction extends Action { public OpenTraceVarDetailsAction() { setText(TracepointsMessages.TraceControlView_action_trace_variable_details); setImageDescriptor(TracepointImageRegistry.getImageDescriptor(TracepointImageRegistry.ICON_Trace_Variables)); } @Override public void run() { Shell shell = Display.getDefault().getActiveShell(); TraceVarDetailsDialog dialog = new TraceVarDetailsDialog(shell, TraceControlView.this); dialog.open(); } } protected final class ExitVisualizationModeDetailsAction extends Action { public ExitVisualizationModeDetailsAction() { setText(TracepointsMessages.TraceControlView_action_exit_visualization_mode); setImageDescriptor(TracepointImageRegistry.getImageDescriptor(TracepointImageRegistry.ICON_Exit_Visualization)); } @Override public void run() { fTraceControlModel.exitVisualizationMode(); // Content of view will be updated from the event // triggered by this asynchronous operation. } } protected TraceControlModel fTraceControlModel; protected RefreshViewAction fRefreshViewAction; protected boolean fAutoRefreshEnabled; protected DisconnectedTracingAction fDisconnectedTracingAction; protected OpenTraceVarDetailsAction fOpenTraceVarDetails; protected ExitVisualizationModeDetailsAction fExitVisualizationAction; protected AutoRefreshAction fAutoRefreshAction; protected boolean fTraceVisualization; protected Job refreshUIJob; protected Font cachedBold; protected long fLastRefreshTime; protected ITraceStatusDMData2 fLastTraceData; protected Composite fTopComposite; protected Composite fStatusComposite; protected Label fStatusLabel; protected Label fSecondaryStatusLabel; protected Composite fSecondaryStatusComposite; protected FlatButton fActionButton; protected Composite fBufferComposite; protected Label fBufferCollectedFramesLabel; protected FlatRadioButton fSetCircularBufferButton; protected CircularProgress fBufferProgress; protected Composite fFrameComposite; protected Label fFrameLabel; protected Label fFrameNumberLabel; protected Slider fFrameSlider; protected Composite fNotesComposite; protected Label fNotesContentLabel; protected Text fNotesContentText; protected Button fSetNotesButton; public TraceControlView() { } @Override public void init(IViewSite site) throws PartInitException { super.init(site); fTraceControlModel = new TraceControlModel(this); } @Override public void init(IViewSite site, IMemento memento) throws PartInitException { init(site); } @Override public void createPartControl(Composite parent) { createActions(); fTopComposite = new Composite(parent, SWT.NONE); GridLayout topLayout = new GridLayout(1, false); topLayout.marginWidth = 0; topLayout.marginHeight = 0; fTopComposite.setLayout(topLayout); fTopComposite.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE)); // Tracing status line createStatusLine(fTopComposite); // Secondary status: start time, stop time and reason setSecondaryStatusLineVisible(false, null); // Buffer line createBufferLine(fTopComposite); setBufferLineVisible(false, null, false); // Frame line createFrameLine(fTopComposite); setFrameLineVisible(false, null); // Trace notes //createNotesLine(fTopComposite); //setNotesLineVisible(false, null, false); fTraceControlModel.init(); } protected void createStatusLine(Composite parent) { fStatusComposite = new Composite(parent, SWT.NONE); GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false); gd.horizontalSpan = 2; gd.minimumHeight = 22; fStatusComposite.setLayoutData(gd); GridLayout l = new GridLayout(2,false); l.marginBottom = 0; fStatusComposite.setLayout(l); fStatusComposite.setBackgroundMode(SWT.INHERIT_FORCE); fStatusLabel = new Label(fStatusComposite, SWT.NONE); if (cachedBold == null) { FontData fontData = fStatusLabel.getFont().getFontData()[0]; fontData.setStyle(SWT.BOLD); cachedBold = new Font(fStatusLabel.getDisplay(),fontData); } fStatusLabel.setFont(cachedBold); GridData d = new GridData(SWT.LEFT, SWT.CENTER, false, false); fStatusLabel.setLayoutData(d); fStatusLabel.setText(TracepointsMessages.TraceControlView_trace_status_no_debug_session); fStatusLabel.setBackground(parent.getBackground()); fActionButton = new FlatButton(fStatusComposite, SWT.NONE); fActionButton.setText(EMPTY_STRING); GridData acGd = new GridData(SWT.LEFT, SWT.CENTER, false, false); acGd.horizontalIndent = ACTION_BUTTON_INDENTATION; fActionButton.setLayoutData(acGd); fActionButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { // Run action IHandlerService handlerService = getSite().getService(IHandlerService.class); if (handlerService == null) { GdbUIPlugin.log(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, "Missing command handler service")); //$NON-NLS-1$ return; } try { String text = ((FlatButton)e.getSource()).getText(); if (TracepointsMessages.TraceControlView_action_start.equals(text) || TracepointsMessages.TraceControlView_action_restart.equals(text)) { handlerService.executeCommand("org.eclipse.cdt.debug.ui.command.startTracing", null); //$NON-NLS-1$ } else if (TracepointsMessages.TraceControlView_action_stop.equals(text)) { handlerService.executeCommand("org.eclipse.cdt.debug.ui.command.stopTracing", null); //$NON-NLS-1$ } else if (TracepointsMessages.TraceControlView_action_finish_visualization.equals(text)) { fTraceControlModel.exitVisualizationMode(); } // Note that the content of the view will be updated due to the event // triggered by the above operations. There is no point in updating the // content ourselves since some of the above calls are asynchronous // and have not completed yet. } catch (Exception ex) { GdbUIPlugin.log(ex); } } }); fSecondaryStatusLabel = new Label(fStatusComposite, SWT.NONE | SWT.WRAP); GridData sslGd = new GridData(SWT.FILL, SWT.TOP, true, false); sslGd.horizontalSpan = 2; fSecondaryStatusLabel.setLayoutData(sslGd); fSecondaryStatusLabel.setBackground(parent.getBackground()); Label separator = new Label(fStatusComposite, SWT.SEPARATOR | SWT.HORIZONTAL); GridData sGd = new GridData(SWT.FILL, SWT.BOTTOM, true, false); //sGd.heightHint = 3; sGd.horizontalSpan = 2; separator.setLayoutData(sGd); } protected void setActionLinkVisible(boolean visible, String text) { fActionButton.setVisible(visible); fActionButton.setText(visible ? text: EMPTY_STRING); } private void setSecondaryStatusLineVisible(boolean visible, ITraceStatusDMData2 tData) { fSecondaryStatusLabel.setVisible(visible); ((GridData)fSecondaryStatusLabel.getLayoutData()).exclude = !visible; if (visible && tData != null) { STOP_REASON_ENUM stopReason = tData.getStopReason(); if (stopReason != null) { fSecondaryStatusLabel.setText(getStopMessage(tData)); } else if (tData.isTracingActive() && tData.getStartTime() != null) { String user = EMPTY_STRING; String lastRefreshed = EMPTY_STRING; // In case autorefresh is disabled, show when view was manually refreshed last time if (!fAutoRefreshEnabled) { lastRefreshed = TracepointsMessages.bind( TracepointsMessages.TraceControlView_trace_status_secondary_refresh_time, formatTimeInterval(fLastRefreshTime, System.currentTimeMillis(), true)); } if (tData.getUserName() != null && tData.getUserName().length() > 0) { user = TracepointsMessages.bind(TracepointsMessages.TraceControlView_trace_status_secondary_user, tData.getUserName()); } fSecondaryStatusLabel.setText(TracepointsMessages.bind( TracepointsMessages.TraceControlView_trace_status_secondary_running, new Object[] { formatTime(tData.getStartTime()), user, lastRefreshed} )); } else { // Should not happen if usage is correct fSecondaryStatusLabel.setText(EMPTY_STRING); } } else { fSecondaryStatusLabel.setText(EMPTY_STRING); } } protected void createNotesLine(final Composite parent) { // Trace notes: notes text and edit notes button fNotesComposite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(3, false); layout.marginWidth = 0; layout.marginHeight = 0; fNotesComposite.setLayout(layout); fNotesComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); fNotesComposite.setBackgroundMode(SWT.INHERIT_FORCE); // Separator on the left of whole notes composite Label separator = new Label(fNotesComposite, SWT.SEPARATOR | SWT.VERTICAL); GridData slGd = new GridData(SWT.RIGHT, SWT.FILL, false, true); //slGd.widthHint = 3; slGd.verticalSpan = 4; separator.setLayoutData(slGd); separator.setBackground(fNotesComposite.getBackground()); Label fNotesLabel = new Label(fNotesComposite, SWT.NONE); fNotesLabel.setBackground(parent.getBackground()); fNotesLabel.setText(TracepointsMessages.TraceControlView_trace_notes_label); if (cachedBold != null) { fNotesLabel.setFont(cachedBold); } fSetNotesButton = new Button(fNotesComposite, SWT.TOGGLE); fSetNotesButton.setImage(TracepointImageRegistry.getImageDescriptor( TracepointImageRegistry.ICON_Edit_enabled).createImage()); fSetNotesButton.setSelection(false); fSetNotesButton.setToolTipText(TracepointsMessages.TraceControlView_trace_notes_edit_tooltip); fSetNotesButton.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false)); fSetNotesButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { handleEditNotesButtonPressed(); } }); fNotesContentLabel = new Label(fNotesComposite, SWT.WRAP); fNotesContentLabel.setBackground(parent.getBackground()); fNotesContentLabel.setText(TracepointsMessages.TraceControlView_trace_notes_not_set); GridData nclGd = new GridData(SWT.FILL, SWT.TOP, true, false); nclGd.horizontalSpan = 2; fNotesContentLabel.setLayoutData(nclGd); fNotesContentText = new Text(fNotesComposite, SWT.BORDER); fNotesContentText.setVisible(false); GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false); gd.horizontalSpan = 2; gd.exclude = true; fNotesContentText.setLayoutData(gd); fNotesContentText.addSelectionListener(new SelectionAdapter() { @Override public void widgetDefaultSelected(SelectionEvent e) { fSetNotesButton.setSelection(false); handleEditNotesButtonPressed(); } }); fNotesContentText.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.keyCode == 0x1b) { // Esc was pressed, cancel editing fSetNotesButton.setSelection(false); handleEditNotesButtonPressed(true); } } }); } protected void handleEditNotesButtonPressed() { handleEditNotesButtonPressed(false); } protected void handleEditNotesButtonPressed(boolean cancelEditing) { boolean isEditMode = fSetNotesButton.getSelection(); fNotesContentLabel.setVisible(!isEditMode); ((GridData)fNotesContentLabel.getLayoutData()).exclude = isEditMode; fNotesContentText.setVisible(isEditMode); ((GridData)fNotesContentText.getLayoutData()).exclude = !isEditMode; fNotesContentText.setFocus(); if (isEditMode) { String txt = fNotesContentLabel.getText(); txt = TracepointsMessages.TraceControlView_trace_notes_not_set.equals(txt) ? EMPTY_STRING : txt; fNotesContentText.setText(txt); fSetNotesButton.setToolTipText(TracepointsMessages.TraceControlView_trace_notes_save_tooltip); } else { fSetNotesButton.setToolTipText(TracepointsMessages.TraceControlView_trace_notes_edit_tooltip); if (!cancelEditing) { fNotesContentLabel.setText(fNotesContentText.getText()); fNotesContentLabel.getSize(); fTraceControlModel.setTraceNotes(fNotesContentText.getText()); } } fNotesComposite.layout(); fNotesComposite.redraw(); fTraceControlModel.updateContent(); } protected void setNotesLineVisible(boolean visible, ITraceStatusDMData2 tData, boolean readonly) { fNotesComposite.setVisible(visible); ((GridData)fNotesComposite.getLayoutData()).exclude = !visible; if (visible) { if (tData.getNotes() != null && tData.getNotes().length() > 0) { fNotesContentLabel.setText(removeQuotes(tData.getNotes())); } else { fNotesContentLabel.setText(TracepointsMessages.TraceControlView_trace_notes_not_set); } if (tData != null && tData.getStartTime() != null) fSetNotesButton.setEnabled(!readonly); } } protected void createFrameLine(Composite parent) { fFrameComposite = new Composite(parent, SWT.NONE); GridData fcGd = new GridData(SWT.FILL, SWT.TOP, true, false); fcGd.horizontalSpan = 2; fFrameComposite.setLayoutData(fcGd); GridLayout layout = new GridLayout(2, false); layout.marginHeight = 0; fFrameComposite.setLayout(layout); Label separator = new Label(fFrameComposite, SWT.SEPARATOR | SWT.HORIZONTAL); GridData sepGd = new GridData(SWT.FILL, SWT.CENTER, true, false); sepGd.horizontalSpan = 2; sepGd.verticalIndent = 2; separator.setLayoutData(sepGd); fFrameSlider = new Slider(fFrameComposite, SWT.HORIZONTAL | SWT.BORDER); GridData gd2 = new GridData(SWT.FILL, SWT.CENTER, true, false); gd2.horizontalSpan = 2; fFrameSlider.setLayoutData(gd2); fFrameSlider.setValues(0, 0, 100, 1, 1, 10); fFrameSlider.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { IHandlerService handlerService = getSite().getService(IHandlerService.class); if (e.detail == SWT.ARROW_DOWN) { try { handlerService.executeCommand("org.eclipse.cdt.dsf.gdb.ui.command.selectNextTraceRecord", null); //$NON-NLS-1$ } catch (Exception ex) { } } else if (e.detail == SWT.ARROW_UP) { try { handlerService.executeCommand("org.eclipse.cdt.dsf.gdb.ui.command.selectPreviousTraceRecord", null); //$NON-NLS-1$ } catch (Exception ex) { } } else if (e.detail == SWT.DRAG) { // We don't want to query gdb while user drags thumb, just update the label instead // but postpone actual gdb query to the time thumb is released (e.detail == SWT.NONE) fFrameNumberLabel.setText(TracepointsMessages.bind( TracepointsMessages.TraceControlView_frame_dragging, fFrameSlider.getSelection())); } else { fTraceControlModel.setCurrentTraceRecord(Integer.toString(fFrameSlider.getSelection())); } } }); fFrameLabel = new Label(fFrameComposite, SWT.NONE); fFrameLabel.setText(TracepointsMessages.TraceControlView_frame_label); fFrameLabel.setLayoutData(new GridData()); fFrameNumberLabel = new Label(fFrameComposite, SWT.NONE); fFrameNumberLabel.setText(TracepointsMessages.TraceControlView_frame_not_looking); GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false); fFrameNumberLabel.setLayoutData(gd); } protected void setFrameLineVisible(boolean visible, ITraceStatusDMData2 traceData) { fFrameComposite.setVisible(visible); ((GridData)fFrameComposite.getLayoutData()).exclude = !visible; if (visible) { fFrameSlider.setMinimum(0); if (traceData.getNumberOfCollectedFrame() == 0) { fFrameSlider.setMaximum(1); } else { fFrameSlider.setMaximum(traceData.getNumberOfCollectedFrame()); } int inc = traceData.getNumberOfCollectedFrame() / 20; fFrameSlider.setPageIncrement(inc <= 1 ? 2 : inc); String fl = EMPTY_STRING; if (traceData.getCurrentTraceFrameId() != null) { fl += TracepointsMessages.bind(TracepointsMessages.TraceControlView_frame_looking, new Object[] { traceData.getCurrentTraceFrameId(), Integer.valueOf(traceData.getTracepointNumberForCurrentTraceFrame())} ); int recId = 0; try { recId = Integer.parseInt(traceData.getCurrentTraceFrameId()); } catch (NumberFormatException e) { } fFrameSlider.setSelection(recId); } else { fl += TracepointsMessages.bind(TracepointsMessages.TraceControlView_frame_not_looking, traceData.getNumberOfCollectedFrame()); fFrameSlider.setSelection(0); } fFrameNumberLabel.setText(fl); } if (traceData != null && traceData != null) { fFrameSlider.setEnabled(traceData.getNumberOfCollectedFrame() != 0); } } protected void createBufferLine(final Composite parent) { fBufferComposite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(3, false); layout.marginHeight = 0; fBufferComposite.setLayout(layout); GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false); fBufferComposite.setLayoutData(gd); fBufferComposite.setBackgroundMode(SWT.INHERIT_FORCE); Label fBufferLabel = new Label(fBufferComposite, SWT.NONE); fBufferLabel.setText(TracepointsMessages.TraceControlView_buffer_label); if (cachedBold != null) { fBufferLabel.setFont(cachedBold); } GridData gdBL = new GridData(SWT.FILL, SWT.CENTER, true, false); fBufferLabel.setLayoutData(gdBL); fBufferLabel.setBackground(fBufferComposite.getBackground()); fBufferProgress = new CircularProgress(fBufferComposite, SWT.NONE); GridData bpGd = new GridData(SWT.CENTER, SWT.TOP, false, false); bpGd.verticalSpan = 2; fBufferProgress.setLayoutData(bpGd); fSetCircularBufferButton = new FlatRadioButton(fBufferComposite, SWT.NONE); fSetCircularBufferButton.setText(TracepointsMessages.TraceControlView_buffer_circular_button_label); fSetCircularBufferButton.setSelection(false); fSetCircularBufferButton.setEnabled(true); fSetCircularBufferButton.setToolTipText(TracepointsMessages.TraceControlView_buffer_circular_off_tooltip); GridData cbbGd = new GridData(SWT.RIGHT, SWT.CENTER, false, false); cbbGd.horizontalIndent = 20; fSetCircularBufferButton.setLayoutData(cbbGd); fSetCircularBufferButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fTraceControlModel.setCircularBuffer(fSetCircularBufferButton.getSelection()); fTraceControlModel.updateContent(); } }); fBufferCollectedFramesLabel = new Label(fBufferComposite, SWT.WRAP); fBufferCollectedFramesLabel.setText(TracepointsMessages.TraceControlView_buffer_label); GridData gd3 = new GridData(SWT.FILL, SWT.BOTTOM, true, false); fBufferCollectedFramesLabel.setLayoutData(gd3); } protected void setBufferLineVisible(boolean visible, ITraceStatusDMData2 tData, boolean readonly) { fBufferComposite.setVisible(visible); ((GridData)fBufferComposite.getLayoutData()).exclude = !visible; if (visible && tData != null){ if (tData.getStopReason() != null && tData.getStopReason() == STOP_REASON_ENUM.OVERFLOW){ // Buffer overflowed, it should be 100% full instead of 99% fBufferProgress.setProgress(100); } else if (tData.getStopReason() != null && tData.isCircularBuffer() && tData.getNumberOfCreatedFrames() > tData.getNumberOfCollectedFrame()) { // Buffer is circular and overflowed once, it should be 100% full instead of 99% fBufferProgress.setProgress(100); } else if (tData.isCircularBuffer() && tData.isTracingActive() && tData.getNumberOfCreatedFrames() > tData.getNumberOfCollectedFrame()) { // If we run with Circular buffer and all buffer was filled in once, we continue displaying progress 100% // and showing moving bar that makes a circle every tData.getNumberOfCollectedFrame() because it is buffer size in frames // and actual number of collected frames from the start is tData.getNumberOfCreatedFrames(), but only last // tData.getNumberOfCollectedFrame() are stored in the buffer int p = (tData.getNumberOfCreatedFrames() % tData.getNumberOfCollectedFrame()) * 100 / tData.getNumberOfCollectedFrame(); // 100 is an indicator that buffer is already full and should be showed in different manner fBufferProgress.setProgress(100 + p); } else { fBufferProgress.setProgress((tData.getTotalBufferSize() - tData.getFreeBufferSize()) * 100 / tData.getTotalBufferSize()); } fSetCircularBufferButton.setSelection(tData.isCircularBuffer()); fSetCircularBufferButton.setEnabled(!readonly); fSetCircularBufferButton.setToolTipText(fSetCircularBufferButton.getSelection() ? TracepointsMessages.TraceControlView_buffer_circular_on_tooltip : TracepointsMessages.TraceControlView_buffer_circular_off_tooltip); fSetCircularBufferButton.redraw(); fSetCircularBufferButton.update(); fBufferCollectedFramesLabel.setText(TracepointsMessages.bind( TracepointsMessages.TraceControlView_buffer_frames_collected, tData.getNumberOfCollectedFrame(), (tData.getTotalBufferSize() - tData.getFreeBufferSize())/1000)); fBufferProgress.redraw(); fBufferProgress.update(); } } protected void createActions() { IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); window.getActivePage().showActionSet("org.eclipse.cdt.debug.ui.tracepointActionSet"); //$NON-NLS-1$ IActionBars bars = getViewSite().getActionBars(); IToolBarManager manager = bars.getToolBarManager(); // Create the action to refresh the view fRefreshViewAction = new RefreshViewAction(); bars.setGlobalActionHandler(ActionFactory.REFRESH.getId(), fRefreshViewAction); manager.add(fRefreshViewAction); fRefreshViewAction.setEnabled(false); fAutoRefreshAction = new AutoRefreshAction(); manager.add(fAutoRefreshAction); fAutoRefreshAction.setChecked(true); fAutoRefreshAction.setEnabled(true); fAutoRefreshEnabled = true; fLastRefreshTime = System.currentTimeMillis(); fDisconnectedTracingAction = new DisconnectedTracingAction(); manager.add(fDisconnectedTracingAction); fDisconnectedTracingAction.setEnabled(false); // Create the action to open the trace variable details fOpenTraceVarDetails = new OpenTraceVarDetailsAction(); manager.add(fOpenTraceVarDetails); // Create the action to exit visualization mode fExitVisualizationAction = new ExitVisualizationModeDetailsAction(); manager.add(fExitVisualizationAction); bars.updateActionBars(); updateActionEnablement(null); } @Override public void dispose() { fTraceControlModel.dispose(); fStatusLabel = null; // Indicate that we have been disposed if (refreshUIJob != null) { refreshUIJob.cancel(); } if (cachedBold != null) { cachedBold.dispose(); cachedBold = null; } super.dispose(); } protected void updateUI(final String statusMessage) { try { fLastTraceData = null; setSecondaryStatusLineVisible(false, null); //setNotesLineVisible(false, null, false); setFrameLineVisible(false, null); setBufferLineVisible(false, null, false); fStatusLabel.setText(statusMessage); setActionLinkVisible(false, EMPTY_STRING); updateActionEnablement(null); updateLayout(); fDisconnectedTracingAction.setEnabled(false); } catch (SWTException ex) { } } protected void updateUI(final ITraceStatusDMData2 traceData) { fLastTraceData = traceData; if (traceData == null ) { // should not happen, but still process it correctly updateUI(TracepointsMessages.TraceControlView_trace_status_inactive); } else if (!traceData.isTracingSupported()) { updateUI(TracepointsMessages.TraceControlView_trace_status_not_supported); } else if (traceData.isTracingFromFile()) { // Off-line tracing from data file fDisconnectedTracingAction.setEnabled(false); String s = TracepointsMessages.TraceControlView_trace_status_offline; fStatusLabel.setText(s); setActionLinkVisible(false, EMPTY_STRING); // If start and stop time are not available in trace data file, do not show secondary status line if (getTimeMilliseconds(traceData.getStartTime()) != 0 && getTimeMilliseconds(traceData.getStopTime()) != 0) { setSecondaryStatusLineVisible(true, traceData); } else { setSecondaryStatusLineVisible(false, traceData); } //setNotesLineVisible(true, traceData, true); setBufferLineVisible(true, traceData, true); setFrameLineVisible(true, traceData); updateActionEnablement(traceData); updateLayout(); } else if (!traceData.isTracingActive() && traceData.getStopReason() == null){ // Tracing is not started yet fDisconnectedTracingAction.setEnabled(true); fStatusLabel.setText(TracepointsMessages.TraceControlView_trace_status_not_started); setActionLinkVisible(true,TracepointsMessages.TraceControlView_action_start); setSecondaryStatusLineVisible(false, null); //setNotesLineVisible(true, traceData, false); setBufferLineVisible(true, traceData, false); setFrameLineVisible(false, null); updateActionEnablement(traceData); updateLayout(); } else { // Live execution tracing started and running or started and stopped fDisconnectedTracingAction.setEnabled(true); // If stopped, stop reason, time and note. STOP_REASON_ENUM fStopReason = traceData.getStopReason(); if (fStopReason != null) { // Tracing has stopped we need notes, secondary status line, and frames slider setSecondaryStatusLineVisible(true, traceData); //setNotesLineVisible(true, traceData, false); setFrameLineVisible(true, traceData); setBufferLineVisible(true, traceData, false); if (traceData.getCurrentTraceFrameId() != null) { fStatusLabel.setText(TracepointsMessages.TraceControlView_trace_status_visualization); setActionLinkVisible(true, TracepointsMessages.TraceControlView_action_finish_visualization); } else { if (traceData.getNumberOfCollectedFrame() == 0) { fStatusLabel.setText(TracepointsMessages.TraceControlView_trace_status_not_started); } else { fStatusLabel.setText(TracepointsMessages.TraceControlView_trace_status_stopped); } setActionLinkVisible(true, TracepointsMessages.TraceControlView_action_restart); } } else { // Tracing is running, don't show stop reason line, stop notes and frames line. String s = TracepointsMessages.TraceControlView_trace_status_in_progress; fStatusLabel.setText(s); setActionLinkVisible(true, TracepointsMessages.TraceControlView_action_stop); setSecondaryStatusLineVisible(true, traceData); //setNotesLineVisible(true, traceData, false); setFrameLineVisible(false, traceData); setBufferLineVisible(true, traceData, true); startRefreshUIJob(); } updateActionEnablement(traceData); updateLayout(); } } protected void startRefreshUIJob() { if (refreshUIJob == null) { refreshUIJob = new UIJob("Refresh Trace Control view UI") { //$NON-NLS-1$ @Override public IStatus runInUIThread(IProgressMonitor monitor) { // Run on the UI thread to avoid synchronization if (fAutoRefreshEnabled) { fTraceControlModel.updateContent(); } else { // Update the UI to simply say how long ago was the last refresh updateUI(fLastTraceData); } return Status.OK_STATUS; } }; } refreshUIJob.schedule(UI_REFRESH_DELAY); } protected String getStopMessage(ITraceStatusDMData2 tData) { String stopMessage; STOP_REASON_ENUM fStopReason = tData.getStopReason(); if (fStopReason == STOP_REASON_ENUM.REQUEST) { stopMessage = TracepointsMessages.TraceControlView_tracing_stopped_user_request; } else if (fStopReason == STOP_REASON_ENUM.PASSCOUNT) { if (tData.getStoppingTracepoint() != null) { stopMessage = TracepointsMessages.bind(TracepointsMessages.TraceControlView_tracing_stopped_tracepoint_number, tData.getStoppingTracepoint()); } else { stopMessage = TracepointsMessages.TraceControlView_tracing_stopped_passcount; } } else if (fStopReason == STOP_REASON_ENUM.OVERFLOW) { stopMessage = TracepointsMessages.TraceControlView_tracing_stopped_buffer_full; } else if (fStopReason == STOP_REASON_ENUM.DISCONNECTION) { stopMessage = TracepointsMessages.TraceControlView_tracing_stopped_disconnection; } else if (fStopReason == STOP_REASON_ENUM.ERROR) { stopMessage = TracepointsMessages.TraceControlView_tracing_stopped_error; } else { stopMessage = TracepointsMessages.TraceControlView_tracing_stopped_unknown; } String user = EMPTY_STRING; if (tData.getUserName() != null && tData.getUserName().length() > 0) { user = TracepointsMessages.bind(TracepointsMessages.TraceControlView_trace_status_secondary_user, tData.getUserName()); } if (tData.isTracingFromFile()) { stopMessage = TracepointsMessages.bind( TracepointsMessages.TraceControlView_trace_status_secondary_offline, new Object[] {formatTime(tData.getStartTime()), user, formatTime(tData.getStopTime()), stopMessage }); } else { stopMessage = TracepointsMessages.bind( TracepointsMessages.TraceControlView_trace_status_secondary_stopped, new Object[] {formatTimeInterval(tData.getStartTime(),tData.getStopTime()), user, formatTime(tData.getStopTime()), stopMessage }); } return stopMessage; } protected void updateActionEnablement(ITraceStatusDMData2 traceData) { fOpenTraceVarDetails.setEnabled(traceData != null && traceData.isTracingSupported()); fExitVisualizationAction.setEnabled(traceData != null && traceData.getCurrentTraceFrameId() != null && !traceData.isTracingFromFile()); fDisconnectedTracingAction.setChecked(traceData != null && traceData.isDisconnectedTracingEnabled()); } @Override public void setFocus() { if (fStatusLabel != null) { fStatusLabel.setFocus(); } } public void updateLayout() { fStatusComposite.layout(true); fTopComposite.layout(true); } protected long getTimeMilliseconds(String time) { long microseconds = 0; try { if (time.length() != 0) { String[] times = time.split("\\."); //$NON-NLS-1$ microseconds += Long.parseLong(times[0]) * 1000000; microseconds += Long.parseLong(times[1]); } } catch (NumberFormatException ex) { GdbPlugin.log(ex); } return microseconds / 1000; } /** * Format time from gdb presentation into user-understandable form * @param time in gd presentation * @return */ protected String formatTime(String time) { long milliseconds = getTimeMilliseconds(time); return formatTime(milliseconds); } /** * Format time from standard milliseconds since Epoch into user-understandable form */ protected String formatTime(long milliseconds) { Date date = new Date(milliseconds); long currentTime = System.currentTimeMillis(); long days = TimeUnit.MILLISECONDS.toDays(currentTime - milliseconds); if (days == 0) { // today return TracepointsMessages.bind(TracepointsMessages.TraceControlView_today, DateFormat.getTimeInstance(DateFormat.SHORT).format(date)); } else if (days == 1) { // yesterday return TracepointsMessages.bind(TracepointsMessages.TraceControlView_yesterday, DateFormat.getTimeInstance(DateFormat.SHORT).format(date)); } return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(date); } /** * Format time interval returned by trace status command into human-readable */ protected String formatTimeInterval(String startTime, String stopTime) { long startMicroseconds = 0; long stopMicroseconds = 0; try { if (startTime.length() != 0) { String[] times = startTime.split("\\."); //$NON-NLS-1$ startMicroseconds += Long.parseLong(times[0]) * 1000000; startMicroseconds += Long.parseLong(times[1]); } if (stopTime.length() != 0) { String[] times = stopTime.split("\\."); //$NON-NLS-1$ stopMicroseconds += Long.parseLong(times[0]) * 1000000; stopMicroseconds += Long.parseLong(times[1]); } return formatTimeInterval(startMicroseconds/1000, stopMicroseconds/1000, true); } catch (NumberFormatException ex) { GdbPlugin.log(ex); } return EMPTY_STRING; } /** * Format time interval returned by trace status command into human-readable */ protected String formatTimeInterval(long startMilliseconds, long stopMilliseconds, boolean shortForm) { long millis = stopMilliseconds - startMilliseconds; long days = TimeUnit.MILLISECONDS.toDays(millis); millis -= TimeUnit.DAYS.toMillis(days); long hours = TimeUnit.MILLISECONDS.toHours(millis); millis -= TimeUnit.HOURS.toMillis(hours); long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); millis -= TimeUnit.MINUTES.toMillis(minutes); long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); StringBuilder sb = new StringBuilder(64); if (!shortForm) { if (days != 0) sb.append(days).append(TracepointsMessages.TraceControlView_date_days); if (hours != 0) sb.append(hours).append(TracepointsMessages.TraceControlView_date_hours); if (minutes != 0) sb.append(minutes).append(TracepointsMessages.TraceControlView_date_minutes); if (seconds != 0) sb.append(seconds).append(TracepointsMessages.TraceControlView_date_seconds); if (sb.length() == 0) sb.append(TracepointsMessages.TraceControlView_date_zero); } else { if (days != 0) sb.append(days).append(TracepointsMessages.TraceControlView_date_short_days); if (hours != 0) sb.append(hours).append(TracepointsMessages.TraceControlView_date_short_hours); if (minutes != 0) sb.append(minutes).append(TracepointsMessages.TraceControlView_date_short_minutes); if (seconds != 0) sb.append(seconds).append(TracepointsMessages.TraceControlView_date_short_seconds); if (sb.length() == 0) sb.append(TracepointsMessages.TraceControlView_date_short_zero); } return(sb.toString()); } /** * GDB's set trace-user and set trace-notes commands require quotes if argument contains spaces, * but these quotes are returned by trace status, to workaround this we remove quotes on UI side */ protected String removeQuotes(String s) { if (s.startsWith("\"") && s.endsWith("\"")) { //$NON-NLS-1$//$NON-NLS-2$ return s.substring(1, s.length()-1); } else { return s; } } }