Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: b160e29d0b612d0771c837c0704c5f138c7eb2ad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/*******************************************************************************
 * Copyright (c) 2000, 2017 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.team.internal.ui.synchronize;

import java.util.*;

import org.eclipse.core.resources.IResource;
import org.eclipse.team.core.synchronize.*;
import org.eclipse.team.ui.synchronize.ISynchronizeModelElement;
import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration;

/**
 * This class provides functionality for defining composite synchronize model
 * providers. A composite provider is one that breaks up the displayed
 * {@link SyncInfoSet} into subsets that may be displayed using one
 * or more synchronize model providers.
 *
 */
public abstract class CompositeModelProvider extends AbstractSynchronizeModelProvider {

    private final List<ISynchronizeModelProvider> providers = new ArrayList<>();
    private final Map<IResource, List <ISynchronizeModelElement>> resourceToElements = new HashMap<>();
    private final Map<ISynchronizeModelElement, AbstractSynchronizeModelProvider> elementToProvider = new HashMap<>();

    protected CompositeModelProvider(ISynchronizePageConfiguration configuration, SyncInfoSet set) {
        super(configuration, set);
    }

    /**
     * Add the provider to the list of providers.
     * @param provider the provider to be added
     */
    protected void addProvider(ISynchronizeModelProvider provider) {
        providers.add(provider);
    }

    /**
     * Remove the provider from the list of providers.
     * @param provider the provider to be removed
     */
    protected void removeProvider(ISynchronizeModelProvider provider) {
        providers.remove(provider);
        provider.dispose();
    }

    @Override
	protected ISynchronizeModelProvider getProvider(ISynchronizeModelElement element) {
        return elementToProvider.get(element);
    }

    @Override
	public ISynchronizeModelElement[] getClosestExistingParents(IResource resource) {
        ISynchronizeModelProvider[] providers = getProviders();
        if (providers.length == 0) {
            return new ISynchronizeModelElement[0];
        }
        if (providers.length == 1 && providers[0] instanceof AbstractSynchronizeModelProvider) {
            return ((AbstractSynchronizeModelProvider)providers[0]).getClosestExistingParents(resource);
        }
        List<ISynchronizeModelElement> result = new ArrayList<>();
        for (int i = 0; i < providers.length; i++) {
            ISynchronizeModelProvider provider = providers[i];
            if (provider instanceof AbstractSynchronizeModelProvider) {
	            ISynchronizeModelElement[] elements = ((AbstractSynchronizeModelProvider)provider).getClosestExistingParents(resource);
	            for (int j = 0; j < elements.length; j++) {
	                ISynchronizeModelElement element = elements[j];
	                result.add(element);
	            }
            }
        }
        return result.toArray(new ISynchronizeModelElement[result.size()]);
    }

    /**
     * Return all the sub-providers of this composite.
     * @return the sub-providers of this composite
     */
    protected ISynchronizeModelProvider[] getProviders() {
        return providers.toArray(new ISynchronizeModelProvider[providers.size()]);
    }

    /**
     * Return the providers that are displaying the given resource.
     * @param resource the resource
     * @return the providers displaying the resource
     */
    protected ISynchronizeModelProvider[] getProvidersContaining(IResource resource) {
        List<ISynchronizeModelElement> elements = resourceToElements.get(resource);
        if (elements == null || elements.isEmpty()) {
            return new ISynchronizeModelProvider[0];
        }
        List<ISynchronizeModelProvider> result = new ArrayList<>();
        for (Iterator<ISynchronizeModelElement> iter = elements.iterator(); iter.hasNext();) {
            ISynchronizeModelElement element = iter.next();
            result.add(getProvider(element));
        }
        return result.toArray(new ISynchronizeModelProvider[result.size()]);
    }

    @Override
	protected final void handleResourceAdditions(ISyncInfoTreeChangeEvent event) {
        handleAdditions(event.getAddedResources());
    }

    /**
     * Handle the resource additions by adding them to any existing
     * sub-providers or by creating addition sub-providers as needed.
     * @param resources
     */
    protected void handleAdditions(SyncInfo[] resources) {
        for (int i = 0; i < resources.length; i++) {
            SyncInfo info = resources[i];
            handleAddition(info);
        }
    }

    /**
     * Handle the addition of the given sync info to this provider
     * @param info the added sync info
     */
    protected abstract void handleAddition(SyncInfo info);

    /* (non-Javadoc)
     * @see org.eclipse.team.internal.ui.synchronize.AbstractSynchronizeModelProvider#handleResourceChanges(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
     */
    @Override
	protected final void handleResourceChanges(ISyncInfoTreeChangeEvent event) {
        SyncInfo[] infos = event.getChangedResources();
        for (int i = 0; i < infos.length; i++) {
            SyncInfo info = infos[i];
            handleChange(info);
        }
    }

