blob: 8493a47e391e8f660b69e288d74debb83ac45b2b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 Wind River Systems, Inc.
* 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:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.tcf.filesystem.core.internal.operations;
import static java.util.Arrays.asList;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.tcf.protocol.IToken;
import org.eclipse.tcf.services.IFileSystem;
import org.eclipse.tcf.services.IFileSystem.DirEntry;
import org.eclipse.tcf.services.IFileSystem.DoneClose;
import org.eclipse.tcf.services.IFileSystem.DoneOpen;
import org.eclipse.tcf.services.IFileSystem.DoneReadDir;
import org.eclipse.tcf.services.IFileSystem.FileSystemException;
import org.eclipse.tcf.services.IFileSystem.IFileHandle;
import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback;
import org.eclipse.tcf.te.tcf.filesystem.core.interfaces.IConfirmCallback;
import org.eclipse.tcf.te.tcf.filesystem.core.interfaces.IOperation;
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.nls.Messages;
public abstract class AbstractOperation implements IOperation {
public interface IReadDirDone {
void error(FileSystemException error);
boolean checkCancelled();
void done(List<DirEntry> entries);
}
private static final DecimalFormat SIZE_FORMAT = new DecimalFormat("#,##0.##"); //$NON-NLS-1$
protected static final int DEFAULT_CHUNK_SIZE = 5 * 1024;
private int fStandardAnswer = -1;
protected abstract IStatus doRun(IProgressMonitor monitor);
@Override
public final IStatus run(IProgressMonitor monitor) {
if (monitor == null)
monitor = new NullProgressMonitor();
try {
return doRun(monitor);
} finally {
monitor.done();
}
}
@Override
public final void runInJob(ICallback callback) {
runInJob(false, callback);
}
@Override
public final void runInUserJob(ICallback callback) {
runInJob(true, callback);
}
private final void runInJob(boolean user, final ICallback callback) {
Job job = new Job(getName()){
@Override
protected IStatus run(IProgressMonitor monitor) {
return AbstractOperation.this.run(monitor);
}
};
if (callback != null) {
job.addJobChangeListener(new JobChangeAdapter(){
@Override
public void done(final IJobChangeEvent event) {
callback.done(AbstractOperation.this, event.getResult());
}
});
}
job.setUser(user);
job.schedule();
}
protected String getPath(FSTreeNode node, String childName) {
String path = node.getLocation(true);
if (path.charAt(path.length()-1) == '/')
return path + childName;
return path + '/' + childName;
}
protected List<FSTreeNode> dropNestedNodes(List<? extends IFSTreeNode> nodes) {
List<FSTreeNode> result = new ArrayList<FSTreeNode>();
for (IFSTreeNode n : nodes) {
addWithoutNested(result, n);
}
return result;
}
private void addWithoutNested(List<FSTreeNode> result, IFSTreeNode newNode) {
if (!(newNode instanceof FSTreeNode))
return;
for (ListIterator<FSTreeNode> it = result.listIterator(); it.hasNext(); ) {
FSTreeNode node = it.next();
if (node == newNode || node.isAncestorOf(newNode))
return;
if (newNode.isAncestorOf(node)) {
it.set((FSTreeNode) newNode);
return;
}
}
result.add((FSTreeNode) newNode);
}
protected IStatus refresh(FSTreeNode node, long olderThan, IProgressMonitor monitor) {
if (node.getLastRefresh() < olderThan)
return node.operationRefresh(false).run(new SubProgressMonitor(monitor, 0));
return Status.OK_STATUS;
}
protected int confirmCallback(final FSTreeNode node, IConfirmCallback confirmCallback) {
if (confirmCallback == null)
return IConfirmCallback.YES;
if (fStandardAnswer >= 0)
return fStandardAnswer;
int answer = confirmCallback.confirms(node);
switch (answer) {
case IConfirmCallback.CANCEL:
case IConfirmCallback.NO:
case IConfirmCallback.YES:
return answer;
case IConfirmCallback.NO_TO_ALL:
fStandardAnswer = IConfirmCallback.NO;
return fStandardAnswer;
case IConfirmCallback.YES_TO_ALL:
fStandardAnswer = IConfirmCallback.YES;
return fStandardAnswer;
default:
return IConfirmCallback.CANCEL;
}
}
/**
* Use the SIZE_FORMAT to format the file's size. The rule is: 1. If the
* size is less than 1024 bytes, then show it as "####" bytes. 2. If the
* size is less than 1024 KBs, while more than 1 KB, then show it as
* "####.##" KBs. 3. If the size is more than 1 MB, then show it as
* "####.##" MBs.
*
* @param size
* The file size to be displayed.
* @return The string representation of the size.
*/
protected String formatSize(long size) {
double kbSize = size / 1024.0;
if (kbSize < 1.0) {
return SIZE_FORMAT.format(size) + Messages.OpStreamOp_Bytes;
}
double mbSize = kbSize / 1024.0;
if (mbSize < 1.0)
return SIZE_FORMAT.format(kbSize) + Messages.OpStreamOp_KBs;
return SIZE_FORMAT.format(mbSize) + Messages.OpStreamOp_MBs;
}
protected void tcfReadDir(final IFileSystem fs, String path, final IReadDirDone callback) {
fs.opendir(path, new DoneOpen() {
private IFileHandle fHandle;
protected List<DirEntry> fEntries;
@Override
public void doneOpen(IToken token, FileSystemException error, final IFileHandle handle) {
if (error != null) {
callback.error(error);
} else {
fHandle = handle;
if (callback.checkCancelled()) {
cleanup();
} else {
fEntries = new ArrayList<DirEntry>();
readDir();
}
}
}
protected void readDir() {
fs.readdir(fHandle, new DoneReadDir() {
@Override
public void doneReadDir(IToken token, FileSystemException error, DirEntry[] entries, boolean eof) {
if (error != null) {
cleanup();
callback.error(error);
} else if (callback.checkCancelled()) {
cleanup();
} else {
fEntries.addAll(asList(entries));
if (eof) {
cleanup();
callback.done(fEntries);
} else {
readDir();
}
}
}
});
}
protected void cleanup() {
if (fHandle != null) {
fs.close(fHandle, new DoneClose() {
@Override
public void doneClose(IToken token, FileSystemException error) {
}
});
}
}
});
}
}