blob: 1bd79b2c980485058e19998607dde1b010eee7aa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ui.synchronize;
import org.eclipse.compare.structuremergeviewer.IDiffElement;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent;
import org.eclipse.team.core.synchronize.SyncInfo;
import org.eclipse.team.core.synchronize.SyncInfoTree;
import org.eclipse.team.internal.ui.ITeamUIImages;
import org.eclipse.team.internal.ui.Policy;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.team.ui.TeamImages;
import org.eclipse.team.ui.synchronize.ISynchronizeModelElement;
import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration;
/**
* An input that can be used with both {@link } and
* {@link }. The
* job of this input is to create the logical model of the contents of the
* sync set for displaying to the user. The created logical model must diff
* nodes.
* <p>
* 1. First, prepareInput is called to initialize the model with the given sync
* set. Building the model occurs in the ui thread.
* 2. The input must react to changes in the sync set and adjust its diff node
* model then update the viewer. In effect mediating between the sync set
* changes and the model shown to the user. This happens in the ui thread.
* </p>
* NOT ON DEMAND - model is created then maintained!
* @since 3.0
*/
public class HierarchicalModelProvider extends SynchronizeModelProvider {
public static class HierarchicalModelProviderDescriptor implements ISynchronizeModelProviderDescriptor {
public static final String ID = TeamUIPlugin.ID + ".modelprovider_hierarchical"; //$NON-NLS-1$
public String getId() {
return ID;
}
public String getName() {
return Policy.bind("HierarchicalModelProvider.0"); //$NON-NLS-1$
}
public ImageDescriptor getImageDescriptor() {
return TeamImages.getImageDescriptor(ITeamUIImages.IMG_HIERARCHICAL);
}
}
private static final HierarchicalModelProviderDescriptor hierarchicalDescriptor = new HierarchicalModelProviderDescriptor();
/**
* Create an input based on the provide sync set. The input is not initialized
* until <code>prepareInput</code> is called.
*
* @param set the sync set used as the basis for the model created by this input.
*/
public HierarchicalModelProvider(ISynchronizePageConfiguration configuration, SyncInfoTree set) {
super(configuration, set);
}
/* (non-Javadoc)
* @see org.eclipse.team.internal.ui.synchronize.ISynchronizeModelProvider#getDescriptor()
*/
public ISynchronizeModelProviderDescriptor getDescriptor() {
return hierarchicalDescriptor;
}
public ViewerSorter getViewerSorter() {
return new SynchronizeModelElementSorter();
}
protected SyncInfoTree getSyncInfoTree() {
return (SyncInfoTree)getSyncInfoSet();
}
/**
* Invoked by the <code>buildModelObject</code> method to create
* the childen of the given node. This method can be overriden
* by subclasses but subclasses should inv
* @param container
* @return
*/
protected IDiffElement[] createModelObjects(ISynchronizeModelElement container) {
IResource resource = null;
if (container == getModelRoot()) {
resource = ResourcesPlugin.getWorkspace().getRoot();
} else {
resource = container.getResource();
}
if(resource != null) {
SyncInfoTree infoTree = getSyncInfoTree();
IResource[] children = infoTree.members(resource);
ISynchronizeModelElement[] nodes = new ISynchronizeModelElement[children.length];
for (int i = 0; i < children.length; i++) {
nodes[i] = createModelObject(container, children[i]);
}
return nodes;
}
return new IDiffElement[0];
}
protected ISynchronizeModelElement createModelObject(ISynchronizeModelElement parent, IResource resource) {
SyncInfo info = getSyncInfoTree().getSyncInfo(resource);
SynchronizeModelElement newNode;
if(info != null) {
newNode = new SyncInfoModelElement(parent, info);
} else {
newNode = new UnchangedResourceModelElement(parent, resource);
}
addToViewer(newNode);
return newNode;
}
/**
* Invokes <code>getModelObject(Object)</code> on an array of resources.
* @param resources
* the resources
* @return the model objects for the resources
*/
protected Object[] getModelObjects(IResource[] resources) {
Object[] result = new Object[resources.length];
for (int i = 0; i < resources.length; i++) {
result[i] = getModelObject(resources[i]);
}
return result;
}
/**
* Handle the change for the existing diff node. The diff node
* should be changed to have the given sync info
* @param diffNode the diff node to be changed
* @param info the new sync info for the diff node
*/
protected void handleChange(ISynchronizeModelElement diffNode, SyncInfo info) {
IResource local = info.getLocal();
if(diffNode instanceof SyncInfoModelElement) {
((SyncInfoModelElement)diffNode).update(info);
propogateConflictState(diffNode, false);
} else {
removeFromViewer(local);
addResources(new IResource[] {local});
}
}
protected void addResources(IResource[] added) {
for (int i = 0; i < added.length; i++) {
IResource resource = added[i];
ISynchronizeModelElement node = getModelObject(resource);
if (node != null) {
// Somehow the node exists. Remove it and read it to ensure
// what is shown matches the contents of the sync set
removeFromViewer(resource);
}
// Build the sub-tree rooted at this node
ISynchronizeModelElement parent = getModelObject(resource.getParent());
if (parent != null) {
node = createModelObject(parent, resource);
buildModelObjects(node);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#buildModelObjects(org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement)
*/
protected IDiffElement[] buildModelObjects(ISynchronizeModelElement node) {
IDiffElement[] children = createModelObjects(node);
for (int i = 0; i < children.length; i++) {
IDiffElement element = children[i];
if (element instanceof ISynchronizeModelElement) {
buildModelObjects((ISynchronizeModelElement) element);
}
}
return children;
}
/* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#doAdd(org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement, org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement)
*/
protected void doAdd(ISynchronizeModelElement parent, ISynchronizeModelElement element) {
AbstractTreeViewer viewer = (AbstractTreeViewer)getViewer();
viewer.add(parent, element);
}
/* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#doRemove(org.eclipse.team.ui.synchronize.viewers.SynchronizeModelElement)
*/
protected void doRemove(ISynchronizeModelElement element) {
AbstractTreeViewer viewer = (AbstractTreeViewer)getViewer();
viewer.remove(element);
}
/* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceAdditions(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
*/
protected void handleResourceAdditions(ISyncInfoTreeChangeEvent event) {
IResource[] added = event.getAddedSubtreeRoots();
addResources(added);
}
/* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceChanges(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
*/
protected void handleResourceChanges(ISyncInfoTreeChangeEvent event) {
// Refresh the viewer for each changed resource
SyncInfo[] infos = event.getChangedResources();
for (int i = 0; i < infos.length; i++) {
SyncInfo info = infos[i];
IResource local = info.getLocal();
ISynchronizeModelElement diffNode = getModelObject(local);
if (diffNode != null) {
handleChange(diffNode, info);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.team.ui.synchronize.viewers.SynchronizeModelProvider#handleResourceRemovals(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
*/
protected void handleResourceRemovals(ISyncInfoTreeChangeEvent event) {
// Remove the removed subtrees
IResource[] removedRoots = event.getRemovedSubtreeRoots();
for (int i = 0; i < removedRoots.length; i++) {
removeFromViewer(removedRoots[i]);
}
// We have to look for folders that may no longer be in the set
// (i.e. are in-sync) but still have descendants in the set
IResource[] removedResources = event.getRemovedResources();
for (int i = 0; i < removedResources.length; i++) {
IResource resource = removedResources[i];
if (resource.getType() != IResource.FILE) {
ISynchronizeModelElement node = getModelObject(resource);
if (node != null) {
removeFromViewer(resource);
addResources(new IResource[] {resource});
}
}
}
}
}