import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
+import android.content.Intent;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
}
+ //public void moveFolder(OCFile folder, String newPath) {
+ public void moveLocalFile(OCFile file, String targetPath) {
+ // TODO check newPath
+ if (file != null && file.fileExists()) {
+
+ if (//file.isFolder() && // should work for regular files!!
+ !OCFile.ROOT_PATH.equals(file.getFileName())) {
+
+ /// 0. move in local file system
+
+ /// 1. get all the descendants in a single QUERY (including the folder)
+ Cursor c = null;
+ if (getContentProviderClient() != null) {
+ try {
+ c = getContentProviderClient().query(
+ ProviderTableMeta.CONTENT_URI,
+ null,
+ ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
+ ProviderTableMeta.FILE_PATH + " LIKE ? ",
+ new String[] {
+ mAccount.name,
+ file.getRemotePath() + "%"
+ },
+ ProviderTableMeta.FILE_PATH + " ASC "
+ );
+ } catch (RemoteException e) {
+ Log_OC.e(TAG, e.getMessage());
+ }
+
+ } else {
+ c = getContentResolver().query(
+ ProviderTableMeta.CONTENT_URI,
+ null,
+ ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
+ ProviderTableMeta.FILE_PATH + " LIKE ? ",
+ new String[] {
+ mAccount.name,
+ file.getRemotePath() + "%"
+ },
+ ProviderTableMeta.FILE_PATH + " ASC "
+ );
+ }
+
+ /// 2. prepare a batch of update operations to change all the descendants
+ ArrayList<ContentProviderOperation> operations =
+ new ArrayList<ContentProviderOperation>(c.getCount());
+ if (c.moveToFirst()) {
+ int lengthOfOldPath = file.getRemotePath().length();
+ String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
+ int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
+ do {
+ ContentValues cv = new ContentValues(); // keep construction in the loop
+ OCFile child = createFileInstance(c);
+ cv.put(
+ ProviderTableMeta.FILE_PATH,
+ targetPath + child.getRemotePath().substring(lengthOfOldPath)
+ );
+ if (child.getStoragePath() != null &&
+ child.getStoragePath().startsWith(defaultSavePath)) {
+ // update link to downloaded content - but local move is not done here!
+ cv.put(
+ ProviderTableMeta.FILE_STORAGE_PATH,
+ defaultSavePath + targetPath +
+ child.getStoragePath().substring(lengthOfOldStoragePath)
+ );
+ }
+ operations.add(
+ ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
+ withValues(cv).
+ withSelection(
+ ProviderTableMeta._ID + "=?",
+ new String[] { String.valueOf(child.getFileId()) }
+ )
+ .build());
+
+ } while (c.moveToNext());
+ }
+ c.close();
+
+ /// 3. apply updates in batch
+ try {
+ if (getContentResolver() != null) {
+ getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+
+ } else {
+ getContentProviderClient().applyBatch(operations);
+ }
+
+ } catch (Exception e) {
+ Log_OC.e(
+ TAG,
+ "Fail to update " + file.getFileId() + " and descendants in database",
+ e
+ );
+ }
+
+ }
+ }
+
+ /*
+ private void saveLocalDirectory() {
+ * TODO implement local movement of folder
+ getStorageManager().moveFolder(mFile, mNewPath);
+ String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
+ File localDir = new File(localPath);
+ if (localDir.exists()) {
+ localDir.renameTo(new File(FileStorageUtils.getSavePath(mAccount.name) + mNewPath));
+ // TODO - if renameTo fails, children files that are already down will result unlinked
+ }
+ }
+ */
+
+ /*
+ private void saveLocalFile() {
+ mFile.setRFileName(mNewName); <<< NO >
+
+ // try to move the local copy of the file
+ if (mFile.isDown()) {
+ File f = new File(mFile.getStoragePath());
+ String parentStoragePath = f.getParent();
+ if (!parentStoragePath.endsWith(File.separator))
+ parentStoragePath += File.separator;
+ if (f.renameTo(new File())) {
+ mFile.setStoragePath(parentStoragePath + mNewName);
+ }
+ // else - NOTHING: the link to the local file is kept although the local name can't be updated
+ // TODO - study conditions when this could be a problem
+ }
+
+ getStorageManager().saveFile(mFile);
+ }
+ */
+
+ }
+
+
private Vector<OCFile> getFolderContent(long parentId) {
Vector<OCFile> ret = new Vector<OCFile>();
*/
//}
}
+
}
package com.owncloud.android.operations;
-import java.io.File;
-import java.io.IOException;
-
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation;
-import com.owncloud.android.lib.resources.files.RenameRemoteFileOperation;
import com.owncloud.android.operations.common.SyncOperation;
-import com.owncloud.android.utils.FileStorageUtils;
-import com.owncloud.android.utils.Log_OC;
import android.accounts.Account;
*/
public class MoveFileOperation extends SyncOperation {
- private static final String TAG = MoveFileOperation.class.getSimpleName();
+ //private static final String TAG = MoveFileOperation.class.getSimpleName();
+
+ private String mSrcPath;
+ private String mTargetParentPath;
- private String mPath;
- private Account mAccount;
- private String mNewParentPath;
private OCFile mFile;
- private String mNewPath;
* @param newParentPath Path to the folder where the file will be moved into.
* @param account OwnCloud account containing both the file and the target folder
*/
- public MoveFileOperation(String path, String newParentPath, Account account) {
- mPath = path;
- mNewParentPath = newParentPath;
- mAccount = account;
+ public MoveFileOperation(String srcPath, String targetParentPath, Account account) {
+ mSrcPath = srcPath;
+ mTargetParentPath = targetParentPath;
+ if (!mTargetParentPath.endsWith(OCFile.PATH_SEPARATOR)) {
+ mTargetParentPath += OCFile.PATH_SEPARATOR;
+ }
mFile = null;
- mNewPath = "";
}
- public OCFile getFile() {
- return mFile;
- }
-
-
/**
* Performs the operation.
*
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
-
- mFile = getStorageManager().getFileByPath(mPath);
-
- try {
- /// 1. check move validity
-
-
- /// 2. remove move
- MoveRemoteFileOperation operation = new MoveRemoteFileOperation(
- mFile.getRemotePath(),
- mNewPath,
- false
- );
- result = operation.execute(client);
-
-
- /// 3. local move
- if (result.isSuccess()) {
- //moveLocaly();
- /*
- if (mFile.isFolder()) {
- saveLocalDirectory();
-
- } else {
- saveLocalFile();
- }
- */
- }
-
-
- String parentPath = (new File(mFile.getRemotePath())).getParent();
- parentPath = (parentPath.endsWith(OCFile.PATH_SEPARATOR))
- ? parentPath
- : parentPath + OCFile.PATH_SEPARATOR;
-
- mNewPath = mNewParentPath + mFile.getFileName();
- if (mFile.isFolder() && !mNewPath.endsWith(OCFile.PATH_SEPARATOR)) {
- mNewPath += OCFile.PATH_SEPARATOR;
- }
-
- // check local overwrite
- if (getStorageManager().getFileByPath(mPath) != null) {
- return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
- }
-
- /*
- } catch (IOException e) {
- Log_OC.e(TAG, "Move " + mFile.getRemotePath() + " to " +
- (mNewParentPath==null) + ": " +
- ((result!= null) ? result.getLogMessage() : ""), e);*/
- } finally {
-
+ /// 1. check move validity
+ if (mTargetParentPath.startsWith(mSrcPath)) {
+ return new RemoteOperationResult(ResultCode.INVALID_MOVE_INTO_DESCENDANT);
}
-
- return result;
- }
-
-
- private void saveLocalDirectory() {
- getStorageManager().moveFolder(mFile, mNewPath);
- String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
- File localDir = new File(localPath);
- if (localDir.exists()) {
- localDir.renameTo(new File(FileStorageUtils.getSavePath(mAccount.name) + mNewPath));
- // TODO - if renameTo fails, children files that are already down will result unlinked
+ mFile = getStorageManager().getFileByPath(mSrcPath);
+ if (mFile == null) {
+ return new RemoteOperationResult(ResultCode.FILE_NOT_FOUND);
}
- }
-
- private void saveLocalFile() {
- /*
- mFile.setRFileName(mNewName); <<< NO >
-
- // try to move the local copy of the file
- if (mFile.isDown()) {
- File f = new File(mFile.getStoragePath());
- String parentStoragePath = f.getParent();
- if (!parentStoragePath.endsWith(File.separator))
- parentStoragePath += File.separator;
- if (f.renameTo(new File())) {
- mFile.setStoragePath(parentStoragePath + mNewName);
- }
- // else - NOTHING: the link to the local file is kept although the local name can't be updated
- // TODO - study conditions when this could be a problem
- }
-
- getStorageManager().saveFile(mFile);
- */
- }
-
- /**
- * Checks if the new name to set is valid in the file system
- *
- * The only way to be sure is trying to create a file with that name. It's made in the temporal directory
- * for downloads, out of any account, and then removed.
- *
- * IMPORTANT: The test must be made in the same file system where files are download. The internal storage
- * could be formatted with a different file system.
- *
- * TODO move this method, and maybe FileDownload.get***Path(), to a class with utilities specific for the interactions with the file system
- *
- * @return 'True' if a temporal file named with the name to set could be created in the file system where
- * local files are stored.
- * @throws IOException When the temporal folder can not be created.
- */
- private boolean isValidNewName() throws IOException {
- return true;
- /*
- // check tricky names
- if (mNewName == null || mNewName.length() <= 0 || mNewName.contains(File.separator) || mNewName.contains("%")) {
- return false;
- }
- // create a test file
- String tmpFolderName = FileStorageUtils.getTemporalPath("");
- File testFile = new File(tmpFolderName + mNewName);
- File tmpFolder = testFile.getParentFile();
- tmpFolder.mkdirs();
- if (!tmpFolder.isDirectory()) {
- throw new IOException("Unexpected error: temporal directory could not be created");
- }
- try {
- testFile.createNewFile(); // return value is ignored; it could be 'false' because the file already existed, that doesn't invalidate the name
- } catch (IOException e) {
- Log_OC.i(TAG, "Test for validity of name " + mNewName + " in the file system failed");
- return false;
- }
- boolean result = (testFile.exists() && testFile.isFile());
+ /// 2. remote move
+ String targetPath = mTargetParentPath + mFile.getFileName();
+ MoveRemoteFileOperation operation = new MoveRemoteFileOperation(
+ mSrcPath,
+ targetPath,
+ false
+ );
+ result = operation.execute(client);
- // cleaning ; result is ignored, since there is not much we could do in case of failure, but repeat and repeat...
- testFile.delete();
+ /// 3. local move
+ if (result.isSuccess()) {
+ // TODO work in progress
+ //getStorageManager().moveLocalFile(mFile, targetPath);
+ }
+ // TODO handle ResultCode.PARTIAL_MOVE_DONE in client Activity, for the moment
return result;
- */
}
+
}