/* * Freeplane - mind map editor * Copyright (C) 2008 Dimitry Polivaev * * This file author is Dimitry Polivaev * * This program 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 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.freeplane.core.ui; import java.util.AbstractCollection; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import javax.swing.tree.DefaultMutableTreeNode; import org.freeplane.core.util.LogUtils; /** * @author Dimitry Polivaev * 25.12.2008 */ public class IndexedTree { public static class Node extends DefaultMutableTreeNode { /** * */ private static final long serialVersionUID = 1L; private Object key; Node(final Object userObject) { super(userObject); } Node(final Object userObject, final Object key) { this(userObject); this.key = key; } public Object getKey() { return key; } } private final class UserObjects extends AbstractCollection<Object> { @Override public void clear() { string2Element.clear(); } @Override public boolean contains(final Object o) { final Iterator<Object> iterator = iterator(); while (iterator.hasNext()) { final Object next = iterator.next(); if (o != null) { if (o.equals(next)) { return true; } } if (next == null) { return true; } } return false; } @Override public Iterator<Object> iterator() { return newObjectIterator(); } @Override public int size() { return string2Element.size(); } } public static final int APPEND = 2; public static final int AFTER = 1; public static final int AS_CHILD = 0; public static final int BEFORE = -1; public static final int PREPEND = -2; private final HashMap<Object, Node> string2Element; public IndexedTree(final Object root) { super(); final Node rootNode = new Node(root); string2Element = new HashMap<Object, Node>(); string2Element.put(this, rootNode); } public DefaultMutableTreeNode addElement(final Object relativeKey, final Object element, final int position) { final DefaultMutableTreeNode relativeNode = getNode(relativeKey); final DefaultMutableTreeNode node = new Node(element); if (relativeNode == null) { return node; } addNode(relativeNode, node, position); return node; } public DefaultMutableTreeNode addElement(final Object relativeKey, final Object element, final Object key, final int position) { final DefaultMutableTreeNode existingNode = get(key); if (existingNode != null) { throw new KeyAlreadyUsedException(key.toString() + " added twice"); } final DefaultMutableTreeNode relativeNode = getNode(relativeKey); if (relativeNode == null) { return null; } final Node node = new Node(element, key); addNode(relativeNode, node, position); string2Element.put(key, node); return node; } protected void addNode(final DefaultMutableTreeNode relativeNode, final DefaultMutableTreeNode node, final int position) { switch (position) { case AS_CHILD: relativeNode.add(node); break; case BEFORE: { final DefaultMutableTreeNode parent = (DefaultMutableTreeNode) relativeNode.getParent(); if (parent == null) { throw new RuntimeException("relative node has no parent element"); } final int index = parent.getIndex(relativeNode); parent.insert(node, index); break; } case AFTER: { final DefaultMutableTreeNode parent = (DefaultMutableTreeNode) relativeNode.getParent(); if (parent == null) { throw new RuntimeException("relative node has no parent element"); } final int index = parent.getIndex(relativeNode); parent.insert(node, index + 1); break; } case PREPEND: { //DOCEAR - // final int index = relativeNode.getChildCount()-1; relativeNode.insert(node, 0); break; } case APPEND: { final int index = relativeNode.getChildCount()-1; relativeNode.insert(node, index + 1); break; } default: throw new RuntimeException("wrong position"); } } public boolean contains(final Object key) { return string2Element.containsKey(key); } public String dump() { return string2Element.toString(); } public DefaultMutableTreeNode get(final Object key) { final Object object = string2Element.get(key); if (object == null) { return null; } return (DefaultMutableTreeNode) object; } public Object getKeyByUserObject(final Object object) { final Collection<Node> values = string2Element.values(); for (final Node node : values) { if (object != null && object.equals(node.getUserObject())) { return node.getKey(); } } return null; } protected DefaultMutableTreeNode getNode(final Object key) { final DefaultMutableTreeNode node = (string2Element.get(key)); if (node == null) { LogUtils.warn(key + " not found"); } return node; } public DefaultMutableTreeNode getRoot() { return string2Element.get(this); } public Collection<Object> getUserObjects() { return Collections.unmodifiableCollection(new UserObjects()); } public Iterator<Object> newObjectIterator() { return new Iterator<Object>() { private final Iterator<Node> nodeIterator = string2Element.values().iterator(); public boolean hasNext() { return nodeIterator.hasNext(); } public Object next() { return nodeIterator.next().getUserObject(); } public void remove() { nodeIterator.remove(); } }; } public void removeChildElements(final Object key) { final DefaultMutableTreeNode node = getNode(key); final Enumeration<?> children = node.children(); while (children.hasMoreElements()) { final Node child = (Node) children.nextElement(); final Object childKey = child.getKey(); if (childKey != null) { removeChildElements(childKey); string2Element.remove(childKey); } } node.removeAllChildren(); } /** */ protected void removeChildKeys(final Node node) { final Enumeration<?> children = node.children(); while (children.hasMoreElements()) { final Node child = (Node) children.nextElement(); string2Element.remove(child.getKey()); removeChildKeys(child); } } public DefaultMutableTreeNode removeElement(final Object key) { final DefaultMutableTreeNode node = (string2Element.remove(key)); if (node != null) { removeChildKeys((Node) node); } return node; } }