001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Red Hat, Inc - changed TarFileStructureProvider to TarLeveledStructureProvider
011: *******************************************************************************/package org.eclipse.ui.wizards.datatransfer;
012:
013: import java.io.File;
014: import java.io.IOException;
015: import java.io.InputStream;
016: import java.util.ArrayList;
017: import java.util.Arrays;
018: import java.util.Iterator;
019: import java.util.List;
020:
021: import org.eclipse.core.resources.IContainer;
022: import org.eclipse.core.resources.IFile;
023: import org.eclipse.core.resources.IFolder;
024: import org.eclipse.core.resources.IResource;
025: import org.eclipse.core.resources.IWorkspace;
026: import org.eclipse.core.resources.IWorkspaceRoot;
027: import org.eclipse.core.resources.ResourceAttributes;
028: import org.eclipse.core.resources.ResourcesPlugin;
029: import org.eclipse.core.runtime.CoreException;
030: import org.eclipse.core.runtime.IAdaptable;
031: import org.eclipse.core.runtime.IPath;
032: import org.eclipse.core.runtime.IProgressMonitor;
033: import org.eclipse.core.runtime.IStatus;
034: import org.eclipse.core.runtime.MultiStatus;
035: import org.eclipse.core.runtime.OperationCanceledException;
036: import org.eclipse.core.runtime.Path;
037: import org.eclipse.core.runtime.Status;
038: import org.eclipse.core.runtime.SubProgressMonitor;
039: import org.eclipse.osgi.util.NLS;
040: import org.eclipse.swt.widgets.Shell;
041: import org.eclipse.ui.PlatformUI;
042: import org.eclipse.ui.actions.WorkspaceModifyOperation;
043: import org.eclipse.ui.dialogs.ContainerGenerator;
044: import org.eclipse.ui.dialogs.IOverwriteQuery;
045: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
046: import org.eclipse.ui.internal.wizards.datatransfer.DataTransferMessages;
047: import org.eclipse.ui.internal.wizards.datatransfer.TarLeveledStructureProvider;
048:
049: /**
050: * An operation which does the actual work of copying objects from the local file
051: * system into the workspace.
052: * <p>
053: * This class may be instantiated; it is not intended to be subclassed.
054: * </p>
055: */
056: public class ImportOperation extends WorkspaceModifyOperation {
057: private static final int POLICY_DEFAULT = 0;
058:
059: private static final int POLICY_SKIP_CHILDREN = 1;
060:
061: private static final int POLICY_FORCE_OVERWRITE = 2;
062:
063: private Object source;
064:
065: private IPath destinationPath;
066:
067: private IContainer destinationContainer;
068:
069: private List selectedFiles;
070:
071: private List rejectedFiles;
072:
073: private IImportStructureProvider provider;
074:
075: private IProgressMonitor monitor;
076:
077: protected IOverwriteQuery overwriteCallback;
078:
079: private Shell context;
080:
081: private List errorTable = new ArrayList();
082:
083: private boolean createContainerStructure = true;
084:
085: //The constants for the overwrite 3 state
086: private static final int OVERWRITE_NOT_SET = 0;
087:
088: private static final int OVERWRITE_NONE = 1;
089:
090: private static final int OVERWRITE_ALL = 2;
091:
092: private int overwriteState = OVERWRITE_NOT_SET;
093:
094: /**
095: * Creates a new operation that recursively imports the entire contents of the
096: * specified root file system object.
097: * <p>
098: * The <code>source</code> parameter represents the root file system object to
099: * import. All contents of this object are imported. Valid types for this parameter
100: * are determined by the supplied <code>IImportStructureProvider</code>.
101: * </p>
102: * <p>
103: * The <code>provider</code> parameter allows this operation to deal with the
104: * source object in an abstract way. This operation calls methods on the provider
105: * and the provider in turn calls specific methods on the source object.
106: * </p>
107: * <p>
108: * The default import behavior is to recreate the complete container structure
109: * for the contents of the root file system object in their destination.
110: * If <code>setCreateContainerStructure</code> is set to false then the container
111: * structure created is relative to the root file system object.
112: * </p>
113: *
114: * @param containerPath the full path of the destination container within the
115: * workspace
116: * @param source the root file system object to import
117: * @param provider the file system structure provider to use
118: * @param overwriteImplementor the overwrite strategy to use
119: */
120: public ImportOperation(IPath containerPath, Object source,
121: IImportStructureProvider provider,
122: IOverwriteQuery overwriteImplementor) {
123: super ();
124: this .destinationPath = containerPath;
125: this .source = source;
126: this .provider = provider;
127: overwriteCallback = overwriteImplementor;
128: }
129:
130: /**
131: * Creates a new operation that imports specific file system objects.
132: * In this usage context, the specified source file system object is used by the
133: * operation solely to determine the destination container structure of the file system
134: * objects being imported.
135: * <p>
136: * The <code>source</code> parameter represents the root file system object to
137: * import. Valid types for this parameter are determined by the supplied
138: * <code>IImportStructureProvider</code>. The contents of the source which
139: * are to be imported are specified in the <code>filesToImport</code>
140: * parameter.
141: * </p>
142: * <p>
143: * The <code>provider</code> parameter allows this operation to deal with the
144: * source object in an abstract way. This operation calls methods on the provider
145: * and the provider in turn calls specific methods on the source object.
146: * </p>
147: * <p>
148: * The <code>filesToImport</code> parameter specifies what contents of the root
149: * file system object are to be imported.
150: * </p>
151: * <p>
152: * The default import behavior is to recreate the complete container structure
153: * for the file system objects in their destination. If <code>setCreateContainerStructure</code>
154: * is set to <code>false</code>, then the container structure created for each of
155: * the file system objects is relative to the supplied root file system object.
156: * </p>
157: *
158: * @param containerPath the full path of the destination container within the
159: * workspace
160: * @param source the root file system object to import from
161: * @param provider the file system structure provider to use
162: * @param overwriteImplementor the overwrite strategy to use
163: * @param filesToImport the list of file system objects to be imported
164: * (element type: <code>Object</code>)
165: */
166: public ImportOperation(IPath containerPath, Object source,
167: IImportStructureProvider provider,
168: IOverwriteQuery overwriteImplementor, List filesToImport) {
169: this (containerPath, source, provider, overwriteImplementor);
170: setFilesToImport(filesToImport);
171: }
172:
173: /**
174: * Creates a new operation that imports specific file system objects.
175: * <p>
176: * The <code>provider</code> parameter allows this operation to deal with the
177: * source object in an abstract way. This operation calls methods on the provider
178: * and the provider in turn calls specific methods on the source object.
179: * </p>
180: * <p>
181: * The <code>filesToImport</code> parameter specifies what file system objects
182: * are to be imported.
183: * </p>
184: * <p>
185: * The default import behavior is to recreate the complete container structure
186: * for the file system objects in their destination. If <code>setCreateContainerStructure</code>
187: * is set to <code>false</code>, then no container structure is created for each of
188: * the file system objects.
189: * </p>
190: *
191: * @param containerPath the full path of the destination container within the
192: * workspace
193: * @param provider the file system structure provider to use
194: * @param overwriteImplementor the overwrite strategy to use
195: * @param filesToImport the list of file system objects to be imported
196: * (element type: <code>Object</code>)
197: */
198: public ImportOperation(IPath containerPath,
199: IImportStructureProvider provider,
200: IOverwriteQuery overwriteImplementor, List filesToImport) {
201: this (containerPath, null, provider, overwriteImplementor);
202: setFilesToImport(filesToImport);
203: }
204:
205: /**
206: * Prompts if existing resources should be overwritten. Recursively collects
207: * existing read-only files to overwrite and resources that should not be
208: * overwritten.
209: *
210: * @param sourceStart destination path to check for existing files
211: * @param sources file system objects that may exist in the destination
212: * @param noOverwrite files that were selected to be skipped (don't overwrite).
213: * object type IPath
214: * @param overwriteReadonly the collected existing read-only files to overwrite.
215: * object type IPath
216: * @param policy on of the POLICY constants defined in the
217: * class.
218: */
219: void collectExistingReadonlyFiles(IPath sourceStart, List sources,
220: ArrayList noOverwrite, ArrayList overwriteReadonly,
221: int policy) {
222: IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace()
223: .getRoot();
224: Iterator sourceIter = sources.iterator();
225: IPath sourceRootPath = null;
226:
227: if (this .source != null) {
228: sourceRootPath = new Path(provider.getFullPath(this .source));
229: }
230: while (sourceIter.hasNext()) {
231: Object nextSource = sourceIter.next();
232: IPath sourcePath = new Path(provider
233: .getFullPath(nextSource));
234: IPath newDestinationPath;
235: IResource newDestination;
236:
237: if (sourceRootPath == null) {
238: newDestinationPath = sourceStart.append(provider
239: .getLabel(nextSource));
240: } else {
241: int prefixLength = sourcePath
242: .matchingFirstSegments(sourceRootPath);
243: IPath relativeSourcePath = sourcePath
244: .removeFirstSegments(prefixLength);
245: newDestinationPath = this .destinationPath
246: .append(relativeSourcePath);
247: }
248: newDestination = workspaceRoot
249: .findMember(newDestinationPath);
250: if (newDestination == null) {
251: continue;
252: }
253:
254: IFolder folder = getFolder(newDestination);
255: if (folder != null) {
256: if (policy != POLICY_FORCE_OVERWRITE) {
257: if (this .overwriteState == OVERWRITE_NONE
258: || !queryOverwrite(newDestinationPath)) {
259: noOverwrite.add(folder);
260: continue;
261: }
262: }
263: if (provider.isFolder(nextSource)) {
264: collectExistingReadonlyFiles(newDestinationPath,
265: provider.getChildren(nextSource),
266: noOverwrite, overwriteReadonly,
267: POLICY_FORCE_OVERWRITE);
268: }
269: } else {
270: IFile file = getFile(newDestination);
271:
272: if (file != null) {
273: if (!queryOverwriteFile(file, policy)) {
274: noOverwrite.add(file.getFullPath());
275: } else if (file.isReadOnly()) {
276: overwriteReadonly.add(file);
277: }
278: }
279: }
280: }
281: }
282:
283: /**
284: * Creates the folders that appear in the specified resource path.
285: * These folders are created relative to the destination container.
286: *
287: * @param path the relative path of the resource
288: * @return the container resource coresponding to the given path
289: * @exception CoreException if this method failed
290: */
291: IContainer createContainersFor(IPath path) throws CoreException {
292:
293: IContainer currentFolder = destinationContainer;
294:
295: int segmentCount = path.segmentCount();
296:
297: //No containers to create
298: if (segmentCount == 0) {
299: return currentFolder;
300: }
301:
302: //Needs to be handles differently at the root
303: if (currentFolder.getType() == IResource.ROOT) {
304: return createFromRoot(path);
305: }
306:
307: for (int i = 0; i < segmentCount; i++) {
308: currentFolder = currentFolder.getFolder(new Path(path
309: .segment(i)));
310: if (!currentFolder.exists()) {
311: ((IFolder) currentFolder).create(false, true, null);
312: }
313: }
314:
315: return currentFolder;
316: }
317:
318: /**
319: * Creates the folders that appear in the specified resource path
320: * assuming that the destinationContainer begins at the root. Do not create projects.
321: *
322: * @param path the relative path of the resource
323: * @return the container resource coresponding to the given path
324: * @exception CoreException if this method failed
325: */
326: private IContainer createFromRoot(IPath path) throws CoreException {
327:
328: int segmentCount = path.segmentCount();
329:
330: //Assume the project exists
331: IContainer currentFolder = ((IWorkspaceRoot) destinationContainer)
332: .getProject(path.segment(0));
333:
334: for (int i = 1; i < segmentCount; i++) {
335: currentFolder = currentFolder.getFolder(new Path(path
336: .segment(i)));
337: if (!currentFolder.exists()) {
338: ((IFolder) currentFolder).create(false, true, null);
339: }
340: }
341:
342: return currentFolder;
343: }
344:
345: /**
346: * Deletes the given resource. If the resource fails to be deleted, adds a
347: * status object to the list to be returned by <code>getResult</code>.
348: *
349: * @param resource the resource
350: */
351: void deleteResource(IResource resource) {
352: try {
353: resource.delete(IResource.KEEP_HISTORY, null);
354: } catch (CoreException e) {
355: errorTable.add(e.getStatus());
356: }
357: }
358:
359: /* (non-Javadoc)
360: * Method declared on WorkbenchModifyOperation.
361: * Imports the specified file system objects from the file system.
362: */
363: protected void execute(IProgressMonitor progressMonitor) {
364:
365: monitor = progressMonitor;
366:
367: try {
368: if (selectedFiles == null) {
369: //Set the amount to 1000 as we have no idea of how long this will take
370: monitor.beginTask(
371: DataTransferMessages.DataTransfer_importTask,
372: 1000);
373: ContainerGenerator generator = new ContainerGenerator(
374: destinationPath);
375: monitor.worked(30);
376: validateFiles(Arrays.asList(new Object[] { source }));
377: monitor.worked(50);
378: destinationContainer = generator
379: .generateContainer(new SubProgressMonitor(
380: monitor, 50));
381: importRecursivelyFrom(source, POLICY_DEFAULT);
382: //Be sure it finishes
383: monitor.worked(90);
384: } else {
385: // Choose twice the selected files size to take folders into account
386: int creationCount = selectedFiles.size();
387: monitor.beginTask(
388: DataTransferMessages.DataTransfer_importTask,
389: creationCount + 100);
390: ContainerGenerator generator = new ContainerGenerator(
391: destinationPath);
392: monitor.worked(30);
393: validateFiles(selectedFiles);
394: monitor.worked(50);
395: destinationContainer = generator
396: .generateContainer(new SubProgressMonitor(
397: monitor, 50));
398: importFileSystemObjects(selectedFiles);
399: monitor.done();
400: }
401: } catch (CoreException e) {
402: errorTable.add(e.getStatus());
403: } finally {
404: monitor.done();
405: }
406: }
407:
408: /**
409: * Returns the container resource that the passed file system object should be
410: * imported into.
411: *
412: * @param fileSystemObject the file system object being imported
413: * @return the container resource that the passed file system object should be
414: * imported into
415: * @exception CoreException if this method failed
416: */
417: IContainer getDestinationContainerFor(Object fileSystemObject)
418: throws CoreException {
419: IPath pathname = new Path(provider
420: .getFullPath(fileSystemObject));
421:
422: if (createContainerStructure) {
423: return createContainersFor(pathname.removeLastSegments(1));
424: }
425: if (source == fileSystemObject) {
426: return null;
427: }
428: IPath sourcePath = new Path(provider.getFullPath(source));
429: IPath destContainerPath = pathname.removeLastSegments(1);
430: IPath relativePath = destContainerPath.removeFirstSegments(
431: sourcePath.segmentCount()).setDevice(null);
432: return createContainersFor(relativePath);
433:
434: }
435:
436: /**
437: * Returns the resource either casted to or adapted to an IFile.
438: *
439: * @param resource resource to cast/adapt
440: * @return the resource either casted to or adapted to an IFile.
441: * <code>null</code> if the resource does not adapt to IFile
442: */
443: IFile getFile(IResource resource) {
444: if (resource instanceof IFile) {
445: return (IFile) resource;
446: }
447: Object adapted = ((IAdaptable) resource)
448: .getAdapter(IFile.class);
449: if (adapted == null) {
450: return null;
451: }
452: return (IFile) adapted;
453:
454: }
455:
456: /**
457: * Returns the resource either casted to or adapted to an IFolder.
458: *
459: * @param resource resource to cast/adapt
460: * @return the resource either casted to or adapted to an IFolder.
461: * <code>null</code> if the resource does not adapt to IFolder
462: */
463: IFolder getFolder(IResource resource) {
464: if (resource instanceof IFolder) {
465: return (IFolder) resource;
466: }
467: Object adapted = ((IAdaptable) resource)
468: .getAdapter(IFolder.class);
469: if (adapted == null) {
470: return null;
471: }
472: return (IFolder) adapted;
473: }
474:
475: /**
476: * Returns the rejected files based on the given multi status.
477: *
478: * @param multiStatus multi status to use to determine file rejection
479: * @param files source files
480: * @return list of rejected files as absolute paths. Object type IPath.
481: */
482: ArrayList getRejectedFiles(IStatus multiStatus, IFile[] files) {
483: ArrayList filteredFiles = new ArrayList();
484:
485: IStatus[] status = multiStatus.getChildren();
486: for (int i = 0; i < status.length; i++) {
487: if (status[i].isOK() == false) {
488: errorTable.add(status[i]);
489: filteredFiles.add(files[i].getFullPath());
490: }
491: }
492: return filteredFiles;
493: }
494:
495: /**
496: * Returns the status of the import operation.
497: * If there were any errors, the result is a status object containing
498: * individual status objects for each error.
499: * If there were no errors, the result is a status object with error code <code>OK</code>.
500: *
501: * @return the status
502: */
503: public IStatus getStatus() {
504: IStatus[] errors = new IStatus[errorTable.size()];
505: errorTable.toArray(errors);
506: return new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK,
507: errors,
508: DataTransferMessages.ImportOperation_importProblems,
509: null);
510: }
511:
512: /**
513: * Imports the specified file system object into the workspace.
514: * If the import fails, adds a status object to the list to be returned by
515: * <code>getResult</code>.
516: *
517: * @param fileObject the file system object to be imported
518: * @param policy determines how the file object is imported
519: */
520: void importFile(Object fileObject, int policy) {
521: IContainer containerResource;
522: try {
523: containerResource = getDestinationContainerFor(fileObject);
524: } catch (CoreException e) {
525: IStatus coreStatus = e.getStatus();
526: String newMessage = NLS
527: .bind(
528: DataTransferMessages.ImportOperation_coreImportError,
529: fileObject, coreStatus.getMessage());
530: IStatus status = new Status(coreStatus.getSeverity(),
531: coreStatus.getPlugin(), coreStatus.getCode(),
532: newMessage, null);
533: errorTable.add(status);
534: return;
535: }
536:
537: String fileObjectPath = provider.getFullPath(fileObject);
538: monitor.subTask(fileObjectPath);
539: IFile targetResource = containerResource.getFile(new Path(
540: provider.getLabel(fileObject)));
541: monitor.worked(1);
542:
543: if (rejectedFiles.contains(targetResource.getFullPath())) {
544: return;
545: }
546:
547: // ensure that the source and target are not the same
548: IPath targetPath = targetResource.getLocation();
549: // Use Files for comparison to avoid platform specific case issues
550: if (targetPath != null
551: && (targetPath.toFile()
552: .equals(new File(fileObjectPath)))) {
553: errorTable
554: .add(new Status(
555: IStatus.ERROR,
556: PlatformUI.PLUGIN_ID,
557: 0,
558: NLS
559: .bind(
560: DataTransferMessages.ImportOperation_targetSameAsSourceError,
561: fileObjectPath), null));
562: return;
563: }
564:
565: InputStream contentStream = provider.getContents(fileObject);
566: if (contentStream == null) {
567: errorTable
568: .add(new Status(
569: IStatus.ERROR,
570: PlatformUI.PLUGIN_ID,
571: 0,
572: NLS
573: .bind(
574: DataTransferMessages.ImportOperation_openStreamError,
575: fileObjectPath), null));
576: return;
577: }
578:
579: try {
580: if (targetResource.exists()) {
581: targetResource.setContents(contentStream,
582: IResource.KEEP_HISTORY, null);
583: } else {
584: targetResource.create(contentStream, false, null);
585: }
586: setResourceAttributes(targetResource, fileObject);
587:
588: if (provider instanceof TarLeveledStructureProvider) {
589: try {
590: targetResource
591: .setResourceAttributes(((TarLeveledStructureProvider) provider)
592: .getResourceAttributes(fileObject));
593: } catch (CoreException e) {
594: errorTable.add(e.getStatus());
595: }
596: }
597: } catch (CoreException e) {
598: errorTable.add(e.getStatus());
599: } finally {
600: try {
601: contentStream.close();
602: } catch (IOException e) {
603: errorTable
604: .add(new Status(
605: IStatus.ERROR,
606: PlatformUI.PLUGIN_ID,
607: 0,
608: NLS
609: .bind(
610: DataTransferMessages.ImportOperation_closeStreamError,
611: fileObjectPath), e));
612: }
613: }
614: }
615:
616: /**
617: * Reuse the file attributes set in the import.
618: * @param targetResource
619: * @param fileObject
620: */
621: private void setResourceAttributes(IFile targetResource,
622: Object fileObject) {
623:
624: if (fileObject instanceof File) {
625: try {
626: targetResource.setResourceAttributes(ResourceAttributes
627: .fromFile((File) fileObject));
628: } catch (CoreException e) {
629: //Inform the log that the attributes reading failed
630: IDEWorkbenchPlugin.log(e.getStatus().getMessage(), e);
631: }
632: }
633:
634: }
635:
636: /**
637: * Imports the specified file system objects into the workspace.
638: * If the import fails, adds a status object to the list to be returned by
639: * <code>getStatus</code>.
640: *
641: * @param filesToImport the list of file system objects to import
642: * (element type: <code>Object</code>)
643: * @exception OperationCanceledException if canceled
644: */
645: void importFileSystemObjects(List filesToImport) {
646: Iterator filesEnum = filesToImport.iterator();
647: while (filesEnum.hasNext()) {
648: Object fileSystemObject = filesEnum.next();
649: if (source == null) {
650: // We just import what we are given into the destination
651: IPath sourcePath = new Path(provider
652: .getFullPath(fileSystemObject))
653: .removeLastSegments(1);
654: if (provider.isFolder(fileSystemObject)
655: && sourcePath.isEmpty()) {
656: // If we don't have a parent then we have selected the
657: // file systems root. Roots can't copied (at least not
658: // under windows).
659: errorTable
660: .add(new Status(
661: IStatus.INFO,
662: PlatformUI.PLUGIN_ID,
663: 0,
664: DataTransferMessages.ImportOperation_cannotCopy,
665: null));
666: continue;
667: }
668: source = sourcePath.toFile();
669: }
670: importRecursivelyFrom(fileSystemObject, POLICY_DEFAULT);
671: }
672: }
673:
674: /**
675: * Imports the specified file system container object into the workspace.
676: * If the import fails, adds a status object to the list to be returned by
677: * <code>getResult</code>.
678: *
679: * @param folderObject the file system container object to be imported
680: * @param policy determines how the folder object and children are imported
681: * @return the policy to use to import the folder's children
682: */
683: int importFolder(Object folderObject, int policy) {
684: IContainer containerResource;
685: try {
686: containerResource = getDestinationContainerFor(folderObject);
687: } catch (CoreException e) {
688: errorTable.add(e.getStatus());
689: return policy;
690: }
691:
692: if (containerResource == null) {
693: return policy;
694: }
695:
696: monitor.subTask(provider.getFullPath(folderObject));
697: IWorkspace workspace = destinationContainer.getWorkspace();
698: IPath containerPath = containerResource.getFullPath();
699: IPath resourcePath = containerPath.append(provider
700: .getLabel(folderObject));
701:
702: // Do not attempt the import if the resource path is unchanged. This may happen
703: // when importing from a zip file.
704: if (resourcePath.equals(containerPath)) {
705: return policy;
706: }
707:
708: if (workspace.getRoot().exists(resourcePath)) {
709: if (rejectedFiles.contains(resourcePath)) {
710: return POLICY_SKIP_CHILDREN;
711: }
712:
713: return POLICY_FORCE_OVERWRITE;
714: }
715:
716: try {
717: workspace.getRoot().getFolder(resourcePath).create(false,
718: true, null);
719: } catch (CoreException e) {
720: errorTable.add(e.getStatus());
721: }
722:
723: return policy;
724: }
725:
726: /**
727: * Imports the specified file system object recursively into the workspace.
728: * If the import fails, adds a status object to the list to be returned by
729: * <code>getStatus</code>.
730: *
731: * @param fileSystemObject the file system object to be imported
732: * @param policy determines how the file system object and children are imported
733: * @exception OperationCanceledException if canceled
734: */
735: void importRecursivelyFrom(Object fileSystemObject, int policy) {
736: if (monitor.isCanceled()) {
737: throw new OperationCanceledException();
738: }
739:
740: if (!provider.isFolder(fileSystemObject)) {
741: importFile(fileSystemObject, policy);
742: return;
743: }
744:
745: int childPolicy = importFolder(fileSystemObject, policy);
746: if (childPolicy != POLICY_SKIP_CHILDREN) {
747: Iterator children = provider.getChildren(fileSystemObject)
748: .iterator();
749: while (children.hasNext()) {
750: importRecursivelyFrom(children.next(), childPolicy);
751: }
752: }
753: }
754:
755: /**
756: * Queries the user whether the resource with the specified path should be
757: * overwritten by a file system object that is being imported.
758: *
759: * @param resourcePath the workspace path of the resource that needs to be overwritten
760: * @return <code>true</code> to overwrite, <code>false</code> to not overwrite
761: * @exception OperationCanceledException if canceled
762: */
763: boolean queryOverwrite(IPath resourcePath)
764: throws OperationCanceledException {
765: String overwriteAnswer = overwriteCallback
766: .queryOverwrite(resourcePath.makeRelative().toString());
767:
768: if (overwriteAnswer.equals(IOverwriteQuery.CANCEL)) {
769: throw new OperationCanceledException(
770: DataTransferMessages.DataTransfer_emptyString);
771: }
772:
773: if (overwriteAnswer.equals(IOverwriteQuery.NO)) {
774: return false;
775: }
776:
777: if (overwriteAnswer.equals(IOverwriteQuery.NO_ALL)) {
778: this .overwriteState = OVERWRITE_NONE;
779: return false;
780: }
781:
782: if (overwriteAnswer.equals(IOverwriteQuery.ALL)) {
783: this .overwriteState = OVERWRITE_ALL;
784: }
785:
786: return true;
787: }
788:
789: /**
790: * Returns whether the given file should be overwritten.
791: *
792: * @param targetFile the file to ask to overwrite
793: * @param policy determines if the user is queried for overwrite
794: * @return <code>true</code> if the file should be overwritten, and
795: * <code>false</code> if not.
796: */
797: boolean queryOverwriteFile(IFile targetFile, int policy) {
798: //If force overwrite is on don't bother
799: if (policy != POLICY_FORCE_OVERWRITE) {
800: if (this .overwriteState == OVERWRITE_NOT_SET
801: && !queryOverwrite(targetFile.getFullPath())) {
802: return false;
803: }
804: if (this .overwriteState == OVERWRITE_NONE) {
805: return false;
806: }
807: }
808: return true;
809: }
810:
811: /**
812: * Sets the context for use by the VCM provider to prompt the user
813: * for check-out of files.
814: *
815: * @param shell context for use by the VCM provider to prompt user
816: * for check-out. The user will not be prompted if set to <code>null</code>.
817: * @see IWorkspace#validateEdit(org.eclipse.core.resources.IFile[], java.lang.Object)
818: * @since 2.1
819: */
820: public void setContext(Shell shell) {
821: context = shell;
822: }
823:
824: /**
825: * Sets whether the containment structures that are implied from the full paths
826: * of file system objects being imported should be duplicated in the workbench.
827: *
828: * @param value <code>true</code> if containers should be created, and
829: * <code>false</code> otherwise
830: */
831: public void setCreateContainerStructure(boolean value) {
832: createContainerStructure = value;
833: }
834:
835: /**
836: * Sets the file system objects to import.
837: *
838: * @param filesToImport the list of file system objects to be imported
839: * (element type: <code>Object</code>)
840: */
841: public void setFilesToImport(List filesToImport) {
842: this .selectedFiles = filesToImport;
843: }
844:
845: /**
846: * Sets whether imported file system objects should automatically overwrite
847: * existing workbench resources when a conflict occurs.
848: *
849: * @param value <code>true</code> to automatically overwrite, and
850: * <code>false</code> otherwise
851: */
852: public void setOverwriteResources(boolean value) {
853: if (value) {
854: this .overwriteState = OVERWRITE_ALL;
855: }
856: }
857:
858: /**
859: * Validates that the given source resources can be copied to the
860: * destination as decided by the VCM provider.
861: *
862: * @param existingFiles existing files to validate
863: * @return list of rejected files as absolute paths. Object type IPath.
864: */
865: ArrayList validateEdit(List existingFiles) {
866:
867: if (existingFiles.size() > 0) {
868: IFile[] files = (IFile[]) existingFiles
869: .toArray(new IFile[existingFiles.size()]);
870: IWorkspace workspace = ResourcesPlugin.getWorkspace();
871: IStatus status = workspace.validateEdit(files, context);
872:
873: //If there was a mix return the bad ones
874: if (status.isMultiStatus()) {
875: return getRejectedFiles(status, files);
876: }
877:
878: if (!status.isOK()) {
879: //If just a single status reject them all
880: errorTable.add(status);
881: ArrayList filteredFiles = new ArrayList();
882:
883: for (int i = 0; i < files.length; i++) {
884: filteredFiles.add(files[i].getFullPath());
885: }
886: return filteredFiles;
887: }
888:
889: }
890: return new ArrayList();
891: }
892:
893: /**
894: * Validates the given file system objects.
895: * The user is prompted to overwrite existing files.
896: * Existing read-only files are validated with the VCM provider.
897: *
898: * @param sourceFiles files to validate
899: */
900: void validateFiles(List sourceFiles) {
901: ArrayList noOverwrite = new ArrayList();
902: ArrayList overwriteReadonly = new ArrayList();
903:
904: collectExistingReadonlyFiles(destinationPath, sourceFiles,
905: noOverwrite, overwriteReadonly, POLICY_DEFAULT);
906: rejectedFiles = validateEdit(overwriteReadonly);
907: rejectedFiles.addAll(noOverwrite);
908: }
909: }
|