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
;
16 import java
.util
.ArrayList
;
17 import java
.util
.Collections
;
18 import java
.util
.Comparator
;
19 import java
.util
.HashMap
;
20 import java
.util
.Iterator
;
21 import java
.util
.List
;
23 import java
.util
.TreeSet
;
25 import org
.eclipse
.core
.resources
.IResource
;
26 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
27 import org
.eclipse
.core
.runtime
.CoreException
;
28 import org
.eclipse
.core
.runtime
.IConfigurationElement
;
29 import org
.eclipse
.core
.runtime
.IPath
;
30 import org
.eclipse
.core
.runtime
.IStatus
;
31 import org
.eclipse
.core
.runtime
.Status
;
32 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TmfTraceImportException
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TmfTraceType
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TraceTypeHelper
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.util
.Pair
;
39 import org
.eclipse
.swt
.SWT
;
40 import org
.eclipse
.swt
.events
.SelectionEvent
;
41 import org
.eclipse
.swt
.events
.SelectionListener
;
42 import org
.eclipse
.swt
.layout
.RowLayout
;
43 import org
.eclipse
.swt
.widgets
.Button
;
44 import org
.eclipse
.swt
.widgets
.Display
;
45 import org
.eclipse
.swt
.widgets
.Shell
;
46 import org
.eclipse
.ui
.dialogs
.FileSystemElement
;
49 * Utils class for the UI-specific parts of @link {@link TmfTraceType}.
51 * @author Alexandre Montplaisir
54 public final class TmfTraceTypeUIUtils
{
56 private static final String DEFAULT_TRACE_ICON_PATH
= "icons" + File
.separator
+ "elcl16" + File
.separator
+ "trace.gif"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
58 private static final char SEPARATOR
= ':';
60 private TmfTraceTypeUIUtils() {}
62 private static List
<File
> isolateTraces(List
<FileSystemElement
> selectedResources
) {
63 List
<File
> traces
= new ArrayList
<>();
66 Iterator
<FileSystemElement
> resources
= selectedResources
.iterator();
68 // Get the sorted list of unique entries
69 Map
<String
, File
> fileSystemObjects
= new HashMap
<>();
70 while (resources
.hasNext()) {
71 File resource
= (File
) resources
.next().getFileSystemObject();
72 String key
= resource
.getAbsolutePath();
73 fileSystemObjects
.put(key
, resource
);
75 List
<String
> files
= new ArrayList
<>(fileSystemObjects
.keySet());
76 Collections
.sort(files
);
78 // After sorting, traces correspond to the unique prefixes
80 for (int i
= 0; i
< files
.size(); i
++) {
81 File file
= fileSystemObjects
.get(files
.get(i
));
82 String name
= file
.getAbsolutePath();
83 if (prefix
== null || !name
.startsWith(prefix
)) {
84 prefix
= name
; // new prefix
93 private static List
<Pair
<Integer
, TraceTypeHelper
>> reduce(List
<Pair
<Integer
, TraceTypeHelper
>> candidates
) {
94 List
<Pair
<Integer
, TraceTypeHelper
>> retVal
= new ArrayList
<>();
96 // get all the tracetypes that are unique in that stage
97 for (Pair
<Integer
, TraceTypeHelper
> candidatePair
: candidates
) {
98 TraceTypeHelper candidate
= candidatePair
.getSecond();
99 if (isUnique(candidate
, candidates
)) {
100 retVal
.add(candidatePair
);
107 * Only return the leaves of the trace types. Ignore custom trace types.
109 private static boolean isUnique(TraceTypeHelper trace
, List
<Pair
<Integer
, TraceTypeHelper
>> set
) {
110 if (isCustomTraceId(trace
.getCanonicalName())) {
113 // check if the trace type is the leaf. we make an instance of the trace
114 // type and if it is only an instance of itself, it is a leaf
115 final ITmfTrace tmfTrace
= trace
.getTrace();
117 for (Pair
<Integer
, TraceTypeHelper
> child
: set
) {
118 final ITmfTrace traceCandidate
= child
.getSecond().getTrace();
119 if (tmfTrace
.getClass().isInstance(traceCandidate
)) {
128 * Is the trace type id a custom (user-defined) trace type. These are the
129 * traces like : text and xml defined by the custom trace wizard.
133 * @return true if the trace is a custom type
135 private static boolean isCustomTraceId(String traceTypeId
) {
136 TraceTypeHelper traceType
= TmfTraceType
.getInstance().getTraceType(traceTypeId
);
137 if (traceType
!= null) {
138 return TmfTraceType
.isCustomTrace(traceType
.getCategoryName() + SEPARATOR
+ traceType
.getName());
143 private static TraceTypeHelper
getTraceTypeToSet(TmfTraceType type
, List
<Pair
<Integer
, TraceTypeHelper
>> candidates
, Shell shell
) {
144 final Map
<String
, String
> names
= new HashMap
<>();
145 Shell shellToShow
= new Shell(shell
);
146 shellToShow
.setText(Messages
.TmfTraceType_SelectTraceType
);
147 final String candidatesToSet
[] = new String
[1];
148 for (Pair
<Integer
, TraceTypeHelper
> candidatePair
: candidates
) {
149 TraceTypeHelper candidate
= candidatePair
.getSecond();
150 Button b
= new Button(shellToShow
, SWT
.RADIO
);
151 final String displayName
= candidate
.getCategoryName() + ':' + candidate
.getName();
152 b
.setText(displayName
);
153 names
.put(displayName
, candidate
.getCanonicalName());
155 b
.addSelectionListener(new SelectionListener() {
158 public void widgetSelected(SelectionEvent e
) {
159 final Button source
= (Button
) e
.getSource();
160 candidatesToSet
[0] = (names
.get(source
.getText()));
161 source
.getParent().dispose();
165 public void widgetDefaultSelected(SelectionEvent e
) {
170 shellToShow
.setLayout(new RowLayout(SWT
.VERTICAL
));
174 Display display
= shellToShow
.getDisplay();
175 while (!shellToShow
.isDisposed()) {
176 if (!display
.readAndDispatch()) {
180 return type
.getTraceTypeHelper(candidatesToSet
[0]);
184 * validate list of traces with a tracetype
187 * The TmfTraceType instance
188 * @param traceTypeName
189 * the trace category (canonical name)
190 * @param selectedResources
191 * List of traces to validate
192 * @return true if all the traces are valid
194 public static boolean validateTrace(TmfTraceType type
, String traceTypeName
, List
<FileSystemElement
> selectedResources
) {
195 List
<File
> traces
= isolateTraces(selectedResources
);
196 return type
.validateTraceFiles(traceTypeName
, traces
);
200 * This member figures out the trace type of a given file. It will prompt
201 * the user if it needs more information to properly pick the trace type.
204 * The path of file to import
206 * a shell to display the message to. If it is null, it is
207 * assumed to be cancelled.
208 * @param traceTypeHint
209 * the ID of a trace (like "o.e.l.specifictrace" )
210 * @return null if the request is cancelled or a TraceTypeHelper if it
212 * @throws TmfTraceImportException
213 * if the traces don't match or there are errors in the trace
216 public static TraceTypeHelper
selectTraceType(String path
, Shell shell
, String traceTypeHint
) throws TmfTraceImportException
{
217 TmfTraceType type
= TmfTraceType
.getInstance();
219 Comparator
<Pair
<Integer
, TraceTypeHelper
>> comparator
= new Comparator
<Pair
<Integer
, TraceTypeHelper
>>() {
221 public int compare(Pair
<Integer
, TraceTypeHelper
> o1
, Pair
<Integer
, TraceTypeHelper
> o2
) {
222 int res
= -o1
.getFirst().compareTo(o2
.getFirst()); // invert so that highest confidence is first
224 res
= o1
.getSecond().getName().compareTo(o2
.getSecond().getName());
229 TreeSet
<Pair
<Integer
, TraceTypeHelper
>> validCandidates
= new TreeSet
<>(comparator
);
230 final Iterable
<TraceTypeHelper
> traceTypeHelpers
= type
.getTraceTypeHelpers();
231 for (TraceTypeHelper traceTypeHelper
: traceTypeHelpers
) {
232 int confidence
= traceTypeHelper
.validateWithConfidence(path
);
233 if (confidence
>= 0) {
234 // insert in the tree map, ordered by confidence (highest confidence first) then name
235 Pair
<Integer
, TraceTypeHelper
> element
= new Pair
<>(confidence
, traceTypeHelper
);
236 validCandidates
.add(element
);
240 TraceTypeHelper traceTypeToSet
= null;
241 if (validCandidates
.isEmpty()) {
242 final String errorMsg
= Messages
.TmfOpenTraceHelper_NoTraceTypeMatch
+ path
;
243 throw new TmfTraceImportException(errorMsg
);
244 } else if (validCandidates
.size() != 1) {
245 List
<Pair
<Integer
, TraceTypeHelper
>> candidates
= new ArrayList
<>(validCandidates
);
246 List
<Pair
<Integer
, TraceTypeHelper
>> reducedCandidates
= reduce(candidates
);
247 for (Pair
<Integer
, TraceTypeHelper
> candidatePair
: reducedCandidates
) {
248 TraceTypeHelper candidate
= candidatePair
.getSecond();
249 if (candidate
.getCanonicalName().equals(traceTypeHint
)) {
250 traceTypeToSet
= candidate
;
254 if (traceTypeToSet
== null) {
255 if (reducedCandidates
.size() == 0) {
256 throw new TmfTraceImportException(Messages
.TmfOpenTraceHelper_ReduceError
);
257 } else if (reducedCandidates
.size() == 1) {
258 traceTypeToSet
= reducedCandidates
.get(0).getSecond();
259 } else if (shell
== null) {
260 Pair
<Integer
, TraceTypeHelper
> candidate
= reducedCandidates
.get(0);
261 // if the best match has lowest confidence, don't select it
262 if (candidate
.getFirst() > 0) {
263 traceTypeToSet
= candidate
.getSecond();
266 traceTypeToSet
= getTraceTypeToSet(type
, reducedCandidates
, shell
);
270 traceTypeToSet
= validCandidates
.first().getSecond();
272 return traceTypeToSet
;
277 * Set the trace type of a {@Link TraceTypeHelper}. Should only be
278 * used internally by this project.
281 * the {@link IPath} path of the resource to set
283 * the {@link TraceTypeHelper} to set the trace type to.
284 * @return Status.OK_Status if successful, error is otherwise.
285 * @throws CoreException
286 * An exception caused by accessing eclipse project items.
288 public static IStatus
setTraceType(IPath path
, TraceTypeHelper traceType
) throws CoreException
{
289 IResource resource
= ResourcesPlugin
.getWorkspace().getRoot().findMember(path
);
290 String traceBundle
= null, traceTypeId
= traceType
.getCanonicalName(), traceIcon
= null;
291 if (isCustomTraceId(traceTypeId
)) {
292 traceBundle
= Activator
.getDefault().getBundle().getSymbolicName();
293 traceIcon
= DEFAULT_TRACE_ICON_PATH
;
295 IConfigurationElement ce
= TmfTraceType
.getInstance().getTraceAttributes(traceTypeId
);
296 traceBundle
= ce
.getContributor().getName();
297 traceIcon
= ce
.getAttribute(TmfTraceType
.ICON_ATTR
);
300 resource
.setPersistentProperty(TmfCommonConstants
.TRACEBUNDLE
, traceBundle
);
301 resource
.setPersistentProperty(TmfCommonConstants
.TRACETYPE
, traceTypeId
);
302 resource
.setPersistentProperty(TmfCommonConstants
.TRACEICON
, traceIcon
);
304 TmfProjectElement tmfProject
= TmfProjectRegistry
.getProject(resource
.getProject(), true);
305 final TmfTraceFolder tracesFolder
= tmfProject
.getTracesFolder();
306 List
<TmfTraceElement
> traces
= tracesFolder
.getTraces();
307 for (TmfTraceElement traceElement
: traces
) {
308 if (traceElement
.getName().equals(resource
.getName())) {
309 traceElement
.refreshTraceType();
313 tmfProject
.refresh();
314 return Status
.OK_STATUS
;