/******************************************************************************* * 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.io.File; 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.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.StatusHelper; import org.eclipse.tcf.te.tcf.filesystem.core.nls.Messages; /** * The operation class that copies selected FSTreeNodes to a specify destination folder. */ public abstract class OpCopyBase<D> extends AbstractOperation { private static class WorkItem<D> { final boolean fTop; final D fDestination; final FSTreeNode[] fSources; WorkItem(FSTreeNode[] sources, D destination, boolean top) { fSources = sources; fDestination = destination; fTop = top; } } private IConfirmCallback fConfirmCallback; private LinkedList<WorkItem<D>> fWork = new LinkedList<WorkItem<D>>(); private long fStartTime; /** * Create a copy operation using the specified nodes and destination folder, * using the specified flags of copying permissions and ownership and a callback * to confirm to overwrite existing files. * * @param nodes The file/folder nodes to be copied. * @param dest The destination folder to be copied to. */ public OpCopyBase(List<? extends IFSTreeNode> nodes, D dest, IConfirmCallback confirmCallback) { super(); fConfirmCallback = confirmCallback; nodes = dropNestedNodes(nodes); fWork.add(new WorkItem<D>(nodes.toArray(new FSTreeNode[nodes.size()]), dest, true)); } abstract protected void notifyChange(D destination); abstract protected IStatus refreshDestination(D destination, long startTime, IProgressMonitor monitor); abstract protected D findChild(D destination, String newName); abstract protected boolean isDirectory(D existing); abstract protected boolean isFile(D existing); abstract protected String getLocation(D existing); abstract protected IStatus performCopy(final FSTreeNode source, final D destination, final String newName, final D existing, IProgressMonitor monitor); protected void addWorkItem(FSTreeNode[] nodes, D dest) { fWork.addFirst(new WorkItem<D>(nodes, dest, false)); } @Override public final IStatus doRun(IProgressMonitor monitor) { fStartTime = System.currentTimeMillis(); monitor.beginTask(getName(), IProgressMonitor.UNKNOWN); WorkItem<D> lastTop = null; while (!fWork.isEmpty()) { WorkItem<D> item = fWork.remove(); if (item.fTop) { if (lastTop != null) notifyChange(lastTop.fDestination); lastTop = item; } IStatus s = runWorkItem(item, monitor); if (!s.isOK()) { if (lastTop != null) { notifyChange(lastTop.fDestination); } return s; } } if (lastTop != null) notifyChange(lastTop.fDestination); return Status.OK_STATUS; } protected IStatus runWorkItem(final WorkItem<D> item, IProgressMonitor monitor) { final D destination = item.fDestination; IStatus status = refreshDestination(destination, fStartTime, monitor); if (!status.isOK()) { return status; } for (FSTreeNode source : item.fSources) { status = refresh(source, fStartTime, monitor); if (!status.isOK()) { return status; } status = performCopy(source, destination, monitor); if (!status.isOK()) return status; } return Status.OK_STATUS; } private IStatus performCopy(FSTreeNode source, D destination, IProgressMonitor monitor) { String newName = new File(source.getName().replace(':', '$')).getName(); D existing = findChild(destination, newName); if (existing != null) { if (source == existing) { newName = createNewNameForCopy(destination, newName); existing = null; } else if (source.isDirectory()) { if (!isDirectory(existing)) { return StatusHelper.createStatus(format(Messages.OpCopy_error_noDirectory, getLocation(existing)), null); } int replace = confirmCallback(existing, fConfirmCallback); if (replace == IConfirmCallback.NO) { return Status.OK_STATUS; } if (replace != IConfirmCallback.YES) { return Status.CANCEL_STATUS; } fWork.addFirst(new WorkItem<D>(source.getChildren(), existing, false)); return Status.OK_STATUS; } else if (source.isFile()) { if (!isFile(existing)) { return StatusHelper.createStatus(format(Messages.OpCopy_error_noFile, getLocation(existing)), null); } int replace = confirmCallback(existing, fConfirmCallback); if (replace == IConfirmCallback.NO) { return Status.OK_STATUS; } if (replace != IConfirmCallback.YES) { return Status.CANCEL_STATUS; } } else { return Status.OK_STATUS; } } return performCopy(source, destination, newName, existing, monitor); } private String createNewNameForCopy(D node, String origName) { String name = origName; int n = 0; while (findChild(node, name) != null) { if (n > 0) { name = NLS.bind(Messages.Operation_CopyNOfFile, Integer.valueOf(n), origName); } else { name = NLS.bind(Messages.Operation_CopyOfFile, origName); } n++; } return name; } @Override public String getName() { return Messages.OpCopy_CopyingFile; } }