    /**
     * The state of the sync info for a resource has changed. Propagate the
     * change to any sub-providers that contain the resource.
     * @param info the sync info for the resource whose sync state has changed
     */
    protected void handleChange(SyncInfo info) {
        handleRemoval(info.getLocal());
        handleAddition(info);
    }

    /* (non-Javadoc)
     * @see org.eclipse.team.internal.ui.synchronize.AbstractSynchronizeModelProvider#handleResourceRemovals(org.eclipse.team.core.synchronize.ISyncInfoTreeChangeEvent)
     */
    @Override
	protected final void handleResourceRemovals(ISyncInfoTreeChangeEvent event) {
        IResource[] resources = event.getRemovedResources();
        for (int i = 0; i < resources.length; i++) {
            IResource resource = resources[i];
            handleRemoval(resource);
        }
    }

    /**
     * Remove the resource from all providers that are displaying it
     * @param resource the resource to be removed
     */
    protected void handleRemoval(IResource resource) {
        ISynchronizeModelProvider[] providers = getProvidersContaining(resource);
        for (int i = 0; i < providers.length; i++) {
            ISynchronizeModelProvider provider = providers[i];
            removeFromProvider(resource, provider);
        }
    }

    /**
     * Remove the resource from the sync set of the given provider
     * unless the provider is this composite. Subclasses can
     * override if they show resources directly.
     * @param resource the resource to be removed
     * @param provider the provider from which to remove the resource
     */
    protected void removeFromProvider(IResource resource, ISynchronizeModelProvider provider) {
        if (provider != this) {
            provider.getSyncInfoSet().remove(resource);
        }
    }

	@Override
	protected void nodeAdded(ISynchronizeModelElement node, AbstractSynchronizeModelProvider provider) {
		// Update the resource-to-element map and the element-to-provider map
		IResource r = node.getResource();
		if(r != null) {
			List<ISynchronizeModelElement> elements = resourceToElements.get(r);
			if(elements == null) {
				elements = new ArrayList<>(2);
				resourceToElements.put(r, elements);
			}
			elements.add(node);
		}
		elementToProvider.put(node, provider);
		super.nodeAdded(node, provider);
	}

    @Override
	public void modelObjectCleared(ISynchronizeModelElement node) {
        super.modelObjectCleared(node);
	    IResource r = node.getResource();
		if(r != null) {
			List elements = resourceToElements.get(r);
			if(elements != null) {
				elements.remove(node);
				if (elements.isEmpty()) {
				    resourceToElements.remove(r);
				}
			}
		}
		elementToProvider.remove(node);
    }

    @Override
	protected void recursiveClearModelObjects(ISynchronizeModelElement node) {
        super.recursiveClearModelObjects(node);
        if (node == getModelRoot()) {
            clearProviders();
        }
    }

    private void clearProviders() {
        for (Iterator iter = providers.iterator(); iter.hasNext();) {
            ISynchronizeModelProvider provider = (ISynchronizeModelProvider) iter.next();
            provider.dispose();
        }
        providers.clear();
        resourceToElements.clear();
        elementToProvider.clear();
    }

    /**
     * Helper method for creating a provider for the given id.
     * @param parent the root node for the new provider
     * @param id the id of the providers descriptor
     * @return the new provider
     */
	protected ISynchronizeModelProvider createModelProvider(ISynchronizeModelElement parent, String id, SyncInfoTree syncInfoTree) {
        if (id != null && id.endsWith(FlatModelProvider.FlatModelProviderDescriptor.ID)) {
		    return new FlatModelProvider(this, parent, getConfiguration(), syncInfoTree);
		} else if (id != null && id.endsWith(CompressedFoldersModelProvider.CompressedFolderModelProviderDescriptor.ID)) {
			return new CompressedFoldersModelProvider(this, parent, getConfiguration(), syncInfoTree);
		} else {
			return new HierarchicalModelProvider(this, parent, getConfiguration(), syncInfoTree);
		}
	}

    @Override
	public void dispose() {
        clearProviders();
        super.dispose();
    }

    @Override
	protected boolean hasViewerState() {
        return resourceToElements != null && !resourceToElements.isEmpty();
    }

    @Override
	protected ISynchronizeModelElement[] getModelObjects(IResource resource) {
        List<ISynchronizeModelElement> elements = resourceToElements.get(resource);
        if (elements == null) {
            return new ISynchronizeModelElement[0];
        }
        return elements.toArray(new ISynchronizeModelElement[elements.size()]);
    }
}

Back to the top