Java tutorial
/*=============================================================================# # Copyright (c) 2005-2015 Stephan Wahlbrink (WalWare.de) # 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: # Stephan Wahlbrink - initial API and implementation #=============================================================================*/ package de.walware.statet.nico.ui.console; import java.io.IOException; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IDebugEventSetListener; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.IStreamListener; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IStreamMonitor; import org.eclipse.jface.resource.FontRegistry; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.console.ConsolePlugin; import org.eclipse.ui.console.IConsoleView; import org.eclipse.ui.console.TextConsole; import org.eclipse.ui.part.IPageBookViewPage; import de.walware.ecommons.preferences.PreferencesUtil; import de.walware.ecommons.preferences.SettingsChangeNotifier; import de.walware.ecommons.ts.ITool; import de.walware.ecommons.ui.util.UIAccess; import de.walware.statet.nico.core.runtime.SubmitType; import de.walware.statet.nico.core.runtime.ToolProcess; import de.walware.statet.nico.core.runtime.ToolStreamMonitor; import de.walware.statet.nico.internal.ui.NicoUIPlugin; import de.walware.statet.nico.internal.ui.console.NIConsolePartitioner; import de.walware.statet.nico.internal.ui.preferences.ConsolePreferences; import de.walware.statet.nico.ui.NicoUITools; /** * A console to interact with controller using command-line-based interface. */ public abstract class NIConsole extends TextConsole implements IAdaptable { public static final String NICONSOLE_TYPE = "de.walware.statet.nico.console"; //$NON-NLS-1$ public static final String ADJUST_OUTPUT_WIDTH_COMMAND_ID = "de.walware.statet.nico.commands.AdjustOutputWidth"; //$NON-NLS-1$ private static boolean gFontInitialized; private class SettingsListener implements SettingsChangeNotifier.ChangeListener, IPropertyChangeListener { @Override public void settingsChanged(final Set<String> groupIds) { if (groupIds.contains(ConsolePreferences.GROUP_ID)) { updateSettings(); } if (groupIds.contains(ConsolePreferences.OUTPUT_TEXTSTYLE_GROUP_ID)) { final NIConsoleColorAdapter adapter = fAdapter; if (adapter != null) { adapter.updateSettings(); } } } @Override public void propertyChange(final PropertyChangeEvent event) { if (getSymbolicFontName().equals(event.getProperty())) { setFont(null); } } } private final NIConsolePartitioner fPartitioner; private final Map<String, NIConsoleOutputStream> fStreams = new HashMap<String, NIConsoleOutputStream>(); private boolean fStreamsClosed; private final ToolProcess fProcess; private NIConsoleColorAdapter fAdapter; private IDebugEventSetListener fDebugListener; private final SettingsListener fSettingsListener = new SettingsListener(); private int fCurrentWatermark; /** * Constructs a new console. * * @param name console name */ public NIConsole(final ToolProcess process, final NIConsoleColorAdapter adapter) { super(process.getAttribute(IProcess.ATTR_PROCESS_LABEL), NICONSOLE_TYPE, NicoUITools.getImageDescriptor(process), true); fProcess = process; fAdapter = adapter; fPartitioner = new NIConsolePartitioner(this, fAdapter.getStreamIds()); fPartitioner.connect(getDocument()); if (!gFontInitialized) { UIAccess.getDisplay().syncExec(new Runnable() { @Override public void run() { setFont(null); gFontInitialized = true; } }); } else { setFont(null); } PreferencesUtil.getSettingsChangeNotifier().addChangeListener(fSettingsListener); updateWatermarks(); fStreamsClosed = fProcess.isTerminated(); fAdapter.connect(process, this); fDebugListener = new IDebugEventSetListener() { @Override public void handleDebugEvents(final DebugEvent[] events) { EVENTS: for (final DebugEvent event : events) { if (event.getSource() == fProcess) { switch (event.getKind()) { case DebugEvent.CHANGE: final Object obj = event.getData(); if (obj != null && obj instanceof String[]) { final String[] attrChange = (String[]) obj; if (attrChange.length == 3 && IProcess.ATTR_PROCESS_LABEL.equals(attrChange[0])) { runSetName(attrChange[2]); } } continue EVENTS; case DebugEvent.TERMINATE: disconnect(); continue EVENTS; } } } } private void runSetName(final String name) { UIAccess.getDisplay().syncExec(new Runnable() { @Override public void run() { setName(name); // ConsolePlugin.getDefault().getConsoleManager().warnOfContentChange(NIConsole.this); ConsolePlugin.getDefault().getConsoleManager().refresh(NIConsole.this); } }); } }; DebugPlugin.getDefault().addDebugEventListener(fDebugListener); } protected void updateSettings() { updateWatermarks(); } protected void updateWatermarks() { final boolean limitBufferSize = true; if (limitBufferSize) { int lowWater = PreferencesUtil.getInstancePrefs().getPreferenceValue(ConsolePreferences.PREF_CHARLIMIT); if (lowWater < 10000) { lowWater = 10000; } if (lowWater == fCurrentWatermark) { return; } final int highWater = lowWater + 10000; fPartitioner.setWaterMarks(lowWater, highWater); } else { fPartitioner.setWaterMarks(-1, -1); } } protected String getSymbolicFontName() { return JFaceResources.TEXT_FONT; } @Override public void setFont(Font newFont) { if (newFont == null) { JFaceResources.getFont(getSymbolicFontName()).getFontData()[0].getName(); newFont = JFaceResources.getFont(getSymbolicFontName()); } super.setFont(newFont); } @Override protected void init() { super.init(); JFaceResources.getFontRegistry().addListener(fSettingsListener); } @Override public void clearConsole() { if (fPartitioner != null) { fPartitioner.clearBuffer(); } } @Override protected void dispose() { super.dispose(); final DebugPlugin debugPlugin = DebugPlugin.getDefault(); if (debugPlugin != null) { debugPlugin.removeDebugEventListener(fDebugListener); } fDebugListener = null; final SettingsChangeNotifier changeNotifier = PreferencesUtil.getSettingsChangeNotifier(); if (changeNotifier != null) { changeNotifier.removeChangeListener(fSettingsListener); } final FontRegistry fontRegistry = JFaceResources.getFontRegistry(); if (fontRegistry != null) { fontRegistry.removeListener(fSettingsListener); } disconnect(); } @Override public abstract IPageBookViewPage createPage(IConsoleView view); @Override protected NIConsolePartitioner getPartitioner() { return fPartitioner; } public void connect(final ToolStreamMonitor streamMonitor, final String streamId, final EnumSet<SubmitType> filter) { synchronized (fStreams) { if (fStreamsClosed) { return; } NIConsoleOutputStream stream = fStreams.get(streamId); if (stream == null) { stream = new NIConsoleOutputStream(this, streamId); fStreams.put(streamId, stream); } final NIConsoleOutputStream out = stream; streamMonitor.addListener(new IStreamListener() { private static final int BUFFER_SIZE = 9216; private final StringBuilder fBuffer = new StringBuilder(BUFFER_SIZE); @Override public void streamAppended(final String text, final IStreamMonitor monitor) { try { synchronized (out) { // it would be better to run the check later, e.g. in partitioning job, but this is internal Eclipse int start = 0; final int n = text.length(); for (int idx = 0; idx < n;) { final char c = text.charAt(idx); if (c <= 12) { switch (c) { case 7: // bell fBuffer.append(text, start, idx); ring(); start = ++idx; continue; case 8: // back fBuffer.append(text, start, idx); if (fBuffer.length() > 0) { final char prev = fBuffer.charAt(fBuffer.length() - 1); if (prev != '\n' && prev != '\r') { fBuffer.deleteCharAt(fBuffer.length() - 1); } } start = ++idx; continue; case 11: // vertical tab fBuffer.append(text, start, idx); printVTab(); start = ++idx; continue; case 12: // formfeed fBuffer.append(text, start, idx); printFormfeed(); start = ++idx; continue; } } ++idx; continue; } if (start == 0) { out.write(text); } else { fBuffer.append(text, start, n); out.write(fBuffer.toString()); if (fBuffer.capacity() > BUFFER_SIZE * 5) { fBuffer.setLength(BUFFER_SIZE); fBuffer.trimToSize(); } fBuffer.setLength(0); } // TODO // if (text.length() >= 7168) { // try { // Thread.sleep(10); // } // catch (final InterruptedException e) { // Thread.interrupted(); // } // } } } catch (final IOException e) { NicoUIPlugin.logError(NicoUIPlugin.INTERNAL_ERROR, "Error of unexpected type occured, when writing to console stream.", e); //$NON-NLS-1$ } } private void ring() { final Display display = UIAccess.getDisplay(); display.asyncExec(new Runnable() { @Override public void run() { display.beep(); }; }); } private void printVTab() { final String br = fProcess.getWorkspaceData().getLineSeparator(); fBuffer.append(br); } private void printFormfeed() { final String br = fProcess.getWorkspaceData().getLineSeparator(); fBuffer.append(br + br); } }, filter); } } public NIConsoleOutputStream getStream(final String streamId) { synchronized (fStreams) { return fStreams.get(streamId); } } private void disconnect() { synchronized (fStreams) { if (fStreamsClosed) { return; } for (final NIConsoleOutputStream stream : fStreams.values()) { stream.close(); } fStreamsClosed = true; fAdapter.disconnect(); fAdapter = null; } } public final ToolProcess getProcess() { return fProcess; } @Override public Object getAdapter(final Class required) { if (ITool.class.equals(required)) { return fProcess; } if (ILaunchConfiguration.class.equals(required)) { final ILaunch launch = getProcess().getLaunch(); if (launch != null) { return launch.getLaunchConfiguration(); } return null; } return null; } }