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