com.rapidminer.gui.flow.processrendering.annotations.AnnotationDrawUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.rapidminer.gui.flow.processrendering.annotations.AnnotationDrawUtils.java

Source

/**
 * Copyright (C) 2001-2015 by RapidMiner and the contributors
 *
 * Complete list of developers available at our web site:
 *
 *      http://rapidminer.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.flow.processrendering.annotations;

import java.io.IOException;
import java.io.StringWriter;

import javax.swing.JEditorPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.html.HTMLDocument;

import org.apache.commons.lang.StringEscapeUtils;

import com.rapidminer.gui.flow.processrendering.annotations.model.WorkflowAnnotation;
import com.rapidminer.gui.flow.processrendering.annotations.style.AnnotationStyle;
import com.rapidminer.tools.SystemInfoUtilities;
import com.rapidminer.tools.SystemInfoUtilities.OperatingSystem;

/**
 * Utility methods for {@link WorkflowAnnotation}s.
 *
 * @author Marco Boeck
 * @since 6.4.0
 *
 */
public final class AnnotationDrawUtils {

    /** surrounding HTML for annotations where styling information can be set */
    private static final String ANNOTATION_HTML_FORMAT = "<div id=\"anno_style_div\" style=\"font-size: 10px; font-family: 'Open Sans'; padding: %dpx; %s\">%s</div>";

    /** this is removed from the beginning of the document */
    private static final String ANNOTATION_HTML_FORMATTING_START_REGEX = "\\s*<html>\\s*(<head>)?\\s*.*\\s*(</head>)?\\s*<body>\\s*";

    /** this is removed from the end of the document */
    private static final String ANNOTATION_HTML_FORMATTING_END_REGEX = "\\s*</body>\\s*</html>\\s*";

    /** divs are forbidden because we use them to style the annotation globally */
    private static final String ANNOTATION_HTML_FORMATTING_MISC_DIV_START = "<div(.*?)>";

    /** divs are forbidden because we use them to style the annotation globally */
    private static final String ANNOTATION_HTML_FORMATTING_MISC_DIV_END = "</div>";

    /** the signal we fake everytime the user enters a newline */
    public static final String ANNOTATION_HTML_NEWLINE_SIGNAL = "\r";

    /**
     * Private constructor which throws if called.
     */
    private AnnotationDrawUtils() {
        throw new UnsupportedOperationException("Static utility class");
    }

    /**
     * Creates a HTML document which applies the style information from the given annotation.
     *
     * @param annotation
     *            the annotation for which to create the full HTML document
     * @return the HTML document as a string
     */
    public static String createStyledCommentString(final WorkflowAnnotation annotation) {
        if (annotation == null) {
            throw new IllegalArgumentException("annotation must not be null!");
        }
        return createStyledCommentString(annotation.getComment(), annotation.getStyle());
    }

    /**
     * Creates a HTML document which applies the style information from the given annotation.
     *
     * @param comment
     *            the comment for which to create the full HTML document
     * @param style
     *            the style which should be used to style the comment
     * @return the HTML document as a string
     */
    public static String createStyledCommentString(final String comment, final AnnotationStyle style) {
        if (comment == null) {
            throw new IllegalArgumentException("comment must not be null!");
        }
        if (style == null) {
            throw new IllegalArgumentException("style must not be null!");
        }
        return String.format(ANNOTATION_HTML_FORMAT, style.getPadding(), style.getAnnotationAlignment().getCSS(),
                comment);
    }

    /**
     * This method removes styling information from the HTML comment.
     * <p>
     * <strong>Attention:</strong> It is not possible to use Regex to parse arbitrary HTML!! This
     * will fail horribly in case the user entered complex HTML! Works fine for simple HTML without
     * tables etc.
     * </p>
     *
     * @param comment
     *            the comment to remove styling information from
     * @return the sanitized comment
     */
    public static String removeStyleFromComment(final String comment) {
        if (comment == null) {
            throw new IllegalArgumentException("comment must not be null!");
        }
        String newComment = comment.replaceAll(ANNOTATION_HTML_FORMATTING_START_REGEX, "");
        newComment = newComment.replaceAll(ANNOTATION_HTML_FORMATTING_END_REGEX, "");
        // replace potential occurances of any divs
        newComment = newComment.replaceAll(ANNOTATION_HTML_FORMATTING_MISC_DIV_START, "");
        newComment = newComment.replaceAll(ANNOTATION_HTML_FORMATTING_MISC_DIV_END, "");

        // IMPORTANT: convert newline signal to HTML linebreak
        newComment = newComment.replaceAll(ANNOTATION_HTML_NEWLINE_SIGNAL, "<br/>");

        // remove superflous whitespaces
        newComment = newComment.replaceAll("\n", "");
        newComment = newComment.replaceAll("\\s+", " ");
        newComment = newComment.trim();
        return newComment;
    }

    /**
     * Returns plain text from the editor.
     *
     * @param editor
     *            the editor from which to take the text.
     * @param onlySelected
     *            if {@code true} will only return the selected text
     * @return the text of the editor converted to plain text
     * @throws BadLocationException
     * @throws IOException
     */
    public static String getPlaintextFromEditor(final JEditorPane editor, final boolean onlySelected)
            throws IOException, BadLocationException {
        if (editor == null) {
            throw new IllegalArgumentException("editor must not be null!");
        }
        HTMLDocument document = (HTMLDocument) editor.getDocument();
        StringWriter writer = new StringWriter();
        int start = 0;
        int length = document.getLength();
        if (onlySelected) {
            start = editor.getSelectionStart();
            length = editor.getSelectionEnd() - start;
        }
        editor.getEditorKit().write(writer, document, start, length);
        String text = writer.toString();
        text = AnnotationDrawUtils.removeStyleFromComment(text);
        // switch <br> and <br/> to actual newline (current system)
        text = text.replaceAll("<br.*?>", System.lineSeparator());
        // kill all other html tags
        text = text.replaceAll("\\<.*?>", "");
        text = StringEscapeUtils.unescapeHtml(text);
        return text;
    }

    /**
     * Calculates the preferred height of an editor pane with the given fixed width for the
     * specified string.
     *
     * @param comment
     *            the annotation comment string
     * @param width
     *            the width of the content
     * @return the preferred height given the comment
     */
    public static int getContentHeight(final String comment, final int width) {
        if (comment == null) {
            throw new IllegalArgumentException("comment must not be null!");
        }
        JEditorPane dummyEditorPane = new JEditorPane("text/html", "");
        dummyEditorPane.setText(comment);
        dummyEditorPane.setBorder(null);
        dummyEditorPane.setSize(width, Short.MAX_VALUE);

        // height is not exact. Multiply by magic number to get a more fitting value...
        if (SystemInfoUtilities.getOperatingSystem() == OperatingSystem.OSX
                || SystemInfoUtilities.getOperatingSystem() == OperatingSystem.UNIX
                || SystemInfoUtilities.getOperatingSystem() == OperatingSystem.SOLARIS) {
            return (int) (dummyEditorPane.getPreferredSize().getHeight() * 1.05f);
        } else {
            return (int) dummyEditorPane.getPreferredSize().getHeight();
        }
    }
}