| /******************************************************************************* |
| * Copyright (c) 2011, 2015 Wind River Systems, Inc. and others. All rights reserved. |
| * This program and the accompanying materials are made available under the terms |
| * of the Eclipse Public License v1.0 which accompanies this distribution, and is |
| * available at http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Wind River Systems - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.tcf.te.tcf.filesystem.core.internal.operations; |
| |
| import static java.text.MessageFormat.format; |
| |
| import java.util.ArrayList; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.tcf.protocol.IToken; |
| import org.eclipse.tcf.protocol.Protocol; |
| import org.eclipse.tcf.services.IFileSystem; |
| import org.eclipse.tcf.services.IFileSystem.DoneRemove; |
| import org.eclipse.tcf.services.IFileSystem.DoneRename; |
| import org.eclipse.tcf.services.IFileSystem.FileSystemException; |
| import org.eclipse.tcf.te.tcf.filesystem.core.interfaces.IConfirmCallback; |
| import org.eclipse.tcf.te.tcf.filesystem.core.interfaces.runtime.IFSTreeNode; |
| import org.eclipse.tcf.te.tcf.filesystem.core.internal.FSTreeNode; |
| import org.eclipse.tcf.te.tcf.filesystem.core.internal.utils.CacheManager; |
| import org.eclipse.tcf.te.tcf.filesystem.core.internal.utils.StatusHelper; |
| import org.eclipse.tcf.te.tcf.filesystem.core.nls.Messages; |
| |
| /** |
| * FSMove moves specified tree nodes to a destination folder. |
| */ |
| public class OpMove extends AbstractOperation { |
| private static class WorkItem { |
| final WorkItem fParent; |
| final FSTreeNode fDestination; |
| final FSTreeNode fSource; |
| boolean fContentCleared = false; |
| boolean fContentLeftOK = false; |
| |
| WorkItem(FSTreeNode source, FSTreeNode destination) { |
| this(null, source, destination); |
| } |
| |
| WorkItem(WorkItem parent, FSTreeNode source, FSTreeNode destination) { |
| fParent = parent; |
| fSource = source; |
| fDestination = destination; |
| } |
| |
| void setContentLeftOK() { |
| fContentLeftOK = true; |
| if (fParent != null) |
| fParent.setContentLeftOK(); |
| } |
| |
| } |
| |
| IConfirmCallback fConfirmCallback; |
| |
| LinkedList<WorkItem> fWork = new LinkedList<WorkItem>(); |
| private long fStartTime; |
| |
| public OpMove(List<? extends IFSTreeNode> nodes, FSTreeNode dest, IConfirmCallback confirmCallback) { |
| fConfirmCallback = confirmCallback; |
| for (FSTreeNode node : dropNestedNodes(nodes)) { |
| fWork.add(new WorkItem(node, dest)); |
| } |
| } |
| |
| @Override |
| public String getName() { |
| return Messages.OpMove_MovingFile; |
| } |
| |
| @Override |
| public IStatus doRun(IProgressMonitor monitor) { |
| if (fWork.isEmpty()) |
| return Status.OK_STATUS; |
| |
| fStartTime = System.currentTimeMillis(); |
| monitor.beginTask(getName(), IProgressMonitor.UNKNOWN); |
| |
| List<FSTreeNode> notify = new ArrayList<FSTreeNode>(); |
| notify.add(fWork.peek().fDestination); |
| for (WorkItem item : fWork) { |
| notify.add(item.fSource.getParent()); |
| } |
| |
| IStatus status = Status.OK_STATUS; |
| while (!fWork.isEmpty()) { |
| WorkItem item = fWork.remove(); |
| status = runWorkItem(item, monitor); |
| if (!status.isOK()) |
| break; |
| } |
| |
| for (FSTreeNode node : dropNestedNodes(notify)) { |
| node.notifyChange(); |
| } |
| return status; |
| } |
| |
| protected IStatus runWorkItem(final WorkItem item, final IProgressMonitor monitor) { |
| if (item.fContentLeftOK) |
| return Status.OK_STATUS; |
| |
| if (item.fContentCleared) { |
| return deleteEmptyFolder(item.fSource, monitor); |
| } |
| |
| return move(item, monitor); |
| } |
| |
| private IStatus move(final WorkItem item, final IProgressMonitor monitor) { |
| monitor.subTask(NLS.bind(Messages.OpMove_Moving, item.fSource.getLocation())); |
| |
| final FSTreeNode source = item.fSource; |
| final FSTreeNode destination = item.fDestination; |
| IStatus status = refresh(destination, fStartTime, monitor); |
| if (!status.isOK()) |
| return status; |
| |
| status = refresh(source, fStartTime, monitor); |
| if (!status.isOK()) |
| return status; |
| |
| final FSTreeNode existing = destination.findChild(source.getName()); |
| if (existing != null) { |
| if (source == existing) { |
| return Status.OK_STATUS; |
| } |
| if (source.isDirectory()) { |
| if (!existing.isDirectory()) { |
| return StatusHelper.createStatus(format(Messages.OpCopy_error_noDirectory, existing.getLocation()), null); |
| } |
| int replace = confirmCallback(existing, fConfirmCallback); |
| if (replace == IConfirmCallback.NO) { |
| item.setContentLeftOK(); |
| return Status.OK_STATUS; |
| } |
| if (replace != IConfirmCallback.YES) { |
| return Status.CANCEL_STATUS; |
| } |
| |
| item.fContentCleared = true; |
| fWork.addFirst(item); |
| for (FSTreeNode child : source.getChildren()) { |
| fWork.addFirst(new WorkItem(item, child, existing)); |
| } |
| return Status.OK_STATUS; |
| } else if (source.isFile()) { |
| if (!existing.isFile()) { |
| return StatusHelper.createStatus(format(Messages.OpCopy_error_noFile, existing.getLocation()), null); |
| } |
| int replace = confirmCallback(existing, fConfirmCallback); |
| if (replace == IConfirmCallback.NO) { |
| item.setContentLeftOK(); |
| return Status.OK_STATUS; |
| } |
| if (replace != IConfirmCallback.YES) { |
| return Status.CANCEL_STATUS; |
| } |
| } else { |
| return Status.OK_STATUS; |
| } |
| } |
| |
| CacheManager.clearCache(existing); |
| CacheManager.clearCache(source); |
| |
| final TCFResult<?> result = new TCFResult<Object>(); |
| Protocol.invokeLater(new Runnable() { |
| @Override |
| public void run() { |
| if (existing != null) { |
| tcfMoveReplace(source, destination, existing, result); |
| } else { |
| tcfMove(source, destination, result); |
| } |
| } |
| }); |
| return result.waitDone(monitor); |
| } |
| |
| |
| protected void tcfMoveReplace(final FSTreeNode source, final FSTreeNode destination, final FSTreeNode existing, final TCFResult<?> result) { |
| if (result.checkCancelled()) |
| return; |
| |
| final IFileSystem fileSystem = destination.getRuntimeModel().getFileSystem(); |
| if (fileSystem == null) { |
| result.setCancelled(); |
| return; |
| } |
| |
| fileSystem.remove(existing.getLocation(true), new DoneRemove() { |
| @Override |
| public void doneRemove(IToken token, FileSystemException error) { |
| if (error != null) { |
| result.setError(format(Messages.OpMove_CannotMove, source.getLocation()), error); |
| } else if (!result.checkCancelled()) { |
| existing.getParent().removeNode(existing, false); |
| tcfMove(source, destination, result); |
| } |
| } |
| }); |
| } |
| |
| protected void tcfMove(final FSTreeNode source, final FSTreeNode dest, final TCFResult<?> result) { |
| final IFileSystem fileSystem = dest.getRuntimeModel().getFileSystem(); |
| if (fileSystem == null) { |
| result.setCancelled(); |
| return; |
| } |
| |
| final String sourcePath = source.getLocation(true); |
| final String destPath = getPath(dest, source.getName()); |
| |
| fileSystem.rename(sourcePath, destPath, new DoneRename() { |
| @Override |
| public void doneRename(IToken token, FileSystemException error) { |
| if (error != null) { |
| result.setError(format(Messages.OpMove_CannotMove, sourcePath), error); |
| } else { |
| source.getParent().removeNode(source, false); |
| source.changeParent(dest); |
| dest.addNode(source, false); |
| result.setDone(null); |
| } |
| } |
| }); |
| } |
| |
| private IStatus deleteEmptyFolder(final FSTreeNode source, IProgressMonitor monitor) { |
| CacheManager.clearCache(source); |
| final TCFResult<?> result = new TCFResult<Object>(); |
| Protocol.invokeLater(new Runnable() { |
| @Override |
| public void run() { |
| tcfDeleteEmptyFolder(source, result); |
| } |
| }); |
| return result.waitDone(monitor); |
| } |
| |
| protected void tcfDeleteEmptyFolder(final FSTreeNode source, final TCFResult<?> result) { |
| final IFileSystem fs = source.getRuntimeModel().getFileSystem(); |
| if (fs == null) { |
| result.setCancelled(); |
| return; |
| } |
| fs.rmdir(source.getLocation(true), new DoneRemove() { |
| @Override |
| public void doneRemove(IToken token, FileSystemException error) { |
| if (error != null) { |
| result.setError(format(Messages.OpDelete_error_delete, source.getLocation()), error); |
| } else if (!result.checkCancelled()) { |
| source.getParent().removeNode(source, false); |
| result.setDone(null); |
| } |
| } |
| }); |
| } |
| } |