/******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.team.core.variants; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.team.core.Team; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.subscribers.ISubscriberChangeEvent; import org.eclipse.team.core.subscribers.SubscriberChangeEvent; import org.eclipse.team.internal.core.TeamPlugin; import org.eclipse.team.internal.core.subscribers.ThreeWayBaseTree; /** * A resource variant tree subscriber whose trees use an underlying * ThreeWaySycnrhonizer to store and manage the * synchronization state for the local workspace. Subclasses need to * provide a subclass of ThreeWayRemoteTree and a method * to create resource variant handles from the bytes cached in the * ThreeWaySynchronizer. * * @see ThreeWaySynchronizer * @see ThreeWayRemoteTree * @see CachedResourceVariant * * @since 3.0 */ public abstract class ThreeWaySubscriber extends ResourceVariantTreeSubscriber implements ISynchronizerChangeListener { private ThreeWayResourceComparator comparator; private ThreeWayBaseTree baseTree; private ThreeWayRemoteTree remoteTree; private ThreeWaySynchronizer synchronizer; /** * Create a three-way subscriber that uses the given synchronizer * to manage the synchronization state of local resoures * and their variants * @param synchronizer the three-way synchronizer for this subscriber */ protected ThreeWaySubscriber(ThreeWaySynchronizer synchronizer) { this.synchronizer = synchronizer; baseTree = new ThreeWayBaseTree(this); getSynchronizer().addListener(this); } /* (non-Javadoc) * @see org.eclipse.team.core.variants.ResourceVariantTreeSubscriber#getBaseTree() */ protected final IResourceVariantTree getBaseTree() { return baseTree; } /* (non-Javadoc) * @see org.eclipse.team.core.variants.ResourceVariantTreeSubscriber#getRemoteTree() */ protected final IResourceVariantTree getRemoteTree() { if (remoteTree == null) { remoteTree = createRemoteTree(); } return remoteTree; } /* (non-Javadoc) * @see org.eclipse.team.core.subscribers.Subscriber#getResourceComparator() */ public final IResourceVariantComparator getResourceComparator() { if (comparator == null) { comparator = new ThreeWayResourceComparator(this.getSynchronizer()); } return comparator; } /* (non-Javadoc) * @see org.eclipse.team.core.variants.ISynchronizerChangeListener#syncStateChanged(org.eclipse.core.resources.IResource[]) */ public void syncStateChanged(IResource[] resources) { fireTeamResourceChange(SubscriberChangeEvent.asSyncChangedDeltas(this, resources)); } /** * Returns false for resources that are not children * of a subscriber root, are ignored by the subscriber's synchronizer * or are ignored by the Team.ignoreHist(IResource). Returns * true otherwise. * @see org.eclipse.team.core.subscribers.Subscriber#isSupervised(IResource) */ public boolean isSupervised(IResource resource) throws TeamException { if (!isChildOfRoot(resource)) return false; if (getSynchronizer().isIgnored(resource)) return false; if (Team.isIgnoredHint(resource)) return false; return true; } /** * Return the three-way sychronizer of this subscriber. * @return the three-way sychronizer of this subscriber. */ public ThreeWaySynchronizer getSynchronizer() { return synchronizer; } /** * Create the resource variant for the given local resource from the * given bytes. The bytes are those that were previously returned * from a call to IResourceVariant#asBytes(). * @param resource the local resource * @param bytes the bytes that identify a variant of the resource * @return the resouce variant handle recreated from the bytes * @throws TeamException */ public abstract IResourceVariant getResourceVariant(IResource resource, byte[] bytes) throws TeamException; /** * Create the three-way remote tree which provides access to the * remote bytes in the three-way synchronizer. This method is invoked * once when the remote tree is first accessed. The returned object is * cached and reused on subsequent accesses. * @return the remote tree */ protected abstract ThreeWayRemoteTree createRemoteTree(); /** * Convenience method that can be used by subclasses to notify listeners * when a root is added or removed from the subscriber. The added * parameter should be true if the root was added and false * if it was removed. * @param resource the added or removed root * @param added true if the root was added and false * if it was removed. */ protected void handleRootChanged(IResource resource, boolean added) { if (added) { rootAdded(resource); } else { rootRemoved(resource); } } private void rootAdded(IResource resource) { SubscriberChangeEvent delta = new SubscriberChangeEvent(this, ISubscriberChangeEvent.ROOT_ADDED, resource); fireTeamResourceChange(new SubscriberChangeEvent[] { delta }); } private void rootRemoved(IResource resource) { try { getSynchronizer().flush(resource, IResource.DEPTH_INFINITE); } catch (TeamException e) { TeamPlugin.log(e); } SubscriberChangeEvent delta = new SubscriberChangeEvent(this, ISubscriberChangeEvent.ROOT_REMOVED, resource); fireTeamResourceChange(new SubscriberChangeEvent[] { delta }); } private boolean isChildOfRoot(IResource resource) { IResource[] roots = roots(); IPath fullPath = resource.getFullPath(); for (int i = 0; i < roots.length; i++) { IResource root = roots[i]; if (root.getFullPath().isPrefixOf(fullPath)) { return true; } } return false; } }