1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson
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 * Patrick Tasse - Initial API and implementation
11 * Patrick Tasse - Add support for DROP_LINK and rename prompt on name clash
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.internal
.tmf
.ui
.project
.handlers
;
17 import java
.io
.FileInputStream
;
18 import java
.io
.FileNotFoundException
;
19 import java
.io
.InputStream
;
20 import java
.lang
.reflect
.InvocationTargetException
;
21 import java
.util
.Arrays
;
22 import java
.util
.List
;
25 import org
.eclipse
.core
.resources
.IFile
;
26 import org
.eclipse
.core
.resources
.IFolder
;
27 import org
.eclipse
.core
.resources
.IProject
;
28 import org
.eclipse
.core
.resources
.IResource
;
29 import org
.eclipse
.core
.resources
.IWorkspace
;
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
.IProgressMonitor
;
34 import org
.eclipse
.core
.runtime
.IStatus
;
35 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
36 import org
.eclipse
.core
.runtime
.Path
;
37 import org
.eclipse
.core
.runtime
.QualifiedName
;
38 import org
.eclipse
.core
.runtime
.Status
;
39 import org
.eclipse
.jface
.operation
.IRunnableWithProgress
;
40 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
41 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTrace
;
44 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.ITmfProjectModelElement
;
45 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfExperimentElement
;
46 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfProjectElement
;
47 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfProjectRegistry
;
48 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceElement
;
49 import org
.eclipse
.linuxtools
.tmf
.ui
.project
.model
.TmfTraceFolder
;
50 import org
.eclipse
.osgi
.util
.NLS
;
51 import org
.eclipse
.swt
.SWT
;
52 import org
.eclipse
.swt
.dnd
.DND
;
53 import org
.eclipse
.swt
.dnd
.DropTargetEvent
;
54 import org
.eclipse
.swt
.dnd
.FileTransfer
;
55 import org
.eclipse
.swt
.dnd
.TransferData
;
56 import org
.eclipse
.swt
.widgets
.MessageBox
;
57 import org
.eclipse
.ui
.PlatformUI
;
58 import org
.eclipse
.ui
.actions
.WorkspaceModifyDelegatingOperation
;
59 import org
.eclipse
.ui
.dialogs
.IOverwriteQuery
;
60 import org
.eclipse
.ui
.navigator
.CommonDropAdapter
;
61 import org
.eclipse
.ui
.navigator
.CommonDropAdapterAssistant
;
62 import org
.eclipse
.ui
.wizards
.datatransfer
.FileSystemStructureProvider
;
63 import org
.eclipse
.ui
.wizards
.datatransfer
.ImportOperation
;
66 * Drop adapter assistant for project explorer
68 public class DropAdapterAssistant
extends CommonDropAdapterAssistant
{
73 public DropAdapterAssistant() {
77 * @see org.eclipse.ui.navigator.CommonDropAdapterAssistant#isSupportedType(org.eclipse.swt.dnd.TransferData)
80 public boolean isSupportedType(TransferData aTransferType
) {
81 return super.isSupportedType(aTransferType
) || FileTransfer
.getInstance().isSupportedType(aTransferType
);
85 * @see org.eclipse.ui.navigator.CommonDropAdapterAssistant#validateDrop(java.lang.Object, int, org.eclipse.swt.dnd.TransferData)
88 public IStatus
validateDrop(Object target
, int operation
, TransferData transferType
) {
89 if (target
instanceof TmfTraceFolder
) {
90 return Status
.OK_STATUS
;
92 if (target
instanceof TmfExperimentElement
) {
93 return Status
.OK_STATUS
;
95 if (target
instanceof TmfTraceElement
) {
96 ITmfProjectModelElement parent
= ((TmfTraceElement
) target
).getParent();
97 if (parent
instanceof TmfTraceFolder
) {
98 return Status
.OK_STATUS
;
100 if (parent
instanceof TmfExperimentElement
) {
101 return Status
.OK_STATUS
;
104 if (target
instanceof IProject
) {
105 return Status
.OK_STATUS
;
107 return Status
.CANCEL_STATUS
;
111 * @see org.eclipse.ui.navigator.CommonDropAdapterAssistant#handleDrop(org.eclipse.ui.navigator.CommonDropAdapter, org.eclipse.swt.dnd.DropTargetEvent, java.lang.Object)
114 public IStatus
handleDrop(CommonDropAdapter aDropAdapter
, DropTargetEvent aDropTargetEvent
, Object aTarget
) {
117 // Use local variable to avoid parameter assignment
118 Object targetToUse
= aTarget
;
120 int operation
= aDropTargetEvent
.detail
;
121 if (operation
!= DND
.DROP_LINK
) {
122 operation
= DND
.DROP_COPY
;
125 // If target is a trace, use its parent (either trace folder or experiment)
126 if (targetToUse
instanceof TmfTraceElement
) {
127 targetToUse
= ((TmfTraceElement
) targetToUse
).getParent();
130 // If target is a project, use its trace folder
131 if (targetToUse
instanceof IProject
) {
132 TmfProjectElement projectElement
= TmfProjectRegistry
.getProject((IProject
) targetToUse
);
133 if (projectElement
!= null) {
134 targetToUse
= projectElement
.getTracesFolder();
138 if (aDropTargetEvent
.data
instanceof IStructuredSelection
) {
139 IStructuredSelection selection
= (IStructuredSelection
) aDropTargetEvent
.data
;
140 for (Object source
: selection
.toArray()) {
141 if (source
instanceof IResource
) {
142 // If source resource is a trace, use the trace element
143 IResource sourceResource
= (IResource
) source
;
144 TmfProjectElement projectElement
= TmfProjectRegistry
.getProject(sourceResource
.getProject());
145 if (projectElement
!= null && projectElement
.getTracesFolder() != null) {
146 for (TmfTraceElement trace
: projectElement
.getTracesFolder().getTraces()) {
147 if (trace
.getResource().equals(sourceResource
)) {
154 if (source
instanceof TmfTraceElement
) {
155 TmfTraceElement sourceTrace
= (TmfTraceElement
) source
;
156 // If source trace is under an experiment, use the original trace from the traces folder
157 sourceTrace
= sourceTrace
.getElementUnderTraceFolder();
158 if (targetToUse
instanceof TmfExperimentElement
) {
159 TmfExperimentElement targetExperiment
= (TmfExperimentElement
) targetToUse
;
160 ok
|= drop(sourceTrace
, targetExperiment
, operation
);
161 } else if (targetToUse
instanceof TmfTraceFolder
) {
162 TmfTraceFolder traceFolder
= (TmfTraceFolder
) targetToUse
;
163 ok
|= drop(sourceTrace
, traceFolder
, operation
);
165 } else if (source
instanceof IResource
) {
166 IResource sourceResource
= (IResource
) source
;
167 if (sourceResource
.getType() != IResource
.FILE
&& sourceResource
.getType() != IResource
.FOLDER
) {
170 if (targetToUse
instanceof TmfExperimentElement
) {
171 TmfExperimentElement targetExperiment
= (TmfExperimentElement
) targetToUse
;
172 ok
|= (drop(sourceResource
, targetExperiment
, operation
) != null);
173 } else if (targetToUse
instanceof TmfTraceFolder
) {
174 TmfTraceFolder traceFolder
= (TmfTraceFolder
) targetToUse
;
175 ok
|= (drop(sourceResource
, traceFolder
, operation
) != null);
179 } else if (aDropTargetEvent
.data
instanceof String
[]) {
180 String
[] sources
= (String
[]) aDropTargetEvent
.data
;
181 for (String source
: sources
) {
182 Path path
= new Path(source
);
183 if (targetToUse
instanceof TmfExperimentElement
) {
184 TmfExperimentElement targetExperiment
= (TmfExperimentElement
) targetToUse
;
185 ok
|= drop(path
, targetExperiment
, operation
);
186 } else if (targetToUse
instanceof TmfTraceFolder
) {
187 TmfTraceFolder traceFolder
= (TmfTraceFolder
) targetToUse
;
188 ok
|= drop(path
, traceFolder
, operation
);
192 return (ok ? Status
.OK_STATUS
: Status
.CANCEL_STATUS
);
197 * Drop a trace by copying/linking a trace element in a target experiment
199 * @param sourceTrace the source trace element to copy
200 * @param targetExperiment the target experiment
201 * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK)
202 * @return true if successful
204 private static boolean drop(TmfTraceElement sourceTrace
,
205 TmfExperimentElement targetExperiment
,
208 IResource sourceResource
= sourceTrace
.getResource();
209 IResource targetResource
= drop(sourceResource
, targetExperiment
, operation
);
211 if (targetResource
!= null) {
212 if (! sourceTrace
.getProject().equals(targetExperiment
.getProject())) {
213 IFolder destinationSupplementaryFolder
= targetExperiment
.getTraceSupplementaryFolder(targetResource
.getName());
214 sourceTrace
.copySupplementaryFolder(destinationSupplementaryFolder
);
222 * Drop a trace by copying/linking a resource in a target experiment
224 * @param sourceResource the source resource
225 * @param targetExperiment the target experiment
226 * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK)
227 * @return the target resource or null if unsuccessful
229 private static IResource
drop(IResource sourceResource
,
230 TmfExperimentElement targetExperiment
,
233 IResource traceResource
= sourceResource
;
235 TmfProjectElement projectElement
= TmfProjectRegistry
.getProject(sourceResource
.getProject());
236 for (TmfTraceElement trace
: targetExperiment
.getTraces()) {
237 if (trace
.getName().equals(sourceResource
.getName()) && targetExperiment
.getProject().equals(projectElement
)) {
241 if (!targetExperiment
.getProject().equals(projectElement
)) {
242 String targetName
= sourceResource
.getName();
243 for (TmfTraceElement trace
: targetExperiment
.getProject().getTracesFolder().getTraces()) {
244 if (trace
.getName().equals(targetName
)) {
245 targetName
= promptRename(trace
);
246 if (targetName
== null) {
253 if (operation
== DND
.DROP_COPY
) {
254 IPath destination
= targetExperiment
.getProject().getTracesFolder().getResource().getFullPath().addTrailingSeparator().append(targetName
);
255 sourceResource
.copy(destination
, false, null);
256 cleanupBookmarks(destination
);
258 createLink(targetExperiment
.getProject().getTracesFolder().getResource(), sourceResource
, targetName
);
260 // use the copied resource for the experiment
261 if (sourceResource
.getType() == IResource
.FILE
) {
262 traceResource
= targetExperiment
.getProject().getTracesFolder().getResource().getFile(targetName
);
263 } else if (sourceResource
.getType() == IResource
.FOLDER
) {
264 traceResource
= targetExperiment
.getProject().getTracesFolder().getResource().getFolder(targetName
);
266 } catch (CoreException e
) {
271 if (traceResource
!= null && traceResource
.exists()) {
272 createLink(targetExperiment
.getResource(), traceResource
, traceResource
.getName());
273 return traceResource
;
279 * Drop a trace by copying/linking a trace element in a trace folder
281 * @param sourceTrace the source trace
282 * @param traceFolder the target trace folder
283 * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK)
284 * @return true if successful
286 private static boolean drop(TmfTraceElement sourceTrace
,
287 TmfTraceFolder traceFolder
,
290 IResource sourceResource
= sourceTrace
.getResource();
291 IResource targetResource
= drop(sourceResource
, traceFolder
, operation
);
293 if (targetResource
!= null) {
294 IFolder destinationSupplementaryFolder
= traceFolder
.getTraceSupplementaryFolder(targetResource
.getName());
295 sourceTrace
.copySupplementaryFolder(destinationSupplementaryFolder
);
302 * Drop a trace by copying/linking a resource in a trace folder
304 * @param sourceResource the source resource
305 * @param traceFolder the target trace folder
306 * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK)
307 * @return the target resource or null if unsuccessful
309 private static IResource
drop(IResource sourceResource
,
310 TmfTraceFolder traceFolder
,
313 if (sourceResource
.getProject().equals(traceFolder
.getResource().getProject())) {
316 String targetName
= sourceResource
.getName();
317 for (TmfTraceElement trace
: traceFolder
.getTraces()) {
318 if (trace
.getName().equals(targetName
)) {
319 targetName
= promptRename(trace
);
320 if (targetName
== null) {
327 if (operation
== DND
.DROP_COPY
) {
328 IPath destination
= traceFolder
.getResource().getFullPath().addTrailingSeparator().append(targetName
);
329 sourceResource
.copy(destination
, false, null);
330 cleanupBookmarks(destination
);
332 createLink(traceFolder
.getResource(), sourceResource
, targetName
);
334 return traceFolder
.getResource().findMember(targetName
);
335 } catch (CoreException e
) {
342 * Drop a trace by importing/linking a path in a target experiment
344 * @param path the source path
345 * @param targetExperiment the target experiment
346 * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK)
347 * @return true if successful
349 private static boolean drop(Path path
,
350 TmfExperimentElement targetExperiment
,
353 // Use local variable to avoid parameter assignment
354 Path pathToUse
= path
;
356 for (TmfTraceElement trace
: targetExperiment
.getTraces()) {
357 if (trace
.getName().equals(pathToUse
.lastSegment()) && pathToUse
.toString().startsWith(targetExperiment
.getProject().getResource().getLocation().toString())) {
361 if (!pathToUse
.toString().startsWith(targetExperiment
.getProject().getResource().getLocation().toString())) {
362 String targetName
= pathToUse
.lastSegment();
363 for (TmfTraceElement trace
: targetExperiment
.getProject().getTracesFolder().getTraces()) {
364 if (trace
.getName().equals(targetName
)) {
365 targetName
= promptRename(trace
);
366 if (targetName
== null) {
372 if (operation
== DND
.DROP_COPY
) {
373 importTrace(targetExperiment
.getProject().getTracesFolder().getResource(), pathToUse
, targetName
);
375 createLink(targetExperiment
.getProject().getTracesFolder().getResource(), pathToUse
, targetName
);
377 // use the copied resource for the experiment
378 IResource resource
= null;
379 File file
= new File(pathToUse
.toString());
380 if (file
.exists() && file
.isFile()) {
381 resource
= targetExperiment
.getProject().getTracesFolder().getResource().getFile(targetName
);
382 } else if (file
.exists() && file
.isDirectory()) {
383 resource
= targetExperiment
.getProject().getTracesFolder().getResource().getFolder(targetName
);
385 if (resource
!= null && resource
.exists()) {
386 createLink(targetExperiment
.getResource(), resource
, resource
.getName());
394 * Drop a trace by importing/linking a path in a trace folder
396 * @param path the source path
397 * @param traceFolder the target trace folder
398 * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK)
399 * @return true if successful
401 private static boolean drop(Path path
,
402 TmfTraceFolder traceFolder
,
405 String targetName
= path
.lastSegment();
406 for (TmfTraceElement trace
: traceFolder
.getTraces()) {
407 if (trace
.getName().equals(targetName
)) {
408 targetName
= promptRename(trace
);
409 if (targetName
== null) {
415 if (operation
== DND
.DROP_COPY
) {
416 importTrace(traceFolder
.getResource(), path
, targetName
);
418 createLink(traceFolder
.getResource(), path
, targetName
);
424 * Import a trace to the trace folder
426 * @param folder the trace folder resource
427 * @param path the path to the trace to import
428 * @param targetName the target name
430 private static void importTrace(final IFolder folder
, final Path path
, final String targetName
) {
431 final File source
= new File(path
.toString());
432 if (source
.isDirectory()) {
433 IPath containerPath
= folder
.getFullPath().addTrailingSeparator().append(targetName
);
434 IOverwriteQuery overwriteImplementor
= new IOverwriteQuery() {
436 public String
queryOverwrite(String pathString
) {
437 return IOverwriteQuery
.NO_ALL
;
440 List
<File
> filesToImport
= Arrays
.asList(source
.listFiles());
441 ImportOperation operation
= new ImportOperation(
444 FileSystemStructureProvider
.INSTANCE
,
445 overwriteImplementor
,
447 operation
.setCreateContainerStructure(false);
449 operation
.run(new NullProgressMonitor());
450 } catch (InvocationTargetException e
) {
452 } catch (InterruptedException e
) {
456 IRunnableWithProgress runnable
= new IRunnableWithProgress() {
458 public void run(IProgressMonitor monitor
) throws InvocationTargetException
, InterruptedException
{
460 InputStream inputStream
= new FileInputStream(source
);
461 IFile targetFile
= folder
.getFile(targetName
);
462 targetFile
.create(inputStream
, IResource
.NONE
, monitor
);
463 } catch (CoreException e
) {
465 } catch (FileNotFoundException e
) {
470 WorkspaceModifyDelegatingOperation operation
= new WorkspaceModifyDelegatingOperation(runnable
);
472 operation
.run(new NullProgressMonitor());
473 } catch (InvocationTargetException e
) {
475 } catch (InterruptedException e
) {
482 * Create a link to the actual trace and set the trace type
484 * @param parentFolder the parent folder
485 * @param resource the resource
486 * @param targetName the target name
488 private static void createLink(IFolder parentFolder
, IResource resource
, String targetName
) {
489 IPath location
= resource
.getLocation();
490 IWorkspace workspace
= ResourcesPlugin
.getWorkspace();
492 Map
<QualifiedName
, String
> properties
= resource
.getPersistentProperties();
493 String bundleName
= properties
.get(TmfCommonConstants
.TRACEBUNDLE
);
494 String traceType
= properties
.get(TmfCommonConstants
.TRACETYPE
);
495 String iconUrl
= properties
.get(TmfCommonConstants
.TRACEICON
);
496 String supplFolder
= properties
.get(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER
);
498 if (resource
instanceof IFolder
) {
499 IFolder folder
= parentFolder
.getFolder(targetName
);
500 if (workspace
.validateLinkLocation(folder
, location
).isOK()) {
501 folder
.createLink(location
, IResource
.REPLACE
, null);
502 setProperties(folder
, bundleName
, traceType
, iconUrl
, supplFolder
);
505 Activator
.getDefault().logError("Invalid Trace Location"); //$NON-NLS-1$
508 IFile file
= parentFolder
.getFile(targetName
);
509 if (workspace
.validateLinkLocation(file
, location
).isOK()) {
510 file
.createLink(location
, IResource
.REPLACE
, null);
511 setProperties(file
, bundleName
, traceType
, iconUrl
, supplFolder
);
513 Activator
.getDefault().logError("Invalid Trace Location"); //$NON-NLS-1$
516 } catch (CoreException e
) {
522 * Create a link to a file or folder
524 * @param parentFolder the parent folder
525 * @param source the file or folder
526 * @param targetName the target name
528 private static void createLink(IFolder parentFolder
, IPath location
, String targetName
) {
529 File source
= new File(location
.toString());
530 IWorkspace workspace
= ResourcesPlugin
.getWorkspace();
533 if (source
.isDirectory()) {
534 IFolder folder
= parentFolder
.getFolder(targetName
);
535 if (workspace
.validateLinkLocation(folder
, location
).isOK()) {
536 folder
.createLink(location
, IResource
.REPLACE
, null);
538 Activator
.getDefault().logError("Invalid Trace Location"); //$NON-NLS-1$
541 IFile file
= parentFolder
.getFile(targetName
);
542 if (workspace
.validateLinkLocation(file
, location
).isOK()) {
543 file
.createLink(location
, IResource
.REPLACE
, null);
545 Activator
.getDefault().logError("Invalid Trace Location"); //$NON-NLS-1$
548 } catch (CoreException e
) {
554 * Prompts the user to rename a trace
556 * @param trace the existing trace
557 * @return the new name to use or null if rename is canceled
559 private static String
promptRename(TmfTraceElement trace
) {
560 MessageBox mb
= new MessageBox(PlatformUI
.getWorkbench().getActiveWorkbenchWindow().getShell(), SWT
.ICON_QUESTION
| SWT
.CANCEL
| SWT
.OK
);
561 mb
.setText(Messages
.DropAdapterAssistant_RenameTraceTitle
);
562 mb
.setMessage(NLS
.bind(Messages
.DropAdapterAssistant_RenameTraceMessage
, trace
.getName()));
563 if (mb
.open() != SWT
.OK
) {
566 IFolder folder
= trace
.getProject().getTracesFolder().getResource();
569 String name
= trace
.getName() + '-' + Integer
.toString(i
++);
570 IResource resource
= folder
.findMember(name
);
571 if (resource
== null) {
578 * Cleanup bookmarks file in copied trace
580 private static void cleanupBookmarks(IPath path
) {
581 IFolder folder
= ResourcesPlugin
.getWorkspace().getRoot().getFolder(path
);
582 if (folder
.exists()) {
584 for (IResource member
: folder
.members()) {
585 if (TmfTrace
.class.getCanonicalName().equals(member
.getPersistentProperty(TmfCommonConstants
.TRACETYPE
))) {
586 member
.delete(true, null);
589 } catch (CoreException e
) {
596 * Set the trace persistent properties
598 * @param resource the trace resource
599 * @param bundleName the bundle name
600 * @param traceType the trace type
601 * @param iconUrl the icon URL
602 * @param supplFolder the directory of the directory for supplementary information or null to ignore the property
603 * @throws CoreException
605 private static void setProperties(IResource resource
, String bundleName
,
606 String traceType
, String iconUrl
, String supplFolder
)
607 throws CoreException
{
608 resource
.setPersistentProperty(TmfCommonConstants
.TRACEBUNDLE
, bundleName
);
609 resource
.setPersistentProperty(TmfCommonConstants
.TRACETYPE
, traceType
);
610 resource
.setPersistentProperty(TmfCommonConstants
.TRACEICON
, iconUrl
);
611 resource
.setPersistentProperty(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER
, supplFolder
);
615 * Display an exception in a message box
617 * @param e the exception
619 private static void displayException(Exception e
) {
620 MessageBox mb
= new MessageBox(PlatformUI
.getWorkbench().getActiveWorkbenchWindow().getShell());
621 mb
.setText(e
.getClass().getName());
622 mb
.setMessage(e
.getMessage());