1 /*******************************************************************************
2 * Copyright (c) 2014 Ericsson
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
10 * Alexandre Montplaisir - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
;
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
;
21 import java
.util
.TreeSet
;
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
;
45 * Utils class for the UI-specific parts of @link {@link TmfTraceType}.
47 * @author Alexandre Montplaisir
50 public final class TmfTraceTypeUIUtils
{
52 /** Extension point ID */
53 public static final String TMF_TRACE_TYPE_UI_ID
= "org.eclipse.linuxtools.tmf.ui.tracetypeui"; //$NON-NLS-1$
55 /** Extension point element 'type' (should match the type in TmfTraceType) */
56 public static final String TYPE_ELEM
= "type"; //$NON-NLS-1$
59 * Extension point element 'experiment' (should match the type in
62 public static final String EXPERIMENT_ELEM
= "experiment"; //$NON-NLS-1$
64 /** Extension point element 'Default editor' */
65 public static final String DEFAULT_EDITOR_ELEM
= "defaultEditor"; //$NON-NLS-1$
67 /** Extension point element 'Events table type' */
68 public static final String EVENTS_TABLE_TYPE_ELEM
= "eventsTableType"; //$NON-NLS-1$
70 /** Extension point attribute 'tracetype' */
71 public static final String TRACETYPE_ATTR
= "tracetype"; //$NON-NLS-1$
73 /** Extension point attribute 'icon' */
74 public static final String ICON_ATTR
= "icon"; //$NON-NLS-1$
76 /** Extension point attribute 'class' (attribute of eventsTableType) */
77 public static final String CLASS_ATTR
= "class"; //$NON-NLS-1$
79 private static final char SEPARATOR
= ':';
81 private TmfTraceTypeUIUtils() {}
83 private static List
<Pair
<Integer
, TraceTypeHelper
>> reduce(List
<Pair
<Integer
, TraceTypeHelper
>> candidates
) {
84 List
<Pair
<Integer
, TraceTypeHelper
>> retVal
= new ArrayList
<>();
86 // get all the tracetypes that are unique in that stage
87 for (Pair
<Integer
, TraceTypeHelper
> candidatePair
: candidates
) {
88 TraceTypeHelper candidate
= candidatePair
.getSecond();
89 if (isUnique(candidate
, candidates
)) {
90 retVal
.add(candidatePair
);
97 * Only return the leaves of the trace types. Ignore custom trace types.
99 private static boolean isUnique(TraceTypeHelper trace
, List
<Pair
<Integer
, TraceTypeHelper
>> set
) {
100 if (isCustomTraceId(trace
.getCanonicalName())) {
103 // check if the trace type is the leaf. we make an instance of the trace
104 // type and if it is only an instance of itself, it is a leaf
105 final ITmfTrace tmfTrace
= trace
.getTrace();
107 for (Pair
<Integer
, TraceTypeHelper
> child
: set
) {
108 final ITmfTrace traceCandidate
= child
.getSecond().getTrace();
109 if (tmfTrace
.getClass().isInstance(traceCandidate
)) {
118 * Is the trace type id a custom (user-defined) trace type. These are the
119 * traces like : text and xml defined by the custom trace wizard.
123 * @return true if the trace is a custom type
125 private static boolean isCustomTraceId(String traceTypeId
) {
126 TraceTypeHelper traceType
= TmfTraceType
.getInstance().getTraceType(traceTypeId
);
127 if (traceType
!= null) {
128 return TmfTraceType
.isCustomTrace(traceType
.getCategoryName() + SEPARATOR
+ traceType
.getName());
133 private static TraceTypeHelper
getTraceTypeToSet(TmfTraceType type
, List
<Pair
<Integer
, TraceTypeHelper
>> candidates
, Shell shell
) {
134 final Map
<String
, String
> names
= new HashMap
<>();
135 Shell shellToShow
= new Shell(shell
);
136 shellToShow
.setText(Messages
.TmfTraceType_SelectTraceType
);
137 final String candidatesToSet
[] = new String
[1];
138 for (Pair
<Integer
, TraceTypeHelper
> candidatePair
: candidates
) {
139 TraceTypeHelper candidate
= candidatePair
.getSecond();
140 Button b
= new Button(shellToShow
, SWT
.RADIO
);
141 final String displayName
= candidate
.getCategoryName() + ':' + candidate
.getName();
142 b
.setText(displayName
);
143 names
.put(displayName
, candidate
.getCanonicalName());
145 b
.addSelectionListener(new SelectionListener() {
148 public void widgetSelected(SelectionEvent e
) {
149 final Button source
= (Button
) e
.getSource();
150 candidatesToSet
[0] = (names
.get(source
.getText()));
151 source
.getParent().dispose();
155 public void widgetDefaultSelected(SelectionEvent e
) {
160 shellToShow
.setLayout(new RowLayout(SWT
.VERTICAL
));
164 Display display
= shellToShow
.getDisplay();
165 while (!shellToShow
.isDisposed()) {
166 if (!display
.readAndDispatch()) {
170 return type
.getTraceTypeHelper(candidatesToSet
[0]);
174 * This member figures out the trace type of a given file. It will prompt
175 * the user if it needs more information to properly pick the trace type.
178 * The path of file to import
180 * a shell to display the message to. If it is null, it is
181 * assumed to be cancelled.
182 * @param traceTypeHint
183 * the ID of a trace (like "o.e.l.specifictrace" )
184 * @return null if the request is cancelled or a TraceTypeHelper if it
186 * @throws TmfTraceImportException
187 * if the traces don't match or there are errors in the trace
190 public static TraceTypeHelper
selectTraceType(String path
, Shell shell
, String traceTypeHint
) throws TmfTraceImportException
{
191 TmfTraceType type
= TmfTraceType
.getInstance();
193 Comparator
<Pair
<Integer
, TraceTypeHelper
>> comparator
= new Comparator
<Pair
<Integer
, TraceTypeHelper
>>() {
195 public int compare(Pair
<Integer
, TraceTypeHelper
> o1
, Pair
<Integer
, TraceTypeHelper
> o2
) {
196 int res
= -o1
.getFirst().compareTo(o2
.getFirst()); // invert so that highest confidence is first
198 res
= o1
.getSecond().getName().compareTo(o2
.getSecond().getName());
203 TreeSet
<Pair
<Integer
, TraceTypeHelper
>> validCandidates
= new TreeSet
<>(comparator
);
204 final Iterable
<TraceTypeHelper
> traceTypeHelpers
= type
.getTraceTypeHelpers();
205 for (TraceTypeHelper traceTypeHelper
: traceTypeHelpers
) {
206 int confidence
= traceTypeHelper
.validateWithConfidence(path
);
207 if (confidence
>= 0) {
208 // insert in the tree map, ordered by confidence (highest confidence first) then name
209 Pair
<Integer
, TraceTypeHelper
> element
= new Pair
<>(confidence
, traceTypeHelper
);
210 validCandidates
.add(element
);
214 TraceTypeHelper traceTypeToSet
= null;
215 if (validCandidates
.isEmpty()) {
216 final String errorMsg
= Messages
.TmfOpenTraceHelper_NoTraceTypeMatch
+ path
;
217 throw new TmfTraceImportException(errorMsg
);
218 } else if (validCandidates
.size() != 1) {
219 List
<Pair
<Integer
, TraceTypeHelper
>> candidates
= new ArrayList
<>(validCandidates
);
220 List
<Pair
<Integer
, TraceTypeHelper
>> reducedCandidates
= reduce(candidates
);
221 for (Pair
<Integer
, TraceTypeHelper
> candidatePair
: reducedCandidates
) {
222 TraceTypeHelper candidate
= candidatePair
.getSecond();
223 if (candidate
.getCanonicalName().equals(traceTypeHint
)) {
224 traceTypeToSet
= candidate
;
228 if (traceTypeToSet
== null) {
229 if (reducedCandidates
.size() == 0) {
230 throw new TmfTraceImportException(Messages
.TmfOpenTraceHelper_ReduceError
);
231 } else if (reducedCandidates
.size() == 1) {
232 traceTypeToSet
= reducedCandidates
.get(0).getSecond();
233 } else if (shell
== null) {
234 Pair
<Integer
, TraceTypeHelper
> candidate
= reducedCandidates
.get(0);
235 // if the best match has lowest confidence, don't select it
236 if (candidate
.getFirst() > 0) {
237 traceTypeToSet
= candidate
.getSecond();
240 traceTypeToSet
= getTraceTypeToSet(type
, reducedCandidates
, shell
);
244 traceTypeToSet
= validCandidates
.first().getSecond();
246 return traceTypeToSet
;
251 * Set the trace type of a {@Link TraceTypeHelper}. Should only be
252 * used internally by this project.
255 * the resource to set
257 * the {@link TraceTypeHelper} to set the trace type to.
258 * @return Status.OK_Status if successful, error is otherwise.
259 * @throws CoreException
260 * An exception caused by accessing eclipse project items.
262 public static IStatus
setTraceType(IResource resource
, TraceTypeHelper traceType
) throws CoreException
{
263 String traceTypeId
= traceType
.getCanonicalName();
265 resource
.setPersistentProperty(TmfCommonConstants
.TRACETYPE
, traceTypeId
);
267 TmfProjectElement tmfProject
= TmfProjectRegistry
.getProject(resource
.getProject(), true);
268 if (resource
.getParent().equals(tmfProject
.getTracesFolder().getResource())) {
269 refreshTraceElement(tmfProject
.getTracesFolder().getTraces(), resource
.getName());
271 for (TmfExperimentElement experimentElement
: tmfProject
.getExperimentsFolder().getExperiments()) {
272 if (resource
.getParent().equals(experimentElement
.getResource())) {
273 refreshTraceElement(experimentElement
.getTraces(), resource
.getName());
278 tmfProject
.refresh();
279 return Status
.OK_STATUS
;
282 private static void refreshTraceElement(List
<TmfTraceElement
> traceElements
, String traceName
) {
283 for (TmfTraceElement traceElement
: traceElements
) {
284 if (traceElement
.getName().equals(traceName
)) {
285 traceElement
.refreshTraceType();
292 * Retrieves all configuration elements from the platform extension registry
293 * for the trace type UI extension.
295 * @return An array of trace type configuration elements
297 public static IConfigurationElement
[] getTypeUIElements() {
298 IConfigurationElement
[] elements
=
299 Platform
.getExtensionRegistry().getConfigurationElementsFor(TMF_TRACE_TYPE_UI_ID
);
300 List
<IConfigurationElement
> typeElements
= new LinkedList
<>();
301 for (IConfigurationElement element
: elements
) {
302 if (element
.getName().equals(TYPE_ELEM
)) {
303 typeElements
.add(element
);
306 return typeElements
.toArray(new IConfigurationElement
[typeElements
.size()]);
310 * Get the UI elements for the given trace type
314 * @return The top-level configuration element (access its children with
315 * .getChildren()). Or null if there is no such element.
318 public static IConfigurationElement
getTraceUIAttributes(String traceType
) {
319 IConfigurationElement
[] elements
= getTypeUIElements();
320 for (IConfigurationElement ce
: elements
) {
321 if (traceType
.equals(ce
.getAttribute(TRACETYPE_ATTR
))) {