/* ******************************************************************************
*
* Copyright 2008-2010 Hans Dijkema
*
* JRichTextEditor is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* JRichTextEditor 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JRichTextEditor. If not, see <http://www.gnu.org/licenses/>.
*
* ******************************************************************************/
package nl.dykema.jxmlnote;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyleConstants;
import javax.swing.undo.UndoManager;
import nl.dykema.jxmlnote.document.XMLNoteDocument;
import nl.dykema.jxmlnote.document.XMLNoteMark;
import nl.dykema.jxmlnote.events.JXMLNoteEditorActionListener;
import nl.dykema.jxmlnote.exceptions.BadStyleException;
import nl.dykema.jxmlnote.exceptions.MarkExistsException;
import nl.dykema.jxmlnote.exceptions.MarkNoExistException;
import nl.dykema.jxmlnote.exceptions.NoSelectionException;
import nl.dykema.jxmlnote.exceptions.NoStyleException;
import nl.dykema.jxmlnote.interfaces.MarkMarkupProviderMaker;
import nl.dykema.jxmlnote.internationalization.DefaultXMLNoteTranslator;
import nl.dykema.jxmlnote.internationalization.XMLNoteTranslator;
import nl.dykema.jxmlnote.toolbar.JXMLNoteToolBar;
import nl.dykema.jxmlnote.toolbar.JXMLNoteToolBarReflect;
import nl.dykema.jxmlnote.undo.XMLNoteUndoManager;
import nl.dykema.jxmlnote.utils.JXMLNoteConstants;
import nl.dykema.jxmlnote.widgets.JXMLNotePane;
import nl.dykema.jxmlnote.widgets.JXMLNoteRuler;
import nl.dykema.jxmlnote.widgets.marks.DefaultMarkMarkupProviderMaker;
public class JXMLNoteEditor extends JScrollPane implements ActionListener {
/**
* Versie
*/
private static final long serialVersionUID = 1L;
private XMLNoteTranslator _tr;
private JXMLNotePane _notePane;
private JXMLNoteToolBar _toolbar;
private JXMLNoteRuler _ruler;
private JXMLNoteToolBarReflect _reflecter;
// Actions
public void actionPerformed(ActionEvent e) {
try {
String cmd=e.getActionCommand();
//System.out.println("Command:"+cmd);
if (cmd.startsWith("style:")) {
String styleId=cmd.substring(6);
pane().applyStyle(styleId);
} else if (cmd.equals("font-bold")) {
pane().applyBold();
} else if (cmd.equals("font-italic")) {
pane().applyItalic();
} else if (cmd.equals("font-underline")) {
pane().applyUnderline();
} else if (cmd.equals("align-left")) {
pane().applyAlign(StyleConstants.ALIGN_LEFT);
} else if (cmd.equals("align-right")) {
pane().applyAlign(StyleConstants.ALIGN_RIGHT);
} else if (cmd.equals("align-center")) {
pane().applyAlign(StyleConstants.ALIGN_CENTER);
} else if (cmd.equals("align-justify")) {
pane().applyAlign(StyleConstants.ALIGN_JUSTIFIED);
} else if (cmd.equals("undo")) {
UndoManager m=pane().getXMLNoteDoc().getUndoManager();
if (m.canUndo()) { pane().getXMLNoteDoc().getUndoManager().undo(); }
} else if (cmd.equals("redo")) {
UndoManager m=pane().getXMLNoteDoc().getUndoManager();
if (m.canRedo()) { pane().getXMLNoteDoc().getUndoManager().redo(); }
} else if (cmd.equals("copy-to-clipboard")) {
pane().copy();
} else if (cmd.equals("cut-to-clipboard")) {
pane().cut();
} else if (cmd.equals("paste-from-clipboard")) {
pane().paste();
} else if (cmd.equals("select-all")) {
pane().selectAll();
} else if (cmd.equals("indent-more")) {
pane().indentMore(JXMLNoteConstants.getStandardIndentPoints());
} else if (cmd.equals("indent-less")) {
pane().indentLess(JXMLNoteConstants.getStandardIndentPoints());
} else if (cmd.startsWith("zoom")) {
Pattern p=Pattern.compile("[0-9]+");
Matcher m=p.matcher(cmd);
if (m.find()) {
String zoom=m.group();
double zfactor=Double.parseDouble(zoom)/100.0;
pane().setZoomFactor(zfactor);
}
} else if (cmd.equals("set-zoom")) {
String result=JOptionPane.showInputDialog(pane(), _tr._("Give a zoom factor (in %)"), "Zooming", JOptionPane.QUESTION_MESSAGE);
if (result!=null) {
Pattern p=Pattern.compile("[0-9]+");
Matcher m=p.matcher(result);
if (m.find()) {
String zoom=m.group();
double zfactor=Double.parseDouble(zoom)/100.0;
if (zfactor<0.1) { zfactor=0.1; }
else if (zfactor>5.0) { zfactor=5.0; }
pane().setZoomFactor(zfactor);
}
}
}
} catch (NoStyleException e1) {
e1.printStackTrace();
} catch (NoSelectionException e1) {
e1.printStackTrace();
} catch (BadLocationException e1) {
e1.printStackTrace();
} catch (BadStyleException e1) {
e1.printStackTrace();
}
}
// toolbar state
private void updateToolbarState() {
//System.out.println("updatetoolbarstate");
UndoManager m=pane().getXMLNoteDoc().getUndoManager();
_toolbar.enable("@edit","undo",m.canUndo());
_toolbar.enable("@edit","redo",m.canRedo());
}
// Getters, Setters
/**
* @return Returns the toolbar widget associated with this editor
*/
public JXMLNoteToolBar toolbar() {
return _toolbar;
}
/**
* @return Returns the document associated with this editor
*/
public XMLNoteDocument document() {
return pane().getXMLNoteDoc();
}
/**
* @return Returns the XMLNote editor pane (outside the scrollpane).
*/
public JXMLNotePane pane() {
return _notePane;
}
/**
* Proxy for pane().setDocument().
* @param d
*/
public void setDocument(XMLNoteDocument d) {
pane().setDocument(d);
}
/**
* Proxy for pane().getXMLNoteDoc().
* @return
*/
public XMLNoteDocument getDocument() {
return pane().getXMLNoteDoc();
}
/**
* Proxy for pane().getCaretPosition()
* @return
*/
public int getCaretPosition() {
return pane().getCaretPosition();
}
/**
* Proxy for pane().setCaretPosition()
* @param offset
*/
public void setCaretPosition(int offset) {
pane().setCaretPosition(offset);
}
/**
* Proxy for pane().setCaretPositionHome()
*/
public void setCaretPositionHome() {
pane().setCaretPositionHome();
}
/**
* Proxy for pane().getSelectionStart()
* @return the start of a selection on pane().
*/
public int getSelectionStart() {
return pane().getSelectionStart();
}
/**
* Proxy for pane().getSelectionEnd()
* @return the end of a selection on pane().
*/
public int getSelectionEnd() {
return pane().getSelectionEnd();
}
/**
* Proxy for pane().getPositionForOffset()
* @param offset
* @return
* @throws BadLocationException
*/
public Point getPositionForOffset(int offset) throws BadLocationException {
return pane().getPositionForOffset(offset);
}
/**
* Sets the responsiveness of the editor to commands. If the editor is unresponsive,
* it won't accept edits.
*
* @param a
*/
public void setUnresponsive(boolean a) {
_notePane.setEditable(!a);
}
/********************************************************************************************
* Marks and Marker markup
********************************************************************************************/
/**
* Proxy for pane().setMarkMarkupProviderMaker()
*
* @param m
*/
public void setMarkMarkupProviderMaker(MarkMarkupProviderMaker m) {
pane().setMarkMarkupProviderMaker(m);
}
/**
* Proxy for pane().getMarkMarkupProviderMaker()
*
* @return The associated MarkMarkupProviderMaker.
*/
public MarkMarkupProviderMaker getMarkMarkupProviderMaker() {
return pane().getMarkMarkupProviderMaker();
}
/**
* Proxy for {@link nl.dykema.jxmlnote.widgets.JXMLNotePane#getMarksForSelection pane().getMarksForSelection()}
*
* @throws NoSelectionException
* @return
*/
public Vector<XMLNoteMark> getMarksForSelection() throws NoSelectionException {
return pane().getMarksForSelection();
}
/**
* Proxy for {@link nl.dykema.jxmlnote.widgets.JXMLNotePane#getMarksForCaret() pane().getMarksForCaret()}.
*
* @return
*/
public Vector<XMLNoteMark> getMarksForCaret() {
return pane().getMarksForCaret();
}
/**
* Proxy for {@link nl.dykema.jxmlnote.widgets.JXMLNotePane#getMarksContainedInSelection() pane().getMarksContainedInSelection()}.
* @return
* @throws NoSelectionException
*/
public Vector<XMLNoteMark> getMarksContainedInSelection() throws NoSelectionException {
return pane().getMarksContainedInSelection();
}
/**
* Proxy for {@link nl.dykema.jxmlnote.widgets.JXMLNotePane#insertMark(String) pane().insertMark()}.
* @param id The id of the mark
* @param _class The class of the mark
* @return
* @throws MarkExistsException
* @throws NoSelectionException
* @throws BadLocationException
*/
public boolean insertMark(String id,String _class) throws MarkExistsException, NoSelectionException, BadLocationException {
return pane().insertMark(id,_class);
}
/**
*
* Proxy for {@link nl.dykema.jxmlnote.widgets.JXMLNotePane#insertMark(String) pane().insertMark()}.
* @param id The id of the mark
* @param _class The class of the mark
* @param offset The offset in the text
* @param length The length of the mark
* @return
* @throws MarkExistsException
* @throws NoSelectionException
* @throws BadLocationException
*/
public boolean insertMark(String id,String _class,int offset,int length)
throws MarkExistsException, NoSelectionException, BadLocationException {
return pane().insertMark(id, _class, offset, length);
}
/**
* Proxy for {@link nl.dykema.jxmlnote.widgets.JXMLNotePane#removeMark(String) pane().removeMark()}.
* @param id
* @return
* @throws MarkNoExistException
*/
public boolean removeMark(String id) throws MarkNoExistException {
return pane().removeMark(id);
}
/********************************************************************************************
* Reflect changes for the current caret position in the toolbar
********************************************************************************************/
/**
* Reflects the style under the caret position in the toolbar
*/
public void reflectCaretInToolbar() {
_reflecter.reflect(document(), getCaretPosition());
}
/********************************************************************************************
* Other stuff
********************************************************************************************/
/**
* Sets the {@link nl.dykema.jxmlnote.widgets.JXMLNotePane#setComponentPopupMenu(JPopupMenu) popup menu for XMLNotePane} .
*/
public void setPopupMenu(JPopupMenu m) {
pane().setComponentPopupMenu(m);
}
/**
* Proxy for {@link nl.dykema.jxmlnote.widgets.JXMLNotePane#selectionSize() JXMLNotePane.selectionSize()}.
* @return
*/
public int selectionSize() {
return pane().selectionSize();
}
/********************************************************************************************
* initialization
********************************************************************************************/
private void init(XMLNoteDocument doc,boolean addRuler,ActionListener ll) {
_tr=new DefaultXMLNoteTranslator();
// get the text pane
JViewport v=(JViewport) super.getComponent(0);
_notePane=(JXMLNotePane) v.getComponent(0);
// toolbar and actions and reflecter
_toolbar=new JXMLNoteToolBar(ll,pane().getXMLNoteDoc().getStyles());
_reflecter=new JXMLNoteToolBarReflect(_toolbar);
_notePane.addCaretListener(new CaretListener() {
public void caretUpdate(CaretEvent e) {
reflectCaretInToolbar();
}
});
// Undo/Redo
//KeyStroke ctrlz=KeyStroke.getKeyStroke(KeyEvent.VK_Z,KeyEvent.CTRL_MASK);
//_toolbar.setAccelerator("@edit","undo",ctrlz);
//KeyStroke ctrly=KeyStroke.getKeyStroke(KeyEvent.VK_Z,KeyEvent.CTRL_MASK);
//_toolbar.setAccelerator("@edit","redo",ctrly);
/*
* KEYSTROKES ARE PART OF THE KEYMAP OF JXMLNotePane
// Copy/Paste/Cut
KeyStroke ctrlv=KeyStroke.getKeyStroke(KeyEvent.VK_V,KeyEvent.CTRL_MASK);
_toolbar.setAccelerator(JXMLNoteToolBar.SECTION_EDIT,JXMLNoteToolBar.ACTION_PASTE,ctrlv);
KeyStroke ctrlc=KeyStroke.getKeyStroke(KeyEvent.VK_C,KeyEvent.CTRL_MASK);
_toolbar.setAccelerator(JXMLNoteToolBar.SECTION_EDIT,JXMLNoteToolBar.ACTION_COPY, ctrlc);
KeyStroke ctrlx=KeyStroke.getKeyStroke(KeyEvent.VK_X,KeyEvent.CTRL_MASK);
_toolbar.setAccelerator(JXMLNoteToolBar.SECTION_EDIT,JXMLNoteToolBar.ACTION_CUT,ctrlx);
KeyStroke ctrla=KeyStroke.getKeyStroke(KeyEvent.VK_A,KeyEvent.CTRL_MASK);
_toolbar.setAccelerator(JXMLNoteToolBar.SECTION_EDIT,JXMLNoteToolBar.ACTION_SELECT_ALL,ctrla);
// bold, italic, underline
KeyStroke ctrlb=KeyStroke.getKeyStroke(KeyEvent.VK_B,KeyEvent.CTRL_MASK);
_toolbar.setAccelerator(JXMLNoteToolBar.SECTION_CHARSTYLE,JXMLNoteToolBar.ACTION_BOLD,ctrlb);
KeyStroke ctrli=KeyStroke.getKeyStroke(KeyEvent.VK_I,KeyEvent.CTRL_MASK);
_toolbar.setAccelerator(JXMLNoteToolBar.SECTION_CHARSTYLE,JXMLNoteToolBar.ACTION_ITALIC, ctrli);
KeyStroke ctrlu=KeyStroke.getKeyStroke(KeyEvent.VK_U,KeyEvent.CTRL_MASK);
_toolbar.setAccelerator(JXMLNoteToolBar.SECTION_CHARSTYLE,JXMLNoteToolBar.ACTION_UNDERLINE,ctrlu);
*/
// Ruler
if (addRuler) {
_ruler=new JXMLNoteRuler(_notePane.textPane());
super.setColumnHeaderView(_ruler);
}
// Get notified when the state of the undo manager changes
pane().getXMLNoteDoc().getUndoManager().addStateUpdater(new XMLNoteUndoManager.StateUpdater() {
public void update(XMLNoteUndoManager m) {
updateToolbarState();
}
});
}
/**
* Constructs a new JXMLNoteEditor with given document and a DefaultMarkMarkupProviderMaker.
* @param doc
*/
public JXMLNoteEditor(XMLNoteDocument doc) {
this(doc,new DefaultMarkMarkupProviderMaker(),true);
}
/**
* Constructs a new JXMLNoteEditor with given document and a DefaultMarkMarkupProviderMaker and controls whether a ruler
* is created or not.
* @param doc
*/
public JXMLNoteEditor(XMLNoteDocument doc,boolean createRuler) {
this(doc,new DefaultMarkMarkupProviderMaker(),createRuler);
}
/**
* Constructs a new JXMLNoteEditor with given document and MarkMarkupProviderMaker.
* @param doc
* @param maker
*/
public JXMLNoteEditor(XMLNoteDocument doc,MarkMarkupProviderMaker maker) {
this(doc,maker,true);
}
/**
* Contructs a new JXMLNoteEditor with given document, MarkMarkupProviderMaker and controls whether a ruler
* is created or not.
* @param doc
* @param maker
* @param createRuler
*/
public JXMLNoteEditor(XMLNoteDocument doc,MarkMarkupProviderMaker maker,boolean createRuler) {
this(new JXMLNoteEditorActionListener(),doc,maker,createRuler);
}
protected JXMLNoteEditor(JXMLNoteEditorActionListener l,XMLNoteDocument doc,MarkMarkupProviderMaker maker,boolean createRuler) {
super(new JXMLNotePane(doc,maker,l),ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
l.setMe(this);
init(doc,createRuler,l);
}
}