--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/filemanager/src/filemanager/src/operationservice/fmoperationcopyormove.cpp Thu Aug 05 11:30:07 2010 +0800
@@ -0,0 +1,426 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+#include "fmoperationcopyormove.h"
+#include "fmcommon.h"
+#include "fmoperationbase.h"
+#include "fmdrivedetailstype.h"
+#include "fmutils.h"
+
+#include <QDir>
+#include <QFileInfo>
+#include <QStringList>
+#include <QStack>
+
+/* \fn void askForReplace( const QString &srcFile, const QString &destFile, bool *isAccepted )
+ * This signal is emitted when the same file as \a srcFile exists.
+ * \a destFile the destination file.
+ * \a isAccepted whether to replace the destination file.
+ */
+
+/* \fn void askForRename( const QString &srcFile, QString *destFile )
+ * This signal is emitted when \a srcFile needs to be renamed.
+ * \a destFile return the new name.
+ */
+
+/* \fn void driveSpaceChanged()
+ * This signal is emitted when copy or move is completed, and used to update the drive size.
+ */
+
+//the size of one time copy
+const int FmOneTimeCopyOrMoveSize = 1024;
+//the total steps of progress bar
+const int FmTotalProgressBarSteps = 100;
+/*
+ * Constructs a copy or move operation with
+ * \a operationService parent
+ * \a type the type of operation(EOperationTypeCopy or EOperationTypeMove)
+ * \a sourceList the source file or path lists that will be copied
+ * \a targetPath the target path where the source file will be copied
+ */
+FmOperationCopyOrMove::FmOperationCopyOrMove( FmOperationService *operationService, FmOperationService::TOperationType type, const QStringList &sourceList, const QString &targetPath )
+ : FmOperationBase( operationService, type ),
+ mOperationService( operationService ), mSourceList( sourceList ), mTargetPath( targetPath ),
+ mStop( 0 ), mTotalSize( 0 ), mCopiedOrMovedSize( 0 ), mTotalSteps( FmTotalProgressBarSteps ), mCurrentStep( 0 )
+{
+ mTargetPath = FmUtils::fillPathWithSplash( mTargetPath );
+ connect( this, SIGNAL( askForRename( QString, QString* ) ),
+ mOperationService, SLOT( on_operation_askForRename( QString, QString* )), Qt::BlockingQueuedConnection );
+ connect( this, SIGNAL( askForReplace( QString, QString, bool* ) ),
+ mOperationService, SLOT( on_operation_askForReplace( QString, QString, bool* )), Qt::BlockingQueuedConnection );
+ connect( this, SIGNAL( driveSpaceChanged() ),
+ mOperationService, SLOT( on_operation_driveSpaceChanged() ) );
+}
+
+/*
+ * Destructs the copy or move operation.
+ */
+FmOperationCopyOrMove::~FmOperationCopyOrMove()
+{
+}
+
+/*
+ * Returns the source file or path list
+ */
+QStringList FmOperationCopyOrMove::sourceList()
+{
+ return mSourceList;
+}
+
+/*
+ * Returns the target path
+ */
+QString FmOperationCopyOrMove::targetPath()
+{
+ return mTargetPath;
+}
+
+/*
+ * Starts the operation.
+ * \a isStopped flag the outside stop operation
+ */
+void FmOperationCopyOrMove::start( volatile bool *isStopped )
+{
+ mStop = isStopped;
+ mTotalSize = 0;
+ mCopiedOrMovedSize = 0;
+ mCurrentStep = 0;
+
+ if( mSourceList.empty() ) {
+ emit notifyError( FmErrWrongParam, mErrString );
+ return ;
+ }
+
+ emit notifyPreparing( true );
+
+ int numofFolders = 0;
+ int numofFiles = 0;
+
+ int ret = FmFolderDetails::queryDetailOfContentList( mSourceList, numofFolders,
+ numofFiles, mTotalSize, mStop, true );
+ if( ret != FmErrNone ) {
+ emit notifyError( ret, mErrString );
+ return;
+ }
+
+ emit notifyStart( true, mTotalSteps );
+
+ foreach( const QString& source, mSourceList ) {
+ // formatPath, but do not append splash in the end
+ // Otherwise could not get fileName in QFileInfo::fileName
+ QString checkedSource( FmUtils::formatPath( source ) );
+ QFileInfo fi( checkedSource );
+ if( !fi.exists() ) {
+ mErrString = checkedSource;
+ emit notifyError( FmErrSrcPathDoNotExist, mErrString );
+ return;
+ }
+ QString newName;
+ bool isAcceptReplace = false;
+ QFileInfo destFi( mTargetPath + fi.fileName() );
+
+ // while for duplicated file/dir
+ while( destFi.exists() ) {
+ if( destFi.isFile() && destFi.absoluteFilePath().compare( fi.absoluteFilePath(), Qt::CaseInsensitive ) != 0 ) {
+ emit askForReplace( destFi.absoluteFilePath(), fi.absoluteFilePath(), &isAcceptReplace );
+ if( isAcceptReplace ) {
+ //delete src file
+ if( !QFile::remove( destFi.absoluteFilePath() ) ) {
+ mErrString = destFi.absoluteFilePath();
+ ret = FmErrCannotRemove;
+ break;
+ }
+ destFi.setFile( destFi.absoluteFilePath() );
+ } else {
+ queryForRename( destFi.absoluteFilePath(), &newName );
+ if( newName.isEmpty() ) {
+ ret = FmErrCancel;
+ break;
+ }
+ QString targetName = mTargetPath + newName;
+ destFi.setFile( targetName );
+ }
+ } else{
+ // destination is dir
+ queryForRename( destFi.absoluteFilePath(), &newName );
+ if( newName.isEmpty() ) {
+ ret = FmErrCancel;
+ break;
+ }
+ QString targetName = mTargetPath + newName;
+ destFi.setFile( targetName );
+ }
+ }
+ if( ret != FmErrNone ) {
+ emit notifyError( ret, mErrString );
+ // refresh drive space no care if cancel, error or finished.
+ // as filemanger cannot notify drive space changed
+ // do not refresh path as QFileSystemModel will do auto-refresh
+ emit driveSpaceChanged();
+ return;
+ }
+ ret = copyOrMove( checkedSource, mTargetPath, newName );
+ if( ret != FmErrNone ) {
+ emit notifyError( ret, mErrString );
+ emit driveSpaceChanged();
+ return;
+ }
+ }
+ emit notifyFinish();
+ emit driveSpaceChanged();
+}
+
+/*
+ * Copy or move the \a source to \a targetPath
+ * with \a newTargetName
+ */
+int FmOperationCopyOrMove::copyOrMove( const QString &source, const QString &targetPath,
+ const QString &newTargetName )
+{
+ if( *mStop ) {
+ return FmErrCancel;
+ }
+
+ QFileInfo fi( source );
+ if( !fi.exists() ) {
+ mErrString = source;
+ return FmErrSrcPathDoNotExist;
+ }
+ QString newName;
+ if( !newTargetName.isEmpty() ) {
+ newName = targetPath + newTargetName;
+ } else {
+ newName = targetPath + fi.fileName();
+ }
+
+ int ret = FmErrNone;
+
+ if ( fi.isFile() ) {
+ quint64 fileSize = fi.size();
+ ret = copyOneFile( source, newName );
+ if (ret != FmErrNone) {
+ mErrString = source;
+ return ret;
+ }
+ if ( operationType() == FmOperationService::EOperationTypeMove
+ && !QFile::remove( source ) ) {
+ mErrString = source;
+ return FmErrCannotRemove;
+ }
+ } else if ( fi.isDir() ) {
+ if( operationType() == FmOperationService::EOperationTypeMove
+ && FmUtils::isDefaultFolder( source ) ){
+ ret = FmErrRemoveDefaultFolder;
+ }
+ else{
+ ret = copyOrMoveDirInsideContent( source, newName );
+ }
+ if( ret!= FmErrNone ) {
+ return ret;
+ }
+ if ( operationType() == FmOperationService::EOperationTypeMove
+ && !fi.dir().rmdir( fi.absoluteFilePath() ) ) {
+ mErrString = fi.absolutePath();
+ return FmErrCannotRemove;
+ }
+ } else {
+ qWarning( "Things other than file and directory are not copied" );
+ ret = FmErrIsNotFileOrFolder;
+ }
+
+ return ret;
+}
+
+/*
+ copy \a srcPath as \a destPath
+ both \a srcPath and \a destPath are Directory
+*/
+int FmOperationCopyOrMove::copyOrMoveDirInsideContent( const QString &srcPath, const QString &destPath )
+{
+ QFileInfo srcInfo( srcPath );
+ QFileInfo destInfo( destPath );
+
+ if( FmUtils::isSubLevelPath( srcPath, destPath ) ) {
+ mErrString = destPath;
+ if ( operationType() == FmOperationService::EOperationTypeMove ) {
+ return FmErrMoveDestToSubFolderInSrc;
+ } else {
+ return FmErrCopyDestToSubFolderInSrc;
+ }
+
+ }
+
+ if( !srcInfo.isDir() || !srcInfo.exists() ) {
+ mErrString = srcPath;
+ return FmErrSrcPathDoNotExist;
+ }
+
+ if( !destInfo.exists() ) {
+ if( !destInfo.dir().mkdir( destInfo.absoluteFilePath() ) ) {
+ mErrString = destPath;
+ return FmErrCannotMakeDir;
+ }
+ }
+ destInfo.setFile( destPath );
+ if( !destInfo.isDir() ) {
+ mErrString = destPath;
+ return FmErrCannotMakeDir;
+ }
+
+ //start to copy
+ QFileInfoList infoList = QDir( srcPath ).entryInfoList( QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden | QDir::System );
+ while( !infoList.isEmpty() ) {
+ if( *mStop ) {
+ return FmErrCancel;
+ }
+
+ QFileInfo fileInfo = infoList.takeFirst();
+ if( fileInfo.isFile() ){
+ //copy file
+ QString newFilePath = destPath + fileInfo.absoluteFilePath().mid( srcPath.length() );
+ int ret = copyOneFile( fileInfo.absoluteFilePath(), newFilePath );
+ if ( ret != FmErrNone ) {
+ mErrString = fileInfo.absoluteFilePath();
+ return ret;
+ }
+ if( operationType() == FmOperationService::EOperationTypeMove
+ && !QFile::remove( fileInfo.absoluteFilePath() ) ) {
+ mErrString = fileInfo.absoluteFilePath();
+ return FmErrCannotRemove;
+ }
+ } else if( fileInfo.isDir() ) {
+ //makedir
+ QString newDirPath = destPath + fileInfo.absoluteFilePath().mid( srcPath.length() );
+ if( !QDir( newDirPath ).exists() && !QDir( destPath ).mkdir( newDirPath ) ) {
+ mErrString = newDirPath;
+ return FmErrCannotMakeDir;
+ }
+ // add dir content to list.
+ QFileInfoList infoListDir = QDir( fileInfo.absoluteFilePath() ).entryInfoList(
+ QDir::NoDotAndDotDot | QDir::AllEntries );
+ if ( operationType() == FmOperationService::EOperationTypeMove ) {
+ if( infoListDir.isEmpty() ) {
+ if ( !fileInfo.dir().rmdir( fileInfo.absoluteFilePath() ) ) {
+ mErrString = fileInfo.absolutePath();
+ return FmErrCannotRemove;
+ }
+ } else {
+ infoList.push_front( fileInfo );
+ }
+ }
+ while( !infoListDir.isEmpty() ) {
+ infoList.push_front( infoListDir.takeLast() );
+ }
+
+ } else {
+ mErrString = fileInfo.absoluteFilePath();
+ return FmErrIsNotFileOrFolder;
+ }
+
+ }
+
+ return FmErrNone;
+}
+
+/*
+ * Increase the progress bar
+ * \a size the current copy or moved size
+ */
+void FmOperationCopyOrMove::increaseProgress( quint64 size )
+{
+ if( mTotalSize <=0 ) {
+ return;
+ }
+ mCopiedOrMovedSize += size;
+ int step = ( mCopiedOrMovedSize * FmTotalProgressBarSteps ) / mTotalSize;
+ if( step > mCurrentStep ) {
+ mCurrentStep = step;
+ emit notifyProgress( mCurrentStep );
+ }
+}
+
+/*
+ * Emits askForRename signal.
+ * \a srcFile the source file path.
+ * \a destFile get the new name from user input
+ */
+void FmOperationCopyOrMove::queryForRename( const QString &srcFile, QString *destFile )
+{
+ emit askForRename( srcFile, destFile );
+}
+
+/*
+ * Copys one file from \a srcFile to \a desFile
+ */
+int FmOperationCopyOrMove::copyOneFile( const QString &srcFile, const QString &desFile )
+{
+ QFile src( srcFile );
+ QFile des( desFile );
+ if ( !src.open( QIODevice::ReadOnly ) || !des.open( QIODevice::WriteOnly ) ) {
+ return FmErrCannotCopy;
+ }
+ QDataStream outputStream( &src );
+ QDataStream inputStream( &des );
+ //used to cache data from source file to target file during one copy
+ QScopedPointer<char> tempString( new char[FmOneTimeCopyOrMoveSize] );
+ memset( tempString.data(), 0, FmOneTimeCopyOrMoveSize );
+ while ( !outputStream.atEnd() ) {
+ if ( *mStop ) {
+ src.close();
+ des.close();
+ QFile::remove( desFile );
+ return FmErrCancel;
+ }
+ int ret = outputStream.readRawData(tempString.data(), FmOneTimeCopyOrMoveSize );
+ if (ret == -1) {
+ src.close();
+ des.close();
+ QFile::remove( desFile );
+ return FmErrCannotCopy;
+ }
+ ret = inputStream.writeRawData(tempString.data(), ret);
+ if (ret == -1) {
+ src.close();
+ des.close();
+ QFile::remove( desFile );
+ return FmErrCannotCopy;
+ }
+ memset( tempString.data(), 0, FmOneTimeCopyOrMoveSize );
+ increaseProgress( ret );
+ }
+ src.close();
+ des.close();
+ if ( FmUtils::setFileAttributes( srcFile, desFile ) != FmErrNone ) {
+ QFile::remove( desFile );
+ return FmErrCannotCopy;
+ }
+ return FmErrNone;
+}
+
+/*
+ * Prepare some work before starting operation.
+ * Returns error number.
+ */
+int FmOperationCopyOrMove::prepare()
+{
+ if( mSourceList.empty() ) {
+ return FmErrWrongParam;
+ } else {
+ return FmErrNone;
+ }
+}
+