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