blob: 94a7c4be84eabeed08e8f25f6370ff32de469eac [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2010 Sonatype, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Sonatype, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.m2e.core.ui.internal.console;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jface.preference.JFacePreferences;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceColors;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleListener;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.IOConsole;
import org.eclipse.ui.console.IOConsoleOutputStream;
import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
import org.eclipse.m2e.core.ui.internal.M2EUIPluginActivator;
import org.eclipse.m2e.core.ui.internal.Messages;
/**
* Maven Console implementation
*
* @author Dmitri Maximovich
*/
public class MavenConsoleImpl extends IOConsole implements MavenConsole, IPropertyChangeListener {
private boolean initialized = false;
// console is visible in the Console view
private boolean visible = false;
private ConsoleDocument consoleDocument;
// created colors for each line type - must be disposed at shutdown
private Color messageColor;
// streams for each command type - each stream has its own color
private IOConsoleOutputStream commandStream;
private IOConsoleOutputStream messageStream;
private IOConsoleOutputStream errorStream;
private static final String TITLE = Messages.MavenConsoleImpl_title;
private List<IMavenConsoleListener> listeners = new CopyOnWriteArrayList<IMavenConsoleListener>();
public MavenConsoleImpl(ImageDescriptor imageDescriptor) {
super(TITLE, imageDescriptor);
this.setConsoleDocument(new ConsoleDocument());
}
protected void init() {
super.init();
// Ensure that initialization occurs in the UI thread
Display.getDefault().asyncExec(() -> {
JFaceResources.getFontRegistry().addListener(MavenConsoleImpl.this);
initializeConsoleStreams(Display.getDefault());
dumpConsole();
});
}
/*
* Initialize three streams of the console. Must be called from the UI thread, so synchronization is unnecessary.
*/
protected void initializeConsoleStreams(Display display) {
if(!initialized) {
setCommandStream(newOutputStream());
setErrorStream(newOutputStream());
setMessageStream(newOutputStream());
ColorRegistry colorRegistry = JFaceResources.getColorRegistry();
// TODO convert this to use themes
// install colors
Color background = colorRegistry.get(JFacePreferences.INFORMATION_BACKGROUND_COLOR);
if(background == null) {
background = JFaceColors.getInformationViewerBackgroundColor(display);
}
setBackground(background);
Color commandColor = colorRegistry.get(JFacePreferences.INFORMATION_FOREGROUND_COLOR);
if(commandColor == null) {
commandColor = JFaceColors.getInformationViewerForegroundColor(display);
}
messageColor = new Color(display, commandColor.getRGB(), 200);
Color errorColor = colorRegistry.get(JFacePreferences.ERROR_COLOR);
if(errorColor == null) {
errorColor = JFaceColors.getErrorText(display);
}
getCommandStream().setColor(commandColor);
getMessageStream().setColor(messageColor);
getErrorStream().setColor(errorColor);
// install font
setFont(JFaceResources.getFontRegistry().get("pref_console_font")); //$NON-NLS-1$
initialized = true;
}
}
/**
* Is always called from main thread, so synchronization not necessary
*/
protected void dumpConsole() {
setVisible(true);
ConsoleDocument.ConsoleLine[] lines = getConsoleDocument().getLines();
for(int i = 0; i < lines.length; i++ ) {
ConsoleDocument.ConsoleLine line = lines[i];
appendLine(line.type, line.line);
}
getConsoleDocument().clear();
}
private void appendLine(final int type, final String line) {
show(false);
//the synchronization here caused a deadlock. since the writes are simply appending to the output stream
//or the document, just doing it on the main thread to avoid deadlocks and or corruption of the
//document or output stream
Display.getDefault().asyncExec(() -> {
if(isVisible()) {
try {
switch(type) {
case ConsoleDocument.COMMAND:
getCommandStream().write(line);
getCommandStream().write('\n');
break;
case ConsoleDocument.MESSAGE:
getMessageStream().write(line);
getMessageStream().write('\n');
break;
case ConsoleDocument.ERROR:
getErrorStream().write(line);
getErrorStream().write('\n');
break;
}
} catch(IOException ex) {
// Don't log using slf4j - it will cause a cycle
ex.printStackTrace();
}
} else {
getConsoleDocument().appendConsoleLine(type, line);
}
});
}
/**
* Show the console.
*
* @param showNoMatterWhat ignore preferences if <code>true</code>
*/
public void show(boolean showNoMatterWhat) {
if(showNoMatterWhat) {
if(!isVisible()) {
showConsole();
} else {
ConsolePlugin.getDefault().getConsoleManager().showConsoleView(this);
}
}
}
public void showConsole() {
boolean exists = false;
IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager();
for(IConsole element : manager.getConsoles()) {
if(this == element) {
exists = true;
}
}
if(!exists) {
manager.addConsoles(new IConsole[] {this});
}
manager.showConsoleView(this);
}
public void closeConsole() {
IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager();
manager.removeConsoles(new IConsole[] {this});
ConsolePlugin.getDefault().getConsoleManager().addConsoleListener(this.newLifecycle());
}
public void propertyChange(PropertyChangeEvent event) {
// font changed
setFont(JFaceResources.getFontRegistry().get("pref_console_font")); //$NON-NLS-1$
}
private void bringConsoleToFront() {
if(PlatformUI.isWorkbenchRunning()) {
IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager();
if(!isVisible()) {
manager.addConsoles(new IConsole[] {this});
}
manager.showConsoleView(this);
}
}
// Called when console is removed from the console view
protected void dispose() {
// Here we can't call super.dispose() because we actually want the partitioner to remain
// connected, but we won't show lines until the console is added to the console manager
// again.
Display.getDefault().asyncExec(() -> {
setVisible(false);
JFaceResources.getFontRegistry().removeListener(MavenConsoleImpl.this);
});
}
public void shutdown() {
// Call super dispose because we want the partitioner to be
// disconnected.
super.dispose();
if(messageColor != null) {
messageColor.dispose();
}
}
private DateFormat getDateFormat() {
return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, Locale.getDefault());
}
// MavenConsole
public void debug(String message) {
if(!M2EUIPluginActivator.getDefault().getPreferenceStore().getBoolean(MavenPreferenceConstants.P_DEBUG_OUTPUT)) {
return;
}
if(showConsoleOnOutput()) {
bringConsoleToFront();
}
appendLine(ConsoleDocument.MESSAGE, getDateFormat().format(new Date()) + ": " + message);
for(IMavenConsoleListener listener : listeners) {
try {
listener.loggingMessage(message);
} catch(Exception e) {
e.printStackTrace();
}
}
}
public void info(String message) {
if(showConsoleOnOutput()) {
bringConsoleToFront();
}
appendLine(ConsoleDocument.MESSAGE, getDateFormat().format(new Date()) + ": " + message);
for(IMavenConsoleListener listener : listeners) {
try {
listener.loggingMessage(message);
} catch(Exception e) {
e.printStackTrace();
}
}
}
public void error(String message) {
if(showConsoleOnError()) {
bringConsoleToFront();
}
appendLine(ConsoleDocument.ERROR, getDateFormat().format(new Date()) + ": " + message); //$NON-NLS-1$
for(IMavenConsoleListener listener : listeners) {
try {
listener.loggingError(message);
} catch(Exception e) {
e.printStackTrace();
}
}
}
public boolean showConsoleOnError() {
return M2EUIPluginActivator.getDefault().getPreferenceStore()
.getBoolean(MavenPreferenceConstants.P_SHOW_CONSOLE_ON_ERR);
}
public boolean showConsoleOnOutput() {
return M2EUIPluginActivator.getDefault().getPreferenceStore()
.getBoolean(MavenPreferenceConstants.P_SHOW_CONSOLE_ON_OUTPUT);
}
public IConsoleListener newLifecycle() {
return new MavenConsoleLifecycle();
}
/**
* @param commandStream The commandStream to set.
*/
protected void setCommandStream(IOConsoleOutputStream commandStream) {
this.commandStream = commandStream;
}
/**
* @return Returns the commandStream.
*/
protected IOConsoleOutputStream getCommandStream() {
return commandStream;
}
/**
* @param messageStream The messageStream to set.
*/
protected void setMessageStream(IOConsoleOutputStream messageStream) {
this.messageStream = messageStream;
}
/**
* @return Returns the messageStream.
*/
protected IOConsoleOutputStream getMessageStream() {
return messageStream;
}
/**
* @param errorStream The errorStream to set.
*/
protected void setErrorStream(IOConsoleOutputStream errorStream) {
this.errorStream = errorStream;
}
/**
* @return Returns the errorStream.
*/
protected IOConsoleOutputStream getErrorStream() {
return errorStream;
}
/**
* @param visible The visible to set.
*/
protected void setVisible(boolean visible) {
this.visible = visible;
}
/**
* @return Returns the visible.
*/
protected boolean isVisible() {
return visible;
}
/**
* @param consoleDocument The consoleDocument to set.
*/
private void setConsoleDocument(ConsoleDocument consoleDocument) {
this.consoleDocument = consoleDocument;
}
/**
* @return Returns the consoleDocument.
*/
protected ConsoleDocument getConsoleDocument() {
return consoleDocument;
}
/**
* Used to notify this console of lifecycle methods <code>init()</code> and <code>dispose()</code>.
*/
public class MavenConsoleLifecycle implements org.eclipse.ui.console.IConsoleListener {
public void consolesAdded(IConsole[] consoles) {
for(int i = 0; i < consoles.length; i++ ) {
IConsole console = consoles[i];
if(console == MavenConsoleImpl.this) {
init();
}
}
}
public void consolesRemoved(IConsole[] consoles) {
for(int i = 0; i < consoles.length; i++ ) {
IConsole console = consoles[i];
if(console == MavenConsoleImpl.this) {
ConsolePlugin.getDefault().getConsoleManager().removeConsoleListener(this);
dispose();
}
}
}
}
public void addMavenConsoleListener(IMavenConsoleListener listener) {
listeners.remove(listener);
listeners.add(listener);
}
public void removeMavenConsoleListener(IMavenConsoleListener listener) {
listeners.remove(listener);
}
}