Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 451cfc74b8e9d03af46520d00108731974fb1ba0 (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
/*******************************************************************************
 *  Copyright (c) 2007, 2011 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.equinox.internal.p2.ui.model;

import java.util.*;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils;
import org.eclipse.equinox.internal.p2.ui.ElementQueryDescriptor;
import org.eclipse.equinox.internal.p2.ui.QueryProvider;
import org.eclipse.equinox.internal.p2.ui.query.IUViewQueryContext;
import org.eclipse.equinox.p2.query.IQueryable;
import org.eclipse.equinox.p2.ui.Policy;
import org.eclipse.equinox.p2.ui.ProvisioningUI;

/**
 * Element class that represents an element that gets its children
 * by using a query.
 * 
 * @since 3.4
 *
 */
public abstract class QueriedElement extends ProvElement {

	protected IQueryable<?> queryable;
	// This cache is used internally to facilitate child elements
	// that want to eliminate duplicates from the parent hierarchy.
	// This cache is *not* used as a general purpose child cache.
	private Collection<?> cachedChildren;

	protected QueriedElement(Object parent) {
		super(parent);
	}

	public Policy getPolicy() {
		Object parent = getParent(this);
		if (parent instanceof QueriedElement)
			return ((QueriedElement) parent).getPolicy();
		return getProvisioningUI().getPolicy();
	}

	public ProvisioningUI getProvisioningUI() {
		Object parent = getParent(this);
		if (parent instanceof QueriedElement)
			return ((QueriedElement) parent).getProvisioningUI();
		// if we really can't find a UI then get the default. In general this should
		// not happen though.  Turn on tracing in getDefaultUI() to see places where 
		// it is happening.
		return ProvisioningUI.getDefaultUI();

	}

	public IUViewQueryContext getQueryContext() {
		Object parent = getParent(this);
		if (parent instanceof QueriedElement)
			return ((QueriedElement) parent).getQueryContext();
		return null;
	}

	public Object[] getChildren(Object o) {
		Object[] cache = getCachedChildren();
		if (cache.length > 0) {
			return getCachedChildren();
		}
		return fetchChildren(o, new NullProgressMonitor());
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.ui.model.IWorkbenchAdapter#getLabel(java.lang.Object)
	 */
	public String getLabel(Object o) {
		return null;
	}

	/**
	 * Return the query type that is appropriate for this element when there
	 * is no query context.
	 * @return  The integer query type
	 */
	protected abstract int getDefaultQueryType();

	/**
	 * Return the query type that should be used for this element.
	 * Depending on the element, the query type may take the query context
	 * into account.  Subclasses should override this method if there are
	 * context-dependent decisions to be made to determine the query.
	 * @return The integer query type
	 */
	public int getQueryType() {
		return getDefaultQueryType();
	}

	protected Object[] fetchChildren(Object o, IProgressMonitor monitor) {
		cachedChildren = CollectionUtils.emptyList();
		QueryProvider provider = new QueryProvider(getProvisioningUI());
		ElementQueryDescriptor queryDescriptor = provider.getQueryDescriptor(this);
		if (queryDescriptor == null)
			return new Object[0];
		Collection<?> results = queryDescriptor.performQuery(monitor);
		cachedChildren = Collections.unmodifiableCollection(results);
		if (results.size() > 0) {
			Collection<Object> returnedChildren = new HashSet<Object>();
			returnedChildren.addAll(results);
			Object[] siblings = getSiblings();
			for (int i = 0; i < siblings.length; i++) {
				returnedChildren.remove(siblings[i]);
			}
			return returnedChildren.toArray();
		}
		return new Object[0];
	}

	public void setQueryable(IQueryable<?> queryable) {
		this.queryable = queryable;
	}

	public IQueryable<?> getQueryable() {
		return queryable;
	}

	/**
	 * Return a boolean indicating whether the receiver
	 * has enough information to get its queryable.  This is used in lieu
	 * of {{@link #getQueryable()} when lazy initialization
	 * of the queryable is not desired, and a client wishes
	 * to know whether the queryable could be obtained.  Subclasses
	 * that cache information needed to retrieve the queryable rather
	 * than the queryable itself should
	 * override this. 
	 * 
	 * @return <code>true</code> if the receiver has enough
	 * information to retrieve its queryable, <code>false</code> 
	 * if it does not.
	 */
	public boolean knowsQueryable() {
		return queryable != null;
	}

	/**
	 * Return a boolean indicating whether the receiver
	 * actually has its queryable.  This is used in lieu
	 * of {{@link #getQueryable()} when lazy initialization
	 * of the queryable is not desired.  For example, when
	 * working with an element whose queryable may be 
	 * expensive to obtain, clients may check this before
	 * actually getting the queryable.  Subclasses
	 * should typically not need to override this.
	 * 
	 * @return <code>true</code> if the receiver has its
	 * queryable, <code>false</code> if it does not yet.
	 */
	public boolean hasQueryable() {
		return queryable != null;
	}

	public Object[] getCachedChildren() {
		if (cachedChildren == null) {
			return new Object[0];
		}
		return cachedChildren.toArray();
	}

	protected Object[] getSiblings() {
		Object parent = getParent(this);
		if (parent instanceof QueriedElement)
			return ((QueriedElement) parent).getCachedChildren();
		if (parent instanceof IUElementListRoot)
			return ((IUElementListRoot) parent).getChildren(parent);
		return new Object[0];
	}
}

Back to the top