Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 2236edc0da771fe8094fc9531e78724b29616eac (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
/*******************************************************************************
 * Copyright (c) 2008, 2016 Oracle. 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:
 *     Oracle - initial API and implementation
 ******************************************************************************/
package org.eclipse.jpt.common.ui.internal.jface;

import java.util.HashMap;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jpt.common.ui.internal.plugin.JptCommonUiPlugin;
import org.eclipse.jpt.common.ui.jface.ItemExtendedLabelProvider;
import org.eclipse.jpt.common.ui.jface.ItemTreeContentProvider;
import org.eclipse.jpt.common.ui.jface.TreeStateProvider;
import org.eclipse.jpt.common.utility.exception.ExceptionHandler;
import org.eclipse.jpt.common.utility.internal.ArrayTools;
import com.ibm.icu.text.MessageFormat;

/**
 * Add a cache of item content providers (for branch and leaf items).
 * 
 * @see AbstractItemStructuredStateProviderManager
 * @see ItemTreeContentProvider
 */
public class ItemTreeStateProviderManager
	extends AbstractItemStructuredStateProviderManager<TreeViewer, ItemTreeContentProvider, ItemTreeContentProvider.Factory>
	implements TreeStateProvider,
				ItemTreeContentProvider.Manager
{
	private final HashMap<Object, ItemTreeContentProvider> itemContentProviders = new HashMap<>();


	public ItemTreeStateProviderManager(ItemTreeContentProvider.Factory itemContentProviderFactory, ResourceManager resourceManager) {
		this(itemContentProviderFactory, NullItemExtendedLabelProviderFactory.instance(), resourceManager);
	}

	public ItemTreeStateProviderManager(
			ItemTreeContentProvider.Factory itemContentProviderFactory,
			ItemExtendedLabelProvider.Factory itemLabelProviderFactory,
			ResourceManager resourceManager
	) {
		this(itemContentProviderFactory, itemLabelProviderFactory, resourceManager, JptCommonUiPlugin.exceptionHandler());
	}

	public ItemTreeStateProviderManager(
			ItemTreeContentProvider.Factory itemContentProviderFactory,
			ItemExtendedLabelProvider.Factory itemLabelProviderFactory,
			ResourceManager resourceManager,
			ExceptionHandler exceptionHandler
	) {
		super(itemContentProviderFactory, itemLabelProviderFactory, resourceManager, exceptionHandler);
	}


	// ********** tree content provider **********

	/**
	 * We need a <code>null</code> check here because, when a project is
	 * renamed, the common viewer can be refreshed <em>before</em> we get the
	 * various change events, and the common viewer will call this method,
	 * passing the new project,* and we do not have the provider for the
	 * project yet.
	 */
	public boolean hasChildren(Object element) {
		ItemTreeContentProvider provider = this.getItemContentProvider(element);
		return (provider != null) && provider.hasChildren();
	}

	public Object[] getChildren(Object parentElement) {
		return this.getItemContentProvider(parentElement).getChildren();
	}

	/**
	 * We need a <code>null</code> check here because
	 * {@link org.eclipse.jface.viewers.StructuredViewer#preservingSelection(Runnable, boolean)}
	 * will call this method with a "dead" object in an attempt to save the
	 * selection when the view is updated.
	 */
	public Object getParent(Object element) {
		ItemTreeContentProvider provider = this.getItemContentProvider(element);
		return (provider == null) ? null : provider.getParent();
	}

	/**
	 * <strong>NB:</strong> We have a bug (probably in our <code>plugin.xml</code>)
	 * if this method ever returns <code>null</code> unexpectedly.
	 */
	private ItemTreeContentProvider getItemContentProvider(Object item) {
		return this.itemContentProviders.get(item);
	}


	// ********** children changed **********

	/**
	 * If the specified item has been removed from under us, ignore the "event".
	 */
	public void childrenChanged(Object item, Iterable<?> addedChildren, Iterable<?> removedChildren) {
		this.checkUIThread();
		if (this.getItemContentProvider(item) != null) {
			this.childrenChanged_(item, addedChildren, removedChildren);
		}
	}

	private void childrenChanged_(Object item, Iterable<?> addedChildren, Iterable<?> removedChildren) {
		this.addAll(item, addedChildren);
		this.removeAll(removedChildren);
		this.viewer.add(item, ArrayTools.array(addedChildren));
		this.viewer.remove(item, ArrayTools.array(removedChildren));
	}

	@Override
	/* private-protected */ void add(Object parent, Object item) {
		super.add(parent, item);
		ItemTreeContentProvider provider = this.itemContentProviderFactory.buildProvider(item, parent, this);
		this.itemContentProviders.put(item, provider);
		this.addAll(item, provider.getChildren());  // recurse over descendants
	}

	@Override
	/* private-protected */ void remove(Object item) {
		ItemTreeContentProvider provider = this.itemContentProviders.get(item);
		this.removeAll(provider.getChildren());  // recurse over descendants
		provider.dispose();
		this.itemContentProviders.remove(item);
		super.remove(item);
	}


	// ********** dispose **********

	@Override
	public void dispose() {
		super.dispose();
		if ( ! this.itemContentProviders.isEmpty()) {
			String msg = MessageFormat.format("Not all item content providers were disposed: {0}", this.itemContentProviders); //$NON-NLS-1$
			IllegalStateException ex = new IllegalStateException(msg);
			if (PLUG_IN != null) {
				PLUG_IN.logError(ex);
			} else {
				ex.printStackTrace();
			}
		}
	}
}

Back to the top