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
.event
.ITmfEvent
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomTxtEvent
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomTxtTrace
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomTxtTraceDefinition
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomXmlEvent
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomXmlTrace
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.parsers
.custom
.CustomXmlTraceDefinition
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.project
.model
.TmfTraceType
;
46 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
47 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTraceProperties
;
48 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTrace
;
49 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTraceManager
;
50 import org
.eclipse
.linuxtools
.tmf
.ui
.editors
.TmfEventsEditor
;
51 import org
.eclipse
.linuxtools
.tmf
.ui
.properties
.ReadOnlyTextPropertyDescriptor
;
52 import org
.eclipse
.ui
.IActionFilter
;
53 import org
.eclipse
.ui
.views
.properties
.IPropertyDescriptor
;
54 import org
.eclipse
.ui
.views
.properties
.IPropertySource2
;
57 * Implementation of trace model element representing a trace. It provides
58 * methods to instantiate <code>ITmfTrace</code> and <code>ITmfEvent</code> as
59 * well as editor ID from the trace type extension definition.
62 * @author Francois Chouinard
64 public class TmfTraceElement
extends TmfCommonProjectElement
implements IActionFilter
, IPropertySource2
{
66 // ------------------------------------------------------------------------
68 // ------------------------------------------------------------------------
72 * Bundle attribute name
74 public static final String BUNDLE
= "bundle"; //$NON-NLS-1$
76 * IsLinked attribute name.
78 public static final String IS_LINKED
= "isLinked"; //$NON-NLS-1$
80 // Property View stuff
81 private static final String sfResourcePropertiesCategory
= Messages
.TmfTraceElement_ResourceProperties
;
82 private static final String sfName
= Messages
.TmfTraceElement_Name
;
83 private static final String sfPath
= Messages
.TmfTraceElement_Path
;
84 private static final String sfLocation
= Messages
.TmfTraceElement_Location
;
85 private static final String sfEventType
= Messages
.TmfTraceElement_EventType
;
86 private static final String sfIsLinked
= Messages
.TmfTraceElement_IsLinked
;
87 private static final String sfTracePropertiesCategory
= Messages
.TmfTraceElement_TraceProperties
;
89 private static final ReadOnlyTextPropertyDescriptor sfNameDescriptor
= new ReadOnlyTextPropertyDescriptor(sfName
, sfName
);
90 private static final ReadOnlyTextPropertyDescriptor sfPathDescriptor
= new ReadOnlyTextPropertyDescriptor(sfPath
, sfPath
);
91 private static final ReadOnlyTextPropertyDescriptor sfLocationDescriptor
= new ReadOnlyTextPropertyDescriptor(sfLocation
, sfLocation
);
92 private static final ReadOnlyTextPropertyDescriptor sfTypeDescriptor
= new ReadOnlyTextPropertyDescriptor(sfEventType
, sfEventType
);
93 private static final ReadOnlyTextPropertyDescriptor sfIsLinkedDescriptor
= new ReadOnlyTextPropertyDescriptor(sfIsLinked
, sfIsLinked
);
95 private static final IPropertyDescriptor
[] sfDescriptors
= { sfNameDescriptor
, sfPathDescriptor
, sfLocationDescriptor
,
96 sfTypeDescriptor
, sfIsLinkedDescriptor
};
99 sfNameDescriptor
.setCategory(sfResourcePropertiesCategory
);
100 sfPathDescriptor
.setCategory(sfResourcePropertiesCategory
);
101 sfLocationDescriptor
.setCategory(sfResourcePropertiesCategory
);
102 sfTypeDescriptor
.setCategory(sfResourcePropertiesCategory
);
103 sfIsLinkedDescriptor
.setCategory(sfResourcePropertiesCategory
);
106 // ------------------------------------------------------------------------
107 // Static initialization
108 // ------------------------------------------------------------------------
110 // The mapping of available trace type IDs to their corresponding
111 // configuration element
112 private static final Map
<String
, IConfigurationElement
> sfTraceTypeAttributes
= new HashMap
<>();
113 private static final Map
<String
, IConfigurationElement
> sfTraceTypeUIAttributes
= new HashMap
<>();
114 private static final Map
<String
, IConfigurationElement
> sfTraceCategories
= new HashMap
<>();
117 * Initialize statically at startup by getting extensions from the platform
118 * extension registry.
120 public static void init() {
121 /* Read the tmf.core "tracetype" extension point */
122 IConfigurationElement
[] config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceType
.TMF_TRACE_TYPE_ID
);
123 for (IConfigurationElement ce
: config
) {
124 switch (ce
.getName()) {
125 case TmfTraceType
.TYPE_ELEM
:
126 String traceTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
127 sfTraceTypeAttributes
.put(traceTypeId
, ce
);
129 case TmfTraceType
.CATEGORY_ELEM
:
130 String categoryId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
131 sfTraceCategories
.put(categoryId
, ce
);
138 * Read the corresponding tmf.ui "tracetypeui" extension point for this
139 * trace type, if it exists.
141 config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceTypeUIUtils
.TMF_TRACE_TYPE_UI_ID
);
142 for (IConfigurationElement ce
: config
) {
143 String elemName
= ce
.getName();
144 if (TmfTraceTypeUIUtils
.TYPE_ELEM
.equals(elemName
)) {
145 String traceType
= ce
.getAttribute(TmfTraceTypeUIUtils
.TRACETYPE_ATTR
);
146 sfTraceTypeUIAttributes
.put(traceType
, ce
);
151 // ------------------------------------------------------------------------
153 // ------------------------------------------------------------------------
155 * Constructor. Creates trace model element under the trace folder.
160 * The trace resource.
162 * The parent element (trace folder)
164 public TmfTraceElement(String name
, IResource trace
, TmfTraceFolder parent
) {
165 this(name
, trace
, (TmfProjectModelElement
) parent
);
169 * Constructor. Creates trace model element under the experiment folder.
174 * The trace resource.
176 * The parent element (experiment folder)
178 public TmfTraceElement(String name
, IResource trace
, TmfExperimentElement parent
) {
179 this(name
, trace
, (TmfProjectModelElement
) parent
);
182 private TmfTraceElement(String name
, IResource trace
, TmfProjectModelElement parent
) {
183 super(name
, trace
, parent
);
186 // ------------------------------------------------------------------------
188 // ------------------------------------------------------------------------
191 * Instantiate a <code>ITmfTrace</code> object based on the trace type and
192 * the corresponding extension.
194 * @return the <code>ITmfTrace</code> or <code>null</code> for an error
197 public ITmfTrace
instantiateTrace() {
200 // make sure that supplementary folder exists
201 refreshSupplementaryFolder();
203 if (getTraceType() != null) {
204 if (getTraceType().startsWith(CustomTxtTrace
.class.getCanonicalName())) {
205 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
206 if (getTraceType().equals(CustomTxtTrace
.class.getCanonicalName() + ":" + def
.definitionName
)) { //$NON-NLS-1$
207 return new CustomTxtTrace(def
);
211 if (getTraceType().startsWith(CustomXmlTrace
.class.getCanonicalName())) {
212 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
213 if (getTraceType().equals(CustomXmlTrace
.class.getCanonicalName() + ":" + def
.definitionName
)) { //$NON-NLS-1$
214 return new CustomXmlTrace(def
);
218 IConfigurationElement ce
= sfTraceTypeAttributes
.get(getTraceType());
222 ITmfTrace trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.TRACE_TYPE_ATTR
);
225 } catch (CoreException e
) {
226 Activator
.getDefault().logError("Error instantiating ITmfTrace object for trace " + getName(), e
); //$NON-NLS-1$
232 * Instantiate a <code>ITmfEvent</code> object based on the trace type and
233 * the corresponding extension.
235 * @return the <code>ITmfEvent</code> or <code>null</code> for an error
237 public ITmfEvent
instantiateEvent() {
239 if (getTraceType() != null) {
240 if (getTraceType().startsWith(CustomTxtTrace
.class.getCanonicalName())) {
241 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
242 if (getTraceType().equals(CustomTxtTrace
.class.getCanonicalName() + ":" + def
.definitionName
)) { //$NON-NLS-1$
243 return new CustomTxtEvent(def
);
247 if (getTraceType().startsWith(CustomXmlTrace
.class.getCanonicalName())) {
248 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
249 if (getTraceType().equals(CustomXmlTrace
.class.getCanonicalName() + ":" + def
.definitionName
)) { //$NON-NLS-1$
250 return new CustomXmlEvent(def
);
254 IConfigurationElement ce
= sfTraceTypeAttributes
.get(getTraceType());
258 ITmfEvent event
= (ITmfEvent
) ce
.createExecutableExtension(TmfTraceType
.EVENT_TYPE_ATTR
);
261 } catch (CoreException e
) {
262 Activator
.getDefault().logError("Error instantiating ITmfEvent object for trace " + getName(), e
); //$NON-NLS-1$
268 public String
getEditorId() {
269 if (getTraceType() != null) {
270 if (getTraceType().startsWith(CustomTxtTrace
.class.getCanonicalName())) {
271 return TmfEventsEditor
.ID
;
273 if (getTraceType().startsWith(CustomXmlTrace
.class.getCanonicalName())) {
274 return TmfEventsEditor
.ID
;
276 IConfigurationElement ce
= sfTraceTypeUIAttributes
.get(getTraceType());
278 /* This trace type does not define UI attributes */
281 IConfigurationElement
[] defaultEditorCE
= ce
.getChildren(TmfTraceTypeUIUtils
.DEFAULT_EDITOR_ELEM
);
282 if (defaultEditorCE
.length
== 1) {
283 return defaultEditorCE
[0].getAttribute(TmfTraceType
.ID_ATTR
);
290 * Returns the file resource used to store bookmarks after creating it if
291 * necessary. If the trace resource is a file, it is returned directly. If
292 * the trace resource is a folder, a linked file is returned. The file will
293 * be created if it does not exist.
295 * @return the bookmarks file
296 * @throws CoreException
297 * if the bookmarks file cannot be created
301 public IFile
createBookmarksFile() throws CoreException
{
302 IFile file
= getBookmarksFile();
303 if (fResource
instanceof IFolder
) {
304 return createBookmarksFile(getProject().getTracesFolder().getResource(), TmfTrace
.class.getCanonicalName());
310 * Returns the file resource used to store bookmarks. The file may not
313 * @return the bookmarks file
317 public IFile
getBookmarksFile() {
319 if (fResource
instanceof IFile
) {
320 file
= (IFile
) fResource
;
321 } else if (fResource
instanceof IFolder
) {
322 final IFolder folder
= (IFolder
) fResource
;
323 file
= folder
.getFile(getName() + '_');
329 * Returns the <code>TmfTraceElement</code> located under the
330 * <code>TmfTracesFolder</code>.
332 * @return <code>this</code> if this element is under the
333 * <code>TmfTracesFolder</code> else the corresponding
334 * <code>TmfTraceElement</code> if this element is under
335 * <code>TmfExperimentElement</code>.
337 public TmfTraceElement
getElementUnderTraceFolder() {
339 // If trace is under an experiment, return original trace from the
341 if (getParent() instanceof TmfExperimentElement
) {
342 for (TmfTraceElement aTrace
: getProject().getTracesFolder().getTraces()) {
343 if (aTrace
.getName().equals(getName())) {
352 public String
getTypeName() {
353 return Messages
.TmfTraceElement_TypeName
;
356 // ------------------------------------------------------------------------
358 // ------------------------------------------------------------------------
361 public boolean testAttribute(Object target
, String name
, String value
) {
362 if (name
.equals(IS_LINKED
)) {
363 boolean isLinked
= getResource().isLinked();
364 return Boolean
.toString(isLinked
).equals(value
);
369 // ------------------------------------------------------------------------
371 // ------------------------------------------------------------------------
374 public TmfProjectElement
getProject() {
375 if (getParent() instanceof TmfTraceFolder
) {
376 TmfTraceFolder folder
= (TmfTraceFolder
) getParent();
377 TmfProjectElement project
= (TmfProjectElement
) folder
.getParent();
380 if (getParent() instanceof TmfExperimentElement
) {
381 TmfExperimentElement experiment
= (TmfExperimentElement
) getParent();
382 TmfExperimentFolder folder
= (TmfExperimentFolder
) experiment
.getParent();
383 TmfProjectElement project
= (TmfProjectElement
) folder
.getParent();
389 // ------------------------------------------------------------------------
391 // ------------------------------------------------------------------------
394 public Object
getEditableValue() {
399 * Get the trace properties of this traceElement if the corresponding trace
400 * is opened in an editor
402 * @return a map with the names and values of the trace properties
403 * respectively as keys and values
405 private Map
<String
, String
> getTraceProperties() {
406 for (ITmfTrace openedTrace
: TmfTraceManager
.getInstance().getOpenedTraces()) {
407 for (ITmfTrace singleTrace
: TmfTraceManager
.getTraceSet(openedTrace
)) {
408 if (this.getLocation().getPath().endsWith(singleTrace
.getPath())) {
409 if (singleTrace
instanceof ITmfTraceProperties
) {
410 ITmfTraceProperties traceProperties
= (ITmfTraceProperties
) singleTrace
;
411 return traceProperties
.getTraceProperties();
416 return new HashMap
<>();
420 public IPropertyDescriptor
[] getPropertyDescriptors() {
421 Map
<String
, String
> traceProperties
= getTraceProperties();
422 if (!traceProperties
.isEmpty()) {
423 IPropertyDescriptor
[] propertyDescriptorArray
= new IPropertyDescriptor
[traceProperties
.size() + sfDescriptors
.length
];
425 for (Map
.Entry
<String
, String
> varName
: traceProperties
.entrySet()) {
426 ReadOnlyTextPropertyDescriptor descriptor
= new ReadOnlyTextPropertyDescriptor(this.getName() + "_" + varName
.getKey(), varName
.getKey()); //$NON-NLS-1$
427 descriptor
.setCategory(sfTracePropertiesCategory
);
428 propertyDescriptorArray
[index
] = descriptor
;
431 for (int i
= 0; i
< sfDescriptors
.length
; i
++) {
432 propertyDescriptorArray
[index
] = sfDescriptors
[i
];
435 return propertyDescriptorArray
;
437 return Arrays
.copyOf(sfDescriptors
, sfDescriptors
.length
);
441 public Object
getPropertyValue(Object id
) {
443 if (sfName
.equals(id
)) {
447 if (sfPath
.equals(id
)) {
448 return getPath().toString();
451 if (sfLocation
.equals(id
)) {
452 return URIUtil
.toUnencodedString(getLocation());
455 if (sfIsLinked
.equals(id
)) {
456 return Boolean
.valueOf(getResource().isLinked()).toString();
459 if (sfEventType
.equals(id
)) {
460 if (getTraceType() != null) {
461 IConfigurationElement ce
= sfTraceTypeAttributes
.get(getTraceType());
462 return (ce
!= null) ?
(getCategory(ce
) + " : " + ce
.getAttribute(TmfTraceType
.NAME_ATTR
)) : ""; //$NON-NLS-1$ //$NON-NLS-2$
466 Map
<String
, String
> traceProperties
= getTraceProperties();
467 if (id
!= null && !traceProperties
.isEmpty()) {
468 String key
= (String
) id
;
469 key
= key
.replaceFirst(this.getName() + "_", ""); //$NON-NLS-1$ //$NON-NLS-2$
470 String value
= traceProperties
.get(key
);
477 private static String
getCategory(IConfigurationElement ce
) {
478 String categoryId
= ce
.getAttribute(TmfTraceType
.CATEGORY_ATTR
);
479 if (categoryId
!= null) {
480 IConfigurationElement category
= sfTraceCategories
.get(categoryId
);
481 if (category
!= null) {
482 return category
.getAttribute(TmfTraceType
.NAME_ATTR
);
485 return "[no category]"; //$NON-NLS-1$
489 public void resetPropertyValue(Object id
) {
493 public void setPropertyValue(Object id
, Object value
) {
497 public boolean isPropertyResettable(Object id
) {
502 public boolean isPropertySet(Object id
) {
507 * Copy this trace in the trace folder. No other parameters are mentioned so
508 * the trace is copied in this element's project trace folder
512 * @return the new Resource object
515 public TmfTraceElement
copy(String string
) {
516 TmfTraceFolder folder
= this.getProject().getTracesFolder();
517 IResource res
= super.copy(string
, false);
518 return new TmfTraceElement(string
, res
, folder
);
522 * Close opened editors associated with this trace.
527 public void closeEditors() {
528 super.closeEditors();
530 // Close experiments that contain the trace if open
531 if (getParent() instanceof TmfTraceFolder
) {
532 TmfExperimentFolder experimentFolder
= getProject().getExperimentsFolder();
533 for (ITmfProjectModelElement experiment
: experimentFolder
.getChildren()) {
534 for (ITmfProjectModelElement child
: experiment
.getChildren()) {
535 if (child
.getName().equals(getName())) {
536 ((TmfExperimentElement
) experiment
).closeEditors();
541 } else if (getParent() instanceof TmfExperimentElement
) {
542 TmfExperimentElement experiment
= (TmfExperimentElement
) getParent();
543 experiment
.closeEditors();
548 * Delete the trace resource, remove it from experiments and delete its
549 * supplementary files
551 * @param progressMonitor
552 * a progress monitor, or null if progress reporting is not
555 * @throws CoreException
556 * thrown when IResource.delete fails
559 public void delete(IProgressMonitor progressMonitor
) throws CoreException
{
562 IPath path
= fResource
.getLocation();
564 if (getParent() instanceof TmfTraceFolder
) {
565 TmfExperimentFolder experimentFolder
= getProject().getExperimentsFolder();
567 // Propagate the removal to traces
568 for (ITmfProjectModelElement experiment
: experimentFolder
.getChildren()) {
569 List
<ITmfProjectModelElement
> toRemove
= new LinkedList
<>();
570 for (ITmfProjectModelElement child
: experiment
.getChildren()) {
571 if (child
.getName().equals(getName())) {
575 for (ITmfProjectModelElement child
: toRemove
) {
576 ((TmfExperimentElement
) experiment
).removeTrace((TmfTraceElement
) child
);
580 // Delete supplementary files
581 deleteSupplementaryFolder();
583 } else if (getParent() instanceof TmfExperimentElement
) {
584 TmfExperimentElement experimentElement
= (TmfExperimentElement
) getParent();
585 experimentElement
.removeTrace(this);
589 // Finally, delete the trace
590 fResource
.delete(true, progressMonitor
);