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