summaryrefslogtreecommitdiffstats
path: root/src/app/Synchronizer/synchronizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/Synchronizer/synchronizer.cpp')
-rw-r--r--src/app/Synchronizer/synchronizer.cpp1493
1 files changed, 1493 insertions, 0 deletions
diff --git a/src/app/Synchronizer/synchronizer.cpp b/src/app/Synchronizer/synchronizer.cpp
new file mode 100644
index 0000000..612f756
--- /dev/null
+++ b/src/app/Synchronizer/synchronizer.cpp
@@ -0,0 +1,1493 @@
+/***************************************************************************
+ synchronizer.cpp - description
+ -------------------
+ copyright : (C) 2003 + by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ S o u r c e F i l e
+
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "synchronizer.h"
+#include "synchronizerdirlist.h"
+#include "../krusader.h"
+#include "../krservices.h"
+#include "../VFS/vfs.h"
+#include "../VFS/krquery.h"
+#include "config.h"
+#include <kurl.h>
+#include <tdemessagebox.h>
+#include <tdelocale.h>
+#include <tqapplication.h>
+#include <tqregexp.h>
+#include <tqdir.h>
+#include <tqtimer.h>
+#include <tdeio/job.h>
+#include <kdialogbase.h>
+#include <tdeio/observer.h>
+#include <tdeio/renamedlg.h>
+#include <tdeio/skipdlg.h>
+#include <unistd.h>
+#include <tqeventloop.h>
+#include <tqpushbutton.h>
+#include <tqdatetime.h>
+#include <kprocess.h>
+#include <kdialogbase.h>
+#include <kprogress.h>
+#include <tqlayout.h>
+#include <kurlcompletion.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <utime.h>
+#include <pwd.h>
+#include <grp.h>
+#include <tqlabel.h>
+
+
+
+#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL )
+#include <sys/acl.h>
+#ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
+#include <acl/libacl.h>
+#endif
+#endif
+
+
+#define DISPLAY_UPDATE_PERIOD 2
+
+Synchronizer::Synchronizer() : displayUpdateCount( 0 ), markEquals( true ),
+ markDiffers ( true ), markCopyToLeft( true ), markCopyToRight( true ), markDeletable( true ),
+ stack(), jobMap(), receivedMap(), parentWidget( 0 )
+{
+ resultList.setAutoDelete( true );
+ stack.setAutoDelete( true );
+}
+
+void Synchronizer::reset()
+{
+ displayUpdateCount = 0;
+ markEquals = markDiffers = markCopyToLeft = markCopyToRight = markDeletable = true;
+ stopped = false;
+ recurseSubDirs = followSymLinks = ignoreDate = asymmetric = cmpByContent = ignoreCase = autoScroll = false;
+ markEquals = markDiffers = markCopyToLeft = markCopyToRight = markDeletable = markDuplicates = markSingles = false;
+ leftCopyEnabled = rightCopyEnabled = deleteEnabled = overWrite = autoSkip = paused = false;
+ leftCopyNr = rightCopyNr = deleteNr = 0;
+ leftCopySize = rightCopySize = deleteSize = 0;
+ comparedDirs = fileCount = 0;
+ leftBaseDir = rightBaseDir = TQString();
+ resultList.clear();
+ temporaryList.clear();
+ stack.clear();
+}
+
+int Synchronizer::compare( TQString leftURL, TQString rightURL, KRQuery *query, bool subDirs,
+ bool symLinks, bool igDate, bool asymm, bool cmpByCnt, bool igCase,
+ bool autoSc, TQStringList &selFiles, int equThres, int timeOffs, int parThreads, bool hiddenFiles )
+{
+ resultList.clear();
+ temporaryList.clear();
+
+ recurseSubDirs = subDirs;
+ followSymLinks = symLinks;
+ ignoreDate = igDate;
+ asymmetric = asymm;
+ cmpByContent = cmpByCnt;
+ autoScroll = autoSc;
+ ignoreCase = igCase;
+ selectedFiles = selFiles;
+ equalsThreshold= equThres;
+ timeOffset = timeOffs;
+ parallelThreads= parThreads;
+ ignoreHidden = hiddenFiles;
+
+ stopped = false;
+
+ this->query = query;
+
+ leftURL = KURLCompletion::replacedPath( leftURL, true, true );
+ rightURL = KURLCompletion::replacedPath( rightURL, true, true );
+
+ if( !leftURL.endsWith("/" )) leftURL+="/";
+ if( !rightURL.endsWith("/" )) rightURL+="/";
+
+ excludedPaths = query->dontSearchInDirs().toStringList();
+ for( unsigned i = 0; i != excludedPaths.count(); i++ )
+ if( excludedPaths[ i ].endsWith( "/" ) )
+ excludedPaths[ i ].truncate( excludedPaths[ i ].length() - 1 );
+
+ comparedDirs = fileCount = 0;
+
+ stack.append( new CompareTask( 0, leftBaseDir = leftURL, rightBaseDir = rightURL, "", "", ignoreHidden ) );
+ compareLoop();
+
+ SynchronizerFileItem *item = temporaryList.first();
+ while( item )
+ {
+ if( item->isTemporary() )
+ delete item;
+ item = temporaryList.next();
+ }
+ temporaryList.clear();
+
+
+ if( !autoScroll )
+ refresh( true );
+
+ emit statusInfo( i18n( "Number of files: %1" ).arg( fileCount ) );
+ return fileCount;
+}
+
+void Synchronizer::compareLoop() {
+ while( !stopped && !stack.isEmpty() ) {
+ for( int thread=0; thread < (int)stack.count() && thread < parallelThreads; thread++ ) {
+ SynchronizerTask * entry = stack.at( thread );
+
+ if( entry->state() == ST_STATE_NEW )
+ entry->start( parentWidget );
+
+ if( entry->inherits("CompareTask") ) {
+ if( entry->state() == ST_STATE_READY ) {
+ CompareTask *ctentry = (CompareTask *) entry;
+ if( ctentry->isDuplicate() )
+ compareDirectory( ctentry->parent(), ctentry->leftDirList(), ctentry->rightDirList(),
+ ctentry->leftDir(), ctentry->rightDir() );
+ else
+ addSingleDirectory( ctentry->parent(), ctentry->dirList(), ctentry->dir(),
+ ctentry->isLeft() );
+ }
+ if( entry->state() == ST_STATE_READY || entry->state() == ST_STATE_ERROR )
+ comparedDirs++;
+ }
+ switch( entry->state() ) {
+ case ST_STATE_STATUS:
+ emit statusInfo( entry->status() );
+ break;
+ case ST_STATE_READY:
+ case ST_STATE_ERROR:
+ emit statusInfo( i18n( "Number of compared directories: %1" ).arg( comparedDirs ) );
+ stack.removeRef( entry );
+ continue;
+ default:
+ break;
+ }
+ }
+ if( !stack.isEmpty() )
+ tqApp->processEvents();
+ }
+ stack.clear();
+}
+
+void Synchronizer::compareDirectory( SynchronizerFileItem *parent, SynchronizerDirList * left_directory,
+ SynchronizerDirList * right_directory, const TQString &leftDir,
+ const TQString &rightDir )
+{
+ const TQString &leftURL = left_directory->url();
+ const TQString &rightURL = right_directory->url();
+ vfile * left_file;
+ vfile * right_file;
+
+ TQString file_name;
+ bool checkIfSelected = false;
+
+ if( leftDir.isEmpty() && rightDir.isEmpty() && selectedFiles.count() )
+ checkIfSelected = true;
+
+ /* walking through in the left directory */
+ for( left_file=left_directory->first(); left_file != 0 && !stopped ;
+ left_file=left_directory->next() )
+ {
+ if ( isDir( left_file ) )
+ continue;
+
+ file_name = left_file->vfile_getName();
+
+ if( checkIfSelected && !selectedFiles.contains( file_name ) )
+ continue;
+
+ if( !query->match( left_file ) )
+ continue;
+
+ if( (right_file = right_directory->search( file_name, ignoreCase )) == 0 )
+ addLeftOnlyItem( parent, file_name, leftDir, left_file->vfile_getSize(), left_file->vfile_getTime_t(),
+ readLink( left_file ), left_file->vfile_getOwner(), left_file->vfile_getGroup(),
+ left_file->vfile_getMode(), left_file->vfile_getACL() );
+ else
+ {
+ if( isDir( right_file ) )
+ continue;
+
+ addDuplicateItem( parent, file_name, right_file->vfile_getName(), leftDir, rightDir, left_file->vfile_getSize(), right_file->vfile_getSize(),
+ left_file->vfile_getTime_t(), right_file->vfile_getTime_t(), readLink( left_file ),
+ readLink( right_file ), left_file->vfile_getOwner(), right_file->vfile_getOwner(),
+ left_file->vfile_getGroup(), right_file->vfile_getGroup(),
+ left_file->vfile_getMode(), right_file->vfile_getMode(),
+ left_file->vfile_getACL(), right_file->vfile_getACL() );
+ }
+ }
+
+ /* walking through in the right directory */
+ for( right_file=right_directory->first(); right_file != 0 && !stopped ;
+ right_file=right_directory->next() )
+ {
+ if( isDir( right_file ) )
+ continue;
+
+ file_name = right_file->vfile_getName();
+
+ if( checkIfSelected && !selectedFiles.contains( file_name ) )
+ continue;
+
+ if( !query->match( right_file ) )
+ continue;
+
+ if( left_directory->search( file_name, ignoreCase ) == 0 )
+ addRightOnlyItem( parent, file_name, rightDir, right_file->vfile_getSize(), right_file->vfile_getTime_t(),
+ readLink( right_file ), right_file->vfile_getOwner(), right_file->vfile_getGroup(),
+ right_file->vfile_getMode(), right_file->vfile_getACL() );
+ }
+
+ /* walking through the subdirectories */
+ if( recurseSubDirs )
+ {
+ for( left_file=left_directory->first(); left_file != 0 && !stopped ;
+ left_file=left_directory->next() )
+ {
+ if ( left_file->vfile_isDir() && ( followSymLinks || !left_file->vfile_isSymLink()) )
+ {
+ TQString left_file_name = left_file->vfile_getName();
+
+ if( checkIfSelected && !selectedFiles.contains( left_file_name ) )
+ continue;
+
+ if( excludedPaths.contains( leftDir.isEmpty() ? left_file_name : leftDir+"/"+left_file_name ) )
+ continue;
+
+ if( !query->matchDirName( left_file_name ) )
+ continue;
+
+ if( (right_file = right_directory->search( left_file_name, ignoreCase )) == 0 )
+ {
+ SynchronizerFileItem *me = addLeftOnlyItem( parent, left_file_name, leftDir, 0,
+ left_file->vfile_getTime_t(), readLink( left_file ),
+ left_file->vfile_getOwner(), left_file->vfile_getGroup(),
+ left_file->vfile_getMode(), left_file->vfile_getACL(),
+ true, !query->match( left_file ) );
+ stack.append( new CompareTask( me, leftURL+left_file_name+"/",
+ leftDir.isEmpty() ? left_file_name : leftDir+"/"+left_file_name, true, ignoreHidden ) );
+ } else {
+ TQString right_file_name = right_file->vfile_getName();
+ SynchronizerFileItem *me = addDuplicateItem( parent, left_file_name, right_file_name,
+ leftDir, rightDir, 0, 0,
+ left_file->vfile_getTime_t(), right_file->vfile_getTime_t(),
+ readLink( left_file ), readLink( right_file ),
+ left_file->vfile_getOwner(), right_file->vfile_getOwner(),
+ left_file->vfile_getGroup(), right_file->vfile_getGroup(),
+ left_file->vfile_getMode(), right_file->vfile_getMode(),
+ left_file->vfile_getACL(), right_file->vfile_getACL(),
+ true, !query->match( left_file ) );
+ stack.append( new CompareTask( me, leftURL+left_file_name+"/", rightURL+right_file_name+"/",
+ leftDir.isEmpty() ? left_file_name : leftDir+"/"+left_file_name,
+ rightDir.isEmpty() ? right_file_name : rightDir+"/"+right_file_name, ignoreHidden ) );
+ }
+ }
+ }
+
+ /* walking through the the right side subdirectories */
+ for( right_file=right_directory->first(); right_file != 0 && !stopped ;
+ right_file=right_directory->next() )
+ {
+ if ( right_file->vfile_isDir() && (followSymLinks || !right_file->vfile_isSymLink()) )
+ {
+ file_name = right_file->vfile_getName();
+
+ if( checkIfSelected && !selectedFiles.contains( file_name ) )
+ continue;
+
+ if( excludedPaths.contains( rightDir.isEmpty() ? file_name : rightDir+"/"+file_name ) )
+ continue;
+
+ if( !query->matchDirName( file_name ) )
+ continue;
+
+ if( left_directory->search( file_name, ignoreCase ) == 0 )
+ {
+ SynchronizerFileItem *me = addRightOnlyItem( parent, file_name, rightDir, 0,
+ right_file->vfile_getTime_t(), readLink( right_file ),
+ right_file->vfile_getOwner(), right_file->vfile_getGroup(),
+ right_file->vfile_getMode(), right_file->vfile_getACL(),
+ true, !query->match( right_file ) );
+ stack.append( new CompareTask( me, rightURL+file_name+"/",
+ rightDir.isEmpty() ? file_name : rightDir+"/"+file_name, false, ignoreHidden ) );
+ }
+ }
+ }
+ }
+}
+
+TQString Synchronizer::getTaskTypeName( TaskType taskType )
+{
+ static TQString names[] = {"=","!=","<-","->","DEL","?","?","?","?","?"};
+
+ return names[taskType];
+}
+
+SynchronizerFileItem * Synchronizer::addItem( SynchronizerFileItem *parent, const TQString &leftFile,
+ const TQString &rightFile, const TQString &leftDir,
+ const TQString &rightDir, bool existsLeft, bool existsRight,
+ TDEIO::filesize_t leftSize, TDEIO::filesize_t rightSize,
+ time_t leftDate, time_t rightDate, const TQString &leftLink,
+ const TQString &rightLink, const TQString &leftOwner,
+ const TQString &rightOwner, const TQString &leftGroup,
+ const TQString &rightGroup, mode_t leftMode, mode_t rightMode,
+ const TQString &leftACL, const TQString &rightACL, TaskType tsk,
+ bool isDir, bool isTemp )
+{
+ bool marked = autoScroll ? !isTemp && isMarked( tsk, existsLeft && existsRight ) : false;
+ SynchronizerFileItem *item = new SynchronizerFileItem( leftFile, rightFile, leftDir, rightDir, marked,
+ existsLeft, existsRight, leftSize, rightSize, leftDate, rightDate, leftLink, rightLink,
+ leftOwner, rightOwner, leftGroup, rightGroup, leftMode, rightMode, leftACL, rightACL, tsk, isDir,
+ isTemp, parent );
+
+ if( !isTemp )
+ {
+ while( parent && parent->isTemporary() )
+ setPermanent( parent );
+
+ bool doRefresh = false;
+
+ if( marked )
+ {
+ fileCount++;
+ if( autoScroll && markParentDirectories( item ) )
+ doRefresh = true;
+ }
+
+ resultList.append( item );
+ emit comparedFileData( item );
+
+ if( doRefresh )
+ refresh( true );
+
+ if( marked && (displayUpdateCount++ % DISPLAY_UPDATE_PERIOD == (DISPLAY_UPDATE_PERIOD-1) ) )
+ tqApp->processEvents();
+ }
+ else
+ temporaryList.append( item );
+
+ return item;
+}
+
+void Synchronizer::compareContentResult( SynchronizerFileItem * item, bool res ) {
+ item->compareContentResult( res );
+ bool marked = autoScroll ? isMarked( item->task(), item->existsInLeft() && item->existsInRight() ) : false;
+ item->setMarked( marked );
+ if( marked ) {
+ markParentDirectories( item );
+ fileCount++;
+ emit markChanged( item, true );
+ }
+}
+
+void Synchronizer::setPermanent( SynchronizerFileItem *item )
+{
+ if( item->parent() && item->parent()->isTemporary() )
+ setPermanent( item->parent() );
+
+ item->setPermanent();
+ resultList.append( item );
+ emit comparedFileData( item );
+}
+
+SynchronizerFileItem * Synchronizer::addLeftOnlyItem( SynchronizerFileItem *parent,
+ const TQString &file_name, const TQString &dir, TDEIO::filesize_t size,
+ time_t date, const TQString &link, const TQString &owner,
+ const TQString &group, mode_t mode, const TQString &acl, bool isDir,
+ bool isTemp )
+{
+ return addItem( parent, file_name, file_name, dir, dir, true, false, size, 0, date, 0, link, TQString(),
+ owner, TQString(), group, TQString(), mode, (mode_t)-1, acl, TQString(),
+ asymmetric ? TT_DELETE : TT_COPY_TO_RIGHT, isDir, isTemp );
+}
+
+SynchronizerFileItem * Synchronizer::addRightOnlyItem( SynchronizerFileItem *parent,
+ const TQString &file_name, const TQString &dir, TDEIO::filesize_t size,
+ time_t date, const TQString &link, const TQString &owner,
+ const TQString &group, mode_t mode, const TQString &acl, bool isDir,
+ bool isTemp )
+{
+ return addItem( parent, file_name, file_name, dir, dir, false, true, 0, size, 0, date, TQString(), link,
+ TQString(), owner, TQString(), group, (mode_t)-1, mode, TQString(), acl,
+ TT_COPY_TO_LEFT, isDir, isTemp );
+}
+
+SynchronizerFileItem * Synchronizer::addDuplicateItem( SynchronizerFileItem *parent,
+ const TQString &leftName, const TQString &rightName,
+ const TQString &leftDir, const TQString &rightDir,
+ TDEIO::filesize_t leftSize, TDEIO::filesize_t rightSize, time_t leftDate, time_t rightDate,
+ const TQString &leftLink, const TQString &rightLink,
+ const TQString &leftOwner, const TQString &rightOwner,
+ const TQString &leftGroup, const TQString &rightGroup,
+ mode_t leftMode, mode_t rightMode,
+ const TQString &leftACL, const TQString &rightACL,
+ bool isDir, bool isTemp )
+{
+ TaskType task;
+
+ int checkedRightDate = rightDate - timeOffset;
+ int uncertain = 0;
+
+ do
+ {
+ if( isDir )
+ {
+ task = TT_EQUALS;
+ break;
+ }
+ if( leftSize == rightSize )
+ {
+ if( !leftLink.isNull() || !rightLink.isNull() ) {
+ if( leftLink == rightLink ) {
+ task = TT_EQUALS;
+ break;
+ }
+ } else if( cmpByContent )
+ uncertain = TT_UNKNOWN;
+ else {
+ if( ignoreDate || leftDate == checkedRightDate ) {
+ task = TT_EQUALS;
+ break;
+ }
+ time_t diff = ( leftDate > checkedRightDate ) ? leftDate - checkedRightDate : checkedRightDate - leftDate;
+ if( diff <= equalsThreshold ) {
+ task = TT_EQUALS;
+ break;
+ }
+ }
+ }
+
+ if( asymmetric )
+ task = TT_COPY_TO_LEFT;
+ else if( ignoreDate )
+ task = TT_DIFFERS;
+ else if( leftDate > checkedRightDate )
+ task = TT_COPY_TO_RIGHT;
+ else if( leftDate < checkedRightDate )
+ task = TT_COPY_TO_LEFT;
+ else
+ task = TT_DIFFERS;
+
+ }while( false );
+
+ SynchronizerFileItem * item = addItem( parent, leftName, rightName, leftDir, rightDir, true, true,
+ leftSize, rightSize, leftDate, rightDate, leftLink, rightLink,
+ leftOwner, rightOwner, leftGroup, rightGroup,
+ leftMode, rightMode, leftACL, rightACL,
+ (TaskType)(task + uncertain), isDir, isTemp );
+
+ if( uncertain == TT_UNKNOWN ) {
+ KURL leftURL = vfs::fromPathOrURL( leftDir.isEmpty() ? leftBaseDir + leftName : leftBaseDir + leftDir + "/" + leftName );
+ KURL rightURL = vfs::fromPathOrURL( rightDir.isEmpty() ? rightBaseDir + rightName : rightBaseDir + rightDir + "/" + rightName );
+ stack.append( new CompareContentTask( this, item, leftURL, rightURL, leftSize ) );
+ }
+
+ return item;
+}
+
+void Synchronizer::addSingleDirectory( SynchronizerFileItem *parent, SynchronizerDirList *directory,
+ const TQString &dirName, bool isLeft )
+{
+ const TQString &url = directory->url();
+ vfile * file;
+ TQString file_name;
+
+ /* walking through the directory files */
+ for( file=directory->first(); file != 0 && !stopped; file = directory->next() )
+ {
+ if ( isDir( file ) )
+ continue;
+
+ file_name = file->vfile_getName();
+
+ if( !query->match( file ) )
+ continue;
+
+ if( isLeft )
+ addLeftOnlyItem( parent, file_name, dirName, file->vfile_getSize(), file->vfile_getTime_t(), readLink( file ),
+ file->vfile_getOwner(), file->vfile_getGroup(), file->vfile_getMode(), file->vfile_getACL() );
+ else
+ addRightOnlyItem( parent, file_name, dirName, file->vfile_getSize(), file->vfile_getTime_t(), readLink( file ),
+ file->vfile_getOwner(), file->vfile_getGroup(), file->vfile_getMode(), file->vfile_getACL() );
+ }
+
+ /* walking through the subdirectories */
+ for( file=directory->first(); file != 0 && !stopped; file=directory->next() )
+ {
+ if ( file->vfile_isDir() && (followSymLinks || !file->vfile_isSymLink()) )
+ {
+ file_name = file->vfile_getName();
+
+ if( excludedPaths.contains( dirName.isEmpty() ? file_name : dirName+"/"+file_name ) )
+ continue;
+
+ if( !query->matchDirName( file_name ) )
+ continue;
+
+ SynchronizerFileItem *me;
+
+ if( isLeft )
+ me = addLeftOnlyItem( parent, file_name, dirName, 0, file->vfile_getTime_t(), readLink( file ),
+ file->vfile_getOwner(), file->vfile_getGroup(), file->vfile_getMode(),
+ file->vfile_getACL(), true, !query->match( file ) );
+ else
+ me = addRightOnlyItem( parent, file_name, dirName, 0, file->vfile_getTime_t(), readLink( file ),
+ file->vfile_getOwner(), file->vfile_getGroup(), file->vfile_getMode(),
+ file->vfile_getACL(), true, !query->match( file ) );
+ stack.append( new CompareTask( me, url+file_name+"/",
+ dirName.isEmpty() ? file_name : dirName+"/"+file_name, isLeft, ignoreHidden ) );
+ }
+ }
+}
+
+void Synchronizer::setMarkFlags( bool left, bool equal, bool differs, bool right, bool dup, bool sing,
+ bool del )
+{
+ markEquals = equal;
+ markDiffers = differs;
+ markCopyToLeft = left;
+ markCopyToRight = right;
+ markDeletable = del;
+ markDuplicates = dup;
+ markSingles = sing;
+}
+
+bool Synchronizer::isMarked( TaskType task, bool isDuplicate )
+{
+ if( (isDuplicate && !markDuplicates) || (!isDuplicate && !markSingles) )
+ return false;
+
+ switch( task )
+ {
+ case TT_EQUALS:
+ return markEquals;
+ case TT_DIFFERS:
+ return markDiffers;
+ case TT_COPY_TO_LEFT:
+ return markCopyToLeft;
+ case TT_COPY_TO_RIGHT:
+ return markCopyToRight;
+ case TT_DELETE:
+ return markDeletable;
+ default:
+ return false;
+ }
+}
+
+bool Synchronizer::markParentDirectories( SynchronizerFileItem *item )
+{
+ if( item->parent() == 0 || item->parent()->isMarked() )
+ return false;
+
+ markParentDirectories( item->parent() );
+
+ item->parent()->setMarked( true );
+
+ fileCount++;
+ emit markChanged( item->parent(), false );
+ return true;
+}
+
+int Synchronizer::refresh(bool nostatus)
+{
+ fileCount = 0;
+
+ SynchronizerFileItem *item = resultList.first();
+
+ while( item )
+ {
+ bool marked = isMarked( item->task(), item->existsInLeft() && item->existsInRight() );
+ item->setMarked( marked );
+
+ if( marked )
+ {
+ markParentDirectories( item );
+ fileCount++;
+ }
+
+ item = resultList.next();
+ }
+
+ item = resultList.first();
+ while( item )
+ {
+ emit markChanged( item, false );
+ item = resultList.next();
+ }
+
+ if( !nostatus )
+ emit statusInfo( i18n( "Number of files: %1" ).arg( fileCount ) );
+
+ return fileCount;
+}
+
+void Synchronizer::operate( SynchronizerFileItem *item,
+ void (*executeOperation)(SynchronizerFileItem *) )
+{
+ executeOperation( item );
+
+ if( item->isDir() )
+ {
+ TQString leftDirName = ( item->leftDirectory() == "" ) ?
+ item->leftName() : item->leftDirectory() + "/" + item->leftName() ;
+ TQString rightDirName = ( item->rightDirectory() == "" ) ?
+ item->rightName() : item->rightDirectory() + "/" + item->rightName() ;
+
+ item = resultList.first();
+ while( item )
+ {
+ if( item->leftDirectory() == leftDirName || item->leftDirectory().startsWith( leftDirName + "/" ) ||
+ item->rightDirectory() == rightDirName || item->rightDirectory().startsWith( rightDirName + "/" ) )
+ executeOperation( item );
+
+ item = resultList.next();
+ }
+ }
+}
+
+void Synchronizer::excludeOperation( SynchronizerFileItem *item )
+{
+ item->setTask( TT_DIFFERS );
+}
+
+void Synchronizer::exclude( SynchronizerFileItem *item )
+{
+ if( !item->parent() || item->parent()->task() != TT_DELETE )
+ operate( item, excludeOperation ); /* exclude only if the parent task is not DEL */
+}
+
+void Synchronizer::restoreOperation( SynchronizerFileItem *item )
+{
+ item->restoreOriginalTask();
+}
+
+void Synchronizer::restore( SynchronizerFileItem *item )
+{
+ operate( item, restoreOperation );
+
+ while( ( item = item->parent() ) != 0 ) /* in case of restore, the parent directories */
+ { /* must be changed for being consistent */
+ if( item->task() != TT_DIFFERS )
+ break;
+
+ if( item->originalTask() == TT_DELETE ) /* if the parent original task is delete */
+ break; /* don't touch it */
+
+ item->restoreOriginalTask(); /* restore */
+ }
+}
+
+void Synchronizer::reverseDirectionOperation( SynchronizerFileItem *item )
+{
+ if( item->existsInRight() && item->existsInLeft() )
+ {
+ if( item->task() == TT_COPY_TO_LEFT )
+ item->setTask( TT_COPY_TO_RIGHT );
+ else if( item->task() == TT_COPY_TO_RIGHT )
+ item->setTask( TT_COPY_TO_LEFT );
+ }
+}
+
+void Synchronizer::reverseDirection( SynchronizerFileItem *item )
+{
+ operate( item, reverseDirectionOperation );
+}
+
+void Synchronizer::deleteLeftOperation( SynchronizerFileItem *item )
+{
+ if( !item->existsInRight() && item->existsInLeft() )
+ item->setTask( TT_DELETE );
+}
+
+void Synchronizer::deleteLeft( SynchronizerFileItem *item )
+{
+ operate( item, deleteLeftOperation );
+}
+
+void Synchronizer::copyToLeftOperation( SynchronizerFileItem *item )
+{
+ if( item->existsInRight() )
+ {
+ if( !item->isDir() )
+ item->setTask( TT_COPY_TO_LEFT );
+ else
+ {
+ if( item->existsInLeft() && item->existsInRight() )
+ item->setTask( TT_EQUALS );
+ else if( !item->existsInLeft() && item->existsInRight() )
+ item->setTask( TT_COPY_TO_LEFT );
+ }
+ }
+}
+
+void Synchronizer::copyToLeft( SynchronizerFileItem *item )
+{
+ operate( item, copyToLeftOperation );
+
+ while( ( item = item->parent() ) != 0 )
+ {
+ if( item->task() != TT_DIFFERS )
+ break;
+
+ if( item->existsInLeft() && item->existsInRight() )
+ item->setTask( TT_EQUALS );
+ else if( !item->existsInLeft() && item->existsInRight() )
+ item->setTask( TT_COPY_TO_LEFT );
+ }
+}
+
+void Synchronizer::copyToRightOperation( SynchronizerFileItem *item )
+{
+ if( item->existsInLeft() )
+ {
+ if( !item->isDir() )
+ item->setTask( TT_COPY_TO_RIGHT );
+ else
+ {
+ if( item->existsInLeft() && item->existsInRight() )
+ item->setTask( TT_EQUALS );
+ else if( item->existsInLeft() && !item->existsInRight() )
+ item->setTask( TT_COPY_TO_RIGHT );
+ }
+ }
+}
+
+void Synchronizer::copyToRight( SynchronizerFileItem *item )
+{
+ operate( item, copyToRightOperation );
+
+ while( ( item = item->parent() ) != 0 )
+ {
+ if( item->task() != TT_DIFFERS && item->task() != TT_DELETE )
+ break;
+
+ if( item->existsInLeft() && item->existsInRight() )
+ item->setTask( TT_EQUALS );
+ else if( item->existsInLeft() && !item->existsInRight() )
+ item->setTask( TT_COPY_TO_RIGHT );
+ }
+}
+
+bool Synchronizer::totalSizes( int * leftCopyNr, TDEIO::filesize_t *leftCopySize, int * rightCopyNr,
+ TDEIO::filesize_t *rightCopySize, int *deleteNr, TDEIO::filesize_t *deletableSize )
+{
+ bool hasAnythingToDo = false;
+
+ *leftCopySize = *rightCopySize = *deletableSize = 0;
+ *leftCopyNr = *rightCopyNr = *deleteNr = 0;
+
+ SynchronizerFileItem *item = resultList.first();
+
+ while( item )
+ {
+ if( item->isMarked() )
+ {
+ switch( item->task() )
+ {
+ case TT_COPY_TO_LEFT:
+ *leftCopySize += item->rightSize();
+ (*leftCopyNr)++;
+ hasAnythingToDo = true;
+ break;
+ case TT_COPY_TO_RIGHT:
+ *rightCopySize += item->leftSize();
+ (*rightCopyNr)++;
+ hasAnythingToDo = true;
+ break;
+ case TT_DELETE:
+ *deletableSize += item->leftSize();
+ (*deleteNr)++;
+ hasAnythingToDo = true;
+ break;
+ default:
+ break;
+ }
+ }
+ item = resultList.next();
+ }
+
+ return hasAnythingToDo;
+}
+
+void Synchronizer::swapSides()
+{
+ TQString leftTmp = leftBaseDir;
+ leftBaseDir = rightBaseDir;
+ rightBaseDir = leftTmp;
+
+ SynchronizerFileItem *item = resultList.first();
+
+ while( item )
+ {
+ item->swap( asymmetric );
+ item = resultList.next();
+ }
+}
+
+void Synchronizer::setScrolling( bool scroll )
+{
+ if( autoScroll = scroll )
+ {
+ int oldFileCount = fileCount;
+ refresh( true );
+ fileCount = oldFileCount;
+ }
+}
+
+void Synchronizer::synchronize( TQWidget *syncWdg, bool leftCopyEnabled, bool rightCopyEnabled,
+ bool deleteEnabled, bool overWrite, int parThreads )
+{
+ this->leftCopyEnabled = leftCopyEnabled;
+ this->rightCopyEnabled = rightCopyEnabled;
+ this->deleteEnabled = deleteEnabled;
+ this->overWrite = overWrite;
+ this->parallelThreads = parThreads;
+ this->syncDlgWidget = syncWdg;
+
+ autoSkip = paused = disableNewTasks = false;
+
+ leftCopyNr = rightCopyNr = deleteNr = 0;
+ leftCopySize = rightCopySize = deleteSize = 0;
+
+ inTaskFinished = 0;
+ lastTask = 0;
+
+ jobMap.clear();
+ receivedMap.clear();
+
+ resultList.first();
+ synchronizeLoop();
+}
+
+void Synchronizer::synchronizeLoop() {
+ if( disableNewTasks ) {
+ if( resultList.current() == 0 && jobMap.count() == 0 )
+ emit synchronizationFinished();
+ return;
+ }
+
+ while( (int)jobMap.count() < parallelThreads ) {
+ SynchronizerFileItem *task = getNextTask();
+ if( task == 0 ) {
+ if( jobMap.count() == 0 )
+ emit synchronizationFinished();
+ return;
+ }
+ executeTask( task );
+ if( disableNewTasks )
+ break;
+ }
+}
+
+SynchronizerFileItem * Synchronizer::getNextTask() {
+ TaskType task;
+ SynchronizerFileItem * currentTask = resultList.current();
+
+ do {
+ if( currentTask == 0 )
+ return 0;
+
+ if( currentTask->isMarked() )
+ {
+ task = currentTask->task();
+
+ if( leftCopyEnabled && task == TT_COPY_TO_LEFT )
+ break;
+ else if( rightCopyEnabled && task == TT_COPY_TO_RIGHT )
+ break;
+ else if( deleteEnabled && task == TT_DELETE )
+ break;
+ }
+
+ currentTask = resultList.next();
+ }while( true );
+
+ resultList.next();
+ return lastTask = currentTask;
+}
+
+
+void Synchronizer::executeTask( SynchronizerFileItem * task )
+{
+ TQString leftDirName = task->leftDirectory();
+ if( !leftDirName.isEmpty() )
+ leftDirName += "/";
+ TQString rightDirName = task->rightDirectory();
+ if( !rightDirName.isEmpty() )
+ rightDirName += "/";
+
+ KURL leftURL = vfs::fromPathOrURL( leftBaseDir + leftDirName + task->leftName() );
+ KURL rightURL = vfs::fromPathOrURL( rightBaseDir + rightDirName + task->rightName() );
+
+ switch( task->task() )
+ {
+ case TT_COPY_TO_LEFT:
+ if( task->isDir() )
+ {
+ TDEIO::SimpleJob *job = TDEIO::mkdir( leftURL );
+ connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*)));
+ jobMap[ job ] = task;
+ disableNewTasks = true;
+ }
+ else
+ {
+ KURL destURL( leftURL );
+ if( !task->destination().isNull() )
+ destURL = vfs::fromPathOrURL( task->destination() );
+
+ if( task->rightLink().isNull() ) {
+ TDEIO::FileCopyJob *job = TDEIO::file_copy(rightURL, destURL, -1,
+ overWrite || task->overWrite(), false, false );
+ connect(job,TQ_SIGNAL(processedSize (TDEIO::Job *, TDEIO::filesize_t )), this,
+ TQ_SLOT (slotProcessedSize (TDEIO::Job *, TDEIO::filesize_t )));
+ connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*)));
+ jobMap[ job ] = task;
+ } else {
+ TDEIO::SimpleJob *job = TDEIO::symlink( task->rightLink(), destURL,
+ overWrite || task->overWrite(), false );
+ connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*)));
+ jobMap[ job ] = task;
+ }
+ }
+ break;
+ case TT_COPY_TO_RIGHT:
+ if( task->isDir() )
+ {
+ TDEIO::SimpleJob *job = TDEIO::mkdir( rightURL );
+ connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*)));
+ jobMap[ job ] = task;
+ disableNewTasks = true;
+ }
+ else
+ {
+ KURL destURL( rightURL );
+ if( !task->destination().isNull() )
+ destURL = vfs::fromPathOrURL( task->destination() );
+
+ if( task->leftLink().isNull() ) {
+ TDEIO::FileCopyJob *job = TDEIO::file_copy(leftURL, destURL, -1,
+ overWrite || task->overWrite(), false, false );
+ connect(job,TQ_SIGNAL(processedSize (TDEIO::Job *, TDEIO::filesize_t )), this,
+ TQ_SLOT (slotProcessedSize (TDEIO::Job *, TDEIO::filesize_t )));
+ connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*)));
+ jobMap[ job ] = task;
+ } else {
+ TDEIO::SimpleJob *job = TDEIO::symlink( task->leftLink(), destURL,
+ overWrite || task->overWrite(), false );
+ connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*)));
+ jobMap[ job ] = task;
+ }
+ }
+ break;
+ case TT_DELETE:
+ {
+ TDEIO::DeleteJob *job = TDEIO::del( leftURL, false );
+ connect(job,TQ_SIGNAL(result(TDEIO::Job*)),this,TQ_SLOT(slotTaskFinished(TDEIO::Job*)));
+ jobMap[ job ] = task;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void Synchronizer::slotTaskFinished(TDEIO::Job *job )
+{
+ inTaskFinished++;
+
+ SynchronizerFileItem * item = jobMap[ job ];
+ jobMap.remove( job );
+
+ TDEIO::filesize_t receivedSize = 0;
+
+ if( receivedMap.contains( job ) ) {
+ receivedSize = receivedMap[ job ];
+ receivedMap.remove( job );
+ }
+
+ if( disableNewTasks && item == lastTask )
+ disableNewTasks = false; // the blocker task finished
+
+ TQString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + "/";
+ TQString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + "/";
+ KURL leftURL = vfs::fromPathOrURL( leftBaseDir + leftDirName + item->leftName() );
+ KURL rightURL = vfs::fromPathOrURL( rightBaseDir + rightDirName + item->rightName() );
+
+ do {
+ if( !job->error() )
+ {
+ switch( item->task() )
+ {
+ case TT_COPY_TO_LEFT:
+ if( leftURL.isLocalFile() )
+ {
+ struct utimbuf timestamp;
+
+ timestamp.actime = time( 0 );
+ timestamp.modtime = item->rightDate() - timeOffset;
+
+ utime( (const char *)( leftURL.path( -1 ).local8Bit() ), &timestamp );
+
+ uid_t newOwnerID = (uid_t)-1; // chown(2) : -1 means no change
+ if ( !item->rightOwner().isEmpty() )
+ {
+ struct passwd* pw = getpwnam(TQFile::encodeName(item->rightOwner()));
+ if ( pw != 0L )
+ newOwnerID = pw->pw_uid;
+ }
+ gid_t newGroupID = (gid_t)-1; // chown(2) : -1 means no change
+ if ( !item->rightGroup().isEmpty() )
+ {
+ struct group* g = getgrnam(TQFile::encodeName(item->rightGroup()));
+ if ( g != 0L )
+ newGroupID = g->gr_gid;
+ }
+ chown( (const char *)( leftURL.path( -1 ).local8Bit() ), newOwnerID, (gid_t)-1 );
+ chown( (const char *)( leftURL.path( -1 ).local8Bit() ), (uid_t)-1, newGroupID );
+
+ chmod( (const char *)( leftURL.path( -1 ).local8Bit() ), item->rightMode() & 07777 );
+
+#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL )
+ if( !item->rightACL().isNull() )
+ {
+ acl_t acl = acl_from_text( item->rightACL().latin1() );
+ if( acl && !acl_valid( acl ) )
+ acl_set_file( leftURL.path( -1 ).local8Bit(), ACL_TYPE_ACCESS, acl );
+ if( acl )
+ acl_free( acl );
+ }
+#endif
+ }
+ break;
+ case TT_COPY_TO_RIGHT:
+ if( rightURL.isLocalFile() )
+ {
+ struct utimbuf timestamp;
+
+ timestamp.actime = time( 0 );
+ timestamp.modtime = item->leftDate() + timeOffset;
+
+ utime( (const char *)( rightURL.path( -1 ).local8Bit() ), &timestamp );
+
+ uid_t newOwnerID = (uid_t)-1; // chown(2) : -1 means no change
+ if ( !item->leftOwner().isEmpty() )
+ {
+ struct passwd* pw = getpwnam(TQFile::encodeName(item->leftOwner()));
+ if ( pw != 0L )
+ newOwnerID = pw->pw_uid;
+ }
+ gid_t newGroupID = (gid_t)-1; // chown(2) : -1 means no change
+ if ( !item->leftGroup().isEmpty() )
+ {
+ struct group* g = getgrnam(TQFile::encodeName(item->leftGroup()));
+ if ( g != 0L )
+ newGroupID = g->gr_gid;
+ }
+ chown( (const char *)( rightURL.path( -1 ).local8Bit() ), newOwnerID, (uid_t)-1 );
+ chown( (const char *)( rightURL.path( -1 ).local8Bit() ), (uid_t)-1, newGroupID );
+
+ chmod( (const char *)( rightURL.path( -1 ).local8Bit() ), item->leftMode() & 07777 );
+
+#if KDE_IS_VERSION(3,5,0) && defined( HAVE_POSIX_ACL )
+ if( !item->leftACL().isNull() )
+ {
+ acl_t acl = acl_from_text( item->leftACL().latin1() );
+ if( acl && !acl_valid( acl ) )
+ acl_set_file( rightURL.path( -1 ).local8Bit(), ACL_TYPE_ACCESS, acl );
+ if( acl )
+ acl_free( acl );
+ }
+#endif
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ if( job->error() == TDEIO::ERR_FILE_ALREADY_EXIST && item->task() != TT_DELETE )
+ {
+ TDEIO::RenameDlg_Result result;
+ TQString newDest;
+
+ if( autoSkip )
+ break;
+
+ if ( item->task() == TT_COPY_TO_LEFT )
+ {
+ TQWidget *mainWidget = tqApp->mainWidget(); // WORKAROUND, don't give focus to the main widget
+ tqApp->setMainWidget( syncDlgWidget );
+
+ result = Observer::self()->open_RenameDlg ( job, i18n("File Already Exists"),
+ vfs::pathOrURL( rightURL ), vfs::pathOrURL( leftURL ),
+ (TDEIO::RenameDlg_Mode)( TDEIO::M_OVERWRITE | TDEIO::M_SKIP | TDEIO::M_MULTI ), newDest,
+ item->rightSize(), item->leftSize(), (time_t)-1, (time_t)-1,
+ item->rightDate(), item->leftDate());
+
+ tqApp->setMainWidget( mainWidget );
+ }
+ else
+ {
+ TQWidget *mainWidget = tqApp->mainWidget(); // WORKAROUND, don't give focus to the main widget
+ tqApp->setMainWidget( syncDlgWidget );
+
+ result = Observer::self()->open_RenameDlg ( job, i18n("File Already Exists"),
+ vfs::pathOrURL( leftURL ), vfs::pathOrURL( rightURL ),
+ (TDEIO::RenameDlg_Mode)( TDEIO::M_OVERWRITE | TDEIO::M_SKIP | TDEIO::M_MULTI ), newDest,
+ item->leftSize(), item->rightSize(), (time_t)-1, (time_t)-1,
+ item->leftDate(), item->rightDate());
+
+ tqApp->setMainWidget( mainWidget );
+ }
+
+ switch ( result )
+ {
+ case TDEIO::R_RENAME:
+ item->setDestination( newDest );
+ executeTask( item );
+ inTaskFinished--;
+ return;
+ case TDEIO::R_OVERWRITE:
+ item->setOverWrite();
+ executeTask( item );
+ inTaskFinished--;
+ return;
+ case TDEIO::R_OVERWRITE_ALL:
+ overWrite = true;
+ executeTask( item );
+ inTaskFinished--;
+ return;
+ case TDEIO::R_AUTO_SKIP:
+ autoSkip = true;
+ case TDEIO::R_SKIP:
+ default:
+ break;
+ }
+ break;
+ }
+
+ if( job->error() != TDEIO::ERR_DOES_NOT_EXIST || item->task() != TT_DELETE )
+ {
+ if( autoSkip )
+ break;
+
+ TQString error;
+
+ switch( item->task() )
+ {
+ case TT_COPY_TO_LEFT:
+ error = i18n("Error at copying file %1 to %2!")
+ .arg( vfs::pathOrURL( rightURL ) )
+ .arg( vfs::pathOrURL( leftURL ) );
+ break;
+ case TT_COPY_TO_RIGHT:
+ error = i18n("Error at copying file %1 to %2!")
+ .arg( vfs::pathOrURL( leftURL ) )
+ .arg( vfs::pathOrURL( rightURL ) );
+ break;
+ case TT_DELETE:
+ error = i18n("Error at deleting file %1!").arg( vfs::pathOrURL( leftURL ) );
+ break;
+ default:
+ break;
+ }
+
+ TQWidget *mainWidget = tqApp->mainWidget(); // WORKAROUND, don't give focus to the main widget
+ tqApp->setMainWidget( syncDlgWidget );
+
+ TDEIO::SkipDlg_Result result = Observer::self()->open_SkipDlg( job, true, error );
+
+ tqApp->setMainWidget( mainWidget );
+
+ switch( result )
+ {
+ case TDEIO::S_CANCEL:
+ executeTask( item ); /* simply retry */
+ inTaskFinished--;
+ return;
+ case TDEIO::S_AUTO_SKIP:
+ autoSkip = true;
+ default:
+ break;
+ }
+ }
+ }
+ }while( false );
+
+ switch( item->task() )
+ {
+ case TT_COPY_TO_LEFT:
+ leftCopyNr++;
+ leftCopySize += item->rightSize() - receivedSize;
+ break;
+ case TT_COPY_TO_RIGHT:
+ rightCopyNr++;
+ rightCopySize += item->leftSize() - receivedSize;
+ break;
+ case TT_DELETE:
+ deleteNr++;
+ deleteSize += item->leftSize() - receivedSize;
+ break;
+ default:
+ break;
+ }
+
+ emit processedSizes( leftCopyNr, leftCopySize, rightCopyNr, rightCopySize, deleteNr, deleteSize );
+
+ if( --inTaskFinished == 0 ) {
+ if( paused )
+ emit pauseAccepted();
+ else
+ synchronizeLoop();
+ }
+}
+
+void Synchronizer::slotProcessedSize( TDEIO::Job * job , TDEIO::filesize_t size)
+{
+ TDEIO::filesize_t dl = 0, dr = 0, dd = 0;
+ SynchronizerFileItem * item = jobMap[ job ];
+
+ TDEIO::filesize_t lastProcessedSize = 0;
+ if( receivedMap.contains( job ) )
+ lastProcessedSize = receivedMap[ job ];
+
+ receivedMap[ job ] = size;
+
+ switch( item->task() )
+ {
+ case TT_COPY_TO_LEFT:
+ dl = size - lastProcessedSize;
+ break;
+ case TT_COPY_TO_RIGHT:
+ dr = size - lastProcessedSize;
+ break;
+ case TT_DELETE:
+ dd = size - lastProcessedSize;
+ break;
+ default:
+ break;
+ }
+
+ emit processedSizes( leftCopyNr, leftCopySize+=dl, rightCopyNr, rightCopySize+=dr, deleteNr, deleteSize+=dd );
+}
+
+void Synchronizer::pause()
+{
+ paused = true;
+}
+
+void Synchronizer::resume()
+{
+ paused = false;
+ synchronizeLoop();
+}
+
+TQString Synchronizer::leftBaseDirectory()
+{
+ return leftBaseDir;
+}
+
+TQString Synchronizer::rightBaseDirectory()
+{
+ return rightBaseDir;
+}
+
+class KgetProgressDialog : public KDialogBase
+{
+public:
+ KgetProgressDialog( TQWidget *parent=0, const char *name=0, const TQString &caption=TQString(),
+ const TQString &text=TQString(), bool modal=false) : KDialogBase( KDialogBase::Plain,
+ caption, KDialogBase::User1 | KDialogBase::Cancel, KDialogBase::Cancel, parent, name, modal )
+ {
+ showButton(KDialogBase::Close, false);
+
+ TQFrame* mainWidget = plainPage();
+ TQVBoxLayout* layout = new TQVBoxLayout(mainWidget, 10);
+
+ TQLabel *mLabel = new TQLabel(text, mainWidget);
+ layout->addWidget(mLabel);
+
+ mProgressBar = new KProgress(mainWidget);
+ layout->addWidget(mProgressBar);
+
+ setButtonText( KDialogBase::User1, i18n( "Pause" ) );
+
+ mCancelled = mPaused = false;
+ }
+
+ KProgress *progressBar() { return mProgressBar; }
+
+ void slotUser1()
+ {
+ if( ( mPaused = !mPaused ) == false )
+ setButtonText( KDialogBase::User1, i18n( "Pause" ) );
+ else
+ setButtonText( KDialogBase::User1, i18n( "Resume" ) );
+ }
+
+ void slotCancel()
+ {
+ mCancelled = true;
+
+ KDialogBase::slotCancel();
+ }
+
+ bool wasCancelled() { return mCancelled; }
+ bool isPaused() { return mPaused; }
+
+private:
+ KProgress *mProgressBar;
+ bool mCancelled;
+ bool mPaused;
+};
+
+
+void Synchronizer::synchronizeWithKGet()
+{
+ bool isLeftLocal = vfs::fromPathOrURL( leftBaseDirectory() ).isLocalFile();
+ KgetProgressDialog *progDlg = 0;
+ int processedCount = 0, totalCount = 0;
+
+ SynchronizerFileItem *item = resultList.first();
+ for(; item; item = resultList.next() )
+ if( item->isMarked() )
+ totalCount++;
+
+ item = resultList.first();
+ while( item )
+ {
+ if( item->isMarked() )
+ {
+ KURL downloadURL, destURL;
+ TQString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + "/";
+ TQString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + "/";
+ TQString destDir;
+
+ if( progDlg == 0 )
+ {
+ progDlg = new KgetProgressDialog( krApp, "Synchronizer Progress Dlg", i18n("Krusader::Synchronizer"),
+ i18n( "Feeding the URLs to Kget" ), true );
+ progDlg->progressBar()->setTotalSteps( totalCount );
+ progDlg->show();
+ tqApp->processEvents();
+ }
+
+ if( item->task() == TT_COPY_TO_RIGHT && !isLeftLocal )
+ {
+ downloadURL = vfs::fromPathOrURL( leftBaseDirectory() + leftDirName + item->leftName() );
+ destDir = rightBaseDirectory() + rightDirName;
+ destURL = vfs::fromPathOrURL( destDir + item->rightName() );
+
+ if( item->isDir() )
+ destDir += item->leftName();
+ }
+ if( item->task() == TT_COPY_TO_LEFT && isLeftLocal )
+ {
+ downloadURL = vfs::fromPathOrURL( rightBaseDirectory() + rightDirName + item->rightName() );
+ destDir = leftBaseDirectory() + leftDirName;
+ destURL = vfs::fromPathOrURL( destDir + item->leftName() );
+
+ if( item->isDir() )
+ destDir += item->rightName();
+ }
+
+ // creating the directory system
+ for( int i=0; i >= 0 ; i= destDir.find('/',i+1) )
+ if( !TQDir( destDir.left(i) ).exists() )
+ TQDir().mkdir( destDir.left(i) );
+
+ if( !item->isDir() && !downloadURL.isEmpty() )
+ {
+ if( TQFile( destURL.path() ).exists() )
+ TQFile( destURL.path() ).remove();
+
+ TQString source = downloadURL.prettyURL();
+ if( source.contains( '@' ) >= 2 ) /* is this an ftp proxy URL? */
+ {
+ int lastAt = source.findRev( '@' );
+ TQString startString = source.left( lastAt );
+ TQString endString = source.mid( lastAt );
+ startString.replace( "@", "%40" );
+ source = startString+endString;
+ }
+
+ TDEProcess p;
+
+ p << KrServices::fullPathName( "kget" ) << source << destURL.path();
+ if (!p.start(TDEProcess::Block))
+ KMessageBox::error(parentWidget,i18n("Error executing ")+KrServices::fullPathName( "kget" )+" !");
+ else
+ p.detach();
+ }
+
+ progDlg->progressBar()->setProgress( ++processedCount );
+
+ do
+ {
+ tqApp->processEvents();
+
+ if( progDlg->wasCancelled() )
+ break;
+
+ if( progDlg->isPaused() )
+ usleep( 100000 );
+
+ }while( progDlg->isPaused() );
+
+ if( progDlg->wasCancelled() )
+ break;
+ }
+ item = resultList.next();
+ }
+
+ if( progDlg )
+ delete progDlg;
+}
+
+bool Synchronizer::isDir( const vfile * file ) {
+ if( followSymLinks ) {
+ return file->vfile_isDir();
+ }
+ else {
+ return file->vfile_isDir() && !file->vfile_isSymLink();
+ }
+}
+
+TQString Synchronizer::readLink( const vfile * file ) {
+ if( file->vfile_isSymLink() )
+ return file->vfile_getSymDest();
+ else
+ return TQString();
+}
+
+#include "synchronizer.moc"