/**
* Copyright (c) 2009, 2010 Mark Feber, MulgaSoft
*
* 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
*
*/
package com.mulgasoft.emacsplus.execute;
import java.io.IOException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.LineBackgroundListener;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.console.IOConsole;
import org.eclipse.ui.console.IOConsoleOutputStream;
import org.eclipse.ui.console.TextConsolePage;
import org.eclipse.ui.console.TextConsoleViewer;
import org.eclipse.ui.internal.console.IOConsoleViewer;
import org.eclipse.ui.part.IPageBookViewPage;
import org.osgi.framework.Bundle;
import com.mulgasoft.emacsplus.EmacsPlusActivator;
import com.mulgasoft.emacsplus.EmacsPlusUtils;
/**
* Extend a IOConsole for use as the Emacs+ console
*
* @author Mark Feber - initial API and implementation
*/
@SuppressWarnings("restriction") // for cast to internal class org.eclipse.ui.internal.console.IOConsoleViewer
public class EmacsPlusConsole extends IOConsole implements VerifyKeyListener {
private static String WI_CONSOLE= EmacsPlusActivator.getResourceString("Cmd_Console"); //$NON-NLS-1$
private static EmacsPlusConsole instance = null;
static boolean pre33 = false;
public Color highlightColor = new Color(null,237,237,252); // pale background
private Color contextColor = new Color(null,0,0,255); // blue
private Color defaultColor = new Color(null,0,0,0); // black
private StyledText myWidget = null;
private TextConsolePage myPage = null;
private TextConsoleViewer myViewer = null;
private IEmacsPlusConsoleKey keyHandler = null;
/**
* Singleton
*/
private EmacsPlusConsole() {
super(WI_CONSOLE,null);
}
public static EmacsPlusConsole getInstance() {
if (instance == null) {
pre33 = checkBundle(); // see kludge comment below
instance = new EmacsPlusConsole();
ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[]{ instance });
}
return instance;
}
/**
* @see org.eclipse.ui.console.IOConsole#dispose()
*/
protected void dispose() {
clear();
super.dispose();
}
/**
* Clear console content.
*/
public void clear() {
setName(WI_CONSOLE);
removeBackground();
setKeyHandler(null);
if (!pre33) {
clearConsole();
}
IDocument document = getDocument();
if (document != null) {
document.set(EmacsPlusUtils.EMPTY_STR);
}
getWidget();
}
/**
* Expose setName functionality
*
* @see org.eclipse.ui.console.AbstractConsole#setName(java.lang.String)
*/
public void setName(String name) {
super.setName(name);
}
/**
* @see org.eclipse.ui.console.IConsole#createPage(org.eclipse.ui.console.IConsoleView)
*/
public IPageBookViewPage createPage(IConsoleView view) {
IPageBookViewPage page = super.createPage(view);
if (page instanceof TextConsolePage) {
myPage = (TextConsolePage)page;
}
return page;
}
public void setFocus(final boolean reset) {
super.activate();
if (getWidget() != null) {
if (reset) {
myViewer.revealRange(0, 0);
myWidget.setTopIndex(0);
}
myWidget.setFocus();
}
}
private StyledText getWidget() {
// we have to delay this, as the widget/viewer are not set up
// until after the console has finished all its delayed Jobs
if (myWidget == null && myPage != null) {
myViewer = myPage.getViewer();
if (myViewer != null) {
myWidget = myPage.getViewer().getTextWidget();
myWidget.setEditable(false);
// restricted: It is lame that we have to cast to internal class to remove this behavior
if (myViewer instanceof IOConsoleViewer) {
((IOConsoleViewer)myViewer).setAutoScroll(false);
}
}
}
return myWidget;
}
/**
* Print command help in the console.
*/
public void print(final String message, final Color c, final int style) {
printMessage(message, c, style);
}
public void printContext(String context) {
print(context,contextColor,SWT.ITALIC);
}
public void printBinding(String binding) {
printBold(binding);
}
public void printBold(String str) {
print(str,defaultColor,SWT.BOLD);
}
public void printItalic(String str) {
print(str,defaultColor,SWT.ITALIC);
}
public void print(String message, int style) {
this.print(message,null,style);
}
public void print(String message, Color c) {
this.print(message,c,SWT.DEFAULT);
}
public void print(String message) {
this.print(message,SWT.DEFAULT);
}
private IOConsoleOutputStream getOutputStream() {
return newOutputStream();
}
protected void printMessage(String message, Color c, int style) {
if (message != null) {
IOConsoleOutputStream outputStream = getOutputStream();
outputStream.setActivateOnWrite(true);
if (c != null) {
outputStream.setColor(c);
}
outputStream.setFontStyle(style);
try {
outputStream.write(message);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public int getLine() {
int result = 0;
StyledText st = getWidget();
if (st != null ) {
result = st.getLineAtOffset(st.getCaretOffset());
}
return result;
}
public int getOffset() {
int result = 0;
StyledText st = getWidget();
if (st != null ) {
result = st.getCaretOffset();
}
return result;
}
private LineBackgroundListener background = null;
public void addBackground(LineBackgroundListener listener) {
if (getWidget() != null && !myWidget.isDisposed()) {
myWidget.addLineBackgroundListener(listener);
background = listener;
}
}
private void removeBackground() {
if (background != null) {
removeBackground(background);
background = null;
}
}
public void removeBackground(LineBackgroundListener listener) {
if (getWidget() != null && !myWidget.isDisposed()) {
myWidget.removeLineBackgroundListener(listener);
}
}
/*
* Permit the command handler to specialize the console's key handling
*/
public void setKeyHandler(IEmacsPlusConsoleKey handler) {
keyHandler = handler;
}
/**
* PageParticipant activation
*/
void onLine() {
if (getWidget() != null) {
if (keyHandler != null) {
myViewer.appendVerifyKeyListener(this);
}
}
}
/**
* PageParticipant deactivation
*/
void offLine() {
if (getWidget() != null) {
myViewer.removeVerifyKeyListener(this);
}
}
/**
* @see org.eclipse.swt.custom.VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
*/
public void verifyKey(VerifyEvent event) {
handleKey(event);
}
/**
* Dispatch the key handling to the command
*
* @param event
*/
protected void handleKey(VerifyEvent event) {
if (!event.doit)
return;
if (keyHandler != null && event.character != 0) { // process typed character
keyHandler.handleKey(event,myViewer);
}
}
// kludge: (totally) due to Europa <-> Ganymede changes
// There was an incompatible change in bug 202564 (https://bugs.eclipse.org/bugs/show_bug.cgi?id=202564)
// Before the change: the change listener invoked by document.set("") would clear the partitioning information
// After the change: clearConsole() needs to be called to effect this
// But: calling clearConsole in the 3.2 version 'hangs' the console and nothing is printed
// TODO: There must be a better way to either 1) clear the partition information or 2) get the bundle version
private static boolean checkBundle() {
boolean result = false;
Bundle bundle = EmacsPlusActivator.getDefault().getBundle();
for (Bundle b : bundle.getBundleContext().getBundles()) {
if ("org.eclipse.ui.console".equals(b.getSymbolicName())) { //$NON-NLS-$
Object v = b.getHeaders().get("Bundle-Version"); //$NON-NLS-$
result = (v != null && v instanceof String && ((String)v).startsWith("3.2")); //$NON-NLS-$
break;
}
}
return result;
}
}