/** * Metaphase Editor - WYSIWYG HTML Editor Component * Copyright (C) 2010 Rudolf Visagie * Full text of license can be found in com/metaphaseeditor/LICENSE.txt * * This library 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. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * The author can be contacted at metaphase.editor@gmail.com. */ package com.metaphaseeditor; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Desktop; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.print.PrinterException; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Vector; import java.util.zip.ZipInputStream; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JColorChooser; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextPane; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; import javax.swing.text.Element; import javax.swing.text.MutableAttributeSet; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledEditorKit; import javax.swing.text.html.HTML; import javax.swing.text.html.HTML.Tag; import javax.swing.text.html.HTMLDocument; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import javax.swing.undo.UndoManager; import org.openflexo.swing.layout.WrapLayout; import org.openflexo.toolbox.HTMLUtils; import org.openflexo.toolbox.ImageIconResource; import com.metaphaseeditor.action.AddAttributesAction; import com.metaphaseeditor.action.ClearFormattingAction; import com.metaphaseeditor.action.DecreaseIndentAction; import com.metaphaseeditor.action.FindReplaceAction; import com.metaphaseeditor.action.FormatAction; import com.metaphaseeditor.action.IncreaseIndentAction; import com.metaphaseeditor.action.InsertHtmlAction; import com.metaphaseeditor.action.InsertTextAction; import com.metaphaseeditor.action.RemoveAttributesAction; import com.metaphaseeditor.action.UnlinkAction; import com.swabunga.spell.engine.SpellDictionary; import com.swabunga.spell.engine.SpellDictionaryHashMap; import com.swabunga.spell.swing.JTextComponentSpellChecker; /** * * @author Rudolf Visagie */ public class MetaphaseEditorPanel extends JPanel { public static final String SOURCE_PANEL_KEY = "SourcePanel"; public static final String SOURCE_BUTTON_KEY = "SourcePanel.SourceButton"; public static final String PAGE_PANEL_KEY = "PagePanel"; public static final String OPEN_BUTTON_KEY = "PagePanel.OpenButton"; public static final String SAVE_BUTTON_KEY = "PagePanel.SaveButton"; public static final String NEW_BUTTON_KEY = "PagePanel.NewButton"; public static final String PREVIEW_BUTTON_KEY = "PagePanel.PreviewButton"; public static final String EDIT_PANEL_KEY = "EditPanel"; public static final String CUT_BUTTON_KEY = "EditPanel.CutButton"; public static final String COPY_BUTTON_KEY = "EditPanel.CopyButton"; public static final String PASTE_BUTTON_KEY = "EditPanel.PasteButton"; public static final String PASTE_AS_TEXT_BUTTON_KEY = "EditPanel.PasteAsTextButton"; public static final String TOOLS_PANEL_KEY = "ToolsPanel"; public static final String PRINT_BUTTON_KEY = "ToolsPanel.PrintButton"; public static final String SPELL_CHECK_BUTTON_KEY = "ToolsPanel.SpellcheckButton"; public static final String UNDO_REDO_PANEL_KEY = "UndoRedoPanel"; public static final String UNDO_BUTTON_KEY = "UndoRedoPanel.UndoButton"; public static final String REDO_BUTTON_KEY = "UndoRedoPanel.RedoButton"; public static final String SEARCH_PANEL_KEY = "SearchPanel"; public static final String FIND_BUTTON_KEY = "SearchPanel.FindButton"; public static final String REPLACE_BUTTON_KEY = "SearchPanel.ReplaceButton"; public static final String FORMAT_PANEL_KEY = "FormatPanel"; public static final String SELECT_ALL_BUTTON_KEY = "FormatPanel.SelectAllButton"; public static final String CLEAR_FORMATTING_BUTTON_KEY = "FormatPanel.ClearFormattingButton"; public static final String TEXT_EFFECT_PANEL_KEY = "TextEffectPanel"; public static final String BOLD_BUTTON_KEY = "TextEffectPanel.BoldButton"; public static final String ITALIC_BUTTON_KEY = "TextEffectPanel.ItalicButton"; public static final String UNDERLINE_BUTTON_KEY = "TextEffectPanel.UnderlineButton"; public static final String STRIKE_BUTTON_KEY = "TextEffectPanel.StrikethroughButton"; public static final String SUB_SUPER_SCRIPT_PANEL_KEY = "SubSuperScriptPanel"; public static final String SUB_SCRIPT_BUTTON_KEY = "SubSuperScriptPanel.SubscriptButton"; public static final String SUPER_SCRIPT_BUTTON_KEY = "SubSuperScriptPanel.SuperscriptButton"; public static final String LIST_PANEL_KEY = "ListPanel"; public static final String NUMBERED_LIST_BUTTON_KEY = "ListPanel.InsertRemoveNumberedListButton"; public static final String BULLETED_BUTTON_KEY = "ListPanel.InsertRemoveBulletedListButton"; public static final String BLOCK_PANEL_KEY = "BlockPanel"; public static final String DECREASE_INDENT_BUTTON_KEY = "BlockPanel.DecreaseIndentButton"; public static final String INCREASE_INDENT_BUTTON_KEY = "BlockPanel.IncreaseIndentButton"; public static final String BLOCK_QUOTE_BUTTON_KEY = "BlockPanel.BlockQuoteButton"; public static final String DIV_BUTTON_KEY = "BlockPanel.CreateDivButton"; public static final String PARAGRAPH_BUTTON_KEY = "BlockPanel.CreateParagraphButton"; public static final String JUSTIFICATION_PANEL_KEY = "JustificationPanel"; public static final String LEFT_JUSTIFY_BUTTON_KEY = "JustificationPanel.LeftJustifyButton"; public static final String CENTER_JUSTIFY_BUTTON_KEY = "JustificationPanel.CenterJustifyButton"; public static final String RIGHT_JUSTIFY_BUTTON_KEY = "JustificationPanel.RightJustifyButton"; public static final String BLOCK_JUSTIFY_BUTTON_KEY = "JustificationPanel.BlockJustifyButton"; public static final String LINK_PANEL_KEY = "LinkPanel"; public static final String LINK_BUTTON_KEY = "LinkPanel.LinkButton"; public static final String UNLINK_BUTTON_KEY = "LinkPanel.UnlinkButton"; public static final String ANCHOR_BUTTON_KEY = "LinkPanel.AnchorButton"; public static final String MISC_PANEL_KEY = "MiscPanel"; public static final String IMAGE_BUTTON_KEY = "MiscPanel.InsertImage"; public static final String TABLE_BUTTON_KEY = "MiscPanel.InsertTableButton"; public static final String HORIZONTAL_LINE_BUTTON_KEY = "MiscPanel.InsertHorizontalLineButton"; public static final String SPECIAL_CHAR_BUTTON_KEY = "MiscPanel.InsertSpecialCharButton"; public static final String FONT_PANEL_KEY = "FontComboBox"; public static final String FONT_SIZE_PANEL_KEY = "FontSizeComboBox"; public static final String PARAGRAPH_FORMAT_PANEL_KEY = "ParagraphFormatComboBox"; public static final String COLOR_PANEL_KEY = "ColorPanel"; public static final String TEXT_COLOR_BUTTON_KEY = "ColorPanel.TextColorButton"; public static final String BACKGROUND_COLOR_BUTTON_KEY = "ColorPanel.BackgroundColorButton"; public static final String ABOUT_PANEL_KEY = "AboutPanel"; public static final String ABOUT_BUTTON_KEY = "AboutPanel.AboutButton"; private JTextComponentSpellChecker spellChecker = null; private SpellDictionary dictionary = null; private JTextArea htmlTextArea; private boolean htmlSourceMode = false; private SpecialCharacterDialog specialCharacterDialog = new SpecialCharacterDialog(null, true); private Hashtable<Object, Action> editorKitActions; private SpellCheckDictionaryVersion spellCheckDictionaryVersion = SpellCheckDictionaryVersion.LIBERAL_US; private String customDictionaryFilename = null; /** Listener for the edits on the current document. */ protected UndoableEditListener undoHandler = new UndoHandler(); /** UndoManager that we add edits to. */ protected UndoManager undo = new UndoManager(); private UndoAction undoAction = new UndoAction(); private RedoAction redoAction = new RedoAction(); private HTMLEditorKit.CutAction cutAction = new HTMLEditorKit.CutAction(); private HTMLEditorKit.CopyAction copyAction = new HTMLEditorKit.CopyAction(); private HTMLEditorKit.PasteAction pasteAction = new HTMLEditorKit.PasteAction(); private FindReplaceAction findReplaceAction; private HTMLEditorKit editorKit = new HTMLEditorKit(); private JPopupMenu contextMenu; public static interface ImageInsertRequestHandler { public void insertImage(JTextPane htmlTextPane); } private List<ContextMenuListener> contextMenuListeners = new ArrayList<ContextMenuListener>(); private List<EditorMouseMotionListener> editorMouseMotionListeners = new ArrayList<EditorMouseMotionListener>(); private enum ParagraphFormat { PARAGRAPH_FORMAT("Format", null), NORMAL("Normal", Tag.P), HEADING1("Heading 1", Tag.H1), HEADING2("Heading 2", Tag.H2), HEADING3( "Heading 3", Tag.H3), HEADING4("Heading 4", Tag.H4), HEADING5("Heading 5", Tag.H5), HEADING6("Heading 6", Tag.H6), FORMATTED( "Formatted", Tag.PRE), ADDRESS("Address", Tag.ADDRESS); private String text; private Tag tag; ParagraphFormat(String text, Tag tag) { this.text = text; this.tag = tag; } public Tag getTag() { return tag; } public String getText() { return text; } @Override public String toString() { return text; } } private enum FontItem { FONT("Font", null), ARIAL("Arial", "Arial"), COMIC_SANS_MS("Comic Sans MS", "Comic Sans MS"), COURIER_NEW("Courier New", "Courier New"), GEORGIA("Georgia", "Georgia"), LUCINDA_SANS_UNICODE("Lucinda Sans Unicode", "Lucinda Sans Unicode"), TAHOMA("Tahoma", "Tahoma"), TIMES_NEW_ROMAN("Times New Roman", "Times New Roman"), TREBUCHET_MS("Trebuchet MS", "Trebuchet MS"), VERDANA("Verdana", "Verdana"); private String text; private String fontName; FontItem(String text, String fontName) { this.text = text; this.fontName = fontName; } public String getText() { return text; } public String getFontName() { return fontName; } @Override public String toString() { return text; } } private enum FontSize { FONT_SIZE("Size", -1), SIZE8("8", 8), SIZE9("9", 9), SIZE10("10", 10), SIZE11("11", 11), SIZE12("12", 12), SIZE14("14", 14), SIZE18("18", 18), SIZE20("20", 20), SIZE22("22", 22), SIZE24("24", 24), SIZE26("26", 26), SIZE28("28", 28), SIZE36("36", 36), SIZE48("48", 48), SIZE72("72", 72); private String text; private int size; FontSize(String text, int size) { this.text = text; this.size = size; } public String getText() { return text; } public int getSize() { return size; } @Override public String toString() { return text; } } private javax.swing.JPanel toolbarPanel; private javax.swing.JTextPane htmlTextPane; private javax.swing.JScrollPane mainScrollPane; private javax.swing.text.html.HTMLDocument htmlDocument; private javax.swing.JPanel sourcePanel; private javax.swing.JButton sourceButton; private javax.swing.JPanel pagePanel; private javax.swing.JButton openButton; private javax.swing.JButton saveButton; private javax.swing.JButton newButton; private javax.swing.JButton previewButton; private javax.swing.JPanel editPanel; private javax.swing.JButton cutButton; private javax.swing.JButton copyButton; private javax.swing.JButton pasteButton; private javax.swing.JButton pasteAsTextButton; private javax.swing.JPanel toolsPanel; private javax.swing.JButton printButton; private javax.swing.JButton spellcheckButton; private javax.swing.JPanel undoRedoPanel; private javax.swing.JButton undoButton; private javax.swing.JButton redoButton; private javax.swing.JPanel searchPanel; private javax.swing.JButton findButton; private javax.swing.JButton replaceButton; private javax.swing.JPanel formatPanel; private javax.swing.JButton selectAllButton; private javax.swing.JButton clearFormattingButton; private javax.swing.JPanel textEffectPanel; private javax.swing.JButton boldButton; private javax.swing.JButton italicButton; private javax.swing.JButton underlineButton; private javax.swing.JButton strikethroughButton; private javax.swing.JPanel subSuperScriptPanel; private javax.swing.JButton subscriptButton; private javax.swing.JButton superscriptButton; private javax.swing.JPanel listPanel; private javax.swing.JButton insertRemoveNumberedListButton; private javax.swing.JButton insertRemoveBulletedListButton; private javax.swing.JPanel blockPanel; private javax.swing.JButton decreaseIndentButton; private javax.swing.JButton increaseIndentButton; private javax.swing.JButton blockQuoteButton; private javax.swing.JButton createDivButton; private javax.swing.JButton createParagraphButton; private javax.swing.JPanel justificationPanel; private javax.swing.JButton leftJustifyButton; private javax.swing.JButton centerJustifyButton; private javax.swing.JButton rightJustifyButton; private javax.swing.JButton blockJustifyButton; private javax.swing.JPanel linkPanel; private javax.swing.JButton linkButton; private javax.swing.JButton unlinkButton; private javax.swing.JButton anchorButton; private javax.swing.JPanel miscPanel; private javax.swing.JButton insertImage; private javax.swing.JButton insertTableButton; private javax.swing.JButton insertHorizontalLineButton; private javax.swing.JButton insertSpecialCharButton; private javax.swing.JComboBox fontComboBox; private javax.swing.JComboBox fontSizeComboBox; private javax.swing.JComboBox paragraphFormatComboBox; private javax.swing.JPanel colorPanel; private javax.swing.JButton textColorButton; private javax.swing.JButton backgroundColorButton; private javax.swing.JPanel aboutPanel; private javax.swing.JButton aboutButton; private ImageInsertRequestHandler insertImageRequestHandler; public void documentWasEdited() { } /** Creates new form MetaphaseEditorPanel */ public MetaphaseEditorPanel(MetaphaseEditorConfiguration configuration) { insertImageRequestHandler = new DefaultImageInsertRequestHandler(); initComponents(); updateComponents(configuration); createEditorKitActionTable(); htmlTextArea = new JTextArea(); htmlTextArea.setFont(new Font("Monospaced", Font.PLAIN, 12)); htmlTextPane.setContentType("text/html"); htmlTextPane.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { super.focusGained(e); } @Override public void focusLost(FocusEvent e) { super.focusLost(e); documentWasEdited(); } }); findReplaceAction = new FindReplaceAction("Find/Replace", htmlTextPane); cutButton.setAction(cutAction); cutButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/cut.png")); cutButton.setText(""); cutButton.setToolTipText("Cut"); copyButton.setAction(copyAction); copyButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/copy.png")); copyButton.setText(""); copyButton.setToolTipText("Copy"); pasteButton.setAction(pasteAction); pasteButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/paste.png")); pasteButton.setText(""); pasteButton.setToolTipText("Paste"); undoButton.setAction(undoAction); undoButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/undo.png")); undoButton.setText(""); undoButton.setToolTipText("Undo"); redoButton.setAction(redoAction); redoButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/redo.png")); redoButton.setText(""); redoButton.setToolTipText("Redo"); findButton.setAction(findReplaceAction); findButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/find.png")); findButton.setText(""); findButton.setToolTipText("Find"); replaceButton.setAction(findReplaceAction); replaceButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/replace.png")); replaceButton.setText(""); replaceButton.setToolTipText("Replace"); clearFormattingButton.setAction(new ClearFormattingAction(this, "Remove Format")); clearFormattingButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/removeformat.png")); clearFormattingButton.setText(""); clearFormattingButton.setToolTipText("Remove Format"); boldButton.setAction(new HTMLEditorKit.BoldAction()); boldButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/bold.png")); boldButton.setText(""); boldButton.setToolTipText("Bold"); italicButton.setAction(new HTMLEditorKit.ItalicAction()); italicButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/italic.png")); italicButton.setText(""); italicButton.setToolTipText("Italic"); underlineButton.setAction(new HTMLEditorKit.UnderlineAction()); underlineButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/underline.png")); underlineButton.setText(""); underlineButton.setToolTipText("Underline"); strikethroughButton.setAction(new StrikeThroughAction()); strikethroughButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/strikethrough.png")); strikethroughButton.setText(""); strikethroughButton.setToolTipText("Strike Through"); subscriptButton.setAction(new SubscriptAction()); subscriptButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/subscript.png")); subscriptButton.setText(""); subscriptButton.setToolTipText("Subscript"); superscriptButton.setAction(new SuperscriptAction()); superscriptButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/superscript.png")); superscriptButton.setText(""); superscriptButton.setToolTipText("Superscript"); // TODO: change increase and decrease indent to add inner <li> when // inside bulleted or numbered list increaseIndentButton.setAction(new IncreaseIndentAction("Increase Indent", this)); increaseIndentButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/incindent.png")); increaseIndentButton.setText(""); increaseIndentButton.setToolTipText("Increase Indent"); decreaseIndentButton.setAction(new DecreaseIndentAction("Decrease Indent", this)); decreaseIndentButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/decindent.png")); decreaseIndentButton.setText(""); decreaseIndentButton.setToolTipText("Decrease Indent"); blockQuoteButton.setAction(new FormatAction(this, "Block Quote", Tag.BLOCKQUOTE)); blockQuoteButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/blockquote.png")); blockQuoteButton.setText(""); blockQuoteButton.setToolTipText("Block Quote"); leftJustifyButton.setAction(new HTMLEditorKit.AlignmentAction("Left Align", StyleConstants.ALIGN_LEFT)); leftJustifyButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/leftjustify.png")); leftJustifyButton.setText(""); leftJustifyButton.setToolTipText("Left Justify"); centerJustifyButton.setAction(new HTMLEditorKit.AlignmentAction("Center Align", StyleConstants.ALIGN_CENTER)); centerJustifyButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/centerjustify.png")); centerJustifyButton.setText(""); centerJustifyButton.setToolTipText("Center Justify"); rightJustifyButton.setAction(new HTMLEditorKit.AlignmentAction("Left Align", StyleConstants.ALIGN_RIGHT)); rightJustifyButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/rightjustify.png")); rightJustifyButton.setText(""); rightJustifyButton.setToolTipText("Right Justify"); blockJustifyButton.setAction(new HTMLEditorKit.AlignmentAction("Justified Align", StyleConstants.ALIGN_JUSTIFIED)); blockJustifyButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/blockjustify.png")); blockJustifyButton.setText(""); blockJustifyButton.setToolTipText("Block Justify"); unlinkButton.setAction(new UnlinkAction(this, "Unlink")); unlinkButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/unlink.png")); unlinkButton.setText(""); unlinkButton.setToolTipText("Unlink"); // TODO: horizontal rule - doesn't insert correctly if within anything // other than P, ie. TD or H1 insertHorizontalLineButton.setAction(new HTMLEditorKit.InsertHTMLTextAction("Insert Horizontal Line", "<hr/>", Tag.P, Tag.HR, Tag.BODY, Tag.HR)); insertHorizontalLineButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/horizontalline.png")); insertHorizontalLineButton.setText(""); insertHorizontalLineButton.setToolTipText("Insert Horizontal Line"); paragraphFormatComboBox.setRenderer(new ParagraphFormatListCellRenderer()); paragraphFormatComboBox.removeAllItems(); ParagraphFormat[] paragraphFormats = ParagraphFormat.values(); for (int i = 0; i < paragraphFormats.length; i++) { paragraphFormatComboBox.addItem(paragraphFormats[i]); } fontComboBox.setRenderer(new FontListCellRenderer()); fontComboBox.removeAllItems(); FontItem[] fontItems = FontItem.values(); for (int i = 0; i < fontItems.length; i++) { fontComboBox.addItem(fontItems[i]); } fontSizeComboBox.setRenderer(new FontSizeListCellRenderer()); fontSizeComboBox.removeAllItems(); FontSize[] fontSizes = FontSize.values(); for (int i = 0; i < fontSizes.length; i++) { fontSizeComboBox.addItem(fontSizes[i]); } setToolbarFocusActionListener(this); htmlTextPane.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo"); htmlTextPane.getActionMap().put("Undo", undoAction); htmlTextPane.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo"); htmlTextPane.getActionMap().put("Redo", redoAction); htmlTextPane.getInputMap().put(KeyStroke.getKeyStroke("control F"), "Find"); htmlTextPane.getActionMap().put("Find", findReplaceAction); htmlTextPane.getInputMap().put(KeyStroke.getKeyStroke("control R"), "Replace"); htmlTextPane.getActionMap().put("Replace", findReplaceAction); contextMenu = new JPopupMenu(); JMenuItem cutMenuItem = new JMenuItem(); cutMenuItem.setAction(cutAction); cutMenuItem.setText("Cut"); cutMenuItem.setMnemonic('C'); cutMenuItem.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/cut.png")); JMenuItem copyMenuItem = new JMenuItem(); copyMenuItem.setAction(copyAction); copyMenuItem.setText("Copy"); copyMenuItem.setMnemonic('o'); copyMenuItem.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/copy.png")); JMenuItem pasteMenuItem = new JMenuItem(); pasteMenuItem.setAction(pasteAction); pasteMenuItem.setText("Paste"); pasteMenuItem.setMnemonic('P'); pasteMenuItem.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/paste.png")); contextMenu.add(cutMenuItem); contextMenu.add(copyMenuItem); contextMenu.add(pasteMenuItem); htmlTextPane.addMouseMotionListener(new DefaultEditorMouseMotionListener()); htmlTextPane.setEditorKit(editorKit); startNewDocument(); // initSpellChecker(); } // The following two methods allow us to find an // action provided by the editor kit by its name. private void createEditorKitActionTable() { editorKitActions = new Hashtable<Object, Action>(); Action[] actionsArray = editorKit.getActions(); for (int i = 0; i < actionsArray.length; i++) { Action a = actionsArray[i]; editorKitActions.put(a.getValue(Action.NAME), a); } } private Action getEditorKitActionByName(String name) { return editorKitActions.get(name); } protected void resetUndoManager() { undo.discardAllEdits(); undoAction.update(); redoAction.update(); } public void startNewDocument() { Document oldDoc = htmlTextPane.getDocument(); if (oldDoc != null) { oldDoc.removeUndoableEditListener(undoHandler); } htmlDocument = (HTMLDocument) editorKit.createDefaultDocument(); htmlTextPane.setDocument(htmlDocument); htmlTextPane.getDocument().addUndoableEditListener(undoHandler); resetUndoManager(); // TODO: check if necessary htmlDocument.putProperty("IgnoreCharsetDirective", Boolean.TRUE); htmlDocument.setPreservesUnknownTags(false); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this * method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") private void initComponents() { htmlDocument = new javax.swing.text.html.HTMLDocument(); cutButton = new javax.swing.JButton(); copyButton = new javax.swing.JButton(); pasteAsTextButton = new javax.swing.JButton(); pasteButton = new javax.swing.JButton(); saveButton = new javax.swing.JButton(); newButton = new javax.swing.JButton(); previewButton = new javax.swing.JButton(); openButton = new javax.swing.JButton(); printButton = new javax.swing.JButton(); spellcheckButton = new javax.swing.JButton(); undoButton = new javax.swing.JButton(); redoButton = new javax.swing.JButton(); findButton = new javax.swing.JButton(); replaceButton = new javax.swing.JButton(); selectAllButton = new javax.swing.JButton(); clearFormattingButton = new javax.swing.JButton(); boldButton = new javax.swing.JButton(); italicButton = new javax.swing.JButton(); strikethroughButton = new javax.swing.JButton(); underlineButton = new javax.swing.JButton(); subscriptButton = new javax.swing.JButton(); superscriptButton = new javax.swing.JButton(); insertRemoveNumberedListButton = new javax.swing.JButton(); insertRemoveBulletedListButton = new javax.swing.JButton(); decreaseIndentButton = new javax.swing.JButton(); increaseIndentButton = new javax.swing.JButton(); createDivButton = new javax.swing.JButton(); blockQuoteButton = new javax.swing.JButton(); createParagraphButton = new javax.swing.JButton(); leftJustifyButton = new javax.swing.JButton(); centerJustifyButton = new javax.swing.JButton(); blockJustifyButton = new javax.swing.JButton(); rightJustifyButton = new javax.swing.JButton(); insertTableButton = new javax.swing.JButton(); insertHorizontalLineButton = new javax.swing.JButton(); insertSpecialCharButton = new javax.swing.JButton(); insertImage = new javax.swing.JButton(); paragraphFormatComboBox = new javax.swing.JComboBox(); fontComboBox = new javax.swing.JComboBox(); fontSizeComboBox = new javax.swing.JComboBox(); textColorButton = new javax.swing.JButton(); backgroundColorButton = new javax.swing.JButton(); aboutButton = new javax.swing.JButton(); sourceButton = new javax.swing.JButton(); linkButton = new javax.swing.JButton(); unlinkButton = new javax.swing.JButton(); anchorButton = new javax.swing.JButton(); htmlTextPane = new javax.swing.JTextPane(); cutButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/cut.png")); // NOI18N cutButton.setToolTipText("Cut"); cutButton.setName(CUT_BUTTON_KEY); copyButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/copy.png")); // NOI18N copyButton.setToolTipText("Copy"); copyButton.setName(COPY_BUTTON_KEY); pasteAsTextButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/paste_as_text.png")); // NOI18N pasteAsTextButton.setToolTipText("Paste as plain text"); pasteAsTextButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { pasteAsTextButtonActionPerformed(evt); } }); pasteAsTextButton.setName(PASTE_AS_TEXT_BUTTON_KEY); pasteButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/paste.png")); // NOI18N pasteButton.setToolTipText("Paste"); pasteButton.setName(PASTE_BUTTON_KEY); saveButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/save.png")); // NOI18N saveButton.setToolTipText("Save"); saveButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { saveButtonActionPerformed(evt); } }); saveButton.setName(SAVE_BUTTON_KEY); newButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/newpage.png")); // NOI18N newButton.setToolTipText("New"); newButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { newButtonActionPerformed(evt); } }); newButton.setName(NEW_BUTTON_KEY); previewButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/preview.png")); // NOI18N previewButton.setToolTipText("Preview"); previewButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { previewButtonActionPerformed(evt); } }); previewButton.setName(PREVIEW_BUTTON_KEY); openButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/open.png")); // NOI18N openButton.setToolTipText("Open"); openButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { openButtonActionPerformed(evt); } }); openButton.setName(OPEN_BUTTON_KEY); printButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/print.png")); // NOI18N printButton.setToolTipText("Print"); printButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { printButtonActionPerformed(evt); } }); printButton.setName(PRINT_BUTTON_KEY); spellcheckButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/spellcheck.png")); // NOI18N spellcheckButton.setToolTipText("Check Spelling"); spellcheckButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { spellcheckButtonActionPerformed(evt); } }); spellcheckButton.setName(SPELL_CHECK_BUTTON_KEY); undoButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/undo.png")); // NOI18N undoButton.setToolTipText("Undo"); undoButton.setName(UNDO_BUTTON_KEY); redoButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/redo.png")); // NOI18N redoButton.setToolTipText("Redo"); redoButton.setName(REDO_BUTTON_KEY); findButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/find.png")); // NOI18N findButton.setToolTipText("Find"); findButton.setName(FIND_BUTTON_KEY); replaceButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/replace.png")); // NOI18N replaceButton.setToolTipText("Replace"); replaceButton.setName(REPLACE_BUTTON_KEY); selectAllButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/selectall.png")); // NOI18N selectAllButton.setToolTipText("Select All"); selectAllButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { selectAllButtonActionPerformed(evt); } }); selectAllButton.setName(SELECT_ALL_BUTTON_KEY); clearFormattingButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/removeformat.png")); // NOI18N clearFormattingButton.setToolTipText("Remove Format"); clearFormattingButton.setName(CLEAR_FORMATTING_BUTTON_KEY); boldButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/bold.png")); // NOI18N boldButton.setToolTipText("Bold"); boldButton.setName(BOLD_BUTTON_KEY); italicButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/italic.png")); // NOI18N italicButton.setToolTipText("Italic"); italicButton.setName(ITALIC_BUTTON_KEY); strikethroughButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/strikethrough.png")); // NOI18N strikethroughButton.setToolTipText("Strike Through"); strikethroughButton.setName(STRIKE_BUTTON_KEY); underlineButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/underline.png")); // NOI18N underlineButton.setToolTipText("Underline"); underlineButton.setName(UNDERLINE_BUTTON_KEY); subscriptButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/subscript.png")); // NOI18N subscriptButton.setToolTipText("Subscript"); subscriptButton.setName(SUB_SCRIPT_BUTTON_KEY); superscriptButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/superscript.png")); // NOI18N superscriptButton.setToolTipText("Superscript"); superscriptButton.setName(SUPER_SCRIPT_BUTTON_KEY); insertRemoveNumberedListButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/numberlist.png")); // NOI18N insertRemoveNumberedListButton.setToolTipText("Insert/Remove Numbered List"); insertRemoveNumberedListButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { insertRemoveNumberedListButtonActionPerformed(evt); } }); insertRemoveNumberedListButton.setName(NUMBERED_LIST_BUTTON_KEY); insertRemoveBulletedListButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/bulletlist.png")); // NOI18N insertRemoveBulletedListButton.setToolTipText("Insert/Remove Bulleted List"); insertRemoveBulletedListButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { insertRemoveBulletedListButtonActionPerformed(evt); } }); insertRemoveBulletedListButton.setName(BULLETED_BUTTON_KEY); decreaseIndentButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/decindent.png")); // NOI18N decreaseIndentButton.setToolTipText("Decrease Indent"); decreaseIndentButton.setName(DECREASE_INDENT_BUTTON_KEY); increaseIndentButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/incindent.png")); // NOI18N increaseIndentButton.setToolTipText("Increase Indent"); increaseIndentButton.setName(INCREASE_INDENT_BUTTON_KEY); createDivButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/creatediv.png")); // NOI18N createDivButton.setToolTipText("Create Div Container"); createDivButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { createDivButtonActionPerformed(evt); } }); createDivButton.setName(DIV_BUTTON_KEY); blockQuoteButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/blockquote.png")); // NOI18N blockQuoteButton.setToolTipText("Block Quote"); blockQuoteButton.setName(BLOCK_QUOTE_BUTTON_KEY); createParagraphButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/createparagraph.png")); // NOI18N createParagraphButton.setToolTipText("Create Paragraph"); createParagraphButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { createParagraphButtonActionPerformed(evt); } }); createParagraphButton.setName(PARAGRAPH_BUTTON_KEY); leftJustifyButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/leftjustify.png")); // NOI18N leftJustifyButton.setToolTipText("Left Justify"); leftJustifyButton.setName(LEFT_JUSTIFY_BUTTON_KEY); centerJustifyButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/centerjustify.png")); // NOI18N centerJustifyButton.setToolTipText("Center Justify"); centerJustifyButton.setName(CENTER_JUSTIFY_BUTTON_KEY); blockJustifyButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/blockjustify.png")); // NOI18N blockJustifyButton.setToolTipText("Block Justify"); blockJustifyButton.setName(BLOCK_JUSTIFY_BUTTON_KEY); rightJustifyButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/rightjustify.png")); // NOI18N rightJustifyButton.setToolTipText("Right Justify"); rightJustifyButton.setName(RIGHT_JUSTIFY_BUTTON_KEY); insertTableButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/table.png")); // NOI18N insertTableButton.setToolTipText("Table"); insertTableButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { insertTableButtonActionPerformed(evt); } }); insertTableButton.setName(TABLE_BUTTON_KEY); insertHorizontalLineButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/horizontalline.png")); // NOI18N insertHorizontalLineButton.setToolTipText("Insert Horizontal Line"); insertHorizontalLineButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { insertHorizontalLineButtonActionPerformed(evt); } }); insertHorizontalLineButton.setName(HORIZONTAL_LINE_BUTTON_KEY); insertSpecialCharButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/symbol.png")); // NOI18N insertSpecialCharButton.setToolTipText("Insert Special Character"); insertSpecialCharButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { insertSpecialCharButtonActionPerformed(evt); } }); insertSpecialCharButton.setName(SPECIAL_CHAR_BUTTON_KEY); insertImage.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/image.png")); // NOI18N insertImage.setToolTipText("Image"); insertImage.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { insertImageActionPerformed(evt); } }); insertImage.setName(IMAGE_BUTTON_KEY); paragraphFormatComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Normal", "Heading 1", "Heading 2", "Heading 3", "Heading 4", "Heading 5", "Heading 6", "Formatted", "Address", "Normal (DIV)" })); paragraphFormatComboBox.setToolTipText("Paragraph Format"); paragraphFormatComboBox.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { paragraphFormatComboBoxActionPerformed(evt); } }); paragraphFormatComboBox.setName(PARAGRAPH_FORMAT_PANEL_KEY); fontComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Arial", "Comic Sans MS", "Courier New", "Georgia", "Lucinda Sans Unicode", "Tahoma", "Times New Roman", "Trebuchet MS", "Verdana" })); fontComboBox.setToolTipText("Font"); fontComboBox.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { fontComboBoxActionPerformed(evt); } }); fontComboBox.setName(FONT_PANEL_KEY); fontSizeComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28", "36", "48", "72" })); fontSizeComboBox.setToolTipText("Font Size"); fontSizeComboBox.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { fontSizeComboBoxActionPerformed(evt); } }); fontSizeComboBox.setName(FONT_SIZE_PANEL_KEY); textColorButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/textcolor.png")); // NOI18N textColorButton.setToolTipText("Text Color"); textColorButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { textColorButtonActionPerformed(evt); } }); textColorButton.setName(TEXT_COLOR_BUTTON_KEY); backgroundColorButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/backgroundcolor.png")); // NOI18N backgroundColorButton.setToolTipText("Background Color"); backgroundColorButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { backgroundColorButtonActionPerformed(evt); } }); backgroundColorButton.setName(BACKGROUND_COLOR_BUTTON_KEY); aboutButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/about.png")); // NOI18N aboutButton.setToolTipText("About Metaphase Editor"); aboutButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { aboutButtonActionPerformed(evt); } }); aboutButton.setName(ABOUT_BUTTON_KEY); sourceButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/source.png")); // NOI18N sourceButton.setText("Source"); sourceButton.setToolTipText("Source"); // sourceButton.setPreferredSize(new java.awt.Dimension(87, 24)); sourceButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { sourceButtonActionPerformed(evt); } }); sourceButton.setName(SOURCE_BUTTON_KEY); linkButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/link.png")); // NOI18N linkButton.setToolTipText("Link"); linkButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { linkButtonActionPerformed(evt); } }); linkButton.setName(LINK_BUTTON_KEY); unlinkButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/unlink.png")); // NOI18N unlinkButton.setToolTipText("Unlink"); unlinkButton.setName(UNLINK_BUTTON_KEY); anchorButton.setIcon(new ImageIconResource("Icons/MetaphaseEditor/icons/anchor.png")); // NOI18N anchorButton.setToolTipText("Anchor"); anchorButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { anchorButtonActionPerformed(evt); } }); anchorButton.setName(ANCHOR_BUTTON_KEY); htmlTextPane.addMouseListener(new java.awt.event.MouseAdapter() { @Override public void mouseClicked(java.awt.event.MouseEvent evt) { htmlTextPaneMouseClicked(evt); } }); Action insertBreakAction = htmlTextPane.getActionMap().get(DefaultEditorKit.insertBreakAction); Action deletePrevCharAction = htmlTextPane.getActionMap().get(DefaultEditorKit.deletePrevCharAction); htmlTextPane.getActionMap().put(DefaultEditorKit.insertBreakAction, new InsertBreakAction(insertBreakAction, deletePrevCharAction)); /*htmlTextPane.addKeyListener(new java.awt.event.KeyAdapter() { @Override public void keyPressed(java.awt.event.KeyEvent evt) { htmlTextPaneKeyPressed(evt); } @Override public void keyReleased(java.awt.event.KeyEvent evt) { htmlTextPaneKeyReleased(evt); } @Override public void keyTyped(java.awt.event.KeyEvent evt) { htmlTextPaneKeyTyped(evt); } });*/ mainScrollPane = new JScrollPane(); mainScrollPane.setOpaque(false); mainScrollPane.setViewportView(htmlTextPane); setLayout(new BorderLayout()); toolbarPanel = new JPanel(new GridBagLayout()); toolbarPanel.setOpaque(false); // toolbarPanel.setLayout(new BoxLayout(toolbarPanel, BoxLayout.Y_AXIS)); add(toolbarPanel, BorderLayout.NORTH); add(mainScrollPane, BorderLayout.CENTER); } public void updateComponents(MetaphaseEditorConfiguration configuration) { toolbarPanel.removeAll(); if (configuration.hasOption(SOURCE_PANEL_KEY)) { sourcePanel = makeGroup(SOURCE_PANEL_KEY, configuration, sourceButton); } if (configuration.hasOption(PAGE_PANEL_KEY)) { pagePanel = makeGroup(PAGE_PANEL_KEY, configuration, openButton, saveButton, newButton, previewButton); } if (configuration.hasOption(EDIT_PANEL_KEY)) { editPanel = makeGroup(EDIT_PANEL_KEY, configuration, cutButton, copyButton, pasteButton, pasteAsTextButton); } if (configuration.hasOption(TOOLS_PANEL_KEY)) { toolsPanel = makeGroup(TOOLS_PANEL_KEY, configuration, printButton, spellcheckButton); } if (configuration.hasOption(UNDO_REDO_PANEL_KEY)) { undoRedoPanel = makeGroup(UNDO_REDO_PANEL_KEY, configuration, undoButton, redoButton); } if (configuration.hasOption(SEARCH_PANEL_KEY)) { searchPanel = makeGroup(SEARCH_PANEL_KEY, configuration, findButton, replaceButton); } if (configuration.hasOption(FORMAT_PANEL_KEY)) { formatPanel = makeGroup(FORMAT_PANEL_KEY, configuration, selectAllButton, clearFormattingButton); } if (configuration.hasOption(TEXT_EFFECT_PANEL_KEY)) { textEffectPanel = makeGroup(TEXT_EFFECT_PANEL_KEY, configuration, boldButton, italicButton, strikethroughButton, underlineButton); } if (configuration.hasOption(SUB_SUPER_SCRIPT_PANEL_KEY)) { subSuperScriptPanel = makeGroup(SUB_SUPER_SCRIPT_PANEL_KEY, configuration, subscriptButton, superscriptButton); } if (configuration.hasOption(LIST_PANEL_KEY)) { listPanel = makeGroup(LIST_PANEL_KEY, configuration, insertRemoveNumberedListButton, insertRemoveBulletedListButton); } if (configuration.hasOption(BLOCK_PANEL_KEY)) { blockPanel = makeGroup(BLOCK_PANEL_KEY, configuration, decreaseIndentButton, increaseIndentButton, blockQuoteButton, createDivButton, createParagraphButton); } if (configuration.hasOption(JUSTIFICATION_PANEL_KEY)) { justificationPanel = makeGroup(JUSTIFICATION_PANEL_KEY, configuration, leftJustifyButton, centerJustifyButton, rightJustifyButton, blockJustifyButton); } if (configuration.hasOption(LINK_PANEL_KEY)) { linkPanel = makeGroup(LINK_PANEL_KEY, configuration, linkButton, unlinkButton, anchorButton); } if (configuration.hasOption(MISC_PANEL_KEY)) { miscPanel = makeGroup(MISC_PANEL_KEY, configuration, insertImage, insertTableButton, insertHorizontalLineButton, insertSpecialCharButton); } if (configuration.hasOption(COLOR_PANEL_KEY)) { colorPanel = makeGroup(COLOR_PANEL_KEY, configuration, textColorButton, backgroundColorButton); } if (configuration.hasOption(ABOUT_PANEL_KEY)) { aboutPanel = makeGroup(ABOUT_PANEL_KEY, configuration, aboutButton); } GridBagConstraints gbc = new GridBagConstraints(); gbc.weightx = 1.0; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.LINE_START; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets = new Insets(3, 3, 3, 3); toolbarPanel.add(makeLinePanel(1, configuration), gbc); toolbarPanel.add(makeLinePanel(2, configuration), gbc); toolbarPanel.add(makeLinePanel(3, configuration), gbc); toolbarPanel.revalidate(); toolbarPanel.repaint(); } private JPanel makeGroup(String groupName, final MetaphaseEditorConfiguration configuration, JButton... buttons) { JPanel returned = new JPanel(); returned.setOpaque(false); returned.setName(groupName); // returned.setBorder(BorderFactory.createEtchedBorder()); returned.setBorder(BorderFactory.createEmptyBorder()); returned.setLayout(new FlowLayout(FlowLayout.LEADING, 0, 0)); Vector<JButton> buttonList = new Vector<JButton>(); for (JButton b : buttons) { if (configuration.hasOption(b.getName())) { buttonList.add(b); } } Collections.sort(buttonList, new Comparator<JButton>() { @Override public int compare(JButton o1, JButton o2) { return configuration.getOption(o1.getName()).index - configuration.getOption(o2.getName()).index; } }); for (JButton c : buttonList) { returned.add(c); } return returned; } private JPanel makeLinePanel(int line, final MetaphaseEditorConfiguration configuration) { Vector<JComponent> components = new Vector<JComponent>(); if (configuration.hasOption(SOURCE_PANEL_KEY, line)) { components.add(sourcePanel); } if (configuration.hasOption(PAGE_PANEL_KEY, line)) { components.add(pagePanel); } if (configuration.hasOption(EDIT_PANEL_KEY, line)) { components.add(editPanel); } if (configuration.hasOption(TOOLS_PANEL_KEY, line)) { components.add(toolsPanel); } if (configuration.hasOption(UNDO_REDO_PANEL_KEY, line)) { components.add(undoRedoPanel); } if (configuration.hasOption(SEARCH_PANEL_KEY, line)) { components.add(searchPanel); } if (configuration.hasOption(FORMAT_PANEL_KEY, line)) { components.add(formatPanel); } if (configuration.hasOption(TEXT_EFFECT_PANEL_KEY, line)) { components.add(textEffectPanel); } if (configuration.hasOption(SUB_SUPER_SCRIPT_PANEL_KEY, line)) { components.add(subSuperScriptPanel); } if (configuration.hasOption(LIST_PANEL_KEY, line)) { components.add(listPanel); } if (configuration.hasOption(BLOCK_PANEL_KEY, line)) { components.add(blockPanel); } if (configuration.hasOption(JUSTIFICATION_PANEL_KEY, line)) { components.add(justificationPanel); } if (configuration.hasOption(LINK_PANEL_KEY, line)) { components.add(linkPanel); } if (configuration.hasOption(MISC_PANEL_KEY, line)) { components.add(miscPanel); } if (configuration.hasOption(PARAGRAPH_FORMAT_PANEL_KEY, line)) { components.add(paragraphFormatComboBox); } if (configuration.hasOption(FONT_PANEL_KEY, line)) { components.add(fontComboBox); } if (configuration.hasOption(FONT_SIZE_PANEL_KEY, line)) { components.add(fontSizeComboBox); } if (configuration.hasOption(COLOR_PANEL_KEY, line)) { components.add(colorPanel); } if (configuration.hasOption(ABOUT_PANEL_KEY, line)) { components.add(aboutPanel); } Collections.sort(components, new Comparator<JComponent>() { @Override public int compare(JComponent o1, JComponent o2) { return configuration.getOption(o1.getName()).index - configuration.getOption(o2.getName()).index; } }); JPanel returned = new JPanel(); returned.setOpaque(false); returned.setVisible(components.size() > 0); returned.setLayout(new WrapLayout(FlowLayout.LEADING, 10, 0)); for (JComponent c : components) { returned.add(c); } return returned; } private void printButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_printButtonActionPerformed try { htmlTextPane.print(); } catch (PrinterException e) { throw new MetaphaseEditorException(e.getMessage(), e); } }// GEN-LAST:event_printButtonActionPerformed public JTextPane getHtmlTextPane() { return htmlTextPane; } public void setEditorToolTipText(String string) { htmlTextPane.setToolTipText(string); } public void addEditorMouseMotionListener(EditorMouseMotionListener editorMouseMotionListener) { editorMouseMotionListeners.add(editorMouseMotionListener); } public void removeEditorMouseMotionListener(EditorMouseMotionListener editorMouseMotionListener) { editorMouseMotionListeners.remove(editorMouseMotionListener); } public Element getParentTag(HTML.Tag tag) { Element e = htmlDocument.getCharacterElement(htmlTextPane.getSelectionStart()); while (!e.getName().equalsIgnoreCase("html")) { if (e.getName().equalsIgnoreCase(tag.toString())) { return e; } e = e.getParentElement(); } return null; } public AttributeSet getSelectedParagraphAttributes() { int start = htmlTextPane.getSelectionStart(); Element element = htmlDocument.getParagraphElement(start); MutableAttributeSet attributes = new SimpleAttributeSet(element.getAttributes()); Element charElement = htmlDocument.getCharacterElement(start); if (charElement != null) { Element impliedParagraph = charElement.getParentElement(); if (impliedParagraph != null) { Element listElement = impliedParagraph.getParentElement(); if (listElement.getName().equals("li")) { // re-add the existing attributes to the list item AttributeSet listElementAttrs = listElement.getAttributes(); Enumeration currentAttrEnum = listElementAttrs.getAttributeNames(); while (currentAttrEnum.hasMoreElements()) { Object attrName = currentAttrEnum.nextElement(); Object attrValue = listElement.getAttributes().getAttribute(attrName); if ((attrName instanceof String || attrName instanceof HTML.Attribute) && attrValue instanceof String) { attributes.addAttribute(attrName, attrValue); } } } } } return attributes; } public void addAttributesToSelectedParagraph(Map<String, String> attributes) { new AddAttributesAction(this, "Add Attributes To Selected Paragraph", attributes).actionPerformed(null); } public void removeAttributesFromSelectedParagraph(String[] attributeNames) { new RemoveAttributesAction(this, "Remove Attributes From Selected Paragraph", attributeNames).actionPerformed(null); } public String getDocument() { return htmlTextPane.getText(); } public void setDocument(String value) { try { StringReader reader = new StringReader(value); Document oldDoc = htmlTextPane.getDocument(); if (oldDoc != null) { oldDoc.removeUndoableEditListener(undoHandler); } htmlDocument = (HTMLDocument) editorKit.createDefaultDocument(); editorKit.read(reader, htmlDocument, 0); htmlDocument.addUndoableEditListener(undoHandler); htmlTextPane.setDocument(htmlDocument); resetUndoManager(); } catch (BadLocationException e) { throw new MetaphaseEditorException(e.getMessage(), e); } catch (IOException e) { throw new MetaphaseEditorException(e.getMessage(), e); } } public JPopupMenu getContextMenu() { return contextMenu; } public void addStyleSheetRule(String rule) { StyleSheet styleSheet = editorKit.getStyleSheet(); styleSheet.addRule(rule); } public void refreshAfterAction() { int pos = htmlTextPane.getCaretPosition(); htmlTextPane.setText(htmlTextPane.getText()); htmlTextPane.validate(); try { htmlTextPane.setCaretPosition(pos); } catch (IllegalArgumentException e) { // swallow the exception // seems like a bug in the JTextPane component // only happens occasionally when pasting text at the end of a // document System.err.println(e.getMessage()); } } private void insertRemoveNumberedListButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_insertRemoveNumberedListButtonActionPerformed new HTMLEditorKit.InsertHTMLTextAction("Insert Bulleted List", "<ol><li></li></ol>", Tag.BODY, Tag.OL).actionPerformed(evt); }// GEN-LAST:event_insertRemoveNumberedListButtonActionPerformed private void textColorButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_textColorButtonActionPerformed Color color = JColorChooser.showDialog(null, "Text Color", null); if (color != null) { new StyledEditorKit.ForegroundAction("Color", color).actionPerformed(evt); } }// GEN-LAST:event_textColorButtonActionPerformed private void selectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_selectAllButtonActionPerformed htmlTextPane.selectAll(); }// GEN-LAST:event_selectAllButtonActionPerformed private void aboutButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_aboutButtonActionPerformed AboutDialog aboutDialog = new AboutDialog(null, true); aboutDialog.setVisible(true); }// GEN-LAST:event_aboutButtonActionPerformed private void backgroundColorButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_backgroundColorButtonActionPerformed Color color = JColorChooser.showDialog(null, "Text Color", null); if (color != null) { new BackgroundColorAction(color).actionPerformed(evt); } }// GEN-LAST:event_backgroundColorButtonActionPerformed private void sourceButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_sourceButtonActionPerformed if (htmlSourceMode) { htmlTextPane.setText(htmlTextArea.getText()); mainScrollPane.setViewportView(htmlTextPane); htmlSourceMode = false; setToolbarComponentEnable(this, true); } else { htmlTextArea.setText(htmlTextPane.getText()); mainScrollPane.setViewportView(htmlTextArea); htmlSourceMode = true; setToolbarComponentEnable(this, false); } }// GEN-LAST:event_sourceButtonActionPerformed private void insertHorizontalLineButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_insertHorizontalLineButtonActionPerformed }// GEN-LAST:event_insertHorizontalLineButtonActionPerformed private void insertSpecialCharButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_insertSpecialCharButtonActionPerformed String specialChars = specialCharacterDialog.showDialog(); if (specialChars != null) { new InsertTextAction(this, "Insert Special Character", specialChars).actionPerformed(evt); } }// GEN-LAST:event_insertSpecialCharButtonActionPerformed private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_saveButtonActionPerformed try { File current = new File("."); JFileChooser chooser = new JFileChooser(current); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setFileFilter(new HTMLFileFilter()); for (;;) { int approval = chooser.showSaveDialog(this); if (approval == JFileChooser.APPROVE_OPTION) { File newFile = chooser.getSelectedFile(); if (newFile.exists()) { String message = newFile.getAbsolutePath() + " already exists. \n" + "Do you want to replace it?"; int option = JOptionPane.showConfirmDialog(this, message, "Save", JOptionPane.YES_NO_CANCEL_OPTION); if (option == JOptionPane.YES_OPTION) { File currentFile = newFile; FileWriter fw = new FileWriter(currentFile); fw.write(htmlTextPane.getText()); fw.close(); break; } else if (option == JOptionPane.NO_OPTION) { continue; } else if (option == JOptionPane.CANCEL_OPTION) { break; } } else { File currentFile = new File(newFile.getAbsolutePath()); FileWriter fw = new FileWriter(currentFile); fw.write(htmlTextPane.getText()); fw.close(); break; } } else { break; } } } catch (FileNotFoundException e) { throw new MetaphaseEditorException(e.getMessage(), e); } catch (IOException e) { throw new MetaphaseEditorException(e.getMessage(), e); } }// GEN-LAST:event_saveButtonActionPerformed private void newButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_newButtonActionPerformed if (JOptionPane.showConfirmDialog(this, "Are you sure you want to erase all the current content and start a new document?", "New", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { startNewDocument(); if (htmlSourceMode) { htmlTextArea.setText(htmlTextPane.getText()); } } }// GEN-LAST:event_newButtonActionPerformed private void paragraphFormatComboBoxActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_paragraphFormatComboBoxActionPerformed ParagraphFormat paragraphFormat = (ParagraphFormat) paragraphFormatComboBox.getSelectedItem(); if (paragraphFormat != null && paragraphFormat.getTag() != null) { new FormatAction(this, "Paragraph Format", paragraphFormat.getTag()).actionPerformed(evt); } if (paragraphFormatComboBox.getItemCount() > 0) { paragraphFormatComboBox.setSelectedIndex(0); } }// GEN-LAST:event_paragraphFormatComboBoxActionPerformed private void fontComboBoxActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_fontComboBoxActionPerformed FontItem fontItem = (FontItem) fontComboBox.getSelectedItem(); if (fontItem != null && fontItem.getFontName() != null) { new HTMLEditorKit.FontFamilyAction(fontItem.getText(), fontItem.getFontName()).actionPerformed(evt); } if (fontComboBox.getItemCount() > 0) { fontComboBox.setSelectedIndex(0); } }// GEN-LAST:event_fontComboBoxActionPerformed private void fontSizeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_fontSizeComboBoxActionPerformed FontSize fontSize = (FontSize) fontSizeComboBox.getSelectedItem(); if (fontSize != null && fontSize.getSize() != -1) { new HTMLEditorKit.FontSizeAction(fontSize.getText(), fontSize.getSize()).actionPerformed(evt); } if (fontSizeComboBox.getItemCount() > 0) { fontSizeComboBox.setSelectedIndex(0); } }// GEN-LAST:event_fontSizeComboBoxActionPerformed private void previewButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_previewButtonActionPerformed try { if (htmlSourceMode) { htmlTextPane.setText(htmlTextArea.getText()); } File tempFile = File.createTempFile("metaphaseeditorpreview", ".html"); tempFile.deleteOnExit(); FileWriter fw = new FileWriter(tempFile); fw.write(htmlTextPane.getText()); fw.close(); Desktop.getDesktop().browse(tempFile.toURI()); } catch (IOException e) { throw new MetaphaseEditorException(e.getMessage(), e); } }// GEN-LAST:event_previewButtonActionPerformed private void insertTableButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_insertTableButtonActionPerformed TableDialog tableDialog = new TableDialog(null, true); String tableHtml = tableDialog.showDialog(); if (tableHtml != null) { try { editorKit.insertHTML(htmlDocument, htmlTextPane.getCaretPosition(), tableHtml, 0, 0, Tag.TABLE); refreshAfterAction(); } catch (BadLocationException e) { throw new MetaphaseEditorException(e.getMessage(), e); } catch (IOException e) { throw new MetaphaseEditorException(e.getMessage(), e); } } }// GEN-LAST:event_insertTableButtonActionPerformed private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_openButtonActionPerformed try { File current = new File("."); JFileChooser chooser = new JFileChooser(current); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setFileFilter(new HTMLFileFilter()); int approval = chooser.showOpenDialog(this); if (approval == JFileChooser.APPROVE_OPTION) { File currentFile = chooser.getSelectedFile(); if (currentFile.exists()) { FileReader fr = new FileReader(currentFile); Document oldDoc = htmlTextPane.getDocument(); if (oldDoc != null) { oldDoc.removeUndoableEditListener(undoHandler); } htmlDocument = (HTMLDocument) editorKit.createDefaultDocument(); editorKit.read(fr, htmlDocument, 0); htmlDocument.addUndoableEditListener(undoHandler); htmlTextPane.setDocument(htmlDocument); resetUndoManager(); } else { JOptionPane.showMessageDialog(null, "The selected file does not exist.", "Error", JOptionPane.ERROR_MESSAGE); } } } catch (BadLocationException e) { throw new MetaphaseEditorException(e.getMessage(), e); } catch (FileNotFoundException e) { throw new MetaphaseEditorException(e.getMessage(), e); } catch (IOException e) { throw new MetaphaseEditorException(e.getMessage(), e); } }// GEN-LAST:event_openButtonActionPerformed private void pasteAsTextButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_pasteAsTextButtonActionPerformed Clipboard clipboard = getToolkit().getSystemClipboard(); Transferable transferable = clipboard.getContents(null); if (transferable != null) { try { String plainText = (String) transferable.getTransferData(DataFlavor.stringFlavor); plainText = plainText.replaceAll("\\r\\n", "<br/>"); plainText = plainText.replaceAll("\\n", "<br/>"); plainText = plainText.replaceAll("\\r", "<br/>"); new InsertHtmlAction(this, "Paste as Text", "<p>" + plainText + "</p>", Tag.P).actionPerformed(null); } catch (UnsupportedFlavorException e) { throw new MetaphaseEditorException(e.getMessage(), e); } catch (IOException e) { throw new MetaphaseEditorException(e.getMessage(), e); } } }// GEN-LAST:event_pasteAsTextButtonActionPerformed private void htmlTextPaneMouseClicked(java.awt.event.MouseEvent evt) {// GEN-FIRST:event_htmlTextPaneMouseClicked if (evt.getButton() == MouseEvent.BUTTON3) { for (int i = 0; i < contextMenuListeners.size(); i++) { contextMenuListeners.get(i).beforeContextMenuPopup(); } contextMenu.show(evt.getComponent(), evt.getX(), evt.getY()); } }// GEN-LAST:event_htmlTextPaneMouseClicked private void anchorButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_anchorButtonActionPerformed AnchorDialog anchorDialog = new AnchorDialog(null, true); String anchorHtml = anchorDialog.showDialog(); if (anchorHtml != null) { new InsertHtmlAction(this, "Anchor", anchorHtml, Tag.A).actionPerformed(evt); } }// GEN-LAST:event_anchorButtonActionPerformed private void insertImageActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_insertImageActionPerformed insertImageRequestHandler.insertImage(htmlTextPane); }// GEN-LAST:event_insertImageActionPerformed private void insertRemoveBulletedListButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_insertRemoveBulletedListButtonActionPerformed new HTMLEditorKit.InsertHTMLTextAction("Insert Bulleted List", "<ul><li></li></ul>", Tag.BODY, Tag.UL).actionPerformed(evt); }// GEN-LAST:event_insertRemoveBulletedListButtonActionPerformed private void htmlTextPaneKeyPressed(java.awt.event.KeyEvent evt) {// GEN-FIRST:event_htmlTextPaneKeyPressed }// GEN-LAST:event_htmlTextPaneKeyPressed private void htmlTextPaneKeyReleased(java.awt.event.KeyEvent evt) {// GEN-FIRST:event_htmlTextPaneKeyReleased }// GEN-LAST:event_htmlTextPaneKeyReleased private void htmlTextPaneKeyTyped(java.awt.event.KeyEvent evt) {// GEN-FIRST:event_htmlTextPaneKeyTyped if (evt.getKeyChar() == KeyEvent.VK_ENTER) { } }// GEN-LAST:event_htmlTextPaneKeyTyped private void createDivButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_createDivButtonActionPerformed DivDialog divDialog = new DivDialog(null, true); String divHtml = divDialog.showDialog(); if (divHtml != null) { try { editorKit.insertHTML(htmlDocument, htmlTextPane.getCaretPosition(), divHtml, 0, 0, Tag.DIV); refreshAfterAction(); } catch (BadLocationException e) { throw new MetaphaseEditorException(e.getMessage(), e); } catch (IOException e) { throw new MetaphaseEditorException(e.getMessage(), e); } } }// GEN-LAST:event_createDivButtonActionPerformed private void linkButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_linkButtonActionPerformed LinkDialog linkDialog = new LinkDialog(null, true); String html = linkDialog.showDialog(); if (html != null) { new InsertHtmlAction(this, "Anchor", html, Tag.A).actionPerformed(evt); } }// GEN-LAST:event_linkButtonActionPerformed private void spellcheckButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_spellcheckButtonActionPerformed // JOptionPane.showMessageDialog(null, // "The spelling checker functionality is currently unavailable."); Thread thread = new Thread() { @Override public void run() { try { spellChecker.spellCheck(htmlTextPane); JOptionPane.showMessageDialog(null, "The spelling check is complete.", "Check Spelling", JOptionPane.INFORMATION_MESSAGE); } catch (Exception ex) { throw new MetaphaseEditorException(ex.getMessage(), ex); } } }; thread.start(); }// GEN-LAST:event_spellcheckButtonActionPerformed private void createParagraphButtonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_createParagraphButtonActionPerformed new InsertHtmlAction(this, "Paragraph", "<p>TODO: modify paragraph contents</p>", Tag.P).actionPerformed(evt); }// GEN-LAST:event_createParagraphButtonActionPerformed private void setToolbarFocusActionListener(JComponent component) { Component[] vComponents = component.getComponents(); for (int i = 0; i < vComponents.length; i++) { if (vComponents[i] instanceof JButton) { JButton button = (JButton) vComponents[i]; button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { htmlTextPane.requestFocusInWindow(); } }); } else if (vComponents[i] instanceof JComboBox) { JComboBox comboBox = (JComboBox) vComponents[i]; comboBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { htmlTextPane.requestFocusInWindow(); } }); } else if (vComponents[i] instanceof JPanel) { JPanel panel = (JPanel) vComponents[i]; setToolbarFocusActionListener(panel); } } } private void setToolbarComponentEnable(JComponent component, boolean enabled) { Component[] vComponents = component.getComponents(); for (int i = 0; i < vComponents.length; i++) { if (vComponents[i] == sourceButton || vComponents[i] == newButton || vComponents[i] == previewButton || vComponents[i] == aboutButton) { return; } else if (vComponents[i] instanceof JButton) { JButton button = (JButton) vComponents[i]; button.setEnabled(enabled); } else if (vComponents[i] instanceof JComboBox) { JComboBox comboBox = (JComboBox) vComponents[i]; comboBox.setEnabled(enabled); } else if (vComponents[i] instanceof JPanel) { JPanel panel = (JPanel) vComponents[i]; setToolbarComponentEnable(panel, enabled); } } } public void addContextMenuListener(ContextMenuListener contextMenuListener) { contextMenuListeners.add(contextMenuListener); } public void removeContextMenuListener(ContextMenuListener contextMenuListener) { contextMenuListeners.remove(contextMenuListener); } public ImageInsertRequestHandler getInsertImageRequestHandler() { return insertImageRequestHandler; } public void setInsertImageRequestHandler(ImageInsertRequestHandler insertImageRequestHandler) { if (insertImageRequestHandler != null) { this.insertImageRequestHandler = insertImageRequestHandler; } else { this.insertImageRequestHandler = new DefaultImageInsertRequestHandler(); } } public void initSpellChecker() { try { ZipInputStream zipInputStream = null; InputStream inputStream = null; if (spellCheckDictionaryVersion == SpellCheckDictionaryVersion.CUSTOM) { if (customDictionaryFilename == null) { throw new MetaphaseEditorException( "The dictionary version has been set to CUSTOM but no custom dictionary file name has been specified."); } inputStream = new FileInputStream(customDictionaryFilename); } else { inputStream = new FileInputStream(spellCheckDictionaryVersion.getFile());// this.getClass().getResourceAsStream(spellCheckDictionaryVersion.getFilename()); } zipInputStream = new ZipInputStream(inputStream); zipInputStream.getNextEntry(); dictionary = new SpellDictionaryHashMap(new BufferedReader(new InputStreamReader(zipInputStream))); spellChecker = new JTextComponentSpellChecker(dictionary, null, "Check Spelling"); } catch (FileNotFoundException e) { throw new MetaphaseEditorException(e.getMessage(), e); } catch (IOException e) { throw new MetaphaseEditorException(e.getMessage(), e); } } public void setCustomDictionaryFilename(String customDictionaryFilename) { this.customDictionaryFilename = customDictionaryFilename; } public String getCustomDictionaryFilename() { return customDictionaryFilename; } public void setDictionaryVersion(SpellCheckDictionaryVersion spellCheckDictionaryVersion) { this.spellCheckDictionaryVersion = spellCheckDictionaryVersion; initSpellChecker(); } public SpellCheckDictionaryVersion getDictionaryVersion() { return spellCheckDictionaryVersion; } class SubscriptAction extends StyledEditorKit.StyledTextAction { public SubscriptAction() { super(StyleConstants.Subscript.toString()); } @Override public void actionPerformed(ActionEvent ae) { JEditorPane editor = getEditor(ae); if (editor != null) { boolean subscript = StyleConstants.isSubscript(getStyledEditorKit(editor).getInputAttributes()) ? false : true; SimpleAttributeSet sas = new SimpleAttributeSet(); StyleConstants.setSubscript(sas, subscript); setCharacterAttributes(editor, sas, false); } } } class SuperscriptAction extends StyledEditorKit.StyledTextAction { public SuperscriptAction() { super(StyleConstants.Superscript.toString()); } @Override public void actionPerformed(ActionEvent ae) { JEditorPane editor = getEditor(ae); if (editor != null) { StyledEditorKit kit = getStyledEditorKit(editor); boolean superscript = StyleConstants.isSuperscript(kit.getInputAttributes()) ? false : true; SimpleAttributeSet sas = new SimpleAttributeSet(); StyleConstants.setSuperscript(sas, superscript); setCharacterAttributes(editor, sas, false); } } } class StrikeThroughAction extends StyledEditorKit.StyledTextAction { public StrikeThroughAction() { super(StyleConstants.StrikeThrough.toString()); } @Override public void actionPerformed(ActionEvent ae) { JEditorPane editor = getEditor(ae); if (editor != null) { StyledEditorKit kit = getStyledEditorKit(editor); boolean strikeThrough = StyleConstants.isStrikeThrough(kit.getInputAttributes()) ? false : true; SimpleAttributeSet sas = new SimpleAttributeSet(); StyleConstants.setStrikeThrough(sas, strikeThrough); setCharacterAttributes(editor, sas, false); } } } class BackgroundColorAction extends StyledEditorKit.StyledTextAction { private Color color; public BackgroundColorAction(Color color) { super(StyleConstants.Background.toString()); this.color = color; } @Override public void actionPerformed(ActionEvent ae) { JEditorPane editor = getEditor(ae); // Add span Tag String htmlStyle = "background-color: #" + HTMLUtils.toHexString(color); SimpleAttributeSet attr = new SimpleAttributeSet(); attr.addAttribute(HTML.Attribute.STYLE, htmlStyle); MutableAttributeSet outerAttr = new SimpleAttributeSet(); outerAttr.addAttribute(HTML.Tag.SPAN, attr); // Next line is just an instruction to editor to change color StyleConstants.setBackground(outerAttr, this.color); setCharacterAttributes(editor, outerAttr, false); } } class InsertBreakAction extends HTMLEditorKit.InsertHTMLTextAction { private final Action insertBreakAction; private final Action deletePreviousCharAction; public InsertBreakAction(Action insertBreakAction, Action deletePreviousCharAction) { super(DefaultEditorKit.insertBreakAction, null, null, null, null, null); this.insertBreakAction = insertBreakAction; this.deletePreviousCharAction = deletePreviousCharAction; } @Override public void actionPerformed(ActionEvent ae) { try { Element parentListTag = getParentTag(HTML.Tag.UL); if (parentListTag == null) { parentListTag = getParentTag(HTML.Tag.OL); } if (parentListTag != null) { Element li = getParentTag(HTML.Tag.LI); int start = li.getStartOffset(); final int end = li.getEndOffset(); String liText = htmlTextPane.getText(start, end - start); boolean content = false; for (int i = 0; i < liText.length() && !content; i++) { if (!Character.isWhitespace(liText.charAt(i))) { content = true; } } if (content) { htmlDocument.insertAfterEnd(li, "<li></li>"); htmlTextPane.setText(getDocument()); htmlTextPane.setCaretPosition(end); } else { deletePreviousCharAction.actionPerformed(ae); htmlDocument.insertAfterEnd(parentListTag, "<p></p>"); htmlTextPane.setText(getDocument()); htmlTextPane.setCaretPosition(Math.min(Math.max(0, end - 1), htmlDocument.getLength())); } } else if (insertBreakAction != null) { insertBreakAction.actionPerformed(ae); } } catch (BadLocationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } class UndoHandler implements UndoableEditListener { /** * Messaged when the Document has created an edit, the edit is added to <code>undo</code>, an instance of UndoManager. */ @Override public void undoableEditHappened(UndoableEditEvent e) { undo.addEdit(e.getEdit()); undoAction.update(); redoAction.update(); } } class UndoAction extends AbstractAction { public UndoAction() { super("Undo"); setEnabled(false); } @Override public void actionPerformed(ActionEvent actionEvent) { try { undo.undo(); } catch (CannotUndoException e) { throw new MetaphaseEditorException(e.getMessage(), e); } update(); redoAction.update(); } protected void update() { if (undo.canUndo()) { setEnabled(true); } else { setEnabled(false); } } } class RedoAction extends AbstractAction { public RedoAction() { super("Redo"); setEnabled(false); } @Override public void actionPerformed(ActionEvent actionEvent) { try { undo.redo(); } catch (CannotRedoException e) { throw new MetaphaseEditorException(e.getMessage(), e); } update(); undoAction.update(); } protected void update() { if (undo.canRedo()) { setEnabled(true); } else { setEnabled(false); } } } class HTMLFileFilter extends javax.swing.filechooser.FileFilter { @Override public boolean accept(File f) { return f.isDirectory() || f.getName().toLowerCase().indexOf(".htm") > 0; } @Override public String getDescription() { return "html"; } } class ParagraphFormatListCellRenderer extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (index == 0) { component.setEnabled(false); } ParagraphFormat paragraphFormat = (ParagraphFormat) value; if (paragraphFormat.getTag() != null) { JLabel label = (JLabel) component; // label.setText("<html><" + paragraphFormat.getTag().toString() // + ">" + label.getText() + "</" + // paragraphFormat.getTag().toString() + ">"); } return component; } } class FontListCellRenderer extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (index == 0) { component.setEnabled(false); } FontItem fontItem = (FontItem) value; if (fontItem.getFontName() != null) { Font currentFont = component.getFont(); component.setFont(new Font(fontItem.getFontName(), currentFont.getStyle(), currentFont.getSize())); } return component; } } class FontSizeListCellRenderer extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (index == 0) { component.setEnabled(false); } FontSize fontSize = (FontSize) value; if (fontSize.getSize() != -1) { Font currentFont = component.getFont(); component.setFont(new Font(currentFont.getName(), currentFont.getStyle(), fontSize.getSize())); } return component; } } class DefaultEditorMouseMotionListener implements MouseMotionListener { @Override public void mouseDragged(MouseEvent me) { int pos = htmlTextPane.viewToModel(me.getPoint()); if (pos >= 0) { Element element = htmlDocument.getParagraphElement(pos); MutableAttributeSet attributes = new SimpleAttributeSet(element.getAttributes()); EditorMouseEvent editorMouseEvent = new EditorMouseEvent(); editorMouseEvent.setNearestParagraphAttributes(attributes); for (int i = 0; i < editorMouseMotionListeners.size(); i++) { editorMouseMotionListeners.get(i).mouseDragged(editorMouseEvent); } } } @Override public void mouseMoved(MouseEvent me) { int pos = htmlTextPane.viewToModel(me.getPoint()); if (pos >= 0) { Element element = htmlDocument.getParagraphElement(pos); MutableAttributeSet attributes = new SimpleAttributeSet(element.getAttributes()); EditorMouseEvent editorMouseEvent = new EditorMouseEvent(); editorMouseEvent.setNearestParagraphAttributes(attributes); for (int i = 0; i < editorMouseMotionListeners.size(); i++) { editorMouseMotionListeners.get(i).mouseMoved(editorMouseEvent); } } } } class DefaultImageInsertRequestHandler implements ImageInsertRequestHandler { @Override public void insertImage(JTextPane htmlTextPane) { try { ImageDialog imageDialog = new ImageDialog(SwingUtilities.windowForComponent(htmlTextPane), true); String html = imageDialog.showDialog(); if (html != null) { if (imageDialog.isLink()) { editorKit.insertHTML(htmlDocument, htmlTextPane.getCaretPosition(), html, 0, 0, Tag.A); } else { editorKit.insertHTML(htmlDocument, htmlTextPane.getCaretPosition(), html, 0, 0, Tag.IMG); } refreshAfterAction(); } } catch (BadLocationException e) { throw new MetaphaseEditorException(e.getMessage(), e); } catch (IOException e) { throw new MetaphaseEditorException(e.getMessage(), e); } } } }