1 /*******************************************************************************
2 * Copyright (c) 2010, 2013 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 *******************************************************************************/
19 package org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
;
21 import java
.io
.ByteArrayInputStream
;
22 import java
.io
.InputStream
;
23 import java
.util
.Arrays
;
24 import java
.util
.HashMap
;
27 import org
.eclipse
.core
.resources
.IFile
;
28 import org
.eclipse
.core
.resources
.IFolder
;
29 import org
.eclipse
.core
.resources
.IResource
;
30 import org
.eclipse
.core
.runtime
.CoreException
;
31 import org
.eclipse
.core
.runtime
.IConfigurationElement
;
32 import org
.eclipse
.core
.runtime
.Platform
;
33 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
34 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.parsers
.custom
.CustomTxtEvent
;
35 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.parsers
.custom
.CustomTxtTrace
;
36 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.parsers
.custom
.CustomTxtTraceDefinition
;
37 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.parsers
.custom
.CustomXmlEvent
;
38 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.parsers
.custom
.CustomXmlTrace
;
39 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.parsers
.custom
.CustomXmlTraceDefinition
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTraceProperties
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTrace
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTraceManager
;
46 import org
.eclipse
.linuxtools
.tmf
.ui
.editors
.TmfEventsEditor
;
47 import org
.eclipse
.linuxtools
.tmf
.ui
.properties
.ReadOnlyTextPropertyDescriptor
;
48 import org
.eclipse
.ui
.IActionFilter
;
49 import org
.eclipse
.ui
.IEditorReference
;
50 import org
.eclipse
.ui
.IWorkbench
;
51 import org
.eclipse
.ui
.IWorkbenchPage
;
52 import org
.eclipse
.ui
.IWorkbenchWindow
;
53 import org
.eclipse
.ui
.PartInitException
;
54 import org
.eclipse
.ui
.PlatformUI
;
55 import org
.eclipse
.ui
.part
.FileEditorInput
;
56 import org
.eclipse
.ui
.views
.properties
.IPropertyDescriptor
;
57 import org
.eclipse
.ui
.views
.properties
.IPropertySource2
;
60 * Implementation of trace model element representing a trace. It provides
61 * methods to instantiate <code>ITmfTrace</code> and <code>ITmfEvent</code> as
62 * well as editor ID from the trace type extension definition.
65 * @author Francois Chouinard
67 public class TmfTraceElement
extends TmfWithFolderElement
implements IActionFilter
, IPropertySource2
{
69 // ------------------------------------------------------------------------
71 // ------------------------------------------------------------------------
75 * Bundle attribute name
77 public static final String BUNDLE
= "bundle"; //$NON-NLS-1$
79 * IsLinked attribute name.
81 public static final String IS_LINKED
= "isLinked"; //$NON-NLS-1$
83 // Property View stuff
84 private static final String sfResourcePropertiesCategory
= Messages
.TmfTraceElement_ResourceProperties
;
85 private static final String sfName
= Messages
.TmfTraceElement_Name
;
86 private static final String sfPath
= Messages
.TmfTraceElement_Path
;
87 private static final String sfLocation
= Messages
.TmfTraceElement_Location
;
88 private static final String sfEventType
= Messages
.TmfTraceElement_EventType
;
89 private static final String sfIsLinked
= Messages
.TmfTraceElement_IsLinked
;
90 private static final String sfTracePropertiesCategory
= Messages
.TmfTraceElement_TraceProperties
;
92 private static final ReadOnlyTextPropertyDescriptor sfNameDescriptor
= new ReadOnlyTextPropertyDescriptor(sfName
, sfName
);
93 private static final ReadOnlyTextPropertyDescriptor sfPathDescriptor
= new ReadOnlyTextPropertyDescriptor(sfPath
, sfPath
);
94 private static final ReadOnlyTextPropertyDescriptor sfLocationDescriptor
= new ReadOnlyTextPropertyDescriptor(sfLocation
, sfLocation
);
95 private static final ReadOnlyTextPropertyDescriptor sfTypeDescriptor
= new ReadOnlyTextPropertyDescriptor(sfEventType
, sfEventType
);
96 private static final ReadOnlyTextPropertyDescriptor sfIsLinkedDescriptor
= new ReadOnlyTextPropertyDescriptor(sfIsLinked
, sfIsLinked
);
98 private static final IPropertyDescriptor
[] sfDescriptors
= { sfNameDescriptor
, sfPathDescriptor
, sfLocationDescriptor
,
99 sfTypeDescriptor
, sfIsLinkedDescriptor
};
102 sfNameDescriptor
.setCategory(sfResourcePropertiesCategory
);
103 sfPathDescriptor
.setCategory(sfResourcePropertiesCategory
);
104 sfLocationDescriptor
.setCategory(sfResourcePropertiesCategory
);
105 sfTypeDescriptor
.setCategory(sfResourcePropertiesCategory
);
106 sfIsLinkedDescriptor
.setCategory(sfResourcePropertiesCategory
);
109 private static final String BOOKMARKS_HIDDEN_FILE
= ".bookmarks"; //$NON-NLS-1$
111 // ------------------------------------------------------------------------
113 // ------------------------------------------------------------------------
115 // This trace type ID as defined in plugin.xml
116 private String fTraceTypeId
= null;
118 // ------------------------------------------------------------------------
119 // Static initialization
120 // ------------------------------------------------------------------------
122 // The mapping of available trace type IDs to their corresponding
123 // configuration element
124 private static final Map
<String
, IConfigurationElement
> sfTraceTypeAttributes
= new HashMap
<String
, IConfigurationElement
>();
125 private static final Map
<String
, IConfigurationElement
> sfTraceCategories
= new HashMap
<String
, IConfigurationElement
>();
128 * Initialize statically at startup by getting extensions from the platform
129 * extension registry.
131 public static void init() {
132 IConfigurationElement
[] config
= Platform
.getExtensionRegistry().getConfigurationElementsFor(TmfTraceType
.TMF_TRACE_TYPE_ID
);
133 for (IConfigurationElement ce
: config
) {
134 String elementName
= ce
.getName();
135 if (elementName
.equals(TmfTraceType
.TYPE_ELEM
)) {
136 String traceTypeId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
137 sfTraceTypeAttributes
.put(traceTypeId
, ce
);
138 } else if (elementName
.equals(TmfTraceType
.CATEGORY_ELEM
)) {
139 String categoryId
= ce
.getAttribute(TmfTraceType
.ID_ATTR
);
140 sfTraceCategories
.put(categoryId
, ce
);
145 // ------------------------------------------------------------------------
147 // ------------------------------------------------------------------------
149 * Constructor. Creates trace model element under the trace folder.
154 * The trace resource.
156 * The parent element (trace folder)
158 public TmfTraceElement(String name
, IResource trace
, TmfTraceFolder parent
) {
159 this(name
, trace
, (TmfProjectModelElement
) parent
);
163 * Constructor. Creates trace model element under the experiment folder.
168 * The trace resource.
170 * The parent element (experiment folder)
172 public TmfTraceElement(String name
, IResource trace
, TmfExperimentElement parent
) {
173 this(name
, trace
, (TmfProjectModelElement
) parent
);
176 private TmfTraceElement(String name
, IResource trace
, TmfProjectModelElement parent
) {
177 super(name
, trace
, parent
);
178 parent
.addChild(this);
182 // ------------------------------------------------------------------------
184 // ------------------------------------------------------------------------
186 * Returns the trace type ID.
188 * @return trace type ID.
190 public String
getTraceType() {
195 * Refreshes the trace type filed by reading the trace type persistent
196 * property of the resource referenece.
198 public void refreshTraceType() {
200 fTraceTypeId
= getResource().getPersistentProperty(TmfCommonConstants
.TRACETYPE
);
201 } catch (CoreException e
) {
202 Activator
.getDefault().logError("Error refreshing trace type pesistent property for trace " + getName(), e
); //$NON-NLS-1$
207 * Instantiate a <code>ITmfTrace</code> object based on the trace type and
208 * the corresponding extension.
210 * @return the <code>ITmfTrace</code> or <code>null</code> for an error
212 public ITmfTrace
instantiateTrace() {
215 // make sure that supplementary folder exists
216 refreshSupplementaryFolder();
218 if (fTraceTypeId
!= null) {
219 if (fTraceTypeId
.startsWith(CustomTxtTrace
.class.getCanonicalName())) {
220 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
221 if (fTraceTypeId
.equals(CustomTxtTrace
.class.getCanonicalName() + ":" + def
.definitionName
)) { //$NON-NLS-1$
222 return new CustomTxtTrace(def
);
226 if (fTraceTypeId
.startsWith(CustomXmlTrace
.class.getCanonicalName())) {
227 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
228 if (fTraceTypeId
.equals(CustomXmlTrace
.class.getCanonicalName() + ":" + def
.definitionName
)) { //$NON-NLS-1$
229 return new CustomXmlTrace(def
);
233 IConfigurationElement ce
= sfTraceTypeAttributes
.get(fTraceTypeId
);
237 ITmfTrace trace
= (ITmfTrace
) ce
.createExecutableExtension(TmfTraceType
.TRACE_TYPE_ATTR
);
240 } catch (CoreException e
) {
241 Activator
.getDefault().logError("Error instantiating ITmfTrace object for trace " + getName(), e
); //$NON-NLS-1$
247 * Instantiate a <code>ITmfEvent</code> object based on the trace type and
248 * the corresponding extension.
250 * @return the <code>ITmfEvent</code> or <code>null</code> for an error
252 public ITmfEvent
instantiateEvent() {
254 if (fTraceTypeId
!= null) {
255 if (fTraceTypeId
.startsWith(CustomTxtTrace
.class.getCanonicalName())) {
256 for (CustomTxtTraceDefinition def
: CustomTxtTraceDefinition
.loadAll()) {
257 if (fTraceTypeId
.equals(CustomTxtTrace
.class.getCanonicalName() + ":" + def
.definitionName
)) { //$NON-NLS-1$
258 return new CustomTxtEvent(def
);
262 if (fTraceTypeId
.startsWith(CustomXmlTrace
.class.getCanonicalName())) {
263 for (CustomXmlTraceDefinition def
: CustomXmlTraceDefinition
.loadAll()) {
264 if (fTraceTypeId
.equals(CustomXmlTrace
.class.getCanonicalName() + ":" + def
.definitionName
)) { //$NON-NLS-1$
265 return new CustomXmlEvent(def
);
269 IConfigurationElement ce
= sfTraceTypeAttributes
.get(fTraceTypeId
);
273 ITmfEvent event
= (ITmfEvent
) ce
.createExecutableExtension(TmfTraceType
.EVENT_TYPE_ATTR
);
276 } catch (CoreException e
) {
277 Activator
.getDefault().logError("Error instantiating ITmfEvent object for trace " + getName(), e
); //$NON-NLS-1$
283 * Returns the optional editor ID from the trace type extension.
285 * @return the editor ID or <code>null</code> if not defined.
287 public String
getEditorId() {
288 if (fTraceTypeId
!= null) {
289 if (fTraceTypeId
.startsWith(CustomTxtTrace
.class.getCanonicalName())) {
290 return TmfEventsEditor
.ID
;
292 if (fTraceTypeId
.startsWith(CustomXmlTrace
.class.getCanonicalName())) {
293 return TmfEventsEditor
.ID
;
295 IConfigurationElement ce
= sfTraceTypeAttributes
.get(fTraceTypeId
);
296 IConfigurationElement
[] defaultEditorCE
= ce
.getChildren(TmfTraceType
.DEFAULT_EDITOR_ELEM
);
297 if (defaultEditorCE
.length
== 1) {
298 return defaultEditorCE
[0].getAttribute(TmfTraceType
.ID_ATTR
);
305 * Returns the file resource used to store bookmarks after creating it if
306 * necessary. If the trace resource is a file, it is returned directly. If
307 * the trace resource is a folder, a linked file is returned. The file will
308 * be created if it does not exist.
310 * @return the bookmarks file
311 * @throws CoreException
312 * if the bookmarks file cannot be created
315 public IFile
createBookmarksFile() throws CoreException
{
316 IFile file
= getBookmarksFile();
317 if (fResource
instanceof IFolder
) {
318 if (!file
.exists()) {
319 final IFile bookmarksFile
= getProject().getTracesFolder().getResource().getFile(BOOKMARKS_HIDDEN_FILE
);
320 if (!bookmarksFile
.exists()) {
321 final InputStream source
= new ByteArrayInputStream(new byte[0]);
322 bookmarksFile
.create(source
, true, null);
324 bookmarksFile
.setHidden(true);
325 file
.createLink(bookmarksFile
.getLocation(), IResource
.REPLACE
, null);
326 file
.setHidden(true);
327 file
.setPersistentProperty(TmfCommonConstants
.TRACETYPE
, TmfTrace
.class.getCanonicalName());
334 * Returns the file resource used to store bookmarks. The file may not
337 * @return the bookmarks file
340 public IFile
getBookmarksFile() {
342 if (fResource
instanceof IFile
) {
343 file
= (IFile
) fResource
;
344 } else if (fResource
instanceof IFolder
) {
345 final IFolder folder
= (IFolder
) fResource
;
346 file
= folder
.getFile(getName() + '_');
352 * Returns the <code>TmfTraceElement</code> located under the
353 * <code>TmfTracesFolder</code>.
355 * @return <code>this</code> if this element is under the
356 * <code>TmfTracesFolder</code> else the corresponding
357 * <code>TmfTraceElement</code> if this element is under
358 * <code>TmfExperimentElement</code>.
360 public TmfTraceElement
getElementUnderTraceFolder() {
362 // If trace is under an experiment, return original trace from the
364 if (getParent() instanceof TmfExperimentElement
) {
365 for (TmfTraceElement aTrace
: getProject().getTracesFolder().getTraces()) {
366 if (aTrace
.getName().equals(getName())) {
374 // ------------------------------------------------------------------------
376 // ------------------------------------------------------------------------
379 public boolean testAttribute(Object target
, String name
, String value
) {
380 if (name
.equals(IS_LINKED
)) {
381 boolean isLinked
= getResource().isLinked();
382 return Boolean
.toString(isLinked
).equals(value
);
387 // ------------------------------------------------------------------------
389 // ------------------------------------------------------------------------
392 public TmfProjectElement
getProject() {
393 if (getParent() instanceof TmfTraceFolder
) {
394 TmfTraceFolder folder
= (TmfTraceFolder
) getParent();
395 TmfProjectElement project
= (TmfProjectElement
) folder
.getParent();
398 if (getParent() instanceof TmfExperimentElement
) {
399 TmfExperimentElement experiment
= (TmfExperimentElement
) getParent();
400 TmfExperimentFolder folder
= (TmfExperimentFolder
) experiment
.getParent();
401 TmfProjectElement project
= (TmfProjectElement
) folder
.getParent();
407 // ------------------------------------------------------------------------
409 // ------------------------------------------------------------------------
412 public Object
getEditableValue() {
417 * Get the trace properties of this traceElement if the corresponding trace
418 * is opened in an editor
420 * @return a map with the names and values of the trace properties
421 * respectively as keys and values
423 private Map
<String
, String
> getTraceProperties() {
424 for (ITmfTrace openedTrace
: TmfTraceManager
.getInstance().getOpenedTraces()) {
425 for (ITmfTrace singleTrace
: TmfTraceManager
.getTraceSet(openedTrace
)) {
426 if (this.getLocation().toString().endsWith(singleTrace
.getPath())) {
427 if (singleTrace
instanceof ITmfTraceProperties
) {
428 ITmfTraceProperties traceProperties
= (ITmfTraceProperties
) singleTrace
;
429 return traceProperties
.getTraceProperties();
434 return new HashMap
<String
, String
>();
438 public IPropertyDescriptor
[] getPropertyDescriptors() {
439 Map
<String
, String
> traceProperties
= getTraceProperties();
440 if (!traceProperties
.isEmpty()) {
441 IPropertyDescriptor
[] propertyDescriptorArray
= new IPropertyDescriptor
[traceProperties
.size() + sfDescriptors
.length
];
443 for (Map
.Entry
<String
, String
> varName
: traceProperties
.entrySet()) {
444 ReadOnlyTextPropertyDescriptor descriptor
= new ReadOnlyTextPropertyDescriptor(this.getName() + "_" + varName
.getKey(), varName
.getKey()); //$NON-NLS-1$
445 descriptor
.setCategory(sfTracePropertiesCategory
);
446 propertyDescriptorArray
[index
] = descriptor
;
449 for (int i
= 0; i
< sfDescriptors
.length
; i
++) {
450 propertyDescriptorArray
[index
] = sfDescriptors
[i
];
453 return propertyDescriptorArray
;
455 return Arrays
.copyOf(sfDescriptors
, sfDescriptors
.length
);
459 public Object
getPropertyValue(Object id
) {
461 if (sfName
.equals(id
)) {
465 if (sfPath
.equals(id
)) {
466 return getPath().toString();
469 if (sfLocation
.equals(id
)) {
470 return getLocation().toString();
473 if (sfIsLinked
.equals(id
)) {
474 return Boolean
.valueOf(getResource().isLinked()).toString();
477 if (sfEventType
.equals(id
)) {
478 if (fTraceTypeId
!= null) {
479 IConfigurationElement ce
= sfTraceTypeAttributes
.get(fTraceTypeId
);
480 return (ce
!= null) ?
(getCategory(ce
) + " : " + ce
.getAttribute(TmfTraceType
.NAME_ATTR
)) : ""; //$NON-NLS-1$ //$NON-NLS-2$
484 Map
<String
, String
> traceProperties
= getTraceProperties();
485 if (id
!= null && !traceProperties
.isEmpty()) {
486 String key
= (String
) id
;
487 key
= key
.replaceFirst(this.getName() + "_", ""); //$NON-NLS-1$ //$NON-NLS-2$
488 String value
= traceProperties
.get(key
);
495 private static String
getCategory(IConfigurationElement ce
) {
496 String categoryId
= ce
.getAttribute(TmfTraceType
.CATEGORY_ATTR
);
497 if (categoryId
!= null) {
498 IConfigurationElement category
= sfTraceCategories
.get(categoryId
);
499 if (category
!= null) {
500 return category
.getAttribute(TmfTraceType
.NAME_ATTR
);
503 return "[no category]"; //$NON-NLS-1$
507 public void resetPropertyValue(Object id
) {
511 public void setPropertyValue(Object id
, Object value
) {
515 public boolean isPropertyResettable(Object id
) {
520 public boolean isPropertySet(Object id
) {
525 * Copy this trace in the trace folder. No other parameters are mentioned so
526 * the trace is copied in this element's project trace folder
530 * @return the new Resource object
533 public TmfTraceElement
copy(String string
) {
534 TmfTraceFolder folder
= this.getProject().getTracesFolder();
535 IResource res
= super.copy(string
, false);
536 return new TmfTraceElement(string
, res
, folder
);
540 * Close opened editors associated with this trace.
544 public void closeEditors() {
545 // Close the trace if open
546 IFile file
= getBookmarksFile();
547 FileEditorInput input
= new FileEditorInput(file
);
548 IWorkbench wb
= PlatformUI
.getWorkbench();
549 for (IWorkbenchWindow wbWindow
: wb
.getWorkbenchWindows()) {
550 for (IWorkbenchPage wbPage
: wbWindow
.getPages()) {
551 for (IEditorReference editorReference
: wbPage
.getEditorReferences()) {
553 if (editorReference
.getEditorInput().equals(input
)) {
554 wbPage
.closeEditor(editorReference
.getEditor(false), false);
556 } catch (PartInitException e
) {
557 Activator
.getDefault().logError("Error closing editor for trace " + getName(), e
); //$NON-NLS-1$
563 // Close experiments that contain the trace if open
564 if (getParent() instanceof TmfTraceFolder
) {
565 TmfExperimentFolder experimentFolder
= getProject().getExperimentsFolder();
566 for (ITmfProjectModelElement experiment
: experimentFolder
.getChildren()) {
567 for (ITmfProjectModelElement child
: experiment
.getChildren()) {
568 if (child
.getName().equals(getName())) {
569 ((TmfExperimentElement
) experiment
).closeEditors();
574 } else if (getParent() instanceof TmfExperimentElement
) {
575 TmfExperimentElement experiment
= (TmfExperimentElement
) getParent();
576 experiment
.closeEditors();