/* * Copyright (C) 2011 eXo Platform SAS. * * This 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 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.portal.mop.navigation; import org.exoplatform.portal.mop.Utils; import org.exoplatform.portal.tree.diff.Adapters; import org.exoplatform.portal.tree.diff.HierarchyAdapter; import org.exoplatform.portal.tree.diff.HierarchyChangeIterator; import org.exoplatform.portal.tree.diff.HierarchyChangeType; import org.exoplatform.portal.tree.diff.HierarchyDiff; /** * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */ class TreeUpdate<N1, N2> { static <N1, N2> void perform(TreeContext<N1> src, HierarchyAdapter<String[], NodeContext<N1>, String> srcAdatper, N2 dst, TreeUpdateAdapter<N2> updateAdapter, NodeChangeListener<NodeContext<N1>> listener, Scope.Visitor visitor) { TreeUpdate<N1, N2> update = new TreeUpdate<N1, N2>(src, srcAdatper, dst, updateAdapter, listener, visitor); // update.perform(); } private TreeUpdate(TreeContext<N1> src, HierarchyAdapter<String[], NodeContext<N1>, String> srcAdatper, N2 dst, TreeUpdateAdapter<N2> updateAdapter, NodeChangeListener<NodeContext<N1>> listener, Scope.Visitor visitor) { // We create the diff object HierarchyDiff<String[], NodeContext<N1>, String[], N2, String> diff = HierarchyDiff.create(Adapters.<String> list(), srcAdatper, Adapters.<String> list(), updateAdapter, Utils.<String> comparator()); // We obtain the iterator HierarchyChangeIterator<String[], NodeContext<N1>, String[], N2, String> it = diff.iterator(src.root, dst); // this.it = it; this.updateAdapter = updateAdapter; this.visitor = visitor; this.depth = 0; this.last = null; this.listener = listener; } /** . */ private final HierarchyChangeIterator<String[], NodeContext<N1>, String[], N2, String> it; /** . */ private final TreeUpdateAdapter<N2> updateAdapter; /** . */ private final Scope.Visitor visitor; /** . */ private int depth; /** . */ private NodeContext<N1> last; /** . */ private NodeChangeListener<NodeContext<N1>> listener; private void perform() { // Consume the first ENTER that we won't skip HierarchyChangeType change = it.next(); // Start recursion perform(it.getSource()); } private void perform(NodeContext<N1> parent) { // Compute visit final N2 d = it.getDestination(); final NodeData data = updateAdapter.getData(d); // final VisitMode visit; if (data != null) { visit = visitor.enter(depth, data.id, data.name, data.state); } else { visit = null; } // Cut the recursion if necessary if (visit != VisitMode.ALL_CHILDREN) { it.skip(); // Consume leave it.next(); } else { depth++; // Expand if needed if (!parent.isExpanded()) { parent.expand(); } // while (true) { HierarchyChangeType change = it.next(); if (change == HierarchyChangeType.LEAVE) { // End recursion here break; } else { if (change == HierarchyChangeType.KEEP) { // Consume ENTER it.next(); // Recurse perform(it.getSource()); } else if (change == HierarchyChangeType.ADDED) { // Consume ENTER it.next(); // NodeContext<N1> previous; NodeContext<N1> added; NodeData addedData = updateAdapter.getData(it.getDestination()); if (last == null || last.getParent() != parent) { previous = null; added = parent.insertAt(0, addedData); } else { previous = last; added = last.insertAfter(addedData); } // if (listener != null) { listener.onAdd(added, parent, previous); } // Recurse perform(added); } else if (change == HierarchyChangeType.MOVED_IN) { // Consume ENTER it.next(); // NodeContext<N1> to = parent; NodeContext<N1> moved = it.getSource(); NodeContext<N1> from = moved.getParent(); NodeContext<N1> previous; if (last == null || last.getParent() != parent) { previous = null; to.insertAt(0, moved); } else { previous = last; last.insertAfter(moved); } // if (listener != null) { listener.onMove(moved, from, to, previous != null ? previous : null); } // Recurse perform(it.getSource()); } else if (change == HierarchyChangeType.MOVED_OUT) { // Do nothing } else if (change == HierarchyChangeType.REMOVED) { NodeContext<N1> removed = it.getSource(); NodeContext<N1> removedParent = removed.getParent(); // removed.remove(); // if (listener != null) { listener.onRemove(removed, removedParent); } } else { throw new UnsupportedOperationException("Not supported " + change); } } } // depth--; } // if (data != null) { if (!parent.data.state.equals(data.state)) { if (listener != null) { listener.onUpdate(parent, data.state); } } // if (!parent.data.name.equals(data.name)) { parent.name = data.name; if (listener != null) { listener.onRename(parent, parent.getParent(), data.name); } } // parent.state = updateAdapter.getState(d); parent.name = updateAdapter.getName(d); parent.data = data; // visitor.leave(depth, data.id, data.name, data.state); } // last = parent; } }