/******************************************************************************* * 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 java.util.HashMap; 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; /** * A tracing console manager which adds and removes tracing consoles * based on launch events and preference events. * TracingConsoles are always running but are only shown in the console * view if enabled by the user preference. * * @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; /** * A map of all TracingConsoles for their corresponding launch. * We keep this list because TracingConsoles may not be registered * with the ConsoleManager, so we need another way to find them. */ private HashMap<ITracedLaunch, TracingConsole> fTracingConsoles = new HashMap<>(); /** * 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); DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); } public void shutdown() { DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); GdbUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this); removeAllConsoles(); } protected void toggleTracingVisibility(boolean visible) { if (visible) { ConsolePlugin.getDefault().getConsoleManager().addConsoles( fTracingConsoles.values().toArray(new IConsole[fTracingConsoles.size()])); } else { ConsolePlugin.getDefault().getConsoleManager().removeConsoles( fTracingConsoles.values().toArray(new IConsole[fTracingConsoles.size()])); } } protected void removeAllConsoles() { ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager().getLaunches(); for (ILaunch launch : launches) { removeConsole(launch); } } @Override public void launchesAdded(ILaunch[] launches) { for (ILaunch launch : launches) { addConsole(launch); } } @Override public void launchesChanged(ILaunch[] launches) { } @Override public void launchesRemoved(ILaunch[] launches) { for (ILaunch launch : launches) { removeConsole(launch); } } @Override 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); } } @Override public void propertyChange(PropertyChangeEvent event) { if (event.getProperty().equals(IGdbDebugPreferenceConstants.PREF_TRACES_ENABLE)) { fTracingEnabled = (Boolean)event.getNewValue(); toggleTracingVisibility(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()) { // Create a new tracing console. TracingConsole console = new TracingConsole(launch, ConsoleMessages.ConsoleMessages_trace_console_name); console.initialize(); console.setWaterMarks(fMinNumCharacters, fMaxNumCharacters); fTracingConsoles.put((ITracedLaunch)launch, console); if (fTracingEnabled) { ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[]{console}); } } // else we don't display a new console for a terminated launch } } } protected void removeConsole(ILaunch launch) { TracingConsole console = fTracingConsoles.remove(launch); if (console != null) { console.destroy(); if (fTracingEnabled) { ConsolePlugin.getDefault().getConsoleManager().removeConsoles(new IConsole[]{console}); } } } protected void renameConsole(ILaunch launch) { TracingConsole console = getConsole(launch); if (console != null) { console.resetName(); } } private TracingConsole getConsole(ILaunch launch) { return fTracingConsoles.get(launch); } /** @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) { TracingConsole console = getConsole(launch); if (console != null) { console.setWaterMarks(fMinNumCharacters, fMaxNumCharacters); } } }