/******************************************************************************* * Copyright (c) 2009, 2011 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 *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.internal.ui.console; import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; import org.eclipse.cdt.dsf.gdb.launching.ITracedLaunch; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchesListener2; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.ui.console.ConsolePlugin; import org.eclipse.ui.console.IConsole; import org.eclipse.ui.console.IConsoleManager; /** * A tracing console manager which adds and removes tracing consoles * based on launch events and preference events. * * @since 2.1 * This class was moved from package org.eclipse.cdt.dsf.gdb.internal.ui.tracing */ public class TracingConsoleManager implements ILaunchesListener2, IPropertyChangeListener { /** * The number of characters that should be deleted once the GDB traces console * reaches its configurable maximum. */ private static final int NUMBER_OF_CHARS_TO_DELETE = 100000; /** * The minimum number of characters that should be kept when truncating * the console output. */ private static final int MIN_NUMBER_OF_CHARS_TO_KEEP = 5000; /** * Member to keep track of the preference. * We keep it up-to-date by registering as an IPropertyChangeListener */ private boolean fTracingEnabled = false; /** * The maximum number of characters that are allowed per console */ private int fMaxNumCharacters = 500000; /** * The number of characters that will be kept in the console once we * go over fMaxNumCharacters and that we must remove some characters */ private int fMinNumCharacters = fMaxNumCharacters - NUMBER_OF_CHARS_TO_DELETE; /** * Start the tracing console. We don't do this in a constructor, because * we need to use <code>this</code>. */ public void startup() { IPreferenceStore store = GdbUIPlugin.getDefault().getPreferenceStore(); store.addPropertyChangeListener(this); fTracingEnabled = store.getBoolean(IGdbDebugPreferenceConstants.PREF_TRACES_ENABLE); int maxChars = store.getInt(IGdbDebugPreferenceConstants.PREF_MAX_GDB_TRACES); setWaterMarks(maxChars); if (fTracingEnabled) { toggleTracing(true); } } public void shutdown() { DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); GdbUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this); removeAllConsoles(); } protected void toggleTracing(boolean enabled) { if (enabled) { DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); addAllConsoles(); } else { DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); removeAllConsoles(); } } protected void addAllConsoles() { ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager().getLaunches(); for (ILaunch launch : launches) { addConsole(launch); } } protected void removeAllConsoles() { ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager().getLaunches(); for (ILaunch launch : launches) { removeConsole(launch); } } public void launchesAdded(ILaunch[] launches) { for (ILaunch launch : launches) { addConsole(launch); } } public void launchesChanged(ILaunch[] launches) { } public void launchesRemoved(ILaunch[] launches) { for (ILaunch launch : launches) { removeConsole(launch); } } public void launchesTerminated(ILaunch[] launches) { for (ILaunch launch : launches) { // Since we already had a console, don't get rid of it // just yet. Simply rename it to show it is terminated. renameConsole(launch); } } public void propertyChange(PropertyChangeEvent event) { if (event.getProperty().equals(IGdbDebugPreferenceConstants.PREF_TRACES_ENABLE)) { fTracingEnabled = (Boolean)event.getNewValue(); toggleTracing(fTracingEnabled); } else if (event.getProperty().equals(IGdbDebugPreferenceConstants.PREF_MAX_GDB_TRACES)) { int maxChars = (Integer)event.getNewValue(); updateAllConsoleWaterMarks(maxChars); } } protected void addConsole(ILaunch launch) { // Tracing consoles are only added to ITracingLaunches if (launch instanceof ITracedLaunch) { // Make sure we didn't already add this console if (getConsole(launch) == null) { if (launch.isTerminated() == false) { // Create and new tracing console. TracingConsole console = new TracingConsole(launch, ConsoleMessages.ConsoleMessages_trace_console_name); console.setWaterMarks(fMinNumCharacters, fMaxNumCharacters); ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[]{console}); } // else we don't display a new console for a terminated launch } } } protected void removeConsole(ILaunch launch) { if (launch instanceof ITracedLaunch) { TracingConsole console = getConsole(launch); if (console != null) { ConsolePlugin.getDefault().getConsoleManager().removeConsoles(new IConsole[]{console}); } } } protected void renameConsole(ILaunch launch) { if (launch instanceof ITracedLaunch) { TracingConsole console = getConsole(launch); if (console != null) { console.resetName(); } } } private TracingConsole getConsole(ILaunch launch) { ConsolePlugin plugin = ConsolePlugin.getDefault(); if (plugin != null) { // I've seen the plugin be null when running headless JUnit tests IConsoleManager manager = plugin.getConsoleManager(); IConsole[] consoles = manager.getConsoles(); for (IConsole console : consoles) { if (console instanceof TracingConsole) { TracingConsole tracingConsole = (TracingConsole)console; if (tracingConsole.getLaunch().equals(launch)) { return tracingConsole; } } } } return null; } /** @since 2.2 */ protected void setWaterMarks(int maxChars) { if (maxChars < (MIN_NUMBER_OF_CHARS_TO_KEEP * 2)) { maxChars = MIN_NUMBER_OF_CHARS_TO_KEEP * 2; } fMaxNumCharacters = maxChars; // If the max number of chars is anything below the number of chars we are going to delete // (plus our minimum buffer), we only keep the minimum. // If the max number of chars is bigger than the number of chars we are going to delete (plus // the minimum buffer), we truncate a fixed amount chars. fMinNumCharacters = maxChars < (NUMBER_OF_CHARS_TO_DELETE + MIN_NUMBER_OF_CHARS_TO_KEEP) ? MIN_NUMBER_OF_CHARS_TO_KEEP : maxChars - NUMBER_OF_CHARS_TO_DELETE; } /** @since 2.2 */ protected void updateAllConsoleWaterMarks(int maxChars) { setWaterMarks(maxChars); ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager().getLaunches(); for (ILaunch launch : launches) { updateConsoleWaterMarks(launch); } } /** @since 2.2 */ protected void updateConsoleWaterMarks(ILaunch launch) { if (launch instanceof ITracedLaunch) { TracingConsole console = getConsole(launch); if (console != null) { console.setWaterMarks(fMinNumCharacters, fMaxNumCharacters); } } } }