1 11 12 package org.eclipse.ui.ide.undo; 13 14 import java.util.ArrayList ; 15 import java.util.List ; 16 17 import org.eclipse.core.commands.operations.IUndoContext; 18 import org.eclipse.core.commands.operations.ObjectUndoContext; 19 import org.eclipse.core.resources.IContainer; 20 import org.eclipse.core.resources.IFile; 21 import org.eclipse.core.resources.IProject; 22 import org.eclipse.core.resources.IResource; 23 import org.eclipse.core.resources.IResourceStatus; 24 import org.eclipse.core.resources.IWorkspace; 25 import org.eclipse.core.resources.IWorkspaceRoot; 26 import org.eclipse.core.resources.ResourcesPlugin; 27 import org.eclipse.core.runtime.CoreException; 28 import org.eclipse.core.runtime.IAdaptable; 29 import org.eclipse.core.runtime.IPath; 30 import org.eclipse.core.runtime.IProgressMonitor; 31 import org.eclipse.core.runtime.IStatus; 32 import org.eclipse.core.runtime.MultiStatus; 33 import org.eclipse.core.runtime.NullProgressMonitor; 34 import org.eclipse.core.runtime.OperationCanceledException; 35 import org.eclipse.core.runtime.Status; 36 import org.eclipse.core.runtime.SubProgressMonitor; 37 import org.eclipse.jface.dialogs.IDialogConstants; 38 import org.eclipse.jface.dialogs.MessageDialog; 39 import org.eclipse.osgi.util.NLS; 40 import org.eclipse.swt.widgets.Shell; 41 import org.eclipse.ui.PlatformUI; 42 import org.eclipse.ui.internal.WorkbenchPlugin; 43 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; 44 import org.eclipse.ui.internal.ide.undo.ContainerDescription; 45 import org.eclipse.ui.internal.ide.undo.FileDescription; 46 import org.eclipse.ui.internal.ide.undo.UndoMessages; 47 48 55 public class WorkspaceUndoUtil { 56 57 private static ObjectUndoContext tasksUndoContext; 58 59 private static ObjectUndoContext bookmarksUndoContext; 60 61 66 public static IUndoContext getWorkspaceUndoContext() { 67 return WorkbenchPlugin.getDefault().getOperationSupport() 68 .getUndoContext(); 69 } 70 71 77 public static IUndoContext getTasksUndoContext() { 78 if (tasksUndoContext == null) { 79 tasksUndoContext = new ObjectUndoContext(new Object (), 80 "Tasks Context"); tasksUndoContext.addMatch(getWorkspaceUndoContext()); 82 } 83 return tasksUndoContext; 84 } 85 86 92 public static IUndoContext getBookmarksUndoContext() { 93 if (bookmarksUndoContext == null) { 94 bookmarksUndoContext = new ObjectUndoContext(new Object (), 95 "Bookmarks Context"); bookmarksUndoContext.addMatch(getWorkspaceUndoContext()); 97 } 98 return bookmarksUndoContext; 99 } 100 101 116 public static IAdaptable getUIInfoAdapter(final Shell shell) { 117 return new IAdaptable() { 118 public Object getAdapter(Class clazz) { 119 if (clazz == Shell.class) { 120 return shell; 121 } 122 return null; 123 } 124 }; 125 } 126 127 private WorkspaceUndoUtil() { 128 } 130 131 154 static ResourceDescription[] delete(IResource[] resourcesToDelete, 155 IProgressMonitor monitor, IAdaptable uiInfo, boolean deleteContent) 156 throws CoreException { 157 final List exceptions = new ArrayList (); 158 boolean forceOutOfSyncDelete = false; 159 ResourceDescription[] returnedResourceDescriptions = new ResourceDescription[resourcesToDelete.length]; 160 monitor.beginTask("", resourcesToDelete.length); monitor 162 .setTaskName(UndoMessages.AbstractResourcesOperation_DeleteResourcesProgress); 163 try { 164 for (int i = 0; i < resourcesToDelete.length; ++i) { 165 if (monitor.isCanceled()) { 166 throw new OperationCanceledException(); 167 } 168 IResource resource = resourcesToDelete[i]; 169 try { 170 returnedResourceDescriptions[i] = delete(resource, 171 new SubProgressMonitor(monitor, 1), uiInfo, 172 forceOutOfSyncDelete, deleteContent); 173 } catch (CoreException e) { 174 if (resource.getType() == IResource.FILE) { 175 IStatus[] children = e.getStatus().getChildren(); 176 if (children.length == 1 177 && children[0].getCode() == IResourceStatus.OUT_OF_SYNC_LOCAL) { 178 int result = queryDeleteOutOfSync(resource, uiInfo); 179 180 if (result == IDialogConstants.YES_ID) { 181 delete(resource, new SubProgressMonitor( 183 monitor, 1), uiInfo, true, 184 deleteContent); 185 } else if (result == IDialogConstants.YES_TO_ALL_ID) { 186 forceOutOfSyncDelete = true; 189 delete(resource, new SubProgressMonitor( 190 monitor, 1), uiInfo, 191 forceOutOfSyncDelete, deleteContent); 192 } else if (result == IDialogConstants.CANCEL_ID) { 193 throw new OperationCanceledException(); 194 } else { 195 exceptions.add(e); 196 } 197 } else { 198 exceptions.add(e); 199 } 200 } else { 201 exceptions.add(e); 202 } 203 } 204 } 205 IStatus result = createResult(exceptions); 206 if (!result.isOK()) { 207 throw new CoreException(result); 208 } 209 } finally { 210 monitor.done(); 211 } 212 return returnedResourceDescriptions; 213 } 214 215 246 static ResourceDescription[] copy(IResource[] resources, IPath destination, 247 List resourcesAtDestination, IProgressMonitor monitor, 248 IAdaptable uiInfo, boolean pathIncludesName) throws CoreException { 249 250 monitor.beginTask("", resources.length); monitor 252 .setTaskName(UndoMessages.AbstractResourcesOperation_CopyingResourcesProgress); 253 List overwrittenResources = new ArrayList (); 254 for (int i = 0; i < resources.length; i++) { 255 IResource source = resources[i]; 256 IPath destinationPath; 257 if (pathIncludesName) { 258 destinationPath = destination; 259 } else { 260 destinationPath = destination.append(source.getName()); 261 } 262 IWorkspaceRoot workspaceRoot = getWorkspaceRoot(); 263 IResource existing = workspaceRoot.findMember(destinationPath); 264 if (source.getType() == IResource.FOLDER && existing != null) { 265 if (source.isLinked() == existing.isLinked()) { 268 IResource[] children = ((IContainer) source).members(); 269 ResourceDescription[] overwritten = copy(children, 270 destinationPath, resourcesAtDestination, 271 new SubProgressMonitor(monitor, 1), uiInfo, false); 272 for (int j = 0; j < overwritten.length; j++) { 275 overwrittenResources.add(overwritten[j]); 276 } 277 } else { 278 ResourceDescription[] deleted = delete( 281 new IResource[] { existing }, 282 new SubProgressMonitor(monitor, 0), uiInfo, false); 283 source.copy(destinationPath, IResource.SHALLOW, 284 new SubProgressMonitor(monitor, 1)); 285 resourcesAtDestination.add(getWorkspace().getRoot() 287 .findMember(destinationPath)); 288 for (int j = 0; j < deleted.length; j++) { 289 overwrittenResources.add(deleted[j]); 290 } 291 } 292 } else { 293 if (existing != null) { 294 if (source.isLinked() == existing.isLinked()) { 295 overwrittenResources.add(copyOverExistingResource( 296 source, existing, new SubProgressMonitor( 297 monitor, 1), uiInfo, false)); 298 resourcesAtDestination.add(existing); 300 } else { 301 ResourceDescription[] deleted = delete( 304 new IResource[] { existing }, 305 new SubProgressMonitor(monitor, 0), uiInfo, 306 false); 307 source.copy(destinationPath, IResource.SHALLOW, 308 new SubProgressMonitor(monitor, 1)); 309 resourcesAtDestination.add(getWorkspace().getRoot() 311 .findMember(destinationPath)); 312 for (int j = 0; j < deleted.length; j++) { 313 overwrittenResources.add(deleted[j]); 314 } 315 } 316 } else { 317 IPath parentPath = destination; 320 if (pathIncludesName) { 321 parentPath = destination.removeLastSegments(1); 322 } 323 IContainer generatedParent = generateContainers(parentPath); 324 source.copy(destinationPath, IResource.SHALLOW, 325 new SubProgressMonitor(monitor, 1)); 326 if (generatedParent == null) { 329 resourcesAtDestination.add(getWorkspace().getRoot() 330 .findMember(destinationPath)); 331 } else { 332 resourcesAtDestination.add(generatedParent); 333 } 334 } 335 336 if (monitor.isCanceled()) { 337 throw new OperationCanceledException(); 338 } 339 } 340 } 341 monitor.done(); 342 return (ResourceDescription[]) overwrittenResources 343 .toArray(new ResourceDescription[overwrittenResources.size()]); 344 345 } 346 347 380 static ResourceDescription[] move(IResource[] resources, IPath destination, 381 List resourcesAtDestination, List reverseDestinations, 382 IProgressMonitor monitor, IAdaptable uiInfo, 383 boolean pathIncludesName) throws CoreException { 384 385 monitor.beginTask("", resources.length); monitor 387 .setTaskName(UndoMessages.AbstractResourcesOperation_MovingResources); 388 List overwrittenResources = new ArrayList (); 389 for (int i = 0; i < resources.length; i++) { 390 IResource source = resources[i]; 391 IPath destinationPath; 392 if (pathIncludesName) { 393 destinationPath = destination; 394 } else { 395 destinationPath = destination.append(source.getName()); 396 } 397 IWorkspaceRoot workspaceRoot = getWorkspaceRoot(); 398 IResource existing = workspaceRoot.findMember(destinationPath); 399 if (source.getType() == IResource.FOLDER && existing != null) { 400 if (source.isLinked() == existing.isLinked()) { 403 IResource[] children = ((IContainer) source).members(); 404 ResourceDescription[] overwritten = move(children, 405 destinationPath, resourcesAtDestination, 406 reverseDestinations, new SubProgressMonitor( 407 monitor, 1), uiInfo, false); 408 for (int j = 0; j < overwritten.length; j++) { 411 overwrittenResources.add(overwritten[j]); 412 } 413 delete(source, monitor, uiInfo, false, false); 416 } else { 417 ResourceDescription[] deleted = delete( 420 new IResource[] { existing }, 421 new SubProgressMonitor(monitor, 0), uiInfo, false); 422 reverseDestinations.add(source.getFullPath()); 424 source.move(destinationPath, IResource.SHALLOW 425 | IResource.KEEP_HISTORY, new SubProgressMonitor( 426 monitor, 1)); 427 resourcesAtDestination.add(getWorkspace().getRoot() 429 .findMember(destinationPath)); 430 for (int j = 0; j < deleted.length; j++) { 431 overwrittenResources.add(deleted[j]); 432 } 433 } 434 } else { 435 if (existing != null) { 436 if (source.isLinked() == existing.isLinked()) { 437 reverseDestinations.add(source.getFullPath()); 439 overwrittenResources.add(copyOverExistingResource( 440 source, existing, new SubProgressMonitor( 441 monitor, 1), uiInfo, true)); 442 resourcesAtDestination.add(existing); 443 } else { 444 ResourceDescription[] deleted = delete( 447 new IResource[] { existing }, 448 new SubProgressMonitor(monitor, 0), uiInfo, 449 false); 450 reverseDestinations.add(source.getFullPath()); 451 source.move(destinationPath, IResource.SHALLOW 452 | IResource.KEEP_HISTORY, 453 new SubProgressMonitor(monitor, 1)); 454 resourcesAtDestination.add(getWorkspace().getRoot() 456 .findMember(destinationPath)); 457 for (int j = 0; j < deleted.length; j++) { 458 overwrittenResources.add(deleted[j]); 459 } 460 } 461 } else { 462 reverseDestinations.add(source.getFullPath()); 465 IPath parentPath = destination; 467 if (pathIncludesName) { 468 parentPath = destination.removeLastSegments(1); 469 } 470 471 IContainer generatedParent = generateContainers(parentPath); 472 source.move(destinationPath, IResource.SHALLOW 473 | IResource.KEEP_HISTORY, new SubProgressMonitor( 474 monitor, 1)); 475 if (generatedParent == null) { 478 resourcesAtDestination.add(getWorkspace().getRoot() 479 .findMember(destinationPath)); 480 } else { 481 resourcesAtDestination.add(generatedParent); 482 } 483 } 484 485 if (monitor.isCanceled()) { 486 throw new OperationCanceledException(); 487 } 488 } 489 } 490 monitor.done(); 491 return (ResourceDescription[]) overwrittenResources 492 .toArray(new ResourceDescription[overwrittenResources.size()]); 493 494 } 495 496 513 static IResource[] recreate(ResourceDescription[] resourcesToRecreate, 514 IProgressMonitor monitor, IAdaptable uiInfo) throws CoreException { 515 final List exceptions = new ArrayList (); 516 IResource[] resourcesToReturn = new IResource[resourcesToRecreate.length]; 517 monitor.beginTask("", resourcesToRecreate.length); monitor 519 .setTaskName(UndoMessages.AbstractResourcesOperation_CreateResourcesProgress); 520 try { 521 for (int i = 0; i < resourcesToRecreate.length; ++i) { 522 if (monitor.isCanceled()) { 523 throw new OperationCanceledException(); 524 } 525 try { 526 resourcesToReturn[i] = resourcesToRecreate[i] 527 .createResource(new SubProgressMonitor(monitor, 1)); 528 } catch (CoreException e) { 529 exceptions.add(e); 530 } 531 } 532 IStatus result = WorkspaceUndoUtil.createResult(exceptions); 533 if (!result.isOK()) { 534 throw new CoreException(result); 535 } 536 } finally { 537 monitor.done(); 538 } 539 return resourcesToReturn; 540 } 541 542 567 static ResourceDescription delete(IResource resourceToDelete, 568 IProgressMonitor monitor, IAdaptable uiInfo, 569 boolean forceOutOfSyncDelete, boolean deleteContent) 570 throws CoreException { 571 ResourceDescription resourceDescription = ResourceDescription 572 .fromResource(resourceToDelete); 573 if (resourceToDelete.getType() == IResource.PROJECT) { 574 monitor 576 .setTaskName(UndoMessages.AbstractResourcesOperation_DeleteResourcesProgress); 577 IProject project = (IProject) resourceToDelete; 578 project.delete(deleteContent, forceOutOfSyncDelete, monitor); 579 } else { 580 monitor.beginTask("", 2); monitor 583 .setTaskName(UndoMessages.AbstractResourcesOperation_DeleteResourcesProgress); 584 int updateFlags; 585 if (forceOutOfSyncDelete) { 586 updateFlags = IResource.KEEP_HISTORY | IResource.FORCE; 587 } else { 588 updateFlags = IResource.KEEP_HISTORY; 589 } 590 resourceToDelete.delete(updateFlags, new SubProgressMonitor( 591 monitor, 1)); 592 resourceDescription.recordStateFromHistory(resourceToDelete, 593 new SubProgressMonitor(monitor, 1)); 594 monitor.done(); 595 } 596 597 return resourceDescription; 598 } 599 600 605 private static ResourceDescription copyOverExistingResource( 606 IResource source, IResource existing, IProgressMonitor monitor, 607 IAdaptable uiInfo, boolean deleteSourceFile) throws CoreException { 608 if (!(source instanceof IFile && existing instanceof IFile)) { 609 return null; 610 } 611 IFile file = (IFile) source; 612 IFile existingFile = (IFile) existing; 613 monitor 614 .beginTask( 615 UndoMessages.AbstractResourcesOperation_CopyingResourcesProgress, 616 3); 617 if (file != null && existingFile != null) { 618 if (validateEdit(file, existingFile, getShell(uiInfo))) { 619 FileDescription fileDescription = new FileDescription( 622 existingFile); 623 existingFile.setContents(file.getContents(), 625 IResource.KEEP_HISTORY, new SubProgressMonitor(monitor, 626 1)); 627 fileDescription.recordStateFromHistory(existingFile, 628 new SubProgressMonitor(monitor, 1)); 629 if (deleteSourceFile) { 634 file.delete(IResource.KEEP_HISTORY, new SubProgressMonitor( 635 monitor, 1)); 636 } 637 monitor.done(); 638 return fileDescription; 639 } 640 } 641 monitor.done(); 642 return null; 643 } 644 645 650 private static IContainer generateContainers(IPath path) 651 throws CoreException { 652 IResource container; 653 if (path.segmentCount() == 0) { 654 return null; 656 } 657 container = getWorkspaceRoot().findMember(path); 658 if (container != null) { 660 return null; 661 } 662 663 if (path.segmentCount() == 1) { 665 container = ResourcesPlugin.getWorkspace().getRoot().getProject( 666 path.segment(0)); 667 } else { 668 container = ResourcesPlugin.getWorkspace().getRoot() 669 .getFolder(path); 670 } 671 ContainerDescription containerDescription = ContainerDescription 672 .fromContainer((IContainer) container); 673 container = containerDescription.createResourceHandle(); 674 containerDescription.createExistentResourceFromHandle(container, 675 new NullProgressMonitor()); 676 return (IContainer) container; 677 } 678 679 686 private static int queryDeleteOutOfSync(IResource resource, 687 IAdaptable uiInfo) { 688 Shell shell = getShell(uiInfo); 689 final MessageDialog dialog = new MessageDialog( 690 shell, 691 UndoMessages.AbstractResourcesOperation_deletionMessageTitle, 692 null, 693 NLS 694 .bind( 695 UndoMessages.AbstractResourcesOperation_outOfSyncQuestion, 696 resource.getName()), MessageDialog.QUESTION, 697 new String [] { IDialogConstants.YES_LABEL, 698 IDialogConstants.YES_TO_ALL_LABEL, 699 IDialogConstants.NO_LABEL, 700 IDialogConstants.CANCEL_LABEL }, 0); 701 shell.getDisplay().syncExec(new Runnable () { 702 public void run() { 703 dialog.open(); 704 } 705 }); 706 int result = dialog.getReturnCode(); 707 if (result == 0) { 708 return IDialogConstants.YES_ID; 709 } 710 if (result == 1) { 711 return IDialogConstants.YES_TO_ALL_ID; 712 } 713 if (result == 2) { 714 return IDialogConstants.NO_ID; 715 } 716 return IDialogConstants.CANCEL_ID; 717 } 718 719 723 private static IStatus createResult(List exceptions) { 724 if (exceptions.isEmpty()) { 725 return Status.OK_STATUS; 726 } 727 final int exceptionCount = exceptions.size(); 728 if (exceptionCount == 1) { 729 return ((CoreException) exceptions.get(0)).getStatus(); 730 } 731 CoreException[] children = (CoreException[]) exceptions 732 .toArray(new CoreException[exceptionCount]); 733 boolean outOfSync = false; 734 for (int i = 0; i < children.length; i++) { 735 if (children[i].getStatus().getCode() == IResourceStatus.OUT_OF_SYNC_LOCAL) { 736 outOfSync = true; 737 break; 738 } 739 } 740 String title = outOfSync ? UndoMessages.AbstractResourcesOperation_outOfSyncError 741 : UndoMessages.AbstractResourcesOperation_deletionExceptionMessage; 742 final MultiStatus multi = new MultiStatus( 743 IDEWorkbenchPlugin.IDE_WORKBENCH, 0, title, null); 744 for (int i = 0; i < exceptionCount; i++) { 745 CoreException exception = children[i]; 746 IStatus status = exception.getStatus(); 747 multi.add(new Status(status.getSeverity(), status.getPlugin(), 748 status.getCode(), status.getMessage(), exception)); 749 } 750 return multi; 751 } 752 753 756 private static IWorkspace getWorkspace() { 757 return ResourcesPlugin.getWorkspace(); 758 } 759 760 763 private static IWorkspaceRoot getWorkspaceRoot() { 764 return getWorkspace().getRoot(); 765 } 766 767 772 private static boolean validateEdit(IFile source, IFile destination, 773 Shell shell) { 774 if (destination.isReadOnly()) { 775 IWorkspace workspace = WorkspaceUndoUtil.getWorkspace(); 776 IStatus status; 777 if (source.isReadOnly()) { 778 status = workspace.validateEdit(new IFile[] { source, 779 destination }, shell); 780 } else { 781 status = workspace.validateEdit(new IFile[] { destination }, 782 shell); 783 } 784 return status.isOK(); 785 } 786 return true; 787 } 788 789 802 public static Shell getShell(IAdaptable uiInfo) { 803 if (uiInfo != null) { 804 Shell shell = (Shell) uiInfo.getAdapter(Shell.class); 805 if (shell != null) { 806 return shell; 807 } 808 } 809 return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); 810 } 811 } 812 | Popular Tags |