| package org.eclipse.team.internal.ui.sync; |
| |
| /* |
| * (c) Copyright IBM Corp. 2000, 2002. |
| * All Rights Reserved. |
| */ |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| |
| import org.eclipse.compare.structuremergeviewer.Differencer; |
| import org.eclipse.compare.structuremergeviewer.IDiffContainer; |
| import org.eclipse.compare.structuremergeviewer.IDiffElement; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.team.core.sync.IRemoteSyncElement; |
| import org.eclipse.team.internal.ui.Policy; |
| |
| /** |
| * <b>Note:</b> This class/interface is part of an interim API that is still under |
| * development and expected to change significantly before reaching stability. |
| * It is being made available at this early stage to solicit feedback from pioneering |
| * adopters on the understanding that any code that uses this API will almost |
| * certainly be broken (repeatedly) as the API evolves. |
| * |
| * This class contains a set of resources that are slated to be |
| * synchronized. It performs various operations on the |
| * set in preparation for catchup/release. |
| */ |
| public class SyncSet { |
| private HashSet set; |
| |
| /** |
| * Creates a new sync set on the nodes in the given selection. |
| */ |
| public SyncSet(IStructuredSelection nodeSelection) { |
| this.set = new HashSet(nodeSelection.size() + 1); |
| collectNodes(nodeSelection); |
| } |
| |
| /** |
| * Collects all nodes to which this action will apply. This means |
| * all nodes in the selection, plus all their children. |
| */ |
| private void collectNodes(IStructuredSelection selection) { |
| Object[] nodes = selection.toArray(); |
| for (int i = 0; i < nodes.length; i++) { |
| recursivelyAdd((ITeamNode)nodes[i]); |
| } |
| } |
| |
| /** |
| * Adds all parent creations for the given node to the sync set. |
| */ |
| private void collectParentCreations(ITeamNode node) { |
| IDiffElement parent = node.getParent(); |
| if (parent != null && parent instanceof ITeamNode) { |
| if (parent.getKind() != IRemoteSyncElement.IN_SYNC) { |
| set.add(parent); |
| collectParentCreations((ITeamNode)parent); |
| } |
| } |
| } |
| |
| /** |
| * Returns all nodes in the set that have changes |
| */ |
| public ITeamNode[] getChangedNodes() { |
| ArrayList nodeList = new ArrayList(set.size()); |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| ITeamNode node = (ITeamNode)it.next(); |
| int dir = node.getChangeDirection(); |
| // We assume changed nodes of the wrong type have been culled |
| // during set creation. |
| if (dir != Differencer.NO_CHANGE) { |
| nodeList.add(node); |
| } |
| } |
| ITeamNode[] nodes = new ITeamNode[nodeList.size()]; |
| nodeList.toArray(nodes); |
| return nodes; |
| } |
| |
| /** |
| * Returns the resources from all the nodes in this set. |
| */ |
| public IResource[] getResources() { |
| ITeamNode[] changed = getChangedNodes(); |
| IResource[] resources = new IResource[changed.length]; |
| for (int i = 0; i < changed.length; i++) { |
| resources[i] = changed[i].getResource(); |
| } |
| return resources; |
| } |
| |
| /** |
| * Returns a message for the status line describing this sync set. |
| */ |
| public String getStatusLineMessage() { |
| int incoming = 0; |
| int outgoing = 0; |
| int conflicts = 0; |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| ITeamNode next = (ITeamNode)it.next(); |
| switch (next.getChangeDirection()) { |
| case IRemoteSyncElement.INCOMING: |
| incoming++; |
| break; |
| case IRemoteSyncElement.OUTGOING: |
| outgoing++; |
| break; |
| case IRemoteSyncElement.CONFLICTING: |
| conflicts++; |
| break; |
| } |
| } |
| StringBuffer result = new StringBuffer(); |
| |
| if (conflicts == 0) { |
| result.append(Policy.bind("SyncSet.noConflicts")); //$NON-NLS-1$ |
| } else { |
| result.append(Policy.bind("SyncSet.conflicts", new Object[] {Integer.toString(conflicts)} )); //$NON-NLS-1$ |
| } |
| if (incoming == 0) { |
| result.append(Policy.bind("SyncSet.noIncomings")); //$NON-NLS-1$ |
| } else { |
| result.append(Policy.bind("SyncSet.incomings", new Object[] {Integer.toString(incoming)} )); //$NON-NLS-1$ |
| } |
| if (outgoing == 0) { |
| result.append(Policy.bind("SyncSet.noOutgoings")); //$NON-NLS-1$ |
| } else { |
| result.append(Policy.bind("SyncSet.outgoings", new Object[] {Integer.toString(outgoing)} )); //$NON-NLS-1$ |
| } |
| return result.toString(); |
| } |
| |
| /** |
| * Returns true if there are any conflicting nodes in the set, and |
| * false otherwise. |
| */ |
| public boolean hasConflicts() { |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| if (((ITeamNode)it.next()).getChangeDirection() == IRemoteSyncElement.CONFLICTING) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns true if this sync set has incoming changes. |
| * Note that conflicts are not considered to be incoming changes. |
| */ |
| public boolean hasIncomingChanges() { |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| if (((ITeamNode)it.next()).getChangeDirection() == IRemoteSyncElement.INCOMING) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns true if this sync set has outgoing changes. |
| * Note that conflicts are not considered to be outgoing changes. |
| */ |
| public boolean hasOutgoingChanges() { |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| if (((ITeamNode)it.next()).getChangeDirection() == IRemoteSyncElement.OUTGOING) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns true if this sync set has auto-mergeable conflicts. |
| */ |
| public boolean hasAutoMergeableConflicts() { |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| ITeamNode node = (ITeamNode)it.next(); |
| if ((node.getKind() & IRemoteSyncElement.AUTOMERGE_CONFLICT) != 0) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Adds the given node, plus all its children, to the given set. |
| */ |
| private void recursivelyAdd(ITeamNode node) { |
| // Add the node and recurse |
| if (set.add(node)) { |
| if (node instanceof IDiffContainer) { |
| IDiffElement[] children = ((IDiffContainer)node).getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| if (children[i] instanceof ITeamNode) { |
| recursivelyAdd((ITeamNode)children[i]); |
| } |
| } |
| } |
| // Add any created parents (can't release or load a |
| // resource creation without including new parents) |
| collectParentCreations(node); |
| } |
| } |
| |
| /** |
| * Removes all conflicting nodes from this set. |
| */ |
| public void removeConflictingNodes() { |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| ITeamNode node = (ITeamNode)it.next(); |
| if (node.getChangeDirection() == IRemoteSyncElement.CONFLICTING) { |
| it.remove(); |
| } |
| } |
| } |
| /** |
| * Removes all outgoing nodes from this set. |
| */ |
| public void removeOutgoingNodes() { |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| ITeamNode node = (ITeamNode)it.next(); |
| if (node.getChangeDirection() == IRemoteSyncElement.OUTGOING) { |
| it.remove(); |
| } |
| } |
| } |
| /** |
| * Removes all incoming nodes from this set. |
| */ |
| public void removeIncomingNodes() { |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| ITeamNode node = (ITeamNode)it.next(); |
| if (node.getChangeDirection() == IRemoteSyncElement.INCOMING) { |
| it.remove(); |
| } |
| } |
| } |
| /** |
| * Removes all conflicting nodes from this set that are not auto-mergeable |
| */ |
| public void removeNonMergeableNodes() { |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| ITeamNode node = (ITeamNode)it.next(); |
| if ((node.getKind() & IRemoteSyncElement.MANUAL_CONFLICT) != 0) { |
| it.remove(); |
| } |
| } |
| } |
| |
| /** |
| * Removes all nodes that aren't applicable for the direction. |
| */ |
| public void removeNonApplicableNodes(int direction) { |
| for (Iterator it = set.iterator(); it.hasNext();) { |
| ITeamNode node = (ITeamNode)it.next(); |
| int nodeDirection = node.getKind() & IRemoteSyncElement.DIRECTION_MASK; |
| if (nodeDirection != IRemoteSyncElement.CONFLICTING) { |
| if (nodeDirection != direction) { |
| it.remove(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Remove the given node from the sync set |
| */ |
| public void remove(ITeamNode node) { |
| set.remove(node); |
| } |
| } |