Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: c9fc5c76b12b0a948c7061ff5e2361ed6a8cb7b7 (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
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/*******************************************************************************
 * Copyright (c) 2012 Wind River Systems, Inc. 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:
 * Wind River Systems - initial API and implementation
 *******************************************************************************/
package org.eclipse.tcf.te.ui.views.internal.categories;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.graphics.Image;
import org.eclipse.tcf.te.ui.views.ViewsUtil;
import org.eclipse.tcf.te.ui.views.extensions.CategoriesExtensionPointManager;
import org.eclipse.tcf.te.ui.views.interfaces.ICategory;
import org.eclipse.tcf.te.ui.views.interfaces.IUIConstants;
import org.eclipse.tcf.te.ui.views.interfaces.categories.ICategorizable;
import org.eclipse.ui.ISources;
import org.eclipse.ui.actions.CompoundContributionItem;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.menus.IWorkbenchContribution;
import org.eclipse.ui.services.IServiceLocator;

/**
 * Abstract categories dynamic menu contribution implementation.
 */
public abstract class AbstractCategoryContributionItem extends CompoundContributionItem implements IWorkbenchContribution {
	// Service locator to located the handler service.
	protected IServiceLocator serviceLocator;

	/**
	 * Abstract category action implementation.
	 */
	protected abstract static class AbstractCategoryAction extends Action {
		// The parent contribution item
		private final AbstractCategoryContributionItem item;
		// The selection
		private final ISelection selection;
		// The category
		private final ICategory category;

		/**
         * Constructor.
         *
         * @param item The parent contribution item. Must not be <code>null</code>:
         * @param selection The selection. Must not be <code>null</code>.
         * @param category The category. Must not be <code>null</code>.
         * @param single <code>True</code> if the action is the only item added, <code>false</code> otherwise.
         */
        public AbstractCategoryAction(AbstractCategoryContributionItem item, ISelection selection, ICategory category, boolean single) {
        	super();

        	Assert.isNotNull(item);
        	this.item = item;
        	Assert.isNotNull(selection);
        	this.selection = selection;
        	Assert.isNotNull(category);
        	this.category = category;

        	initialize(single);
        }

        /**
         * Initialize the action state.
         *
         * @param single <code>True</code> if the action is the only item added, <code>false</code> otherwise.
         */
        protected void initialize(boolean single) {
        	setText(single ? makeSingleText(category.getLabel()) : category.getLabel());

        	Image image = category.getImage();
        	if (image != null) setImageDescriptor(ImageDescriptor.createFromImage(image));
        }

        /**
         * Returns the action label in "single" mode.
         *
         * @param text The original label. Must not be <code>null</code>.
         * @return The "single" mode label.
         */
        protected String makeSingleText(String text) {
        	Assert.isNotNull(text);
        	return text;
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.action.Action#run()
         */
        @Override
        public void run() {
        	if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
        		boolean refresh = false;
        		Iterator<?> iterator = ((IStructuredSelection)selection).iterator();
        		while (iterator.hasNext()) {
        			Object element = iterator.next();
        			refresh |= execute(element, category);
        		}

        		// Refresh the view
        		if (refresh) ViewsUtil.refresh(IUIConstants.ID_EXPLORER);
        	}
        }

    	/**
    	 * Returns the categorizable for the given element.
    	 *
    	 * @param element The element or <code>null</code>.
    	 * @return The categorizable or <code>null</code>.
    	 */
    	protected ICategorizable getCategorizable(Object element) {
    		return item.getCategorizable(element);
    	}

        /**
         * Executes the operation to do on the given element.
         *
         * @param selection The selection. Must not be <code>null</code>.
         * @param category The category. Must not be <code>null</code>.
         *
         * @return <code>True</code> if the view needs refreshment, <code>false</code> otherwise.
         */
        protected abstract boolean execute(Object element, ICategory category);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.menus.IWorkbenchContribution#initialize(org.eclipse.ui.services.IServiceLocator)
	 */
	@Override
	public void initialize(IServiceLocator serviceLocator) {
		this.serviceLocator = serviceLocator;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.actions.CompoundContributionItem#getContributionItems()
	 */
	@Override
	protected IContributionItem[] getContributionItems() {
		// Get the selected node.
		IHandlerService service = (IHandlerService)serviceLocator.getService(IHandlerService.class);
		IEvaluationContext state = service.getCurrentState();
		ISelection selection = (ISelection)state.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME);
		IStructuredSelection iss = (IStructuredSelection)selection;

		List<IContributionItem> items = new ArrayList<IContributionItem>();
		ICategory[] categories = getCategories(iss, false);

		// Generate the action contribution items
		for (ICategory category : categories) {
			IAction action = createAction(this, iss, category, categories.length == 1);
			if (action != null) {
				action.setEnabled(isEnabled(iss, category));
				items.add(new ActionContributionItem(action));
			}
		}

		return items.toArray(new IContributionItem[items.size()]);
	}

	/**
	 * Returns the list of valid categories for the given selection.
	 *
	 * @param selection The selection. Must not be <code>null</code>.
	 * @param onlyEnabled If <code>true</code>, returns categories which are valid and enabled only.
	 *
	 * @return The list of valid categories for the given selection, or an empty list.
	 */
	protected ICategory[] getCategories(IStructuredSelection selection, boolean onlyEnabled) {
		Assert.isNotNull(selection);

		List<ICategory> categories = new ArrayList<ICategory>();
		ICategory[] allCategories = CategoriesExtensionPointManager.getInstance().getCategories(false);

		// Analyze the selection and add categories valid for all items in the selection
		boolean firstRun = true;
		Iterator<?> iterator = selection.iterator();
		while (iterator.hasNext()) {
			Object element = iterator.next();
			ICategory parentCategory = getParentCategory(element, selection);

			List<ICategory> candidates = new ArrayList<ICategory>();
			for (ICategory category : allCategories) {
				if (isValid(parentCategory, element, category)
						&& (!onlyEnabled || isEnabled(selection, category))) {
					candidates.add(category);
				}
			}

			// On first run, we remember the candidates as is
			if (firstRun) {
				categories.addAll(candidates);
				firstRun = false;
			} else {
				// Eliminate all categories not being listed as candidate too
				Iterator<ICategory> catIterator = categories.iterator();
				while (catIterator.hasNext()) {
					ICategory category = catIterator.next();
					if (!candidates.contains(category)) {
						catIterator.remove();
					}
				}
			}
		}

		return categories.toArray(new ICategory[categories.size()]);
	}

	/**
	 * Creates the category action instance.
	 *
     * @param item The parent contribution item. Must not be <code>null</code>:
	 * @param selection The selection. Must not be <code>null</code>.
	 * @param category The category. Must not be <code>null</code>.
	 * @param single <code>True</code> if the action is the only item added, <code>false</code> otherwise.
	 *
	 * @return The category action instance.
	 */
	protected abstract IAction createAction(AbstractCategoryContributionItem item, ISelection selection, ICategory category, boolean single);

	/**
	 * Tests if the given combination is valid. If not valid, the combination
	 * will not be added to the menu.
	 *
	 * @param parentCategory The parent category. Must not be <code>null</code>.
	 * @param element The element. Must not be <code>null</code>.
	 * @param category The category. Must not be <code>null</code>.
	 *
	 * @return <code>True</code> if the given combination is valid, <code>false</code> otherwise.
	 */
	protected abstract boolean isValid(ICategory parentCategory, Object element, ICategory category);

	/**
	 * Tests if the given combination is enabled.
	 *
	 * @param element The selection. Must not be <code>null</code>.
	 * @param category The category. Must not be <code>null</code>.
	 *
	 * @return <code>True</code> if the given combination is enabled, <code>false</code> otherwise.
	 */
	protected abstract boolean isEnabled(ISelection selection, ICategory category);

	/**
	 * Determines the parent category for the given element, based on the
	 * given selection.
	 *
	 * @param element The element. Must not be <code>null</code>.
	 * @param selection The selection. Must not be <code>null</code>.
	 *
	 * @return The parent category or <code>null</code>.
	 */
	protected ICategory getParentCategory(Object element, IStructuredSelection selection) {
		Assert.isNotNull(element);
		Assert.isNotNull(selection);

		ICategory parent = null;

		if (selection instanceof ITreeSelection) {
			TreePath[] pathes = ((ITreeSelection)selection).getPathsFor(element);
			for (TreePath path : pathes) {
				TreePath parentPath = path.getParentPath();
				while (parentPath != null) {
					if (parentPath.getLastSegment() instanceof ICategory) {
						parent = (ICategory)parentPath.getLastSegment();
						break;
					}
					parentPath = parentPath.getParentPath();
				}
			}
		}

		return parent;
	}

	/**
	 * Returns the categorizable for the given element.
	 *
	 * @param element The element or <code>null</code>.
	 * @return The categorizable or <code>null</code>.
	 */
	protected ICategorizable getCategorizable(Object element) {
	    ICategorizable categorizable = element instanceof IAdaptable ? (ICategorizable)((IAdaptable)element).getAdapter(ICategorizable.class) : null;
    	if (categorizable == null) categorizable = (ICategorizable)Platform.getAdapterManager().getAdapter(element, ICategorizable.class);
    	return categorizable;
	}
}

Back to the top