/******************************************************************************* * Copyright (c) 2009 Vlad Dumitrescu and others. 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: Vlad Dumitrescu *******************************************************************************/ package org.erlide.ui.console; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.ResourceBundle; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.IFindReplaceTarget; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CaretEvent; import org.eclipse.swt.custom.CaretListener; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.console.IConsoleConstants; import org.eclipse.ui.console.IConsoleView; import org.eclipse.ui.internal.console.ConsoleResourceBundleMessages; import org.eclipse.ui.internal.console.IConsoleHelpContextIds; import org.eclipse.ui.part.Page; import org.eclipse.ui.texteditor.FindReplaceAction; import org.eclipse.ui.texteditor.IUpdate; import org.erlide.backend.api.IBackend; import org.erlide.engine.services.parsing.ParserException; import org.erlide.engine.services.parsing.RuntimeHelper; import org.erlide.runtime.shell.IBackendShell; import org.erlide.ui.internal.ErlideUIPlugin; import org.erlide.ui.util.ColorManager; import org.erlide.ui.util.IColorManager; import org.erlide.util.StringUtils; import com.ericsson.otp.erlang.OtpErlangList; import com.ericsson.otp.erlang.OtpErlangObject; @SuppressWarnings("restriction") public class ErlangConsolePage extends Page implements IAdaptable, IPropertyChangeListener, IErlangConsolePage { public static final String ID = "org.erlide.ui.views.console"; Color bgColor_Ok; Color bgColor_AlmostOk; Color bgColor_Err; StyledText consoleOutputText; private final ErlConsoleDocument fDoc; final ErlangConsoleHistory history = new ErlangConsoleHistory(); StyledText consoleInputText; SourceViewer consoleOutputViewer; private SourceViewer consoleInputViewer; private IBackendShell shell; protected Map<String, IAction> fGlobalActions = new HashMap<>(); protected List<String> fSelectionActions = new ArrayList<>(); // protected ClearOutputAction fClearOutputAction; private final ErlangConsole fConsole; private IConsoleView fConsoleView; private MenuManager fMenuManager; private Composite composite; private boolean disposeColors; private final IBackend backend; private final ISelectionChangedListener selectionChangedListener = new ISelectionChangedListener() { @Override public void selectionChanged(final SelectionChangedEvent event) { updateSelectionDependentActions(); } }; private Color bgcolor; public ErlangConsolePage(final IConsoleView view, final ErlangConsole console, final IBackend backend) { super(); fConsole = console; fConsoleView = view; shell = console.getShell(); fDoc = new ErlConsoleDocument(shell); this.backend = backend; } @Override public void dispose() { consoleOutputViewer.getSelectionProvider() .removeSelectionChangedListener(selectionChangedListener); if (fMenuManager != null) { fMenuManager.dispose(); } // fClearOutputAction = null; fSelectionActions.clear(); fGlobalActions.clear(); shell.dispose(); shell = null; fConsoleView = null; if (disposeColors) { bgColor_Err.dispose(); bgColor_Ok.dispose(); bgColor_AlmostOk.dispose(); } ErlideUIPlugin.getDefault().getErlConsoleManager().removePage(fConsole); super.dispose(); } boolean isInputComplete() { if (!backend.getRuntime().isRunning()) { return false; } try { final String str = consoleInputText.getText() + " "; final RuntimeHelper helper = new RuntimeHelper(backend.getOtpRpc()); final OtpErlangObject o = helper.parseConsoleInput(str); if (o instanceof OtpErlangList && ((OtpErlangList) o).arity() == 0) { return false; } if (!(o instanceof OtpErlangList)) { return false; } } catch (final ParserException e) { return false; } return true; } protected void sendInput() { final String s = consoleInputText.getText(); input(s); consoleInputText.setText(""); } @Override public void input(final String data) { final String data2 = data.trim() + "\n"; shell.input(data2); shell.send(data2); history.addToHistory(data.trim()); } public void setInput(final String str) { consoleInputText.setText(str); consoleInputText.setSelection(str.length()); } /** * @wbp.parser.entryPoint */ @Override public void createControl(final Composite parent) { setBackgroundColors(); composite = new Composite(parent, SWT.NONE); composite.setLayout(new GridLayout(1, false)); final SashForm sashForm = new SashForm(composite, SWT.VERTICAL); sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); consoleOutputViewer = new SourceViewer(sashForm, null, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.READ_ONLY); consoleOutputText = consoleOutputViewer.getTextWidget(); consoleOutputText.setFont(JFaceResources.getTextFont()); bgcolor = DebugUIPlugin .getPreferenceColor(IDebugPreferenceConstants.CONSOLE_BAKGROUND_COLOR); consoleOutputText.setBackground(bgcolor); DebugUIPlugin.getDefault().getPreferenceStore() .addPropertyChangeListener(new IPropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent event) { if (event.getProperty().equals( IDebugPreferenceConstants.CONSOLE_BAKGROUND_COLOR)) { final Color color = DebugUIPlugin.getPreferenceColor( IDebugPreferenceConstants.CONSOLE_BAKGROUND_COLOR); consoleOutputText.setBackground(color); consoleInputText.setBackground(color); } } }); consoleOutputText.addKeyListener(new KeyAdapter() { @Override public void keyPressed(final KeyEvent e) { if (e.stateMask == 0 && e.character != '\0') { consoleInputText.setFocus(); consoleInputText.append("" + e.character); consoleInputText.setCaretOffset(consoleInputText.getText().length()); } e.doit = true; } }); final IPreferenceStore store = ErlideUIPlugin.getDefault().getPreferenceStore(); final IColorManager colorManager = new ColorManager(); consoleOutputViewer.setDocument(fDoc); consoleOutputViewer.configure( new ErlangConsoleSourceViewerConfiguration(store, colorManager, backend)); consoleInputViewer = new SourceViewer(sashForm, null, SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); consoleInputText = consoleInputViewer.getTextWidget(); consoleInputViewer.setDocument(new Document()); consoleInputViewer.configure( new ErlangConsoleSourceViewerConfiguration(store, colorManager, backend)); sashForm.setWeights(new int[] { 2, 1 }); final Label helpLabel = new Label(composite, SWT.NONE); helpLabel.setText( "To send the input to the console: press Enter at the end of an expression." + "Ctrl/Cmd-arrows navigate the input history."); helpLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); final ModifyListener modifyListener = new ModifyListener() { @Override public void modifyText(final ModifyEvent e) { final String consoleText = trimInput(consoleInputText.getText()); final boolean atEndOfInput = consoleText.endsWith(".") && consoleInputText.getCaretOffset() >= consoleText.length(); if (atEndOfInput) { final boolean inputComplete = isInputComplete(); if (inputComplete) { consoleInputText.setBackground(bgColor_Ok); } } else { consoleInputText.setBackground(bgcolor); } } }; // consoleInput.addModifyListener(modifyListener); consoleInputText.addCaretListener(new CaretListener() { @Override public void caretMoved(final CaretEvent event) { modifyListener.modifyText(null); } }); consoleInputText.addKeyListener(new KeyAdapter() { @Override public void keyPressed(final KeyEvent e) { final boolean ctrlOrCommandPressed = (e.stateMask & SWT.MOD1) == SWT.MOD1; final String conText = trimInput(consoleInputText.getText()); final boolean atEndOfInput = consoleInputText.getCaretOffset() >= conText .length() && conText.endsWith("."); e.doit = true; if (e.keyCode == 13 && (ctrlOrCommandPressed || atEndOfInput)) { final boolean inputComplete = isInputComplete(); if (inputComplete) { sendInput(); } } else if (ctrlOrCommandPressed && e.keyCode == SWT.SPACE) { consoleInputViewer.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS); } else if (ctrlOrCommandPressed && e.keyCode == SWT.ARROW_UP) { e.doit = false; history.prev(); final String s = history.get(); if (s != null) { consoleInputText.setText(s); consoleInputText .setSelection(consoleInputText.getText().length()); } } else if (ctrlOrCommandPressed && e.keyCode == SWT.ARROW_DOWN) { e.doit = false; history.next(); final String s = history.get(); if (s != null) { consoleInputText.setText(s); consoleInputText .setSelection(consoleInputText.getText().length()); } } } }); consoleInputText.setFont(consoleOutputText.getFont()); consoleInputText.setBackground(consoleOutputText.getBackground()); consoleInputText.setWordWrap(true); consoleInputText.setFocus(); // end layout final IDocumentListener documentListener = new IDocumentListener() { @Override public void documentAboutToBeChanged(final DocumentEvent event) { } @Override public void documentChanged(final DocumentEvent event) { final int end = consoleOutputViewer.getDocument().getLength(); consoleOutputViewer.setSelectedRange(end, end); consoleOutputViewer.revealRange(end, 0); } }; addDocumentListener(documentListener); final String id = "#ContextMenu"; //$NON-NLS-1$ // if (getConsole().getType() != null) { // id = getConsole().getType() + "." + id; //$NON-NLS-1$ // } fMenuManager = new MenuManager("#ContextMenu", id); //$NON-NLS-1$ fMenuManager.setRemoveAllWhenShown(true); fMenuManager.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(final IMenuManager m) { contextMenuAboutToShow(m); } }); final Menu menu = fMenuManager.createContextMenu(getControl()); getControl().setMenu(menu); createActions(); configureToolBar(getSite().getActionBars().getToolBarManager()); getSite().registerContextMenu(id, fMenuManager, consoleOutputViewer); getSite().setSelectionProvider(consoleOutputViewer); consoleOutputViewer.getSelectionProvider() .addSelectionChangedListener(selectionChangedListener); } private void setBackgroundColors() { final Color color = DebugUIPlugin .getPreferenceColor(IDebugPreferenceConstants.CONSOLE_BAKGROUND_COLOR); final float[] hsbvals = new float[3]; java.awt.Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsbvals); if (hsbvals[1] >= 0.01) { bgColor_Ok = color; bgColor_AlmostOk = color; bgColor_Err = color; disposeColors = false; } else { final float red = java.awt.Color.RGBtoHSB(255, 0, 0, null)[0]; final float green = java.awt.Color.RGBtoHSB(0, 255, 0, null)[0]; final float deltaSaturation = 0.05f; int rgb = java.awt.Color.HSBtoRGB(red, deltaSaturation, hsbvals[2]); java.awt.Color cx = new java.awt.Color(rgb); bgColor_Err = new Color(Display.getCurrent(), new RGB(cx.getRed(), cx.getGreen(), cx.getBlue())); rgb = java.awt.Color.HSBtoRGB(green, 2 * deltaSaturation, hsbvals[2]); cx = new java.awt.Color(rgb); bgColor_Ok = new Color(Display.getCurrent(), new RGB(cx.getRed(), cx.getGreen(), cx.getBlue())); rgb = java.awt.Color.HSBtoRGB(green, deltaSaturation, hsbvals[2]); cx = new java.awt.Color(rgb); bgColor_AlmostOk = new Color(Display.getCurrent(), new RGB(cx.getRed(), cx.getGreen(), cx.getBlue())); disposeColors = true; } } @Override public Control getControl() { return composite; } @Override public void setActionBars(final IActionBars bars) { } @Override public void setFocus() { consoleInputText.setFocus(); } @Override public Object getAdapter(@SuppressWarnings("rawtypes") final Class required) { if (IFindReplaceTarget.class.equals(required)) { return consoleOutputViewer.getFindReplaceTarget(); } if (Widget.class.equals(required)) { return consoleOutputViewer.getTextWidget(); } return null; } @Override public void propertyChange(final PropertyChangeEvent event) { if (consoleOutputViewer != null) { final Object source = event.getSource(); final String property = event.getProperty(); if (source.equals(fConsole) && IConsoleConstants.P_FONT.equals(property)) { // consoleOutputViewer.setFont(fConsole.getFont()); } else if (IConsoleConstants.P_FONT_STYLE.equals(property)) { consoleOutputViewer.getTextWidget().redraw(); } else if (property.equals(IConsoleConstants.P_STREAM_COLOR)) { consoleOutputViewer.getTextWidget().redraw(); } else if (source.equals(fConsole) && property.equals(IConsoleConstants.P_TAB_SIZE)) { // Integer tabSize = (Integer) event.getNewValue(); // consoleOutputViewer.setTabWidth(tabSize.intValue()); } else if (source.equals(fConsole) && property.equals(IConsoleConstants.P_CONSOLE_WIDTH)) { // consoleOutputViewer.setConsoleWidth(fConsole.getConsoleWidth()); } else if (IConsoleConstants.P_BACKGROUND_COLOR.equals(property)) { consoleOutputViewer.getTextWidget() .setBackground(fConsole.getBackground()); } } } protected void createActions() { final IActionBars actionBars = getSite().getActionBars(); // TextViewerAction action = new TextViewerAction(consoleOutputViewer, // ITextOperationTarget.SELECT_ALL); // action.configureAction(ConsoleMessages.TextConsolePage_SelectAllText, // ConsoleMessages.TextConsolePage_SelectAllDescrip, // ConsoleMessages.TextConsolePage_SelectAllDescrip); // action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_SELECT_ALL); // PlatformUI.getWorkbench().getHelpSystem() // .setHelp(action, IConsoleHelpContextIds.CONSOLE_SELECT_ALL_ACTION); // setGlobalAction(actionBars, ActionFactory.SELECT_ALL.getId(), // action); // // action = new TextViewerAction(consoleOutputViewer, // ITextOperationTarget.CUT); // action.configureAction(ConsoleMessages.TextConsolePage_CutText, // ConsoleMessages.TextConsolePage_CutDescrip, // ConsoleMessages.TextConsolePage_CutDescrip); // action.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages() // .getImageDescriptor(ISharedImages.IMG_TOOL_CUT)); // action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_CUT); // PlatformUI.getWorkbench().getHelpSystem() // .setHelp(action, IConsoleHelpContextIds.CONSOLE_CUT_ACTION); // setGlobalAction(actionBars, ActionFactory.CUT.getId(), action); // // action = new TextViewerAction(consoleOutputViewer, // ITextOperationTarget.COPY); // action.configureAction(ConsoleMessages.TextConsolePage_CopyText, // ConsoleMessages.TextConsolePage_CopyDescrip, // ConsoleMessages.TextConsolePage_CopyDescrip); // action.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages() // .getImageDescriptor(ISharedImages.IMG_TOOL_COPY)); // action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_COPY); // PlatformUI.getWorkbench().getHelpSystem() // .setHelp(action, IConsoleHelpContextIds.CONSOLE_COPY_ACTION); // setGlobalAction(actionBars, ActionFactory.COPY.getId(), action); // fClearOutputAction = new ClearOutputAction(fConsole); final ResourceBundle bundle = ConsoleResourceBundleMessages.getBundle(); final FindReplaceAction fraction = new FindReplaceAction(bundle, "find_replace_action_", fConsoleView); //$NON-NLS-1$ PlatformUI.getWorkbench().getHelpSystem().setHelp(fraction, IConsoleHelpContextIds.CONSOLE_FIND_REPLACE_ACTION); setGlobalAction(actionBars, ActionFactory.FIND.getId(), fraction); // fSelectionActions.add(ActionFactory.CUT.getId()); // fSelectionActions.add(ActionFactory.COPY.getId()); fSelectionActions.add(ActionFactory.FIND.getId()); actionBars.updateActionBars(); } protected void setGlobalAction(final IActionBars actionBars, final String actionID, final IAction action) { fGlobalActions.put(actionID, action); actionBars.setGlobalActionHandler(actionID, action); } protected void contextMenuAboutToShow(final IMenuManager menuManager) { final IDocument doc = consoleOutputViewer.getDocument(); if (doc == null) { return; } menuManager.add(fGlobalActions.get(ActionFactory.CUT.getId())); menuManager.add(fGlobalActions.get(ActionFactory.COPY.getId())); menuManager.add(fGlobalActions.get(ActionFactory.SELECT_ALL.getId())); menuManager.add(new Separator("FIND")); //$NON-NLS-1$ menuManager.add(fGlobalActions.get(ActionFactory.FIND.getId())); // menuManager.add(new FollowHyperlinkAction(consoleOutputViewer)); // menuManager.add(fClearOutputAction); menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); } protected void configureToolBar(final IToolBarManager mgr) { // mgr.appendToGroup(IConsoleConstants.OUTPUT_GROUP, // fClearOutputAction); } protected void updateSelectionDependentActions() { final Iterator<String> iterator = fSelectionActions.iterator(); while (iterator.hasNext()) { updateAction(iterator.next()); } } protected void updateAction(final String actionId) { final IAction action = fGlobalActions.get(actionId); if (action instanceof IUpdate) { ((IUpdate) action).update(); } } public void addDocumentListener(final IDocumentListener documentListener) { fDoc.addDocumentListener(documentListener); } public void removeDocumentListener(final IDocumentListener documentListener) { fDoc.removeDocumentListener(documentListener); } public IBackendShell getShell() { return shell; } private static String trimInput(final String s) { String conText = StringUtils.rightTrim(s, ' '); conText = StringUtils.rightTrim(conText, '\n'); conText = StringUtils.rightTrim(conText, '\r'); return conText; } }