filemanager/src/filemanager/src/operationservice/fmoperationcopyormove.cpp
branchRCL_3
changeset 39 65326cf895ed
parent 38 491b3ed49290
child 42 f5c50b8af68c
equal deleted inserted replaced
38:491b3ed49290 39:65326cf895ed
     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 	emit notifyPreparing( true );
       
   108 
       
   109     int numofFolders = 0;
       
   110     int numofFiles      = 0;
       
   111 
       
   112     int ret = FmFolderDetails::queryDetailOfContentList( mSourceList, numofFolders, 
       
   113         numofFiles, mTotalSize, mStop, true );
       
   114     if( ret != FmErrNone ) {
       
   115         emit notifyError( ret, mErrString );
       
   116         return;        
       
   117     }    
       
   118     if ( !targetHasEnoughSpace() ) {
       
   119         emit notifyError( FmErrDiskFull, mErrString );
       
   120         return;
       
   121         }    
       
   122     emit notifyStart( true, mTotalSteps );
       
   123 
       
   124     foreach( const QString& source, mSourceList ) {
       
   125         // formatPath, but do not append splash in the end
       
   126         // Otherwise could not get fileName in QFileInfo::fileName
       
   127         QString checkedSource( FmUtils::formatPath( source ) );
       
   128         QFileInfo fi( checkedSource );
       
   129         if( !fi.exists() ) {
       
   130             mErrString = checkedSource;            
       
   131             emit notifyError( FmErrSrcPathDoNotExist, mErrString );
       
   132             return;
       
   133         }
       
   134         QString newName;
       
   135         bool    isAcceptReplace = false;
       
   136         QFileInfo destFi( mTargetPath + fi.fileName() );
       
   137 
       
   138         // while for duplicated file/dir
       
   139         while( destFi.exists() ) {
       
   140             if( destFi.isFile() && destFi.absoluteFilePath().compare( fi.absoluteFilePath(), Qt::CaseInsensitive ) != 0 ) {
       
   141                 emit askForReplace( destFi.absoluteFilePath(), fi.absoluteFilePath(), &isAcceptReplace );
       
   142                 if( isAcceptReplace ) {
       
   143                     //delete src file
       
   144                     if( !QFile::remove( destFi.absoluteFilePath() ) ) {
       
   145                         mErrString = destFi.absoluteFilePath();
       
   146                         ret = FmErrCannotRemove;
       
   147                         break;
       
   148                     }
       
   149                     destFi.setFile( destFi.absoluteFilePath() );
       
   150                 } else {
       
   151                     queryForRename( destFi.absoluteFilePath(), &newName );
       
   152                     if( newName.isEmpty() ) {
       
   153                         ret = FmErrCancel;
       
   154                         break;
       
   155                     }
       
   156                     QString targetName = mTargetPath + newName;
       
   157                     destFi.setFile( targetName );
       
   158                 }
       
   159             } else{
       
   160                 // destination is dir
       
   161                 queryForRename( destFi.absoluteFilePath(), &newName );
       
   162                 if( newName.isEmpty() ) {
       
   163                     ret = FmErrCancel;
       
   164                     break;
       
   165                 }
       
   166                 QString targetName = mTargetPath + newName;
       
   167                 destFi.setFile( targetName );
       
   168             }
       
   169         }
       
   170         if( ret != FmErrNone ) {
       
   171             emit notifyError( ret, mErrString );
       
   172             // refresh drive space no care if cancel, error or finished.
       
   173             // as filemanger cannot notify drive space changed
       
   174             // do not refresh path as QFileSystemModel will do auto-refresh
       
   175             emit driveSpaceChanged();
       
   176             return;
       
   177         }
       
   178         ret = copyOrMove( checkedSource, mTargetPath, newName );
       
   179         if( ret != FmErrNone ) {
       
   180             emit notifyError( ret, mErrString );            
       
   181             emit driveSpaceChanged();
       
   182             return;
       
   183         }
       
   184     }
       
   185     emit notifyFinish();
       
   186     emit driveSpaceChanged();
       
   187 }
       
   188 
       
   189 /*
       
   190  * Copy or move the \a source to \a targetPath
       
   191  * with \a newTargetName
       
   192  */
       
   193 int FmOperationCopyOrMove::copyOrMove( const QString &source, const QString &targetPath,
       
   194                          const QString &newTargetName )
       
   195 {        
       
   196     if( *mStop ) {
       
   197         return FmErrCancel;
       
   198     }
       
   199 
       
   200     QFileInfo fi( source );
       
   201     if( !fi.exists() ) {
       
   202         mErrString = source;
       
   203         return FmErrSrcPathDoNotExist;
       
   204     }
       
   205     QString newName;
       
   206     if( !newTargetName.isEmpty() ) {
       
   207         newName = targetPath + newTargetName;
       
   208     } else {
       
   209         newName = targetPath + fi.fileName();
       
   210     }
       
   211 
       
   212     int ret = FmErrNone;
       
   213     
       
   214     if ( fi.isFile() ) {
       
   215         if ( FmUtils::getDriveLetterFromPath( source ) == 
       
   216                 FmUtils::getDriveLetterFromPath( targetPath ) && 
       
   217                 operationType() == FmOperationService::EOperationTypeMove ) 
       
   218             {
       
   219             return FmUtils::moveInsideDrive( source, newName );
       
   220             
       
   221             }
       
   222         quint64 fileSize = fi.size();
       
   223         ret = copyOneFile( source, newName );
       
   224         if (ret != FmErrNone) {
       
   225             mErrString = source;
       
   226             return ret;
       
   227         }        
       
   228         if ( operationType() == FmOperationService::EOperationTypeMove 
       
   229                 && !QFile::remove( source ) ) {
       
   230             mErrString = source;
       
   231             return FmErrCannotRemove;           
       
   232         }
       
   233     } else if ( fi.isDir() ) {
       
   234         if( operationType() == FmOperationService::EOperationTypeMove 
       
   235                 && FmUtils::isDefaultFolder( source ) ){
       
   236             ret = FmErrRemoveDefaultFolder;
       
   237         }
       
   238         else{
       
   239             ret = copyOrMoveDirInsideContent( source, newName );
       
   240         }        
       
   241         if( ret!= FmErrNone ) {
       
   242             return ret;
       
   243         }
       
   244         if ( operationType() == FmOperationService::EOperationTypeMove 
       
   245                 && !fi.dir().rmdir( fi.absoluteFilePath() ) ) {
       
   246             mErrString = fi.absolutePath();
       
   247             return FmErrCannotRemove;
       
   248         }
       
   249     } else {
       
   250         qWarning( "Things other than file and directory are not copied" );
       
   251         ret = FmErrIsNotFileOrFolder;
       
   252     }
       
   253 
       
   254     return ret;
       
   255 }
       
   256 
       
   257 /*
       
   258   copy \a srcPath as \a destPath
       
   259   both \a srcPath and \a destPath are Directory
       
   260 */
       
   261 int FmOperationCopyOrMove::copyOrMoveDirInsideContent( const QString &srcPath, const QString &destPath )
       
   262 {
       
   263     QFileInfo srcInfo( srcPath );
       
   264     QFileInfo destInfo( destPath );
       
   265     
       
   266     if( FmUtils::isSubLevelPath( srcPath, destPath ) ) {
       
   267         mErrString = destPath;
       
   268         if ( operationType() == FmOperationService::EOperationTypeMove ) {
       
   269             return FmErrMoveDestToSubFolderInSrc;
       
   270         } else {
       
   271             return FmErrCopyDestToSubFolderInSrc;
       
   272         }
       
   273         
       
   274     }
       
   275     
       
   276     if( !srcInfo.isDir() || !srcInfo.exists() ) {
       
   277         mErrString = srcPath;
       
   278         return FmErrSrcPathDoNotExist;
       
   279     }
       
   280     
       
   281     if( !destInfo.exists() ) {
       
   282         if( !destInfo.dir().mkdir( destInfo.absoluteFilePath() ) ) {
       
   283             mErrString = destPath;
       
   284             return FmErrCannotMakeDir;
       
   285         }
       
   286     }    
       
   287     destInfo.setFile( destPath );
       
   288     if( !destInfo.isDir() ) {
       
   289         mErrString = destPath;
       
   290         return FmErrCannotMakeDir;
       
   291     }
       
   292 
       
   293     //start to copy
       
   294     QFileInfoList infoList = QDir( srcPath ).entryInfoList( QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden | QDir::System );
       
   295     while( !infoList.isEmpty() ) {
       
   296         if( *mStop ) {
       
   297             return FmErrCancel;
       
   298         }
       
   299 
       
   300         QFileInfo fileInfo = infoList.takeFirst();
       
   301         if( fileInfo.isFile() ){
       
   302             //copy file
       
   303             QString newFilePath = destPath + fileInfo.absoluteFilePath().mid( srcPath.length() );
       
   304             int ret = copyOneFile( fileInfo.absoluteFilePath(), newFilePath );
       
   305             if ( ret != FmErrNone ) {
       
   306                 mErrString = fileInfo.absoluteFilePath();
       
   307                 return ret;
       
   308             }
       
   309             if( operationType() == FmOperationService::EOperationTypeMove 
       
   310                     && !QFile::remove( fileInfo.absoluteFilePath() ) ) {
       
   311                 mErrString = fileInfo.absoluteFilePath();
       
   312                 return FmErrCannotRemove;
       
   313             }   
       
   314         } else if( fileInfo.isDir() ) {
       
   315             //makedir
       
   316             QString newDirPath = destPath + fileInfo.absoluteFilePath().mid( srcPath.length() );
       
   317             if( !QDir( newDirPath ).exists() && !QDir( destPath ).mkdir( newDirPath ) ) {
       
   318                 mErrString = newDirPath;
       
   319                 return FmErrCannotMakeDir;
       
   320             }
       
   321             // add dir content to list.
       
   322             QFileInfoList infoListDir = QDir( fileInfo.absoluteFilePath() ).entryInfoList(
       
   323                 QDir::NoDotAndDotDot | QDir::AllEntries );
       
   324             if ( operationType() == FmOperationService::EOperationTypeMove ) {
       
   325                 if( infoListDir.isEmpty() ) {
       
   326                     if ( !fileInfo.dir().rmdir( fileInfo.absoluteFilePath() ) ) {
       
   327                         mErrString = fileInfo.absolutePath();
       
   328                         return FmErrCannotRemove;
       
   329                     }
       
   330                 } else {
       
   331                     infoList.push_front( fileInfo );
       
   332                 }
       
   333             }
       
   334             while( !infoListDir.isEmpty() ) {
       
   335                 infoList.push_front( infoListDir.takeLast() );
       
   336             }
       
   337 
       
   338         } else {
       
   339             mErrString = fileInfo.absoluteFilePath();
       
   340             return FmErrIsNotFileOrFolder;
       
   341         }
       
   342 
       
   343     }
       
   344 
       
   345     return FmErrNone;
       
   346 }
       
   347 
       
   348 /*
       
   349  * Increase the progress bar
       
   350  * \a size the current copy or moved size
       
   351  */
       
   352 void FmOperationCopyOrMove::increaseProgress( quint64 size )
       
   353 {
       
   354     if( mTotalSize <=0 ) {
       
   355         return;
       
   356     }
       
   357     mCopiedOrMovedSize += size;
       
   358     int step = ( mCopiedOrMovedSize * FmTotalProgressBarSteps ) / mTotalSize;
       
   359     if( step > mCurrentStep ) {
       
   360         mCurrentStep = step;
       
   361         emit notifyProgress( mCurrentStep );
       
   362     }
       
   363 }
       
   364 
       
   365 /*
       
   366  * Emits askForRename signal.
       
   367  * \a srcFile the source file path.
       
   368  * \a destFile get the new name from user input
       
   369  */
       
   370 void FmOperationCopyOrMove::queryForRename( const QString &srcFile, QString *destFile )
       
   371 {
       
   372     emit askForRename( srcFile, destFile );
       
   373 }
       
   374 
       
   375 /*
       
   376  * Copies one file from \a srcFile to \a desFile
       
   377  */
       
   378 int FmOperationCopyOrMove::copyOneFile( const QString &srcFile, const QString &desFile )
       
   379 {
       
   380     QFile src( srcFile );
       
   381     QFile des( desFile );
       
   382     if ( !src.open( QIODevice::ReadOnly ) || !des.open( QIODevice::WriteOnly ) ) {
       
   383         return FmErrCannotCopy;
       
   384     }
       
   385     QDataStream  outputStream( &src );
       
   386     QDataStream  inputStream( &des );
       
   387     //used to cache data from source file to target file during one copy
       
   388     QScopedPointer<char> tempString( new char[FmOneTimeCopyOrMoveSize] );
       
   389     memset( tempString.data(), 0, FmOneTimeCopyOrMoveSize );
       
   390     while ( !outputStream.atEnd() ) {
       
   391         if ( *mStop ) {            
       
   392             src.close();
       
   393             des.close();
       
   394             QFile::remove( desFile );
       
   395             return FmErrCancel;
       
   396         }
       
   397         int ret = outputStream.readRawData(tempString.data(), FmOneTimeCopyOrMoveSize );
       
   398         if (ret == -1) {
       
   399             src.close();
       
   400             des.close();
       
   401             QFile::remove( desFile );            
       
   402             return FmErrCannotCopy;
       
   403         }
       
   404         ret = inputStream.writeRawData(tempString.data(), ret);
       
   405         if (ret == -1) {
       
   406             src.close();
       
   407             des.close();
       
   408             QFile::remove( desFile );            
       
   409             return FmErrCannotCopy;
       
   410         }        
       
   411         memset( tempString.data(), 0, FmOneTimeCopyOrMoveSize );
       
   412         increaseProgress( ret );
       
   413     }    
       
   414     src.close();
       
   415     des.close();
       
   416     if ( FmUtils::setFileAttributes( srcFile, desFile ) != FmErrNone ) {
       
   417         QFile::remove( desFile );        
       
   418         return FmErrCannotCopy;
       
   419     }
       
   420     return FmErrNone;
       
   421 }
       
   422 
       
   423 /*
       
   424  * Prepare some work before starting operation.
       
   425  * Returns error number.
       
   426  */
       
   427 int FmOperationCopyOrMove::prepare()
       
   428 {
       
   429     if( mSourceList.empty() ) {
       
   430         return FmErrWrongParam;
       
   431     } else {
       
   432     return FmErrNone;
       
   433     }
       
   434 }
       
   435 
       
   436 bool FmOperationCopyOrMove::targetHasEnoughSpace()
       
   437 {
       
   438     QString sourceDrive = FmUtils::getDriveLetterFromPath( mSourceList.front() );
       
   439     QString targetDrive = FmUtils::getDriveLetterFromPath( mTargetPath );
       
   440     if ( sourceDrive == targetDrive &&
       
   441             operationType() == FmOperationService::EOperationTypeMove ) {
       
   442         return true;
       
   443     } else {
       
   444         return FmUtils::hasEnoughSpace( targetDrive, mTotalSize );
       
   445     }
       
   446 }