| /******************************************************************************* |
| * Copyright (c) 2010, 2018 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Francois Chouinard - Initial API and implementation |
| * Bernd Hufmann - Added supplementary files/folder handling |
| * Patrick Tasse - Refactor resource change listener |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.tmf.ui.project.model; |
| |
| import java.io.File; |
| import java.net.URI; |
| import java.util.List; |
| import java.util.concurrent.CopyOnWriteArrayList; |
| |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.ICoreRunnable; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.SubMonitor; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.tracecompass.internal.tmf.ui.Activator; |
| import org.eclipse.tracecompass.internal.tmf.ui.project.model.TmfProjectModelHelper; |
| import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; |
| import org.eclipse.ui.IViewPart; |
| import org.eclipse.ui.IViewReference; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.model.IWorkbenchAdapter; |
| import org.eclipse.ui.model.WorkbenchAdapter; |
| import org.eclipse.ui.navigator.CommonNavigator; |
| import org.eclipse.ui.navigator.CommonViewer; |
| |
| import com.google.common.collect.ImmutableList; |
| |
| /** |
| * The implementation of the base TMF project model element. It provides default implementation |
| * of the <code>ITmfProjectModelElement</code> interface. |
| * <p> |
| * @version 1.0 |
| * @author Francois Chouinard |
| */ |
| public abstract class TmfProjectModelElement implements ITmfProjectModelElement, IAdaptable { |
| |
| // ------------------------------------------------------------------------ |
| // Attributes |
| // ------------------------------------------------------------------------ |
| |
| private final String fName; |
| |
| /** The project model element resource */ |
| private final IResource fResource; |
| |
| /** The project model resource location (URI) */ |
| private final URI fLocation; |
| |
| /** The project model path of a resource */ |
| private final IPath fPath; |
| |
| private final ITmfProjectModelElement fParent; |
| |
| /** The list of children elements */ |
| private final @NonNull List<ITmfProjectModelElement> fChildren; |
| |
| // ------------------------------------------------------------------------ |
| // Constructor |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Constructor. |
| * |
| * Creates a base project model element. |
| * |
| * @param name |
| * The name of the element. |
| * @param resource |
| * The element resource. |
| * @param parent |
| * The parent model element. |
| */ |
| protected TmfProjectModelElement(String name, IResource resource, ITmfProjectModelElement parent) { |
| fName = name; |
| fResource = resource; |
| fPath = resource.getFullPath(); |
| fLocation = new File(resource.getLocationURI()).toURI(); |
| fParent = parent; |
| fChildren = new CopyOnWriteArrayList<>(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| // ITmfProjectModelElement |
| // ------------------------------------------------------------------------ |
| |
| @Override |
| public String getName() { |
| return fName; |
| } |
| |
| @Override |
| public IResource getResource() { |
| return fResource; |
| } |
| |
| @Override |
| public IPath getPath() { |
| return fPath; |
| } |
| |
| @Override |
| public URI getLocation() { |
| return fLocation; |
| } |
| |
| @Override |
| public TmfProjectElement getProject() { |
| return fParent.getProject(); |
| } |
| |
| @Override |
| public ITmfProjectModelElement getParent() { |
| return fParent; |
| } |
| |
| @Override |
| public List<ITmfProjectModelElement> getChildren() { |
| return ImmutableList.copyOf(fChildren); |
| } |
| |
| @Override |
| public void refresh() { |
| // make sure the model is updated in the current thread |
| refreshChildren(); |
| |
| refreshViewer(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Object |
| // ------------------------------------------------------------------------ |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((fPath == null) ? 0 : fPath.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (this == other) { |
| return true; |
| } |
| if (other == null) { |
| return false; |
| } |
| if (!(other.getClass().equals(this.getClass()))) { |
| return false; |
| } |
| TmfProjectModelElement element = (TmfProjectModelElement) other; |
| return element.fPath.equals(fPath); |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Operations |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Refresh the children of this model element, adding new children and |
| * removing dangling children as necessary. The remaining children should |
| * also refresh their own children sub-tree. |
| * <p> |
| * The method implementation must be thread-safe. |
| * |
| * @since 2.0 |
| */ |
| protected abstract void refreshChildren(); |
| |
| /** |
| * Refresh the common navigator viewer starting with this element. Does not |
| * refresh the model. |
| * |
| * @since 3.1 |
| */ |
| public void refreshViewer() { |
| Display.getDefault().asyncExec(() -> { |
| IWorkbench wb = PlatformUI.getWorkbench(); |
| IWorkbenchWindow wbWindow = wb.getActiveWorkbenchWindow(); |
| if (wbWindow == null) { |
| return; |
| } |
| IWorkbenchPage activePage = wbWindow.getActivePage(); |
| if (activePage == null) { |
| return; |
| } |
| |
| for (IViewReference viewReference : activePage.getViewReferences()) { |
| IViewPart viewPart = viewReference.getView(false); |
| if (viewPart instanceof CommonNavigator) { |
| CommonViewer commonViewer = ((CommonNavigator) viewPart).getCommonViewer(); |
| Object element = TmfProjectModelElement.this; |
| if (element instanceof TmfProjectElement) { |
| IProject project = (IProject) getResource(); |
| if (project != null && !TmfProjectModelHelper.isShadowProject(project)) { |
| // for the project element the viewer uses the IProject resource |
| element = getResource(); |
| } |
| } |
| commonViewer.refresh(element); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Add a new child element to this element. |
| * |
| * @param child |
| * The child to add |
| */ |
| protected void addChild(ITmfProjectModelElement child) { |
| fChildren.add(child); |
| } |
| |
| /** |
| * Remove an element from the current child elements. |
| * <p> |
| * Disposes the removed element. It should no longer be used. |
| * |
| * @param child |
| * The child to remove |
| */ |
| protected void removeChild(ITmfProjectModelElement child) { |
| fChildren.remove(child); |
| child.dispose(); |
| } |
| |
| /** |
| * Returns the trace specific supplementary folder under the project's |
| * supplementary folder. The returned folder and its parent folders may not |
| * exist. |
| * |
| * @param supplFolderPath |
| * folder path relative to the project's supplementary folder |
| * @return the trace specific supplementary folder |
| */ |
| public IFolder getTraceSupplementaryFolder(String supplFolderPath) { |
| TmfProjectElement project = getProject(); |
| IFolder supplFolderParent = project.getSupplementaryFolder(); |
| return supplFolderParent.getFolder(supplFolderPath); |
| } |
| |
| /** |
| * Returns the trace specific supplementary folder under the project's |
| * supplementary folder. Its parent folders will be created if they don't exist. |
| * If createFolder is true, the returned folder will be created, otherwise it |
| * may not exist. |
| * |
| * @param supplFolderPath |
| * folder path relative to the project's supplementary folder |
| * @param createFolder |
| * if true, the returned folder will be created |
| * @param progressMonitor |
| * the progress monitor |
| * @return the trace specific supplementary folder |
| * @since 4.0 |
| */ |
| public IFolder prepareTraceSupplementaryFolder(String supplFolderPath, boolean createFolder, IProgressMonitor progressMonitor) { |
| SubMonitor subMonitor = SubMonitor.convert(progressMonitor); |
| IFolder folder = getTraceSupplementaryFolder(supplFolderPath); |
| IFolder propertiesFolder = folder.getFolder(TmfCommonConstants.TRACE_PROPERTIES_FOLDER); |
| if ((createFolder && propertiesFolder.exists() && propertiesFolder.isHidden()) || |
| (!createFolder && folder.getParent().exists())) { |
| return folder; |
| } |
| try { |
| ICoreRunnable runnable = monitor -> { |
| if (createFolder) { |
| TraceUtils.createFolder(propertiesFolder, monitor); |
| propertiesFolder.setHidden(true); |
| } else { |
| TraceUtils.createFolder((IFolder) folder.getParent(), monitor); |
| } |
| }; |
| ResourcesPlugin.getWorkspace().run(runnable, folder.getProject(), IWorkspace.AVOID_UPDATE, subMonitor); |
| } catch (CoreException e) { |
| Activator.getDefault().logError("Error creating supplementary folder " + folder.getFullPath(), e); //$NON-NLS-1$ |
| } |
| return folder; |
| } |
| |
| /** |
| * Returns the trace specific supplementary folder under the project's |
| * supplementary folder. Its parent folders will be created if they don't exist. |
| * If createFolder is true, the returned folder will be created, otherwise it |
| * may not exist. |
| * |
| * @param supplFolderPath |
| * folder path relative to the project's supplementary folder |
| * @param createFolder |
| * if true, the returned folder will be created |
| * @return the trace specific supplementary folder |
| */ |
| public IFolder prepareTraceSupplementaryFolder(String supplFolderPath, boolean createFolder) { |
| return prepareTraceSupplementaryFolder(supplFolderPath, createFolder, new NullProgressMonitor()); |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getSimpleName() + '(' + getPath() + ')'; |
| } |
| |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public <T> @Nullable T getAdapter(Class<T> adapter) { |
| if (adapter.getClass().isInstance(this)) { |
| return (T)this; |
| } |
| if (IWorkbenchAdapter.class.isAssignableFrom(adapter)) { |
| return ((@Nullable T) new WorkbenchAdapter() { |
| @Override |
| public String getLabel(Object object) { |
| return ((TmfProjectModelElement)object).getName(); |
| } |
| }); |
| } |
| return null; |
| } |
| } |