blob: da427d777df14910f025b0dd585e8e4eb7da0076 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2005, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.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.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.console.TextConsole;
import org.eclipse.ui.part.IPageBookViewPage;
import org.eclipse.statet.jcommons.ts.core.Tool;
import org.eclipse.statet.ecommons.preferences.PreferencesUtil;
import org.eclipse.statet.ecommons.preferences.SettingsChangeNotifier;
import org.eclipse.statet.ecommons.preferences.core.util.PreferenceUtils;
import org.eclipse.statet.ecommons.ui.util.UIAccess;
import org.eclipse.statet.internal.nico.ui.NicoUIPlugin;
import org.eclipse.statet.internal.nico.ui.console.NIConsolePartitioner;
import org.eclipse.statet.internal.nico.ui.preferences.ConsolePreferences;
import org.eclipse.statet.nico.core.runtime.SubmitType;
import org.eclipse.statet.nico.core.runtime.ToolProcess;
import org.eclipse.statet.nico.core.runtime.ToolStreamMonitor;
import org.eclipse.statet.nico.ui.NicoUIPreferences;
import org.eclipse.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= "org.eclipse.statet.nico.console"; //$NON-NLS-1$
public static final String ADJUST_OUTPUT_WIDTH_COMMAND_ID= "org.eclipse.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= NIConsole.this.adapter;
if (adapter != null) {
adapter.updateSettings();
}
}
}
@Override
public void propertyChange(final PropertyChangeEvent event) {
if (getSymbolicFontName().equals(event.getProperty()) ) {
setFont(null);
}
}
}
private final NIConsolePartitioner partitioner;
private final Map<String, NIConsoleOutputStream> streams= new HashMap<>();
private boolean streamsClosed;
private final ToolProcess process;
private NIConsoleColorAdapter adapter;
private IDebugEventSetListener debugListener;
private final SettingsListener settingsListener= new SettingsListener();
private int currentWatermark;
/**
* 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);
this.process= process;
this.adapter= adapter;
this.partitioner= new NIConsolePartitioner(this, this.adapter.getStreamIds());
this.partitioner.connect(getDocument());
if (!gFontInitialized) {
UIAccess.getDisplay().syncExec(new Runnable() {
@Override
public void run() {
setFont(null);
gFontInitialized= true;
}
});
}
else {
setFont(null);
}
PreferencesUtil.getSettingsChangeNotifier().addChangeListener(this.settingsListener);
updateWatermarks();
this.streamsClosed= this.process.isTerminated();
this.adapter.connect(process, this);
this.debugListener= new IDebugEventSetListener() {
@Override
public void handleDebugEvents(final DebugEvent[] events) {
ITER_EVENTS: for (final DebugEvent event : events) {
if (event.getSource() == NIConsole.this.process) {
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 ITER_EVENTS;
case DebugEvent.TERMINATE:
disconnect();
continue ITER_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(this.debugListener);
}
protected void updateSettings() {
updateWatermarks();
}
protected void updateWatermarks() {
final boolean limitBufferSize= true;
if (limitBufferSize) {
int lowWater= PreferenceUtils.getInstancePrefs().getPreferenceValue(NicoUIPreferences.OUTPUT_CHARLIMIT_PREF);
if (lowWater < 100000) {
lowWater= 100000;
}
if (lowWater == this.currentWatermark) {
return;
}
final int highWater= lowWater + 10000;
this.partitioner.setWaterMarks(lowWater, highWater);
}
else {
this.partitioner.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(this.settingsListener);
}
@Override
public void clearConsole() {
if (this.partitioner != null) {
this.partitioner.clearBuffer();
}
}
@Override
protected void dispose() {
super.dispose();
final DebugPlugin debugPlugin= DebugPlugin.getDefault();
if (debugPlugin != null) {
debugPlugin.removeDebugEventListener(this.debugListener);
}
this.debugListener= null;
final SettingsChangeNotifier changeNotifier= PreferencesUtil.getSettingsChangeNotifier();
if (changeNotifier != null) {
changeNotifier.removeChangeListener(this.settingsListener);
}
final FontRegistry fontRegistry= JFaceResources.getFontRegistry();
if (fontRegistry != null) {
fontRegistry.removeListener(this.settingsListener);
}
disconnect();
}
@Override
public abstract IPageBookViewPage createPage(IConsoleView view);
@Override
protected NIConsolePartitioner getPartitioner() {
return this.partitioner;
}
public void connect(final ToolStreamMonitor streamMonitor, final String streamId,
final EnumSet<SubmitType> filter) {
synchronized (this.streams) {
if (this.streamsClosed) {
return;
}
NIConsoleOutputStream stream= this.streams.get(streamId);
if (stream == null) {
stream= new NIConsoleOutputStream(this, streamId);
this.streams.put(streamId, stream);
}
final NIConsoleOutputStream out= stream;
streamMonitor.addListener(new IStreamListener() {
@Override
public void streamAppended(final String text, final IStreamMonitor monitor) {
try {
out.write(text);
}
catch (final IOException e) {
NicoUIPlugin.logError(NicoUIPlugin.INTERNAL_ERROR, "Error of unexpected type occured, when writing to console stream.", e); //$NON-NLS-1$
}
}
}, filter);
}
}
public NIConsoleOutputStream getStream(final String streamId) {
synchronized (this.streams) {
return this.streams.get(streamId);
}
}
private void disconnect() {
synchronized (this.streams) {
if (this.streamsClosed) {
return;
}
for (final NIConsoleOutputStream stream : this.streams.values()) {
stream.close();
}
this.streamsClosed= true;
this.partitioner.finish();
this.adapter.disconnect();
this.adapter= null;
}
}
public final ToolProcess getProcess() {
return this.process;
}
@Override
@SuppressWarnings("unchecked")
public <T> T getAdapter(final Class<T> adapterType) {
if (adapterType == Tool.class) {
return (T) this.process;
}
if(adapterType == ILaunchConfiguration.class) {
final ILaunch launch= getProcess().getLaunch();
if (launch != null) {
return (T) launch.getLaunchConfiguration();
}
return null;
}
return null;
}
}