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