/*
Jreepad - personal information manager.
Copyright (C) 2004 Dan Stowell
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.
The full license can be read online here:
http://www.gnu.org/copyleft/gpl.html
*/
package jreepad.editor;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.BoxView;
import javax.swing.text.ComponentView;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.IconView;
import javax.swing.text.LabelView;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import jreepad.JreepadArticle;
import jreepad.JreepadPrefs;
import jreepad.JreepadView;
/**
* The plain text editor pane.
*/
public class PlainTextEditor extends EditorPaneView implements CaretListener, UndoableEditListener
{
private ContentChangeListener contentChangeListener = null;
public PlainTextEditor(JreepadArticle article)
{
super("text/plain", article);
editorPane.setEditable(true);
if (getPrefs().wrapToWindow)
editorPane.setEditorKit(new JPEditorKit());
// Add a listener to make sure the editorpane's content is always stored
// when it changes
editorPane.addCaretListener(this);
editorPane.getDocument().addUndoableEditListener(this);
}
public void insertText(String text)
{
Document doc = editorPane.getDocument();
int here = editorPane.getCaretPosition();
try
{
editorPane.setText(doc.getText(0, here) + text
+ doc.getText(here, doc.getLength() - here));
editorPane.setCaretPosition(here + text.length());
}
catch (BadLocationException e)
{
// Simply ignore this
}
}
public void setContentChangeListener(ContentChangeListener listener)
{
contentChangeListener = listener;
}
private void notifyContentChangeListener()
{
if (contentChangeListener != null)
contentChangeListener.contentChanged();
}
public String selectWordUnderCursor()
{
try
{
String text = editorPane.getText();
int startpos = editorPane.getCaretPosition();
int endpos = startpos;
if (text.length() > 0)
{
// Select the character before/after the current position, and
// grow it until we hit whitespace...
while (startpos > 0 && !Character.isWhitespace(editorPane.getText(startpos - 1, 1).charAt(0)))
startpos--;
while (endpos < (text.length()) && !Character.isWhitespace(editorPane.getText(endpos, 1).charAt(0)))
endpos++;
if (endpos > startpos)
{
editorPane.setSelectionStart(startpos);
editorPane.setSelectionEnd(endpos);
return getSelectedText();
}
}
}
catch (BadLocationException e)
{
}
return "";
}
public void caretUpdate(CaretEvent e)
{
if (editLocked)
return; // i.e. we are deactivated while changing from node to node
if (article.getArticleMode() != JreepadArticle.ARTICLEMODE_ORDINARY)
return; // i.e. we are only relevant when in plain-text mode
if (!editorPane.getText().equals(article.getContent()))
{
// System.out.println("UPDATE - I'd now overwrite node content with
// editorpane content");
article.setContent(editorPane.getText());
notifyContentChangeListener();
}
else
{
// System.out.println(" No need to update content.");
}
}
public static JreepadPrefs getPrefs()
{
return JreepadView.getPrefs();
}
// Code to ensure that the article word-wraps follows
// - contributed by Michael Labhard based on code found on the web...
private static class JPEditorKit extends StyledEditorKit
{
public ViewFactory getViewFactory()
{
return new JPRTFViewFactory();
}
}
private static class JPRTFViewFactory implements ViewFactory
{
public View create(Element elem)
{
String kind = elem.getName();
if (kind != null)
if (kind.equals(AbstractDocument.ContentElementName))
{
return new LabelView(elem);
}
else if (kind.equals(AbstractDocument.ParagraphElementName))
{
return new JPParagraphView(elem);
}
else if (kind.equals(AbstractDocument.SectionElementName))
{
return new BoxView(elem, View.Y_AXIS);
}
else if (kind.equals(StyleConstants.ComponentElementName))
{
return new ComponentView(elem);
}
else if (kind.equals(StyleConstants.IconElementName))
{
return new IconView(elem);
}
// default to text display
return new LabelView(elem);
}
}
private static short paraRightMargin = 0;
static class JPParagraphView extends javax.swing.text.ParagraphView
{
public JPParagraphView(Element e)
{
super(e);
this.setInsets((short) 0, (short) 0, (short) 0, paraRightMargin);
}
}
// Code to ensure that the article word-wraps ends here
// - contributed by Michael Labhard
//This one listens for edits that can be undone.
public void undoableEditHappened(UndoableEditEvent e) {
// System.out.println("Undoable event is " +
// (e.getEdit().isSignificant()?"":"NOT ") + "significant");
// System.out.println("Undoable event source: " + e.getEdit());
// Remember the edit and update the menus.
if(!editLocked) {
// System.out.println("Storing undoable event for node " +
// getCurrentNode().getTitle());
// System.out.println(" Event is " +
// e.getEdit().getPresentationName() );
// if(getCurrentNode().lastEditStyle !=
// e.getEdit().getPresentationName()){
// System.out.println(" This is a SIGNIFICANT change.");
// }
// System.out.println(" Content: " + getCurrentNode().getContent());
// System.out.println(" Node undoMgr: " + getCurrentNode().undoMgr);
// Thread.currentThread().dumpStack();
article.getUndoMgr().addEdit(e.getEdit());
}
// undoAction.updateUndoState();
// redoAction.updateRedoState();
}
}