/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.ui.console;
import com.google.dart.tools.debug.core.DartDebugCorePlugin;
import com.google.dart.tools.debug.core.DartLaunchConfigWrapper;
import com.google.dart.tools.debug.ui.launch.OpenObservatoryAction;
import com.google.dart.tools.debug.ui.launch.StopPubServeAction;
import com.google.dart.tools.deploy.Activator;
import com.google.dart.tools.ui.DartToolsPlugin;
import com.google.dart.tools.ui.actions.InstrumentedAction;
import com.google.dart.tools.ui.instrumentation.UIInstrumentationBuilder;
import com.google.dart.tools.ui.internal.preferences.FontPreferencePage;
import com.google.dart.tools.ui.internal.util.SWTUtil;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchesListener2;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
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.MessageConsole;
import org.eclipse.ui.console.TextConsole;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.internal.console.IOConsolePage;
import org.eclipse.ui.part.IPageBookViewPage;
import org.eclipse.ui.part.PageSite;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import java.io.IOException;
/**
* An Eclipse view class that displays one and only one IConsole. This is different from the normal
* ConsoleView which displays n consoles.
*/
@SuppressWarnings("restriction")
public class DartConsoleView extends ViewPart implements IConsoleView, IPropertyChangeListener {
private class ClearAction extends InstrumentedAction {
public ClearAction() {
super("Clear", Activator.getImageDescriptor("icons/full/eview16/rem_co.gif"));
}
public void dispose() {
}
@Override
protected void doRun(Event event, UIInstrumentationBuilder instrumentation) {
Runnable r = new Runnable() {
@Override
public void run() {
if (console instanceof IOConsole) {
IOConsole ioConsole = (IOConsole) console;
ioConsole.clearConsole();
} else if (console instanceof MessageConsole) {
MessageConsole messageConsole = (MessageConsole) console;
messageConsole.clearConsole();
}
}
};
new Thread(r).start();
}
}
private class FontPropertyChangeListener implements IPropertyChangeListener {
@Override
public void propertyChange(final PropertyChangeEvent event) {
if (FontPreferencePage.VIEW_BASE_FONT_KEY.equals(event.getProperty())) {
updateFont();
}
}
}
private class PropertiesAction extends Action {
public PropertiesAction() {
super("Properties...", Activator.getImageDescriptor("icons/full/obj16/properties.gif"));
}
@Override
public void run() {
PreferenceDialog dialog = PreferencesUtil.createPropertyDialogOn(
getSite().getShell(),
getProcess(),
null,
null,
null);
dialog.open();
}
}
private class ScrollLockAction extends Action {
public ScrollLockAction() {
super("Pin Console");
setImageDescriptor(Activator.getImageDescriptor("icons/full/eview16/pin.gif"));
setChecked(getScrollLock());
}
/**
* @see org.eclipse.jface.action.IAction#run()
*/
@Override
public void run() {
setScrollLock(isChecked());
}
}
private class TerminateAction extends InstrumentedAction implements ILaunchesListener2 {
public TerminateAction() {
super("Terminate", Activator.getImageDescriptor("icons/full/eview16/terminate.gif"));
DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
update();
}
public void dispose() {
DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this);
}
@Override
public void launchesAdded(ILaunch[] launches) {
update();
}
@Override
public void launchesChanged(ILaunch[] launches) {
update();
}
@Override
public void launchesRemoved(ILaunch[] launches) {
update();
}
@Override
public void launchesTerminated(ILaunch[] launches) {
update();
}
@Override
protected void doRun(Event event, UIInstrumentationBuilder instrumentation) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
getProcess().terminate();
} catch (DebugException e) {
Activator.logError(e);
}
}
};
new Thread(r).start();
}
void update() {
IProcess process = getProcess();
if (process != null) {
setEnabled(!process.isTerminated());
} else {
setEnabled(false);
}
}
}
public static final String VIEW_ID = "com.google.dart.tools.ui.console";
private Composite parent;
private IConsole console;
private Object consoleLock = new Object();
private IPageBookViewPage page;
private PageSite pageSite;
private TerminateAction terminateAction;
private ClearAction clearAction;
private ScrollLockAction pinAction;
private IAction propertiesAction;
private StopPubServeAction stopPubServeAction;
private Display display;
private IPreferenceStore preferences;
private IPropertyChangeListener fontPropertyChangeListener = new FontPropertyChangeListener();
private IPropertyChangeListener propertyChangeListener = new IPropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
doPropertyChange(event);
}
};
private boolean scrollLock;
private OpenObservatoryAction openObservatoryAction;
public DartConsoleView() {
DartConsoleManager.getManager().consoleViewOpened(this);
}
@Override
public void createPartControl(Composite parent) {
this.parent = parent;
preferences = DartToolsPlugin.getDefault().getCombinedPreferenceStore();
display = Display.getCurrent();
JFaceResources.getFontRegistry().addListener(fontPropertyChangeListener);
getPreferences().addPropertyChangeListener(propertyChangeListener);//background
clearAction = new ClearAction();
pinAction = new ScrollLockAction();
propertiesAction = new PropertiesAction();
terminateAction = new TerminateAction();
stopPubServeAction = new StopPubServeAction();
stopPubServeAction.setImageDescriptor(Activator.getImageDescriptor("icons/full/obj16/psstop.gif"));
stopPubServeAction.setDisabledImageDescriptor(Activator.getImageDescriptor("icons/full/obj16/psstop_g.gif"));
openObservatoryAction = new OpenObservatoryAction();
openObservatoryAction.setImageDescriptor(Activator.getImageDescriptor("icons/full/obj16/open_browser.gif"));
openObservatoryAction.setDisabledImageDescriptor(Activator.getImageDescriptor("icons/full/obj16/open_browser_g.gif"));
updateToolBar();
}
@Override
public void display(IConsole inConsole) {
if (this.console != null) {
this.console.removePropertyChangeListener(this);
if (console instanceof ProcessConsole) {
getPreferences().removePropertyChangeListener((ProcessConsole) this.console);//in,out,err
}
this.console = null;
}
if (this.page != null) {
page.getControl().dispose();
page.dispose();
page = null;
}
// We recycle the console; remove any contributions from the previous ProcessConsole.
clearToolBar();
synchronized (consoleLock) {
this.console = inConsole;
}
// Add back our tolbar contributions.
updateToolBar();
// show the new console
if (this.console != null) {
this.console.addPropertyChangeListener(this);
if (console instanceof ProcessConsole) {
getPreferences().addPropertyChangeListener((ProcessConsole) this.console);
}
page = console.createPage(this);
try {
page.init(getPageSite());
page.createControl(parent);
} catch (PartInitException e) {
Activator.logError(e);
}
parent.layout();
}
updateFont();
updateColors();
updateContentDescription();
updateIcon();
terminateAction.update();
propertiesAction.setEnabled(getProcess() != null);
// Show cmdline used to launch process
if (console instanceof ProcessConsole) {
IProcess process = ((ProcessConsole) console).getProcess();
openObservatoryAction.updateEnablement(process.getLaunch());
showPauseOnStartMessage(process.getLaunch().getLaunchConfiguration());
}
}
@Override
public void dispose() {
JFaceResources.getFontRegistry().removeListener(fontPropertyChangeListener);
display = null;
DartConsoleManager.getManager().consoleViewClosed(this);
synchronized (consoleLock) {
if (console != null && isDead()) {
IProcess process = ((ProcessConsole) console).getProcess();
DebugPlugin.getDefault().getLaunchManager().removeLaunch(process.getLaunch());
}
}
terminateAction.dispose();
clearAction.dispose();
if (fontPropertyChangeListener != null) {
JFaceResources.getFontRegistry().removeListener(fontPropertyChangeListener);
fontPropertyChangeListener = null;
}
if (propertyChangeListener != null) {
getPreferences().removePropertyChangeListener(propertyChangeListener);
propertyChangeListener = null;
}
super.dispose();
}
@Override
public IConsole getConsole() {
return console;
}
@Override
public boolean getScrollLock() {
return scrollLock;
}
public boolean isDead() {
if (console == null) {
return true;
}
synchronized (consoleLock) {
if (console instanceof ProcessConsole) {
ProcessConsole processConsole = (ProcessConsole) console;
if (processConsole.getProcess() == null) {
return true;
}
return processConsole.getProcess().isTerminated();
}
}
return false;
}
@Override
public boolean isPinned() {
return false;
}
@Override
public void pin(IConsole console) {
}
@Override
public void propertyChange(PropertyChangeEvent event) {
if (display != null) {
display.asyncExec(new Runnable() {
@Override
public void run() {
updateContentDescription();
updateIcon();
}
});
}
}
@Override
public void setFocus() {
if (page != null) {
page.setFocus();
}
}
@Override
public void setPinned(boolean pin) {
}
@Override
public void setScrollLock(boolean scrollLock) {
this.scrollLock = scrollLock;
if (page instanceof IOConsolePage) {
((IOConsolePage) page).setAutoScroll(!scrollLock);
}
}
@Override
public void warnOfContentChange(IConsole console) {
// If the view stack is minimized, we don't want to show it and make it focused.
// https://code.google.com/p/dart/issues/detail?id=22307
if (isMinimized()) {
return;
}
IWorkbenchSiteProgressService progressService = (IWorkbenchSiteProgressService) getViewSite().getAdapter(
IWorkbenchSiteProgressService.class);
if (progressService != null) {
progressService.warnOfContentChange();
}
bringToFront();
}
protected void updateColors() {
// update DebugUI preferences
{
String themeColorStr = getPreferences().getString(
AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND);
if (themeColorStr != null) {
DebugUIPlugin.getDefault().getPreferenceStore().setValue(
IDebugPreferenceConstants.CONSOLE_BAKGROUND_COLOR,
themeColorStr);
}
}
// update the control
if (page != null && page.getControl() != null) {
SWTUtil.setColors((StyledText) page.getControl(), getPreferences());
}
}
private void bringToFront() {
IWorkbenchPage page = getViewSite().getPage();
if (!page.isPartVisible(this)) {
page.activate(this);
}
}
private void clearToolBar() {
IToolBarManager toolbar = getViewSite().getActionBars().getToolBarManager();
toolbar.removeAll();
}
private void doPropertyChange(PropertyChangeEvent event) {
SWTUtil.runUI(new Runnable() {
@Override
public void run() {
updateColors();
}
});
}
private PageSite getPageSite() {
if (pageSite == null) {
pageSite = new PageSite(getViewSite());
}
return pageSite;
}
private IPreferenceStore getPreferences() {
return preferences;
}
private IProcess getProcess() {
synchronized (consoleLock) {
if (console instanceof ProcessConsole) {
return ((ProcessConsole) console).getProcess();
} else {
return null;
}
}
}
private boolean isMinimized() {
IWorkbenchPage workbenchPage = getSite().getPage();
IViewReference thisRef = (IViewReference) workbenchPage.getReference(this);
return thisRef.isFastView();
}
private void showPauseOnStartMessage(ILaunchConfiguration config) {
try {
if (config.getType().getIdentifier().equals(DartDebugCorePlugin.SERVER_LAUNCH_CONFIG_ID)) {
DartLaunchConfigWrapper wrapper = new DartLaunchConfigWrapper(config);
if (wrapper.getPauseIsolateOnStart()) {
IOConsoleOutputStream stream = ((ProcessConsole) getConsole()).getStream(IDebugUIConstants.ID_STANDARD_OUTPUT_STREAM);
try {
stream.write("Isolate paused on start. Click on the \"Open Observatory\" button "
+ "in the Toolbar \nto open Observatory and continue isolate execution.\n\n");
} catch (IOException e) {
// do nothing
}
}
}
} catch (CoreException e) {
// do nothing
}
}
private void updateContentDescription() {
if (console instanceof ProcessConsole) {
IProcess process = ((ProcessConsole) console).getProcess();
String configName = process.getLaunch().getLaunchConfiguration().getName();
String name = "<" + configName + "> ";
if (process.isTerminated()) {
try {
name = name + " exit code = " + process.getExitValue();
} catch (DebugException ex) {
// ignore
}
bringToFront();
}
setContentDescription(name);
setPartName(configName);
} else {
setContentDescription("");
setPartName("Tools Output");
}
}
private void updateFont() {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
Font newFont = JFaceResources.getFont(FontPreferencePage.VIEW_BASE_FONT_KEY);
if (page != null && page.getControl() != null) {
Font oldFont = page.getControl().getFont();
Font font = SWTUtil.changeFontSize(oldFont, newFont);
((TextConsole) console).setFont(font);
page.getControl().setFont(font);
}
}
});
}
private void updateIcon() {
if (isDead()) {
setTitleImage(Activator.getImage("icons/full/eview16/console_view_d.gif"));
} else {
setTitleImage(Activator.getImage("icons/full/eview16/console_view.gif"));
}
}
private void updateToolBar() {
IToolBarManager toolbar = getViewSite().getActionBars().getToolBarManager();
toolbar.add(clearAction);
toolbar.add(propertiesAction);
toolbar.add(pinAction);
toolbar.add(new Separator());
if (!(console instanceof ProcessConsole)) {
toolbar.add(stopPubServeAction);
toolbar.add(new Separator());
} else {
toolbar.add(openObservatoryAction);
}
toolbar.add(terminateAction);
toolbar.add(new Separator("outputGroup"));
getViewSite().getActionBars().updateActionBars();
}
}