/* * RapidMiner * * Copyright (C) 2001-2011 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ActionEvent; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JMenu; import javax.swing.JToolBar; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import javax.swing.text.html.HTMLDocument; import javax.swing.text.html.HTMLEditorKit; import com.rapidminer.Process; import com.rapidminer.gui.operatormenu.OperatorMenu; import com.rapidminer.gui.tools.ExtendedJToolBar; import com.rapidminer.gui.tools.ResourceAction; import com.rapidminer.operator.Operator; import com.rapidminer.operator.OperatorDescription; import com.rapidminer.parameter.ParameterType; import com.rapidminer.tools.LogService; import com.rapidminer.tools.documentation.OperatorDocumentation; /** Extends the standard operator documentation viewer with edit functionality. * * @author Simon Fischer, Tobias Malbrecht * */ public class OperatorDocEditor extends OperatorDocViewer { private static final long serialVersionUID = 3341472230093161784L; private static final String[] EDIT_ACTION_NAMES = { "font-bold", "font-italic", "InsertOrderedList", "InsertOrderedListItem", "InsertUnorderedList", "InsertUnorderedListItem" }; private final List<Action> editActions = new LinkedList<Action>(); private final Action clearAction = new ResourceAction(true, "operatorhelp.clear") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { getEditor().setText("<html><head></head><body></body></html>"); getEditor().requestFocus(); } }; private final Action applyChanges = new ResourceAction(true, "operatorhelp.apply_changes") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { if (editWhat != null) { String strippedHtml = stripHtmlFrame(getEditor().getText()); if (editWhat.equals("edit_description")) { OperatorDocumentation doc = getDisplayedOperator().getOperatorDescription().getOperatorDocumentation(); if (doc != null) { doc.setDocumentation(strippedHtml); } } else if (editWhat.equals("edit_synopsis")) { OperatorDocumentation doc = getDisplayedOperator().getOperatorDescription().getOperatorDocumentation(); if (doc != null) { doc.setSynopsis(strippedHtml); } } else if (editWhat.startsWith("edit_parameter_")) { } setEditEnabled(false); showHelptext(); } } }; private final Action discardChanges = new ResourceAction(true, "operatorhelp.discard_changes") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { if (editWhat != null) { setEditEnabled(false); showHelptext(); } } }; private final Action addExample = new ResourceAction(true, "operatorhelp.add_example") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { Process current = RapidMinerGUI.getMainFrame().getProcess(); getDisplayedOperator().getOperatorDescription().getOperatorDocumentation().addExample(current, current.getRootOperator().getUserDescription()); showHelptext(); } }; private final Action insertOpLink = new ResourceAction(true, "operatorhelp.insert_operator_link") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { JMenu menu = new OperatorMenu("test", false) { private static final long serialVersionUID = 1L; @Override public void performAction(OperatorDescription description) { try { String link = "<a href=\"rm://opdoc/"+description.getKey()+"\">"+description.getName()+"</a>"; ((HTMLEditorKit)getEditor().getEditorKit()).insertHTML((HTMLDocument) getEditor().getDocument(), getEditor().getCaretPosition(), link, 0, 0, null); } catch (Exception e) { LogService.getRoot().log(Level.WARNING, "Error inserting link: "+e.toString(), e); } } }; menu.getPopupMenu().show(insertOpLinkButton, 0, insertOpLinkButton.getHeight()); } }; private final JButton insertOpLinkButton = new JButton(insertOpLink); { insertOpLinkButton.setText(null); } private String editWhat; private boolean isEditing = false; public OperatorDocEditor() { final JToolBar toolBar = new ExtendedJToolBar(); toolBar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.LIGHT_GRAY)); toolBar.add(addExample); toolBar.addSeparator(); toolBar.add(applyChanges); toolBar.add(discardChanges); toolBar.addSeparator(); toolBar.add(clearAction); toolBar.add(insertOpLinkButton); Map<String,Action> actionMap = new HashMap<String,Action>(); for (final Action action : getEditor().getActions()) { actionMap.put((String) action.getValue(Action.NAME), action); } for (final String editActionName : EDIT_ACTION_NAMES) { final Action editAction = actionMap.get(editActionName); editActions.add(new ResourceAction(true, "operatorhelp." + (String) editAction.getValue(Action.NAME)) { private static final long serialVersionUID = -8259341536856732400L; @Override public void actionPerformed(ActionEvent e) { editAction.actionPerformed(e); } }); } for (final Action action : editActions) { toolBar.add(action); } add(toolBar, BorderLayout.NORTH); setEditEnabled(false); getEditor().addHyperlinkListener(new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { if (e.getDescription().startsWith("edit_")) { edit(e.getDescription()); } else if (e.getDescription().startsWith("delete_example_")) { int index = Integer.parseInt(e.getDescription().substring("delete_example_".length())); getDisplayedOperator().getOperatorDescription().getOperatorDocumentation().removeExample(index); showHelptext(); } } } }); } // @Override // protected Object makeExampleFooter(int exampleIndex) { // return super.makeExampleFooter(exampleIndex) + " <small><a href=\"delete_example_"+exampleIndex+"\">(delete)</a></small>"; // } // // @Override // protected String makeSynopsisHeader() { // return "<h4>Synopsis <small><a href=\"edit_synopsis\">(edit)</a></small></h4>"; // } // // @Override // protected String makeDescriptionHeader() { // return "<h4>Description <small><a href=\"edit_description\">(edit)</a></h4>"; // } // // @Override // protected String makeParameterHeader(ParameterType type) { // return super.makeParameterHeader(type) + " <small><a href=\"edit_parameter_"+type.getKey()+"\">(edit)</a></small>"; // } /** Enables/disables all actions for editing HTML text.*/ private void setEditEnabled(boolean enabled) { isEditing = enabled; getEditor().getCaret().setVisible(enabled); applyChanges.setEnabled(enabled); discardChanges.setEnabled(enabled); for (Action action : editActions) { action.setEnabled(enabled); } } /** * * @param editWhat Either "synopsis", "description", or "parameter_KEY" where key is a parameter key. */ private void edit(String editWhat) { this.editWhat = editWhat; String initialText = null; if (editWhat.equals("edit_description")) { initialText = getDisplayedOperator().getOperatorDescription().getLongDescriptionHTML(); } else if (editWhat.equals("edit_synopsis")) { initialText = getDisplayedOperator().getOperatorDescription().getShortDescription(); } else if (editWhat.startsWith("edit_parameter_")) { String key = editWhat.substring("edit_parameter_".length()); ParameterType type = getDisplayedOperator().getParameters().getParameterType(key); if (type != null) { initialText = type.getDescription(); } } if (initialText != null) { if (initialText.startsWith("<html>")) { getEditor().setText(initialText); } else { getEditor().setText("<html><head></head><body>"+initialText+"</body></html>"); } getEditor().setEditable(true); setEditEnabled(true); getEditor().requestFocus(true); getEditor().setCaretPosition(0); } } @Override public void setSelection(List<Operator> selection) { if (isEditing) { // Don't disturb me. I am editing. } else { super.setSelection(selection); } } @Override public void setDisplayedOperator(Operator operator) { if (isEditing) { // Don't disturb me. I am editing. } else { super.setDisplayedOperator(operator); } } private static String stripHtmlFrame(String html) { int bodyStart = html.indexOf("<body>"); if (bodyStart != -1) { html = html.substring(bodyStart + "<body>".length()); } int bodyEnd = html.lastIndexOf("</body>"); if (bodyEnd != -1) { html = html.substring(0, bodyEnd); } // change line breaks to brs html = html.replace("\n\n", "</p><p><br>"); html = html.replace("\n", ""); html = html.trim(); if (!html.startsWith("<p>")) html = "<p>" + html + "</p>"; return html; } }