Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 400512e3bd5c33610a5e99205f64a82e355bab00 (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
/*******************************************************************************
 * Copyright (c) 2000, 2009 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.ui.internal.navigator.resources;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;

import org.eclipse.swt.widgets.Item;
import org.eclipse.ui.navigator.CommonViewer;
import org.eclipse.ui.navigator.ICommonViewerMapper;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;

/**
 * Adds a supplemental map for the CommonViewer to efficiently handle resource
 * changes.  When objects are added to the Viewer's map, this is called to see
 * if there is an associated resource.  If so, it's added to the map here.
 * When resource change notifications happen, this map is checked, and if the
 * resource is found, this class causes the Viewer to be updated.  If the 
 * resource is not found, the notification can be ignored because the object
 * corresponding to the resource is not present in the viewer.
 * 
 */
public class ResourceToItemsMapper implements ICommonViewerMapper {

	private static final int NUMBER_LIST_REUSE = 10;

	// map from resource to item. Value can be single Item of List<Item>
	private HashMap<IResource, Object> _resourceToItem;
	private Stack<List<Item>> _reuseLists;

	private CommonViewer _commonViewer;

	public ResourceToItemsMapper(CommonViewer viewer) {
		_resourceToItem = new HashMap<IResource, Object>();
		_reuseLists = new Stack<List<Item>>();

		_commonViewer = viewer;
		viewer.setMapper(this);
	}

	public void addToMap(Object element, Item item) {
		IResource resource = getCorrespondingResource(element);
		if (resource != null) {
			Object existingMapping = _resourceToItem.get(resource);
			if (existingMapping == null) {
				_resourceToItem.put(resource, item);
			} else if (existingMapping instanceof Item) {
				if (existingMapping != item) {
					List<Item> list = getNewList();
					list.add((Item)existingMapping);
					list.add(item);
					_resourceToItem.put(resource, list);
				}
			} else { // List
				List<Item> list = (List<Item>) existingMapping;
				if (!list.contains(item)) {
					list.add(item);
				}
			}
		}
	}

	public void removeFromMap(Object element, Item item) {
		IResource resource = getCorrespondingResource(element);
		if (resource != null) {
			Object existingMapping = _resourceToItem.get(resource);
			if (existingMapping == null) {
				return;
			} else if (existingMapping instanceof Item) {
				_resourceToItem.remove(resource);
			} else { // List
				List<Item> list = (List<Item>) existingMapping;
				list.remove(item);
				if (list.isEmpty()) {
					_resourceToItem.remove(list);
					releaseList(list);
				}
			}
		}
	}

	public void clearMap() {
		_resourceToItem.clear();
	}

	public boolean isEmpty() {
		return _resourceToItem.isEmpty();
	}

	private List<Item> getNewList() {
		if (!_reuseLists.isEmpty()) {
			return _reuseLists.pop();
		}
		return new ArrayList<Item>(2);
	}

	private void releaseList(List<Item> list) {
		if (_reuseLists.size() < NUMBER_LIST_REUSE) {
			_reuseLists.push(list);
		}
	}

	public boolean handlesObject(Object object) {
		return object instanceof IResource;
	}
	

	/**
	 * Must be called from the UI thread.
	 * 
	 * @param changedResource
	 *            Changed resource
	 */
	public void objectChanged(Object changedResource) {
		Object obj = _resourceToItem.get(changedResource);
		if (obj == null) {
			// not mapped
		} else if (obj instanceof Item) {
			updateItem((Item) obj);
		} else { // List of Items
			List<Item> list = (List<Item>) obj;
			for (Item item : list) {
				updateItem(item);
			}
		}
	}

	private void updateItem(Item item) {
		if (!item.isDisposed()) {
			_commonViewer.doUpdateItem(item);
		}
	}

	private static IResource getCorrespondingResource(Object element) {
		if (element instanceof IResource)
			return (IResource) element;
		if (element instanceof IAdaptable)
			return (IResource) ((IAdaptable) element).getAdapter(IResource.class);
		return null;
	}
}

Back to the top