
net.vectorpublish.desktop.vp.api.vpd.ModificationContext 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.api.vpd;
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.plaf.TreeUI;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import net.vectorpublish.desktop.vp.History;
import net.vectorpublish.desktop.vp.api.ContextHolder;
import net.vectorpublish.desktop.vp.api.layer.Layer;
import net.vectorpublish.desktop.vp.api.layer.LayerItemContribution;
import net.vectorpublish.desktop.vp.api.ui.KeyframeSlider;
import net.vectorpublish.desktop.vp.api.ui.MouseParticipant;
import net.vectorpublish.desktop.vp.log.Log;
import net.vectorpublish.desktop.vp.utils.SetUtils;
/**
* The context for modifications.
*
* This context is only available in
* {@link net.vectorpublish.desktop.vp.api.history.ReadOnlyHistoryStepDataBean
* HistoryStepData} .
*/
public class ModificationContext {
/**
* A mutable Treenode. You can only use this in context of modification,
* otherwise you need to use {@link VectorPublishNode} what is readonly.
*
*
* To have a specific icon for this node use the
* {@link LayerItemContribution layeritem contributions}.
*/
public abstract class LayerNodeImpl implements VectorPublishNode {
private final Set childLayer = new LinkedHashSet<>();
/**
* The parent layer of this Layer or null
if the parent is
* the root.
*/
private LayerNodeImpl parent;
/**
* The Document this Node is in. Never null
!
*/
protected final DocumentNode documentNode;
/**
* The constructor using the current active Document.
*/
public LayerNodeImpl() {
this(getDocument());
}
public LayerNodeImpl(DocumentNode root) {
this.documentNode = Objects.requireNonNull(root);
this.documentNode.addTrunk(this);
this.parent = null;
updateList.add(new UpdateNode(this, TreeChangeType.INSERT));
}
private synchronized void internalMove(VectorPublishNode newParent, ModificationContext mc) {
if (newParent instanceof LayerNodeImpl) {
LayerNodeImpl node = (LayerNodeImpl) newParent;
if (parent != null) {
parent.childLayer.remove(this);
} else {
doc.removeTrunk(this);
}
LinkedHashSet old = new LinkedHashSet<>(node.childLayer);
node.childLayer.clear();
node.childLayer.add(this);
node.childLayer.addAll(old);
parent = node;
mc.updateList.add(new UpdateNode(this, TreeChangeType.MOVE));
mustRepaintComponent = true;
} else if (newParent == doc) {
DocumentNode dn = (DocumentNode) newParent;
if (parent == null) {
doc.removeTrunk(this);
} else {
parent.childLayer.remove(this);
}
dn.addTrunk(this);
parent = null;
mc.updateList.add(new UpdateNode(this, TreeChangeType.MOVE));
mustRepaintComponent = true;
}
}
public LayerNodeImpl(LayerNodeImpl parent) {
this.documentNode = getDocument();
this.parent = Objects.requireNonNull(parent);
this.parent.childLayer.add(this);
updateList.add(new UpdateNode(this, TreeChangeType.INSERT));
}
@Override
public Enumeration children() {
return new Vector(this.childLayer).elements();
}
@Override
public VectorPublishNode findSelfOrChildByPaintParticipant(MouseParticipant dp) {
if (dp == getParticipant()) {
return this;
}
for (final LayerNodeImpl child : childLayer) {
final VectorPublishNode candidate = child.findSelfOrChildByPaintParticipant(dp);
if (candidate != null) {
return candidate;
}
}
return null;
}
@Override
public abstract boolean getAllowsChildren();
@Override
public LayerNodeImpl getChildAt(int childIndex) {
return (LayerNodeImpl) childLayer.toArray()[childIndex];
}
@Override
public int getChildCount() {
return childLayer.size();
}
/**
* Returns the Document.
*
* @return The Document.
*/
public DocumentNode getDocumentNode() {
return documentNode;
}
@Override
public int getIndex(TreeNode node) {
int index = -1;
for (final LayerNodeImpl layerNode : childLayer) {
index++;
if (layerNode == node) {
return index;
}
}
return -1;
}
/**
* Returns the parent layer or the document.
*
* @return The parent layer or the document.
*/
@Override
public VectorPublishNode getParent() {
return parent == null ? documentNode : parent;
}
/**
* Removes this layer and all the childlayers from the tree.
*
* @param updateList
* The Updatelist to collect changes.
*/
private void internalRemoveFromParent(Set updateList) {
updateList.add(new UpdateNode(this, TreeChangeType.REMOVE));
for (final LayerNodeImpl layerNode : childLayer) {
layerNode.internalRemoveFromParent(updateList);
}
if (parent == null) {
documentNode.removeTrunk(this);
} else {
parent.childLayer.remove(this);
}
}
@Override
public boolean isLeaf() {
return childLayer.isEmpty();
}
/**
* Removes this node and all subnodes from parent.
*
* @see #internalRemoveFromParent(Set)
* @param ctx
* The modification context.
*/
public void removeFromParent(ModificationContext ctx) {
internalRemoveFromParent(ctx.updateList);
}
@Override
public String toString() {
return LayerNodeImpl.class.getName() + "#" + getParticipant();
}
}
private static final Log LOG = ContextHolder.context.getBean(Log.class);
private final Set updateList = new LinkedHashSet<>();
/**
* The history so long.
*/
private final History history;
/**
* The Document.
*/
private final DocumentNode doc;
private final Layer layer;
private boolean mustRepaintComponent;
private boolean addedKeyframes;
private final KeyframeSlider slider;
public ModificationContext(History history, DocumentNode doc, Layer layer, KeyframeSlider slider) {
this.slider = slider;
this.layer = Objects.requireNonNull(layer);
this.history = Objects.requireNonNull(history);
this.doc = Objects.requireNonNull(doc);
}
public void cleanUp() {
boolean didSomething = false;
if (!updateList.isEmpty()) {
final TreePath[] selectionPaths = layer.getSelectionPaths();
LOG.found("Changed treenodes (" + selectionPaths.length + ")");
layer.reload();
TreeUI ui = layer.getUI();
for (TreePath treePath : selectionPaths) {
ui.startEditingAtPath(layer, treePath);
}
layer.setSelectionPaths(selectionPaths);
layer.expandPath(layer.getSelectionPath());
ui.stopEditing(layer);
LOG.notify("Document about updated Treenodes.");
doc.notify(updateList);
LOG.system("Clear list of Treenodes to update.");
updateList.clear();
if (layer.getSelectionRows().length > 0) {
layer.scrollRowToVisible(layer.getSelectionRows()[0]);
}
didSomething = true;
}
if (mustRepaintComponent) {
LOG.system("Repaint document.");
doc.getComponent().repaint();
didSomething = true;
}
if (addedKeyframes) {
LOG.notify("Slider about new Keyframes.");
slider.notifyIncommingKeyframes();
didSomething = true;
}
if (!didSomething) {
LOG.missing("Cleanup", "had no work.");
}
}
public DocumentNode getDocument() {
return doc;
}
/**
* Moves an node to the first child of the newParent.
*
* @param moveable
* The moveable to move, never null
.
* @param newParent
* The new parent, never null
.
*/
public void move(LayerNodeImpl moveable, VectorPublishNode newParent) {
moveable.internalMove(newParent, this);
}
public History getHistory() {
return history;
}
public boolean hasChangedLayers() {
return true;
}
public void setAddedKeyframes(boolean evaluate) {
addedKeyframes = evaluate;
}
/**
* @param repaint
* true
if the {@link MouseParticipant} must be
* repainted, false
if not.
*/
public void setRepaintComponent(boolean repaint) {
this.mustRepaintComponent = repaint;
}
public void setSelection(VectorPublishNode node) {
TreePath tp = SetUtils.createPath(node);
layer.expandPath(tp);
layer.setSelectionPath(tp);
}
}