filemanager/src/filemanager/src/operationservice/fmoperationcopyormove.cpp
changeset 33 328cf6fbe40c
child 40 4167eb56f30d
equal deleted inserted replaced
32:39cf9ced4cc4 33:328cf6fbe40c
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 #include "fmoperationcopyormove.h"
       
    19 #include "fmcommon.h"
       
    20 #include "fmoperationbase.h"
       
    21 #include "fmdrivedetailstype.h"
       
    22 #include "fmutils.h"
       
    23 
       
    24 #include <QDir>
       
    25 #include <QFileInfo>
       
    26 #include <QStringList>
       
    27 #include <QStack>
       
    28 
       
    29 /* \fn void askForReplace( const QString &srcFile, const QString &destFile, bool *isAccepted )
       
    30  * This signal is emitted when the same file as \a srcFile exists.
       
    31  * \a destFile the destination file.
       
    32  * \a isAccepted whether to replace the destination file.
       
    33  */
       
    34 
       
    35 /* \fn void askForRename( const QString &srcFile, QString *destFile )
       
    36  * This signal is emitted when \a srcFile needs to be renamed.
       
    37  * \a destFile return the new name.
       
    38  */
       
    39 
       
    40 /* \fn  void driveSpaceChanged()
       
    41  * This signal is emitted when copy or move is completed, and used to update the drive size.
       
    42  */
       
    43 
       
    44 //the size of one time copy
       
    45 const int FmOneTimeCopyOrMoveSize = 1024;
       
    46 //the total steps of progress bar
       
    47 const int FmTotalProgressBarSteps = 100;
       
    48 /*
       
    49  * Constructs a copy or move operation with
       
    50  * \a operationService parent
       
    51  * \a type the type of operation(EOperationTypeCopy or EOperationTypeMove)
       
    52  * \a sourceList the source file or path lists that will be copied
       
    53  * \a targetPath the target path where the source file will be copied
       
    54  */
       
    55 FmOperationCopyOrMove::FmOperationCopyOrMove( FmOperationService *operationService, FmOperationService::TOperationType type, const QStringList &sourceList, const QString &targetPath )
       
    56         : FmOperationBase( operationService, type ),
       
    57           mOperationService( operationService ), mSourceList( sourceList ), mTargetPath( targetPath ),
       
    58           mStop( 0 ), mTotalSize( 0 ), mCopiedOrMovedSize( 0 ), mTotalSteps( FmTotalProgressBarSteps ), mCurrentStep( 0 )
       
    59 {
       
    60 	mTargetPath = FmUtils::fillPathWithSplash( mTargetPath );
       
    61     connect( this, SIGNAL( askForRename( QString, QString* ) ),
       
    62                 mOperationService, SLOT( on_operation_askForRename( QString, QString* )), Qt::BlockingQueuedConnection );
       
    63     connect( this, SIGNAL( askForReplace( QString, QString, bool* ) ),
       
    64                 mOperationService, SLOT( on_operation_askForReplace( QString, QString, bool* )), Qt::BlockingQueuedConnection );    
       
    65     connect( this, SIGNAL( driveSpaceChanged() ),
       
    66                 mOperationService, SLOT( on_operation_driveSpaceChanged() ) );
       
    67 }
       
    68 
       
    69 /*
       
    70  * Destructs the copy or move operation.
       
    71  */
       
    72 FmOperationCopyOrMove::~FmOperationCopyOrMove()
       
    73 {
       
    74 }
       
    75 
       
    76 /*
       
    77  * Returns the source file or path list
       
    78  */
       
    79 QStringList FmOperationCopyOrMove::sourceList()
       
    80 {
       
    81     return mSourceList;
       
    82 }
       
    83 
       
    84 /*
       
    85  * Returns the target path
       
    86  */
       
    87 QString FmOperationCopyOrMove::targetPath()
       
    88 {
       
    89     return mTargetPath;
       
    90 }
       
    91 
       
    92 /*
       
    93  * Starts the operation.
       
    94  * \a isStopped flag the outside stop operation
       
    95  */
       
    96 void FmOperationCopyOrMove::start( volatile bool *isStopped )
       
    97 {
       
    98     mStop = isStopped; 
       
    99     mTotalSize   = 0;
       
   100     mCopiedOrMovedSize  = 0;
       
   101     mCurrentStep = 0;
       
   102 
       
   103     if( mSourceList.empty() ) {
       
   104         emit notifyError( FmErrWrongParam, mErrString );    
       
   105         return ;
       
   106     }
       
   107 
       
   108     emit notifyPreparing( true );
       
   109 
       
   110     int numofFolders = 0;
       
   111     int numofFiles      = 0;
       
   112 
       
   113     int ret = FmFolderDetails::queryDetailOfContentList( mSourceList, numofFolders, 
       
   114         numofFiles, mTotalSize, mStop, true );
       
   115     if( ret != FmErrNone ) {
       
   116         emit notifyError( ret, mErrString );
       
   117         return;        
       
   118     }
       
   119 
       
   120     emit notifyStart( true, mTotalSteps );
       
   121 
       
   122     foreach( const QString& source, mSourceList ) {
       
   123         // formatPath, but do not append splash in the end
       
   124         // Otherwise could not get fileName in QFileInfo::fileName
       
   125         QString checkedSource( FmUtils::formatPath( source ) );
       
   126         QFileInfo fi( checkedSource );
       
   127         if( !fi.exists() ) {
       
   128             mErrString = checkedSource;            
       
   129             emit notifyError( FmErrSrcPathDoNotExist, mErrString );
       
   130             return;
       
   131         }
       
   132         QString newName;
       
   133         bool    isAcceptReplace = false;
       
   134         QFileInfo destFi( mTargetPath + fi.fileName() );
       
   135 
       
   136         // while for duplicated file/dir
       
   137         while( destFi.exists() ) {
       
   138             if( destFi.isFile() && destFi.absoluteFilePath().compare( fi.absoluteFilePath(), Qt::CaseInsensitive ) != 0 ) {
       
   139                 emit askForReplace( destFi.absoluteFilePath(), fi.absoluteFilePath(), &isAcceptReplace );
       
   140                 if( isAcceptReplace ) {
       
   141                     //delete src file
       
   142                     if( !QFile::remove( destFi.absoluteFilePath() ) ) {
       
   143                         mErrString = destFi.absoluteFilePath();
       
   144                         ret = FmErrCannotRemove;
       
   145                         break;
       
   146                     }
       
   147                     destFi.setFile( destFi.absoluteFilePath() );
       
   148                 } else {
       
   149                     queryForRename( destFi.absoluteFilePath(), &newName );
       
   150                     if( newName.isEmpty() ) {
       
   151                         ret = FmErrCancel;
       
   152                         break;
       
   153                     }
       
   154                     QString targetName = mTargetPath + newName;
       
   155                     destFi.setFile( targetName );
       
   156                 }
       
   157             } else{
       
   158                 // destination is dir
       
   159                 queryForRename( destFi.absoluteFilePath(), &newName );
       
   160                 if( newName.isEmpty() ) {
       
   161                     ret = FmErrCancel;
       
   162                     break;
       
   163                 }
       
   164                 QString targetName = mTargetPath + newName;
       
   165                 destFi.setFile( targetName );
       
   166             }
       
   167         }
       
   168         if( ret != FmErrNone ) {
       
   169             emit notifyError( ret, mErrString );
       
   170             // refresh drive space no care if cancel, error or finished.
       
   171             // as filemanger cannot notify drive space changed
       
   172             // do not refresh path as QFileSystemModel will do auto-refresh
       
   173             emit driveSpaceChanged();
       
   174             return;
       
   175         }
       
   176         ret = copyOrMove( checkedSource, mTargetPath, newName );
       
   177         if( ret != FmErrNone ) {
       
   178             emit notifyError( ret, mErrString );            
       
   179             emit driveSpaceChanged();
       
   180             return;
       
   181         }
       
   182     }
       
   183     emit notifyFinish();
       
   184     emit driveSpaceChanged();
       
   185 }
       
   186 
       
   187 /*
       
   188  * Copy or move the \a source to \a targetPath
       
   189  * with \a newTargetName
       
   190  */
       
   191 int FmOperationCopyOrMove::copyOrMove( const QString &source, const QString &targetPath,
       
   192                          const QString &newTargetName )
       
   193 {        
       
   194     if( *mStop ) {
       
   195         return FmErrCancel;
       
   196     }
       
   197 
       
   198     QFileInfo fi( source );
       
   199     if( !fi.exists() ) {
       
   200         mErrString = source;
       
   201         return FmErrSrcPathDoNotExist;
       
   202     }
       
   203     QString newName;
       
   204     if( !newTargetName.isEmpty() ) {
       
   205         newName = targetPath + newTargetName;
       
   206     } else {
       
   207         newName = targetPath + fi.fileName();
       
   208     }
       
   209 
       
   210     int ret = FmErrNone;
       
   211     
       
   212     if ( fi.isFile() ) {
       
   213         quint64 fileSize = fi.size();
       
   214         ret = copyOneFile( source, newName );
       
   215         if (ret != FmErrNone) {
       
   216             mErrString = source;
       
   217             return ret;
       
   218         }        
       
   219         if ( operationType() == FmOperationService::EOperationTypeMove 
       
   220                 && !QFile::remove( source ) ) {
       
   221             mErrString = source;
       
   222             return FmErrCannotRemove;           
       
   223         }
       
   224     } else if ( fi.isDir() ) {
       
   225         if( operationType() == FmOperationService::EOperationTypeMove 
       
   226                 && FmUtils::isDefaultFolder( source ) ){
       
   227             ret = FmErrRemoveDefaultFolder;
       
   228         }
       
   229         else{
       
   230             ret = copyOrMoveDirInsideContent( source, newName );
       
   231         }        
       
   232         if( ret!= FmErrNone ) {
       
   233             return ret;
       
   234         }
       
   235         if ( operationType() == FmOperationService::EOperationTypeMove 
       
   236                 && !fi.dir().rmdir( fi.absoluteFilePath() ) ) {
       
   237             mErrString = fi.absolutePath();
       
   238             return FmErrCannotRemove;
       
   239         }
       
   240     } else {
       
   241         qWarning( "Things other than file and directory are not copied" );
       
   242         ret = FmErrIsNotFileOrFolder;
       
   243     }
       
   244 
       
   245     return ret;
       
   246 }
       
   247 
       
   248 /*
       
   249   copy \a srcPath as \a destPath
       
   250   both \a srcPath and \a destPath are Directory
       
   251 */
       
   252 int FmOperationCopyOrMove::copyOrMoveDirInsideContent( const QString &srcPath, const QString &destPath )
       
   253 {
       
   254     QFileInfo srcInfo( srcPath );
       
   255     QFileInfo destInfo( destPath );
       
   256     
       
   257     if( FmUtils::isSubLevelPath( srcPath, destPath ) ) {
       
   258         mErrString = destPath;
       
   259         if ( operationType() == FmOperationService::EOperationTypeMove ) {
       
   260             return FmErrMoveDestToSubFolderInSrc;
       
   261         } else {
       
   262             return FmErrCopyDestToSubFolderInSrc;
       
   263         }
       
   264         
       
   265     }
       
   266     
       
   267     if( !srcInfo.isDir() || !srcInfo.exists() ) {
       
   268         mErrString = srcPath;
       
   269         return FmErrSrcPathDoNotExist;
       
   270     }
       
   271     
       
   272     if( !destInfo.exists() ) {
       
   273         if( !destInfo.dir().mkdir( destInfo.absoluteFilePath() ) ) {
       
   274             mErrString = destPath;
       
   275             return FmErrCannotMakeDir;
       
   276         }
       
   277     }    
       
   278     destInfo.setFile( destPath );
       
   279     if( !destInfo.isDir() ) {
       
   280         mErrString = destPath;
       
   281         return FmErrCannotMakeDir;
       
   282     }
       
   283 
       
   284     //start to copy
       
   285     QFileInfoList infoList = QDir( srcPath ).entryInfoList( QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden | QDir::System );
       
   286     while( !infoList.isEmpty() ) {
       
   287         if( *mStop ) {
       
   288             return FmErrCancel;
       
   289         }
       
   290 
       
   291         QFileInfo fileInfo = infoList.takeFirst();
       
   292         if( fileInfo.isFile() ){
       
   293             //copy file
       
   294             QString newFilePath = destPath + fileInfo.absoluteFilePath().mid( srcPath.length() );
       
   295             int ret = copyOneFile( fileInfo.absoluteFilePath(), newFilePath );
       
   296             if ( ret != FmErrNone ) {
       
   297                 mErrString = fileInfo.absoluteFilePath();
       
   298                 return ret;
       
   299             }
       
   300             if( operationType() == FmOperationService::EOperationTypeMove 
       
   301                     && !QFile::remove( fileInfo.absoluteFilePath() ) ) {
       
   302                 mErrString = fileInfo.absoluteFilePath();
       
   303                 return FmErrCannotRemove;
       
   304             }   
       
   305         } else if( fileInfo.isDir() ) {
       
   306             //makedir
       
   307             QString newDirPath = destPath + fileInfo.absoluteFilePath().mid( srcPath.length() );
       
   308             if( !QDir( newDirPath ).exists() && !QDir( destPath ).mkdir( newDirPath ) ) {
       
   309                 mErrString = newDirPath;
       
   310                 return FmErrCannotMakeDir;
       
   311             }
       
   312             // add dir content to list.
       
   313             QFileInfoList infoListDir = QDir( fileInfo.absoluteFilePath() ).entryInfoList(
       
   314                 QDir::NoDotAndDotDot | QDir::AllEntries );
       
   315             if ( operationType() == FmOperationService::EOperationTypeMove ) {
       
   316                 if( infoListDir.isEmpty() ) {
       
   317                     if ( !fileInfo.dir().rmdir( fileInfo.absoluteFilePath() ) ) {
       
   318                         mErrString = fileInfo.absolutePath();
       
   319                         return FmErrCannotRemove;
       
   320                     }
       
   321                 } else {
       
   322                     infoList.push_front( fileInfo );
       
   323                 }
       
   324             }
       
   325             while( !infoListDir.isEmpty() ) {
       
   326                 infoList.push_front( infoListDir.takeLast() );
       
   327             }
       
   328 
       
   329         } else {
       
   330             mErrString = fileInfo.absoluteFilePath();
       
   331             return FmErrIsNotFileOrFolder;
       
   332         }
       
   333 
       
   334     }
       
   335 
       
   336     return FmErrNone;
       
   337 }
       
   338 
       
   339 /*
       
   340  * Increase the progress bar
       
   341  * \a size the current copy or moved size
       
   342  */
       
   343 void FmOperationCopyOrMove::increaseProgress( quint64 size )
       
   344 {
       
   345     if( mTotalSize <=0 ) {
       
   346         return;
       
   347     }
       
   348     mCopiedOrMovedSize += size;
       
   349     int step = ( mCopiedOrMovedSize * FmTotalProgressBarSteps ) / mTotalSize;
       
   350     if( step > mCurrentStep ) {
       
   351         mCurrentStep = step;
       
   352         emit notifyProgress( mCurrentStep );
       
   353     }
       
   354 }
       
   355 
       
   356 /*
       
   357  * Emits askForRename signal.
       
   358  * \a srcFile the source file path.
       
   359  * \a destFile get the new name from user input
       
   360  */
       
   361 void FmOperationCopyOrMove::queryForRename( const QString &srcFile, QString *destFile )
       
   362 {
       
   363     emit askForRename( srcFile, destFile );
       
   364 }
       
   365 
       
   366 /*
       
   367  * Copys one file from \a srcFile to \a desFile
       
   368  */
       
   369 int FmOperationCopyOrMove::copyOneFile( const QString &srcFile, const QString &desFile )
       
   370 {
       
   371     QFile src( srcFile );
       
   372     QFile des( desFile );
       
   373     if ( !src.open( QIODevice::ReadOnly ) || !des.open( QIODevice::WriteOnly ) ) {
       
   374         return FmErrCannotCopy;
       
   375     }
       
   376     QDataStream  outputStream( &src );
       
   377     QDataStream  inputStream( &des );
       
   378     //used to cache data from source file to target file during one copy
       
   379     QScopedPointer<char> tempString( new char[FmOneTimeCopyOrMoveSize] );
       
   380     memset( tempString.data(), 0, FmOneTimeCopyOrMoveSize );
       
   381     while ( !outputStream.atEnd() ) {
       
   382         if ( *mStop ) {            
       
   383             src.close();
       
   384             des.close();
       
   385             QFile::remove( desFile );
       
   386             return FmErrCancel;
       
   387         }
       
   388         int ret = outputStream.readRawData(tempString.data(), FmOneTimeCopyOrMoveSize );
       
   389         if (ret == -1) {
       
   390             src.close();
       
   391             des.close();
       
   392             QFile::remove( desFile );            
       
   393             return FmErrCannotCopy;
       
   394         }
       
   395         ret = inputStream.writeRawData(tempString.data(), ret);
       
   396         if (ret == -1) {
       
   397             src.close();
       
   398             des.close();
       
   399             QFile::remove( desFile );            
       
   400             return FmErrCannotCopy;
       
   401         }        
       
   402         memset( tempString.data(), 0, FmOneTimeCopyOrMoveSize );
       
   403         increaseProgress( ret );
       
   404     }    
       
   405     src.close();
       
   406     des.close();
       
   407     if ( FmUtils::setFileAttributes( srcFile, desFile ) != FmErrNone ) {
       
   408         QFile::remove( desFile );        
       
   409         return FmErrCannotCopy;
       
   410     }
       
   411     return FmErrNone;
       
   412 }
       
   413 
       
   414 /*
       
   415  * Prepare some work before starting operation.
       
   416  * Returns error number.
       
   417  */
       
   418 int FmOperationCopyOrMove::prepare()
       
   419 {
       
   420     if( mSourceList.empty() ) {
       
   421         return FmErrWrongParam;
       
   422     } else {
       
   423     return FmErrNone;
       
   424     }
       
   425 }
       
   426