tk.tomby.tedit.core.Buffer.java Source code

Java tutorial

Introduction

Here is the source code for tk.tomby.tedit.core.Buffer.java

Source

/*
 * $Id: Buffer.java,v 1.1.1.1 2004/09/18 17:16:19 amunoz Exp $
 *
 * Copyright (C) 2003 Antonio G. Muoz Conejo <amunoz@tomby.homelinux.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package tk.tomby.tedit.core;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import java.net.URL;
import java.util.Iterator;

import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import tk.tomby.tedit.core.snr.FindReplaceWorker;

import tk.tomby.tedit.messages.BufferMessage;
import tk.tomby.tedit.messages.IMessageListener;
import tk.tomby.tedit.messages.PreferenceMessage;

import tk.tomby.tedit.services.EditorKitManager;
import tk.tomby.tedit.services.MessageManager;
import tk.tomby.tedit.services.PreferenceManager;
import tk.tomby.tedit.services.ResourceManager;
import tk.tomby.tedit.services.TaskManager;
import tk.tomby.tedit.services.WorkspaceManager;

/**
 * DOCUMENT ME!
 *
 * @author $Author: amunoz $
 * @version $Revision: 1.1.1.1 $
 */
public class Buffer extends JPanel implements IBuffer, IMessageListener<PreferenceMessage> {
    //~ Static fields/initializers *****************************************************************

    /** DOCUMENT ME! */
    private static Log log = LogFactory.getLog(Buffer.class);

    /** DOCUMENT ME! */
    private static final String DEFAULT_FILE_NAME = ResourceManager.getProperty("main.default.filename");

    //~ Instance fields ****************************************************************************

    /** DOCUMENT ME! */
    private ColourTextArea editor = null;

    /** DOCUMENT ME! */
    private FindReplaceWorker worker = null;

    /** DOCUMENT ME! */
    private LineNumbering lines = null;

    /** DOCUMENT ME! */
    private String fileName = null;

    /** DOCUMENT ME! */
    private UndoManager undo = null;

    /** DOCUMENT ME! */
    private UndoableEditListener undoableListener = null;

    /** DOCUMENT ME! */
    private boolean modifiedState = false;

    /** DOCUMENT ME! */
    private boolean newState = true;

    //~ Constructors *******************************************************************************

    /**
     * Creates a new Buffer object.
     */
    public Buffer() {
        super();

        setLayout(new BorderLayout());

        JPanel internalPanel = new JPanel();
        internalPanel.setLayout(new BorderLayout());

        editor = new ColourTextArea();

        int red = PreferenceManager.getInt("general.editor.background.red", 0);
        int green = PreferenceManager.getInt("general.editor.background.green", 0);
        int blue = PreferenceManager.getInt("general.editor.background.blue", 0);
        editor.setBackground(new Color(red, green, blue));

        red = PreferenceManager.getInt("general.editor.foreground.red", 0);
        green = PreferenceManager.getInt("general.editor.foreground.green", 0);
        blue = PreferenceManager.getInt("general.editor.foreground.blue", 0);
        editor.setForeground(new Color(red, green, blue));

        red = PreferenceManager.getInt("general.editor.selection.red", 0);
        green = PreferenceManager.getInt("general.editor.selection.green", 0);
        blue = PreferenceManager.getInt("general.editor.selection.blue", 0);
        editor.setSelectionColor(new Color(red, green, blue));

        String font = PreferenceManager.getString("general.editor.font", "Monospaced");
        int size = PreferenceManager.getInt("general.editor.fontSize", 12);
        editor.setFont(new Font(font, Font.PLAIN, size));

        editor.setEditable(true);
        editor.setDragEnabled(true);
        editor.setEditorKit(EditorKitManager.createEditorKit(getExtension(DEFAULT_FILE_NAME)));

        InputMap map = editor.getInputMap(JComponent.WHEN_FOCUSED);

        for (InputMap imap = map; imap != null; imap = imap.getParent()) {
            imap.remove(KeyStroke.getKeyStroke('V', InputEvent.CTRL_MASK, false));
            imap.remove(KeyStroke.getKeyStroke('C', InputEvent.CTRL_MASK, false));
            imap.remove(KeyStroke.getKeyStroke('X', InputEvent.CTRL_MASK, false));
            imap.remove(KeyStroke.getKeyStroke('A', InputEvent.CTRL_MASK, false));
        }

        editor.setInputMap(JComponent.WHEN_FOCUSED, map);

        editor.addCaretListener(new CaretListener() {
            public void caretUpdate(CaretEvent evt) {
                MessageManager.sendMessage(new BufferMessage(evt.getSource(), BufferMessage.CARET_EVENT));
            }
        });

        internalPanel.add(BorderLayout.CENTER, editor);

        if (PreferenceManager.getBoolean("general.editor.lineNumbers", false)) {
            lines = new LineNumbering();
            lines.setPreferredSize(new Dimension(50, 0));
            lines.setFont(new Font(font, Font.PLAIN, size));
            lines.setFocusable(false);
            lines.setDocument(editor.getDocument());

            internalPanel.add(BorderLayout.WEST, lines);
        }

        JScrollPane scroll = new JScrollPane(internalPanel);
        scroll.getVerticalScrollBar().setUnitIncrement(10);
        scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
        scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scroll.getViewport().setScrollMode(JViewport.BLIT_SCROLL_MODE);

        add(BorderLayout.CENTER, scroll);

        editor.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent evt) {
                if (evt.isPopupTrigger()) {
                    WorkspaceManager.getPopupMenu().show(evt.getComponent(), evt.getX(), evt.getY());
                }
            }

