/**
* Copyright (C) 2001-2017 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.model;
import java.awt.geom.Rectangle2D;
import java.util.UUID;
import com.rapidminer.gui.flow.processrendering.annotations.AnnotationsVisualizer;
import com.rapidminer.gui.flow.processrendering.annotations.style.AnnotationStyle;
import com.rapidminer.gui.flow.processrendering.view.ProcessRendererView;
import com.rapidminer.operator.ExecutionUnit;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.OperatorChain;
/**
* Describes a single workflow annotation shown in the {@link ProcessRendererView} via the
* {@link AnnotationsVisualizer}. An annotation can either be set to an arbitrary location in the
* process or it can be attached to an {@link Operator}. It mainly consists of HTML text as well as
* some specific styling options via CSS.
*
* @author Marco Boeck
* @since 6.4.0
*
*/
public abstract class WorkflowAnnotation {
/** the minimum x coordinate an annotation can have */
public static final int MIN_X = 10;
/** the minimum y coordinate an annotation can have */
public static final int MIN_Y = 10;
/** the actual annotation as HTML */
private String comment;
/** the style for this comment */
private AnnotationStyle style;
/** the location (coordinates and size) of the annotation */
private Rectangle2D location;
/** indicating if the user ever resized the annotation */
private boolean wasResized;
/** indicating if the user ever manually assigned a color */
private boolean wasColored;
/** if this annotation is overflowing on y axis */
private boolean overflowing;
/** a unique ID only relevant during Studio session */
private UUID id;
/**
* Creates a new workflow annotation which just has width and height.
*
* @param comment
* the actual annotation as HTML
* @param style
* the style of the annotation
* @param wasResized
* if the user has ever resized the annotation
* @param wasColored
* if the user ever manually colored the annotation
* @param width
* the width of the annotation
* @param height
* the height of the annotation
*/
protected WorkflowAnnotation(final String comment, final AnnotationStyle style, final boolean wasResized,
final boolean wasColored, final double width, final double height) {
this(comment, style, wasResized, wasColored, new Rectangle2D.Double(0, 0, width, height));
}
/**
* Creates a new workflow annotation which is freely positioned in the given
* {@link OperatorChain}.
*
* @param comment
* the actual annotation as HTML
* @param style
* the style of the annotation
* @param wasResized
* if the user has ever resized the annotation
* @param wasColored
* if the user ever manually colored the annotation
* @param location
* the location of the annotation
*
*/
protected WorkflowAnnotation(final String comment, final AnnotationStyle style, final boolean wasResized,
final boolean wasColored, final Rectangle2D location) {
if (comment == null) {
throw new IllegalArgumentException("comment must not be null!");
}
if (style == null) {
throw new IllegalArgumentException("style must not be null!");
}
if (location == null) {
throw new IllegalArgumentException("location must not be null!");
}
this.comment = comment;
this.style = style;
this.location = new Rectangle2D.Double();
this.location.setFrame(location.getFrame());
this.wasResized = wasResized;
this.wasColored = wasColored;
this.id = UUID.randomUUID();
}
/**
* Returns the actual annotation as HTML.
*
* @return the comment, never {@code null}
*/
public String getComment() {
return comment;
}
/**
* Sets the actual annotation comment. Supports HTML.
*
* @param comment
* the comment, never {@code null}
*/
public void setComment(final String comment) {
if (comment == null) {
throw new IllegalArgumentException("comment must not be null!");
}
this.comment = comment;
}
/**
* Returns the styling information.
*
* @return the style, never {@code null}
*/
public AnnotationStyle getStyle() {
return style;
}
/**
* Returns the location of this annotation. X and Y coordinates may not be set.
*
* @return the location, never {@code null}
*/
public Rectangle2D getLocation() {
return location;
}
/**
* Sets the location of this annotation.
*
* @param location
* the location, never {@code null}
*/
public void setLocation(Rectangle2D location) {
if (location == null) {
throw new IllegalArgumentException("location must not be null!");
}
this.location = location;
}
/**
* Returns whether this annotation was ever resized by the user. An annotation that has been
* manually resized will never resize itself automatically again.
*
* @return {@code true} if the user has manually resized this annotation; {@code false}
* otherwise
*/
public boolean wasResized() {
return wasResized;
}
/**
* Call if the annotation has been manually resized by the user. After this has been called,
* {@link #wasResized()} will always return {@code true}.
*/
public void setResized() {
wasResized = true;
}
/**
* Returns whether this annotation was ever manually colored by the user. An annotation that has
* been manually colored will never change its color automatically again.
*
* @return {@code true} if the user has manually colored this annotation; {@code false}
* otherwise
*/
public boolean wasColored() {
return wasColored;
}
/**
* Call if the annotation has been manually colored by the user. After this has been called,
* {@link #wasColored()} will always return {@code true}.
*/
public void setColored() {
wasColored = true;
}
/**
* Return a unique ID of this annotation. Generated anew for each Studio session.
*
* @return the id, never {@code null}
*/
public UUID getId() {
return id;
}
/**
* Notifies the process that something has changed and thus enables save action etc.
*/
public abstract void fireUpdate();
/**
* Returns the {@link ExecutionUnit} this annotation is located in.
*
* @return the process, never {@code null}
*/
public abstract ExecutionUnit getProcess();
/**
* Returns whether this annotation text is overflowing on the y axis.
*
* @return {@code true} if it is; {@code false} otherwise
*/
public boolean isOverflowing() {
return overflowing;
}
/**
* Sets whether this annotation text is overflowing on the y axis.
*
* @return {@code true} if it is; {@code false} otherwise
*/
public void setOverflowing(boolean overflowing) {
this.overflowing = overflowing;
}
/**
* Creates a new {@link OperatorAnnotation} based on this annotation. Can be used to either
* clone an operator annotation or to convert a process annotation.
*
* @param attachedTo
* the operator the annotation should be attached to
* @return the annotation instance, never {@code null}
*/
public abstract OperatorAnnotation createOperatorAnnotation(Operator attachedTo);
/**
* Creates a new {@link ProcessAnnotation} based on this annotation. Can be used to either clone
* a process annotation or to convert an operator annotation.
*
* @param process
* the process the annotation should be attached to
* @return the annotation instance, never {@code null}
*/
public abstract ProcessAnnotation createProcessAnnotation(ExecutionUnit process);
@Override
public String toString() {
return "WorkflowAnnotation [comment=" + comment + ", style=" + style + ", location=" + location + "]";
}
}