From: David A. Velasco Date: Wed, 21 Nov 2012 13:32:40 +0000 (+0100) Subject: Fixed database update due to renaming folders X-Git-Tag: oc-android-1.4.3~88^2~8 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/d0b7df16e7db7aacfeab0685eb9ceaf6b58fbc08?hp=-c Fixed database update due to renaming folders --- d0b7df16e7db7aacfeab0685eb9ceaf6b58fbc08 diff --git a/src/com/owncloud/android/datamodel/DataStorageManager.java b/src/com/owncloud/android/datamodel/DataStorageManager.java index 7cca9702..0ab05049 100644 --- a/src/com/owncloud/android/datamodel/DataStorageManager.java +++ b/src/com/owncloud/android/datamodel/DataStorageManager.java @@ -42,4 +42,6 @@ public interface DataStorageManager { public void removeFile(OCFile file, boolean removeLocalCopy); public void removeDirectory(OCFile dir, boolean removeDBData, boolean removeLocalContent); + + public void moveDirectory(OCFile dir, String newPath); } diff --git a/src/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/com/owncloud/android/datamodel/FileDataStorageManager.java index a8186cd5..be016555 100644 --- a/src/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -500,5 +500,76 @@ public class FileDataStorageManager implements DataStorageManager { } } } + + + /** + * Updates database for a folder that was moved to a different location. + * + * TODO explore better (faster) implementations + * TODO throw exceptions up ! + */ + @Override + public void moveDirectory(OCFile dir, String newPath) { + // TODO check newPath + + if (dir != null && dir.isDirectory() && dir.fileExists() && !dir.getFileName().equals(OCFile.PATH_SEPARATOR)) { + /// 1. get all the descendants of 'dir' in a single QUERY (including 'dir') + Cursor c = null; + if (getContentProvider() != null) { + try { + c = getContentProvider().query(ProviderTableMeta.CONTENT_URI, + null, + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?", + new String[] { mAccount.name, dir.getRemotePath() + "%" }, null); + } catch (RemoteException e) { + Log.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, dir.getRemotePath() + "%" }, null); + } + + /// 2. prepare a batch of update operations to change all the descendants + ArrayList operations = new ArrayList(c.getCount()); + ContentValues cv = new ContentValues(); + int lengthOfOldPath = dir.getRemotePath().length(); + String defaultSavePath = FileDownloader.getSavePath(mAccount.name); + int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath; + if (c.moveToFirst()) { + do { + OCFile child = createFileInstance(c); + cv.put(ProviderTableMeta.FILE_PATH, newPath + child.getRemotePath().substring(lengthOfOldPath)); + if (child.getStoragePath() != null && child.getStoragePath().startsWith(defaultSavePath)) { + cv.put(ProviderTableMeta.FILE_STORAGE_PATH, defaultSavePath + newPath + 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(ProviderMeta.AUTHORITY_FILES, operations); + + } else { + getContentProvider().applyBatch(operations); + } + + } catch (OperationApplicationException e) { + Log.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e); + + } catch (RemoteException e) { + Log.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e); + } + + } + } } diff --git a/src/com/owncloud/android/operations/RenameFileOperation.java b/src/com/owncloud/android/operations/RenameFileOperation.java index fd97c581..d5af9767 100644 --- a/src/com/owncloud/android/operations/RenameFileOperation.java +++ b/src/com/owncloud/android/operations/RenameFileOperation.java @@ -24,6 +24,7 @@ import java.io.IOException; import org.apache.jackrabbit.webdav.client.methods.DavMethodBase; //import org.apache.jackrabbit.webdav.client.methods.MoveMethod; +import android.accounts.Account; import android.util.Log; import com.owncloud.android.datamodel.DataStorageManager; @@ -48,7 +49,9 @@ public class RenameFileOperation extends RemoteOperation { private OCFile mFile; + private Account mAccount; private String mNewName; + private String mNewRemotePath; private DataStorageManager mStorageManager; @@ -56,12 +59,15 @@ public class RenameFileOperation extends RemoteOperation { * Constructor * * @param file OCFile instance describing the remote file or folder to rename + * @param account OwnCloud account containing the remote file * @param newName New name to set as the name of file. * @param storageManager Reference to the local database corresponding to the account where the file is contained. */ - public RenameFileOperation(OCFile file, String newName, DataStorageManager storageManager) { + public RenameFileOperation(OCFile file, Account account, String newName, DataStorageManager storageManager) { mFile = file; + mAccount = account; mNewName = newName; + mNewRemotePath = null; mStorageManager = storageManager; } @@ -80,7 +86,7 @@ public class RenameFileOperation extends RemoteOperation { RemoteOperationResult result = null; LocalMoveMethod move = null; - String newRemotePath = null; + mNewRemotePath = null; try { if (mNewName.equals(mFile.getFileName())) { return new RemoteOperationResult(ResultCode.OK); @@ -88,7 +94,10 @@ public class RenameFileOperation extends RemoteOperation { String parent = (new File(mFile.getRemotePath())).getParent(); parent = (parent.endsWith(OCFile.PATH_SEPARATOR)) ? parent : parent + OCFile.PATH_SEPARATOR; - newRemotePath = parent + mNewName; + mNewRemotePath = parent + mNewName; + if (mFile.isDirectory()) { + mNewRemotePath += OCFile.PATH_SEPARATOR; + } // check if the new name is valid in the local file system if (!isValidNewName()) { @@ -96,34 +105,22 @@ public class RenameFileOperation extends RemoteOperation { } // check if a file with the new name already exists - if (client.existsFile(newRemotePath) || // remote check could fail by network failure, or by indeterminate behavior of HEAD for folders ... - mStorageManager.getFileByPath(newRemotePath) != null) { // ... so local check is convenient + if (client.existsFile(mNewRemotePath) || // remote check could fail by network failure, or by indeterminate behavior of HEAD for folders ... + mStorageManager.getFileByPath(mNewRemotePath) != null) { // ... so local check is convenient return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE); } move = new LocalMoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()), - client.getBaseUri() + WebdavUtils.encodePath(newRemotePath)); + client.getBaseUri() + WebdavUtils.encodePath(mNewRemotePath)); int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT); if (move.succeeded()) { - // create new OCFile instance for the renamed file - /*OCFile newFile = new OCFile(mStorageManager.getFileById(mFile.getParentId()).getRemotePath() + mNewName; // TODO - NOT CREATE NEW OCFILE; ADD setFileName METHOD - OCFile oldFile = mFile; - mFile = newFile; */ - mFile.setFileName(mNewName); - - // try to rename the local copy of the file - if (mFile.isDown()) { - File f = new File(mFile.getStoragePath()); - String newStoragePath = f.getParent() + mNewName; - if (f.renameTo(new File(newStoragePath))) { - mFile.setStoragePath(newStoragePath); - } - // 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 + if (mFile.isDirectory()) { + saveLocalDirectory(); + + } else { + saveLocalFile(); + } - - //mStorageManager.removeFile(oldFile, false); - mStorageManager.saveFile(mFile); /* *} else if (mFile.isDirectory() && (status == 207 || status >= 500)) { @@ -141,11 +138,11 @@ public class RenameFileOperation extends RemoteOperation { move.getResponseBodyAsString(); // exhaust response, although not interesting result = new RemoteOperationResult(move.succeeded(), status); - Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + newRemotePath + ": " + result.getLogMessage()); + Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + mNewRemotePath + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((newRemotePath==null) ? mNewName : newRemotePath) + ": " + result.getLogMessage(), e); + Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e); } finally { if (move != null) @@ -155,6 +152,33 @@ public class RenameFileOperation extends RemoteOperation { } + private void saveLocalDirectory() { + mStorageManager.moveDirectory(mFile, mNewRemotePath); + String localPath = FileDownloader.getSavePath(mAccount.name) + mFile.getRemotePath(); + File localDir = new File(localPath); + if (localDir.exists()) { + localDir.renameTo(new File(FileDownloader.getSavePath(mAccount.name) + mNewRemotePath)); + // TODO - if renameTo fails, children files that are already down will result unlinked + } + } + + private void saveLocalFile() { + mFile.setFileName(mNewName); + + // try to rename the local copy of the file + if (mFile.isDown()) { + File f = new File(mFile.getStoragePath()); + String newStoragePath = f.getParent() + mNewName; + if (f.renameTo(new File(newStoragePath))) { + mFile.setStoragePath(newStoragePath); + } + // 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 + } + + mStorageManager.saveFile(mFile); + } + /** * Checks if the new name to set is valid in the file system * diff --git a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java index 9b0f03bc..cd89807b 100644 --- a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -829,6 +829,7 @@ public class FileDetailFragment extends SherlockFragment implements String newFilename = dialog.getNewFilename(); Log.d(TAG, "name edit dialog dismissed with new name " + newFilename); mLastRemoteOperation = new RenameFileOperation( mFile, + mAccount, newFilename, new FileDataStorageManager(mAccount, getActivity().getContentResolver())); WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext()); diff --git a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java index cb41a777..45bf110c 100644 --- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -441,6 +441,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial String newFilename = dialog.getNewFilename(); Log.d(TAG, "name edit dialog dismissed with new name " + newFilename); RemoteOperation operation = new RenameFileOperation(mTargetFile, + AccountUtils.getCurrentOwnCloudAccount(getActivity()), newFilename, mContainerActivity.getStorageManager()); WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity().getApplicationContext());