1 /*******************************************************************************
2 * Copyright (c) 2010, 2014 Ericsson, École Polytechnique de Montréal
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 * Francois Chouinard - Initial API and implementation
11 * Bernd Hufmann - Added supplementary files handling
12 * Geneviève Bastien - Moved supplementary files handling to parent class,
13 * added code to copy trace
14 * Patrick Tasse - Close editors to release resources
15 * Jean-Christian Kouame - added trace properties to be shown into
17 * Geneviève Bastien - Moved trace type related methods to parent class
18 *******************************************************************************/
20 package org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
;
22 import java
.util
.Arrays
;
23 import java
.util
.HashMap
;
24 import java
.util
.LinkedList
;
25 import java
.util
.List
;
28 import org
.eclipse
.core
.resources
.IFile
;
29 import org
.eclipse
.core
.resources
.IFolder
;
30 import org
.eclipse
.core
.resources
.IResource
;
31 import org
.eclipse
.core
.runtime
.CoreException
;
32 import org
.eclipse
.core
.runtime
.IConfigurationElement
;
33 import org
.eclipse
.core
.runtime
.IPath
;
34 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
35 import org
.eclipse
.core
.runtime
.Platform
;
36 import org
.eclipse
.core
.runtime
.URIUtil
;
37 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomTxtEvent
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomTxtTrace
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomTxtTraceDefinition
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomXmlEvent
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomXmlTrace
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomXmlTraceDefinition
;
46 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TmfTraceType
;
47 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TraceTypeHelper
;
48 import org
.eclipse
.linuxtools
.tmf
.core
.synchronization
.TimestampTransformFactory
;
49 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestampFormat
;
50 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
51 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTraceProperties
;
52 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTrace
;
53 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTraceManager
;
54 import org
.eclipse
.linuxtools
.tmf
.ui
.editors
.TmfEventsEditor
;
55 import org
.eclipse
.linuxtools
.tmf
.ui
.properties
.ReadOnlyTextPropertyDescriptor
;
56 import org
.eclipse
.swt
.widgets
.Display
;
57 import org
.eclipse
.ui
.IActionFilter
;
58 import org
.eclipse
.ui
.views
.properties
.IPropertyDescriptor
;
59 import org
.eclipse
.ui
.views
.properties
.IPropertySource2
;
62 * Implementation of trace model element representing a trace. It provides
63 * methods to instantiate <code>ITmfTrace</code> and <code>ITmfEvent</code> as
64 * well as editor ID from the trace type extension definition.
67 * @author Francois Chouinard
69 public class TmfTraceElement
extends TmfCommonProjectElement
implements IActionFilter
, IPropertySource2
{
71 // ------------------------------------------------------------------------
73 // ------------------------------------------------------------------------
77 * Bundle attribute name
79 public static final String BUNDLE
= "bundle"; //$NON-NLS-1$
81 * IsLinked attribute name.
83 public static final String IS_LINKED
= "isLinked"; //$NON-NLS-1$
85 // Property View stuff
86 private static final String sfResourcePropertiesCategory
= Messages
.TmfTraceElement_ResourceProperties
;
87 private static final String sfName
= Messages
.TmfTraceElement_Name
;
88 private static final String sfPath
= Messages
.TmfTraceElement_Path
;
89 private static final String sfLocation
= Messages
.TmfTraceElement_Location
;
90 private static final String sfTraceType
= Messages
.TmfTraceElement_EventType
;
91 private static final String sfIsLinked
= Messages
.TmfTraceElement_IsLinked
;
92 private static final String sfSourceLocation
= Messages
.TmfTraceElement_SourceLocation
;
93 private static final String sfTimeOffset
= Messages
.TmfTraceElement_TimeOffset
;
94 private static final String sfTracePropertiesCategory
= Messages
.TmfTraceElement_TraceProperties
;
96 private static final ReadOnlyTextPropertyDescriptor sfNameDescriptor
= new ReadOnlyTextPropertyDescriptor(sfName
, sfName
);
97 private static final ReadOnlyTextPropertyDescriptor sfPathDescriptor
= new ReadOnlyTextPropertyDescriptor(sfPath
, sfPath
);
98 private static final ReadOnlyTextPropertyDescriptor sfLocationDescriptor
= new ReadOnlyTextPropertyDescriptor(sfLocation
, sfLocation
);
99 private static final ReadOnlyTextPropertyDescriptor sfTypeDescriptor
= new ReadOnlyTextPropertyDescriptor(sfTraceType
, sfTraceType
);
100 private static final ReadOnlyTextPropertyDescriptor sfIsLinkedDescriptor
= new ReadOnlyTextPropertyDescriptor(sfIsLinked
, sfIsLinked
);
101 private static final ReadOnlyTextPropertyDescriptor sfSourceLocationDescriptor
= new ReadOnlyTextPropertyDescriptor(sfSourceLocation
, sfSourceLocation
);
102 private static final ReadOnlyTextPropertyDescriptor sfTimeOffsetDescriptor
= new ReadOnlyTextPropertyDescriptor(sfTimeOffset
, sfTimeOffset
);
104 private static final IPropertyDescriptor
[] sfDescriptors
= { sfNameDescriptor
, sfPathDescriptor
, sfLocationDescriptor
,
105 sfTypeDescriptor
, sfIsLinkedDescriptor
, sfSourceLocationDescriptor
,
106 sfTimeOffsetDescriptor
};
109 sfNameDescriptor
.setCategory(sfResourcePropertiesCategory
);
110 sfPathDescriptor
.setCategory(sfResourcePropertiesCategory
);
111 sfLocationDescriptor
.setCategory(sfResourcePropertiesCategory
);
112 sfTypeDescriptor
.setCategory(sfResourcePropertiesCategory
);
113 sfIsLinkedDescriptor
.setCategory(sfResourcePropertiesCategory
);
114 sfSourceLocationDescriptor
.setCategory(sfResourcePropertiesCategory
);
115 sfTimeOffsetDescriptor
.setCategory(sfResourcePropertiesCategory
);
118 private static final TmfTimestampFormat OFFSET_FORMAT
= new TmfTimestampFormat("T.SSS SSS SSS s"); //$NON-NLS-1$
120 // ------------------------------------------------------------------------
121 // Static initialization
122 // ------------------------------------------------------------------------
124 // The mapping of available trace type IDs to their corresponding
125 // configuration element
126 private static final Map
<String
, IConfigurationElement
> sfTraceTypeAttributes
= new HashMap
<>();
127 private static final Map
<String
, IConfigurationElement
> sfTraceTypeUIAttributes
= new HashMap
<>();
128 private static final Map
<String
, IConfigurationElement
> sfTraceCategories
= new HashMap
<>();
131 * Initialize statically at startup by getting extensions from the platform
132 * extension registry.
134 public static void init() {
135 /* Read the tmf.core "tracetype" extension point */
136 IConfigurationElement
[] config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceType
.TMF_TRACE_TYPE_ID
);
137 for (IConfigurationElement ce
: config
) {
138 switch (ce
.getName()) {
139 case TmfTraceType
.TYPE_ELEM
:
140 String traceTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
141 sfTraceTypeAttributes
.put(traceTypeId
, ce
);
143 case TmfTraceType
.CATEGORY_ELEM
:
144 String categoryId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
145 sfTraceCategories
.put(categoryId
, ce
);
152 * Read the corresponding tmf.ui "tracetypeui" extension point for this
153 * trace type, if it exists.
155 config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceTypeUIUtils
.TMF_TRACE_TYPE_UI_ID
);
156 for (IConfigurationElement ce
: config
) {
157 String elemName
= ce
.getName();
158 if (TmfTraceTypeUIUtils
.TYPE_ELEM
.equals(elemName
)) {
159 String traceType
= ce
.getAttribute(TmfTraceTypeUIUtils
.TRACETYPE_ATTR
);
160 sfTraceTypeUIAttributes
.put(traceType
, ce
);
165 // ------------------------------------------------------------------------
167 // ------------------------------------------------------------------------
169 * Constructor. Creates trace model element under the trace folder.
174 * The trace resource.
176 * The parent element (trace folder)
178 public TmfTraceElement(String name
, IResource trace
, TmfTraceFolder parent
) {
179 super(name
, trace
, parent
);
183 * Constructor. Creates trace model element under the experiment folder.
188 * The trace resource.
190 * The parent element (experiment folder)
192 public TmfTraceElement(String name
, IResource trace
, TmfExperimentElement parent
) {
193 super(name
, trace
, parent
);
196 // ------------------------------------------------------------------------
198 // ------------------------------------------------------------------------
201 * Instantiate a <code>ITmfTrace</code> object based on the trace type and
202 * the corresponding extension.
204 * @return the <code>ITmfTrace</code> or <code>null</code> for an error
207 public ITmfTrace
instantiateTrace() {
210 // make sure that supplementary folder exists
211 refreshSupplementaryFolder();
213 if (getTraceType() != null) {
214 if (getTraceType().startsWith(CustomTxtTrace
.class.getCanonicalName())) {
215 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
216 if (getTraceType().equals(CustomTxtTrace
.class.getCanonicalName() + ':' + def
.categoryName
+ ':' + def
.definitionName
)) {
217 return new CustomTxtTrace(def
);
221 if (getTraceType().startsWith(CustomXmlTrace
.class.getCanonicalName())) {
222 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
223 if (getTraceType().equals(CustomXmlTrace
.class.getCanonicalName() + ':' + def
.categoryName
+ ':' + def
.definitionName
)) {
224 return new CustomXmlTrace(def
);
228 IConfigurationElement ce
= sfTraceTypeAttributes
.get(getTraceType());
232 ITmfTrace trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.TRACE_TYPE_ATTR
);
235 } catch (CoreException e
) {
236 Activator
.getDefault().logError("Error instantiating ITmfTrace object for trace " + getName(), e
); //$NON-NLS-1$
242 * Instantiate a <code>ITmfEvent</code> object based on the trace type and
243 * the corresponding extension.
245 * @return the <code>ITmfEvent</code> or <code>null</code> for an error
247 public ITmfEvent
instantiateEvent() {
249 if (getTraceType() != null) {
250 if (getTraceType().startsWith(CustomTxtTrace
.class.getCanonicalName())) {
251 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
252 if (getTraceType().equals(CustomTxtTrace
.class.getCanonicalName() + ':' + def
.categoryName
+ ':' + def
.definitionName
)) {
253 return new CustomTxtEvent(def
);
257 if (getTraceType().startsWith(CustomXmlTrace
.class.getCanonicalName())) {
258 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
259 if (getTraceType().equals(CustomXmlTrace
.class.getCanonicalName() + ':' + def
.categoryName
+ ':' + def
.definitionName
)) {
260 return new CustomXmlEvent(def
);
264 IConfigurationElement ce
= sfTraceTypeAttributes
.get(getTraceType());
268 ITmfEvent event
= (ITmfEvent
) ce
.createExecutableExtension(TmfTraceType
.EVENT_TYPE_ATTR
);
271 } catch (CoreException e
) {
272 Activator
.getDefault().logError("Error instantiating ITmfEvent object for trace " + getName(), e
); //$NON-NLS-1$
278 public String
getEditorId() {
279 if (getTraceType() != null) {
280 if (getTraceType().startsWith(CustomTxtTrace
.class.getCanonicalName())) {
281 return TmfEventsEditor
.ID
;
283 if (getTraceType().startsWith(CustomXmlTrace
.class.getCanonicalName())) {
284 return TmfEventsEditor
.ID
;
286 IConfigurationElement ce
= sfTraceTypeUIAttributes
.get(getTraceType());
288 /* This trace type does not define UI attributes */
291 IConfigurationElement
[] defaultEditorCE
= ce
.getChildren(TmfTraceTypeUIUtils
.DEFAULT_EDITOR_ELEM
);
292 if (defaultEditorCE
.length
== 1) {
293 return defaultEditorCE
[0].getAttribute(TmfTraceType
.ID_ATTR
);
300 * Returns the file resource used to store bookmarks after creating it if
301 * necessary. If the trace resource is a file, it is returned directly. If
302 * the trace resource is a folder, a linked file is returned. The file will
303 * be created if it does not exist.
305 * @return the bookmarks file
306 * @throws CoreException
307 * if the bookmarks file cannot be created
311 public IFile
createBookmarksFile() throws CoreException
{
312 IFile file
= getBookmarksFile();
313 if (fResource
instanceof IFolder
) {
314 return createBookmarksFile(getProject().getTracesFolder().getResource(), TmfTrace
.class.getCanonicalName());
320 * Returns the file resource used to store bookmarks. The file may not
323 * @return the bookmarks file
327 public IFile
getBookmarksFile() {
329 if (fResource
instanceof IFile
) {
330 file
= (IFile
) fResource
;
331 } else if (fResource
instanceof IFolder
) {
332 final IFolder folder
= (IFolder
) fResource
;
333 file
= folder
.getFile(getName() + '_');
339 * Returns the <code>TmfTraceElement</code> located under the
340 * <code>TmfTracesFolder</code>.
342 * @return <code>this</code> if this element is under the
343 * <code>TmfTracesFolder</code> else the corresponding
344 * <code>TmfTraceElement</code> if this element is under
345 * <code>TmfExperimentElement</code>.
347 public TmfTraceElement
getElementUnderTraceFolder() {
349 // If trace is under an experiment, return original trace from the
351 if (getParent() instanceof TmfExperimentElement
) {
352 for (TmfTraceElement aTrace
: getProject().getTracesFolder().getTraces()) {
353 if (aTrace
.getElementPath().equals(getElementPath())) {
362 public String
getTypeName() {
363 return Messages
.TmfTraceElement_TypeName
;
366 // ------------------------------------------------------------------------
368 // ------------------------------------------------------------------------
371 public boolean testAttribute(Object target
, String name
, String value
) {
372 if (name
.equals(IS_LINKED
)) {
373 boolean isLinked
= getResource().isLinked();
374 return Boolean
.toString(isLinked
).equals(value
);
379 // ------------------------------------------------------------------------
381 // ------------------------------------------------------------------------
384 public Object
getEditableValue() {
389 * Get the trace properties of this traceElement if the corresponding trace
390 * is opened in an editor
392 * @return a map with the names and values of the trace properties
393 * respectively as keys and values
395 private Map
<String
, String
> getTraceProperties() {
396 for (ITmfTrace openedTrace
: TmfTraceManager
.getInstance().getOpenedTraces()) {
397 for (ITmfTrace singleTrace
: TmfTraceManager
.getTraceSet(openedTrace
)) {
398 if (getElementUnderTraceFolder().getResource().equals(singleTrace
.getResource())) {
399 if (singleTrace
instanceof ITmfTraceProperties
) {
400 ITmfTraceProperties traceProperties
= (ITmfTraceProperties
) singleTrace
;
401 return traceProperties
.getTraceProperties();
406 return new HashMap
<>();
410 public IPropertyDescriptor
[] getPropertyDescriptors() {
411 Map
<String
, String
> traceProperties
= getTraceProperties();
412 if (!traceProperties
.isEmpty()) {
413 IPropertyDescriptor
[] propertyDescriptorArray
= new IPropertyDescriptor
[traceProperties
.size() + sfDescriptors
.length
];
415 for (Map
.Entry
<String
, String
> varName
: traceProperties
.entrySet()) {
416 ReadOnlyTextPropertyDescriptor descriptor
= new ReadOnlyTextPropertyDescriptor(this.getName() + "_" + varName
.getKey(), varName
.getKey()); //$NON-NLS-1$
417 descriptor
.setCategory(sfTracePropertiesCategory
);
418 propertyDescriptorArray
[index
] = descriptor
;
421 for (int i
= 0; i
< sfDescriptors
.length
; i
++) {
422 propertyDescriptorArray
[index
] = sfDescriptors
[i
];
425 return propertyDescriptorArray
;
427 return Arrays
.copyOf(sfDescriptors
, sfDescriptors
.length
);
431 public Object
getPropertyValue(Object id
) {
433 if (sfName
.equals(id
)) {
437 if (sfPath
.equals(id
)) {
438 return getPath().toString();
441 if (sfLocation
.equals(id
)) {
442 return URIUtil
.toUnencodedString(getLocation());
445 if (sfIsLinked
.equals(id
)) {
446 return Boolean
.valueOf(getResource().isLinked()).toString();
449 if (sfSourceLocation
.equals(id
)) {
451 String sourceLocation
= getElementUnderTraceFolder().getResource().getPersistentProperty(TmfCommonConstants
.SOURCE_LOCATION
);
452 if (sourceLocation
!= null) {
453 return sourceLocation
;
455 } catch (CoreException e
) {
457 return ""; //$NON-NLS-1$
460 if (sfTraceType
.equals(id
)) {
461 if (getTraceType() != null) {
462 TraceTypeHelper helper
= TmfTraceType
.getTraceType(getTraceType());
463 if (helper
!= null) {
464 return helper
.getCategoryName() + " : " + helper
.getName(); //$NON-NLS-1$
467 return ""; //$NON-NLS-1$
470 if (sfTimeOffset
.equals(id
)) {
471 long offset
= TimestampTransformFactory
.getTimestampTransform(getElementUnderTraceFolder().getResource()).transform(0);
473 return OFFSET_FORMAT
.format(offset
);
475 return ""; //$NON-NLS-1$
478 Map
<String
, String
> traceProperties
= getTraceProperties();
479 if (id
!= null && !traceProperties
.isEmpty()) {
480 String key
= (String
) id
;
481 key
= key
.substring(this.getName().length() + 1); // remove name_
482 String value
= traceProperties
.get(key
);
490 public void resetPropertyValue(Object id
) {
494 public void setPropertyValue(Object id
, Object value
) {
498 public boolean isPropertyResettable(Object id
) {
503 public boolean isPropertySet(Object id
) {
508 * Copy this trace in the trace folder. No other parameters are mentioned so
509 * the trace is copied in this element's project trace folder
513 * @return the new Resource object
516 public TmfTraceElement
copy(String newName
) {
517 TmfTraceFolder folder
= (TmfTraceFolder
) getParent();
518 IResource res
= super.copy(newName
, false);
519 for (TmfTraceElement trace
: folder
.getTraces()) {
520 if (trace
.getResource().equals(res
)) {
528 * Close opened editors associated with this trace.
533 public void closeEditors() {
534 super.closeEditors();
536 // Close experiments that contain the trace if open
537 if (getParent() instanceof TmfTraceFolder
) {
538 TmfExperimentFolder experimentsFolder
= getProject().getExperimentsFolder();
539 for (TmfExperimentElement experiment
: experimentsFolder
.getExperiments()) {
540 for (TmfTraceElement trace
: experiment
.getTraces()) {
541 if (trace
.getElementPath().equals(getElementPath())) {
542 experiment
.closeEditors();
547 } else if (getParent() instanceof TmfExperimentElement
) {
548 TmfExperimentElement experiment
= (TmfExperimentElement
) getParent();
549 experiment
.closeEditors();
554 * Delete the trace resource, remove it from experiments and delete its
555 * supplementary files
557 * @param progressMonitor
558 * a progress monitor, or null if progress reporting is not
561 * @throws CoreException
562 * thrown when IResource.delete fails
565 public void delete(IProgressMonitor progressMonitor
) throws CoreException
{
566 // Close editors in UI Thread
567 Display
.getDefault().syncExec(new Runnable() {
574 IPath path
= fResource
.getLocation();
576 if (getParent() instanceof TmfTraceFolder
) {
577 TmfExperimentFolder experimentFolder
= getProject().getExperimentsFolder();
579 // Propagate the removal to traces
580 for (TmfExperimentElement experiment
: experimentFolder
.getExperiments()) {
581 List
<TmfTraceElement
> toRemove
= new LinkedList
<>();
582 for (TmfTraceElement trace
: experiment
.getTraces()) {
583 if (trace
.getElementPath().equals(getElementPath())) {
587 for (TmfTraceElement child
: toRemove
) {
588 experiment
.removeTrace(child
);
592 // Delete supplementary files
593 deleteSupplementaryFolder();
595 } else if (getParent() instanceof TmfExperimentElement
) {
596 TmfExperimentElement experimentElement
= (TmfExperimentElement
) getParent();
597 experimentElement
.removeTrace(this);
601 // Finally, delete the trace
602 fResource
.delete(true, progressMonitor
);