hr.fer.zemris.vhdllab.applets.texteditor.TextEditor.java Source code

Java tutorial

Introduction

Here is the source code for hr.fer.zemris.vhdllab.applets.texteditor.TextEditor.java

Source

/*******************************************************************************
 * See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership.
 * 
 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 * 
 * 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 hr.fer.zemris.vhdllab.applets.texteditor;

import hr.fer.zemris.vhdllab.applets.texteditor.misc.KeywordHighlighterTextPane;

import hr.fer.zemris.vhdllab.applets.texteditor.misc.LineNumbers;
import hr.fer.zemris.vhdllab.applets.texteditor.misc.ModificationListener;

import hr.fer.zemris.vhdllab.entity.File;
import hr.fer.zemris.vhdllab.platform.manager.editor.impl.AbstractEditor;

import java.awt.Color;
import java.awt.Event;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.PrintWriter;
import java.io.StringWriter;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
import javax.swing.text.Highlighter;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;

import org.springframework.richclient.application.Application;

// Pogledaj: http://download.oracle.com/javase/tutorial/uiswing/components/generaltext.html#undo
// http://spring-rich-c.sourceforge.net/1.1.0/apidocs/org/springframework/binding/value/CommitTrigger.html

public class TextEditor extends AbstractEditor implements CaretListener, ModificationListener {

    private CustomJTextPane textPane;
    //private CommitTrigger commitTrigger;

    private Object highlighted;

    @Override
    protected JComponent doInitWithoutData() {
        textPane = new CustomJTextPane(this);
        wrapInScrollPane = false;

        JScrollPane jsp = new JScrollPane(textPane);
        LineNumbers.createInstance(textPane, jsp, 30);

        Document document = textPane.getDocument();

        if (document instanceof AbstractDocument) {
            ((AbstractDocument) document).setDocumentFilter(new DocumentFilter() {

                @Override
                public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
                        throws BadLocationException {
                    if (text != null && (text.length() - length) > 10
                            && !text.equals(CustomJTextPane.getClipboardText()) && !textIsBlank(text)) {
                        informPastingIsDisabled();
                    } else {
                        super.replace(fb, offset, length, text, attrs);
                    }
                }

                private boolean textIsBlank(String text) {
                    if (text == null)
                        return true;
                    for (char c : text.toCharArray()) {
                        switch (c) {
                        case ' ':
                            break;
                        case '\t':
                            break;
                        case '\r':
                            break;
                        case '\n':
                            break;
                        default:
                            return false;
                        }
                    }
                    return true;
                }

                private void informPastingIsDisabled() {
                    JFrame frame = Application.instance().getActiveWindow().getControl();
                    JOptionPane.showMessageDialog(frame, "Pasting text from outside of vhdllab is disabled!",
                            "Paste text", JOptionPane.INFORMATION_MESSAGE);
                }

            });
        }

        textPane.addCaretListener(this);
        // commitTrigger = new CommitTrigger();
        // TextComponentPopup.attachPopup(textPane, commitTrigger);

        return jsp;
    }

    @Override
    protected void doInitWithData(File f) {
        textPane.setText(f.getData());
        textPane.resetUndoManager();
        // commitTrigger.commit();
    }

    @Override
    protected String getData() {
        return textPane.getText();
    }

    @Override
    protected void doDispose() {
    }

    @Override
    public void setEditable(boolean flag) {
        textPane.setEditable(flag);
    }

    @Override
    public void highlightLine(int line) {
        int caret = textPane.getCaretPosition();
        Highlighter h = textPane.getHighlighter();
        h.removeAllHighlights();
        String content = textPane.getText();
        textPane.setCaretPosition(caret);

        int pos = 0;
        line--;
        while (line > 0) {
            pos = content.indexOf('\n', pos) + 1;
            line--;
        }
        int last = content.indexOf('\n', pos) + 1;
        if (last == 0) {
            last = content.length();
        }
        try {
            highlighted = h.addHighlight(pos, last,
                    new DefaultHighlighter.DefaultHighlightPainter(new Color(180, 210, 238)));
        } catch (BadLocationException e) {
            e.printStackTrace();
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            JOptionPane.showMessageDialog(null, sw.toString());
        }
    }

    //
    // ModificationListener implementation
    //
    @Override
    public void contentModified() {
        setModified(true);
    }

    //
    // CaretListener implementation
    //

    @Override
    public void caretUpdate(CaretEvent e) {
        if (highlighted != null) {
            textPane.getHighlighter().removeHighlight(highlighted);
            highlighted = null;
        }
    }

    /**
     * Custom razred koji omogucava presretanje copy&paste operacija.
     * Interno, u globalnu se varijablu pamti sve sto je korisnik
     * kopirao/izrezao iz uredivaca tako da se pastanje toga dozvoljava
     * ali pastanje bilo cega drugoga veceg od 10 znakova ne.
     * Dodatno, font se postavlja na monospaced sto je uobicajeno
     * za uredivace koda.
     */
    private static class CustomJTextPane extends KeywordHighlighterTextPane {

        private static final long serialVersionUID = 1L;

        private static String clipboardText;
        private ModificationListener modificationListener;
        protected UndoManager undoManager;
        protected UndoAction undoAction;
        protected RedoAction redoAction;

        public CustomJTextPane(ModificationListener modificationListener) {
            this.modificationListener = modificationListener;
            Font font = this.getFont();
            int fontSize = font.getSize();
            Font newFont = new Font(Font.MONOSPACED, Font.PLAIN, fontSize);
            this.setFont(newFont);

            undoManager = new UndoManager();
            undoAction = new UndoAction();
            redoAction = new RedoAction();

            InputMap inputMap = getInputMap();
            KeyStroke undoKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z, Event.CTRL_MASK);
            inputMap.put(undoKeyStroke, undoAction);
            KeyStroke redoKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y, Event.CTRL_MASK);
            inputMap.put(redoKeyStroke, redoAction);

            getDocument().addUndoableEditListener(new UndoableEditListener() {
                @Override
                public void undoableEditHappened(UndoableEditEvent e) {
                    if (analysisInProgress)
                        return;
                    undoManager.addEdit(e.getEdit());
                    undoAction.updateUndoState();
                    redoAction.updateRedoState();
                }
            });
            getDocument().addDocumentListener(new DocumentListener() {

                @Override
                public void removeUpdate(DocumentEvent e) {
                    if (!analysisInProgress && CustomJTextPane.this.modificationListener != null) {
                        CustomJTextPane.this.modificationListener.contentModified();
                    }
                }

                @Override
                public void insertUpdate(DocumentEvent e) {
                    if (!analysisInProgress && CustomJTextPane.this.modificationListener != null) {
                        CustomJTextPane.this.modificationListener.contentModified();
                    }
                }

                @Override
                public void changedUpdate(DocumentEvent e) {
                    if (!analysisInProgress && CustomJTextPane.this.modificationListener != null) {
                        CustomJTextPane.this.modificationListener.contentModified();
                    }
                }
            });
        }

        @Override
        public void copy() {
            String selText = this.getSelectedText();
            if (selText == null || selText.isEmpty()) {
                return;
            }
            setClipboardText(selText);
            super.copy();
        }

        @Override
        public void cut() {
            String selText = this.getSelectedText();
            if (selText == null || selText.isEmpty()) {
                return;
            }
            setClipboardText(selText);
            super.cut();
        }

        public void resetUndoManager() {
            undoManager.discardAllEdits();
            undoAction.updateUndoState();
            redoAction.updateRedoState();
        }

        public static synchronized String getClipboardText() {
            return clipboardText;
        }

        public static synchronized void setClipboardText(String clipboardText) {
            CustomJTextPane.clipboardText = clipboardText;
        }

        class UndoAction extends AbstractAction {

            private static final long serialVersionUID = 1L;

            public UndoAction() {
                super("Undo");
                setEnabled(false);
            }

            public void actionPerformed(ActionEvent e) {
                try {
                    undoManager.undo();
                } catch (CannotUndoException ex) {
                    System.out.println("Unable to undo: " + ex);
                    ex.printStackTrace();
                }
                updateUndoState();
                redoAction.updateRedoState();
            }

            protected void updateUndoState() {
                if (undoManager.canUndo()) {
                    setEnabled(true);
                    putValue(Action.NAME, undoManager.getUndoPresentationName());
                } else {
                    setEnabled(false);
                    putValue(Action.NAME, "Undo");
                }
            }
        }

        class RedoAction extends AbstractAction {

            private static final long serialVersionUID = 1L;

            public RedoAction() {
                super("Redo");
                setEnabled(false);
            }

            public void actionPerformed(ActionEvent e) {
                try {
                    undoManager.redo();
                } catch (CannotRedoException ex) {
                    System.out.println("Unable to redo: " + ex);
                    ex.printStackTrace();
                }
                updateRedoState();
                undoAction.updateUndoState();
            }

            protected void updateRedoState() {
                if (undoManager.canRedo()) {
                    setEnabled(true);
                    putValue(Action.NAME, undoManager.getRedoPresentationName());
                } else {
                    setEnabled(false);
                    putValue(Action.NAME, "Redo");
                }
            }
        }
    }
}