1 /*******************************************************************************
2 * Copyright (c) 2010, 2015 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 * Bernd Hufmann - Added supplementary files handling (in class TmfTraceElement)
11 * Geneviève Bastien - Copied supplementary files handling from TmfTracElement
12 * Moved to this class code to copy a model element
13 * Renamed from TmfWithFolderElement to TmfCommonProjectElement
14 * Patrick Tasse - Add support for folder elements
15 *******************************************************************************/
17 package org
.eclipse
.tracecompass
.tmf
.ui
.project
.model
;
19 import java
.io
.ByteArrayInputStream
;
20 import java
.io
.InputStream
;
21 import java
.util
.ArrayList
;
22 import java
.util
.HashMap
;
23 import java
.util
.List
;
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
.ResourcesPlugin
;
31 import org
.eclipse
.core
.runtime
.CoreException
;
32 import org
.eclipse
.core
.runtime
.IPath
;
33 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
34 import org
.eclipse
.core
.runtime
.Path
;
35 import org
.eclipse
.jdt
.annotation
.NonNull
;
36 import org
.eclipse
.osgi
.util
.NLS
;
37 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
38 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.editors
.ITmfEventsEditorConstants
;
39 import org
.eclipse
.tracecompass
.tmf
.core
.TmfCommonConstants
;
40 import org
.eclipse
.tracecompass
.tmf
.core
.analysis
.IAnalysisModuleHelper
;
41 import org
.eclipse
.tracecompass
.tmf
.core
.analysis
.TmfAnalysisManager
;
42 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TmfTraceType
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.project
.model
.TraceTypeHelper
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalManager
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
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
;
58 * Base class for tracing project elements: it implements the common behavior of
59 * all project elements: supplementary files, analysis, types, etc.
61 * @author Geneviève Bastien
63 public abstract class TmfCommonProjectElement
extends TmfProjectModelElement
{
65 // ------------------------------------------------------------------------
67 // ------------------------------------------------------------------------
69 // This trace type ID as defined in plugin.xml
70 private String fTraceTypeId
= null;
72 private static final String BOOKMARKS_HIDDEN_FILE
= ".bookmarks"; //$NON-NLS-1$
74 // ------------------------------------------------------------------------
76 // ------------------------------------------------------------------------
79 * Constructor. Creates model element.
82 * The name of the element
88 public TmfCommonProjectElement(String name
, IResource resource
, TmfProjectModelElement parent
) {
89 super(name
, resource
, parent
);
90 parent
.addChild(this);
92 TmfSignalManager
.register(this);
95 // ------------------------------------------------------------------------
96 // TmfProjectModelElement
97 // ------------------------------------------------------------------------
100 void refreshChildren() {
102 /* Refreshes the analysis under this trace */
103 Map
<String
, TmfAnalysisElement
> childrenMap
= new HashMap
<>();
104 for (TmfAnalysisElement analysis
: getAvailableAnalysis()) {
105 childrenMap
.put(analysis
.getAnalysisId(), analysis
);
108 TraceTypeHelper helper
= TmfTraceType
.getTraceType(getTraceType());
110 Class
<@NonNull ?
extends ITmfTrace
> traceClass
= null;
112 if (helper
!= null) {
113 traceClass
= helper
.getTraceClass();
116 /* Remove all analysis and return */
117 if (traceClass
== null) {
118 for (TmfAnalysisElement analysis
: childrenMap
.values()) {
119 removeChild(analysis
);
124 /** Get the base path to put the resource to */
125 IPath path
= fResource
.getFullPath();
127 /* Add all new analysis modules or refresh outputs of existing ones */
128 for (IAnalysisModuleHelper module
: TmfAnalysisManager
.getAnalysisModules(traceClass
).values()) {
130 /* If the analysis is not a child of the trace, create it */
131 TmfAnalysisElement analysis
= childrenMap
.remove(module
.getId());
132 if (analysis
== null) {
134 * No need for the resource to exist, nothing will be done with
137 IFolder newresource
= ResourcesPlugin
.getWorkspace().getRoot().getFolder(path
.append(module
.getId()));
138 analysis
= new TmfAnalysisElement(module
.getName(), newresource
, this, module
);
140 analysis
.refreshChildren();
143 /* Remove analysis that are not children of this trace anymore */
144 for (TmfAnalysisElement analysis
: childrenMap
.values()) {
145 removeChild(analysis
);
149 // ------------------------------------------------------------------------
151 // ------------------------------------------------------------------------
154 * Returns the trace type ID.
156 * @return trace type ID.
158 public String
getTraceType() {
163 * Refreshes the trace type field by reading the trace type persistent
164 * property of the resource.
166 public void refreshTraceType() {
168 fTraceTypeId
= TmfTraceType
.getTraceTypeId(getResource());
169 } catch (CoreException e
) {
170 Activator
.getDefault().logError(NLS
.bind(Messages
.TmfCommonProjectElement_ErrorRefreshingProperty
, getName()), e
);
175 * Instantiate a <code>ITmfTrace</code> object based on the trace type and
176 * the corresponding extension.
178 * @return the <code>ITmfTrace</code> or <code>null</code> for an error
180 public abstract ITmfTrace
instantiateTrace();
183 * Return the supplementary folder path for this element. The returned path
184 * is relative to the project's supplementary folder.
186 * @return The supplementary folder path for this element
188 protected String
getSupplementaryFolderPath() {
189 return getElementPath() + getSuffix();
193 * Return the element path relative to its common element (traces folder,
194 * experiments folder or experiment element).
196 * @return The element path
198 public String
getElementPath() {
199 ITmfProjectModelElement parent
= getParent();
200 while (!(parent
instanceof TmfTracesFolder
|| parent
instanceof TmfExperimentElement
|| parent
instanceof TmfExperimentFolder
)) {
201 parent
= parent
.getParent();
203 IPath path
= fResource
.getFullPath().makeRelativeTo(parent
.getPath());
204 return path
.toString();
208 * @return The suffix for the supplementary folder
210 protected String
getSuffix() {
211 return ""; //$NON-NLS-1$
215 * Returns a list of TmfTraceElements contained in project element.
217 * @return a list of TmfTraceElements, empty list if none
219 public List
<TmfTraceElement
> getTraces() {
220 return new ArrayList
<>();
224 * Get the instantiated trace associated with this element.
226 * @return The instantiated trace or null if trace is not (yet) available
228 public ITmfTrace
getTrace() {
229 for (ITmfTrace trace
: TmfTraceManager
.getInstance().getOpenedTraces()) {
230 if (trace
.getResource().equals(getResource())) {
238 * Returns the file resource used to store bookmarks after creating it if
239 * necessary. If the trace resource is a file, it is returned directly. If
240 * the trace resource is a folder, a linked file is returned. The file will
241 * be created if it does not exist.
243 * @return the bookmarks file
244 * @throws CoreException
245 * if the bookmarks file cannot be created
247 public abstract IFile
createBookmarksFile() throws CoreException
;
250 * Actually returns the bookmark file or creates it in the project element's
253 * @param bookmarksFolder
254 * Folder where to put the bookmark file
255 * @param editorInputType
256 * The editor input type to set (trace or experiment)
257 * @return The bookmark file
258 * @throws CoreException
259 * if the bookmarks file cannot be created
261 protected IFile
createBookmarksFile(IFolder bookmarksFolder
, String editorInputType
) throws CoreException
{
262 IFile file
= getBookmarksFile();
263 if (!file
.exists()) {
264 final IFile bookmarksFile
= bookmarksFolder
.getFile(BOOKMARKS_HIDDEN_FILE
);
265 if (!bookmarksFile
.exists()) {
266 final InputStream source
= new ByteArrayInputStream(new byte[0]);
267 bookmarksFile
.create(source
, IResource
.FORCE
| IResource
.HIDDEN
, null);
269 file
.createLink(bookmarksFile
.getLocation(), IResource
.REPLACE
| IResource
.HIDDEN
, null);
270 file
.setPersistentProperty(TmfCommonConstants
.TRACETYPE
, editorInputType
);
276 * Returns the optional editor ID from the trace type extension.
278 * @return the editor ID or <code>null</code> if not defined.
280 public abstract String
getEditorId();
283 * Returns the file resource used to store bookmarks. The file may not
286 * @return the bookmarks file
288 public IFile
getBookmarksFile() {
289 final IFolder folder
= (IFolder
) fResource
;
290 IFile file
= folder
.getFile(getName() + '_');
295 * Close open editors associated with this experiment.
297 public void closeEditors() {
298 IFile file
= getBookmarksFile();
299 FileEditorInput input
= new FileEditorInput(file
);
300 IWorkbench wb
= PlatformUI
.getWorkbench();
301 for (IWorkbenchWindow wbWindow
: wb
.getWorkbenchWindows()) {
302 for (IWorkbenchPage wbPage
: wbWindow
.getPages()) {
303 for (IEditorReference editorReference
: wbPage
.getEditorReferences()) {
305 if (editorReference
.getEditorInput().equals(input
)) {
306 wbPage
.closeEditor(editorReference
.getEditor(false), false);
308 } catch (PartInitException e
) {
309 Activator
.getDefault().logError(NLS
.bind(Messages
.TmfCommonProjectElement_ErrorClosingEditor
, getName()), e
);
317 * Get a friendly name for the type of element this common project element
318 * is, to be displayed in UI messages.
320 * @return A string for the type of project element this object is, for
321 * example "trace" or "experiment"
323 public abstract String
getTypeName();
326 * Copy this model element
329 * The name of the new element
330 * @param copySuppFiles
331 * Whether to copy supplementary files or not
332 * @return the new Resource object
334 public IResource
copy(final String newName
, final boolean copySuppFiles
) {
336 final IPath newPath
= getParent().getResource().getFullPath().addTrailingSeparator().append(newName
);
338 /* Copy supplementary files first, only if needed */
340 String newElementPath
= new Path(getElementPath()).removeLastSegments(1).append(newName
).toString();
341 copySupplementaryFolder(newElementPath
);
345 getResource().copy(newPath
, IResource
.FORCE
| IResource
.SHALLOW
, null);
346 IResource trace
= ((IFolder
) getParent().getResource()).findMember(newName
);
348 /* Delete any bookmarks file found in copied trace folder */
349 if (trace
instanceof IFolder
) {
350 IFolder folderTrace
= (IFolder
) trace
;
351 for (IResource member
: folderTrace
.members()) {
352 String traceTypeId
= TmfTraceType
.getTraceTypeId(member
);
353 if (ITmfEventsEditorConstants
.TRACE_INPUT_TYPE_CONSTANTS
.contains(traceTypeId
)) {
354 member
.delete(true, null);
355 } else if (ITmfEventsEditorConstants
.EXPERIMENT_INPUT_TYPE_CONSTANTS
.contains(traceTypeId
)) {
356 member
.delete(true, null);
361 } catch (CoreException e
) {
368 * Get the list of analysis elements
370 * @return Array of analysis elements
372 public List
<TmfAnalysisElement
> getAvailableAnalysis() {
373 List
<ITmfProjectModelElement
> children
= getChildren();
374 List
<TmfAnalysisElement
> analysis
= new ArrayList
<>();
375 for (ITmfProjectModelElement child
: children
) {
376 if (child
instanceof TmfAnalysisElement
) {
377 analysis
.add((TmfAnalysisElement
) child
);
383 // ------------------------------------------------------------------------
384 // Supplementary files operations
385 // ------------------------------------------------------------------------
388 * Deletes this element specific supplementary folder.
390 public void deleteSupplementaryFolder() {
391 IFolder supplFolder
= getTraceSupplementaryFolder(getSupplementaryFolderPath());
393 deleteFolder(supplFolder
);
394 } catch (CoreException e
) {
395 Activator
.getDefault().logError("Error deleting supplementary folder " + supplFolder
, e
); //$NON-NLS-1$
399 private static void deleteFolder(IFolder folder
) throws CoreException
{
400 if (folder
.exists()) {
401 folder
.delete(true, new NullProgressMonitor());
403 IContainer parent
= folder
.getParent();
404 // delete empty folders up to the parent project
405 if (parent
instanceof IFolder
&& (!parent
.exists() || parent
.members().length
== 0)) {
406 deleteFolder((IFolder
) parent
);
411 * Renames the element specific supplementary folder according to the new
412 * element name or path.
414 * @param newElementPath
415 * The new element name or path
417 public void renameSupplementaryFolder(String newElementPath
) {
418 IFolder oldSupplFolder
= getTraceSupplementaryFolder(getSupplementaryFolderPath());
420 // Rename supplementary folder
422 if (oldSupplFolder
.exists()) {
423 IFolder newSupplFolder
= prepareTraceSupplementaryFolder(newElementPath
+ getSuffix(), false);
424 oldSupplFolder
.move(newSupplFolder
.getFullPath(), true, new NullProgressMonitor());
426 deleteFolder(oldSupplFolder
);
427 } catch (CoreException e
) {
428 Activator
.getDefault().logError("Error renaming supplementary folder " + oldSupplFolder
, e
); //$NON-NLS-1$
433 * Copies the element specific supplementary folder to the new element name
436 * @param newElementPath
437 * The new element name or path
439 public void copySupplementaryFolder(String newElementPath
) {
440 IFolder oldSupplFolder
= getTraceSupplementaryFolder(getSupplementaryFolderPath());
442 // copy supplementary folder
443 if (oldSupplFolder
.exists()) {
445 IFolder newSupplFolder
= prepareTraceSupplementaryFolder(newElementPath
+ getSuffix(), false);
446 oldSupplFolder
.copy(newSupplFolder
.getFullPath(), true, new NullProgressMonitor());
447 } catch (CoreException e
) {
448 Activator
.getDefault().logError("Error renaming supplementary folder " + oldSupplFolder
, e
); //$NON-NLS-1$
454 * Copies the element specific supplementary folder a new folder.
457 * The destination folder to copy to.
459 public void copySupplementaryFolder(IFolder destination
) {
460 IFolder oldSupplFolder
= getTraceSupplementaryFolder(getSupplementaryFolderPath());
462 // copy supplementary folder
463 if (oldSupplFolder
.exists()) {
465 TraceUtils
.createFolder((IFolder
) destination
.getParent(), new NullProgressMonitor());
466 oldSupplFolder
.copy(destination
.getFullPath(), true, new NullProgressMonitor());
467 } catch (CoreException e
) {
468 Activator
.getDefault().logError("Error copying supplementary folder " + oldSupplFolder
, e
); //$NON-NLS-1$
474 * Refreshes the element specific supplementary folder information. It
475 * creates the folder if not exists. It sets the persistence property of the
478 public void refreshSupplementaryFolder() {
479 IFolder supplFolder
= createSupplementaryFolder();
481 supplFolder
.refreshLocal(IResource
.DEPTH_INFINITE
, new NullProgressMonitor());
482 } catch (CoreException e
) {
483 Activator
.getDefault().logError("Error refreshing supplementary folder " + supplFolder
, e
); //$NON-NLS-1$
488 * Checks if supplementary resource exist or not.
490 * @return <code>true</code> if one or more files are under the element
491 * supplementary folder
493 public boolean hasSupplementaryResources() {
494 IResource
[] resources
= getSupplementaryResources();
495 return (resources
.length
> 0);
499 * Returns the supplementary resources under the trace supplementary folder.
501 * @return array of resources under the trace supplementary folder.
503 public IResource
[] getSupplementaryResources() {
504 IFolder supplFolder
= getTraceSupplementaryFolder(getSupplementaryFolderPath());
505 if (supplFolder
.exists()) {
507 return supplFolder
.members();
508 } catch (CoreException e
) {
509 Activator
.getDefault().logError("Error deleting supplementary folder " + supplFolder
, e
); //$NON-NLS-1$
512 return new IResource
[0];
516 * Deletes the given resources.
519 * array of resources to delete.
521 public void deleteSupplementaryResources(IResource
[] resources
) {
523 for (int i
= 0; i
< resources
.length
; i
++) {
525 resources
[i
].delete(true, new NullProgressMonitor());
526 } catch (CoreException e
) {
527 Activator
.getDefault().logError("Error deleting supplementary resource " + resources
[i
], e
); //$NON-NLS-1$
533 * Deletes all supplementary resources in the supplementary directory
535 public void deleteSupplementaryResources() {
536 deleteSupplementaryResources(getSupplementaryResources());
539 private IFolder
createSupplementaryFolder() {
540 IFolder supplFolder
= prepareTraceSupplementaryFolder(getSupplementaryFolderPath(), true);
543 fResource
.setPersistentProperty(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER
, supplFolder
.getLocation().toOSString());
544 } catch (CoreException e
) {
545 Activator
.getDefault().logError("Error setting persistant property " + TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER
, e
); //$NON-NLS-1$
550 // -------------------------------------------------------
552 // -------------------------------------------------------
555 * Handler for the Trace Opened signal
558 * The incoming signal
561 public void traceOpened(TmfTraceOpenedSignal signal
) {
562 IResource resource
= signal
.getTrace().getResource();
563 if ((resource
== null) || !resource
.equals(getResource())) {
567 getParent().refresh();