annotate kdiff3/src/directorymergewindow.cpp @ 8:86d21651c8db

KDiff3 version 0.9.70
author joachim99
date Mon, 06 Oct 2003 18:50:45 +0000
parents
children d101155f5c52
rev   line source
joachim99@8 1 /***************************************************************************
joachim99@8 2 directorymergewindow.cpp
joachim99@8 3 -------------------
joachim99@8 4 begin : Sat Oct 19 2002
joachim99@8 5 copyright : (C) 2002 by Joachim Eibl
joachim99@8 6 email : joachim.eibl@gmx.de
joachim99@8 7 ***************************************************************************/
joachim99@8 8
joachim99@8 9 /***************************************************************************
joachim99@8 10 * *
joachim99@8 11 * This program is free software; you can redistribute it and/or modify *
joachim99@8 12 * it under the terms of the GNU General Public License as published by *
joachim99@8 13 * the Free Software Foundation; either version 2 of the License, or *
joachim99@8 14 * (at your option) any later version. *
joachim99@8 15 * *
joachim99@8 16 ***************************************************************************/
joachim99@8 17
joachim99@8 18 /***************************************************************************
joachim99@8 19 * $Log$
joachim99@8 20 * Revision 1.1 2003/10/06 18:38:48 joachim99
joachim99@8 21 * KDiff3 version 0.9.70
joachim99@8 22 * *
joachim99@8 23 ***************************************************************************/
joachim99@8 24
joachim99@8 25 #include "directorymergewindow.h"
joachim99@8 26 #include "optiondialog.h"
joachim99@8 27 #include <vector>
joachim99@8 28 #include <map>
joachim99@8 29
joachim99@8 30 #include <qdir.h>
joachim99@8 31 #include <qapplication.h>
joachim99@8 32 #include <qpixmap.h>
joachim99@8 33 #include <qimage.h>
joachim99@8 34 #include <kpopupmenu.h>
joachim99@8 35 #include <qregexp.h>
joachim99@8 36 #include <qmessagebox.h>
joachim99@8 37 #include <qlayout.h>
joachim99@8 38 #include <qlabel.h>
joachim99@8 39 #include <qtable.h>
joachim99@8 40 #include <qsplitter.h>
joachim99@8 41 #include <qprogressdialog.h>
joachim99@8 42 #include <kmessagebox.h>
joachim99@8 43 #include <kiconloader.h>
joachim99@8 44 #include <klocale.h>
joachim99@8 45 #include <iostream>
joachim99@8 46 #include <assert.h>
joachim99@8 47
joachim99@8 48
joachim99@8 49 class StatusInfo : public QListView
joachim99@8 50 {
joachim99@8 51 public:
joachim99@8 52 StatusInfo(QWidget* pParent) : QListView( pParent )
joachim99@8 53 {
joachim99@8 54 addColumn("");
joachim99@8 55 setSorting(-1); //disable sorting
joachim99@8 56 }
joachim99@8 57
joachim99@8 58 QListViewItem* m_pLast;
joachim99@8 59 QListViewItem* last()
joachim99@8 60 {
joachim99@8 61 if (firstChild()==0) return 0;
joachim99@8 62 else return m_pLast;
joachim99@8 63 }
joachim99@8 64
joachim99@8 65 void addText(const QString& s )
joachim99@8 66 {
joachim99@8 67 if (firstChild()==0) m_pLast = new QListViewItem( this, s );
joachim99@8 68 else m_pLast = new QListViewItem( this, last(), s );
joachim99@8 69 }
joachim99@8 70 };
joachim99@8 71
joachim99@8 72
joachim99@8 73 class TempRemover
joachim99@8 74 {
joachim99@8 75 public:
joachim99@8 76 TempRemover( const QString& origName, FileAccess& fa );
joachim99@8 77 ~TempRemover();
joachim99@8 78 QString name() { return m_name; }
joachim99@8 79 bool success() { return m_bSuccess; }
joachim99@8 80 private:
joachim99@8 81 QString m_name;
joachim99@8 82 bool m_bTemp;
joachim99@8 83 bool m_bSuccess;
joachim99@8 84 };
joachim99@8 85 TempRemover::TempRemover(const QString& origName, FileAccess& fa)
joachim99@8 86 {
joachim99@8 87 if ( fa.isLocal() )
joachim99@8 88 {
joachim99@8 89 m_name = origName;
joachim99@8 90 m_bTemp = false;
joachim99@8 91 m_bSuccess = true;
joachim99@8 92 }
joachim99@8 93 else
joachim99@8 94 {
joachim99@8 95 m_name = FileAccess::tempFileName();
joachim99@8 96 m_bSuccess = fa.copyFile( m_name );
joachim99@8 97 m_bTemp = m_bSuccess;
joachim99@8 98 }
joachim99@8 99 }
joachim99@8 100 TempRemover::~TempRemover()
joachim99@8 101 {
joachim99@8 102 if ( m_bTemp && ! m_name.isEmpty() )
joachim99@8 103 FileAccess::removeFile(m_name);
joachim99@8 104 }
joachim99@8 105
joachim99@8 106 void DirectoryMergeWindow::fastFileComparison(
joachim99@8 107 FileAccess& fi1, FileAccess& fi2,
joachim99@8 108 bool& bEqual, bool& bError, QString& status )
joachim99@8 109 {
joachim99@8 110 status = "";
joachim99@8 111 bEqual = false;
joachim99@8 112 bError = true;
joachim99@8 113
joachim99@8 114 if ( !m_bFollowFileLinks )
joachim99@8 115 {
joachim99@8 116 if ( fi1.isSymLink() != fi2.isSymLink() )
joachim99@8 117 {
joachim99@8 118 status = "Mix of links and normal files.";
joachim99@8 119 return;
joachim99@8 120 }
joachim99@8 121 else if ( fi1.isSymLink() && fi2.isSymLink() )
joachim99@8 122 {
joachim99@8 123 bError = false;
joachim99@8 124 bEqual = fi1.readLink() == fi2.readLink();
joachim99@8 125 status = "Link: ";
joachim99@8 126 return;
joachim99@8 127 }
joachim99@8 128 }
joachim99@8 129
joachim99@8 130 if ( fi1.size()!=fi2.size() )
joachim99@8 131 {
joachim99@8 132 bEqual = false;
joachim99@8 133 status = "Size. ";
joachim99@8 134 return;
joachim99@8 135 }
joachim99@8 136
joachim99@8 137 if ( m_pOptions->m_bDmTrustDate )
joachim99@8 138 {
joachim99@8 139 bEqual = ( fi1.lastModified() == fi2.lastModified() && fi1.size()==fi2.size() );
joachim99@8 140 bError = false;
joachim99@8 141 status = "Date&Size: ";
joachim99@8 142 return;
joachim99@8 143 }
joachim99@8 144
joachim99@8 145 QString fileName1 = fi1.absFilePath();
joachim99@8 146 QString fileName2 = fi2.absFilePath();
joachim99@8 147 TempRemover tr1( fileName1, fi1 );
joachim99@8 148 if ( !tr1.success() )
joachim99@8 149 {
joachim99@8 150 status = "Creating temp copy of " + fileName1 + " failed.";
joachim99@8 151 return;
joachim99@8 152 }
joachim99@8 153 TempRemover tr2( fileName2, fi2 );
joachim99@8 154 if ( !tr2.success() )
joachim99@8 155 {
joachim99@8 156 status = "Creating temp copy of " + fileName2 + " failed.";
joachim99@8 157 return;
joachim99@8 158 }
joachim99@8 159
joachim99@8 160 std::vector<char> buf1(100000);
joachim99@8 161 std::vector<char> buf2(buf1.size());
joachim99@8 162
joachim99@8 163 QFile file1( tr1.name() );
joachim99@8 164
joachim99@8 165 if ( ! file1.open(IO_ReadOnly) )
joachim99@8 166 {
joachim99@8 167 status = "Opening " + fileName1 + " failed.";
joachim99@8 168 return;
joachim99@8 169 }
joachim99@8 170
joachim99@8 171 QFile file2( tr2.name() );
joachim99@8 172
joachim99@8 173 if ( ! file2.open(IO_ReadOnly) )
joachim99@8 174 {
joachim99@8 175 status = "Opening " + fileName2 + " failed.";
joachim99@8 176 return;
joachim99@8 177 }
joachim99@8 178
joachim99@8 179 #if QT_VERSION==230
joachim99@8 180 typedef int t_FileSize;
joachim99@8 181 #else
joachim99@8 182 typedef QFile::Offset t_FileSize;
joachim99@8 183 #endif
joachim99@8 184 t_FileSize size = file1.size();
joachim99@8 185
joachim99@8 186 while( size>0 )
joachim99@8 187 {
joachim99@8 188 int len = min2( size, (t_FileSize)buf1.size() );
joachim99@8 189 if( len != file1.readBlock( &buf1[0], len ) )
joachim99@8 190 {
joachim99@8 191 status = "Error reading from " + fileName1;
joachim99@8 192 return;
joachim99@8 193 }
joachim99@8 194
joachim99@8 195 if( len != file2.readBlock( &buf2[0], len ) )
joachim99@8 196 {
joachim99@8 197 status = "Error reading from " + fileName2;
joachim99@8 198 return;
joachim99@8 199 }
joachim99@8 200
joachim99@8 201 if ( memcmp( &buf1[0], &buf2[0], len ) != 0 )
joachim99@8 202 {
joachim99@8 203 bError = false;
joachim99@8 204 return;
joachim99@8 205 }
joachim99@8 206 size-=len;
joachim99@8 207 }
joachim99@8 208
joachim99@8 209 // If the program really arrives here, then the files are really equal.
joachim99@8 210 bError = false;
joachim99@8 211 bEqual = true;
joachim99@8 212 }
joachim99@8 213
joachim99@8 214
joachim99@8 215
joachim99@8 216
joachim99@8 217
joachim99@8 218 static int s_nameCol = 0;
joachim99@8 219 static int s_ACol = 1;
joachim99@8 220 static int s_BCol = 2;
joachim99@8 221 static int s_CCol = 3;
joachim99@8 222 static int s_OpCol = 4;
joachim99@8 223 static int s_OpStatusCol = 5;
joachim99@8 224 DirectoryMergeWindow::DirectoryMergeWindow( QWidget* pParent, OptionDialog* pOptions, KIconLoader* pIconLoader )
joachim99@8 225 : QListView( pParent )
joachim99@8 226 {
joachim99@8 227 connect( this, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(onDoubleClick(QListViewItem*)));
joachim99@8 228 connect( this, SIGNAL(returnPressed(QListViewItem*)), this, SLOT(onDoubleClick(QListViewItem*)));
joachim99@8 229 connect( this, SIGNAL( pressed(QListViewItem*,const QPoint&, int)),
joachim99@8 230 this, SLOT( onClick(QListViewItem*,const QPoint&, int)) );
joachim99@8 231 connect( this, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(onSelectionChanged(QListViewItem*)));
joachim99@8 232 m_pOptions = pOptions;
joachim99@8 233 m_pIconLoader = pIconLoader;
joachim99@8 234 m_pDirectoryMergeInfo = 0;
joachim99@8 235 m_bAllowResizeEvents = true;
joachim99@8 236 m_bSimulatedMergeStarted=false;
joachim99@8 237 m_bRealMergeStarted=false;
joachim99@8 238 m_bSingleFileOperationStarted=false;
joachim99@8 239 m_bError = false;
joachim99@8 240 m_bSyncMode = false;
joachim99@8 241 m_pStatusInfo = new StatusInfo(0);
joachim99@8 242 m_pStatusInfo->hide();
joachim99@8 243
joachim99@8 244 addColumn("Name");
joachim99@8 245 addColumn("A");
joachim99@8 246 addColumn("B");
joachim99@8 247 addColumn("C");
joachim99@8 248 addColumn("Operation");
joachim99@8 249 addColumn("Status");
joachim99@8 250 }
joachim99@8 251
joachim99@8 252 DirectoryMergeWindow::~DirectoryMergeWindow()
joachim99@8 253 {
joachim99@8 254 }
joachim99@8 255
joachim99@8 256
joachim99@8 257 int DirectoryMergeWindow::totalColumnWidth()
joachim99@8 258 {
joachim99@8 259 int w=0;
joachim99@8 260 for (int i=0; i<s_OpStatusCol; ++i)
joachim99@8 261 {
joachim99@8 262 w += columnWidth(i);
joachim99@8 263 }
joachim99@8 264 return w;
joachim99@8 265 }
joachim99@8 266
joachim99@8 267 void DirectoryMergeWindow::reload()
joachim99@8 268 {
joachim99@8 269 if ( isDirectoryMergeInProgress() )
joachim99@8 270 {
joachim99@8 271 int result = KMessageBox::warningYesNo(this,
joachim99@8 272 i18n("You are currently doing a directory merge. Are you sure, you want to abort the merge and rescan the directory?"),
joachim99@8 273 i18n("Warning"), i18n("Yes - Rescan"), i18n("No - Continue merging") );
joachim99@8 274 if ( result!=KMessageBox::Yes )
joachim99@8 275 return;
joachim99@8 276 }
joachim99@8 277 init( m_dirA, m_dirB, m_dirC, m_dirDest, m_bDirectoryMerge );
joachim99@8 278 }
joachim99@8 279
joachim99@8 280 // Copy pm2 onto pm1, but preserve the alpha value from pm1 where pm2 is transparent.
joachim99@8 281 static QPixmap pixCombiner( const QPixmap& pm1, const QPixmap& pm2 )
joachim99@8 282 {
joachim99@8 283 QImage img1 = pm1.convertToImage().convertDepth(32);
joachim99@8 284 QImage img2 = pm2.convertToImage().convertDepth(32);
joachim99@8 285
joachim99@8 286 for (int y = 0; y < img1.height(); y++)
joachim99@8 287 {
joachim99@8 288 Q_UINT32 *line1 = reinterpret_cast<Q_UINT32 *>(img1.scanLine(y));
joachim99@8 289 Q_UINT32 *line2 = reinterpret_cast<Q_UINT32 *>(img2.scanLine(y));
joachim99@8 290 for (int x = 0; x < img1.width(); x++)
joachim99@8 291 {
joachim99@8 292 if ( qAlpha( line2[x] ) >0 )
joachim99@8 293 line1[x] = (line2[x] | 0xff000000);
joachim99@8 294 }
joachim99@8 295 }
joachim99@8 296 QPixmap pix;
joachim99@8 297 pix.convertFromImage(img1);
joachim99@8 298 return pix;
joachim99@8 299 }
joachim99@8 300
joachim99@8 301 // like pixCombiner but let the pm1 color shine through
joachim99@8 302 static QPixmap pixCombiner2( const QPixmap& pm1, const QPixmap& pm2 )
joachim99@8 303 {
joachim99@8 304 QImage img1 = pm1.convertToImage().convertDepth(32);
joachim99@8 305 QImage img2 = pm2.convertToImage().convertDepth(32);
joachim99@8 306
joachim99@8 307 for (int y = 0; y < img1.height(); y++)
joachim99@8 308 {
joachim99@8 309 Q_UINT32 *line1 = reinterpret_cast<Q_UINT32 *>(img1.scanLine(y));
joachim99@8 310 Q_UINT32 *line2 = reinterpret_cast<Q_UINT32 *>(img2.scanLine(y));
joachim99@8 311 for (int x = 0; x < img1.width(); x++)
joachim99@8 312 {
joachim99@8 313 if ( qAlpha( line2[x] ) >0 )
joachim99@8 314 {
joachim99@8 315 int r = ( qRed( line1[x] ) + qRed( line2[x] ))/2;
joachim99@8 316 int g = ( qGreen( line1[x] ) + qGreen( line2[x] ))/2;
joachim99@8 317 int b = ( qBlue( line1[x] ) + qBlue( line2[x] ))/2;
joachim99@8 318 line1[x] = qRgba( r,g,b, 0xff );
joachim99@8 319 }
joachim99@8 320 }
joachim99@8 321 }
joachim99@8 322 QPixmap pix;
joachim99@8 323 pix.convertFromImage(img1);
joachim99@8 324 return pix;
joachim99@8 325 }
joachim99@8 326
joachim99@8 327 static void calcDirStatus( bool bThreeDirs, DirMergeItem* i, int& nofFiles,
joachim99@8 328 int& nofDirs, int& nofEqualFiles, int& nofManualMerges )
joachim99@8 329 {
joachim99@8 330 if ( i->m_pMFI->m_bDirA || i->m_pMFI->m_bDirB || i->m_pMFI->m_bDirC )
joachim99@8 331 {
joachim99@8 332 ++nofDirs;
joachim99@8 333 }
joachim99@8 334 else
joachim99@8 335 {
joachim99@8 336 ++nofFiles;
joachim99@8 337 if ( i->m_pMFI->m_bEqualAB && (!bThreeDirs || i->m_pMFI->m_bEqualAC ))
joachim99@8 338 {
joachim99@8 339 ++nofEqualFiles;
joachim99@8 340 }
joachim99@8 341 else
joachim99@8 342 {
joachim99@8 343 if ( i->m_pMFI->m_eMergeOperation==eMergeABCToDest || i->m_pMFI->m_eMergeOperation==eMergeABToDest )
joachim99@8 344 ++nofManualMerges;
joachim99@8 345 }
joachim99@8 346 }
joachim99@8 347 for( QListViewItem* p = i->firstChild(); p!=0; p = p->nextSibling() )
joachim99@8 348 calcDirStatus( bThreeDirs, static_cast<DirMergeItem*>(p), nofFiles, nofDirs, nofEqualFiles, nofManualMerges );
joachim99@8 349 }
joachim99@8 350
joachim99@8 351 bool DirectoryMergeWindow::init
joachim99@8 352 (
joachim99@8 353 FileAccess& dirA,
joachim99@8 354 FileAccess& dirB,
joachim99@8 355 FileAccess& dirC,
joachim99@8 356 FileAccess& dirDest,
joachim99@8 357 bool bDirectoryMerge
joachim99@8 358 )
joachim99@8 359 {
joachim99@8 360 m_bFollowDirLinks = m_pOptions->m_bDmFollowDirLinks;
joachim99@8 361 m_bFollowFileLinks = m_pOptions->m_bDmFollowFileLinks;
joachim99@8 362 m_bSimulatedMergeStarted=false;
joachim99@8 363 m_bRealMergeStarted=false;
joachim99@8 364 m_bError=false;
joachim99@8 365 m_bDirectoryMerge = bDirectoryMerge;
joachim99@8 366
joachim99@8 367 clear();
joachim99@8 368
joachim99@8 369 m_pCurrentItemForOperation = 0;
joachim99@8 370
joachim99@8 371 m_dirA = dirA;
joachim99@8 372 m_dirB = dirB;
joachim99@8 373 m_dirC = dirC;
joachim99@8 374 m_dirDest = dirDest;
joachim99@8 375
joachim99@8 376 // Check if all input directories exist and are valid. The dest dir is not tested now.
joachim99@8 377 // The test will happen only when we are going to write to it.
joachim99@8 378 if ( !m_dirA.isDir() || !m_dirB.isDir() ||
joachim99@8 379 (m_dirC.isValid() && !m_dirC.isDir()) )
joachim99@8 380 {
joachim99@8 381 QString text( i18n("Opening of directories failed:") );
joachim99@8 382 text += "\n\n";
joachim99@8 383 if ( !dirA.isDir() )
joachim99@8 384 { text += "Dir A \"" + m_dirA.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
joachim99@8 385
joachim99@8 386 if ( !dirB.isDir() )
joachim99@8 387 { text += "Dir B \"" + m_dirB.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
joachim99@8 388
joachim99@8 389 if ( m_dirC.isValid() && !m_dirC.isDir() )
joachim99@8 390 { text += "Dir C \"" + m_dirC.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
joachim99@8 391
joachim99@8 392 KMessageBox::sorry( this, text, i18n("Directory open error") );
joachim99@8 393 return false;
joachim99@8 394 }
joachim99@8 395
joachim99@8 396 if ( m_dirC.isValid() &&
joachim99@8 397 (m_dirDest.prettyAbsPath() == m_dirA.prettyAbsPath() || m_dirDest.prettyAbsPath()==m_dirB.prettyAbsPath() ) )
joachim99@8 398 {
joachim99@8 399 KMessageBox::error(this,
joachim99@8 400 i18n( "The destination directory must not be the same as A or B when"
joachim99@8 401 "three directories are merged.\nCheck again before continuing."),
joachim99@8 402 "KDiff3: Parameter warning");
joachim99@8 403 return false;
joachim99@8 404 }
joachim99@8 405
joachim99@8 406 m_bSyncMode = m_pOptions->m_bDmSyncMode && !m_dirC.isValid() && !m_dirDest.isValid();
joachim99@8 407
joachim99@8 408 if ( m_dirDest.isValid() )
joachim99@8 409 m_dirDestInternal = m_dirDest;
joachim99@8 410 else
joachim99@8 411 m_dirDestInternal = m_dirC.isValid() ? m_dirC : m_dirB;
joachim99@8 412
joachim99@8 413 QString origCurrentDirectory = QDir::currentDirPath();
joachim99@8 414
joachim99@8 415 g_pProgressDialog->start();
joachim99@8 416
joachim99@8 417 m_fileMergeMap.clear();
joachim99@8 418 t_DirectoryList::iterator i;
joachim99@8 419
joachim99@8 420 // calc how many directories will be read:
joachim99@8 421 double nofScans = ( m_dirA.isValid() ? 1 : 0 )+( m_dirB.isValid() ? 1 : 0 )+( m_dirC.isValid() ? 1 : 0 );
joachim99@8 422 int currentScan = 0;
joachim99@8 423
joachim99@8 424 bool bListDirSuccessA = true;
joachim99@8 425 bool bListDirSuccessB = true;
joachim99@8 426 bool bListDirSuccessC = true;
joachim99@8 427 if ( m_dirA.isValid() )
joachim99@8 428 {
joachim99@8 429 g_pProgressDialog->setInformation("Reading Directory A");
joachim99@8 430 g_pProgressDialog->setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
joachim99@8 431 ++currentScan;
joachim99@8 432
joachim99@8 433 t_DirectoryList dirListA;
joachim99@8 434 bListDirSuccessA = m_dirA.listDir( &dirListA,
joachim99@8 435 m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden,
joachim99@8 436 m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern,
joachim99@8 437 m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks,
joachim99@8 438 m_pOptions->m_bDmUseCvsIgnore);
joachim99@8 439
joachim99@8 440 for (i=dirListA.begin(); i!=dirListA.end();++i )
joachim99@8 441 {
joachim99@8 442 MergeFileInfos& mfi = m_fileMergeMap[i->filePath()];
joachim99@8 443 //std::cout <<i->filePath()<<std::endl;
joachim99@8 444 mfi.m_bExistsInA = true;
joachim99@8 445 mfi.m_fileInfoA = *i;
joachim99@8 446 }
joachim99@8 447 }
joachim99@8 448
joachim99@8 449 if ( m_dirB.isValid() )
joachim99@8 450 {
joachim99@8 451 g_pProgressDialog->setInformation("Reading Directory B");
joachim99@8 452 g_pProgressDialog->setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
joachim99@8 453 ++currentScan;
joachim99@8 454
joachim99@8 455 t_DirectoryList dirListB;
joachim99@8 456 bListDirSuccessB = m_dirB.listDir( &dirListB,
joachim99@8 457 m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden,
joachim99@8 458 m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern,
joachim99@8 459 m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks,
joachim99@8 460 m_pOptions->m_bDmUseCvsIgnore);
joachim99@8 461
joachim99@8 462 for (i=dirListB.begin(); i!=dirListB.end();++i )
joachim99@8 463 {
joachim99@8 464 MergeFileInfos& mfi = m_fileMergeMap[i->filePath()];
joachim99@8 465 mfi.m_bExistsInB = true;
joachim99@8 466 mfi.m_fileInfoB = *i;
joachim99@8 467 }
joachim99@8 468 }
joachim99@8 469
joachim99@8 470 e_MergeOperation eDefaultMergeOp;
joachim99@8 471 if ( m_dirC.isValid() )
joachim99@8 472 {
joachim99@8 473 g_pProgressDialog->setInformation("Reading Directory C");
joachim99@8 474 g_pProgressDialog->setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
joachim99@8 475 ++currentScan;
joachim99@8 476
joachim99@8 477 t_DirectoryList dirListC;
joachim99@8 478 bListDirSuccessC = m_dirC.listDir( &dirListC,
joachim99@8 479 m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden,
joachim99@8 480 m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern,
joachim99@8 481 m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks,
joachim99@8 482 m_pOptions->m_bDmUseCvsIgnore);
joachim99@8 483
joachim99@8 484 for (i=dirListC.begin(); i!=dirListC.end();++i )
joachim99@8 485 {
joachim99@8 486 MergeFileInfos& mfi = m_fileMergeMap[i->filePath()];
joachim99@8 487 mfi.m_bExistsInC = true;
joachim99@8 488 mfi.m_fileInfoC = *i;
joachim99@8 489 }
joachim99@8 490
joachim99@8 491 eDefaultMergeOp = eMergeABCToDest;
joachim99@8 492 }
joachim99@8 493 else
joachim99@8 494 eDefaultMergeOp = m_bSyncMode ? eMergeToAB : eMergeABToDest;
joachim99@8 495
joachim99@8 496 bool bContinue = true;
joachim99@8 497 if ( !bListDirSuccessA || !bListDirSuccessB || !bListDirSuccessC )
joachim99@8 498 {
joachim99@8 499 QString s = i18n("Some subdirectories were not readable in");
joachim99@8 500 if ( !bListDirSuccessA ) s += "\nA: " + m_dirA.prettyAbsPath();
joachim99@8 501 if ( !bListDirSuccessB ) s += "\nB: " + m_dirB.prettyAbsPath();
joachim99@8 502 if ( !bListDirSuccessC ) s += "\nC: " + m_dirC.prettyAbsPath();
joachim99@8 503 s+="\n";
joachim99@8 504 s+= i18n("Check the permissions of the subdirectories.");
joachim99@8 505 bContinue = KMessageBox::Continue == KMessageBox::warningContinueCancel( this, s );
joachim99@8 506 }
joachim99@8 507
joachim99@8 508 if ( bContinue )
joachim99@8 509 {
joachim99@8 510 prepareListView();
joachim99@8 511 g_pProgressDialog->hide();
joachim99@8 512
joachim99@8 513 for( QListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
joachim99@8 514 {
joachim99@8 515 DirMergeItem* pDMI = static_cast<DirMergeItem*>( p );
joachim99@8 516 calcSuggestedOperation( *pDMI->m_pMFI, eDefaultMergeOp );
joachim99@8 517 }
joachim99@8 518 }
joachim99@8 519 else
joachim99@8 520 {
joachim99@8 521 g_pProgressDialog->hide();
joachim99@8 522 setSelected( 0, true );
joachim99@8 523 }
joachim99@8 524
joachim99@8 525 QDir::setCurrent(origCurrentDirectory);
joachim99@8 526
joachim99@8 527 // Try to improve the view a little bit.
joachim99@8 528 QWidget* pParent = parentWidget();
joachim99@8 529 QSplitter* pSplitter = static_cast<QSplitter*>(pParent);
joachim99@8 530 if (pSplitter!=0)
joachim99@8 531 {
joachim99@8 532 QValueList<int> sizes = pSplitter->sizes();
joachim99@8 533 int total = sizes[0] + sizes[1];
joachim99@8 534 sizes[0]=total*6/10;
joachim99@8 535 sizes[1]=total - sizes[0];
joachim99@8 536 pSplitter->setSizes( sizes );
joachim99@8 537 }
joachim99@8 538
joachim99@8 539 if ( bContinue )
joachim99@8 540 {
joachim99@8 541 // Generate a status report
joachim99@8 542 int nofFiles=0;
joachim99@8 543 int nofDirs=0;
joachim99@8 544 int nofEqualFiles=0;
joachim99@8 545 int nofManualMerges=0;
joachim99@8 546 for( QListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
joachim99@8 547 calcDirStatus( m_dirC.isValid(), static_cast<DirMergeItem*>(p),
joachim99@8 548 nofFiles, nofDirs, nofEqualFiles, nofManualMerges );
joachim99@8 549
joachim99@8 550 QString s;
joachim99@8 551 s = i18n("Directory Comparison Status:") + "\n\n" +
joachim99@8 552 i18n("Number of subdirectories:") +" "+ QString::number(nofDirs) + "\n"+
joachim99@8 553 i18n("Number of equal files:") +" "+ QString::number(nofEqualFiles) + "\n"+
joachim99@8 554 i18n("Number of different files:") +" "+ QString::number(nofFiles-nofEqualFiles);
joachim99@8 555
joachim99@8 556 if ( m_dirC.isValid() )
joachim99@8 557 s += "\n" + i18n("Number of manual merges:") +" "+ QString::number(nofManualMerges);
joachim99@8 558 KMessageBox::information( this, s );
joachim99@8 559 setSelected( firstChild(), true );
joachim99@8 560 }
joachim99@8 561
joachim99@8 562 return true;
joachim99@8 563 }
joachim99@8 564
joachim99@8 565
joachim99@8 566
joachim99@8 567 void DirectoryMergeWindow::slotChooseAEverywhere(){ setAllMergeOperations( eCopyAToDest ); }
joachim99@8 568
joachim99@8 569 void DirectoryMergeWindow::slotChooseBEverywhere(){ setAllMergeOperations( eCopyBToDest ); }
joachim99@8 570
joachim99@8 571 void DirectoryMergeWindow::slotChooseCEverywhere(){ setAllMergeOperations( eCopyCToDest ); }
joachim99@8 572
joachim99@8 573 void DirectoryMergeWindow::slotAutoChooseEverywhere()
joachim99@8 574 {
joachim99@8 575 e_MergeOperation eDefaultMergeOp = m_dirC.isValid() ? eMergeABCToDest :
joachim99@8 576 m_bSyncMode ? eMergeToAB : eMergeABToDest;
joachim99@8 577 setAllMergeOperations(eDefaultMergeOp );
joachim99@8 578 }
joachim99@8 579
joachim99@8 580 void DirectoryMergeWindow::slotNoOpEverywhere(){ setAllMergeOperations(eNoOperation); }
joachim99@8 581
joachim99@8 582 static void setListViewItemOpen( QListViewItem* p, bool bOpen )
joachim99@8 583 {
joachim99@8 584 for( QListViewItem* pChild = p->firstChild(); pChild!=0; pChild = pChild->nextSibling() )
joachim99@8 585 setListViewItemOpen( pChild, bOpen );
joachim99@8 586
joachim99@8 587 p->setOpen( bOpen );
joachim99@8 588 }
joachim99@8 589
joachim99@8 590 void DirectoryMergeWindow::slotFoldAllSubdirs()
joachim99@8 591 {
joachim99@8 592 for( QListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
joachim99@8 593 setListViewItemOpen( p, false );
joachim99@8 594 }
joachim99@8 595
joachim99@8 596 void DirectoryMergeWindow::slotUnfoldAllSubdirs()
joachim99@8 597 {
joachim99@8 598 for( QListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
joachim99@8 599 setListViewItemOpen( p, true );
joachim99@8 600 }
joachim99@8 601
joachim99@8 602 void DirectoryMergeWindow::setAllMergeOperations( e_MergeOperation eDefaultOperation )
joachim99@8 603 {
joachim99@8 604 if ( KMessageBox::Yes == KMessageBox::warningYesNo(this,
joachim99@8 605 i18n("This affects all merge operations."),
joachim99@8 606 i18n("KDiff3: Changing all merge operations"),i18n("Continue"), i18n("Cancel") ) )
joachim99@8 607 {
joachim99@8 608 for( QListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
joachim99@8 609 {
joachim99@8 610 DirMergeItem* pDMI = static_cast<DirMergeItem*>( p );
joachim99@8 611 calcSuggestedOperation( *pDMI->m_pMFI, eDefaultOperation );
joachim99@8 612 }
joachim99@8 613 }
joachim99@8 614 }
joachim99@8 615
joachim99@8 616
joachim99@8 617 void DirectoryMergeWindow::compareFilesAndCalcAges( MergeFileInfos& mfi )
joachim99@8 618 {
joachim99@8 619 std::map<QDateTime,int> dateMap;
joachim99@8 620
joachim99@8 621 if( mfi.m_bExistsInA )
joachim99@8 622 {
joachim99@8 623 mfi.m_bLinkA = mfi.m_fileInfoA.isSymLink();
joachim99@8 624 mfi.m_bDirA = mfi.m_fileInfoA.isDir();
joachim99@8 625 dateMap[ mfi.m_fileInfoA.lastModified() ] = 0;
joachim99@8 626 }
joachim99@8 627 if( mfi.m_bExistsInB )
joachim99@8 628 {
joachim99@8 629 mfi.m_bLinkB = mfi.m_fileInfoB.isSymLink();
joachim99@8 630 mfi.m_bDirB = mfi.m_fileInfoB.isDir();
joachim99@8 631 dateMap[ mfi.m_fileInfoB.lastModified() ] = 1;
joachim99@8 632 }
joachim99@8 633 if( mfi.m_bExistsInC )
joachim99@8 634 {
joachim99@8 635 mfi.m_bLinkC = mfi.m_fileInfoC.isSymLink();
joachim99@8 636 mfi.m_bDirC = mfi.m_fileInfoC.isDir();
joachim99@8 637 dateMap[ mfi.m_fileInfoC.lastModified() ] = 2;
joachim99@8 638 }
joachim99@8 639
joachim99@8 640 bool bError;
joachim99@8 641 QString eqStatus;
joachim99@8 642 if( mfi.m_bExistsInA && mfi.m_bExistsInB )
joachim99@8 643 {
joachim99@8 644 if( mfi.m_bDirA ) mfi.m_bEqualAB=true;
joachim99@8 645 else fastFileComparison( mfi.m_fileInfoA, mfi.m_fileInfoB, mfi.m_bEqualAB, bError, eqStatus );
joachim99@8 646 }
joachim99@8 647 if( mfi.m_bExistsInA && mfi.m_bExistsInC )
joachim99@8 648 {
joachim99@8 649 if( mfi.m_bDirA ) mfi.m_bEqualAC=true;
joachim99@8 650 else fastFileComparison( mfi.m_fileInfoA, mfi.m_fileInfoC, mfi.m_bEqualAC, bError, eqStatus );
joachim99@8 651 }
joachim99@8 652 if( mfi.m_bExistsInB && mfi.m_bExistsInC )
joachim99@8 653 {
joachim99@8 654 if (mfi.m_bEqualAB && mfi.m_bEqualAC)
joachim99@8 655 mfi.m_bEqualBC = true;
joachim99@8 656 else
joachim99@8 657 {
joachim99@8 658 if( mfi.m_bDirB ) mfi.m_bEqualBC=true;
joachim99@8 659 else fastFileComparison( mfi.m_fileInfoB, mfi.m_fileInfoC, mfi.m_bEqualBC, bError, eqStatus );
joachim99@8 660 }
joachim99@8 661 }
joachim99@8 662
joachim99@8 663 if (mfi.m_bLinkA!=mfi.m_bLinkB) mfi.m_bEqualAB=false;
joachim99@8 664 if (mfi.m_bLinkA!=mfi.m_bLinkC) mfi.m_bEqualAC=false;
joachim99@8 665 if (mfi.m_bLinkB!=mfi.m_bLinkC) mfi.m_bEqualBC=false;
joachim99@8 666
joachim99@8 667 if (mfi.m_bDirA!=mfi.m_bDirB) mfi.m_bEqualAB=false;
joachim99@8 668 if (mfi.m_bDirA!=mfi.m_bDirC) mfi.m_bEqualAC=false;
joachim99@8 669 if (mfi.m_bDirB!=mfi.m_bDirC) mfi.m_bEqualBC=false;
joachim99@8 670
joachim99@8 671 assert(eNew==0 && eMiddle==1 && eOld==2);
joachim99@8 672
joachim99@8 673 // The map automatically sorts the keys.
joachim99@8 674 int age = eNew;
joachim99@8 675 std::map<QDateTime,int>::reverse_iterator i;
joachim99@8 676 for( i=dateMap.rbegin(); i!=dateMap.rend(); ++i )
joachim99@8 677 {
joachim99@8 678 int n = i->second;
joachim99@8 679 if ( n==0 && mfi.m_ageA==eNotThere )
joachim99@8 680 {
joachim99@8 681 mfi.m_ageA = (e_Age)age; ++age;
joachim99@8 682 if ( mfi.m_bEqualAB ) { mfi.m_ageB = mfi.m_ageA; ++age; }
joachim99@8 683 if ( mfi.m_bEqualAC ) { mfi.m_ageC = mfi.m_ageA; ++age; }
joachim99@8 684 }
joachim99@8 685 else if ( n==1 && mfi.m_ageB==eNotThere )
joachim99@8 686 {
joachim99@8 687 mfi.m_ageB = (e_Age)age; ++age;
joachim99@8 688 if ( mfi.m_bEqualAB ) { mfi.m_ageA = mfi.m_ageB; ++age; }
joachim99@8 689 if ( mfi.m_bEqualBC ) { mfi.m_ageC = mfi.m_ageB; ++age; }
joachim99@8 690 }
joachim99@8 691 else if ( n==2 && mfi.m_ageC==eNotThere)
joachim99@8 692 {
joachim99@8 693 mfi.m_ageC = (e_Age)age; ++age;
joachim99@8 694 if ( mfi.m_bEqualAC ) { mfi.m_ageA = mfi.m_ageC; ++age; }
joachim99@8 695 if ( mfi.m_bEqualBC ) { mfi.m_ageB = mfi.m_ageC; ++age; }
joachim99@8 696 }
joachim99@8 697 }
joachim99@8 698
joachim99@8 699 // The checks below are necessary when the dates of the file are equal but the
joachim99@8 700 // files are not. One wouldn't expect this to happen, yet it happens sometimes.
joachim99@8 701 if ( mfi.m_bExistsInC && mfi.m_ageC==eNotThere )
joachim99@8 702 {
joachim99@8 703 mfi.m_ageC = (e_Age)age; ++age;
joachim99@8 704 mfi.m_bConflictingAges = true;
joachim99@8 705 }
joachim99@8 706 if ( mfi.m_bExistsInB && mfi.m_ageB==eNotThere )
joachim99@8 707 {
joachim99@8 708 mfi.m_ageB = (e_Age)age; ++age;
joachim99@8 709 mfi.m_bConflictingAges = true;
joachim99@8 710 }
joachim99@8 711 if ( mfi.m_bExistsInA && mfi.m_ageA==eNotThere )
joachim99@8 712 {
joachim99@8 713 mfi.m_ageA = (e_Age)age; ++age;
joachim99@8 714 mfi.m_bConflictingAges = true;
joachim99@8 715 }
joachim99@8 716
joachim99@8 717 if ( mfi.m_ageA != eOld && mfi.m_ageB != eOld && mfi.m_ageC != eOld )
joachim99@8 718 {
joachim99@8 719 if (mfi.m_ageA == eMiddle) mfi.m_ageA = eOld;
joachim99@8 720 if (mfi.m_ageB == eMiddle) mfi.m_ageB = eOld;
joachim99@8 721 if (mfi.m_ageC == eMiddle) mfi.m_ageC = eOld;
joachim99@8 722 }
joachim99@8 723 }
joachim99@8 724
joachim99@8 725 static QPixmap* s_pm_dir;
joachim99@8 726 static QPixmap* s_pm_file;
joachim99@8 727
joachim99@8 728 static void setOnePixmap( QListViewItem* pLVI, int col, e_Age eAge, bool bLink, bool bDir )
joachim99@8 729 {
joachim99@8 730 #include "xpm/equal.xpm"
joachim99@8 731 #include "xpm/not_equal.xpm"
joachim99@8 732 #include "xpm/not_everywhere.xpm"
joachim99@8 733 #include "xpm/not_there.xpm"
joachim99@8 734 #include "xpm/link_arrow.xpm"
joachim99@8 735
joachim99@8 736 static QPixmap pmLink( link_arrow );
joachim99@8 737
joachim99@8 738 static QPixmap pmDirLink( pixCombiner( *s_pm_dir, pmLink) );
joachim99@8 739 static QPixmap pmFileLink( pixCombiner( *s_pm_file, pmLink ) );
joachim99@8 740
joachim99@8 741 static QPixmap pmNotThere( not_there_pm );
joachim99@8 742
joachim99@8 743 static QPixmap pmNew( equal_pm );
joachim99@8 744 static QPixmap pmOld( not_equal_pm );
joachim99@8 745 static QPixmap pmMiddle( not_everywhere_pm );
joachim99@8 746
joachim99@8 747 static QPixmap pmNewLink( pixCombiner( pmNew, pmLink) );
joachim99@8 748 static QPixmap pmOldLink( pixCombiner( pmOld, pmLink) );
joachim99@8 749 static QPixmap pmMiddleLink( pixCombiner( pmMiddle, pmLink) );
joachim99@8 750
joachim99@8 751 static QPixmap pmNewDir( pixCombiner2( pmNew, *s_pm_dir) );
joachim99@8 752 static QPixmap pmMiddleDir( pixCombiner2( pmMiddle, *s_pm_dir) );
joachim99@8 753 static QPixmap pmOldDir( pixCombiner2( pmOld, *s_pm_dir) );
joachim99@8 754
joachim99@8 755 static QPixmap pmNewDirLink( pixCombiner( pmNewDir, pmLink) );
joachim99@8 756 static QPixmap pmMiddleDirLink( pixCombiner( pmMiddleDir, pmLink) );
joachim99@8 757 static QPixmap pmOldDirLink( pixCombiner( pmOldDir, pmLink) );
joachim99@8 758
joachim99@8 759 static QPixmap* ageToPm[]= { &pmNew, &pmMiddle, &pmOld, &pmNotThere, s_pm_file };
joachim99@8 760 static QPixmap* ageToPmLink[]= { &pmNewLink, &pmMiddleLink, &pmOldLink, &pmNotThere, &pmFileLink };
joachim99@8 761 static QPixmap* ageToPmDir[]= { &pmNewDir, &pmMiddleDir, &pmOldDir, &pmNotThere, s_pm_dir };
joachim99@8 762 static QPixmap* ageToPmDirLink[]={ &pmNewDirLink, &pmMiddleDirLink, &pmOldDirLink, &pmNotThere, &pmDirLink };
joachim99@8 763
joachim99@8 764 QPixmap** ppPm = bDir ? ( bLink ? ageToPmDirLink : ageToPmDir ):
joachim99@8 765 ( bLink ? ageToPmLink : ageToPm );
joachim99@8 766
joachim99@8 767 pLVI->setPixmap( col, *ppPm[eAge] );
joachim99@8 768 }
joachim99@8 769
joachim99@8 770 static void setPixmaps( MergeFileInfos& mfi, bool bCheckC )
joachim99@8 771 {
joachim99@8 772 setOnePixmap( mfi.m_pDMI, s_nameCol, eAgeEnd,
joachim99@8 773 mfi.m_bLinkA || mfi.m_bLinkB || mfi.m_bLinkC,
joachim99@8 774 mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC
joachim99@8 775 );
joachim99@8 776
joachim99@8 777 if ( mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC )
joachim99@8 778 {
joachim99@8 779 mfi.m_ageA=eNotThere;
joachim99@8 780 mfi.m_ageB=eNotThere;
joachim99@8 781 mfi.m_ageC=eNotThere;
joachim99@8 782 int age = eNew;
joachim99@8 783 if ( mfi.m_bExistsInC )
joachim99@8 784 {
joachim99@8 785 mfi.m_ageC = (e_Age)age;
joachim99@8 786 if (mfi.m_bEqualAC) mfi.m_ageA = (e_Age)age;
joachim99@8 787 if (mfi.m_bEqualBC) mfi.m_ageB = (e_Age)age;
joachim99@8 788 ++age;
joachim99@8 789 }
joachim99@8 790 if ( mfi.m_bExistsInB && mfi.m_ageB==eNotThere )
joachim99@8 791 {
joachim99@8 792 mfi.m_ageB = (e_Age)age;
joachim99@8 793 if (mfi.m_bEqualAB) mfi.m_ageA = (e_Age)age;
joachim99@8 794 ++age;
joachim99@8 795 }
joachim99@8 796 if ( mfi.m_bExistsInA && mfi.m_ageA==eNotThere )
joachim99@8 797 {
joachim99@8 798 mfi.m_ageA = (e_Age)age;
joachim99@8 799 }
joachim99@8 800 if ( mfi.m_ageA != eOld && mfi.m_ageB != eOld && mfi.m_ageC != eOld )
joachim99@8 801 {
joachim99@8 802 if (mfi.m_ageA == eMiddle) mfi.m_ageA = eOld;
joachim99@8 803 if (mfi.m_ageB == eMiddle) mfi.m_ageB = eOld;
joachim99@8 804 if (mfi.m_ageC == eMiddle) mfi.m_ageC = eOld;
joachim99@8 805 }
joachim99@8 806 }
joachim99@8 807
joachim99@8 808 setOnePixmap( mfi.m_pDMI, s_ACol, mfi.m_ageA, mfi.m_bLinkA, mfi.m_bDirA );
joachim99@8 809 setOnePixmap( mfi.m_pDMI, s_BCol, mfi.m_ageB, mfi.m_bLinkB, mfi.m_bDirB );
joachim99@8 810 if ( bCheckC )
joachim99@8 811 setOnePixmap( mfi.m_pDMI, s_CCol, mfi.m_ageC, mfi.m_bLinkC, mfi.m_bDirC );
joachim99@8 812 }
joachim99@8 813
joachim99@8 814 // Iterate through the complete tree. Start by specifying QListView::firstChild().
joachim99@8 815 static QListViewItem* treeIterator( QListViewItem* p, bool bVisitChildren=true )
joachim99@8 816 {
joachim99@8 817 if( p!=0 )
joachim99@8 818 {
joachim99@8 819 if ( bVisitChildren && p->firstChild() != 0 ) p = p->firstChild();
joachim99@8 820 else if ( p->nextSibling() !=0 ) p = p->nextSibling();
joachim99@8 821 else
joachim99@8 822 {
joachim99@8 823 p = p->parent();
joachim99@8 824 while ( p!=0 )
joachim99@8 825 {
joachim99@8 826 if( p->nextSibling()!=0 ) { p = p->nextSibling(); break; }
joachim99@8 827 else { p = p->parent(); }
joachim99@8 828 }
joachim99@8 829 }
joachim99@8 830 }
joachim99@8 831 return p;
joachim99@8 832 }
joachim99@8 833
joachim99@8 834 void DirectoryMergeWindow::prepareListView()
joachim99@8 835 {
joachim99@8 836 static bool bFirstTime = true;
joachim99@8 837 if (bFirstTime)
joachim99@8 838 {
joachim99@8 839 #include "xpm/file.xpm"
joachim99@8 840 #include "xpm/folder.xpm"
joachim99@8 841 s_pm_dir = new QPixmap( m_pIconLoader->loadIcon("folder", KIcon::Small ) );
joachim99@8 842 if (s_pm_dir->size()!=QSize(16,16))
joachim99@8 843 {
joachim99@8 844 delete s_pm_dir;
joachim99@8 845 s_pm_dir = new QPixmap( folder_pm );
joachim99@8 846 }
joachim99@8 847 s_pm_file= new QPixmap( file_pm );
joachim99@8 848 bFirstTime=false;
joachim99@8 849 }
joachim99@8 850
joachim99@8 851 clear();
joachim99@8 852
joachim99@8 853 setRootIsDecorated( true );
joachim99@8 854
joachim99@8 855 bool bCheckC = m_dirC.isValid();
joachim99@8 856
joachim99@8 857 std::map<QString, MergeFileInfos>::iterator j;
joachim99@8 858 int nrOfFiles = m_fileMergeMap.size();
joachim99@8 859 int currentIdx = 1;
joachim99@8 860 QTime t;
joachim99@8 861 t.start();
joachim99@8 862 for( j=m_fileMergeMap.begin(); j!=m_fileMergeMap.end(); ++j )
joachim99@8 863 {
joachim99@8 864 const QString& fileName = j->first;
joachim99@8 865 MergeFileInfos& mfi = j->second;
joachim99@8 866
joachim99@8 867 mfi.m_subPath = mfi.m_fileInfoA.exists() ? mfi.m_fileInfoA.filePath() :
joachim99@8 868 mfi.m_fileInfoB.exists() ? mfi.m_fileInfoB.filePath() :
joachim99@8 869 mfi.m_fileInfoC.exists() ? mfi.m_fileInfoC.filePath() : "";
joachim99@8 870
joachim99@8 871 g_pProgressDialog->setInformation(
joachim99@8 872 "Processing " + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles)
joachim99@8 873 +"\n" + fileName, double(currentIdx) / nrOfFiles, false );
joachim99@8 874 if ( g_pProgressDialog->wasCancelled() ) break;
joachim99@8 875 ++currentIdx;
joachim99@8 876
joachim99@8 877
joachim99@8 878 // The comparisons and calculations for each file take place here.
joachim99@8 879 compareFilesAndCalcAges( mfi );
joachim99@8 880
joachim99@8 881 bool bEqual = bCheckC ? mfi.m_bEqualAB && mfi.m_bEqualAC : mfi.m_bEqualAB;
joachim99@8 882 bool bDir = mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC;
joachim99@8 883
joachim99@8 884 if ( m_pOptions->m_bDmShowOnlyDeltas && !bDir && bEqual )
joachim99@8 885 continue;
joachim99@8 886
joachim99@8 887 // Get dirname from fileName: Search for "/" from end:
joachim99@8 888 int pos = fileName.findRev('/');
joachim99@8 889 QString dirPart;
joachim99@8 890 QString filePart;
joachim99@8 891 if (pos==-1)
joachim99@8 892 {
joachim99@8 893 // Top dir
joachim99@8 894 filePart = fileName;
joachim99@8 895 }
joachim99@8 896 else
joachim99@8 897 {
joachim99@8 898 dirPart = fileName.left(pos);
joachim99@8 899 filePart = fileName.mid(pos+1);
joachim99@8 900 }
joachim99@8 901
joachim99@8 902 if ( dirPart.isEmpty() ) // Top level
joachim99@8 903 {
joachim99@8 904 new DirMergeItem( this, filePart, &mfi );
joachim99@8 905 }
joachim99@8 906 else
joachim99@8 907 {
joachim99@8 908 MergeFileInfos& dirMfi = m_fileMergeMap[dirPart]; // parent
joachim99@8 909 assert(dirMfi.m_pDMI!=0);
joachim99@8 910 new DirMergeItem( dirMfi.m_pDMI, filePart, &mfi );
joachim99@8 911 mfi.m_pParent = &dirMfi;
joachim99@8 912
joachim99@8 913 if ( !bEqual ) // Set all parents to "not equal"
joachim99@8 914 {
joachim99@8 915 MergeFileInfos* p = mfi.m_pParent;
joachim99@8 916 while(p!=0)
joachim99@8 917 {
joachim99@8 918 bool bChange = false;
joachim99@8 919 if ( !mfi.m_bEqualAB && p->m_bEqualAB ){ p->m_bEqualAB = false; bChange=true; }
joachim99@8 920 if ( !mfi.m_bEqualAC && p->m_bEqualAC ){ p->m_bEqualAC = false; bChange=true; }
joachim99@8 921 if ( !mfi.m_bEqualBC && p->m_bEqualBC ){ p->m_bEqualBC = false; bChange=true; }
joachim99@8 922
joachim99@8 923 if ( bChange )
joachim99@8 924 setPixmaps( *p, bCheckC );
joachim99@8 925 else
joachim99@8 926 break;
joachim99@8 927
joachim99@8 928 p = p->m_pParent;
joachim99@8 929 }
joachim99@8 930 }
joachim99@8 931 }
joachim99@8 932
joachim99@8 933 setPixmaps( mfi, bCheckC );
joachim99@8 934 }
joachim99@8 935
joachim99@8 936 if ( m_pOptions->m_bDmShowOnlyDeltas )
joachim99@8 937 {
joachim99@8 938 // Remove all equals. (Search tree depth first)
joachim99@8 939 QListViewItem* p = firstChild();
joachim99@8 940 while( p!=0 && firstChild() != 0 )
joachim99@8 941 {
joachim99@8 942 QListViewItem* pParent = p->parent();
joachim99@8 943 QListViewItem* pNextSibling = p->nextSibling();
joachim99@8 944
joachim99@8 945 DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
joachim99@8 946 bool bDirEqual = bCheckC ? pDMI->m_pMFI->m_bEqualAB && pDMI->m_pMFI->m_bEqualAC
joachim99@8 947 : pDMI->m_pMFI->m_bEqualAB;
joachim99@8 948 if ( pDMI!=0 && pDMI->m_pMFI->m_bDirA && bDirEqual )
joachim99@8 949 {
joachim99@8 950 delete p;
joachim99@8 951 p=0;
joachim99@8 952 }
joachim99@8 953
joachim99@8 954 if ( p!=0 && p->firstChild() != 0 ) p = p->firstChild();
joachim99@8 955 else if ( pNextSibling!=0 ) p = pNextSibling;
joachim99@8 956 else
joachim99@8 957 {
joachim99@8 958 p=pParent;
joachim99@8 959 while ( p!=0 )
joachim99@8 960 {
joachim99@8 961 if( p->nextSibling()!=0 ) { p = p->nextSibling(); break; }
joachim99@8 962 else { p = p->parent(); }
joachim99@8 963 }
joachim99@8 964 }
joachim99@8 965 }
joachim99@8 966 }
joachim99@8 967 }
joachim99@8 968
joachim99@8 969 static bool conflictingFileTypes(MergeFileInfos& mfi)
joachim99@8 970 {
joachim99@8 971 // Now check if file/dir-types fit.
joachim99@8 972 if ( mfi.m_bLinkA || mfi.m_bLinkB || mfi.m_bLinkC )
joachim99@8 973 {
joachim99@8 974 if ( mfi.m_bExistsInA && ! mfi.m_bLinkA ||
joachim99@8 975 mfi.m_bExistsInB && ! mfi.m_bLinkB ||
joachim99@8 976 mfi.m_bExistsInC && ! mfi.m_bLinkC )
joachim99@8 977 {
joachim99@8 978 return true;
joachim99@8 979 }
joachim99@8 980 }
joachim99@8 981
joachim99@8 982 if ( mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC )
joachim99@8 983 {
joachim99@8 984 if ( mfi.m_bExistsInA && ! mfi.m_bDirA ||
joachim99@8 985 mfi.m_bExistsInB && ! mfi.m_bDirB ||
joachim99@8 986 mfi.m_bExistsInC && ! mfi.m_bDirC )
joachim99@8 987 {
joachim99@8 988 return true;
joachim99@8 989 }
joachim99@8 990 }
joachim99@8 991 return false;
joachim99@8 992 }
joachim99@8 993
joachim99@8 994 void DirectoryMergeWindow::calcSuggestedOperation( MergeFileInfos& mfi, e_MergeOperation eDefaultMergeOp )
joachim99@8 995 {
joachim99@8 996 bool bCheckC = m_dirC.isValid();
joachim99@8 997 bool bCopyNewer = m_pOptions->m_bDmCopyNewer;
joachim99@8 998
joachim99@8 999 if ( eDefaultMergeOp == eMergeABCToDest && !bCheckC ) { eDefaultMergeOp = eMergeABToDest; }
joachim99@8 1000 if ( eDefaultMergeOp == eMergeToAB && bCheckC ) { assert(false); }
joachim99@8 1001
joachim99@8 1002 if ( eDefaultMergeOp == eMergeToA || eDefaultMergeOp == eMergeToB ||
joachim99@8 1003 eDefaultMergeOp == eMergeABCToDest || eDefaultMergeOp == eMergeABToDest || eDefaultMergeOp == eMergeToAB )
joachim99@8 1004 {
joachim99@8 1005 if ( !bCheckC )
joachim99@8 1006 {
joachim99@8 1007 if ( mfi.m_bEqualAB )
joachim99@8 1008 {
joachim99@8 1009 mfi.setMergeOperation( eNoOperation ); // All is well, nothing to do.
joachim99@8 1010 }
joachim99@8 1011 else if ( mfi.m_bExistsInA && mfi.m_bExistsInB )
joachim99@8 1012 {
joachim99@8 1013 if ( !bCopyNewer || mfi.m_bDirA )
joachim99@8 1014 mfi.setMergeOperation( eDefaultMergeOp );
joachim99@8 1015 else if ( bCopyNewer && mfi.m_bConflictingAges )
joachim99@8 1016 {
joachim99@8 1017 mfi.setMergeOperation( eConflictingAges );
joachim99@8 1018 }
joachim99@8 1019 else
joachim99@8 1020 {
joachim99@8 1021 if ( mfi.m_ageA == eNew )
joachim99@8 1022 mfi.setMergeOperation( eDefaultMergeOp == eMergeToAB ? eCopyAToB : eCopyAToDest );
joachim99@8 1023 else
joachim99@8 1024 mfi.setMergeOperation( eDefaultMergeOp == eMergeToAB ? eCopyBToA : eCopyBToDest );
joachim99@8 1025 }
joachim99@8 1026 }
joachim99@8 1027 else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB )
joachim99@8 1028 {
joachim99@8 1029 if ( eDefaultMergeOp==eMergeABToDest ) mfi.setMergeOperation( eCopyBToDest );
joachim99@8 1030 else if ( eDefaultMergeOp==eMergeToB ) mfi.setMergeOperation( eNoOperation );
joachim99@8 1031 else mfi.setMergeOperation( eCopyBToA );
joachim99@8 1032 }
joachim99@8 1033 else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB )
joachim99@8 1034 {
joachim99@8 1035 if ( eDefaultMergeOp==eMergeABToDest ) mfi.setMergeOperation( eCopyAToDest );
joachim99@8 1036 else if ( eDefaultMergeOp==eMergeToA ) mfi.setMergeOperation( eNoOperation );
joachim99@8 1037 else mfi.setMergeOperation( eCopyAToB );
joachim99@8 1038 }
joachim99@8 1039 else //if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB )
joachim99@8 1040 {
joachim99@8 1041 mfi.setMergeOperation( eNoOperation ); assert(false);
joachim99@8 1042 }
joachim99@8 1043 }
joachim99@8 1044 else
joachim99@8 1045 {
joachim99@8 1046 if ( mfi.m_bEqualAB && mfi.m_bEqualAC )
joachim99@8 1047 {
joachim99@8 1048 mfi.setMergeOperation( eCopyCToDest );
joachim99@8 1049 }
joachim99@8 1050 else if ( mfi.m_bExistsInA && mfi.m_bExistsInB && mfi.m_bExistsInC)
joachim99@8 1051 {
joachim99@8 1052 if ( mfi.m_bEqualAB )
joachim99@8 1053 mfi.setMergeOperation( eCopyCToDest );
joachim99@8 1054 else if ( mfi.m_bEqualAC )
joachim99@8 1055 mfi.setMergeOperation( eCopyBToDest );
joachim99@8 1056 else if ( mfi.m_bEqualBC )
joachim99@8 1057 mfi.setMergeOperation( eCopyCToDest );
joachim99@8 1058 else
joachim99@8 1059 mfi.setMergeOperation( eMergeABCToDest );
joachim99@8 1060 }
joachim99@8 1061 else if ( mfi.m_bExistsInA && mfi.m_bExistsInB && !mfi.m_bExistsInC )
joachim99@8 1062 {
joachim99@8 1063 if ( mfi.m_bEqualAB )
joachim99@8 1064 mfi.setMergeOperation( eDeleteFromDest );
joachim99@8 1065 else
joachim99@8 1066 mfi.setMergeOperation( eCopyBToDest );
joachim99@8 1067 }
joachim99@8 1068 else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB && mfi.m_bExistsInC )
joachim99@8 1069 {
joachim99@8 1070 if ( mfi.m_bEqualAC )
joachim99@8 1071 mfi.setMergeOperation( eDeleteFromDest );
joachim99@8 1072 else
joachim99@8 1073 mfi.setMergeOperation( eCopyCToDest );
joachim99@8 1074 }
joachim99@8 1075 else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB && mfi.m_bExistsInC )
joachim99@8 1076 {
joachim99@8 1077 if ( mfi.m_bEqualBC )
joachim99@8 1078 mfi.setMergeOperation( eCopyCToDest );
joachim99@8 1079 else
joachim99@8 1080 mfi.setMergeOperation( eMergeABCToDest );
joachim99@8 1081 }
joachim99@8 1082 else if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB && mfi.m_bExistsInC )
joachim99@8 1083 {
joachim99@8 1084 mfi.setMergeOperation( eCopyCToDest );
joachim99@8 1085 }
joachim99@8 1086 else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB && !mfi.m_bExistsInC )
joachim99@8 1087 {
joachim99@8 1088 mfi.setMergeOperation( eCopyBToDest );
joachim99@8 1089 }
joachim99@8 1090 else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB && !mfi.m_bExistsInC)
joachim99@8 1091 {
joachim99@8 1092 mfi.setMergeOperation( eDeleteFromDest );
joachim99@8 1093 }
joachim99@8 1094 else //if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB && !mfi.m_bExistsInC )
joachim99@8 1095 {
joachim99@8 1096 mfi.setMergeOperation( eNoOperation ); assert(false);
joachim99@8 1097 }
joachim99@8 1098 }
joachim99@8 1099
joachim99@8 1100 // Now check if file/dir-types fit.
joachim99@8 1101 if ( conflictingFileTypes(mfi) )
joachim99@8 1102 {
joachim99@8 1103 mfi.setMergeOperation( eConflictingFileTypes );
joachim99@8 1104 }
joachim99@8 1105 }
joachim99@8 1106 else
joachim99@8 1107 {
joachim99@8 1108 e_MergeOperation eMO = eDefaultMergeOp;
joachim99@8 1109 switch ( eDefaultMergeOp )
joachim99@8 1110 {
joachim99@8 1111 case eConflictingFileTypes:
joachim99@8 1112 case eConflictingAges:
joachim99@8 1113 case eDeleteA:
joachim99@8 1114 case eDeleteB:
joachim99@8 1115 case eDeleteAB:
joachim99@8 1116 case eDeleteFromDest:
joachim99@8 1117 case eNoOperation: break;
joachim99@8 1118 case eCopyAToB: if ( !mfi.m_bExistsInA ) { eMO = eDeleteB; } break;
joachim99@8 1119 case eCopyBToA: if ( !mfi.m_bExistsInB ) { eMO = eDeleteA; } break;
joachim99@8 1120 case eCopyAToDest: if ( !mfi.m_bExistsInA ) { eMO = eDeleteFromDest; } break;
joachim99@8 1121 case eCopyBToDest: if ( !mfi.m_bExistsInB ) { eMO = eDeleteFromDest; } break;
joachim99@8 1122 case eCopyCToDest: if ( !mfi.m_bExistsInC ) { eMO = eDeleteFromDest; } break;
joachim99@8 1123
joachim99@8 1124 case eMergeToA:
joachim99@8 1125 case eMergeToB:
joachim99@8 1126 case eMergeToAB:
joachim99@8 1127 case eMergeABCToDest:
joachim99@8 1128 case eMergeABToDest:
joachim99@8 1129 default:
joachim99@8 1130 assert(false);
joachim99@8 1131 }
joachim99@8 1132 mfi.setMergeOperation( eMO );
joachim99@8 1133 }
joachim99@8 1134 }
joachim99@8 1135
joachim99@8 1136 void DirectoryMergeWindow::onDoubleClick( QListViewItem* lvi )
joachim99@8 1137 {
joachim99@8 1138 if (lvi==0) return;
joachim99@8 1139
joachim99@8 1140 if ( m_bDirectoryMerge )
joachim99@8 1141 mergeCurrentFile();
joachim99@8 1142 else
joachim99@8 1143 compareCurrentFile();
joachim99@8 1144 }
joachim99@8 1145
joachim99@8 1146 void DirectoryMergeWindow::onSelectionChanged( QListViewItem* lvi )
joachim99@8 1147 {
joachim99@8 1148 if ( lvi==0 ) return;
joachim99@8 1149
joachim99@8 1150 DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi);
joachim99@8 1151
joachim99@8 1152 MergeFileInfos& mfi = *pDMI->m_pMFI;
joachim99@8 1153 assert( mfi.m_pDMI==pDMI );
joachim99@8 1154
joachim99@8 1155 m_pDirectoryMergeInfo->setInfo( m_dirA, m_dirB, m_dirC, m_dirDestInternal, mfi );
joachim99@8 1156 }
joachim99@8 1157
joachim99@8 1158 void DirectoryMergeWindow::onClick( QListViewItem* lvi, const QPoint& p, int c )
joachim99@8 1159 {
joachim99@8 1160 if ( lvi==0 ) return;
joachim99@8 1161
joachim99@8 1162 DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi);
joachim99@8 1163
joachim99@8 1164 MergeFileInfos& mfi = *pDMI->m_pMFI;
joachim99@8 1165 assert( mfi.m_pDMI==pDMI );
joachim99@8 1166
joachim99@8 1167 if ( c!=s_OpCol ) return;
joachim99@8 1168
joachim99@8 1169 bool bThreeDirs = m_dirC.isValid();
joachim99@8 1170
joachim99@8 1171 //bool bImmediate = (button==Qt::LeftButton);
joachim99@8 1172
joachim99@8 1173 KPopupMenu m(this);
joachim99@8 1174 //if (bImmediate ) m.insertItem("Immediate Mode", eTitleId );
joachim99@8 1175 //else m.insertItem("Postponed Mode", eTitleId );
joachim99@8 1176 //m.setItemEnabled ( eTitleId, false );
joachim99@8 1177 if ( bThreeDirs )
joachim99@8 1178 {
joachim99@8 1179 m.insertItem("Do nothing", eNoOperation );
joachim99@8 1180 int count=0;
joachim99@8 1181 if ( mfi.m_bExistsInA ) { m.insertItem("A", eCopyAToDest ); ++count; }
joachim99@8 1182 if ( mfi.m_bExistsInB ) { m.insertItem("B", eCopyBToDest ); ++count; }
joachim99@8 1183 if ( mfi.m_bExistsInC ) { m.insertItem("C", eCopyCToDest ); ++count; }
joachim99@8 1184 if ( !conflictingFileTypes(mfi) && count>1 ) m.insertItem("Merge", eMergeABCToDest );
joachim99@8 1185 m.insertItem("Delete (if exists)", eDeleteFromDest );
joachim99@8 1186 }
joachim99@8 1187 else if ( m_bSyncMode )
joachim99@8 1188 {
joachim99@8 1189 m.insertItem("Do nothing", eNoOperation );
joachim99@8 1190 if ( mfi.m_bExistsInA ) m.insertItem("Copy A to B", eCopyAToB );
joachim99@8 1191 if ( mfi.m_bExistsInB ) m.insertItem("Copy B to A", eCopyBToA );
joachim99@8 1192 if ( mfi.m_bExistsInA ) m.insertItem("Delete A", eDeleteA );
joachim99@8 1193 if ( mfi.m_bExistsInB ) m.insertItem("Delete B", eDeleteB );
joachim99@8 1194 if ( mfi.m_bExistsInA && mfi.m_bExistsInB )
joachim99@8 1195 {
joachim99@8 1196 m.insertItem("Delete A and B", eDeleteAB );
joachim99@8 1197 if ( !conflictingFileTypes(mfi))
joachim99@8 1198 {
joachim99@8 1199 m.insertItem("Merge to A", eMergeToA );
joachim99@8 1200 m.insertItem("Merge to B", eMergeToB );
joachim99@8 1201 m.insertItem("Merge to A and B", eMergeToAB );
joachim99@8 1202 }
joachim99@8 1203 }
joachim99@8 1204 }
joachim99@8 1205 else
joachim99@8 1206 {
joachim99@8 1207 m.insertItem("Do nothing", eNoOperation );
joachim99@8 1208 if ( mfi.m_bExistsInA ) m.insertItem("A", eCopyAToDest );
joachim99@8 1209 if ( mfi.m_bExistsInB ) m.insertItem("B", eCopyBToDest );
joachim99@8 1210 if ( mfi.m_bExistsInA && mfi.m_bExistsInB && !conflictingFileTypes(mfi) )
joachim99@8 1211 m.insertItem("Merge", eMergeABToDest );
joachim99@8 1212 m.insertItem("Delete (if exists)", eDeleteFromDest );
joachim99@8 1213 }
joachim99@8 1214
joachim99@8 1215 int result = m.exec( p );
joachim99@8 1216 if (result>=0 )
joachim99@8 1217 mfi.setMergeOperation( (e_MergeOperation)result );
joachim99@8 1218 }
joachim99@8 1219
joachim99@8 1220 // Since Qt 2.3.0 doesn't allow the specification of a compare operator, this trick emulates it.
joachim99@8 1221 #if QT_VERSION==230
joachim99@8 1222 #define DIRSORT(x) ( pMFI->m_bDirA ? " " : "" )+x
joachim99@8 1223 #else
joachim99@8 1224 #define DIRSORT(x) x
joachim99@8 1225 #endif
joachim99@8 1226
joachim99@8 1227 DirMergeItem::DirMergeItem( QListView* pParent, const QString& fileName, MergeFileInfos* pMFI )
joachim99@8 1228 : QListViewItem( pParent, DIRSORT( fileName ), "","","", "To do." )
joachim99@8 1229 {
joachim99@8 1230 pMFI->m_pDMI = this;
joachim99@8 1231 m_pMFI = pMFI;
joachim99@8 1232 }
joachim99@8 1233
joachim99@8 1234 DirMergeItem::DirMergeItem( DirMergeItem* pParent, const QString& fileName, MergeFileInfos* pMFI )
joachim99@8 1235 : QListViewItem( pParent, DIRSORT( fileName ), "","","", "To do." )
joachim99@8 1236 {
joachim99@8 1237 pMFI->m_pDMI = this;
joachim99@8 1238 m_pMFI = pMFI;
joachim99@8 1239 }
joachim99@8 1240
joachim99@8 1241 DirMergeItem::~DirMergeItem()
joachim99@8 1242 {
joachim99@8 1243 m_pMFI->m_pDMI = 0;
joachim99@8 1244 }
joachim99@8 1245
joachim99@8 1246 void MergeFileInfos::setMergeOperation( e_MergeOperation eMOp )
joachim99@8 1247 {
joachim99@8 1248 m_eMergeOperation = eMOp;
joachim99@8 1249 const char* s=0;
joachim99@8 1250 bool bDir = m_bDirA || m_bDirB || m_bDirC;
joachim99@8 1251 if( m_pDMI!=0 )
joachim99@8 1252 {
joachim99@8 1253 switch( m_eMergeOperation )
joachim99@8 1254 {
joachim99@8 1255 case eNoOperation: s=""; m_pDMI->setText(s_OpCol,""); break;
joachim99@8 1256 case eCopyAToB: s="Copy A to B"; break;
joachim99@8 1257 case eCopyBToA: s="Copy B to A"; break;
joachim99@8 1258 case eDeleteA: s="Delete A"; break;
joachim99@8 1259 case eDeleteB: s="Delete B"; break;
joachim99@8 1260 case eDeleteAB: s="Delete A and B"; break;
joachim99@8 1261 case eMergeToA: s="Merge to A"; break;
joachim99@8 1262 case eMergeToB: s="Merge to B"; break;
joachim99@8 1263 case eMergeToAB: s="Merge to A and B"; break;
joachim99@8 1264 case eCopyAToDest: s="A"; break;
joachim99@8 1265 case eCopyBToDest: s="B"; break;
joachim99@8 1266 case eCopyCToDest: s="C"; break;
joachim99@8 1267 case eDeleteFromDest: s="Delete (if exists)"; break;
joachim99@8 1268 case eMergeABCToDest: s= bDir ? "Merge" : "Merge (manual)"; break;
joachim99@8 1269 case eMergeABToDest: s= bDir ? "Merge" : "Merge (manual)"; break;
joachim99@8 1270 case eConflictingFileTypes: s="Error: Conflicting File Types"; break;
joachim99@8 1271 case eConflictingAges: s="Error: Dates are equal but files are not."; break;
joachim99@8 1272 default: assert(false); break;
joachim99@8 1273 }
joachim99@8 1274 m_pDMI->setText(s_OpCol,s);
joachim99@8 1275
joachim99@8 1276 e_MergeOperation eChildrenMergeOp = m_eMergeOperation;
joachim99@8 1277 if ( eChildrenMergeOp == eConflictingFileTypes ) eChildrenMergeOp = eMergeABCToDest;
joachim99@8 1278 QListViewItem* p = m_pDMI->firstChild();
joachim99@8 1279 while ( p!=0 )
joachim99@8 1280 {
joachim99@8 1281 DirMergeItem* pDMI = static_cast<DirMergeItem*>( p );
joachim99@8 1282 DirectoryMergeWindow* pDMW = static_cast<DirectoryMergeWindow*>( p->listView() );
joachim99@8 1283 pDMW->calcSuggestedOperation( *pDMI->m_pMFI, eChildrenMergeOp );
joachim99@8 1284 p = p->nextSibling();
joachim99@8 1285 }
joachim99@8 1286 }
joachim99@8 1287 }
joachim99@8 1288
joachim99@8 1289 void DirectoryMergeWindow::compareCurrentFile()
joachim99@8 1290 {
joachim99@8 1291 if (!canContinue()) return;
joachim99@8 1292
joachim99@8 1293 if ( m_bRealMergeStarted )
joachim99@8 1294 {
joachim99@8 1295 KMessageBox::sorry(this,"This operation is currently not possible.","KDiff3");
joachim99@8 1296 return;
joachim99@8 1297 }
joachim99@8 1298
joachim99@8 1299 DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
joachim99@8 1300 if ( pDMI != 0 )
joachim99@8 1301 {
joachim99@8 1302 MergeFileInfos& mfi = *pDMI->m_pMFI;
joachim99@8 1303 if ( !(mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC) )
joachim99@8 1304 {
joachim99@8 1305 emit startDiffMerge(
joachim99@8 1306 mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : QString(""),
joachim99@8 1307 mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : QString(""),
joachim99@8 1308 mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : QString(""),
joachim99@8 1309 "",
joachim99@8 1310 "","",""
joachim99@8 1311 );
joachim99@8 1312 }
joachim99@8 1313 }
joachim99@8 1314 emit updateAvailabilities();
joachim99@8 1315 }
joachim99@8 1316
joachim99@8 1317 void DirectoryMergeWindow::mergeCurrentFile()
joachim99@8 1318 {
joachim99@8 1319 if (!canContinue()) return;
joachim99@8 1320
joachim99@8 1321 if ( m_bRealMergeStarted )
joachim99@8 1322 {
joachim99@8 1323 KMessageBox::sorry(this,"This operation is currently not possible because diff merge currently runs.","KDiff3");
joachim99@8 1324 return;
joachim99@8 1325 }
joachim99@8 1326
joachim99@8 1327 if ( isFileSelected() )
joachim99@8 1328 {
joachim99@8 1329 DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
joachim99@8 1330 if ( pDMI != 0 )
joachim99@8 1331 {
joachim99@8 1332 MergeFileInfos& mfi = *pDMI->m_pMFI;
joachim99@8 1333 m_bSingleFileOperationStarted = true;
joachim99@8 1334 emit startDiffMerge(
joachim99@8 1335 mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : QString(""),
joachim99@8 1336 mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : QString(""),
joachim99@8 1337 mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : QString(""),
joachim99@8 1338 fullNameDest(mfi),
joachim99@8 1339 "","",""
joachim99@8 1340 );
joachim99@8 1341 m_pCurrentItemForOperation = pDMI;
joachim99@8 1342 m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
joachim99@8 1343 }
joachim99@8 1344 }
joachim99@8 1345 emit updateAvailabilities();
joachim99@8 1346 }
joachim99@8 1347
joachim99@8 1348
joachim99@8 1349 bool DirectoryMergeWindow::isFileSelected()
joachim99@8 1350 {
joachim99@8 1351 DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
joachim99@8 1352 if ( pDMI != 0 )
joachim99@8 1353 {
joachim99@8 1354 MergeFileInfos& mfi = *pDMI->m_pMFI;
joachim99@8 1355 return ! (mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC || conflictingFileTypes(mfi) );
joachim99@8 1356 }
joachim99@8 1357 return false;
joachim99@8 1358 }
joachim99@8 1359
joachim99@8 1360 void DirectoryMergeWindow::mergeResultSaved(const QString& fileName)
joachim99@8 1361 {
joachim99@8 1362 m_bSingleFileOperationStarted = false;
joachim99@8 1363 if ( m_pCurrentItemForOperation!=0 && m_pCurrentItemForOperation->m_pMFI==0 )
joachim99@8 1364 {
joachim99@8 1365 KMessageBox::error( this, "This should never happen: \n\nmergeResultSaved: m_pMFI=0\n\nIf you know how to reproduce this, please contact the program author.","Program Error" );
joachim99@8 1366 return;
joachim99@8 1367 }
joachim99@8 1368 if ( m_pCurrentItemForOperation!=0 && fileName == fullNameDest(*m_pCurrentItemForOperation->m_pMFI) )
joachim99@8 1369 {
joachim99@8 1370 if ( m_pCurrentItemForOperation->m_pMFI->m_eMergeOperation==eMergeToAB )
joachim99@8 1371 {
joachim99@8 1372 MergeFileInfos& mfi = *m_pCurrentItemForOperation->m_pMFI;
joachim99@8 1373 bool bSuccess = copyFLD( fullNameB(mfi), fullNameA(mfi) );
joachim99@8 1374 if (!bSuccess)
joachim99@8 1375 {
joachim99@8 1376 KMessageBox::error(this, i18n("An error occurred while copying.\n"), "KDiff3: Error" );
joachim99@8 1377 m_pStatusInfo->setCaption("KDiff3: Merge-Error");
joachim99@8 1378 m_pStatusInfo->show();
joachim99@8 1379 if ( m_pStatusInfo->firstChild()!=0 )
joachim99@8 1380 m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() );
joachim99@8 1381 m_bError = true;
joachim99@8 1382 m_pCurrentItemForOperation->setText( s_OpStatusCol, "Error." );
joachim99@8 1383 mfi.m_eMergeOperation = eCopyBToA;
joachim99@8 1384 return;
joachim99@8 1385 }
joachim99@8 1386 }
joachim99@8 1387 m_pCurrentItemForOperation->setText( s_OpStatusCol, "Done." );
joachim99@8 1388 m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
joachim99@8 1389 }
joachim99@8 1390
joachim99@8 1391 emit updateAvailabilities();
joachim99@8 1392 }
joachim99@8 1393
joachim99@8 1394 bool DirectoryMergeWindow::canContinue()
joachim99@8 1395 {
joachim99@8 1396 bool bCanContinue=false;
joachim99@8 1397 checkIfCanContinue( &bCanContinue );
joachim99@8 1398 if ( bCanContinue && !m_bError )
joachim99@8 1399 {
joachim99@8 1400 if ( m_bRealMergeStarted && m_pCurrentItemForOperation!=0 && ! m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
joachim99@8 1401 {
joachim99@8 1402 m_pCurrentItemForOperation->setText( s_OpStatusCol, "Not saved." );
joachim99@8 1403 m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
joachim99@8 1404 }
joachim99@8 1405 }
joachim99@8 1406 return bCanContinue;
joachim99@8 1407 }
joachim99@8 1408
joachim99@8 1409 void DirectoryMergeWindow::mergeContinue()
joachim99@8 1410 {
joachim99@8 1411 if ( ! canContinue() ) return;
joachim99@8 1412
joachim99@8 1413 m_bSingleFileOperationStarted = false;
joachim99@8 1414
joachim99@8 1415 int nrOfItems = 0;
joachim99@8 1416 int nrOfCompletedItems = 0;
joachim99@8 1417 int nrOfCompletedSimItems = 0;
joachim99@8 1418
joachim99@8 1419 if ( !m_bSimulatedMergeStarted && !m_bRealMergeStarted )
joachim99@8 1420 {
joachim99@8 1421 // First check if an invalid merge operations exist.
joachim99@8 1422 for( QListViewItem* p=firstChild(); p!=0; p = treeIterator( p ) )
joachim99@8 1423 {
joachim99@8 1424 DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
joachim99@8 1425 if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingFileTypes )
joachim99@8 1426 {
joachim99@8 1427 ensureItemVisible( pDMI );
joachim99@8 1428 setSelected( pDMI, true );
joachim99@8 1429 KMessageBox::error(this, i18n("The highlighted item has a different type in the different directories. Select what to do."), "Error");
joachim99@8 1430 return;
joachim99@8 1431 }
joachim99@8 1432 if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingAges )
joachim99@8 1433 {
joachim99@8 1434 ensureItemVisible( pDMI );
joachim99@8 1435 setSelected( pDMI, true );
joachim99@8 1436 KMessageBox::error(this, i18n("The modification dates of the file are equal but the files are not. Select what to do."), "Error");
joachim99@8 1437 return;
joachim99@8 1438 }
joachim99@8 1439 ++nrOfItems;
joachim99@8 1440 if ( pDMI->m_pMFI->m_bSimOpComplete )
joachim99@8 1441 ++nrOfCompletedSimItems;
joachim99@8 1442 if ( pDMI->m_pMFI->m_bOperationComplete )
joachim99@8 1443 ++nrOfCompletedItems;
joachim99@8 1444 }
joachim99@8 1445
joachim99@8 1446 int status = KMessageBox::warningYesNoCancel(this,
joachim99@8 1447 i18n("The merge is about to begin.\n\n"
joachim99@8 1448 "Choose \"Do it\" if you have read the instructions and know what you are doing.\n"
joachim99@8 1449 "Choosing \"Simulate it\" will tell you what would happen.\n\n"
joachim99@8 1450 "Be aware that this program still has beta status "
joachim99@8 1451 "and there is NO WARRANTY whatsoever! Make backups of your vital data!"),
joachim99@8 1452 i18n("KDiff3: Starting the Merge"), i18n("Do it"), i18n("Simulate it") );
joachim99@8 1453 if (status==KMessageBox::Yes) m_bRealMergeStarted = true;
joachim99@8 1454 else if (status==KMessageBox::No ) m_bSimulatedMergeStarted = true;
joachim99@8 1455 else return;
joachim99@8 1456
joachim99@8 1457 m_pStatusInfo->hide();
joachim99@8 1458 m_pStatusInfo->clear();
joachim99@8 1459 }
joachim99@8 1460
joachim99@8 1461 bool bContinueWithCurrentItem = false;
joachim99@8 1462 bool bSkipItem = false;
joachim99@8 1463 if ( m_bError && m_pCurrentItemForOperation!=0 )
joachim99@8 1464 {
joachim99@8 1465 int status = KMessageBox::warningYesNoCancel(this,
joachim99@8 1466 i18n("There was an error in the last step.\n"
joachim99@8 1467 "Do you want to continue with the item that caused the error or do you want to skip this item?"),
joachim99@8 1468 i18n("KDiff3: Continue merge after an error"), i18n("Continue with last item"), i18n("Skip item") );
joachim99@8 1469 if (status==KMessageBox::Yes) bContinueWithCurrentItem = true;
joachim99@8 1470 else if (status==KMessageBox::No ) bSkipItem = true;
joachim99@8 1471 else return;
joachim99@8 1472 m_bError = false;
joachim99@8 1473 }
joachim99@8 1474
joachim99@8 1475 g_pProgressDialog->start();
joachim99@8 1476
joachim99@8 1477 bool bSuccess = true;
joachim99@8 1478 bool bSingleFileMerge = false;
joachim99@8 1479 bool bSim = m_bSimulatedMergeStarted;
joachim99@8 1480 while( bSuccess )
joachim99@8 1481 {
joachim99@8 1482 if ( m_pCurrentItemForOperation!=0 && !bContinueWithCurrentItem )
joachim99@8 1483 {
joachim99@8 1484 if ( bSim )
joachim99@8 1485 {
joachim99@8 1486 if( m_pCurrentItemForOperation->firstChild()==0 )
joachim99@8 1487 {
joachim99@8 1488 m_pCurrentItemForOperation->m_pMFI->m_bSimOpComplete = true;
joachim99@8 1489 }
joachim99@8 1490 }
joachim99@8 1491 else
joachim99@8 1492 {
joachim99@8 1493 if( m_pCurrentItemForOperation->firstChild()==0 )
joachim99@8 1494 {
joachim99@8 1495 if( !m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
joachim99@8 1496 {
joachim99@8 1497 m_pCurrentItemForOperation->setText( s_OpStatusCol, bSkipItem ? "Skipped." : "Done." );
joachim99@8 1498 m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
joachim99@8 1499 bSkipItem = false;
joachim99@8 1500 }
joachim99@8 1501 }
joachim99@8 1502 else
joachim99@8 1503 {
joachim99@8 1504 m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
joachim99@8 1505 }
joachim99@8 1506 }
joachim99@8 1507 }
joachim99@8 1508
joachim99@8 1509 if ( m_pCurrentItemForOperation==0 )
joachim99@8 1510 {
joachim99@8 1511 m_pCurrentItemForOperation = static_cast<DirMergeItem*>( firstChild() );
joachim99@8 1512 }
joachim99@8 1513 else
joachim99@8 1514 {
joachim99@8 1515 if ( ! bContinueWithCurrentItem )
joachim99@8 1516 {
joachim99@8 1517 // Depth first
joachim99@8 1518 QListViewItem* pNextItem = m_pCurrentItemForOperation->firstChild();
joachim99@8 1519 QListViewItem* pCurrentItem = m_pCurrentItemForOperation;
joachim99@8 1520 while( pCurrentItem!=0 && pNextItem==0 )
joachim99@8 1521 {
joachim99@8 1522 // Find an item on this level that hasn't been operated yet. (Always start at beginning.)
joachim99@8 1523 if ( pCurrentItem->parent()==0 )
joachim99@8 1524 pNextItem = firstChild();
joachim99@8 1525 else
joachim99@8 1526 pNextItem = pCurrentItem->parent()->firstChild();
joachim99@8 1527
joachim99@8 1528 while( pNextItem!=0 && ( static_cast<DirMergeItem*>(pNextItem)->m_pMFI->m_bOperationComplete ||
joachim99@8 1529 ( bSim && static_cast<DirMergeItem*>(pNextItem)->m_pMFI->m_bSimOpComplete ) ) )
joachim99@8 1530 {
joachim99@8 1531 pNextItem = pNextItem->nextSibling();
joachim99@8 1532 }
joachim99@8 1533
joachim99@8 1534 if ( pNextItem == 0 )
joachim99@8 1535 {
joachim99@8 1536 pCurrentItem = pCurrentItem->parent();
joachim99@8 1537 if ( pCurrentItem!=0 )
joachim99@8 1538 {
joachim99@8 1539 if (bSim)
joachim99@8 1540 static_cast<DirMergeItem*>(pCurrentItem)->m_pMFI->m_bSimOpComplete = true;
joachim99@8 1541 else
joachim99@8 1542 {
joachim99@8 1543 pCurrentItem->setText( s_OpStatusCol, "Done." );
joachim99@8 1544 static_cast<DirMergeItem*>(pCurrentItem)->m_pMFI->m_bOperationComplete = true;
joachim99@8 1545 }
joachim99@8 1546 }
joachim99@8 1547 }
joachim99@8 1548 }
joachim99@8 1549 m_pCurrentItemForOperation = static_cast<DirMergeItem*>(pNextItem);
joachim99@8 1550 }
joachim99@8 1551 }
joachim99@8 1552
joachim99@8 1553 if( m_pCurrentItemForOperation !=0 &&
joachim99@8 1554 (bSim ? m_pCurrentItemForOperation->m_pMFI->m_bSimOpComplete :
joachim99@8 1555 m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete ))
joachim99@8 1556 m_pCurrentItemForOperation = 0;
joachim99@8 1557
joachim99@8 1558 if ( m_pCurrentItemForOperation==0 )
joachim99@8 1559 {
joachim99@8 1560 if ( m_bRealMergeStarted )
joachim99@8 1561 {
joachim99@8 1562 KMessageBox::information( this, "Merge operation complete.", "The merge is complete." );
joachim99@8 1563 m_bRealMergeStarted = false;
joachim99@8 1564 m_pStatusInfo->setCaption("KDiff3: Merge complete.");
joachim99@8 1565 }
joachim99@8 1566 if ( m_bSimulatedMergeStarted )
joachim99@8 1567 {
joachim99@8 1568 m_bSimulatedMergeStarted = false;
joachim99@8 1569 for( QListViewItem* p=firstChild(); p!=0; p=treeIterator(p) )
joachim99@8 1570 {
joachim99@8 1571 static_cast<DirMergeItem*>(p)->m_pMFI->m_bSimOpComplete = false;
joachim99@8 1572 }
joachim99@8 1573 m_pStatusInfo->setCaption("KDiff3: Simulated merge complete: Check if you agree with the proposed operations.");
joachim99@8 1574 m_pStatusInfo->show();
joachim99@8 1575 }
joachim99@8 1576 g_pProgressDialog->hide();
joachim99@8 1577 return;
joachim99@8 1578 }
joachim99@8 1579
joachim99@8 1580 MergeFileInfos& mfi = *m_pCurrentItemForOperation->m_pMFI;
joachim99@8 1581 bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles;
joachim99@8 1582
joachim99@8 1583 g_pProgressDialog->setInformation( mfi.m_subPath,
joachim99@8 1584 bSim ? double(nrOfCompletedSimItems)/nrOfItems : double(nrOfCompletedItems)/nrOfItems,
joachim99@8 1585 true
joachim99@8 1586 );
joachim99@8 1587 g_pProgressDialog->show();
joachim99@8 1588
joachim99@8 1589 // First decide destname
joachim99@8 1590 QString destName;
joachim99@8 1591 switch( mfi.m_eMergeOperation )
joachim99@8 1592 {
joachim99@8 1593 case eNoOperation: break;
joachim99@8 1594 case eMergeToAB: // let the user save in B. In mergeResultSaved() the file will be copied to A.
joachim99@8 1595 case eMergeToB:
joachim99@8 1596 case eDeleteB:
joachim99@8 1597 case eCopyAToB: destName = fullNameB(mfi); break;
joachim99@8 1598 case eMergeToA:
joachim99@8 1599 case eDeleteA:
joachim99@8 1600 case eCopyBToA: destName = fullNameA(mfi); break;
joachim99@8 1601 case eMergeABToDest:
joachim99@8 1602 case eMergeABCToDest:
joachim99@8 1603 case eCopyAToDest:
joachim99@8 1604 case eCopyBToDest:
joachim99@8 1605 case eCopyCToDest:
joachim99@8 1606 case eDeleteFromDest: destName = fullNameDest(mfi); break;
joachim99@8 1607 default:
joachim99@8 1608 KMessageBox::error( this, "Unknown merge operation.(This must never happen!)", "Error" );
joachim99@8 1609 assert(false);
joachim99@8 1610 }
joachim99@8 1611
joachim99@8 1612 bSuccess = false;
joachim99@8 1613 bSingleFileMerge = false;
joachim99@8 1614 switch( mfi.m_eMergeOperation )
joachim99@8 1615 {
joachim99@8 1616 case eNoOperation: bSuccess = true; break;
joachim99@8 1617 case eCopyAToDest:
joachim99@8 1618 case eCopyAToB: bSuccess = copyFLD( fullNameA(mfi), destName ); break;
joachim99@8 1619 case eCopyBToDest:
joachim99@8 1620 case eCopyBToA: bSuccess = copyFLD( fullNameB(mfi), destName ); break;
joachim99@8 1621 case eCopyCToDest: bSuccess = copyFLD( fullNameC(mfi), destName ); break;
joachim99@8 1622 case eDeleteFromDest:
joachim99@8 1623 case eDeleteA:
joachim99@8 1624 case eDeleteB: bSuccess = deleteFLD( destName, bCreateBackups ); break;
joachim99@8 1625 case eDeleteAB: bSuccess = deleteFLD( fullNameA(mfi), bCreateBackups ) &&
joachim99@8 1626 deleteFLD( fullNameB(mfi), bCreateBackups ); break;
joachim99@8 1627 case eMergeABToDest:
joachim99@8 1628 case eMergeToA:
joachim99@8 1629 case eMergeToAB:
joachim99@8 1630 case eMergeToB: bSuccess = mergeFLD( fullNameA(mfi), fullNameB(mfi), "",
joachim99@8 1631 destName, bSingleFileMerge );
joachim99@8 1632 break;
joachim99@8 1633 case eMergeABCToDest:bSuccess = mergeFLD(
joachim99@8 1634 mfi.m_bExistsInA ? fullNameA(mfi) : QString(""),
joachim99@8 1635 mfi.m_bExistsInB ? fullNameB(mfi) : QString(""),
joachim99@8 1636 mfi.m_bExistsInC ? fullNameC(mfi) : QString(""),
joachim99@8 1637 destName, bSingleFileMerge );
joachim99@8 1638 break;
joachim99@8 1639 default:
joachim99@8 1640 KMessageBox::error( this, "Unknown merge operation.", "Error" );
joachim99@8 1641 assert(false);
joachim99@8 1642 }
joachim99@8 1643 if ( bSuccess )
joachim99@8 1644 {
joachim99@8 1645 if(bSim) ++nrOfCompletedSimItems;
joachim99@8 1646 else ++nrOfCompletedItems;
joachim99@8 1647 bContinueWithCurrentItem = false;
joachim99@8 1648 }
joachim99@8 1649 } // end while
joachim99@8 1650
joachim99@8 1651 g_pProgressDialog->hide();
joachim99@8 1652
joachim99@8 1653 setCurrentItem( m_pCurrentItemForOperation );
joachim99@8 1654 ensureItemVisible( m_pCurrentItemForOperation );
joachim99@8 1655 if ( !bSuccess && !bSingleFileMerge )
joachim99@8 1656 {
joachim99@8 1657 KMessageBox::error(this, i18n("An error occurred. Press OK to see detailed information.\n"), "KDiff3: Error" );
joachim99@8 1658 m_pStatusInfo->setCaption("KDiff3: Merge-Error");
joachim99@8 1659 m_pStatusInfo->show();
joachim99@8 1660 if ( m_pStatusInfo->firstChild()!=0 )
joachim99@8 1661 m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() );
joachim99@8 1662 m_bError = true;
joachim99@8 1663 m_pCurrentItemForOperation->setText( s_OpStatusCol, "Error." );
joachim99@8 1664 }
joachim99@8 1665 else
joachim99@8 1666 {
joachim99@8 1667 m_bError = false;
joachim99@8 1668 }
joachim99@8 1669 emit updateAvailabilities();
joachim99@8 1670 }
joachim99@8 1671
joachim99@8 1672 void DirectoryMergeWindow::allowResizeEvents(bool bAllowResizeEvents )
joachim99@8 1673 {
joachim99@8 1674 m_bAllowResizeEvents = bAllowResizeEvents;
joachim99@8 1675 }
joachim99@8 1676
joachim99@8 1677 void DirectoryMergeWindow::resizeEvent( QResizeEvent* e )
joachim99@8 1678 {
joachim99@8 1679 if (m_bAllowResizeEvents)
joachim99@8 1680 QListView::resizeEvent(e);
joachim99@8 1681 }
joachim99@8 1682
joachim99@8 1683 bool DirectoryMergeWindow::deleteFLD( const QString& name, bool bCreateBackup )
joachim99@8 1684 {
joachim99@8 1685 FileAccess fi(name, true);
joachim99@8 1686 if ( !fi.exists() )
joachim99@8 1687 return true;
joachim99@8 1688
joachim99@8 1689 if ( bCreateBackup )
joachim99@8 1690 {
joachim99@8 1691 bool bSuccess = renameFLD( name, name+".orig" );
joachim99@8 1692 if (!bSuccess)
joachim99@8 1693 {
joachim99@8 1694 m_pStatusInfo->addText( "Error: While deleting "+name+": Creating backup failed." );
joachim99@8 1695 return false;
joachim99@8 1696 }
joachim99@8 1697 }
joachim99@8 1698 else
joachim99@8 1699 {
joachim99@8 1700 if ( fi.isDir() && !fi.isSymLink() )
joachim99@8 1701 m_pStatusInfo->addText("delete directory recursively( "+name+" )");
joachim99@8 1702 else
joachim99@8 1703 m_pStatusInfo->addText("delete( "+name+" )");
joachim99@8 1704
joachim99@8 1705 if ( m_bSimulatedMergeStarted )
joachim99@8 1706 {
joachim99@8 1707 return true;
joachim99@8 1708 }
joachim99@8 1709
joachim99@8 1710 if ( fi.isDir() && !fi.isSymLink() )// recursive directory delete only for real dirs, not symlinks
joachim99@8 1711 {
joachim99@8 1712 t_DirectoryList dirList;
joachim99@8 1713 bool bSuccess = fi.listDir( &dirList, false, true, "*", "", "", false, false ); // not recursive, find hidden files
joachim99@8 1714
joachim99@8 1715 if ( !bSuccess )
joachim99@8 1716 {
joachim99@8 1717 // No Permission to read directory or other error.
joachim99@8 1718 m_pStatusInfo->addText( "Error: delete dir operation failed while trying to read the directory." );
joachim99@8 1719 return false;
joachim99@8 1720 }
joachim99@8 1721
joachim99@8 1722 t_DirectoryList::iterator it; // create list iterator
joachim99@8 1723
joachim99@8 1724 for ( it=dirList.begin(); it!=dirList.end(); ++it ) // for each file...
joachim99@8 1725 {
joachim99@8 1726 FileAccess& fi2 = *it;
joachim99@8 1727 if ( fi2.fileName() == "." || fi2.fileName()==".." )
joachim99@8 1728 continue;
joachim99@8 1729 bSuccess = deleteFLD( fi2.absFilePath(), false );
joachim99@8 1730 if (!bSuccess) break;
joachim99@8 1731 }
joachim99@8 1732 if (bSuccess)
joachim99@8 1733 {
joachim99@8 1734 bSuccess = FileAccess::removeDir( name );
joachim99@8 1735 if ( !bSuccess )
joachim99@8 1736 {
joachim99@8 1737 m_pStatusInfo->addText( "Error: rmdir( "+name+" ) operation failed." );
joachim99@8 1738 return false;
joachim99@8 1739 }
joachim99@8 1740 }
joachim99@8 1741 }
joachim99@8 1742 else
joachim99@8 1743 {
joachim99@8 1744 bool bSuccess = FileAccess::removeFile( name );
joachim99@8 1745 if ( !bSuccess )
joachim99@8 1746 {
joachim99@8 1747 m_pStatusInfo->addText( "Error: delete operation failed." );
joachim99@8 1748 return false;
joachim99@8 1749 }
joachim99@8 1750 }
joachim99@8 1751 }
joachim99@8 1752 return true;
joachim99@8 1753 }
joachim99@8 1754
joachim99@8 1755 bool DirectoryMergeWindow::mergeFLD( const QString& nameA,const QString& nameB,const QString& nameC,const QString& nameDest, bool& bSingleFileMerge )
joachim99@8 1756 {
joachim99@8 1757 FileAccess fi(nameA);
joachim99@8 1758 if (fi.isDir())
joachim99@8 1759 {
joachim99@8 1760 return makeDir(nameDest);
joachim99@8 1761 }
joachim99@8 1762
joachim99@8 1763 // Make sure that the dir exists, into which we will save the file later.
joachim99@8 1764 int pos=nameDest.findRev('/');
joachim99@8 1765 if ( pos>0 )
joachim99@8 1766 {
joachim99@8 1767 QString parentName = nameDest.left(pos);
joachim99@8 1768 bool bSuccess = makeDir(parentName, true /*quiet*/);
joachim99@8 1769 if (!bSuccess)
joachim99@8 1770 return false;
joachim99@8 1771 }
joachim99@8 1772
joachim99@8 1773 m_pStatusInfo->addText("manual merge( "+nameA+ ", "+nameB+","+nameC+" -> " + nameDest +" )" );
joachim99@8 1774 if ( m_bSimulatedMergeStarted )
joachim99@8 1775 {
joachim99@8 1776 m_pStatusInfo->addText(" Note: After a manual merge the user should continue via F5." );
joachim99@8 1777 return true;
joachim99@8 1778 }
joachim99@8 1779
joachim99@8 1780 bSingleFileMerge = true;
joachim99@8 1781 m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
joachim99@8 1782 ensureItemVisible( m_pCurrentItemForOperation );
joachim99@8 1783
joachim99@8 1784 emit startDiffMerge( nameA, nameB, nameC, nameDest, "","","" );
joachim99@8 1785
joachim99@8 1786 return false;
joachim99@8 1787 }
joachim99@8 1788
joachim99@8 1789 bool DirectoryMergeWindow::copyFLD( const QString& srcName, const QString& destName )
joachim99@8 1790 {
joachim99@8 1791 if ( srcName == destName )
joachim99@8 1792 return true;
joachim99@8 1793
joachim99@8 1794 if ( FileAccess(destName, true).exists() )
joachim99@8 1795 {
joachim99@8 1796 bool bSuccess = deleteFLD( destName, m_pOptions->m_bDmCreateBakFiles );
joachim99@8 1797 if ( !bSuccess )
joachim99@8 1798 {
joachim99@8 1799 m_pStatusInfo->addText("Error: copy( "+srcName+ " -> " + destName +" ) failed."
joachim99@8 1800 "Deleting existing destination failed.");
joachim99@8 1801 return false;
joachim99@8 1802 }
joachim99@8 1803 }
joachim99@8 1804
joachim99@8 1805 FileAccess fi( srcName );
joachim99@8 1806
joachim99@8 1807 if ( fi.isSymLink() && (fi.isDir() && !m_bFollowDirLinks || !fi.isDir() && !m_bFollowDirLinks) )
joachim99@8 1808 {
joachim99@8 1809 m_pStatusInfo->addText("copyLink( "+srcName+ " -> " + destName +" )");
joachim99@8 1810 #ifdef _WIN32
joachim99@8 1811 // What are links?
joachim99@8 1812 #else
joachim99@8 1813 if ( m_bSimulatedMergeStarted )
joachim99@8 1814 {
joachim99@8 1815 return true;
joachim99@8 1816 }
joachim99@8 1817 FileAccess destFi(destName);
joachim99@8 1818 if ( !destFi.isLocal() || !fi.isLocal() )
joachim99@8 1819 {
joachim99@8 1820 m_pStatusInfo->addText("Error: copyLink failed: Remote links are not yet supported.");
joachim99@8 1821 return false;
joachim99@8 1822 }
joachim99@8 1823 QString linkTarget = fi.readLink();
joachim99@8 1824 bool bSuccess = FileAccess::symLink( linkTarget, destName );
joachim99@8 1825 if (!bSuccess)
joachim99@8 1826 m_pStatusInfo->addText("Error: copyLink failed.");
joachim99@8 1827 return bSuccess;
joachim99@8 1828 #endif
joachim99@8 1829 }
joachim99@8 1830
joachim99@8 1831 if ( fi.isDir() )
joachim99@8 1832 {
joachim99@8 1833 bool bSuccess = makeDir( destName );
joachim99@8 1834 return bSuccess;
joachim99@8 1835 }
joachim99@8 1836
joachim99@8 1837 int pos=destName.findRev('/');
joachim99@8 1838 if ( pos>0 )
joachim99@8 1839 {
joachim99@8 1840 QString parentName = destName.left(pos);
joachim99@8 1841 bool bSuccess = makeDir(parentName, true /*quiet*/);
joachim99@8 1842 if (!bSuccess)
joachim99@8 1843 return false;
joachim99@8 1844 }
joachim99@8 1845
joachim99@8 1846 m_pStatusInfo->addText("copy( "+srcName+ " -> " + destName +" )");
joachim99@8 1847
joachim99@8 1848 if ( m_bSimulatedMergeStarted )
joachim99@8 1849 {
joachim99@8 1850 return true;
joachim99@8 1851 }
joachim99@8 1852
joachim99@8 1853 FileAccess faSrc ( srcName );
joachim99@8 1854 bool bSuccess = faSrc.copyFile( destName );
joachim99@8 1855 if (! bSuccess ) m_pStatusInfo->addText( faSrc.getStatusText() );
joachim99@8 1856 return bSuccess;
joachim99@8 1857 }
joachim99@8 1858
joachim99@8 1859 // Rename is not an operation that can be selected by the user.
joachim99@8 1860 // It will only be used to create backups.
joachim99@8 1861 // Hence it will delete an existing destination without making a backup (of the old backup.)
joachim99@8 1862 bool DirectoryMergeWindow::renameFLD( const QString& srcName, const QString& destName )
joachim99@8 1863 {
joachim99@8 1864 if ( srcName == destName )
joachim99@8 1865 return true;
joachim99@8 1866
joachim99@8 1867 if ( FileAccess(destName, true).exists() )
joachim99@8 1868 {
joachim99@8 1869 bool bSuccess = deleteFLD( destName, false /*no backup*/ );
joachim99@8 1870 if (!bSuccess)
joachim99@8 1871 {
joachim99@8 1872 m_pStatusInfo->addText( "Error during rename( "+srcName+" -> " + destName + " ): "
joachim99@8 1873 "Cannot delete existing destination." );
joachim99@8 1874 return false;
joachim99@8 1875 }
joachim99@8 1876 }
joachim99@8 1877
joachim99@8 1878 m_pStatusInfo->addText("rename( "+srcName+ " -> " + destName +" )");
joachim99@8 1879 if ( m_bSimulatedMergeStarted )
joachim99@8 1880 {
joachim99@8 1881 return true;
joachim99@8 1882 }
joachim99@8 1883
joachim99@8 1884 bool bSuccess = FileAccess( srcName ).rename( destName );
joachim99@8 1885 if (!bSuccess)
joachim99@8 1886 {
joachim99@8 1887 m_pStatusInfo->addText( "Error: Rename failed." );
joachim99@8 1888 return false;
joachim99@8 1889 }
joachim99@8 1890
joachim99@8 1891 return true;
joachim99@8 1892 }
joachim99@8 1893
joachim99@8 1894 bool DirectoryMergeWindow::makeDir( const QString& name, bool bQuiet )
joachim99@8 1895 {
joachim99@8 1896 FileAccess fi(name, true);
joachim99@8 1897 if( fi.exists() && fi.isDir() )
joachim99@8 1898 return true;
joachim99@8 1899
joachim99@8 1900 if( fi.exists() && !fi.isDir() )
joachim99@8 1901 {
joachim99@8 1902 bool bSuccess = deleteFLD( name, true );
joachim99@8 1903 if (!bSuccess)
joachim99@8 1904 {
joachim99@8 1905 m_pStatusInfo->addText( "Error during makeDir of "+name+
joachim99@8 1906 "Cannot delete existing file." );
joachim99@8 1907 return false;
joachim99@8 1908 }
joachim99@8 1909 }
joachim99@8 1910
joachim99@8 1911 int pos=name.findRev('/');
joachim99@8 1912 if ( pos>0 )
joachim99@8 1913 {
joachim99@8 1914 QString parentName = name.left(pos);
joachim99@8 1915 bool bSuccess = makeDir(parentName,true);
joachim99@8 1916 if (!bSuccess)
joachim99@8 1917 return false;
joachim99@8 1918 }
joachim99@8 1919
joachim99@8 1920 if ( ! bQuiet )
joachim99@8 1921 m_pStatusInfo->addText("makeDir( " + name + " )");
joachim99@8 1922
joachim99@8 1923 if ( m_bSimulatedMergeStarted )
joachim99@8 1924 {
joachim99@8 1925 return true;
joachim99@8 1926 }
joachim99@8 1927
joachim99@8 1928 bool bSuccess = FileAccess::makeDir( name );
joachim99@8 1929 if ( bSuccess == false )
joachim99@8 1930 {
joachim99@8 1931 m_pStatusInfo->addText( "Error while creating directory." );
joachim99@8 1932 return false;
joachim99@8 1933 }
joachim99@8 1934 return true;
joachim99@8 1935 }
joachim99@8 1936
joachim99@8 1937
joachim99@8 1938
joachim99@8 1939
joachim99@8 1940
joachim99@8 1941 DirectoryMergeInfo::DirectoryMergeInfo( QWidget* pParent )
joachim99@8 1942 : QFrame(pParent)
joachim99@8 1943 {
joachim99@8 1944 QVBoxLayout *topLayout = new QVBoxLayout( this );
joachim99@8 1945
joachim99@8 1946
joachim99@8 1947 QGridLayout *grid = new QGridLayout( topLayout );
joachim99@8 1948 grid->setColStretch(1,10);
joachim99@8 1949
joachim99@8 1950 int line=0;
joachim99@8 1951
joachim99@8 1952 m_pA = new QLabel("A",this); grid->addWidget( m_pA,line, 0 );
joachim99@8 1953 m_pInfoA = new QLabel(this); grid->addWidget( m_pInfoA,line,1 ); ++line;
joachim99@8 1954 m_pB = new QLabel("B",this); grid->addWidget( m_pB,line, 0 );
joachim99@8 1955 m_pInfoB = new QLabel(this); grid->addWidget( m_pInfoB,line,1 ); ++line;
joachim99@8 1956 m_pC = new QLabel("C",this); grid->addWidget( m_pC,line, 0 );
joachim99@8 1957 m_pInfoC = new QLabel(this); grid->addWidget( m_pInfoC,line,1 ); ++line;
joachim99@8 1958 m_pDest = new QLabel("Dest",this); grid->addWidget( m_pDest,line, 0 );
joachim99@8 1959 m_pInfoDest = new QLabel(this); grid->addWidget( m_pInfoDest,line,1 ); ++line;
joachim99@8 1960
joachim99@8 1961 m_pInfoList = new QListView(this); topLayout->addWidget( m_pInfoList );
joachim99@8 1962 m_pInfoList->addColumn("Dir");
joachim99@8 1963 m_pInfoList->addColumn("Type");
joachim99@8 1964 m_pInfoList->addColumn("Size");
joachim99@8 1965 m_pInfoList->addColumn("Attr");
joachim99@8 1966 m_pInfoList->addColumn("Last Modification");
joachim99@8 1967 m_pInfoList->addColumn("Link-Destination");
joachim99@8 1968 setMinimumSize( 100,100 );
joachim99@8 1969 }
joachim99@8 1970
joachim99@8 1971 static void addListViewItem( QListView* pListView, const QString& dir,
joachim99@8 1972 const QString& basePath, FileAccess& fi )
joachim99@8 1973 {
joachim99@8 1974 if ( basePath.isEmpty() )
joachim99@8 1975 {
joachim99@8 1976 return;
joachim99@8 1977 }
joachim99@8 1978 else
joachim99@8 1979 {
joachim99@8 1980 if ( fi.exists() )
joachim99@8 1981 {
joachim99@8 1982 #if QT_VERSION==230
joachim99@8 1983 QString dateString = fi.lastModified().toString();
joachim99@8 1984 #else
joachim99@8 1985 QString dateString = fi.lastModified().toString("yyyy-MM-dd hh:mm:ss");
joachim99@8 1986 #endif
joachim99@8 1987
joachim99@8 1988 new QListViewItem(
joachim99@8 1989 pListView,
joachim99@8 1990 dir,
joachim99@8 1991 QString( fi.isDir() ? "Dir" : "File" ) + (fi.isSymLink() ? "-Link" : ""),
joachim99@8 1992 QString::number(fi.size()),
joachim99@8 1993 QString(fi.isReadable() ? "r" : " ") + (fi.isWritable()?"w" : " ")
joachim99@8 1994 #ifdef _WIN32
joachim99@8 1995 /*Future: Use GetFileAttributes()*/,
joachim99@8 1996 #else
joachim99@8 1997 + (fi.isExecutable()?"x" : " "),
joachim99@8 1998 #endif
joachim99@8 1999 dateString,
joachim99@8 2000 QString(fi.isSymLink() ? (" -> " + fi.readLink()) : QString(""))
joachim99@8 2001 );
joachim99@8 2002 }
joachim99@8 2003 else
joachim99@8 2004 {
joachim99@8 2005 new QListViewItem(
joachim99@8 2006 pListView,
joachim99@8 2007 dir,
joachim99@8 2008 "not available",
joachim99@8 2009 "",
joachim99@8 2010 "",
joachim99@8 2011 "",
joachim99@8 2012 ""
joachim99@8 2013 );
joachim99@8 2014 }
joachim99@8 2015 }
joachim99@8 2016 }
joachim99@8 2017
joachim99@8 2018 void DirectoryMergeInfo::setInfo(
joachim99@8 2019 const FileAccess& dirA,
joachim99@8 2020 const FileAccess& dirB,
joachim99@8 2021 const FileAccess& dirC,
joachim99@8 2022 const FileAccess& dirDest,
joachim99@8 2023 MergeFileInfos& mfi )
joachim99@8 2024 {
joachim99@8 2025 bool bHideDest = false;
joachim99@8 2026 if ( dirA.absFilePath()==dirDest.absFilePath() )
joachim99@8 2027 {
joachim99@8 2028 m_pA->setText( "A (Dest): " ); bHideDest=true;
joachim99@8 2029 }
joachim99@8 2030 else
joachim99@8 2031 m_pA->setText( !dirC.isValid() ? "A: " : "A (Base): ");
joachim99@8 2032
joachim99@8 2033 m_pInfoA->setText( dirA.prettyAbsPath() );
joachim99@8 2034
joachim99@8 2035 if ( dirB.absFilePath()==dirDest.absFilePath() )
joachim99@8 2036 {
joachim99@8 2037 m_pB->setText( "B (Dest): " ); bHideDest=true;
joachim99@8 2038 }
joachim99@8 2039 else
joachim99@8 2040 m_pB->setText( "B: " );
joachim99@8 2041 m_pInfoB->setText( dirB.prettyAbsPath() );
joachim99@8 2042
joachim99@8 2043 if ( dirC.absFilePath()==dirDest.absFilePath() )
joachim99@8 2044 {
joachim99@8 2045 m_pC->setText( "C (Dest): " ); bHideDest=true;
joachim99@8 2046 }
joachim99@8 2047 else
joachim99@8 2048 m_pC->setText( "C: " );
joachim99@8 2049 m_pInfoC->setText( dirC.prettyAbsPath() );
joachim99@8 2050
joachim99@8 2051 m_pDest->setText( "Dest: " ); m_pInfoDest->setText( dirDest.prettyAbsPath() );
joachim99@8 2052
joachim99@8 2053 if (!dirC.isValid()) { m_pC->hide(); m_pInfoC->hide(); }
joachim99@8 2054 else { m_pC->show(); m_pInfoC->show(); }
joachim99@8 2055
joachim99@8 2056 if (!dirDest.isValid()||bHideDest) { m_pDest->hide(); m_pInfoDest->hide(); }
joachim99@8 2057 else { m_pDest->show(); m_pInfoDest->show(); }
joachim99@8 2058
joachim99@8 2059 m_pInfoList->clear();
joachim99@8 2060 addListViewItem( m_pInfoList, "A", dirA.prettyAbsPath(), mfi.m_fileInfoA );
joachim99@8 2061 addListViewItem( m_pInfoList, "B", dirB.prettyAbsPath(), mfi.m_fileInfoB );
joachim99@8 2062 addListViewItem( m_pInfoList, "C", dirC.prettyAbsPath(), mfi.m_fileInfoC );
joachim99@8 2063 if (!bHideDest)
joachim99@8 2064 {
joachim99@8 2065 FileAccess fiDest( dirDest.prettyAbsPath() + "/" + mfi.m_subPath, true );
joachim99@8 2066 addListViewItem( m_pInfoList, "Dest", dirDest.prettyAbsPath(), fiDest );
joachim99@8 2067 }
joachim99@8 2068 }
joachim99@8 2069
joachim99@8 2070 #include "directorymergewindow.moc"