TMF: Fix a bug where the experiment trace type is not refreshed right away
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / project / model / TmfTraceTypeUIUtils.java
1 /*******************************************************************************
2 * Copyright (c) 2014 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Alexandre Montplaisir - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.ui.project.model;
14
15 import java.util.ArrayList;
16 import java.util.Comparator;
17 import java.util.HashMap;
18 import java.util.LinkedList;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.TreeSet;
22
23 import org.eclipse.core.resources.IResource;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IConfigurationElement;
26 import org.eclipse.core.runtime.IStatus;
27 import org.eclipse.core.runtime.Platform;
28 import org.eclipse.core.runtime.Status;
29 import org.eclipse.jdt.annotation.Nullable;
30 import org.eclipse.linuxtools.tmf.core.TmfCommonConstants;
31 import org.eclipse.linuxtools.tmf.core.project.model.TmfTraceImportException;
32 import org.eclipse.linuxtools.tmf.core.project.model.TmfTraceType;
33 import org.eclipse.linuxtools.tmf.core.project.model.TmfTraceType.TraceElementType;
34 import org.eclipse.linuxtools.tmf.core.project.model.TraceTypeHelper;
35 import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
36 import org.eclipse.linuxtools.tmf.core.util.Pair;
37 import org.eclipse.swt.SWT;
38 import org.eclipse.swt.events.SelectionEvent;
39 import org.eclipse.swt.events.SelectionListener;
40 import org.eclipse.swt.layout.RowLayout;
41 import org.eclipse.swt.widgets.Button;
42 import org.eclipse.swt.widgets.Display;
43 import org.eclipse.swt.widgets.Shell;
44
45 /**
46 * Utils class for the UI-specific parts of @link {@link TmfTraceType}.
47 *
48 * @author Alexandre Montplaisir
49 * @since 3.0
50 */
51 public final class TmfTraceTypeUIUtils {
52
53 /** Extension point ID */
54 public static final String TMF_TRACE_TYPE_UI_ID = "org.eclipse.linuxtools.tmf.ui.tracetypeui"; //$NON-NLS-1$
55
56 /** Extension point element 'type' (should match the type in TmfTraceType) */
57 public static final String TYPE_ELEM = "type"; //$NON-NLS-1$
58
59 /**
60 * Extension point element 'experiment' (should match the type in
61 * TmfTraceType)
62 */
63 public static final String EXPERIMENT_ELEM = "experiment"; //$NON-NLS-1$
64
65 /** Extension point element 'Default editor' */
66 public static final String DEFAULT_EDITOR_ELEM = "defaultEditor"; //$NON-NLS-1$
67
68 /** Extension point element 'Events table type' */
69 public static final String EVENTS_TABLE_TYPE_ELEM = "eventsTableType"; //$NON-NLS-1$
70
71 /** Extension point attribute 'tracetype' */
72 public static final String TRACETYPE_ATTR = "tracetype"; //$NON-NLS-1$
73
74 /** Extension point attribute 'icon' */
75 public static final String ICON_ATTR = "icon"; //$NON-NLS-1$
76
77 /** Extension point attribute 'class' (attribute of eventsTableType) */
78 public static final String CLASS_ATTR = "class"; //$NON-NLS-1$
79
80 private static final char SEPARATOR = ':';
81
82 private TmfTraceTypeUIUtils() {
83 }
84
85 private static List<Pair<Integer, TraceTypeHelper>> reduce(List<Pair<Integer, TraceTypeHelper>> candidates) {
86 List<Pair<Integer, TraceTypeHelper>> retVal = new ArrayList<>();
87
88 // get all the tracetypes that are unique in that stage
89 for (Pair<Integer, TraceTypeHelper> candidatePair : candidates) {
90 TraceTypeHelper candidate = candidatePair.getSecond();
91 if (isUnique(candidate, candidates)) {
92 retVal.add(candidatePair);
93 }
94 }
95 return retVal;
96 }
97
98 /*
99 * Only return the leaves of the trace types. Ignore custom trace types.
100 */
101 private static boolean isUnique(TraceTypeHelper trace, List<Pair<Integer, TraceTypeHelper>> set) {
102 if (isCustomTraceId(trace.getCanonicalName())) {
103 return true;
104 }
105 // check if the trace type is the leaf. we make an instance of the trace
106 // type and if it is only an instance of itself, it is a leaf
107 final ITmfTrace tmfTrace = trace.getTrace();
108 int count = -1;
109 for (Pair<Integer, TraceTypeHelper> child : set) {
110 final ITmfTrace traceCandidate = child.getSecond().getTrace();
111 if (tmfTrace.getClass().isInstance(traceCandidate)) {
112 count++;
113 }
114 }
115 return count == 0;
116 }
117
118 /**
119 * Is the trace type id a custom (user-defined) trace type. These are the
120 * traces like : text and xml defined by the custom trace wizard.
121 *
122 * @param traceTypeId
123 * the trace type id
124 * @return true if the trace is a custom type
125 */
126 private static boolean isCustomTraceId(String traceTypeId) {
127 TraceTypeHelper traceType = TmfTraceType.getInstance().getTraceType(traceTypeId);
128 if (traceType != null) {
129 return TmfTraceType.isCustomTrace(traceType.getCategoryName() + SEPARATOR + traceType.getName());
130 }
131 return false;
132 }
133
134 private static TraceTypeHelper getTraceTypeToSet(TmfTraceType type, List<Pair<Integer, TraceTypeHelper>> candidates, Shell shell) {
135 final Map<String, String> names = new HashMap<>();
136 Shell shellToShow = new Shell(shell);
137 shellToShow.setText(Messages.TmfTraceType_SelectTraceType);
138 final String candidatesToSet[] = new String[1];
139 for (Pair<Integer, TraceTypeHelper> candidatePair : candidates) {
140 TraceTypeHelper candidate = candidatePair.getSecond();
141 Button b = new Button(shellToShow, SWT.RADIO);
142 final String displayName = candidate.getCategoryName() + ':' + candidate.getName();
143 b.setText(displayName);
144 names.put(displayName, candidate.getCanonicalName());
145
146 b.addSelectionListener(new SelectionListener() {
147
148 @Override
149 public void widgetSelected(SelectionEvent e) {
150 final Button source = (Button) e.getSource();
151 candidatesToSet[0] = (names.get(source.getText()));
152 source.getParent().dispose();
153 }
154
155 @Override
156 public void widgetDefaultSelected(SelectionEvent e) {
157
158 }
159 });
160 }
161 shellToShow.setLayout(new RowLayout(SWT.VERTICAL));
162 shellToShow.pack();
163 shellToShow.open();
164
165 Display display = shellToShow.getDisplay();
166 while (!shellToShow.isDisposed()) {
167 if (!display.readAndDispatch()) {
168 display.sleep();
169 }
170 }
171 return type.getTraceTypeHelper(candidatesToSet[0]);
172 }
173
174 /**
175 * This member figures out the trace type of a given file. It will prompt
176 * the user if it needs more information to properly pick the trace type.
177 *
178 * @param path
179 * The path of file to import
180 * @param shell
181 * a shell to display the message to. If it is null, it is
182 * assumed to be cancelled.
183 * @param traceTypeHint
184 * the ID of a trace (like "o.e.l.specifictrace" )
185 * @return null if the request is cancelled or a TraceTypeHelper if it
186 * passes.
187 * @throws TmfTraceImportException
188 * if the traces don't match or there are errors in the trace
189 * file
190 */
191 public static TraceTypeHelper selectTraceType(String path, Shell shell, String traceTypeHint) throws TmfTraceImportException {
192 TmfTraceType type = TmfTraceType.getInstance();
193
194 Comparator<Pair<Integer, TraceTypeHelper>> comparator = new Comparator<Pair<Integer, TraceTypeHelper>>() {
195 @Override
196 public int compare(Pair<Integer, TraceTypeHelper> o1, Pair<Integer, TraceTypeHelper> o2) {
197 int res = -o1.getFirst().compareTo(o2.getFirst()); // invert so that highest confidence is first
198 if (res == 0) {
199 res = o1.getSecond().getName().compareTo(o2.getSecond().getName());
200 }
201 return res;
202 }
203 };
204 TreeSet<Pair<Integer, TraceTypeHelper>> validCandidates = new TreeSet<>(comparator);
205 final Iterable<TraceTypeHelper> traceTypeHelpers = type.getTraceTypeHelpers();
206 for (TraceTypeHelper traceTypeHelper : traceTypeHelpers) {
207 if (traceTypeHelper.isExperimentType()) {
208 continue;
209 }
210 int confidence = traceTypeHelper.validateWithConfidence(path);
211 if (confidence >= 0) {
212 // insert in the tree map, ordered by confidence (highest confidence first) then name
213 Pair<Integer, TraceTypeHelper> element = new Pair<>(confidence, traceTypeHelper);
214 validCandidates.add(element);
215 }
216 }
217
218 TraceTypeHelper traceTypeToSet = null;
219 if (validCandidates.isEmpty()) {
220 final String errorMsg = Messages.TmfOpenTraceHelper_NoTraceTypeMatch + path;
221 throw new TmfTraceImportException(errorMsg);
222 } else if (validCandidates.size() != 1) {
223 List<Pair<Integer, TraceTypeHelper>> candidates = new ArrayList<>(validCandidates);
224 List<Pair<Integer, TraceTypeHelper>> reducedCandidates = reduce(candidates);
225 for (Pair<Integer, TraceTypeHelper> candidatePair : reducedCandidates) {
226 TraceTypeHelper candidate = candidatePair.getSecond();
227 if (candidate.getCanonicalName().equals(traceTypeHint)) {
228 traceTypeToSet = candidate;
229 break;
230 }
231 }
232 if (traceTypeToSet == null) {
233 if (reducedCandidates.size() == 0) {
234 throw new TmfTraceImportException(Messages.TmfOpenTraceHelper_ReduceError);
235 } else if (reducedCandidates.size() == 1) {
236 traceTypeToSet = reducedCandidates.get(0).getSecond();
237 } else if (shell == null) {
238 Pair<Integer, TraceTypeHelper> candidate = reducedCandidates.get(0);
239 // if the best match has lowest confidence, don't select it
240 if (candidate.getFirst() > 0) {
241 traceTypeToSet = candidate.getSecond();
242 }
243 } else {
244 traceTypeToSet = getTraceTypeToSet(type, reducedCandidates, shell);
245 }
246 }
247 } else {
248 traceTypeToSet = validCandidates.first().getSecond();
249 }
250 return traceTypeToSet;
251 }
252
253 /**
254 * Set the trace type of a {@Link TraceTypeHelper}. Should only be
255 * used internally by this project.
256 *
257 * @param resource
258 * the resource to set
259 * @param traceType
260 * the {@link TraceTypeHelper} to set the trace type to.
261 * @return Status.OK_Status if successful, error is otherwise.
262 * @throws CoreException
263 * An exception caused by accessing eclipse project items.
264 */
265 public static IStatus setTraceType(IResource resource, TraceTypeHelper traceType) throws CoreException {
266 String traceTypeId = traceType.getCanonicalName();
267
268 resource.setPersistentProperty(TmfCommonConstants.TRACETYPE, traceTypeId);
269
270 TmfProjectElement tmfProject = TmfProjectRegistry.getProject(resource.getProject(), true);
271 if (resource.getParent().equals(tmfProject.getTracesFolder().getResource())) {
272 refreshTraceElement(tmfProject.getTracesFolder().getTraces(), resource.getName());
273 } else if (resource.getParent().equals(tmfProject.getExperimentsFolder().getResource())) {
274 /* The trace type to set is for an experiment */
275 for (TmfExperimentElement experimentElement : tmfProject.getExperimentsFolder().getExperiments()) {
276 if (resource.equals(experimentElement.getResource())) {
277 experimentElement.refreshTraceType();
278 break;
279 }
280 }
281 } else {
282 for (TmfExperimentElement experimentElement : tmfProject.getExperimentsFolder().getExperiments()) {
283 if (resource.getParent().equals(experimentElement.getResource())) {
284 refreshTraceElement(experimentElement.getTraces(), resource.getName());
285 break;
286 }
287 }
288 }
289 tmfProject.refresh();
290 return Status.OK_STATUS;
291 }
292
293 private static void refreshTraceElement(List<TmfTraceElement> traceElements, String traceName) {
294 for (TmfTraceElement traceElement : traceElements) {
295 if (traceElement.getName().equals(traceName)) {
296 traceElement.refreshTraceType();
297 break;
298 }
299 }
300 }
301
302 /**
303 * Retrieves all configuration elements from the platform extension registry
304 * for the trace type UI extension.
305 *
306 * @param elType
307 * The type of trace type requested, either TRACE or EXPERIMENT
308 * @return An array of trace type configuration elements
309 */
310 public static IConfigurationElement[] getTypeUIElements(TraceElementType elType) {
311 String elementName = TYPE_ELEM;
312 if (elType == TraceElementType.EXPERIMENT) {
313 elementName = EXPERIMENT_ELEM;
314 }
315 IConfigurationElement[] elements =
316 Platform.getExtensionRegistry().getConfigurationElementsFor(TMF_TRACE_TYPE_UI_ID);
317 List<IConfigurationElement> typeElements = new LinkedList<>();
318 for (IConfigurationElement element : elements) {
319 if (element.getName().equals(elementName)) {
320 typeElements.add(element);
321 }
322 }
323 return typeElements.toArray(new IConfigurationElement[typeElements.size()]);
324 }
325
326 /**
327 * Get the UI elements for the given trace type
328 *
329 * @param traceType
330 * The tracetype ID
331 * @param elType
332 * The type of trace type requested, either TRACE or EXPERIMENT
333 * @return The top-level configuration element (access its children with
334 * .getChildren()). Or null if there is no such element.
335 */
336 @Nullable
337 public static IConfigurationElement getTraceUIAttributes(String traceType, TraceElementType elType) {
338 IConfigurationElement[] elements = getTypeUIElements(elType);
339 for (IConfigurationElement ce : elements) {
340 if (traceType.equals(ce.getAttribute(TRACETYPE_ATTR))) {
341 return ce;
342 }
343 }
344 return null;
345 }
346 }
This page took 0.039585 seconds and 6 git commands to generate.