package menalea;
import java.awt.Component;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.util.prefs.Preferences;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
@SuppressWarnings("serial")
public class MTextArea extends JTextArea {
private final static float MIN_FONT_SIZE = 10f,
MAX_FONT_SIZE = 50f,
ZOOM_SPEED = 0.10f;
private final MessageBundle msgs;
public final UndoAction undoAction;
public final RedoAction redoAction;
public final AbstractAction cutAction, copyAction, pasteAction,
searchAction, selectAllAction,
boldAction, italicAction, strikethroughAction, headingAction;
private final UndoManager undoManager = new UndoManager();
private final Preferences preferences;
private final SearchDialog searchDialog;
public MTextArea(MainWindow mainWindow, MessageBundle msgs) {
this.msgs = msgs;
preferences = Preferences.userNodeForPackage(getClass());
undoAction = new UndoAction();
redoAction = new RedoAction();
cutAction = new CutAction();
copyAction = new CopyAction();
pasteAction = new PasteAction();
searchAction = new SearchAction();
selectAllAction = new SelectAllAction();
boldAction = new BoldAction();
italicAction = new ItalicAction();
strikethroughAction = new StrikethroughAction();
headingAction = new HeadingAction();
getDocument().addUndoableEditListener(new UndoableEditListener() {
@Override
public void undoableEditHappened(UndoableEditEvent e) {
undoManager.addEdit(e.getEdit());
undoAction.updateUndoState();
redoAction.updateRedoState();
}
});
float fontSize = preferences.getFloat(Main.FONT_SIZE_KEY,
Main.DEFAULT_FONT_SIZE);
Font font = new Font(
Font.SANS_SERIF, Font.PLAIN, Main.DEFAULT_FONT_SIZE);
font = font.deriveFont(fontSize);
setFont(font);
searchDialog = new SearchDialog(mainWindow, this);
}
public float getFontSize() {
return getFont().getSize2D();
}
public void setFontSize(float size) {
setFont(getFont().deriveFont(size));
preferences.putFloat(Main.FONT_SIZE_KEY, size);
}
public void zoomIn() {
float fontSize = getFontSize();
if (fontSize < MAX_FONT_SIZE)
setFontSize(fontSize *= 1 + ZOOM_SPEED);
}
public void zoomOut() {
float fontSize = getFontSize();
if (fontSize > MIN_FONT_SIZE)
setFontSize(fontSize *= 1 - ZOOM_SPEED);
}
public void surroundSelection(String prefix, String suffix) {
AbstractDocument document = (AbstractDocument) getDocument();
String selection = getSelectedText();
if (selection == null)
selection = "";
try {
document.replace(getSelectionStart(),
selection.length(),
prefix + selection + suffix,
null);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
public void discardAllEdits() {
undoManager.discardAllEdits();
undoAction.updateUndoState();
redoAction.updateRedoState();
}
///////////////////////////////////////////////////////////////////////////
private class UndoAction extends MAction {
public UndoAction() {
super(msgs.get(Message.menuEditUndo),
KeyStroke.getKeyStroke("control Z"),
Tools.getPNGIcon("edit-undo"));
setEnabled(false);
}
@Override
public void actionPerformed(ActionEvent e) {
try {
undoManager.undo();
} catch (CannotUndoException ex) {
System.out.println("Impossible de d’annuler : " + ex);
ex.printStackTrace();
}
updateUndoState();
redoAction.updateRedoState();
requestFocusInWindow();
}
void updateUndoState() {
if (undoManager.canUndo()) {
setEnabled(true);
} else {
setEnabled(false);
}
}
}
private class RedoAction extends MAction {
public RedoAction() {
super(msgs.get(Message.menuEditRedo),
KeyStroke.getKeyStroke("shift control Z"),
Tools.getPNGIcon("edit-redo"));
setEnabled(false);
}
@Override
public void actionPerformed(ActionEvent e) {
try {
undoManager.redo();
} catch (CannotRedoException ex) {
System.out.println("Impossible de rétablir : " + ex);
ex.printStackTrace();
}
updateRedoState();
undoAction.updateUndoState();
requestFocusInWindow();
}
void updateRedoState() {
if (undoManager.canRedo()) {
setEnabled(true);
} else {
setEnabled(false);
}
}
}
///////////////////////////////////////////////////////////////////////////
private class CutAction extends MAction {
public CutAction() {
super(msgs.get(Message.menuEditCut),
KeyStroke.getKeyStroke("control X"),
Tools.getPNGIcon("edit-cut"));
}
@Override
public void actionPerformed(ActionEvent e) {
Action a = new DefaultEditorKit.CutAction();
a.actionPerformed(null);
requestFocusInWindow();
}
}
private class CopyAction extends MAction {
public CopyAction() {
super(msgs.get(Message.menuEditCopy),
KeyStroke.getKeyStroke("control C"),
Tools.getPNGIcon("edit-copy"));
}
@Override
public void actionPerformed(ActionEvent e) {
Action a = new DefaultEditorKit.CopyAction();
a.actionPerformed(null);
requestFocusInWindow();
}
}
private class PasteAction extends MAction {
public PasteAction() {
super(msgs.get(Message.menuEditPaste),
KeyStroke.getKeyStroke("control V"),
Tools.getPNGIcon("edit-paste"));
}
@Override
public void actionPerformed(ActionEvent e) {
Action a = new DefaultEditorKit.PasteAction();
a.actionPerformed(null);
requestFocusInWindow();
}
}
private class SelectAllAction extends MAction {
public SelectAllAction() {
super(msgs.get(Message.menuEditSelectAll),
KeyStroke.getKeyStroke("control A"),
Tools.getPNGIcon("edit-select-all"));
}
@Override
public void actionPerformed(ActionEvent e) {
selectAll();
requestFocusInWindow();
}
}
private class BoldAction extends MAction {
public BoldAction() {
super(msgs.get(Message.menuFormatBold),
KeyStroke.getKeyStroke("control G"),
Tools.getPNGIcon("format-text-bold"));
}
@Override
public void actionPerformed(ActionEvent e) {
surroundSelection("**", "**");
requestFocusInWindow();
}
}
private class ItalicAction extends MAction {
public ItalicAction() {
super(msgs.get(Message.menuFormatItalic),
KeyStroke.getKeyStroke("control I"),
Tools.getPNGIcon("format-text-italic"));
}
@Override
public void actionPerformed(ActionEvent e) {
surroundSelection("*", "*");
requestFocusInWindow();
}
}
private class StrikethroughAction extends MAction {
public StrikethroughAction() {
super(msgs.get(Message.menuFormatStrike),
Tools.getPNGIcon("format-text-strikethrough"));
}
@Override
public void actionPerformed(ActionEvent e) {
surroundSelection("~~", "~~");
requestFocusInWindow();
}
}
private class HeadingAction extends MAction {
public HeadingAction() {
super(msgs.get(Message.menuFormatHeading));
}
@Override
public void actionPerformed(ActionEvent e) {
Object r = JOptionPane.showInputDialog(
null,
msgs.get(Message.menuFormatHeadingDialogText),
"Menalea",
JOptionPane.QUESTION_MESSAGE,
null,
new Object[] {1, 2, 3, 4, 5, 6},
1);
if (r == null)
return;
Integer level = (Integer) r;
String prefix = "";
for (int i = 0; i < level; i++) {
prefix += "#";
}
surroundSelection(prefix + " ", " " + prefix);
requestFocusInWindow();
}
}
///////////////////////////////////////////////////////////////////////////
private class SearchAction extends MAction {
public SearchAction() {
super(msgs.get(Message.menuEditFindReplace),
KeyStroke.getKeyStroke("control F"),
Tools.getPNGIcon("edit-find-replace"));
}
@Override
public void actionPerformed(ActionEvent e) {
searchDialog.setVisible(true);
}
}
public static Window findWindow(Component c) {
if (c == null) {
return JOptionPane.getRootFrame();
} else if (c instanceof Window) {
return (Window) c;
} else {
return findWindow(c.getParent());
}
}
}