            public void mouseReleased(MouseEvent evt) {
                if (evt.isPopupTrigger()) {
                    WorkspaceManager.getPopupMenu().show(evt.getComponent(), evt.getX(), evt.getY());
                }
            }
        });

        undo = new UndoManager();

        undoableListener = new UndoableEditListener() {
            public void undoableEditHappened(UndoableEditEvent evt) {
                undo.addEdit(evt.getEdit());

                MessageManager.sendMessage(new BufferMessage(evt.getSource(), BufferMessage.UNDOABLE_EDIT_EVENT));

                if (!modifiedState) {
                    setModifiedState(true);
                }
            }
        };

        editor.getDocument().addUndoableEditListener(undoableListener);

        MessageManager.addMessageListener(MessageManager.PREFERENCE_GROUP_NAME, this);

        fileName = DEFAULT_FILE_NAME;
    }

    //~ Methods ************************************************************************************

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public int getCaretPosition() {
        return editor.getCaretPosition();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public int getCurrentLine() {
        int position = getCaretPosition();

        return getDocument().getDefaultRootElement().getElementIndex(position);
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public int getCurrentColumn() {
        int position = getCaretPosition();
        int line = getCurrentLine();

        Element element = getDocument().getDefaultRootElement().getElement(line);

        return (element != null) ? position - element.getStartOffset() : position;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public Document getDocument() {
        return editor.getDocument();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public File getFile() {
        return new File(this.fileName);
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String getFileName() {
        return this.fileName;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String getText() {
        int length = getDocument().getLength();
        try {
            return getDocument().getText(0, length);
        } catch (BadLocationException e) {
            log.error("error getting buffer text", e);
        }
        return null;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String getText(int offset, int length) {
        try {
            return getDocument().getText(offset, length);
        } catch (BadLocationException e) {
            log.error("error getting buffer text", e);
        }
        return null;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public int getLineCount() {
        return getDocument().getDefaultRootElement().getElementCount();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public boolean isModified() {
        return modifiedState;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public boolean isNew() {
        return newState;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public boolean isReadOnly() {
        return !editor.isEditable();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public int getSelectionEnd() {
        return editor.getSelectionEnd();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public int getSelectionStart() {
        return editor.getSelectionStart();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public boolean canRedo() {
        return undo.canRedo();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public boolean canUndo() {
        return undo.canUndo();
    }

    /**
     * DOCUMENT ME!
     */
    public void clean() {
        editor.setText("");
        editor.setEditorKit(EditorKitManager.createEditorKit(getExtension(DEFAULT_FILE_NAME)));

        if (lines != null) {
            lines.setDocument(editor.getDocument());
        }

        resetDocument();

        setFileName(DEFAULT_FILE_NAME);

        setNewState(true);
        setModifiedState(false);
    }

    /**
     * DOCUMENT ME!
     */
    public void close() {
        MessageManager.removeMessageListener(MessageManager.PREFERENCE_GROUP_NAME, this);

        Document doc = editor.getDocument();

        ((ICleanable) doc).cleanup();
    }

    /**
     * DOCUMENT ME!
     */
    public void copy() {
        editor.copy();
    }

    /**
     * DOCUMENT ME!
     */
    public void cut() {
        editor.cut();
    }

    /**
     * DOCUMENT ME!
     */
    public void findNext() {
        if (worker == null) {
            worker = new FindReplaceWorker(this);
        }

        worker.next();
    }

    /**
     * DOCUMENT ME!
     */
    public void findPrevious() {
        if (worker == null) {
            worker = new FindReplaceWorker(this);
        }

        worker.previous();
    }

    /**
     * DOCUMENT ME!
     *
     * @param line DOCUMENT ME!
     */
    public void gotoLine(int line) {
        Element root = editor.getDocument().getDefaultRootElement();

        if ((line < root.getElementCount()) && (line > 0)) {
            Element element = root.getElement(line - 1);
            editor.setCaretPosition(element.getStartOffset());
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param url DOCUMENT ME!
     */
    public void open(URL url) {
        open(url.getFile());
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     */
    public void open(String file) {
        open(new File(file));
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     */
    public void open(File file) {
        try {
            editor.setEditorKit(EditorKitManager.createEditorKit(getExtension(file.getName())));
            editor.getDocument().removeUndoableEditListener(undoableListener);

            FileReader in = new FileReader(file);
            editor.read(in, null);

            if (lines != null) {
                lines.setDocument(editor.getDocument());
            }

            editor.setEditable(file.canWrite());

            resetDocument();

            setFileName(file.getAbsolutePath());

            setNewState(false);
            setModifiedState(false);

            if (log.isDebugEnabled()) {
                log.debug("contentType=" + editor.getContentType());
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * DOCUMENT ME!
     */
    public void paste() {
        editor.paste();
    }

    /**
     * DOCUMENT ME!
     *
     * @param message DOCUMENT ME!
     */
    public void receiveMessage(PreferenceMessage message) {
        if (message.getKey().equals("general.editor.background")) {
            final Color background = (Color) message.getNewValue();
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    editor.setBackground(background);
                }
            });
        } else if (message.getKey().equals("general.editor.foreground")) {
            final Color foreground = (Color) message.getNewValue();
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    editor.setForeground(foreground);
                }
            });
        } else if (message.getKey().equals("general.editor.selection")) {
            final Color selection = (Color) message.getNewValue();
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    editor.setSelectionColor(selection);
                }
            });
        }
    }

    /**
     * DOCUMENT ME!
     */
    public void redo() {
        try {
            undo.redo();
            MessageManager.sendMessage(new BufferMessage(this, BufferMessage.UNDOABLE_EDIT_EVENT));

            if (!modifiedState) {
                setModifiedState(true);
            }
        } catch (CannotRedoException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * DOCUMENT ME!
     */
    public void replace() {
        if (worker == null) {
            worker = new FindReplaceWorker(this);
        }

        worker.replace();
    }

    /**
     * DOCUMENT ME!
     */
    public void save() {
        if (editor.isEditable()) {
            TaskManager.execute(new Runnable() {
                public void run() {
                    try {
                        FileWriter out = new FileWriter(fileName);
                        editor.write(out);
                        setModifiedState(false);
                    } catch (IOException e) {
                        log.error(e.getMessage(), e);
                    }
                }
            });
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param url DOCUMENT ME!
     */
    public void saveAs(URL url) {
        saveAs(url.getFile());
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     */
    public void saveAs(String file) {
        saveAs(new File(file));
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     */
    public void saveAs(final File file) {
        TaskManager.execute(new SwingWorker() {
            @Override
            protected Object doInBackground() throws Exception {
                try {
                    FileWriter out = new FileWriter(file);
                    editor.write(out);
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
                return null;
            }

            @Override
            protected void done() {
                open(file);
            }
        });
    }

    /**
     * DOCUMENT ME!
     *
     * @param start DOCUMENT ME!
     * @param end DOCUMENT ME!
     */
    public void select(int start, int end) {
        editor.select(start, end);
    }

    /**
     * DOCUMENT ME!
     */
    public void selectAll() {
        editor.selectAll();
    }

    /**
     * DOCUMENT ME!
     */
    public void undo() {
        try {
            undo.undo();
            MessageManager.sendMessage(new BufferMessage(this, BufferMessage.UNDOABLE_EDIT_EVENT));

            if (!modifiedState) {
                setModifiedState(true);
            }
        } catch (CannotUndoException e) {
            log.error(e.getMessage(), e);
        }
    }

    public void insertString(int offset, String text) {
        try {
            getDocument().insertString(offset, text, null);
        } catch (BadLocationException e) {
            log.error(e.getMessage(), e);
        }
    }

    public void replaceString(int offset, int length, String text) {
        try {
            getDocument().remove(offset, length);
            getDocument().insertString(offset, text, null);
        } catch (BadLocationException e) {
            log.error(e.getMessage(), e);
        }
    }

    public void removeString(int offset, int length) {
        try {
            getDocument().remove(offset, length);
        } catch (BadLocationException e) {
            log.error(e.getMessage(), e);
        }
    }

    public Iterator<Element> elementIterator() {
        return new ElementIterator(getDocument());
    }

    public Iterator<String> lineIterator() {
        return new LineIterator(getDocument());
    }

    /**
     * DOCUMENT ME!
     *
     * @param fileName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    private String getExtension(String fileName) {
        int index = fileName.lastIndexOf('.');

        if (index > 0) {
            return fileName.substring(index + 1);
        }

        return null;
    }

    /**
     * DOCUMENT ME!
     *
     * @param fileName DOCUMENT ME!
     */
    private void setFileName(String fileName) {
        this.fileName = fileName;

        MessageManager.sendMessage(new BufferMessage(this, BufferMessage.CHANGE_FILE_EVENT));
    }

    /**
     * DOCUMENT ME!
     *
     * @param modifiedState DOCUMENT ME!
     */
    private void setModifiedState(boolean modifiedState) {
        this.modifiedState = modifiedState;

        MessageManager.sendMessage(new BufferMessage(this, BufferMessage.MODIFIED_FILE_EVENT));
    }

    /**
     * DOCUMENT ME!
     *
     * @param newState DOCUMENT ME!
     */
    private void setNewState(boolean newState) {
        this.newState = newState;
    }

    /**
     * DOCUMENT ME!
     */
    private void resetDocument() {
        editor.getDocument().addUndoableEditListener(undoableListener);

        undo.discardAllEdits();

        MessageManager.sendMessage(new BufferMessage(this, BufferMessage.UNDOABLE_EDIT_EVENT));
    }

    class ElementIterator implements Iterator<Element> {

        Document doc;
        int count;

        public ElementIterator(Document doc) {
            this.doc = doc;
        }

        public boolean hasNext() {
            return doc.getDefaultRootElement().getElementCount() > count;
        }

        public Element next() {
            return doc.getDefaultRootElement().getElement(count++);
        }

        public void remove() {
            throw new RuntimeException("not implemented");
        }
    }

    class LineIterator implements Iterator<String> {

        Document doc;
        int count;

        public LineIterator(Document doc) {
            this.doc = doc;
        }

        public boolean hasNext() {
            return doc.getDefaultRootElement().getElementCount() > count;
        }

        public String next() {
            Element line = doc.getDefaultRootElement().getElement(count++);
            try {
                return doc.getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset());
            } catch (BadLocationException e) {
                log.error(e.getMessage(), e);
            }
            return null;
        }

        public void remove() {
            throw new RuntimeException("not implemented");
        }
    }
}