/*
* Created on Nov 7, 2007
*/
package net.sf.thingamablog.gui.editor;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.undo.UndoManager;
import net.atlanticbb.tantlinger.i18n.I18n;
import net.atlanticbb.tantlinger.ui.UIUtils;
import net.atlanticbb.tantlinger.ui.text.CompoundUndoManager;
import net.atlanticbb.tantlinger.ui.text.IndentationFilter;
import net.atlanticbb.tantlinger.ui.text.SourceCodeEditor;
import net.atlanticbb.tantlinger.ui.text.actions.FindReplaceAction;
import net.atlanticbb.tantlinger.ui.text.actions.HTMLEditorActionFactory;
import net.atlanticbb.tantlinger.ui.text.actions.HTMLFontAction;
import net.atlanticbb.tantlinger.ui.text.actions.HTMLFontColorAction;
import net.atlanticbb.tantlinger.ui.text.actions.HTMLInlineAction;
import net.atlanticbb.tantlinger.ui.text.actions.HTMLTextEditAction;
import net.sf.thingamablog.TBGlobals;
import net.sf.thingamablog.blog.Template;
import net.sf.thingamablog.gui.TBAbout;
import net.sf.thingamablog.gui.TBHelpAction;
import novaworx.syntax.SyntaxFactory;
import novaworx.textpane.SyntaxDocument;
import novaworx.textpane.SyntaxGutter;
import novaworx.textpane.SyntaxGutterBase;
import org.bushe.swing.action.ActionList;
import org.bushe.swing.action.ActionUIFactory;
/**
* @author Bob Tantlinger
*
*/
public class HTMLEditor extends JFrame
{
/**
*
*/
private static final long serialVersionUID = 1L;
private static final I18n i18n = I18n.getInstance("net.sf.thingamablog.gui.editor");
public static final int TEMPLATE_MODE = 1;
public static final int FILE_MODE = 2;
private int mode = FILE_MODE;
private Template curTemplate;
private File curFile = new File(System.getProperty("user.home"), "editor.txt"); //$NON-NLS-1$ //$NON-NLS-2$
private SourceCodeEditor editor;
private File lastDir = new File(System.getProperty("user.home")); //$NON-NLS-1$
private Action openAction, saveAction;
private boolean isTextChanged;
private String syntax = "html";
private ActionList actionList;
private JMenuBar menuBar;
private JToolBar toolBar;
private JPopupMenu popupMenu;
public HTMLEditor(Template tmp)
{
super(i18n.str("template_editor") + " [" + tmp.getName() + "]");
curTemplate = tmp;
mode = TEMPLATE_MODE;
syntax = "html";
init();
}
public HTMLEditor(File f)
{
if(f != null)
setTitle(f.getName());
curFile = f;
mode = FILE_MODE;
syntax = "html";
int dot = curFile.getName().lastIndexOf('.');
if(dot != -1 && dot != curFile.getName().length() - 1);
{
syntax = curFile.getName().substring(dot + 1, curFile.getName().length());
}
init();
}
public HTMLEditor(String title)
{
super(title);
mode = FILE_MODE;
syntax = "html";
init();
}
private void init()
{
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
closeEditor();
}
});
setIconImage(UIUtils.getIcon(UIUtils.X16, "tamb.png").getImage());
editor = new SourceCodeEditor();
editor.setFont(TBGlobals.getEditorFont());
editor.addCaretListener(new CaretListener()
{
public void caretUpdate(CaretEvent e)
{
actionList.putContextValueForAll(HTMLTextEditAction.EDITOR, editor);
//actionList.updateEnabledForAll();
}
});
editor.addMouseListener(new PopupHandler());
JScrollPane scrollPane = new JScrollPane(editor);
SyntaxGutter gutter = new SyntaxGutter(editor);
SyntaxGutterBase gutterBase = new SyntaxGutterBase(gutter);
scrollPane.setRowHeaderView(gutter);
scrollPane.setCorner(ScrollPaneConstants.LOWER_LEFT_CORNER, gutterBase);
initActions();
setJMenuBar(menuBar);
getContentPane().add(toolBar, BorderLayout.NORTH);
getContentPane().add(scrollPane, BorderLayout.CENTER);
load();
int w = 640, h = 480;
try
{
w = Integer.parseInt(TBGlobals.getProperty("SRC_EDITOR_WIDTH"));
h = Integer.parseInt(TBGlobals.getProperty("SRC_EDITOR_HEIGHT"));
}
catch(Exception ex){}
setSize(w, h);
actionList.putContextValueForAll(HTMLTextEditAction.EDITOR, editor);
actionList.updateEnabledForAll();
}
public void setVisible(boolean b)
{
if(b)
{
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int x = ((d.width - getSize().width) / 2);
int y = ((d.height - getSize().height) / 2);
setLocation(x, y);
super.setVisible(true);
}
else
super.setVisible(false);
}
private void closeEditor()
{
if(isTextChanged)
{
int r = JOptionPane.showConfirmDialog(this,
i18n.str("save_changes_prompt"), i18n.str("text_changed"), //$NON-NLS-1$ //$NON-NLS-2$
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if(r == JOptionPane.CANCEL_OPTION)
return;
if(r == JOptionPane.YES_OPTION)
{
save();
}
}
TBGlobals.putProperty("SRC_EDITOR_WIDTH", getWidth()+"");
TBGlobals.putProperty("SRC_EDITOR_HEIGHT", getHeight()+"");
dispose();
}
private void initActions()
{
actionList = new ActionList("HTMLEditorActions");
menuBar = new JMenuBar();
toolBar = new JToolBar();
toolBar.setFloatable(false);
openAction = new OpenAction();
saveAction = new SaveAction();
saveAction.setEnabled(false);
JMenuItem close = new JMenuItem(i18n.str("close")); //$NON-NLS-1$
close.setMnemonic(i18n.mnem("close"));
close.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
closeEditor();
}
});
JMenu fileMenu = new JMenu(i18n.str("file")); //$NON-NLS-1$
fileMenu.setMnemonic(i18n.mnem("file"));
fileMenu.add(openAction);
UIUtils.addToolBarButton(toolBar, openAction);//toolBar.add(openAction);
fileMenu.add(saveAction);
UIUtils.addToolBarButton(toolBar, saveAction);//toolBar.add(saveAction);
toolBar.addSeparator();
fileMenu.addSeparator();
fileMenu.add(close);
actionList.add(openAction);
actionList.add(saveAction);
menuBar.add(fileMenu);
ActionList lst = HTMLEditorActionFactory.createEditActionList();
popupMenu = ActionUIFactory.getInstance().createPopupMenu(lst);
ActionList tbEditActions = new ActionList("tbEditActions");
tbEditActions.addAll(lst);
tbEditActions.remove(tbEditActions.size() - 1); //remove selectAll action
tbEditActions.remove(tbEditActions.size() - 1); //remove separator
tbEditActions.remove(tbEditActions.size() - 1); //remove paste formatted
tbEditActions.add(null); //add separator
addToToolBar(tbEditActions);
lst.add(null);
Action act = new HTMLInlineAction(HTMLInlineAction.BOLD);
actionList.add(act);
UIUtils.addToolBarButton(toolBar, new JButton(act));//toolBar.add(act);
act = new HTMLInlineAction(HTMLInlineAction.ITALIC);
actionList.add(act);
UIUtils.addToolBarButton(toolBar, new JButton(act));//toolBar.add(act);
act = new HTMLInlineAction(HTMLInlineAction.UNDERLINE);
actionList.add(act);
UIUtils.addToolBarButton(toolBar, new JButton(act));//toolBar.add(act);
toolBar.addSeparator();
lst.add(new FindReplaceAction(false));
actionList.addAll(lst);
JMenu editMenu = ActionUIFactory.getInstance().createMenu(lst);
editMenu.setText(i18n.str("edit"));
editMenu.setMnemonic(i18n.mnem("edit"));
menuBar.add(editMenu);
// create format menu
JMenu formatMenu = new JMenu(i18n.str("format"));
formatMenu.setMnemonic(i18n.mnem("format"));
lst = HTMLEditorActionFactory.createFontSizeActionList();//HTMLEditorActionFactory.createInlineActionList();
actionList.addAll(lst);
formatMenu.add(createMenu(lst, i18n.str("size")));
lst = HTMLEditorActionFactory.createInlineActionList();
actionList.addAll(lst);
formatMenu.add(createMenu(lst, i18n.str("style")));
act = new HTMLFontColorAction();
actionList.add(act);
formatMenu.add(act);
act = new HTMLFontAction();
actionList.add(act);
formatMenu.add(act);
lst = HTMLEditorActionFactory.createBlockElementActionList();
actionList.addAll(lst);
formatMenu.add(createMenu(lst, i18n.str("paragraph")));
lst = HTMLEditorActionFactory.createListElementActionList();
actionList.addAll(lst);
addToToolBar(lst);
toolBar.addSeparator();
formatMenu.add(createMenu(lst, i18n.str("list")));
formatMenu.addSeparator();
lst = HTMLEditorActionFactory.createAlignActionList();
actionList.addAll(lst);
addToToolBar(lst);
toolBar.addSeparator();
formatMenu.add(createMenu(lst, i18n.str("align")));
menuBar.add(formatMenu);
lst = HTMLEditorActionFactory.createInsertActionList();
actionList.addAll(lst);
JMenu insertMenu = ActionUIFactory.getInstance().createMenu(lst);
insertMenu.setText(i18n.str("insert")); //$NON-NLS-1$
menuBar.add(insertMenu);
insertMenu.setMnemonic(i18n.mnem("insert"));
addToToolBar(lst);
JMenu helpMenu = new JMenu(i18n.str("help"));
helpMenu.setMnemonic(i18n.mnem("help"));
Action help = new TBHelpAction(
i18n.str("help_contents_"), "ch03.item5");
help.putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "help.png"));
help.putValue(Action.MNEMONIC_KEY, new Integer(i18n.mnem("help_contents_")));
help.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0));
helpMenu.add(help);
JMenuItem aboutItem = new JMenuItem(i18n.str("about_"));
aboutItem.setMnemonic(i18n.mnem("about_"));
aboutItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
TBAbout.showAboutBox(HTMLEditor.this);
}
});
helpMenu.add(aboutItem);
menuBar.add(helpMenu);
}
private JMenu createMenu(ActionList lst, String menuName)
{
JMenu m = ActionUIFactory.getInstance().createMenu(lst);
m.setText(menuName);
return m;
}
private void addToToolBar(List al)
{
for(Iterator it = al.iterator(); it.hasNext();)
{
Action a = (Action)it.next();
if(a == null)
toolBar.addSeparator();
else
{
JButton button = new JButton(a);
button.setToolTipText((String)button.getAction().getValue(Action.NAME));
Icon ico = button.getIcon();
if(ico != null)
{
button.setText(null);
button.setMnemonic(0);
button.putClientProperty("hideActionText", Boolean.TRUE);
int square = Math.max(ico.getIconWidth(), ico.getIconHeight()) + 6;
Dimension size = new Dimension(square, square);
button.setPreferredSize(size);
}
toolBar.add(button);
}
}
}
private void load()
{
CompoundUndoManager.discardAllEdits(editor.getDocument());
SyntaxDocument doc = new SyntaxDocument();
doc.setSyntax(SyntaxFactory.getSyntax(syntax));
CompoundUndoManager cuh = new CompoundUndoManager(doc, new UndoManager());
doc.addUndoableEditListener(cuh);
doc.setDocumentFilter(new IndentationFilter());
editor.setDocument(doc);
try
{
if(mode == TEMPLATE_MODE)
{
editor.setText(curTemplate.load());
isTextChanged = true;
}
else
{
editor.setText(readFile(curFile));
}
}
catch(Exception ioe)
{
UIUtils.showError(this, ioe);
}
CompoundUndoManager.discardAllEdits(doc);
editor.setCaretPosition(0);
isTextChanged = false;
saveAction.setEnabled(isTextChanged);
doc.addDocumentListener(new TextChangeListener());
}
private String readFile(File f) throws IOException
{
StringBuffer sb = new StringBuffer((int)f.length());
BufferedReader reader = new BufferedReader(new FileReader(f));
String line = null;
while((line = reader.readLine()) != null)
{
sb.append(line);
sb.append('\n');
}
reader.close();
return sb.toString();
}
private void openFile()
{
JFileChooser fc = new JFileChooser(lastDir);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
int r = fc.showOpenDialog(HTMLEditor.this);
if(r == JFileChooser.CANCEL_OPTION)
return;
File f = fc.getSelectedFile();
if(f == null)
return;
try
{
String text = readFile(f);
editor.setText(text);
editor.setCaretPosition(0);
CompoundUndoManager.discardAllEdits(editor.getDocument());
lastDir = new File(f.getParent());
isTextChanged = false;
saveAction.setEnabled(true);
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
private void save()
{
try
{
if(mode == TEMPLATE_MODE)
curTemplate.save(editor.getText());
else
{
Writer writer = new FileWriter(curFile);
editor.write(writer);
writer.close();
}
saveAction.setEnabled(false);
isTextChanged = false;
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
private class TextChangeListener implements DocumentListener
{
public void insertUpdate(DocumentEvent e)
{
isTextChanged = true;
saveAction.setEnabled(true);
}
public void removeUpdate(DocumentEvent e)
{
isTextChanged = true;
saveAction.setEnabled(true);
}
public void changedUpdate(DocumentEvent e)
{
}
}
private class OpenAction extends AbstractAction
{
/**
*
*/
private static final long serialVersionUID = 1L;
public OpenAction()
{
super(i18n.str("open_"), UIUtils.getIcon(UIUtils.X16, "export.png")); //$NON-NLS-1$ //$NON-NLS-2$
putValue(ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_O, Event.CTRL_MASK));
}
public void actionPerformed(ActionEvent e)
{
openFile();
}
}
private class SaveAction extends AbstractAction
{
/**
*
*/
private static final long serialVersionUID = 1L;
public SaveAction()
{
super(i18n.str("save"), UIUtils.getIcon(UIUtils.X16, "save.png")); //$NON-NLS-1$ //$NON-NLS-2$
putValue(ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_S, Event.CTRL_MASK));
}
public void actionPerformed(ActionEvent e)
{
save();
}
}
private class PopupHandler extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{ checkForPopupTrigger(e); }
public void mouseReleased(MouseEvent e)
{ checkForPopupTrigger(e); }
private void checkForPopupTrigger(MouseEvent e)
{
if(e.isPopupTrigger())
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
}