/* * Freeplane - mind map editor * Copyright (C) 2008 Joerg Mueller, Daniel Polansky, Christian Foltin, Dimitry Polivaev * * This file is modified by Dimitry Polivaev in 2008. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.freeplane.features.text.mindmapmode; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.net.URL; import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.RootPaneContainer; import javax.swing.text.JTextComponent; import javax.swing.text.html.HTMLDocument; import javax.swing.text.html.StyleSheet; import org.freeplane.core.resources.ResourceController; import org.freeplane.core.ui.MenuBuilder; import org.freeplane.core.ui.components.UITools; import org.freeplane.core.util.ColorUtils; import org.freeplane.core.util.HtmlUtils; import org.freeplane.core.util.LogUtils; import org.freeplane.core.util.TextUtils; import org.freeplane.features.map.NodeModel; import org.freeplane.features.spellchecker.mindmapmode.SpellCheckerController; import com.lightdev.app.shtm.SHTMLEditorPane; import com.lightdev.app.shtm.SHTMLPanel; /** * @author Daniel Polansky */ public class EditNodeWYSIWYG extends EditNodeBase { private static class HTMLDialog extends EditDialog { /** * */ private static final long serialVersionUID = 1L; private SHTMLPanel htmlEditorPanel; private JButton splitButton; HTMLDialog(final EditNodeBase base, final String title, String purpose, final RootPaneContainer frame) throws Exception { super(base, title, frame); createEditorPanel(purpose); getContentPane().add(htmlEditorPanel, BorderLayout.CENTER); UITools.addEscapeActionToDialog(getDialog(), new CancelAction()); final JButton okButton = new JButton(); final JButton cancelButton = new JButton(); splitButton = new JButton(); MenuBuilder.setLabelAndMnemonic(okButton, TextUtils.getRawText("ok")); MenuBuilder.setLabelAndMnemonic(cancelButton, TextUtils.getRawText("cancel")); MenuBuilder.setLabelAndMnemonic(splitButton, TextUtils.getRawText("split")); okButton.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { submit(); } }); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { cancel(); } }); splitButton.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { split(); } }); UITools.addKeyActionToDialog(getDialog(), new SubmitAction(), "alt ENTER", "submit"); final JPanel buttonPane = new JPanel(); buttonPane.add(okButton); buttonPane.add(cancelButton); buttonPane.add(splitButton); buttonPane.setMaximumSize(new Dimension(1000, 20)); if (ResourceController.getResourceController().getBooleanProperty("el__buttons_above")) { getContentPane().add(buttonPane, BorderLayout.NORTH); } else { getContentPane().add(buttonPane, BorderLayout.SOUTH); } } /* * (non-Javadoc) * @see freeplane.view.mindmapview.EditNodeBase.Dialog#close() */ @Override protected void cancel() { super.cancel(); final StyleSheet styleSheet = htmlEditorPanel.getDocument().getStyleSheet(); styleSheet.removeStyle("p"); styleSheet.removeStyle("BODY"); getBase().getEditControl().cancel(); } private SHTMLPanel createEditorPanel(String purpose) throws Exception { if (htmlEditorPanel == null) { htmlEditorPanel = MTextController.getController().createSHTMLPanel(purpose); final SHTMLEditorPane editorPane = (SHTMLEditorPane) htmlEditorPanel.getEditorPane(); final SpellCheckerController spellCheckerController = SpellCheckerController.getController(); spellCheckerController.enableAutoSpell(editorPane, true); spellCheckerController.addSpellCheckerMenu(editorPane.getPopup()); spellCheckerController.enableShortKey(editorPane, true); } return htmlEditorPanel; } /** * @return Returns the htmlEditorPanel. */ public SHTMLPanel getHtmlEditorPanel() { return htmlEditorPanel; } @Override public Component getMostRecentFocusOwner() { if (getDialog().isFocused()) { return getFocusOwner(); } else { return htmlEditorPanel.getMostRecentFocusOwner(); } } @Override protected boolean isChanged() { return htmlEditorPanel.needsSaving(); } /* * (non-Javadoc) * @see freeplane.view.mindmapview.EditNodeBase.Dialog#split() */ @Override protected void split() { super.split(); final StyleSheet styleSheet = htmlEditorPanel.getDocument().getStyleSheet(); styleSheet.removeStyle("p"); styleSheet.removeStyle("body"); getBase().getEditControl().split(HtmlUtils.unescapeHTMLUnicodeEntity(htmlEditorPanel.getDocumentText()), htmlEditorPanel.getCaretPosition()); } /* * (non-Javadoc) * @see freeplane.view.mindmapview.EditNodeBase.Dialog#close() */ @Override protected void submit() { super.submit(); htmlEditorPanel.getDocument().getStyleSheet().removeStyle("p"); htmlEditorPanel.getDocument().getStyleSheet().removeStyle("body"); if (htmlEditorPanel.needsSaving()) { getBase().getEditControl().ok(HtmlUtils.unescapeHTMLUnicodeEntity(htmlEditorPanel.getDocumentText())); } else { getBase().getEditControl().cancel(); } } public void setSplitEnabled(boolean enableSplit) { splitButton.setEnabled(enableSplit); splitButton.setVisible(enableSplit); } } private static final Dimension PREFERRED_SIZE = new Dimension(600, 400); private String title; private Font font; private Color textColor = Color.BLACK; private Dimension preferredSize = PREFERRED_SIZE; public String getTitle() { return title; } public void setTitle(String purpose) { this.title = purpose; } public Font getFont() { return font; } public void setFont(Font font) { this.font = font; } public Color getTextColor() { return textColor; } public void setTextColor(Color textColor) { this.textColor = textColor; } public Dimension getPreferredSize() { return preferredSize; } public void setPreferredSize(Dimension preferredSize) { this.preferredSize = preferredSize; } public EditNodeWYSIWYG(final NodeModel node, final String text, final IEditControl editControl, boolean enableSplit) { super(node, text, editControl); } public void show(final RootPaneContainer frame) { try { HTMLDialog htmlEditorWindow = createHtmlEditor(frame); htmlEditorWindow.setBase(this); final String titleText; titleText = TextUtils.getText(title); htmlEditorWindow.getDialog().setTitle(titleText); htmlEditorWindow.setSplitEnabled(getEditControl().canSplit()); final SHTMLPanel htmlEditorPanel = (htmlEditorWindow).getHtmlEditorPanel(); final StringBuilder ruleBuilder = new StringBuilder(100); ruleBuilder.append("body {"); if(font != null){ ruleBuilder.append("font-family: ").append(font.getFamily()).append(";"); final int fontSize = Math.round(font.getSize() / UITools.FONT_SCALE_FACTOR); ruleBuilder.append("font-size: ").append(fontSize).append("pt;"); if (font.isItalic()) { ruleBuilder.append("font-style: italic; "); } if (font.isBold()) { ruleBuilder.append("font-weight: bold; "); } } if(textColor != null) ruleBuilder.append("color: ").append(ColorUtils.colorToString(textColor)).append(";"); final Color bgColor = getBackground(); ruleBuilder.append("background-color: ").append(ColorUtils.colorToString(bgColor)).append(";"); ruleBuilder.append("}\n"); ruleBuilder.append("p {margin-top:0;}\n"); final HTMLDocument document = htmlEditorPanel.getDocument(); final JEditorPane editorPane = htmlEditorPanel.getEditorPane(); if(textColor != null){ editorPane.setForeground(textColor); editorPane.setCaretColor(textColor); } final StyleSheet styleSheet = document.getStyleSheet(); styleSheet.removeStyle("p"); styleSheet.removeStyle("body"); styleSheet.addRule(ruleBuilder.toString()); final URL url = node.getMap().getURL(); if (url != null) { document.setBase(url); } else { document.setBase(new URL("file: ")); } htmlEditorPanel.setContentPanePreferredSize(preferredSize); htmlEditorWindow.getDialog().pack(); if (ResourceController.getResourceController().getBooleanProperty("el__position_window_below_node")) { UITools.setDialogLocationUnder(htmlEditorWindow.getDialog(), node); } else { UITools.setDialogLocationRelativeTo(htmlEditorWindow.getDialog(), node); } String content = text; if (!HtmlUtils.isHtmlNode(content)) { content = HtmlUtils.plainToHTML(content); } htmlEditorPanel.setCurrentDocumentContent(content); final KeyEvent firstKeyEvent = MTextController.getController().getEventQueue().getFirstEvent(); final JTextComponent currentPane = htmlEditorPanel.getEditorPane(); if (currentPane == htmlEditorPanel.getMostRecentFocusOwner()) { redispatchKeyEvents(currentPane, firstKeyEvent); if (firstKeyEvent == null) { editorPane.setCaretPosition(htmlEditorPanel.getDocument().getLength()); } } else{ final EventBuffer keyEventDispatcher = MTextController.getController().getEventQueue(); keyEventDispatcher.deactivate(); } htmlEditorPanel.getMostRecentFocusOwner().requestFocus(); htmlEditorWindow.show(); } catch (final Exception ex) { LogUtils.severe("Loading of WYSIWYG HTML editor failed. Use the other editors instead.", ex); } } public HTMLDialog createHtmlEditor(final RootPaneContainer frame) throws Exception { final JRootPane rootPane = ((RootPaneContainer)frame).getRootPane(); HTMLDialog htmlEditorWindow = (HTMLDialog) rootPane.getClientProperty(HTMLDialog.class); if (htmlEditorWindow == null) { htmlEditorWindow = new HTMLDialog(this, "", "", frame); rootPane.putClientProperty(HTMLDialog.class, htmlEditorWindow); // make sure that SHTML gets notified of relevant config changes! ResourceController.getResourceController().addPropertyChangeListener( new FreeplaneToSHTMLPropertyChangeAdapter(htmlEditorWindow.getHtmlEditorPanel())); } return htmlEditorWindow; } }