1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.team.core.subscribers;
15 
16 import org.eclipse.core.resources.IResource;
17 import org.eclipse.core.resources.IWorkspaceRunnable;
18 import org.eclipse.core.resources.mapping.ResourceTraversal;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.core.runtime.IProgressMonitor;
21 import org.eclipse.core.runtime.ProgressMonitorWrapper;
22 import org.eclipse.team.core.diff.DiffFilter;
23 import org.eclipse.team.core.mapping.ISynchronizationScopeManager;
24 import org.eclipse.team.core.mapping.provider.MergeContext;
25 import org.eclipse.team.core.mapping.provider.ResourceDiffTree;
26 import org.eclipse.team.core.synchronize.SyncInfo;
27 import org.eclipse.team.internal.core.mapping.GroupProgressMonitor;
28 import org.eclipse.team.internal.core.subscribers.SubscriberDiffTreeEventHandler;
29 
30 /**
31  * A merge context that uses a subscriber to populate the diff tree
32  * used by the context. The population of the diff tree is performed
33  * by a handler that runs in a background job.
34  *
35  * @see Subscriber
36  * @see MergeContext
37  *
38  * @since 3.2
39  */
40 public abstract class SubscriberMergeContext extends MergeContext {
41 
42 	private Subscriber subscriber;
43 	private SubscriberDiffTreeEventHandler handler;
44 	private final ISynchronizationScopeManager manager;
45 
46 	/**
47 	 * Create a merge context for the given subscriber
48 	 * @param subscriber the subscriber
49 	 * @param manager the scope manager
50 	 */
SubscriberMergeContext(Subscriber subscriber, ISynchronizationScopeManager manager)51 	protected SubscriberMergeContext(Subscriber subscriber, ISynchronizationScopeManager manager) {
52 		super(manager, getType(subscriber), new ResourceDiffTree());
53 		this.subscriber = subscriber;
54 		this.manager = manager;
55 	}
56 
getType(Subscriber subscriber)57 	private static int getType(Subscriber subscriber) {
58 		return subscriber.getResourceComparator().isThreeWay()
59 			? THREE_WAY : TWO_WAY;
60 	}
61 
62 	/**
63 	 * Initialize the diff tree of this context. This method must
64 	 * be called before the context is given to clients.
65 	 */
initialize()66 	protected void initialize() {
67 		handler = new SubscriberDiffTreeEventHandler(subscriber, manager, (ResourceDiffTree)getDiffTree(), getDiffFilter());
68 		handler.setJobFamily(this);
69 		handler.start();
70 	}
71 
72 	/**
73 	 * Return the diff filter used to filter the differences that the merge context will present to clients.
74 	 * @return the diff filter used to filter the differences that the merge context will present to clients
75 	 * @since 3.3
76 	 */
getDiffFilter()77 	protected DiffFilter getDiffFilter() {
78 		return null;
79 	}
80 
81 	@Override
refresh(ResourceTraversal[] traversals, int flags, IProgressMonitor monitor)82 	public void refresh(ResourceTraversal[] traversals, int flags,
83 			IProgressMonitor monitor) throws CoreException {
84 		GroupProgressMonitor group = getGroup(monitor);
85 		if (group != null)
86 			handler.setProgressGroupHint(group.getGroup(), group.getTicks());
87 		handler.initializeIfNeeded();
88 		subscriber.refresh(traversals, monitor);
89 	}
90 
getGroup(IProgressMonitor monitor)91 	private GroupProgressMonitor getGroup(IProgressMonitor monitor) {
92 		if (monitor instanceof GroupProgressMonitor) {
93 			return (GroupProgressMonitor) monitor;
94 		}
95 		if (monitor instanceof ProgressMonitorWrapper) {
96 			ProgressMonitorWrapper wrapper = (ProgressMonitorWrapper) monitor;
97 			return getGroup(wrapper.getWrappedProgressMonitor());
98 		}
99 		return null;
100 	}
101 
102 	@Override
dispose()103 	public void dispose() {
104 		handler.shutdown();
105 		super.dispose();
106 	}
107 
108 	/**
109 	 * Return the sync info for the given resource.
110 	 * @param resource the resource
111 	 * @return the sync info for the resource obtained from the subscriber
112 	 * @throws CoreException if an error occurs
113 	 */
getSyncInfo(IResource resource)114 	protected SyncInfo getSyncInfo(IResource resource) throws CoreException {
115 		return handler.getSubscriber().getSyncInfo(resource);
116 	}
117 
118 	/**
119 	 * Return the subscriber associated with this context.
120 	 * @return the subscriber associated with this context
121 	 */
getSubscriber()122 	public Subscriber getSubscriber() {
123 		return subscriber;
124 	}
125 
126 	/**
127 	 * Run the given runnable when the background handler
128 	 * for this context is idle. The given runnable should not lock
129 	 * the workspace.
130 	 * @param runnable the runnable
131 	 */
runInBackground(IWorkspaceRunnable runnable)132 	protected void runInBackground(IWorkspaceRunnable runnable) {
133 		handler.run(runnable, false);
134 	}
135 
136 	@Override
137 	@SuppressWarnings("unchecked")
getAdapter(Class<T> adapter)138 	public <T> T getAdapter(Class<T> adapter) {
139 		if (adapter == SubscriberDiffTreeEventHandler.class)
140 			return (T) handler;
141 		return super.getAdapter(adapter);
142 	}
143 
144 }
145