org.deved.antlride.ui.text.AntlrInputSourceViewer.java Source code

Java tutorial

Introduction

Here is the source code for org.deved.antlride.ui.text.AntlrInputSourceViewer.java

Source

/******************************************************************************
 * Copyright (c) 2007, 2008 Edgar Espina.
 * 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 org.deved.antlride.ui.text;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.deved.antlride.core.model.IGrammar;
import org.deved.antlride.core.model.IModelElement;
import org.deved.antlride.core.model.ast.ModelElementQuery;
import org.deved.antlride.internal.ui.views.interpreter.AntlrInterpreterMessages;
import org.deved.antlride.ui.AntlrPreferenceConstants;
import org.deved.antlride.ui.AntlrUIHelper;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.ITextOperationTarget;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.source.CompositeRuler;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.IVerticalRulerColumn;
import org.eclipse.jface.text.source.LineNumberRulerColumn;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ExtendedModifyEvent;
import org.eclipse.swt.custom.ExtendedModifyListener;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
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.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.IUpdate;

public class AntlrInputSourceViewer extends Viewer {

    private IGrammar fGrammar;

    private InputSourceViewerListener fListener;

    private Map<String, IAction> fGlobalActions;

    private MenuManager fMenuManager;

    private SourceViewer fSourceViewer;

    private Composite fComposite;

    private Label fStatusBar;

    private class InputSourceViewerListener
            implements ExtendedModifyListener, ISelectionChangedListener, KeyListener, MouseListener {

        public void modifyText(ExtendedModifyEvent event) {
            StyledText styledText = (StyledText) event.widget;
            String text = styledText.getText();
            if (text != null && text.length() > 0) {
                highlightSyntax(text);
            }
        }

        public void selectionChanged(SelectionChangedEvent event) {
            updateAction(ITextEditorActionConstants.CUT);
            updateAction(ITextEditorActionConstants.COPY);
        }

        public void keyPressed(KeyEvent e) {
            updateStatusLine();
        }

        public void keyReleased(KeyEvent e) {
        }

        public void mouseDoubleClick(MouseEvent e) {
        }

        public void mouseDown(MouseEvent e) {
            updateStatusLine();
        }

        public void mouseUp(MouseEvent e) {
        }
    }

    private class TextViewerAction extends Action implements IUpdate {

        private int fOperationCode = -1;
        private ITextOperationTarget fOperationTarget;

        /**
         * Creates a new action.
         * 
         * @param viewer
         *            the viewer
         * @param operationCode
         *            the opcode
         */
        public TextViewerAction(ITextViewer viewer, int operationCode) {
            fOperationCode = operationCode;
            fOperationTarget = viewer.getTextOperationTarget();
            update();
        }

        /**
         * Updates the enabled state of the action. Fires a property change if
         * the enabled state changes.
         * 
         * @see Action#firePropertyChange(String, Object, Object)
         */
        public void update() {

            boolean wasEnabled = isEnabled();
            boolean isEnabled = (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode));
            setEnabled(isEnabled);

            if (wasEnabled != isEnabled) {
                firePropertyChange(ENABLED, wasEnabled ? Boolean.TRUE : Boolean.FALSE,
                        isEnabled ? Boolean.TRUE : Boolean.FALSE);
            }
        }

        /**
         * @see Action#run()
         */
        public void run() {
            if (fOperationCode != -1 && fOperationTarget != null) {
                fOperationTarget.doOperation(fOperationCode);
            }

        }
    }

    private class ShowMenuListener implements IMenuListener {

        public void menuAboutToShow(IMenuManager manager) {
            onMenuAboutToShow(manager);
        }
    }

    public AntlrInputSourceViewer(Composite parent, boolean editable) {
        createControl(parent, editable);
    }

    public AntlrInputSourceViewer(Composite parent) {
        this(parent, true);
    }

    public void setEditable(boolean editable) {
        fSourceViewer.setEditable(editable);
    }

    protected void createControl(Composite parent, boolean editable) {
        fComposite = new Composite(parent, SWT.BORDER);
        GridLayout layout = new GridLayout(2, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        fComposite.setLayout(layout);
        IVerticalRuler verticalRuler = createVerticalRuler();
        int style = SWT.MULTI | SWT.V_SCROLL | SWT.BORDER;
        fSourceViewer = new SourceViewer(fComposite, verticalRuler, style);
        fSourceViewer.setDocument(new Document());
        fSourceViewer.setEditable(editable);
        // configure text
        fListener = new InputSourceViewerListener();
        StyledText styledText = fSourceViewer.getTextWidget();
        styledText.setFont(getDefaultFont());
        styledText.addExtendedModifyListener(fListener);
        styledText.addMouseListener(fListener);
        styledText.addKeyListener(fListener);
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.horizontalSpan = 2;

        fSourceViewer.getControl().setLayoutData(gd);

        createTextActions();

        fSourceViewer.addSelectionChangedListener(fListener);
        fMenuManager = new MenuManager();
        fMenuManager.addMenuListener(new ShowMenuListener());
        fMenuManager.setRemoveAllWhenShown(true);

        Menu menu = fMenuManager.createContextMenu(styledText);

        styledText.setMenu(menu);
        // status bar
        gd = new GridData(SWT.RIGHT, SWT.FILL, true, false);
        gd.widthHint = 40;
        fStatusBar = new Label(fComposite, SWT.LEFT);
        fStatusBar.setLayoutData(gd);
        updateStatusLine();
        Label separator = new Label(fComposite, SWT.SEPARATOR);
        // separator.setText(" ");
        gd = new GridData();
        gd.widthHint = 8;
        gd.heightHint = 8;
        separator.setLayoutData(gd);
    }

    public StyledText getTextWidget() {
        return fSourceViewer.getTextWidget();
    }

    private void updateStatusLine() {
        StyledText styledText = getTextWidget();
        StringBuilder buf = new StringBuilder();
        int line = styledText.getLineAtOffset(styledText.getCaretOffset());
        buf.append(line + 1);
        buf.append(" : ");
        buf.append(styledText.getCaretOffset() - styledText.getOffsetAtLine(line) + 1);
        // buf.append(" ");
        fStatusBar.setText(buf.toString());
    }

    private static Font getDefaultFont() {
        return JFaceResources.getFont("Monospaced");
    }

    protected void onMenuAboutToShow(IMenuManager menuManager) {
        String[] actions = { ITextEditorActionConstants.CUT, ITextEditorActionConstants.COPY,
                ITextEditorActionConstants.PASTE, null, ITextEditorActionConstants.SELECT_ALL };
        for (String actionId : actions) {
            IAction action = fGlobalActions.get(actionId);
            if (action == null) {
                menuManager.add(new Separator());
            } else {
                menuManager.add(action);
            }
        }
        menuManager.update();
    }

    private void updateAction(String actionId) {
        IAction action = (IAction) fGlobalActions.get(actionId);
        if (action instanceof IUpdate)
            ((IUpdate) action).update();
    }

    private void createTextActions() {
        fGlobalActions = new HashMap<String, IAction>();

        ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();

        TextViewerAction action;

        action = new TextViewerAction(fSourceViewer, ITextOperationTarget.CUT);
        action.setAccelerator(SWT.CTRL | 'X');
        action.setText(AntlrInterpreterMessages.GrammarInterpreter_Cut);
        action.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT));
        action.setDisabledImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT_DISABLED));
        fGlobalActions.put(ITextEditorActionConstants.CUT, action);

        action = new TextViewerAction(fSourceViewer, ITextOperationTarget.COPY);
        action.setAccelerator(SWT.CTRL | 'C');
        action.setText(AntlrInterpreterMessages.GrammarInterpreter_Copy);
        action.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
        action.setDisabledImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED));
        fGlobalActions.put(ITextEditorActionConstants.COPY, action);

        action = new TextViewerAction(fSourceViewer, ITextOperationTarget.PASTE);
        action.setAccelerator(SWT.CTRL | 'V');
        action.setText(AntlrInterpreterMessages.GrammarInterpreter_Paste);
        action.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
        action.setDisabledImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE_DISABLED));
        fGlobalActions.put(ITextEditorActionConstants.PASTE, action);

        action = new TextViewerAction(fSourceViewer, ITextOperationTarget.SELECT_ALL);
        action.setText(AntlrInterpreterMessages.GrammarInterpreter_Select_All);
        fGlobalActions.put(ITextEditorActionConstants.SELECT_ALL, action);

    }

    public void dispose() {
        fGrammar = null;
        fListener = null;
        fComposite.dispose();
    }

    private void highlightSyntax(String text) {
        IGrammar grammar = fGrammar;
        if (grammar == null)
            return;
        StyledText styledText = getTextWidget();
        IModelElement[] literals = ModelElementQuery.collectLiterals(grammar);
        if (literals != null && literals.length > 0) {
            Pattern pattern = Pattern.compile("(\\w(\\w|\\d)*)|(\\S)");
            Matcher matcher = pattern.matcher(text);
            List<StyleRange> styleRanges = new ArrayList<StyleRange>();
            while (matcher.find()) {
                String word = matcher.group();
                if (word.length() > 1) {
                    for (IModelElement literal : literals) {
                        String elementName = literal.getElementName().substring(1,
                                literal.getElementName().length() - 1);
                        if (elementName.equals(word)) {
                            int start = matcher.start();
                            int length = matcher.end() - matcher.start();
                            styleRanges.add(createStyleRange(start, length));
                            break;
                        }
                    }
                }
            }
            styledText.setStyleRanges(styleRanges.toArray(new StyleRange[styleRanges.size()]));
        }
    }

    private StyleRange createStyleRange(int start, int length) {
        StyleRange styleRange = new StyleRange();
        styleRange.start = start;
        styleRange.length = length;
        styleRange.fontStyle = SWT.BOLD;
        styleRange.foreground = JFaceResources.getColorRegistry()
                .get(AntlrPreferenceConstants.EDITOR_KEYWORD_COLOR);
        return styleRange;
    }

    public IGrammar getGrammar() {
        return fGrammar;
    }

    public void setGrammar(IGrammar grammar) {
        fGrammar = grammar;
    }

    private static IVerticalRuler createVerticalRuler() {
        CompositeRuler ruler = new CompositeRuler();
        ruler.addDecorator(0, createLineNumberRulerColumn());
        return ruler;
    }

    private static IVerticalRulerColumn createLineNumberRulerColumn() {
        LineNumberRulerColumn verticalRulerColumn = new LineNumberRulerColumn();
        Color color = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY);
        verticalRulerColumn.setFont(getDefaultFont());
        verticalRulerColumn.setForeground(color);
        return verticalRulerColumn;
    }

    public IAction getAction(String actionId) {
        return fGlobalActions.get(actionId);
    }

    @Override
    public Control getControl() {
        return fComposite;
    }

    @Override
    public Object getInput() {
        return fSourceViewer.getInput();
    }

    @Override
    public ISelection getSelection() {
        return fSourceViewer.getSelection();
    }

    @Override
    public void refresh() {
        fSourceViewer.refresh();
    }

    @Override
    public void setInput(Object input) {
        if (input instanceof String) {
            input = new Document((String) input);
        }
        fSourceViewer.setInput(input);
        highlightSyntax(((Document) fSourceViewer.getInput()).get());
    }

    @Override
    public void setSelection(ISelection selection, boolean reveal) {
        AntlrUIHelper.select(getTextWidget(), (AntlrTextSelection) selection);
    }

    @Override
    public void addSelectionChangedListener(ISelectionChangedListener listener) {
        fSourceViewer.addSelectionChangedListener(listener);
    }
}