| 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2010, 2012 Ericsson |
| 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 | * Bernd Hufmann - Implement getParent() |
| 12 | *******************************************************************************/ |
| 13 | |
| 14 | package org.eclipse.linuxtools.tmf.ui.project.model; |
| 15 | |
| 16 | import java.util.ArrayList; |
| 17 | import java.util.HashMap; |
| 18 | import java.util.List; |
| 19 | import java.util.Map; |
| 20 | import java.util.Set; |
| 21 | |
| 22 | import org.eclipse.core.resources.IFolder; |
| 23 | import org.eclipse.core.resources.IProject; |
| 24 | import org.eclipse.core.resources.IResource; |
| 25 | import org.eclipse.core.runtime.CoreException; |
| 26 | import org.eclipse.jface.viewers.Viewer; |
| 27 | import org.eclipse.ui.IMemento; |
| 28 | import org.eclipse.ui.navigator.ICommonContentExtensionSite; |
| 29 | import org.eclipse.ui.navigator.IPipelinedTreeContentProvider; |
| 30 | import org.eclipse.ui.navigator.PipelinedShapeModification; |
| 31 | import org.eclipse.ui.navigator.PipelinedViewerUpdate; |
| 32 | |
| 33 | /** |
| 34 | * The TMF project content provider for the tree viewer in the project explorer view. |
| 35 | * <p> |
| 36 | * @version 1.0 |
| 37 | * @author Francois Chouinard |
| 38 | */ |
| 39 | public class TmfNavigatorContentProvider implements IPipelinedTreeContentProvider { |
| 40 | |
| 41 | // ------------------------------------------------------------------------ |
| 42 | // ICommonContentProvider |
| 43 | // ------------------------------------------------------------------------ |
| 44 | /* |
| 45 | * (non-Javadoc) |
| 46 | * @see org.eclipse.jface.viewers.ITreeContentProvider#getElements(java.lang.Object) |
| 47 | */ |
| 48 | @Override |
| 49 | public Object[] getElements(Object inputElement) { |
| 50 | return null; |
| 51 | } |
| 52 | |
| 53 | /* |
| 54 | * (non-Javadoc) |
| 55 | * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object) |
| 56 | */ |
| 57 | @Override |
| 58 | public Object getParent(Object element) { |
| 59 | if (element instanceof IProject) { |
| 60 | IProject project = (IProject) element; |
| 61 | return project.getParent(); |
| 62 | } |
| 63 | |
| 64 | if (element instanceof TmfTraceFolder) { |
| 65 | TmfTraceFolder folder = (TmfTraceFolder) element; |
| 66 | // Return the corresponding IProject as parent because from CNF point of view the IProject is the parent. |
| 67 | // The IProject is needed e.g. for link with Editor to work correctly. |
| 68 | return folder.getParent().getResource(); |
| 69 | } |
| 70 | |
| 71 | if (element instanceof TmfTraceElement) { |
| 72 | TmfTraceElement traceElement = (TmfTraceElement) element; |
| 73 | return traceElement.getParent(); |
| 74 | } |
| 75 | |
| 76 | if (element instanceof TmfExperimentFolder) { |
| 77 | TmfExperimentFolder folder = (TmfExperimentFolder) element; |
| 78 | // Return the corresponding IProject as parent because from CNF point of view the IProject is the parent. |
| 79 | // The IProject is needed e.g. for link with Editor to work correctly. |
| 80 | return folder.getParent().getResource(); |
| 81 | } |
| 82 | |
| 83 | if (element instanceof TmfExperimentElement) { |
| 84 | TmfExperimentElement expElement = (TmfExperimentElement) element; |
| 85 | return expElement.getParent(); |
| 86 | } |
| 87 | return null; |
| 88 | } |
| 89 | |
| 90 | /* |
| 91 | * (non-Javadoc) |
| 92 | * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object) |
| 93 | */ |
| 94 | @Override |
| 95 | public boolean hasChildren(Object element) { |
| 96 | if (element instanceof IProject) { |
| 97 | IProject project = (IProject) element; |
| 98 | return project.isAccessible(); |
| 99 | } |
| 100 | if (element instanceof TmfTraceFolder) { |
| 101 | TmfTraceFolder folder = (TmfTraceFolder) element; |
| 102 | return folder.hasChildren(); |
| 103 | } |
| 104 | if (element instanceof TmfExperimentFolder) { |
| 105 | TmfExperimentFolder folder = (TmfExperimentFolder) element; |
| 106 | return folder.hasChildren(); |
| 107 | } |
| 108 | if (element instanceof TmfExperimentElement) { |
| 109 | TmfExperimentElement folder = (TmfExperimentElement) element; |
| 110 | return folder.hasChildren(); |
| 111 | } |
| 112 | return false; |
| 113 | } |
| 114 | |
| 115 | /* |
| 116 | * (non-Javadoc) |
| 117 | * @see org.eclipse.jface.viewers.IContentProvider#dispose() |
| 118 | */ |
| 119 | @Override |
| 120 | public void dispose() { |
| 121 | } |
| 122 | |
| 123 | /* |
| 124 | * (non-Javadoc) |
| 125 | * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) |
| 126 | */ |
| 127 | @Override |
| 128 | public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { |
| 129 | } |
| 130 | |
| 131 | /* |
| 132 | * (non-Javadoc) |
| 133 | * @see org.eclipse.ui.navigator.IMementoAware#restoreState(org.eclipse.ui.IMemento) |
| 134 | */ |
| 135 | @Override |
| 136 | public void restoreState(IMemento aMemento) { |
| 137 | } |
| 138 | |
| 139 | /* |
| 140 | * (non-Javadoc) |
| 141 | * @see org.eclipse.ui.navigator.IMementoAware#saveState(org.eclipse.ui.IMemento) |
| 142 | */ |
| 143 | @Override |
| 144 | public void saveState(IMemento aMemento) { |
| 145 | } |
| 146 | |
| 147 | /* |
| 148 | * (non-Javadoc) |
| 149 | * @see org.eclipse.ui.navigator.ICommonContentProvider#init(org.eclipse.ui.navigator.ICommonContentExtensionSite) |
| 150 | */ |
| 151 | @Override |
| 152 | public void init(ICommonContentExtensionSite aConfig) { |
| 153 | } |
| 154 | |
| 155 | // ------------------------------------------------------------------------ |
| 156 | // ICommonContentProvider - getChildren() |
| 157 | // ------------------------------------------------------------------------ |
| 158 | /* |
| 159 | * (non-Javadoc) |
| 160 | * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object) |
| 161 | */ |
| 162 | @Override |
| 163 | public synchronized Object[] getChildren(Object parentElement) { |
| 164 | |
| 165 | // Tracing project level |
| 166 | if (parentElement instanceof IProject) { |
| 167 | return getProjectChildren((IProject) parentElement); |
| 168 | } |
| 169 | |
| 170 | // Traces "folder" level |
| 171 | if (parentElement instanceof TmfTraceFolder) { |
| 172 | return getTraceFolderChildren((TmfTraceFolder) parentElement); |
| 173 | } |
| 174 | |
| 175 | // Experiments "folder" level |
| 176 | if (parentElement instanceof TmfExperimentFolder) { |
| 177 | return getExperimentFolderChildren((TmfExperimentFolder) parentElement); |
| 178 | } |
| 179 | |
| 180 | // Experiment |
| 181 | if (parentElement instanceof TmfExperimentElement) { |
| 182 | return getExperimentChildren((TmfExperimentElement) parentElement); |
| 183 | } |
| 184 | |
| 185 | return new Object[0]; |
| 186 | } |
| 187 | |
| 188 | // ------------------------------------------------------------------------ |
| 189 | // Helper method |
| 190 | // ------------------------------------------------------------------------ |
| 191 | private Object[] getProjectChildren(IProject project) { |
| 192 | // The children structure |
| 193 | List<Object> children = new ArrayList<Object>(); |
| 194 | |
| 195 | // Get the children from the model |
| 196 | Map<String, ITmfProjectModelElement> childrenMap = new HashMap<String, ITmfProjectModelElement>(); |
| 197 | TmfProjectElement tmfProject = TmfProjectRegistry.getProject(project, true); |
| 198 | for (ITmfProjectModelElement element : tmfProject.getChildren()) { |
| 199 | if (element instanceof TmfTraceFolder) { |
| 200 | TmfTraceFolder child = (TmfTraceFolder) element; |
| 201 | childrenMap.put(child.getResource().getName(), child); |
| 202 | } |
| 203 | if (element instanceof TmfExperimentFolder) { |
| 204 | TmfExperimentFolder child = (TmfExperimentFolder) element; |
| 205 | childrenMap.put(child.getResource().getName(), child); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | // Add the model folder if the corresponding resource exists and is not |
| 210 | // accounted for |
| 211 | IFolder folder = project.getFolder(TmfTraceFolder.TRACE_FOLDER_NAME); |
| 212 | if (folder != null) { |
| 213 | String name = folder.getName(); |
| 214 | ITmfProjectModelElement element = childrenMap.get(name); |
| 215 | if (element == null) { |
| 216 | element = new TmfTraceFolder(TmfTraceFolder.TRACE_FOLDER_NAME, folder, tmfProject); |
| 217 | } |
| 218 | children.add(element); |
| 219 | childrenMap.remove(name); |
| 220 | getTraceFolderChildren((TmfTraceFolder) element); |
| 221 | } |
| 222 | |
| 223 | // Add the model folder if the corresponding resource exists and is not |
| 224 | // accounted for |
| 225 | folder = project.getFolder(TmfExperimentFolder.EXPER_FOLDER_NAME); |
| 226 | if (folder != null) { |
| 227 | String name = folder.getName(); |
| 228 | ITmfProjectModelElement element = childrenMap.get(name); |
| 229 | if (element == null) { |
| 230 | element = new TmfExperimentFolder(TmfExperimentFolder.EXPER_FOLDER_NAME, folder, tmfProject); |
| 231 | } |
| 232 | children.add(element); |
| 233 | childrenMap.remove(name); |
| 234 | getExperimentFolderChildren((TmfExperimentFolder) element); |
| 235 | } |
| 236 | |
| 237 | // Remove the leftovers (what was in the model but removed from the |
| 238 | // project) |
| 239 | cleanupModel(tmfProject, childrenMap); |
| 240 | |
| 241 | return children.toArray(); |
| 242 | } |
| 243 | |
| 244 | private Object[] getTraceFolderChildren(TmfTraceFolder tmfTraceFolder) { |
| 245 | // The children structure |
| 246 | List<Object> children = new ArrayList<Object>(); |
| 247 | |
| 248 | // Get the children from the model |
| 249 | Map<String, ITmfProjectModelElement> childrenMap = new HashMap<String, ITmfProjectModelElement>(); |
| 250 | for (ITmfProjectModelElement element : tmfTraceFolder.getChildren()) { |
| 251 | if (element instanceof TmfTraceElement) { |
| 252 | String name = element.getResource().getName(); |
| 253 | childrenMap.put(name, element); |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | IFolder folder = tmfTraceFolder.getResource(); |
| 258 | try { |
| 259 | IResource[] members = folder.members(); |
| 260 | for (IResource resource : members) { |
| 261 | String name = resource.getName(); |
| 262 | ITmfProjectModelElement trace = childrenMap.get(name); |
| 263 | if (trace == null) { |
| 264 | trace = new TmfTraceElement(name, resource, tmfTraceFolder); |
| 265 | } |
| 266 | children.add(trace); |
| 267 | childrenMap.remove(name); |
| 268 | } |
| 269 | } catch (CoreException e) { |
| 270 | } |
| 271 | |
| 272 | // Remove the leftovers (what was in the model but removed from the |
| 273 | // project) |
| 274 | cleanupModel(tmfTraceFolder, childrenMap); |
| 275 | |
| 276 | return children.toArray(); |
| 277 | } |
| 278 | |
| 279 | private Object[] getExperimentFolderChildren(TmfExperimentFolder tmfExperimentFolder) { |
| 280 | // The children structure |
| 281 | List<Object> children = new ArrayList<Object>(); |
| 282 | |
| 283 | // Get the children from the model |
| 284 | Map<String, ITmfProjectModelElement> childrenMap = new HashMap<String, ITmfProjectModelElement>(); |
| 285 | for (ITmfProjectModelElement element : tmfExperimentFolder.getChildren()) { |
| 286 | if (element instanceof TmfExperimentElement) { |
| 287 | String name = element.getResource().getName(); |
| 288 | childrenMap.put(name, element); |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | IFolder folder = tmfExperimentFolder.getResource(); |
| 293 | try { |
| 294 | IResource[] members = folder.members(); |
| 295 | for (IResource resource : members) { |
| 296 | if (resource instanceof IFolder) { |
| 297 | IFolder expFolder = (IFolder) resource; |
| 298 | String name = resource.getName(); |
| 299 | ITmfProjectModelElement experiment = childrenMap.get(name); |
| 300 | if (experiment == null) { |
| 301 | experiment = new TmfExperimentElement(name, expFolder, tmfExperimentFolder); |
| 302 | } |
| 303 | children.add(experiment); |
| 304 | childrenMap.remove(name); |
| 305 | getExperimentChildren((TmfExperimentElement) experiment); |
| 306 | } |
| 307 | } |
| 308 | } catch (CoreException e) { |
| 309 | } |
| 310 | |
| 311 | // Remove the leftovers (what was in the model but removed from the |
| 312 | // project) |
| 313 | cleanupModel(tmfExperimentFolder, childrenMap); |
| 314 | |
| 315 | return children.toArray(); |
| 316 | } |
| 317 | |
| 318 | private Object[] getExperimentChildren(TmfExperimentElement tmfExperiment) { |
| 319 | // The children structure |
| 320 | List<Object> children = new ArrayList<Object>(); |
| 321 | |
| 322 | // Get the children from the model |
| 323 | Map<String, ITmfProjectModelElement> childrenMap = new HashMap<String, ITmfProjectModelElement>(); |
| 324 | for (ITmfProjectModelElement element : tmfExperiment.getChildren()) { |
| 325 | if (element instanceof TmfTraceElement) { |
| 326 | String name = element.getResource().getName(); |
| 327 | childrenMap.put(name, element); |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | IFolder folder = tmfExperiment.getResource(); |
| 332 | try { |
| 333 | IResource[] members = folder.members(); |
| 334 | for (IResource resource : members) { |
| 335 | String name = resource.getName(); |
| 336 | ITmfProjectModelElement trace = childrenMap.get(name); |
| 337 | if (trace == null && !resource.isHidden()) { |
| 338 | // exclude hidden resources (e.g. bookmarks file) |
| 339 | trace = new TmfTraceElement(name, resource, tmfExperiment); |
| 340 | } |
| 341 | children.add(trace); |
| 342 | childrenMap.remove(name); |
| 343 | } |
| 344 | } catch (CoreException e) { |
| 345 | } |
| 346 | |
| 347 | // Remove the leftovers (what was in the model but removed from the |
| 348 | // project) |
| 349 | cleanupModel(tmfExperiment, childrenMap); |
| 350 | |
| 351 | return children.toArray(); |
| 352 | } |
| 353 | |
| 354 | private void cleanupModel(ITmfProjectModelElement parent, Map<String, ITmfProjectModelElement> danglingChildren) { |
| 355 | if (parent != null) { |
| 356 | for (ITmfProjectModelElement child : danglingChildren.values()) { |
| 357 | Map<String, ITmfProjectModelElement> grandChildren = new HashMap<String, ITmfProjectModelElement>(); |
| 358 | for (ITmfProjectModelElement element : child.getChildren()) { |
| 359 | String name = element.getResource().getName(); |
| 360 | grandChildren.put(name, element); |
| 361 | } |
| 362 | cleanupModel(child, grandChildren); |
| 363 | parent.removeChild(child); |
| 364 | } |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | // ------------------------------------------------------------------------ |
| 369 | // IPipelinedTreeContentProvider |
| 370 | // ------------------------------------------------------------------------ |
| 371 | |
| 372 | /* |
| 373 | * (non-Javadoc) |
| 374 | * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#getPipelinedChildren(java.lang.Object, java.util.Set) |
| 375 | */ |
| 376 | @Override |
| 377 | public void getPipelinedChildren(Object parent, Set currentChildren) { |
| 378 | customizeTmfElements(getChildren(parent), currentChildren); |
| 379 | } |
| 380 | |
| 381 | /* |
| 382 | * (non-Javadoc) |
| 383 | * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#getPipelinedElements(java.lang.Object, java.util.Set) |
| 384 | */ |
| 385 | @Override |
| 386 | public void getPipelinedElements(Object input, Set currentElements) { |
| 387 | customizeTmfElements(getElements(input), currentElements); |
| 388 | } |
| 389 | |
| 390 | /** |
| 391 | * Add/replace the ITmfProjectElement to the list of children |
| 392 | * |
| 393 | * @param elements |
| 394 | * the list returned by getChildren() |
| 395 | * @param children |
| 396 | * the current children |
| 397 | */ |
| 398 | private static void customizeTmfElements(Object[] elements, |
| 399 | Set<Object> children) { |
| 400 | if (elements != null && children != null) { |
| 401 | for (Object element : elements) { |
| 402 | if (element instanceof ITmfProjectModelElement) { |
| 403 | ITmfProjectModelElement tmfElement = (ITmfProjectModelElement) element; |
| 404 | IResource resource = tmfElement.getResource(); |
| 405 | if (resource != null) { |
| 406 | children.remove(resource); |
| 407 | } |
| 408 | children.add(element); |
| 409 | } |
| 410 | else if (element != null) { |
| 411 | children.add(element); |
| 412 | } |
| 413 | } |
| 414 | } |
| 415 | } |
| 416 | |
| 417 | /* |
| 418 | * (non-Javadoc) |
| 419 | * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#getPipelinedParent(java.lang.Object, java.lang.Object) |
| 420 | */ |
| 421 | @Override |
| 422 | public Object getPipelinedParent(Object anObject, Object aSuggestedParent) { |
| 423 | return aSuggestedParent; |
| 424 | } |
| 425 | |
| 426 | /* |
| 427 | * (non-Javadoc) |
| 428 | * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#interceptAdd(org.eclipse.ui.navigator.PipelinedShapeModification) |
| 429 | */ |
| 430 | @Override |
| 431 | public PipelinedShapeModification interceptAdd(PipelinedShapeModification anAddModification) { |
| 432 | return anAddModification; |
| 433 | } |
| 434 | |
| 435 | /* |
| 436 | * (non-Javadoc) |
| 437 | * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#interceptRemove(org.eclipse.ui.navigator.PipelinedShapeModification) |
| 438 | */ |
| 439 | @Override |
| 440 | public PipelinedShapeModification interceptRemove(PipelinedShapeModification aRemoveModification) { |
| 441 | return null; |
| 442 | } |
| 443 | |
| 444 | /* |
| 445 | * (non-Javadoc) |
| 446 | * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#interceptRefresh(org.eclipse.ui.navigator.PipelinedViewerUpdate) |
| 447 | */ |
| 448 | @Override |
| 449 | public boolean interceptRefresh(PipelinedViewerUpdate aRefreshSynchronization) { |
| 450 | return false; |
| 451 | } |
| 452 | |
| 453 | /* |
| 454 | * (non-Javadoc) |
| 455 | * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#interceptUpdate(org.eclipse.ui.navigator.PipelinedViewerUpdate) |
| 456 | */ |
| 457 | @Override |
| 458 | public boolean interceptUpdate(PipelinedViewerUpdate anUpdateSynchronization) { |
| 459 | return false; |
| 460 | } |
| 461 | } |