tmf: Put analyses under their own node in the Project View
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / project / model / TmfExperimentElement.java
CommitLineData
12c155f5 1/*******************************************************************************
58ffe079 2 * Copyright (c) 2010, 2015 Ericsson, École Polytechnique de Montréal
c4c81d91 3 *
12c155f5
FC
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
c4c81d91 8 *
12c155f5
FC
9 * Contributors:
10 * Francois Chouinard - Initial API and implementation
beb19106 11 * Geneviève Bastien - Copied code to add/remove traces in this class
a72a6830 12 * Patrick Tasse - Close editors to release resources
8f5221c2 13 * Geneviève Bastien - Experiment instantiated with trace type
12c155f5
FC
14 *******************************************************************************/
15
2bdf0193 16package org.eclipse.tracecompass.tmf.ui.project.model;
12c155f5 17
5c727157
AM
18import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
19
12c155f5 20import java.util.ArrayList;
5a5c2fc7 21import java.util.Arrays;
dca8b422
BH
22import java.util.Collections;
23import java.util.Comparator;
f537c959 24import java.util.HashMap;
12c155f5 25import java.util.List;
beb19106 26import java.util.Map;
12c155f5 27
339d539c 28import org.eclipse.core.resources.IContainer;
c4c81d91 29import org.eclipse.core.resources.IFile;
12c155f5 30import org.eclipse.core.resources.IFolder;
c4c81d91 31import org.eclipse.core.resources.IResource;
339d539c
PT
32import org.eclipse.core.resources.IResourceProxy;
33import org.eclipse.core.resources.IResourceProxyVisitor;
beb19106
GB
34import org.eclipse.core.resources.IWorkspace;
35import org.eclipse.core.resources.ResourcesPlugin;
c4c81d91 36import org.eclipse.core.runtime.CoreException;
8f5221c2 37import org.eclipse.core.runtime.IConfigurationElement;
beb19106 38import org.eclipse.core.runtime.IPath;
977ca87f 39import org.eclipse.core.runtime.IStatus;
8f5221c2 40import org.eclipse.core.runtime.InvalidRegistryObjectException;
339d539c 41import org.eclipse.core.runtime.NullProgressMonitor;
8f5221c2 42import org.eclipse.core.runtime.Platform;
dff70ccd 43import org.eclipse.jdt.annotation.NonNull;
8f5221c2 44import org.eclipse.osgi.util.NLS;
dff70ccd 45import org.eclipse.swt.graphics.Image;
ea01e5a2 46import org.eclipse.swt.widgets.Display;
2bdf0193 47import org.eclipse.tracecompass.internal.tmf.ui.Activator;
58ffe079 48import org.eclipse.tracecompass.internal.tmf.ui.editors.ITmfEventsEditorConstants;
2bdf0193 49import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
ff7b95a5
GB
50import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModuleHelper;
51import org.eclipse.tracecompass.tmf.core.analysis.TmfAnalysisManager;
2bdf0193
AM
52import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType;
53import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper;
ff7b95a5 54import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
5c5fa260 55import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
2bdf0193
AM
56import org.eclipse.tracecompass.tmf.ui.editors.TmfEventsEditor;
57import org.eclipse.tracecompass.tmf.ui.properties.ReadOnlyTextPropertyDescriptor;
12c155f5
FC
58import org.eclipse.ui.views.properties.IPropertyDescriptor;
59import org.eclipse.ui.views.properties.IPropertySource2;
12c155f5
FC
60
61/**
b544077e 62 * Implementation of TMF Experiment Model Element.
12c155f5 63 * <p>
dc62dbee 64 *
b544077e
BH
65 * @version 1.0
66 * @author Francois Chouinard
c4c81d91 67 *
12c155f5 68 */
16036bc2 69public class TmfExperimentElement extends TmfCommonProjectElement implements IPropertySource2 {
12c155f5
FC
70
71 // ------------------------------------------------------------------------
72 // Constants
73 // ------------------------------------------------------------------------
74
75 // Property View stuff
067cd9de
BH
76 private static final String INFO_CATEGORY = "Info"; //$NON-NLS-1$
77 private static final String NAME = "name"; //$NON-NLS-1$
78 private static final String PATH = "path"; //$NON-NLS-1$
79 private static final String LOCATION = "location"; //$NON-NLS-1$
80 private static final String FOLDER_SUFFIX = "_exp"; //$NON-NLS-1$
81 private static final String EXPERIMENT_TYPE = "type"; //$NON-NLS-1$
82
83 private static final ReadOnlyTextPropertyDescriptor NAME_DESCRIPTOR = new ReadOnlyTextPropertyDescriptor(NAME, NAME);
84 private static final ReadOnlyTextPropertyDescriptor PATH_DESCRIPTOR = new ReadOnlyTextPropertyDescriptor(PATH, PATH);
85 private static final ReadOnlyTextPropertyDescriptor LOCATION_DESCRIPTOR = new ReadOnlyTextPropertyDescriptor(LOCATION,
86 LOCATION);
87 private static final ReadOnlyTextPropertyDescriptor TYPE_DESCRIPTOR = new ReadOnlyTextPropertyDescriptor(EXPERIMENT_TYPE, EXPERIMENT_TYPE);
88
89 private static final IPropertyDescriptor[] DESCRIPTORS = { NAME_DESCRIPTOR, PATH_DESCRIPTOR,
90 LOCATION_DESCRIPTOR, TYPE_DESCRIPTOR };
12c155f5
FC
91
92 static {
067cd9de
BH
93 NAME_DESCRIPTOR.setCategory(INFO_CATEGORY);
94 PATH_DESCRIPTOR.setCategory(INFO_CATEGORY);
95 LOCATION_DESCRIPTOR.setCategory(INFO_CATEGORY);
96 TYPE_DESCRIPTOR.setCategory(INFO_CATEGORY);
12c155f5
FC
97 }
98
8f5221c2
GB
99 // The mapping of available trace type IDs to their corresponding
100 // configuration element
067cd9de
BH
101 private static final Map<String, IConfigurationElement> TRACE_TYPE_ATTRIBUTES = new HashMap<>();
102 private static final Map<String, IConfigurationElement> TRACE_TYPE_UI_ATTRIBUTES = new HashMap<>();
103 private static final Map<String, IConfigurationElement> TRACE_CATEGORIES = new HashMap<>();
8f5221c2
GB
104
105 // ------------------------------------------------------------------------
106 // Static initialization
107 // ------------------------------------------------------------------------
108
109 /**
110 * Initialize statically at startup by getting extensions from the platform
111 * extension registry.
8f5221c2
GB
112 */
113 public static void init() {
114 IConfigurationElement[] config = Platform.getExtensionRegistry().getConfigurationElementsFor(TmfTraceType.TMF_TRACE_TYPE_ID);
115 for (IConfigurationElement ce : config) {
116 String elementName = ce.getName();
117 if (elementName.equals(TmfTraceType.EXPERIMENT_ELEM)) {
118 String traceTypeId = ce.getAttribute(TmfTraceType.ID_ATTR);
067cd9de 119 TRACE_TYPE_ATTRIBUTES.put(traceTypeId, ce);
8f5221c2
GB
120 } else if (elementName.equals(TmfTraceType.CATEGORY_ELEM)) {
121 String categoryId = ce.getAttribute(TmfTraceType.ID_ATTR);
067cd9de 122 TRACE_CATEGORIES.put(categoryId, ce);
8f5221c2
GB
123 }
124 }
125
126 /*
127 * Read the corresponding tmf.ui "tracetypeui" extension point for this
128 * trace type, if it exists.
129 */
130 config = Platform.getExtensionRegistry().getConfigurationElementsFor(TmfTraceTypeUIUtils.TMF_TRACE_TYPE_UI_ID);
131 for (IConfigurationElement ce : config) {
132 String elemName = ce.getName();
133 if (TmfTraceTypeUIUtils.EXPERIMENT_ELEM.equals(elemName)) {
134 String traceType = ce.getAttribute(TmfTraceTypeUIUtils.TRACETYPE_ATTR);
067cd9de 135 TRACE_TYPE_UI_ATTRIBUTES.put(traceType, ce);
8f5221c2
GB
136 }
137 }
138 }
c4c81d91 139
12c155f5
FC
140 // ------------------------------------------------------------------------
141 // Constructors
142 // ------------------------------------------------------------------------
b544077e 143 /**
c4c81d91 144 * Constructor
dc62dbee
CB
145 *
146 * @param name
147 * The name of the experiment
148 * @param folder
149 * The folder reference
150 * @param parent
151 * The experiment folder reference.
b544077e 152 */
12c155f5
FC
153 public TmfExperimentElement(String name, IFolder folder, TmfExperimentFolder parent) {
154 super(name, folder, parent);
12c155f5
FC
155 }
156
157 // ------------------------------------------------------------------------
158 // TmfProjectModelElement
159 // ------------------------------------------------------------------------
160
161 @Override
162 public IFolder getResource() {
b3e4798c 163 return (IFolder) super.getResource();
12c155f5
FC
164 }
165
b3e4798c
AM
166 /**
167 * @since 2.0
168 */
f537c959 169 @Override
b3e4798c 170 protected void refreshChildren() {
f537c959
PT
171 IFolder folder = getResource();
172
8f5221c2 173 /* Update the trace children of this experiment */
f537c959
PT
174 // Get the children from the model
175 Map<String, ITmfProjectModelElement> childrenMap = new HashMap<>();
339d539c
PT
176 for (TmfTraceElement trace : getTraces()) {
177 childrenMap.put(trace.getElementPath(), trace);
f537c959
PT
178 }
179
339d539c
PT
180 List<IResource> members = getTraceResources();
181 for (IResource resource : members) {
182 String name = resource.getName();
183 String elementPath = resource.getFullPath().makeRelativeTo(folder.getFullPath()).toString();
184 ITmfProjectModelElement element = childrenMap.get(elementPath);
185 if (element instanceof TmfTraceElement) {
186 childrenMap.remove(elementPath);
187 } else {
188 element = new TmfTraceElement(name, resource, this);
b3e4798c 189 addChild(element);
f537c959 190 }
f537c959
PT
191 }
192
193 // Cleanup dangling children from the model
194 for (ITmfProjectModelElement danglingChild : childrenMap.values()) {
195 removeChild(danglingChild);
196 }
8f5221c2 197
8f5221c2 198 /* Update the analysis under this experiment */
9928ddeb 199 super.refreshChildren();
ff7b95a5
GB
200
201 /*
202 * If the experiment is opened, add any analysis that was not added by
203 * the parent if it is available with the experiment
204 */
205 ITmfTrace experiment = getTrace();
206 if (experiment == null) {
207 return;
208 }
5c727157
AM
209
210 /* super.refreshChildren() above should have set this */
211 TmfViewsElement viewsElement = checkNotNull(getChildElementViews());
212
ff7b95a5
GB
213 Map<String, TmfAnalysisElement> analysisMap = new HashMap<>();
214 for (TmfAnalysisElement analysis : getAvailableAnalysis()) {
215 analysisMap.put(analysis.getAnalysisId(), analysis);
216 }
217 for (IAnalysisModuleHelper module : TmfAnalysisManager.getAnalysisModules().values()) {
218 if (!analysisMap.containsKey(module.getId()) && module.appliesToExperiment() && (experiment.getAnalysisModule(module.getId()) != null)) {
b3e4798c 219 IFolder newresource = ResourcesPlugin.getWorkspace().getRoot().getFolder(getResource().getFullPath().append(module.getId()));
5c727157
AM
220 TmfAnalysisElement analysis = new TmfAnalysisElement(module.getName(), newresource, viewsElement, module);
221 viewsElement.addChild(analysis);
ff7b95a5
GB
222 analysis.refreshChildren();
223 analysisMap.put(module.getId(), analysis);
224 }
225 }
f537c959
PT
226 }
227
339d539c
PT
228 private List<IResource> getTraceResources() {
229 IFolder folder = getResource();
230 final List<IResource> list = new ArrayList<>();
231 try {
232 folder.accept(new IResourceProxyVisitor() {
233 @Override
234 public boolean visit(IResourceProxy resource) throws CoreException {
235 if (resource.isLinked()) {
236 list.add(resource.requestResource());
237 }
238 return true;
239 }
240 }, IResource.NONE);
241 } catch (CoreException e) {
242 }
dca8b422
BH
243 Comparator<IResource> comparator = new Comparator<IResource>() {
244 @Override
245 public int compare(IResource o1, IResource o2) {
246 return o1.getFullPath().toString().compareTo(o2.getFullPath().toString());
247 }
248 };
249 Collections.sort(list, comparator);
339d539c
PT
250 return list;
251 }
252
dff70ccd
AM
253 /**
254 * @since 2.0
255 */
256 @Override
257 public @NonNull Image getIcon() {
258 Image icon = super.getIcon();
259 return (icon == null ? TmfProjectModelIcons.DEFAULT_EXPERIMENT_ICON : icon);
260 }
261
262 /**
263 * @since 2.0
264 */
265 @Override
266 public String getLabelText() {
267 return getName() + " [" + getTraces().size() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
268 }
269
12c155f5
FC
270 // ------------------------------------------------------------------------
271 // Operations
272 // ------------------------------------------------------------------------
11252342 273
8f5221c2
GB
274 /**
275 * Refreshes the trace type filed by reading the trace type persistent
276 * property of the resource reference.
277 *
278 * If trace type is null after refresh, set it to the generic trace type
279 * (for seamless upgrade)
280 */
281 @Override
282 public void refreshTraceType() {
283 super.refreshTraceType();
284 if (getTraceType() == null) {
a4a116c3 285 IConfigurationElement ce = TmfTraceType.getTraceAttributes(TmfTraceType.DEFAULT_EXPERIMENT_TYPE);
8f5221c2
GB
286 if (ce != null) {
287 try {
288 IFolder experimentFolder = getResource();
289 experimentFolder.setPersistentProperty(TmfCommonConstants.TRACETYPE, ce.getAttribute(TmfTraceType.ID_ATTR));
290 super.refreshTraceType();
291 } catch (InvalidRegistryObjectException | CoreException e) {
292 }
293 }
294 }
295 }
296
b544077e
BH
297 /**
298 * Returns a list of TmfTraceElements contained in this experiment.
dc62dbee 299 *
b544077e
BH
300 * @return a list of TmfTraceElements
301 */
8f5221c2 302 @Override
12c155f5
FC
303 public List<TmfTraceElement> getTraces() {
304 List<ITmfProjectModelElement> children = getChildren();
507b1336 305 List<TmfTraceElement> traces = new ArrayList<>();
12c155f5
FC
306 for (ITmfProjectModelElement child : children) {
307 if (child instanceof TmfTraceElement) {
308 traces.add((TmfTraceElement) child);
309 }
310 }
311 return traces;
312 }
313
beb19106
GB
314 /**
315 * Adds a trace to the experiment
316 *
dc62dbee
CB
317 * @param trace
318 * The trace element to add
beb19106
GB
319 */
320 public void addTrace(TmfTraceElement trace) {
38dfaec4
BH
321 addTrace(trace, true);
322 }
323
324 /**
325 * Adds a trace to the experiment
326 *
dc62dbee
CB
327 * @param trace
328 * The trace element to add
329 * @param refresh
330 * Flag for refreshing the project
38dfaec4
BH
331 */
332 public void addTrace(TmfTraceElement trace, boolean refresh) {
beb19106
GB
333 /**
334 * Create a link to the actual trace and set the trace type
335 */
336 IFolder experiment = getResource();
337 IResource resource = trace.getResource();
338 IPath location = resource.getLocation();
339 IWorkspace workspace = ResourcesPlugin.getWorkspace();
340 try {
4b3b667b 341 String traceTypeId = TmfTraceType.getTraceTypeId(trace.getResource());
a4a116c3 342 TraceTypeHelper traceType = TmfTraceType.getTraceType(traceTypeId);
beb19106
GB
343
344 if (resource instanceof IFolder) {
339d539c
PT
345 IFolder folder = experiment.getFolder(trace.getElementPath());
346 TraceUtils.createFolder((IFolder) folder.getParent(), new NullProgressMonitor());
977ca87f
PT
347 IStatus result = workspace.validateLinkLocation(folder, location);
348 if (result.isOK() || result.matches(IStatus.INFO | IStatus.WARNING)) {
beb19106 349 folder.createLink(location, IResource.REPLACE, null);
5f398902 350 if (traceType != null) {
38dfaec4 351 TmfTraceTypeUIUtils.setTraceType(folder, traceType, refresh);
5f398902 352 }
beb19106
GB
353
354 } else {
355 Activator.getDefault().logError("Error creating link. Invalid trace location " + location); //$NON-NLS-1$
356 }
357 } else {
339d539c
PT
358 IFile file = experiment.getFile(trace.getElementPath());
359 TraceUtils.createFolder((IFolder) file.getParent(), new NullProgressMonitor());
977ca87f
PT
360 IStatus result = workspace.validateLinkLocation(file, location);
361 if (result.isOK() || result.matches(IStatus.INFO | IStatus.WARNING)) {
beb19106 362 file.createLink(location, IResource.REPLACE, null);
5f398902 363 if (traceType != null) {
38dfaec4 364 TmfTraceTypeUIUtils.setTraceType(file, traceType, refresh);
5f398902 365 }
beb19106
GB
366 } else {
367 Activator.getDefault().logError("Error creating link. Invalid trace location " + location); //$NON-NLS-1$
368 }
369 }
370 } catch (CoreException e) {
371 Activator.getDefault().logError("Error creating link to location " + location, e); //$NON-NLS-1$
372 }
373
374 }
375
376 /**
377 * Removes a trace from an experiment
378 *
dc62dbee
CB
379 * @param trace
380 * The trace to remove
381 * @throws CoreException
382 * exception
beb19106
GB
383 */
384 public void removeTrace(TmfTraceElement trace) throws CoreException {
385
ea01e5a2
PT
386 // Close editors in UI Thread
387 Display.getDefault().syncExec(new Runnable() {
388 @Override
389 public void run() {
390 closeEditors();
391 }
392 });
beb19106 393
dc62dbee 394 /* Finally, remove the trace from experiment */
beb19106 395 removeChild(trace);
339d539c 396 deleteTraceResource(trace.getResource());
d9030b38 397 deleteSupplementaryResources();
beb19106
GB
398 }
399
339d539c
PT
400 private void deleteTraceResource(IResource resource) throws CoreException {
401 resource.delete(true, null);
402 IContainer parent = resource.getParent();
403 // delete empty folders up to the parent experiment folder
404 if (!parent.equals(getResource()) && parent.members().length == 0) {
405 deleteTraceResource(parent);
406 }
407 }
408
8f5221c2 409 @Override
81fe3479 410 public IFile createBookmarksFile() throws CoreException {
58ffe079 411 return createBookmarksFile(getProject().getExperimentsFolder().getResource(), ITmfEventsEditorConstants.EXPERIMENT_EDITOR_INPUT_TYPE);
8f5221c2
GB
412 }
413
414 @Override
415 public String getEditorId() {
416 /* See if a default editor was set for this experiment type */
417 if (getTraceType() != null) {
067cd9de 418 IConfigurationElement ce = TRACE_TYPE_UI_ATTRIBUTES.get(getTraceType());
c1c0dfd0
GB
419 if (ce != null) {
420 IConfigurationElement[] defaultEditorCE = ce.getChildren(TmfTraceTypeUIUtils.DEFAULT_EDITOR_ELEM);
421 if (defaultEditorCE.length == 1) {
422 return defaultEditorCE[0].getAttribute(TmfTraceType.ID_ATTR);
423 }
81fe3479 424 }
c4c81d91 425 }
8f5221c2
GB
426
427 /* No default editor, try to find a common editor for all traces */
428 final List<TmfTraceElement> traceEntries = getTraces();
429 String commonEditorId = null;
430
431 for (TmfTraceElement element : traceEntries) {
432 // If all traces use the same editorId, use it, otherwise use the
433 // default
434 final String editorId = element.getEditorId();
435 if (commonEditorId == null) {
436 commonEditorId = (editorId != null) ? editorId : TmfEventsEditor.ID;
437 } else if (!commonEditorId.equals(editorId)) {
438 commonEditorId = TmfEventsEditor.ID;
439 }
440 }
441 return null;
81fe3479
PT
442 }
443
444 /**
8f5221c2
GB
445 * Instantiate a {@link TmfExperiment} object based on the experiment type
446 * and the corresponding extension.
447 *
448 * @return the {@link TmfExperiment} or <code>null</code> for an error
81fe3479 449 */
8f5221c2
GB
450 @Override
451 public TmfExperiment instantiateTrace() {
452 try {
453
454 // make sure that supplementary folder exists
455 refreshSupplementaryFolder();
456
457 if (getTraceType() != null) {
458
067cd9de 459 IConfigurationElement ce = TRACE_TYPE_ATTRIBUTES.get(getTraceType());
8f5221c2
GB
460 if (ce == null) {
461 return null;
462 }
463 TmfExperiment experiment = (TmfExperiment) ce.createExecutableExtension(TmfTraceType.EXPERIMENT_TYPE_ATTR);
464 return experiment;
465 }
466 } catch (CoreException e) {
467 Activator.getDefault().logError(NLS.bind(Messages.TmfExperimentElement_ErrorInstantiatingTrace, getName()), e);
468 }
469 return null;
470 }
471
472 @Override
473 public String getTypeName() {
474 return Messages.TmfExperimentElement_TypeName;
c4c81d91
PT
475 }
476
12c155f5
FC
477 // ------------------------------------------------------------------------
478 // IPropertySource2
479 // ------------------------------------------------------------------------
480
481 @Override
482 public Object getEditableValue() {
483 return null;
484 }
485
486 @Override
487 public IPropertyDescriptor[] getPropertyDescriptors() {
067cd9de 488 return Arrays.copyOf(DESCRIPTORS, DESCRIPTORS.length);
12c155f5
FC
489 }
490
491 @Override
492 public Object getPropertyValue(Object id) {
493
067cd9de 494 if (NAME.equals(id)) {
12c155f5 495 return getName();
c4c81d91 496 }
12c155f5 497
067cd9de 498 if (PATH.equals(id)) {
12c155f5 499 return getPath().toString();
c4c81d91 500 }
12c155f5 501
067cd9de 502 if (LOCATION.equals(id)) {
12c155f5 503 return getLocation().toString();
c4c81d91 504 }
12c155f5 505
067cd9de 506 if (EXPERIMENT_TYPE.equals(id)) {
8f5221c2 507 if (getTraceType() != null) {
067cd9de 508 IConfigurationElement ce = TRACE_TYPE_ATTRIBUTES.get(getTraceType());
8f5221c2
GB
509 if (ce == null) {
510 return ""; //$NON-NLS-1$
511 }
512 String categoryId = ce.getAttribute(TmfTraceType.CATEGORY_ATTR);
513 if (categoryId != null) {
067cd9de 514 IConfigurationElement category = TRACE_CATEGORIES.get(categoryId);
8f5221c2
GB
515 if (category != null) {
516 return category.getAttribute(TmfTraceType.NAME_ATTR) + ':' + ce.getAttribute(TmfTraceType.NAME_ATTR);
517 }
518 }
519 return ce.getAttribute(TmfTraceType.NAME_ATTR);
520 }
521 }
522
12c155f5
FC
523 return null;
524 }
c4c81d91 525
12c155f5
FC
526 @Override
527 public void resetPropertyValue(Object id) {
528 }
529
530 @Override
531 public void setPropertyValue(Object id, Object value) {
532 }
533
534 @Override
535 public boolean isPropertyResettable(Object id) {
536 return false;
537 }
538
539 @Override
540 public boolean isPropertySet(Object id) {
541 return false;
542 }
543
99504bb8
GB
544 /**
545 * Return the suffix for resource names
dc62dbee 546 *
99504bb8
GB
547 * @return The folder suffix
548 */
549 @Override
550 public String getSuffix() {
067cd9de 551 return FOLDER_SUFFIX;
99504bb8
GB
552 }
553
12c155f5 554}
This page took 0.162828 seconds and 5 git commands to generate.