/**
* Copyright 2010-2014 Jingjing Li.
*
* This file is part of jplot2d.
*
* jplot2d 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 any later version.
*
* jplot2d 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 Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with jplot2d. If not, see .
*/
package org.jplot2d.element.impl;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Collections;
import java.util.Map;
import org.jplot2d.element.Element;
import org.jplot2d.transform.PaperTransform;
public abstract class ComponentImpl extends ElementImpl implements ComponentEx {
private boolean visible = true;
private boolean cacheable;
private boolean selectable;
private boolean movable;
private int zOrder;
private Color color = null;
private String fontName;
private int fontStyle = -1;
private float fontSize = Float.NaN;
private float fontScale = 1;
protected PropertyChangeSupport _changes = new PropertyChangeSupport(this);
private boolean redrawNeeded;
public void addPropertyChangeListener(PropertyChangeListener l) {
_changes.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
_changes.removePropertyChangeListener(l);
}
public ContainerEx getParent() {
return (ContainerEx) parent;
}
public Map getMooringMap() {
return Collections.emptyMap();
}
public boolean canContribute() {
return true;
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
redrawCascade(this);
this.visible = visible;
redrawCascade(this);
}
public boolean isCacheable() {
return cacheable;
}
public void setCacheable(boolean cacheMode) {
// uncacheable -> cacheable:
// 1. eliminate this component from its cacheable parent, mark need redraw,
// 2. put redraw flag on this component
// cacheable -> uncacheable:
// 1. put redraw flag on this component
// 2. put redraw flag on its cacheable parent
redraw(this);
this.cacheable = cacheMode;
redraw(this);
}
public boolean isSelectable() {
return selectable;
}
public void setSelectable(boolean selectable) {
this.selectable = selectable;
}
public boolean isMovable() {
return movable;
}
public void setMovable(boolean movable) {
this.movable = movable;
}
public int getZOrder() {
return zOrder;
}
public void setZOrder(int z) {
this.zOrder = z;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
Color oldEC = getEffectiveColor();
this.color = color;
if (!getEffectiveColor().equals(oldEC)) {
thisEffectiveColorChanged();
}
}
public Color getEffectiveColor() {
if (color != null) {
return color;
} else if (getParent() != null) {
return getParent().getEffectiveColor();
} else {
return null;
}
}
public String getFontName() {
return fontName;
}
public void setFontName(String name) {
String oldEFN = getEffectiveFontName();
fontName = name;
if (!getEffectiveFontName().equals(oldEFN)) {
thisEffectiveFontChanged();
}
}
public int getFontStyle() {
return fontStyle;
}
public void setFontStyle(int style) {
int oldEFS = getEffectiveFontStyle();
fontStyle = style;
if (getEffectiveFontStyle() != oldEFS) {
thisEffectiveFontChanged();
}
}
public float getFontSize() {
return fontSize;
}
public void setFontSize(float size) {
float oldEFS = getEffectiveFontSize();
fontSize = size;
if (getEffectiveFontSize() != oldEFS) {
thisEffectiveFontChanged();
}
}
public float getFontScale() {
return fontScale;
}
public void setFontScale(float scale) {
float oldEFS = getEffectiveFontSize();
fontScale = scale;
if (getEffectiveFontSize() != oldEFS) {
thisEffectiveFontChanged();
}
}
public void setFont(Font font) {
Font oldEF = getEffectiveFont();
if (font == null) {
fontName = null;
fontStyle = -1;
fontSize = Float.NaN;
} else {
fontName = font.getName();
fontStyle = font.getStyle();
fontSize = font.getSize2D();
}
if (!getEffectiveFont().equals(oldEF)) {
thisEffectiveFontChanged();
}
}
public String getEffectiveFontName() {
if (fontName != null) {
return fontName;
} else if (getParent() != null) {
return getParent().getEffectiveFontName();
} else {
return null;
}
}
public int getEffectiveFontStyle() {
if ((fontStyle & ~0x03) == 0) {
return fontStyle;
} else if (getParent() != null) {
return getParent().getEffectiveFontStyle();
} else {
return -1;
}
}
public float getEffectiveFontSize() {
if (!Float.isNaN(fontSize)) {
return fontSize;
} else if (getParent() != null) {
return getParent().getEffectiveFontSize() * fontScale;
} else {
return Float.NaN;
}
}
public Font getEffectiveFont() {
float size = getEffectiveFontSize();
return new Font(getEffectiveFontName(), getEffectiveFontStyle(), (int) size).deriveFont(size);
}
public final void parentEffectiveColorChanged() {
if (color == null) {
this.thisEffectiveColorChanged();
}
}
public final void parentEffectiveFontChanged() {
if (fontName == null || (fontStyle & ~0x03) != 0 || Float.isNaN(fontSize)) {
this.thisEffectiveFontChanged();
}
}
public PaperTransform getPaperTransform() {
PaperTransform pxf = getParent() == null ? null : getParent().getPaperTransform();
if (pxf == null) {
return null;
}
Point2D loc = getLocation();
if (loc == null) {
return null;
}
return pxf.translate(loc.getX(), loc.getY());
}
public Rectangle2D getBounds() {
Dimension2D size = getSize();
if (size == null) {
return null;
} else {
return new Rectangle2D.Double(0, 0, size.getWidth(), size.getHeight());
}
}
public Rectangle2D getSelectableBounds() {
return getBounds();
}
public boolean isRedrawNeeded() {
return redrawNeeded;
}
public void setRedrawNeeded(boolean flag) {
redrawNeeded = flag;
}
/**
* Mark redraw flag on cacheable parent and re-render flag on root plot when the given component is added, or to be
* removed. All sub-components are marked cascadedly.
*
* @param comp
* the component added, or to be removed.
*/
protected static void redrawCascade(ComponentEx comp) {
if (comp.isVisible()) {
redraw(comp);
if (comp instanceof ContainerEx) {
for (ComponentEx subcomp : ((ContainerEx) comp).getComponents()) {
redrawCascade(subcomp);
}
}
}
}
/**
* Mark redraw flag on cacheable parent and re-render flag on root plot when the given component is changed
*
* @param comp
* the component changed
*/
protected static void redraw(ComponentEx comp) {
if (comp.isVisible() && comp.canContribute()) {
markRedraw(comp);
}
}
/**
* Mark redraw flag on cacheable parent and re-render flag on root plot. Only the visible component can be marked.
* The property canContribute is not considered.
*
* @param comp
* the component changed
*/
private static void markRedraw(ComponentEx comp) {
if (comp.isVisible()) {
if (!comp.isCacheable() && comp.getParent() != null) {
markRedraw(comp.getParent());
} else {
comp.setRedrawNeeded(true);
markRerender(comp);
}
}
}
/**
* Mark re-render flag on root plot of the given component.
*
* @param comp
* the component
*/
private static void markRerender(ComponentEx comp) {
if (comp.getParent() != null) {
markRerender(comp.getParent());
} else if (comp instanceof PlotEx) {
((PlotEx) comp).setRerenderNeeded(true);
}
}
@Override
public ComponentEx copyStructure(Map orig2copyMap) {
return (ComponentEx) super.copyStructure(orig2copyMap);
}
@Override
public void copyFrom(ElementEx src) {
super.copyFrom(src);
ComponentImpl comp = (ComponentImpl) src;
visible = comp.visible;
cacheable = comp.cacheable;
selectable = comp.selectable;
movable = comp.movable;
zOrder = comp.zOrder;
color = comp.color;
fontName = comp.fontName;
fontStyle = comp.fontStyle;
fontSize = comp.fontSize;
fontScale = comp.fontScale;
redrawNeeded = comp.redrawNeeded;
}
protected void drawBounds(Graphics2D g) {
g.setColor(Color.RED);
Rectangle rect = getPaperTransform().getPtoD(getBounds()).getBounds();
g.draw(new Rectangle(rect.x, rect.y, rect.width - 1, rect.height - 1));
g.drawLine(rect.x, rect.y, (int) rect.getMaxX() - 1, (int) rect.getMaxY() - 1);
g.drawLine(rect.x, (int) rect.getMaxY() - 1, (int) rect.getMaxX() - 1, rect.y);
g.drawString(this.getClass().getSimpleName(), rect.x, (int) (rect.getMaxY() - 1));
}
}
Ads help maintain this website.