/* * JAME 6.2.1 * http://jame.sourceforge.net * * Copyright 2001, 2016 Andrea Medeghini * * This file is part of JAME. * * JAME is an application for creating fractals and other graphics artifacts. * * JAME is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JAME 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 Public License for more details. * * You should have received a copy of the GNU General Public License * along with JAME. If not, see <http://www.gnu.org/licenses/>. * */ package net.sf.jame.core.tree; import net.sf.jame.core.config.ConfigContext; /** * @author Andrea Medeghini */ public abstract class NodeEditor { protected Node node; /** * Constructs a new editor. * * @param node the node. */ public NodeEditor(final Node node) { this.node = node; } /** * @return */ public ConfigContext getContext() { return node.getContext(); } /** * @return the nodeId. */ public String getNodeId() { return node.getNodeId(); } /** * @return */ public String getNodeLabel() { return node.getNodeLabel(); } /** * @return */ public String getNodeClass() { return node.getNodeClass(); } /** * @return true if the node is editable. */ public boolean isNodeEditable() { return node.isEditable(); } /** * @return true if the node is mutable. */ public boolean isNodeMutable() { return node.isMutable(); } /** * @return true if the node is an attribute. */ public boolean isNodeAttribute() { return node.isAttribute(); } /** * @return true if refresh is required. */ public boolean isRefreshRequired() { return true; } /** * Returns the node type. * * @return the node type. */ public abstract Class<?> getNodeValueType(); /** * @param value * @return */ public abstract NodeValue<?> createNodeValue(Object value); /** * Returns the previous node value. * * @return the previous node value. */ public final NodeValue<?> getPreviousNodeValue() { return node.getPreviousNodeValue(); } /** * Returns the node value. * * @return the node value. */ public final NodeValue<?> getNodeValue() { return node.getNodeValue(); } /** * Returns true if value is set. * * @return true if value is set. */ public final boolean hasValue() { return getNodeValue() != null; } /** * Sets the node value. * * @param value the node value to set. */ public final void setNodeValue(final NodeValue<?> value) { if (!node.isEditable()) { throw new UnsupportedOperationException(); } final NodeValue<?> prevValue = node.getNodeValue(); final ForwardCommand command = new ForwardCommand(); node.appendCommand(command); node.setNodeValue(value); command.setCommand(new SetValueCommand(value, prevValue)); if (node.getSession().isAcceptImmediatly()) { node.getContext().updateTimestamp(); node.getSession().fireSessionAccepted(); node.accept(); } } /** * Returns the node value as string. * * @return the string. */ public String getNodeValueAsString() { return node.getValueAsString(); } /** * Returns the node value as transferable value. * * @return the transferable value. */ public TransferableNodeValue getNodeValueAsTransferable() { return new TransferableNodeValue(getNodeValueType(), getNodeValue()); } /** * @return the node index. */ public int getIndex() { return node.getParentNode().indexOf(node); } /** * Returns the number of childs. * * @return the number of childs. */ public int getChildNodeCount() { return node.getChildNodeCount(); } /** * @param index * @return the editor of the child. */ public NodeEditor getChildNodeEditor(final int index) { return node.getChildNode(index).getNodeEditor(); } public String getChildNodeValueAsString(int index) { return node.getChildNode(index).getValueAsString(); } /** * @param value */ public final void appendChildNode(final NodeValue<?> value) { if (!node.isMutable()) { throw new UnsupportedOperationException(); } final Node newNode = createChildNode(value); final ForwardCommand command = new ForwardCommand(); node.appendCommand(command); node.appendChildNode(newNode); command.setCommand(new AppendCommand(newNode)); if (node.getSession().isAcceptImmediatly()) { node.getContext().updateTimestamp(); node.getSession().fireSessionAccepted(); node.accept(); } } /** * @param index * @param value */ public final void insertChildNodeBefore(final int index, final NodeValue<?> value) { if (!node.isMutable()) { throw new UnsupportedOperationException(); } final Node newNode = createChildNode(value); final ForwardCommand command = new ForwardCommand(); node.appendCommand(command); node.insertNodeBefore(index, newNode); command.setCommand(new InsertBeforeCommand(index, newNode)); if (node.getSession().isAcceptImmediatly()) { node.getContext().updateTimestamp(); node.getSession().fireSessionAccepted(); node.accept(); } } /** * @param index * @param value */ public final void insertChildNodeAfter(final int index, final NodeValue<?> value) { if (!node.isMutable()) { throw new UnsupportedOperationException(); } final Node newNode = createChildNode(value); final ForwardCommand command = new ForwardCommand(); node.appendCommand(command); node.insertNodeAfter(index, newNode); command.setCommand(new InsertAfterCommand(index, newNode)); if (node.getSession().isAcceptImmediatly()) { node.getSession().fireSessionAccepted(); node.accept(); } } /** * @param index * @param value */ public void insertChildNodeAt(final Integer index, final NodeValue<?> value) { if (!node.isMutable()) { throw new UnsupportedOperationException(); } final Node newNode = createChildNode(value); if (index < node.getChildNodeCount()) { final ForwardCommand command = new ForwardCommand(); node.appendCommand(command); node.insertNodeBefore(index, newNode); command.setCommand(new InsertBeforeCommand(index, newNode)); } else if (index > 0) { final ForwardCommand command = new ForwardCommand(); node.appendCommand(command); node.insertNodeAfter(index - 1, newNode); command.setCommand(new InsertAfterCommand(index - 1, newNode)); } else { final ForwardCommand command = new ForwardCommand(); node.appendCommand(command); node.appendChildNode(newNode); command.setCommand(new AppendCommand(newNode)); } if (node.getSession().isAcceptImmediatly()) { node.getContext().updateTimestamp(); node.getSession().fireSessionAccepted(); node.accept(); } } /** * @param index */ public final void removeChildNode(final int index) { if (!node.isMutable()) { throw new UnsupportedOperationException(); } if ((index >= 0) && (index < node.getChildNodeCount())) { final Node nodeToRemove = node.getChildNode(index); final ForwardCommand command = new ForwardCommand(); command.setCommand(new RemoveCommand(index, nodeToRemove)); node.removeChildNode(index); node.appendCommand(command); if (node.getSession().isAcceptImmediatly()) { node.getContext().updateTimestamp(); node.getSession().fireSessionAccepted(); node.accept(); } } } /** * @param index */ public final void moveUpChildNode(final int index) { if (!node.isMutable()) { throw new UnsupportedOperationException(); } if ((index >= 0) && (index < node.getChildNodeCount())) { final ForwardCommand command = new ForwardCommand(); command.setCommand(new MoveUpCommand(index)); node.moveUpChildNode(index); node.appendCommand(command); if (node.getSession().isAcceptImmediatly()) { node.getContext().updateTimestamp(); node.getSession().fireSessionAccepted(); node.accept(); } } } /** * @param index */ public final void moveDownChildNode(final int index) { if (!node.isMutable()) { throw new UnsupportedOperationException(); } if ((index >= 0) && (index < node.getChildNodeCount())) { final ForwardCommand command = new ForwardCommand(); command.setCommand(new MoveDownCommand(index)); node.moveDownChildNode(index); node.appendCommand(command); if (node.getSession().isAcceptImmediatly()) { node.getContext().updateTimestamp(); node.getSession().fireSessionAccepted(); node.accept(); } } } /** * */ public void removeAllChildNodes() { while (getChildNodeCount() > 0) { removeChildNode(0); } } /** * @return the parent node editor. */ public NodeEditor getParentNodeEditor() { return node.getParentNode().getNodeEditor(); } /** * @return true if node is removable. */ public boolean isParentMutable() { return node.getParentNode().isMutable(); } /** * @param value */ protected abstract Node createChildNode(NodeValue<?> value); /** * @param value */ protected void doSetValue(final NodeValue<?> value) { } /** * @param node */ protected void doAppendNode(final Node node) { } /** * @param index * @param node */ protected void doInsertNodeAfter(final int index, final Node node) { } /** * @param index * @param node */ protected void doInsertNodeBefore(final int index, final Node node) { } /** * @param nodeIndex */ protected void doRemoveNode(final int nodeIndex) { } /** * @param nodeIndex */ protected void doMoveUpNode(final int nodeIndex) { } /** * @param nodeIndex */ protected void doMoveDownNode(final int nodeIndex) { } /** * @param nodeIndex */ protected void doChangeNode(final int nodeIndex, final Node node) { } private abstract class AbstractCommand implements NodeCommand { private boolean consumed; /** * @see net.sf.jame.core.tree.NodeCommand#consume() */ public void consume() { consumed = true; } /** * @see net.sf.jame.core.tree.NodeCommand#isConsumed() */ public boolean isConsumed() { return consumed; } } private class SetValueCommand extends AbstractCommand { private final NodeValue<?> value; private final NodeValue<?> prevValue; private final NodePath target; /** * @param value * @param prevValue */ public SetValueCommand(final NodeValue<?> value, final NodeValue<?> prevValue) { this.value = value; this.prevValue = prevValue; target = node.getNodePath(); } /** * @see net.sf.jame.core.tree.NodeCommand#accept(net.sf.jame.core.tree.NodeSession, long) */ public void accept(final NodeSession session, final long timestamp) { doSetValue(value); if (isRefreshRequired()) { session.appendAction(new NodeAction(getNodeClass(), NodeAction.ACTION_SET_VALUE, timestamp, false, target, value.getValueClone(), prevValue.getValueClone())); } else { session.appendAction(new NodeAction(getNodeClass(), NodeAction.ACTION_SET_VALUE, timestamp, true, target, value.getValueClone(), prevValue.getValueClone())); } } /** * @see net.sf.jame.core.tree.NodeCommand#accept() */ public void cancel() { node.setNodeValue(prevValue); } } private class AppendCommand extends AbstractCommand { private final int index; private final Node node; private final NodeValue<?> value; private final NodePath target; /** * @param node */ public AppendCommand(final Node node) { this.node = node; value = node.getNodeValue(); target = node.getParentNode().getNodePath(); index = node.getNodePath().getLastPathElement(); } /** * @see net.sf.jame.core.tree.NodeCommand#accept(net.sf.jame.core.tree.NodeSession, long) */ public void accept(final NodeSession session, final long timestamp) { doAppendNode(node); session.appendAction(new NodeAction(getNodeClass(), NodeAction.ACTION_APPEND_NODE, timestamp, target, index, value.getValueClone())); } /** * @see net.sf.jame.core.tree.NodeCommand#accept() */ public void cancel() { NodeEditor.this.node.removeChildNode(index); } } private class InsertBeforeCommand extends AbstractCommand { private final int index; private final Node node; private final NodeValue<?> value; private final NodePath target; /** * @param index * @param node */ public InsertBeforeCommand(final int index, final Node node) { this.index = index; this.node = node; value = node.getNodeValue(); target = node.getParentNode().getNodePath(); } /** * @see net.sf.jame.core.tree.NodeCommand#accept(net.sf.jame.core.tree.NodeSession, long) */ public void accept(final NodeSession session, final long timestamp) { doInsertNodeBefore(index, node); session.appendAction(new NodeAction(getNodeClass(), NodeAction.ACTION_INSERT_NODE_BEFORE, timestamp, target, index, value.getValueClone())); } /** * @see net.sf.jame.core.tree.NodeCommand#accept() */ public void cancel() { NodeEditor.this.node.removeChildNode(index); } } private class InsertAfterCommand extends AbstractCommand { private final int index; private final Node node; private final NodeValue<?> value; private final NodePath target; /** * @param index * @param node */ public InsertAfterCommand(final int index, final Node node) { this.index = index; this.node = node; value = node.getNodeValue(); target = node.getParentNode().getNodePath(); } /** * @see net.sf.jame.core.tree.NodeCommand#accept(net.sf.jame.core.tree.NodeSession, long) */ public void accept(final NodeSession session, final long timestamp) { doInsertNodeAfter(index, node); session.appendAction(new NodeAction(getNodeClass(), NodeAction.ACTION_INSERT_NODE_AFTER, timestamp, target, index, value.getValueClone())); } /** * @see net.sf.jame.core.tree.NodeCommand#accept() */ public void cancel() { NodeEditor.this.node.removeChildNode(index + 1); } } private class RemoveCommand extends AbstractCommand { private final Node node; private final int index; private final NodeValue<?> value; private final NodePath target; /** * @param index * @param node */ public RemoveCommand(final int index, final Node node) { this.index = index; this.node = node; value = node.getNodeValue(); target = node.getParentNode().getNodePath(); } /** * @see net.sf.jame.core.tree.NodeCommand#accept(net.sf.jame.core.tree.NodeSession, long) */ public void accept(final NodeSession session, final long timestamp) { doRemoveNode(index); session.appendAction(new NodeAction(getNodeClass(), NodeAction.ACTION_REMOVE_NODE, timestamp, target, index, value.getValueClone())); } /** * @see net.sf.jame.core.tree.NodeCommand#accept() */ public void cancel() { NodeEditor.this.node.insertChildNodeAt(index, node); } } private class MoveUpCommand extends AbstractCommand { private final int index; private final NodePath target; /** * @param index */ public MoveUpCommand(final int index) { this.index = index; target = node.getNodePath(); } /** * @see net.sf.jame.core.tree.NodeCommand#accept(net.sf.jame.core.tree.NodeSession, long) */ public void accept(final NodeSession session, final long timestamp) { doMoveUpNode(index); session.appendAction(new NodeAction(getNodeClass(), NodeAction.ACTION_MOVE_UP_NODE, timestamp, target, index)); } /** * @see net.sf.jame.core.tree.NodeCommand#accept() */ public void cancel() { node.moveDownChildNode(index); } } private class MoveDownCommand extends AbstractCommand { private final int index; private final NodePath target; /** * @param index */ public MoveDownCommand(final int index) { this.index = index; target = node.getNodePath(); } /** * @see net.sf.jame.core.tree.NodeCommand#accept(net.sf.jame.core.tree.NodeSession, long) */ public void accept(final NodeSession session, final long timestamp) { doMoveDownNode(index); session.appendAction(new NodeAction(getNodeClass(), NodeAction.ACTION_MOVE_DOWN_NODE, timestamp, target, index)); } /** * @see net.sf.jame.core.tree.NodeCommand#accept() */ public void cancel() { node.moveUpChildNode(index); } } private class ForwardCommand implements NodeCommand { private NodeCommand command; /** * @return */ @SuppressWarnings("unused") public NodeCommand getCommand() { return command; } /** * @param command */ void setCommand(final NodeCommand command) { this.command = command; } /** * @see net.sf.jame.core.tree.NodeCommand#accept(net.sf.jame.core.tree.NodeSession, long) */ public void accept(final NodeSession session, final long timestamp) { if (command != null) { command.accept(session, timestamp); } } /** * @see net.sf.jame.core.tree.NodeCommand#cancel() */ public void cancel() { if (command != null) { command.cancel(); } } /** * @see net.sf.jame.core.tree.NodeCommand#consume() */ public void consume() { if (command != null) { command.consume(); } } /** * @see net.sf.jame.core.tree.NodeCommand#isConsumed() */ public boolean isConsumed() { if (command != null) { return command.isConsumed(); } return true; } } }