
net.vectorpublish.desktop.vp.io.VPDocumentNode Maven / Gradle / Ivy
/*
* Copyright (c) 2016, Peter Rader. All rights reserved.
* ___ ___ __ ______ __ __ __ __
* | | |.-----..----.| |_ .-----..----.| __ \.--.--.| |--.| ||__|.-----.| |--.
* | | || -__|| __|| _|| _ || _|| __/| | || _ || || ||__ --|| |
* \_____/ |_____||____||____||_____||__| |___| |_____||_____||__||__||_____||__|__|
*
* http://www.gnu.org/licenses/gpl-3.0.html
*/
package net.vectorpublish.desktop.vp.io;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.Vector;
import javax.swing.JComponent;
import javax.swing.tree.TreeNode;
import net.vectorpublish.desktop.vp.History.HistoryStep;
import net.vectorpublish.desktop.vp.api.DrawParticipant;
import net.vectorpublish.desktop.vp.api.ui.MouseParticipant;
import net.vectorpublish.desktop.vp.api.ui.kf.Keyframe;
import net.vectorpublish.desktop.vp.api.vpd.DocumentNode;
import net.vectorpublish.desktop.vp.api.vpd.ModificationContext;
import net.vectorpublish.desktop.vp.api.vpd.ModificationContext.LayerNodeImpl;
import net.vectorpublish.desktop.vp.api.vpd.TreeChangeType;
import net.vectorpublish.desktop.vp.api.vpd.UpdateNode;
import net.vectorpublish.desktop.vp.api.vpd.VectorPublishNode;
import net.vectorpublish.desktop.vp.pd.official.DrawPanel;
import net.vectorpublish.desktop.vp.pd.official.RelativeKeyframeRecalculator;
import net.vectorpublish.desktop.vp.pd.official.VectorPublishGraphics;
/**
* The Document.
*
*
* Contains everything for the documentfile including the edit-history you have
* done in the past. Also contains all steps you revoke to make available that
* you can redo the {@link HistoryStep} after loading again.
*/
public class VPDocumentNode implements DocumentNode {
private static final Dimension NULL_TEXT_BOUNDARY = new Dimension(0, 0);
/**
* The Drawpanel responsible to draw this document with all the children.
*/
private final DrawPanel drawPanel;
/**
* All the layers who are a direct child of the Document. Theese Trunks will
* have this document as parent and can contain other children.
*/
private final Set layerTrunks = new LinkedHashSet<>();
/**
* The current {@link HistoryStep}. If {@link HistoryStep#previous} exists
* the undo-button is active. If {@link HistoryStep#next} exists the
* redo-button is active.
*/
private HistoryStep> current;
/**
* Stores all {@link MouseParticipant} who are part of the current document,
* no matter if they are invisible in the current keyframe.
*
* Participants who are not part of the tree are not part of the list.
*/
private final Set paintParticipants = new LinkedHashSet<>(100);
/**
* Ordered set of {@link Keyframe Keyframes}.
*
* The last {@link Keyframe} is the latest added to the
* {@link VPDocumentNode}, not the latest in the animation!
*/
private final Set keyframes = new LinkedHashSet<>();
/**
* The default constructor. You can only create a Document if you have a
* {@link DrawPanel} for the contents.
*
* @param drawPanel
* The DrawPanel.
*/
public VPDocumentNode(DrawPanel drawPanel) {
this.drawPanel = Objects.requireNonNull(drawPanel);
}
@Override
public void addKeyframe(Keyframe kf, ModificationContext ctx) {
if (!kf.hasValues()) {
throw new RuntimeException("The keyframe contains no values");
}
keyframes.add(kf);
ctx.setAddedKeyframes(true);
}
/**
* Adds a direct child of the document.
*/
@Override
public void addTrunk(LayerNodeImpl layerNode) {
layerTrunks.add(layerNode);
}
/**
* Enumerates all the children of the Document-Root.
*/
@Override
public Enumeration children() {
return new Vector(layerTrunks).elements();
}
@Override
public VectorPublishNode findByIndex(List list) {
VectorPublishNode node = this;
try {
for (final Integer integer : list) {
node = node.getChildAt(integer);
}
} catch (final ArrayIndexOutOfBoundsException e) {
return null;
}
return node;
}
/*
* (non-Javadoc)
*
* @see net.vectorpublish.desktop.vp.api.vpd.VectorPublishNode#findNode(de.
* e_nexus . desktop.vp.api.vpd.VectorPublishNode,
* net.vectorpublish.desktop.vp.api.ui.PaintParticipant)
*/
@Override
public VectorPublishNode findSelfOrChildByPaintParticipant(MouseParticipant pp) {
if (getParticipant() == pp) {
return this;
}
for (final LayerNodeImpl layerNodeImpl : layerTrunks) {
final VectorPublishNode candidate = layerNodeImpl.findSelfOrChildByPaintParticipant(pp);
if (candidate != null) {
return candidate;
}
}
return null;
}
/**
* Let the document have children.
*/
@Override
public boolean getAllowsChildren() {
return true;
}
@Override
public Set getAllPaintParticipants() {
return paintParticipants;
}
@Override
public LayerNodeImpl getChildAt(int childIndex) {
return (LayerNodeImpl) layerTrunks.toArray()[childIndex];
}
@Override
public int getChildCount() {
return layerTrunks.size();
}
@Override
public DrawPanel getComponent() {
return drawPanel;
}
@Override
public int getIndex(TreeNode node) {
assert node instanceof LayerNodeImpl : "Not a " + LayerNodeImpl.class + "!";
int index = -1;
for (final LayerNodeImpl layerNode : layerTrunks) {
index++;
if (layerNode == node) {
return index;
}
}
return -1;
}
@Override
public Set getKeyframes() {
Set result = keyframes;
assert (result = Collections.unmodifiableSet(result)) != null;
return result;
}
/**
* Returns the current historystep of the document. This does not point to
* the start of the history, it points to the current representation of the
* {@link DrawPanel} you see.
*/
@Override
public HistoryStep> getLastExecutedHistoryStep() {
return current;
}
/**
* The default representation of this Document as a Treenode in the Tree.
*/
@Override
public String getLayerName() {
return "Document";
}
/**
* A document is the lowest element. It can not have a parent.
*/
@Override
@Deprecated
public VectorPublishNode getParent() {
return null;
}
/**
* Returns the PaintParticipant that is responsible for the very basic
* visual platform of the document.
*/
@Override
public DrawParticipant getParticipant() {
return drawPanel.getDrawArea();
}
/**
* The representation of the Document in the status-bar.
*/
@Override
public String getStatusName() {
if (drawPanel == null) {
return IOConstraints.FILE_DESCRIPTION;
}
return IOConstraints.FILE_DESCRIPTION + " " + drawPanel.getDrawArea().getDimensions().width + "x" + drawPanel.getDrawArea().getDimensions().height;
}
/**
* The title of the document in the Filetab.
*/
@Override
public String getTitle() {
return drawPanel.getTitle();
}
@Override
public boolean isLeaf() {
return layerTrunks.isEmpty();
}
@Override
public void notify(Set infos) {
for (final UpdateNode info : infos) {
if (info.getChange() == TreeChangeType.INSERT) {
final MouseParticipant participant = info.getNode().getParticipant();
if (participant != null) {
paintParticipants.add(participant);
}
} else if (info.getChange() == TreeChangeType.REMOVE) {
paintParticipants.remove(info.getNode().getParticipant());
}
}
}
@Override
public void paintChildren(DrawParticipant pp, VectorPublishGraphics g, int width, int height) {
long start = System.currentTimeMillis();
final VectorPublishNode parentNode = findSelfOrChildByPaintParticipant(pp);
final Enumeration childNodes = parentNode.children();
while (childNodes.hasMoreElements()) {
final VectorPublishNode childNode = childNodes.nextElement();
final MouseParticipant targetPP = childNode.getParticipant();
if (targetPP instanceof DrawParticipant) {
final DrawParticipant dp = (DrawParticipant) targetPP;
dp.paint(g, width, height);
}
}
}
@Override
public void paintChildrenOuter(DrawParticipant pp, VectorPublishGraphics g, RelativeKeyframeRecalculator rel, int w, int h) {
final VectorPublishNode parentNode = findSelfOrChildByPaintParticipant(pp);
final Enumeration childNodes = parentNode.children();
while (childNodes.hasMoreElements()) {
final VectorPublishNode childNode = childNodes.nextElement();
final MouseParticipant targetPP = childNode.getParticipant();
if (targetPP instanceof DrawParticipant) {
final DrawParticipant dp = (DrawParticipant) targetPP;
dp.paintOutside(g, rel, w, h);
}
}
}
@Override
public void removeTrunk(LayerNodeImpl layerNode) {
assert layerTrunks.contains(layerNode) : "Not a trunk!";
layerTrunks.remove(layerNode);
}
@Override
public void setFile(File f) {
drawPanel.setTitle(f.getName());
}
@Override
public void setLastExecutedHistoryStep(HistoryStep> current) {
this.current = current;
}
@Override
public Dimension calculateTextBoundary(String text) {
if (text == null) {
return NULL_TEXT_BOUNDARY;
}
JComponent component = getComponent();
Graphics graphics = new VectorPublishGraphics(new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB));
Rectangle2D bounds = graphics.getFontMetrics().getStringBounds(text, graphics);
return new Dimension((int) Math.ceil(bounds.getWidth()), (int) Math.ceil(bounds.getHeight()));
}
}