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 / TmfCommonProjectElement.java
CommitLineData
99504bb8 1/*******************************************************************************
58ffe079 2 * Copyright (c) 2010, 2015 Ericsson, École Polytechnique de Montréal
99504bb8
GB
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 * Bernd Hufmann - Added supplementary files handling (in class TmfTraceElement)
11 * Geneviève Bastien - Copied supplementary files handling from TmfTracElement
16036bc2
GB
12 * Moved to this class code to copy a model element
13 * Renamed from TmfWithFolderElement to TmfCommonProjectElement
339d539c 14 * Patrick Tasse - Add support for folder elements
99504bb8
GB
15 *******************************************************************************/
16
2bdf0193 17package org.eclipse.tracecompass.tmf.ui.project.model;
99504bb8 18
dff70ccd
AM
19import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
20
8f5221c2
GB
21import java.io.ByteArrayInputStream;
22import java.io.InputStream;
23import java.util.ArrayList;
8f5221c2 24import java.util.List;
5c727157 25import java.util.stream.Collectors;
8f5221c2 26
339d539c 27import org.eclipse.core.resources.IContainer;
8f5221c2 28import org.eclipse.core.resources.IFile;
99504bb8
GB
29import org.eclipse.core.resources.IFolder;
30import org.eclipse.core.resources.IResource;
8f5221c2 31import org.eclipse.core.resources.ResourcesPlugin;
99504bb8 32import org.eclipse.core.runtime.CoreException;
dff70ccd 33import org.eclipse.core.runtime.IConfigurationElement;
beb19106 34import org.eclipse.core.runtime.IPath;
99504bb8 35import org.eclipse.core.runtime.NullProgressMonitor;
339d539c 36import org.eclipse.core.runtime.Path;
dff70ccd 37import org.eclipse.core.runtime.Platform;
367e2932 38import org.eclipse.jdt.annotation.NonNull;
8f5221c2 39import org.eclipse.osgi.util.NLS;
dff70ccd 40import org.eclipse.swt.graphics.Image;
2bdf0193 41import org.eclipse.tracecompass.internal.tmf.ui.Activator;
3d04a314 42import org.eclipse.tracecompass.internal.tmf.ui.editors.ITmfEventsEditorConstants;
2bdf0193 43import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
2bdf0193 44import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType;
dff70ccd 45import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType.TraceElementType;
2bdf0193
AM
46import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
47import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
48import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
49import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
2bdf0193 50import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
8f5221c2
GB
51import org.eclipse.ui.IEditorReference;
52import org.eclipse.ui.IWorkbench;
53import org.eclipse.ui.IWorkbenchPage;
54import org.eclipse.ui.IWorkbenchWindow;
55import org.eclipse.ui.PartInitException;
56import org.eclipse.ui.PlatformUI;
57import org.eclipse.ui.part.FileEditorInput;
dff70ccd 58import org.osgi.framework.Bundle;
99504bb8 59
99504bb8 60/**
16036bc2
GB
61 * Base class for tracing project elements: it implements the common behavior of
62 * all project elements: supplementary files, analysis, types, etc.
99504bb8 63 *
e73a4ba5 64 * @author Geneviève Bastien
99504bb8 65 */
16036bc2 66public abstract class TmfCommonProjectElement extends TmfProjectModelElement {
99504bb8 67
8f5221c2
GB
68 // ------------------------------------------------------------------------
69 // Attributes
70 // ------------------------------------------------------------------------
71
8f5221c2
GB
72 private static final String BOOKMARKS_HIDDEN_FILE = ".bookmarks"; //$NON-NLS-1$
73
5c727157
AM
74 private TmfViewsElement fViewsElement = null;
75
76 /** This trace type ID as defined in plugin.xml */
77 private String fTraceTypeId = null;
78
99504bb8
GB
79 // ------------------------------------------------------------------------
80 // Constructors
81 // ------------------------------------------------------------------------
82
99504bb8 83 /**
16036bc2
GB
84 * Constructor. Creates model element.
85 *
86 * @param name
87 * The name of the element
88 * @param resource
89 * The resource.
90 * @param parent
91 * The parent element
99504bb8 92 */
16036bc2 93 public TmfCommonProjectElement(String name, IResource resource, TmfProjectModelElement parent) {
99504bb8 94 super(name, resource, parent);
8f5221c2
GB
95 refreshTraceType();
96 TmfSignalManager.register(this);
97 }
98
99 // ------------------------------------------------------------------------
100 // TmfProjectModelElement
101 // ------------------------------------------------------------------------
102
b3e4798c
AM
103 /**
104 * @since 2.0
105 */
8f5221c2 106 @Override
b3e4798c 107 protected void refreshChildren() {
5c727157
AM
108 /* Get the base path to put the resource to */
109 IPath tracePath = getResource().getFullPath();
110
111 if (fViewsElement == null) {
112 /* Add the "Views" node */
113 IFolder viewsNodeRes = ResourcesPlugin.getWorkspace().getRoot().getFolder(tracePath.append(TmfViewsElement.PATH_ELEMENT));
114 fViewsElement = new TmfViewsElement(viewsNodeRes, this);
115 addChild(fViewsElement);
8f5221c2 116 }
5c727157 117 fViewsElement.refreshChildren();
8f5221c2
GB
118 }
119
dff70ccd
AM
120 /**
121 * @since 2.0
122 */
123 @Override
124 public Image getIcon() {
125 String traceType = getTraceType();
126 if (traceType == null || TmfTraceType.getTraceType(traceType) == null) {
127 // request the label to the Eclipse platform
128 Image icon = TmfProjectModelIcons.WORKSPACE_LABEL_PROVIDER.getImage(getResource());
129 return (icon == null ? TmfProjectModelIcons.DEFAULT_TRACE_ICON : icon);
130 }
131
132 IConfigurationElement traceUIAttributes = TmfTraceTypeUIUtils.getTraceUIAttributes(traceType,
133 (this instanceof TmfTraceElement) ? TraceElementType.TRACE : TraceElementType.EXPERIMENT);
134 if (traceUIAttributes != null) {
135 String iconAttr = traceUIAttributes.getAttribute(TmfTraceTypeUIUtils.ICON_ATTR);
136 if (iconAttr != null) {
137 String name = traceUIAttributes.getContributor().getName();
138 if (name != null) {
139 Bundle bundle = Platform.getBundle(name);
140 if (bundle != null) {
141 Image image = TmfProjectModelIcons.loadIcon(bundle, iconAttr);
142 if (image != null) {
143 return image;
144 }
145 }
146 }
147 }
148 }
149 /* Let subclasses specify an icon */
150 return null;
151 }
152
8f5221c2
GB
153 // ------------------------------------------------------------------------
154 // Operations
155 // ------------------------------------------------------------------------
156
5c727157
AM
157 /**
158 * Get the child element "Views". There should always be one.
159 *
160 * @return The child element
161 * @since 2.0
162 */
163 protected TmfViewsElement getChildElementViews() {
164 return fViewsElement;
165 }
166
8f5221c2
GB
167 /**
168 * Returns the trace type ID.
169 *
170 * @return trace type ID.
171 */
172 public String getTraceType() {
173 return fTraceTypeId;
174 }
175
176 /**
4b3b667b
PT
177 * Refreshes the trace type field by reading the trace type persistent
178 * property of the resource.
8f5221c2
GB
179 */
180 public void refreshTraceType() {
181 try {
4b3b667b 182 fTraceTypeId = TmfTraceType.getTraceTypeId(getResource());
8f5221c2
GB
183 } catch (CoreException e) {
184 Activator.getDefault().logError(NLS.bind(Messages.TmfCommonProjectElement_ErrorRefreshingProperty, getName()), e);
185 }
99504bb8
GB
186 }
187
8f5221c2
GB
188 /**
189 * Instantiate a <code>ITmfTrace</code> object based on the trace type and
190 * the corresponding extension.
191 *
192 * @return the <code>ITmfTrace</code> or <code>null</code> for an error
193 */
194 public abstract ITmfTrace instantiateTrace();
195
99504bb8 196 /**
339d539c
PT
197 * Return the supplementary folder path for this element. The returned path
198 * is relative to the project's supplementary folder.
99504bb8 199 *
339d539c 200 * @return The supplementary folder path for this element
99504bb8 201 */
339d539c
PT
202 protected String getSupplementaryFolderPath() {
203 return getElementPath() + getSuffix();
99504bb8
GB
204 }
205
206 /**
339d539c
PT
207 * Return the element path relative to its common element (traces folder,
208 * experiments folder or experiment element).
e9e2c5ee 209 *
339d539c
PT
210 * @return The element path
211 */
dff70ccd 212 public @NonNull String getElementPath() {
339d539c
PT
213 ITmfProjectModelElement parent = getParent();
214 while (!(parent instanceof TmfTracesFolder || parent instanceof TmfExperimentElement || parent instanceof TmfExperimentFolder)) {
215 parent = parent.getParent();
216 }
b3e4798c 217 IPath path = getResource().getFullPath().makeRelativeTo(parent.getPath());
dff70ccd 218 return checkNotNull(path.toString());
339d539c
PT
219 }
220
221 /**
222 * @return The suffix for the supplementary folder
99504bb8
GB
223 */
224 protected String getSuffix() {
225 return ""; //$NON-NLS-1$
226 }
227
8f5221c2
GB
228 /**
229 * Returns a list of TmfTraceElements contained in project element.
230 *
231 * @return a list of TmfTraceElements, empty list if none
232 */
233 public List<TmfTraceElement> getTraces() {
234 return new ArrayList<>();
235 }
236
237 /**
238 * Get the instantiated trace associated with this element.
239 *
240 * @return The instantiated trace or null if trace is not (yet) available
241 */
242 public ITmfTrace getTrace() {
243 for (ITmfTrace trace : TmfTraceManager.getInstance().getOpenedTraces()) {
244 if (trace.getResource().equals(getResource())) {
245 return trace;
246 }
247 }
248 return null;
249 }
250
251 /**
252 * Returns the file resource used to store bookmarks after creating it if
253 * necessary. If the trace resource is a file, it is returned directly. If
254 * the trace resource is a folder, a linked file is returned. The file will
255 * be created if it does not exist.
256 *
257 * @return the bookmarks file
258 * @throws CoreException
259 * if the bookmarks file cannot be created
260 */
261 public abstract IFile createBookmarksFile() throws CoreException;
262
263 /**
264 * Actually returns the bookmark file or creates it in the project element's
265 * folder
266 *
267 * @param bookmarksFolder
268 * Folder where to put the bookmark file
58ffe079
MAL
269 * @param editorInputType
270 * The editor input type to set (trace or experiment)
8f5221c2
GB
271 * @return The bookmark file
272 * @throws CoreException
273 * if the bookmarks file cannot be created
274 */
58ffe079 275 protected IFile createBookmarksFile(IFolder bookmarksFolder, String editorInputType) throws CoreException {
8f5221c2
GB
276 IFile file = getBookmarksFile();
277 if (!file.exists()) {
278 final IFile bookmarksFile = bookmarksFolder.getFile(BOOKMARKS_HIDDEN_FILE);
279 if (!bookmarksFile.exists()) {
280 final InputStream source = new ByteArrayInputStream(new byte[0]);
858a35cf 281 bookmarksFile.create(source, IResource.FORCE | IResource.HIDDEN, null);
8f5221c2 282 }
858a35cf 283 file.createLink(bookmarksFile.getLocation(), IResource.REPLACE | IResource.HIDDEN, null);
58ffe079 284 file.setPersistentProperty(TmfCommonConstants.TRACETYPE, editorInputType);
8f5221c2
GB
285 }
286 return file;
287 }
288
289 /**
290 * Returns the optional editor ID from the trace type extension.
291 *
292 * @return the editor ID or <code>null</code> if not defined.
293 */
294 public abstract String getEditorId();
295
296 /**
297 * Returns the file resource used to store bookmarks. The file may not
298 * exist.
299 *
300 * @return the bookmarks file
301 */
302 public IFile getBookmarksFile() {
b3e4798c 303 final IFolder folder = (IFolder) getResource();
8f5221c2
GB
304 IFile file = folder.getFile(getName() + '_');
305 return file;
306 }
307
308 /**
309 * Close open editors associated with this experiment.
310 */
311 public void closeEditors() {
312 IFile file = getBookmarksFile();
313 FileEditorInput input = new FileEditorInput(file);
314 IWorkbench wb = PlatformUI.getWorkbench();
315 for (IWorkbenchWindow wbWindow : wb.getWorkbenchWindows()) {
316 for (IWorkbenchPage wbPage : wbWindow.getPages()) {
317 for (IEditorReference editorReference : wbPage.getEditorReferences()) {
318 try {
319 if (editorReference.getEditorInput().equals(input)) {
320 wbPage.closeEditor(editorReference.getEditor(false), false);
321 }
322 } catch (PartInitException e) {
323 Activator.getDefault().logError(NLS.bind(Messages.TmfCommonProjectElement_ErrorClosingEditor, getName()), e);
324 }
325 }
326 }
327 }
328 }
329
330 /**
331 * Get a friendly name for the type of element this common project element
332 * is, to be displayed in UI messages.
333 *
334 * @return A string for the type of project element this object is, for
335 * example "trace" or "experiment"
336 */
337 public abstract String getTypeName();
338
339 /**
340 * Copy this model element
341 *
342 * @param newName
343 * The name of the new element
344 * @param copySuppFiles
345 * Whether to copy supplementary files or not
346 * @return the new Resource object
347 */
348 public IResource copy(final String newName, final boolean copySuppFiles) {
349
350 final IPath newPath = getParent().getResource().getFullPath().addTrailingSeparator().append(newName);
351
352 /* Copy supplementary files first, only if needed */
353 if (copySuppFiles) {
339d539c
PT
354 String newElementPath = new Path(getElementPath()).removeLastSegments(1).append(newName).toString();
355 copySupplementaryFolder(newElementPath);
8f5221c2
GB
356 }
357 /* Copy the trace */
358 try {
359 getResource().copy(newPath, IResource.FORCE | IResource.SHALLOW, null);
e9e2c5ee 360 IResource trace = ((IFolder) getParent().getResource()).findMember(newName);
8f5221c2
GB
361
362 /* Delete any bookmarks file found in copied trace folder */
e9e2c5ee
MK
363 if (trace instanceof IFolder) {
364 IFolder folderTrace = (IFolder) trace;
365 for (IResource member : folderTrace.members()) {
4b3b667b 366 String traceTypeId = TmfTraceType.getTraceTypeId(member);
3d04a314 367 if (ITmfEventsEditorConstants.TRACE_INPUT_TYPE_CONSTANTS.contains(traceTypeId)) {
8f5221c2 368 member.delete(true, null);
3d04a314 369 } else if (ITmfEventsEditorConstants.EXPERIMENT_INPUT_TYPE_CONSTANTS.contains(traceTypeId)) {
8f5221c2
GB
370 member.delete(true, null);
371 }
372 }
373 }
e9e2c5ee 374 return trace;
8f5221c2
GB
375 } catch (CoreException e) {
376
377 }
378 return null;
379 }
380
381 /**
382 * Get the list of analysis elements
383 *
384 * @return Array of analysis elements
385 */
386 public List<TmfAnalysisElement> getAvailableAnalysis() {
5c727157
AM
387 return getChildElementViews().getChildren().stream()
388 .map(elem -> (TmfAnalysisElement) elem)
389 .collect(Collectors.toList());
8f5221c2
GB
390 }
391
16036bc2
GB
392 // ------------------------------------------------------------------------
393 // Supplementary files operations
394 // ------------------------------------------------------------------------
395
99504bb8
GB
396 /**
397 * Deletes this element specific supplementary folder.
398 */
399 public void deleteSupplementaryFolder() {
339d539c
PT
400 IFolder supplFolder = getTraceSupplementaryFolder(getSupplementaryFolderPath());
401 try {
402 deleteFolder(supplFolder);
403 } catch (CoreException e) {
404 Activator.getDefault().logError("Error deleting supplementary folder " + supplFolder, e); //$NON-NLS-1$
405 }
406 }
407
408 private static void deleteFolder(IFolder folder) throws CoreException {
409 if (folder.exists()) {
410 folder.delete(true, new NullProgressMonitor());
411 }
412 IContainer parent = folder.getParent();
413 // delete empty folders up to the parent project
414 if (parent instanceof IFolder && (!parent.exists() || parent.members().length == 0)) {
415 deleteFolder((IFolder) parent);
99504bb8
GB
416 }
417 }
418
419 /**
16036bc2 420 * Renames the element specific supplementary folder according to the new
339d539c 421 * element name or path.
99504bb8 422 *
339d539c
PT
423 * @param newElementPath
424 * The new element name or path
99504bb8 425 */
339d539c
PT
426 public void renameSupplementaryFolder(String newElementPath) {
427 IFolder oldSupplFolder = getTraceSupplementaryFolder(getSupplementaryFolderPath());
99504bb8
GB
428
429 // Rename supplementary folder
339d539c
PT
430 try {
431 if (oldSupplFolder.exists()) {
432 IFolder newSupplFolder = prepareTraceSupplementaryFolder(newElementPath + getSuffix(), false);
99504bb8 433 oldSupplFolder.move(newSupplFolder.getFullPath(), true, new NullProgressMonitor());
99504bb8 434 }
339d539c
PT
435 deleteFolder(oldSupplFolder);
436 } catch (CoreException e) {
437 Activator.getDefault().logError("Error renaming supplementary folder " + oldSupplFolder, e); //$NON-NLS-1$
99504bb8
GB
438 }
439 }
440
441 /**
339d539c
PT
442 * Copies the element specific supplementary folder to the new element name
443 * or path.
99504bb8 444 *
339d539c
PT
445 * @param newElementPath
446 * The new element name or path
99504bb8 447 */
339d539c
PT
448 public void copySupplementaryFolder(String newElementPath) {
449 IFolder oldSupplFolder = getTraceSupplementaryFolder(getSupplementaryFolderPath());
99504bb8
GB
450
451 // copy supplementary folder
452 if (oldSupplFolder.exists()) {
453 try {
339d539c 454 IFolder newSupplFolder = prepareTraceSupplementaryFolder(newElementPath + getSuffix(), false);
99504bb8
GB
455 oldSupplFolder.copy(newSupplFolder.getFullPath(), true, new NullProgressMonitor());
456 } catch (CoreException e) {
457 Activator.getDefault().logError("Error renaming supplementary folder " + oldSupplFolder, e); //$NON-NLS-1$
458 }
459 }
460 }
461
462 /**
463 * Copies the element specific supplementary folder a new folder.
464 *
16036bc2
GB
465 * @param destination
466 * The destination folder to copy to.
99504bb8
GB
467 */
468 public void copySupplementaryFolder(IFolder destination) {
339d539c 469 IFolder oldSupplFolder = getTraceSupplementaryFolder(getSupplementaryFolderPath());
99504bb8
GB
470
471 // copy supplementary folder
472 if (oldSupplFolder.exists()) {
473 try {
c2f1c5b6 474 TraceUtils.createFolder((IFolder) destination.getParent(), new NullProgressMonitor());
99504bb8
GB
475 oldSupplFolder.copy(destination.getFullPath(), true, new NullProgressMonitor());
476 } catch (CoreException e) {
477 Activator.getDefault().logError("Error copying supplementary folder " + oldSupplFolder, e); //$NON-NLS-1$
478 }
479 }
480 }
481
99504bb8 482 /**
16036bc2
GB
483 * Refreshes the element specific supplementary folder information. It
484 * creates the folder if not exists. It sets the persistence property of the
485 * trace resource
99504bb8
GB
486 */
487 public void refreshSupplementaryFolder() {
6b44794a
MK
488 IFolder supplFolder = createSupplementaryFolder();
489 try {
490 supplFolder.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
491 } catch (CoreException e) {
492 Activator.getDefault().logError("Error refreshing supplementary folder " + supplFolder, e); //$NON-NLS-1$
493 }
99504bb8
GB
494 }
495
496 /**
497 * Checks if supplementary resource exist or not.
498 *
16036bc2
GB
499 * @return <code>true</code> if one or more files are under the element
500 * supplementary folder
99504bb8
GB
501 */
502 public boolean hasSupplementaryResources() {
503 IResource[] resources = getSupplementaryResources();
504 return (resources.length > 0);
505 }
506
507 /**
508 * Returns the supplementary resources under the trace supplementary folder.
509 *
510 * @return array of resources under the trace supplementary folder.
511 */
512 public IResource[] getSupplementaryResources() {
339d539c 513 IFolder supplFolder = getTraceSupplementaryFolder(getSupplementaryFolderPath());
99504bb8
GB
514 if (supplFolder.exists()) {
515 try {
516 return supplFolder.members();
517 } catch (CoreException e) {
518 Activator.getDefault().logError("Error deleting supplementary folder " + supplFolder, e); //$NON-NLS-1$
519 }
520 }
521 return new IResource[0];
522 }
523
524 /**
525 * Deletes the given resources.
526 *
16036bc2
GB
527 * @param resources
528 * array of resources to delete.
99504bb8
GB
529 */
530 public void deleteSupplementaryResources(IResource[] resources) {
531
532 for (int i = 0; i < resources.length; i++) {
533 try {
534 resources[i].delete(true, new NullProgressMonitor());
535 } catch (CoreException e) {
536 Activator.getDefault().logError("Error deleting supplementary resource " + resources[i], e); //$NON-NLS-1$
537 }
538 }
539 }
540
4726e963
BH
541 /**
542 * Deletes all supplementary resources in the supplementary directory
543 */
544 public void deleteSupplementaryResources() {
545 deleteSupplementaryResources(getSupplementaryResources());
546 }
547
6b44794a 548 private IFolder createSupplementaryFolder() {
339d539c 549 IFolder supplFolder = prepareTraceSupplementaryFolder(getSupplementaryFolderPath(), true);
99504bb8
GB
550
551 try {
b3e4798c 552 getResource().setPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER, supplFolder.getLocation().toOSString());
99504bb8
GB
553 } catch (CoreException e) {
554 Activator.getDefault().logError("Error setting persistant property " + TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER, e); //$NON-NLS-1$
555 }
6b44794a 556 return supplFolder;
99504bb8
GB
557 }
558
8f5221c2
GB
559 // -------------------------------------------------------
560 // Signal handlers
561 // -------------------------------------------------------
16036bc2 562
beb19106 563 /**
8f5221c2 564 * Handler for the Trace Opened signal
beb19106 565 *
8f5221c2
GB
566 * @param signal
567 * The incoming signal
beb19106 568 */
8f5221c2
GB
569 @TmfSignalHandler
570 public void traceOpened(TmfTraceOpenedSignal signal) {
571 IResource resource = signal.getTrace().getResource();
572 if ((resource == null) || !resource.equals(getResource())) {
573 return;
beb19106 574 }
beb19106 575
8f5221c2 576 getParent().refresh();
beb19106
GB
577 }
578
99504bb8 579}
This page took 0.115712 seconds and 5 git commands to generate.