diff kdiff3/src/directorymergewindow.cpp @ 51:c59d5a3a8ff3

0.9.80
author joachim99
date Tue, 09 Dec 2003 20:29:43 +0000
parents bf8fa177e5a1
children 32d5cbf9db71
line wrap: on
line diff
--- a/kdiff3/src/directorymergewindow.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/directorymergewindow.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -15,18 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.3  2003/10/15 20:14:03  joachim99
- * Fix for MergeOperation DeleteAB.
- *
- * Revision 1.2  2003/10/11 12:41:57  joachim99
- * Fix for gcc 2.95
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- ***************************************************************************/
-
 #include "directorymergewindow.h"
 #include "optiondialog.h"
 #include <vector>
@@ -37,6 +25,7 @@
 #include <qpixmap.h>
 #include <qimage.h>
 #include <kpopupmenu.h>
+#include <kaction.h>
 #include <qregexp.h>
 #include <qmessagebox.h>
 #include <qlayout.h>
@@ -50,6 +39,7 @@
 #include <iostream>
 #include <assert.h>
 
+static bool conflictingFileTypes(MergeFileInfos& mfi);
 
 class StatusInfo : public QListView
 {
@@ -120,14 +110,14 @@
    {
       if ( fi1.isSymLink() != fi2.isSymLink() )
       {
-         status = "Mix of links and normal files.";
+         status = i18n("Mix of links and normal files.");
          return;
       }
       else if ( fi1.isSymLink() && fi2.isSymLink() )
       {
          bError = false;
          bEqual = fi1.readLink() == fi2.readLink();
-         status = "Link: ";
+         status = i18n("Link: ");
          return;
       }
    }
@@ -135,7 +125,12 @@
    if ( fi1.size()!=fi2.size() )
    {
       bEqual = false;
-      status = "Size. ";
+      status = i18n("Size. ");
+      return;
+   }
+   else if ( m_pOptions->m_bDmTrustSize )
+   {
+      bEqual = true;
       return;
    }
 
@@ -143,7 +138,7 @@
    {
       bEqual = ( fi1.lastModified() == fi2.lastModified()  &&  fi1.size()==fi2.size() );
       bError = false;
-      status = "Date&Size: ";
+      status = i18n("Date & Size: ");
       return;
    }
 
@@ -152,13 +147,13 @@
    TempRemover tr1( fileName1, fi1 );
    if ( !tr1.success() )
    {
-      status = "Creating temp copy of " + fileName1 + " failed.";
+      status = i18n("Creating temp copy of %1 failed.").arg(fileName1);
       return;
    }
    TempRemover tr2( fileName2, fi2 );
    if ( !tr2.success() )
    {
-      status = "Creating temp copy of " + fileName2 + " failed.";
+      status = i18n("Creating temp copy of %1 failed.").arg(fileName2);
       return;
    }
 
@@ -169,7 +164,7 @@
 
    if ( ! file1.open(IO_ReadOnly) )
    {
-      status = "Opening " + fileName1 + " failed.";
+      status = i18n("Opening %1 failed.").arg(fileName1);
       return;
    }
 
@@ -177,7 +172,7 @@
 
    if ( ! file2.open(IO_ReadOnly) )
    {
-      status = "Opening " + fileName2 + " failed.";
+      status = i18n("Opening %1 failed.").arg(fileName2);
       return;
    }
 
@@ -193,13 +188,13 @@
       int len = min2( size, (t_FileSize)buf1.size() );
       if( len != file1.readBlock( &buf1[0], len ) )
       {
-         status = "Error reading from " + fileName1;
+         status = i18n("Error reading from %1").arg(fileName1);
          return;
       }
 
       if( len != file2.readBlock( &buf2[0], len ) )
       {
-         status = "Error reading from " + fileName2;
+         status = i18n("Error reading from %1").arg(fileName2);
          return;
       }
 
@@ -240,18 +235,17 @@
    m_bAllowResizeEvents = true;
    m_bSimulatedMergeStarted=false;
    m_bRealMergeStarted=false;
-   m_bSingleFileOperationStarted=false;
    m_bError = false;
    m_bSyncMode = false;
    m_pStatusInfo = new StatusInfo(0);
    m_pStatusInfo->hide();
    
-   addColumn("Name");
+   addColumn(i18n("Name"));
    addColumn("A");
    addColumn("B");
    addColumn("C");
-   addColumn("Operation");
-   addColumn("Status");
+   addColumn(i18n("Operation"));
+   addColumn(i18n("Status"));
 }
 
 DirectoryMergeWindow::~DirectoryMergeWindow()
@@ -275,7 +269,7 @@
    {
       int result = KMessageBox::warningYesNo(this,
          i18n("You are currently doing a directory merge. Are you sure, you want to abort the merge and rescan the directory?"),
-         i18n("Warning"), i18n("Yes - Rescan"), i18n("No - Continue merging") );
+         i18n("Warning"), i18n("Rescan"), i18n("Continue Merging") );
       if ( result!=KMessageBox::Yes )
          return;
    }
@@ -371,7 +365,7 @@
 
    clear();
 
-   m_pCurrentItemForOperation = 0;
+   m_currentItemForOperation = m_mergeItemList.end();
 
    m_dirA = dirA;
    m_dirB = dirB;
@@ -386,15 +380,15 @@
        QString text( i18n("Opening of directories failed:") );
        text += "\n\n";
        if ( !dirA.isDir() )
-       {  text += "Dir A \"" + m_dirA.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
+       {  text += i18n("Dir A \"%1\" does not exist or is not a directory.\n").arg(m_dirA.prettyAbsPath()); }
 
        if ( !dirB.isDir() )
-       {  text += "Dir B \"" + m_dirB.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
+       {  text += i18n("Dir B \"%1\" does not exist or is not a directory.\n").arg(m_dirB.prettyAbsPath()); }
 
        if ( m_dirC.isValid() && !m_dirC.isDir() )
-       {  text += "Dir C \"" + m_dirC.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
+       {  text += i18n("Dir C \"%1\" does not exist or is not a directory.\n").arg(m_dirC.prettyAbsPath()); }
 
-       KMessageBox::sorry( this, text, i18n("Directory open error") );
+       KMessageBox::sorry( this, text, i18n("Directory Open Error") );
        return false;
    }
 
@@ -404,7 +398,7 @@
       KMessageBox::error(this,
          i18n( "The destination directory must not be the same as A or B when"
          "three directories are merged.\nCheck again before continuing."),
-         "KDiff3: Parameter warning");
+         i18n("Parameter Warning"));
       return false;
    }
 
@@ -431,7 +425,7 @@
    bool bListDirSuccessC = true;
    if ( m_dirA.isValid() )
    {
-      g_pProgressDialog->setInformation("Reading Directory A");
+      g_pProgressDialog->setInformation(i18n("Reading Directory A"));
       g_pProgressDialog->setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
       ++currentScan;
 
@@ -453,7 +447,7 @@
 
    if ( m_dirB.isValid() )
    {
-      g_pProgressDialog->setInformation("Reading Directory B");
+      g_pProgressDialog->setInformation(i18n("Reading Directory B"));
       g_pProgressDialog->setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
       ++currentScan;
 
@@ -475,7 +469,7 @@
    e_MergeOperation eDefaultMergeOp;
    if ( m_dirC.isValid() )
    {
-      g_pProgressDialog->setInformation("Reading Directory C");
+      g_pProgressDialog->setInformation(i18n("Reading Directory C"));
       g_pProgressDialog->setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
       ++currentScan;
 
@@ -553,7 +547,7 @@
                         nofFiles, nofDirs, nofEqualFiles, nofManualMerges );
 
       QString s;
-      s = i18n("Directory Comparison Status:") + "\n\n" +
+      s = i18n("Directory Comparison Status") + "\n\n" +
           i18n("Number of subdirectories:") +" "+ QString::number(nofDirs)       + "\n"+
           i18n("Number of equal files:")     +" "+ QString::number(nofEqualFiles) + "\n"+
           i18n("Number of different files:") +" "+ QString::number(nofFiles-nofEqualFiles);
@@ -604,11 +598,91 @@
       setListViewItemOpen( p, true );
 }
 
+static void setMergeOperation( QListViewItem* pLVI, e_MergeOperation eMergeOp )
+{
+   if ( pLVI==0 ) return;
+
+   DirMergeItem* pDMI = static_cast<DirMergeItem*>(pLVI);
+   MergeFileInfos& mfi = *pDMI->m_pMFI;
+
+   mfi.setMergeOperation(eMergeOp );
+}
+
+// Merge current item (merge mode)
+void DirectoryMergeWindow::slotCurrentDoNothing() { setMergeOperation(currentItem(), eNoOperation ); }
+void DirectoryMergeWindow::slotCurrentChooseA()   { setMergeOperation(currentItem(), eCopyAToDest ); }
+void DirectoryMergeWindow::slotCurrentChooseB()   { setMergeOperation(currentItem(), eCopyBToDest ); }
+void DirectoryMergeWindow::slotCurrentChooseC()   { setMergeOperation(currentItem(), eCopyCToDest ); }
+void DirectoryMergeWindow::slotCurrentMerge()
+{
+   bool bThreeDirs = m_dirC.isValid();
+   setMergeOperation(currentItem(), bThreeDirs ? eMergeABCToDest : eMergeABToDest );
+}
+void DirectoryMergeWindow::slotCurrentDelete()    { setMergeOperation(currentItem(), eDeleteFromDest ); }
+// Sync current item
+void DirectoryMergeWindow::slotCurrentCopyAToB()     { setMergeOperation(currentItem(), eCopyAToB ); }
+void DirectoryMergeWindow::slotCurrentCopyBToA()     { setMergeOperation(currentItem(), eCopyBToA ); }
+void DirectoryMergeWindow::slotCurrentDeleteA()      { setMergeOperation(currentItem(), eDeleteA );  }
+void DirectoryMergeWindow::slotCurrentDeleteB()      { setMergeOperation(currentItem(), eDeleteB );  }
+void DirectoryMergeWindow::slotCurrentDeleteAAndB()  { setMergeOperation(currentItem(), eDeleteAB ); }
+void DirectoryMergeWindow::slotCurrentMergeToA()     { setMergeOperation(currentItem(), eMergeToA ); }
+void DirectoryMergeWindow::slotCurrentMergeToB()     { setMergeOperation(currentItem(), eMergeToB ); }
+void DirectoryMergeWindow::slotCurrentMergeToAAndB() { setMergeOperation(currentItem(), eMergeToAB ); }
+
+
+void DirectoryMergeWindow::keyPressEvent( QKeyEvent* e )
+{
+   if ( (e->state() & Qt::ControlButton)!=0 )
+   {
+      bool bThreeDirs = m_dirC.isValid();
+
+      QListViewItem* lvi = currentItem();
+      DirMergeItem* pDMI = lvi==0 ? 0 : static_cast<DirMergeItem*>(lvi);
+      MergeFileInfos* pMFI = pDMI==0 ? 0 : pDMI->m_pMFI;
+
+      if ( pMFI==0 ) return;
+      bool bMergeMode = bThreeDirs || !m_bSyncMode;
+      bool bFTConflict = pMFI==0 ? false : conflictingFileTypes(*pMFI);
+
+      if ( bMergeMode )
+      {
+         switch(e->key())
+         {
+         case Key_1:      if(pMFI->m_bExistsInA){ slotCurrentChooseA(); }  return;
+         case Key_2:      if(pMFI->m_bExistsInB){ slotCurrentChooseB(); }  return;
+         case Key_3:      if(pMFI->m_bExistsInC){ slotCurrentChooseC(); }  return;
+         case Key_Space:  slotCurrentDoNothing();                          return;
+         case Key_4:      if ( !bFTConflict )   { slotCurrentMerge();   }  return;
+         case Key_Delete: slotCurrentDelete();                             return;
+         default: break;
+         }
+      }
+      else
+      {
+         switch(e->key())
+         {
+         case Key_1:      if(pMFI->m_bExistsInA){ slotCurrentCopyAToB(); }  return;
+         case Key_2:      if(pMFI->m_bExistsInB){ slotCurrentCopyBToA(); }  return;
+         case Key_Space:  slotCurrentDoNothing();                           return;
+         case Key_4:      if ( !bFTConflict ) { slotCurrentMergeToAAndB(); }  return;
+         case Key_Delete: if( pMFI->m_bExistsInA && pMFI->m_bExistsInB ) slotCurrentDeleteAAndB();
+                          else if( pMFI->m_bExistsInA ) slotCurrentDeleteA();
+                          else if( pMFI->m_bExistsInB ) slotCurrentDeleteB();
+                          return;
+         default: break;
+         }
+      }
+   }
+
+   QListView::keyPressEvent(e);
+}
+
+
 void DirectoryMergeWindow::setAllMergeOperations( e_MergeOperation eDefaultOperation )
 {
    if ( KMessageBox::Yes == KMessageBox::warningYesNo(this,
         i18n("This affects all merge operations."),
-        i18n("KDiff3: Changing all merge operations"),i18n("Continue"), i18n("Cancel") ) )
+        i18n("Changing All Merge Operations"),i18n("C&ontinue"), i18n("&Cancel") ) )
    {
       for( QListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
       {
@@ -875,7 +949,7 @@
                       QString("");
 
       g_pProgressDialog->setInformation(
-         "Processing " + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles)
+         i18n("Processing ") + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles)
          +"\n" + fileName, double(currentIdx) / nrOfFiles, false );
       if ( g_pProgressDialog->wasCancelled() ) break;
       ++currentIdx;
@@ -1004,10 +1078,10 @@
 
    if ( eDefaultMergeOp == eMergeABCToDest && !bCheckC ) { eDefaultMergeOp = eMergeABToDest; }
    if ( eDefaultMergeOp == eMergeToAB      &&  bCheckC ) { assert(false); }
-   
+
    if ( eDefaultMergeOp == eMergeToA || eDefaultMergeOp == eMergeToB ||
         eDefaultMergeOp == eMergeABCToDest || eDefaultMergeOp == eMergeABToDest || eDefaultMergeOp == eMergeToAB )
-   {   
+   {
       if ( !bCheckC )
       {
          if ( mfi.m_bEqualAB )
@@ -1174,53 +1248,45 @@
 
    bool bThreeDirs = m_dirC.isValid();
 
-   //bool bImmediate = (button==Qt::LeftButton);
-
    KPopupMenu m(this);
-   //if (bImmediate ) m.insertItem("Immediate Mode", eTitleId );
-   //else             m.insertItem("Postponed Mode", eTitleId );
-   //m.setItemEnabled ( eTitleId, false );
    if ( bThreeDirs )
    {
-      m.insertItem("Do nothing", eNoOperation );
+      dirCurrentDoNothing->plug(&m);
       int count=0;
-      if ( mfi.m_bExistsInA ) { m.insertItem("A", eCopyAToDest );  ++count;  }
-      if ( mfi.m_bExistsInB ) { m.insertItem("B", eCopyBToDest );  ++count;  }
-      if ( mfi.m_bExistsInC ) { m.insertItem("C", eCopyCToDest );  ++count;  }
-      if ( !conflictingFileTypes(mfi) && count>1 ) m.insertItem("Merge", eMergeABCToDest );
-      m.insertItem("Delete (if exists)", eDeleteFromDest );
+      if ( mfi.m_bExistsInA ) { dirCurrentChooseA->plug(&m); ++count;  }
+      if ( mfi.m_bExistsInB ) { dirCurrentChooseB->plug(&m); ++count;  }
+      if ( mfi.m_bExistsInC ) { dirCurrentChooseC->plug(&m); ++count;  }
+      if ( !conflictingFileTypes(mfi) && count>1 ) dirCurrentMerge->plug(&m);
+      dirCurrentDelete->plug(&m);
    }
    else if ( m_bSyncMode )
    {
-      m.insertItem("Do nothing", eNoOperation );
-      if ( mfi.m_bExistsInA ) m.insertItem("Copy A to B", eCopyAToB );
-      if ( mfi.m_bExistsInB ) m.insertItem("Copy B to A", eCopyBToA );
-      if ( mfi.m_bExistsInA ) m.insertItem("Delete A", eDeleteA );
-      if ( mfi.m_bExistsInB ) m.insertItem("Delete B", eDeleteB );
+      dirCurrentSyncDoNothing->plug(&m);
+      if ( mfi.m_bExistsInA ) dirCurrentSyncCopyAToB->plug(&m);
+      if ( mfi.m_bExistsInB ) dirCurrentSyncCopyBToA->plug(&m);
+      if ( mfi.m_bExistsInA ) dirCurrentSyncDeleteA->plug(&m);
+      if ( mfi.m_bExistsInB ) dirCurrentSyncDeleteB->plug(&m);
       if ( mfi.m_bExistsInA && mfi.m_bExistsInB )
       {
-         m.insertItem("Delete A and B", eDeleteAB );
+         dirCurrentSyncDeleteAAndB->plug(&m);
          if ( !conflictingFileTypes(mfi))
          {
-            m.insertItem("Merge to A",    eMergeToA );
-            m.insertItem("Merge to B",    eMergeToB );
-            m.insertItem("Merge to A and B",    eMergeToAB );
+            dirCurrentSyncMergeToA->plug(&m);
+            dirCurrentSyncMergeToB->plug(&m);
+            dirCurrentSyncMergeToAAndB->plug(&m);
          }
       }
    }
    else
    {
-      m.insertItem("Do nothing", eNoOperation );
-      if ( mfi.m_bExistsInA ) m.insertItem("A", eCopyAToDest );
-      if ( mfi.m_bExistsInB ) m.insertItem("B", eCopyBToDest );
-      if ( mfi.m_bExistsInA  &&  mfi.m_bExistsInB  && !conflictingFileTypes(mfi) )
-         m.insertItem("Merge", eMergeABToDest );
-      m.insertItem("Delete (if exists)", eDeleteFromDest );
+      dirCurrentDoNothing->plug(&m);
+      if ( mfi.m_bExistsInA ) { dirCurrentChooseA->plug(&m); }
+      if ( mfi.m_bExistsInB ) { dirCurrentChooseB->plug(&m); }
+      if ( !conflictingFileTypes(mfi) && mfi.m_bExistsInA  &&  mfi.m_bExistsInB ) dirCurrentMerge->plug(&m);
+      dirCurrentDelete->plug(&m);
    }
 
-   int result = m.exec( p );
-   if (result>=0 )
-      mfi.setMergeOperation( (e_MergeOperation)result );
+   m.exec( p );
 }
 
 // Since Qt 2.3.0 doesn't allow the specification of a compare operator, this trick emulates it.
@@ -1231,14 +1297,14 @@
 #endif
 
 DirMergeItem::DirMergeItem( QListView* pParent, const QString& fileName, MergeFileInfos* pMFI )
-: QListViewItem( pParent, DIRSORT( fileName ), "","","", "To do." )
+: QListViewItem( pParent, DIRSORT( fileName ), "","","", i18n("To do.") )
 {
    pMFI->m_pDMI = this;
    m_pMFI = pMFI;
 }
 
 DirMergeItem::DirMergeItem( DirMergeItem* pParent, const QString& fileName, MergeFileInfos* pMFI )
-: QListViewItem( pParent, DIRSORT( fileName ), "","","", "To do." )
+: QListViewItem( pParent, DIRSORT( fileName ), "","","", i18n("To do.") )
 {
    pMFI->m_pDMI = this;
    m_pMFI = pMFI;
@@ -1251,30 +1317,36 @@
 
 void MergeFileInfos::setMergeOperation( e_MergeOperation eMOp )
 {
+   if ( eMOp != m_eMergeOperation )
+   {
+      m_bOperationComplete = false;
+      m_pDMI->setText( s_OpStatusCol, "" );
+   }
+
    m_eMergeOperation = eMOp;
-   const char* s=0;
+   QString s;
    bool bDir = m_bDirA || m_bDirB || m_bDirC;
    if( m_pDMI!=0 )
    {
       switch( m_eMergeOperation )
       {
       case eNoOperation:      s=""; m_pDMI->setText(s_OpCol,""); break;
-      case eCopyAToB:         s="Copy A to B";     break;
-      case eCopyBToA:         s="Copy B to A";     break;
-      case eDeleteA:          s="Delete A";        break;
-      case eDeleteB:          s="Delete B";        break;
-      case eDeleteAB:         s="Delete A and B";  break;
-      case eMergeToA:         s="Merge to A";      break;
-      case eMergeToB:         s="Merge to B";      break;
-      case eMergeToAB:        s="Merge to A and B";  break;
+      case eCopyAToB:         s=i18n("Copy A to B");     break;
+      case eCopyBToA:         s=i18n("Copy B to A");     break;
+      case eDeleteA:          s=i18n("Delete A");        break;
+      case eDeleteB:          s=i18n("Delete B");        break;
+      case eDeleteAB:         s=i18n("Delete A & B");    break;
+      case eMergeToA:         s=i18n("Merge to A");      break;
+      case eMergeToB:         s=i18n("Merge to B");      break;
+      case eMergeToAB:        s=i18n("Merge to A & B");  break;
       case eCopyAToDest:      s="A";    break;
       case eCopyBToDest:      s="B";    break;
       case eCopyCToDest:      s="C";    break;
-      case eDeleteFromDest:   s="Delete (if exists)";  break;
-      case eMergeABCToDest:   s= bDir ? "Merge" : "Merge (manual)";  break;
-      case eMergeABToDest:    s= bDir ? "Merge" : "Merge (manual)";  break;
-      case eConflictingFileTypes: s="Error: Conflicting File Types"; break;
-      case eConflictingAges:  s="Error: Dates are equal but files are not."; break;
+      case eDeleteFromDest:   s=i18n("Delete (if exists)");  break;
+      case eMergeABCToDest:   s= bDir ? i18n("Merge") : i18n("Merge (manual)");    break;
+      case eMergeABToDest:    s= bDir ? i18n("Merge") : i18n("Merge (manual)");    break;
+      case eConflictingFileTypes: s=i18n("Error: Conflicting File Types");         break;
+      case eConflictingAges:  s=i18n("Error: Dates are equal but files are not."); break;
       default:                assert(false); break;
       }
       m_pDMI->setText(s_OpCol,s);
@@ -1298,7 +1370,7 @@
 
    if ( m_bRealMergeStarted )
    {
-      KMessageBox::sorry(this,"This operation is currently not possible.","KDiff3");
+      KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible"));
       return;
    }
 
@@ -1320,36 +1392,6 @@
    emit updateAvailabilities();
 }
 
-void DirectoryMergeWindow::mergeCurrentFile()
-{
-   if (!canContinue()) return;
-
-   if ( m_bRealMergeStarted )
-   {
-      KMessageBox::sorry(this,"This operation is currently not possible because diff merge currently runs.","KDiff3");
-      return;
-   }
-
-   if ( isFileSelected() )
-   {
-      DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
-      if ( pDMI != 0 )
-      {
-         MergeFileInfos& mfi = *pDMI->m_pMFI;
-         m_bSingleFileOperationStarted = true;
-         emit startDiffMerge(
-            mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : QString(""),
-            mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : QString(""),
-            mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : QString(""),
-            fullNameDest(mfi),
-            "","",""
-            );
-         m_pCurrentItemForOperation = pDMI;
-         m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
-      }
-   }
-   emit updateAvailabilities();
-}
 
 
 bool DirectoryMergeWindow::isFileSelected()
@@ -1365,33 +1407,41 @@
 
 void DirectoryMergeWindow::mergeResultSaved(const QString& fileName)
 {
-   m_bSingleFileOperationStarted = false;
-   if ( m_pCurrentItemForOperation!=0 && m_pCurrentItemForOperation->m_pMFI==0 )
+   DirMergeItem* pCurrentItemForOperation = (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() )
+                                               ? 0
+                                               : *m_currentItemForOperation;
+
+   if ( pCurrentItemForOperation!=0 && pCurrentItemForOperation->m_pMFI==0 )
    {
-      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" );
+      KMessageBox::error( this, i18n("This should never happen: \n\nmergeResultSaved: m_pMFI=0\n\nIf you know how to reproduce this, please contact the program author."),i18n("Program Error") );
       return;
    }
-   if ( m_pCurrentItemForOperation!=0 && fileName == fullNameDest(*m_pCurrentItemForOperation->m_pMFI) )
+   if ( pCurrentItemForOperation!=0 && fileName == fullNameDest(*pCurrentItemForOperation->m_pMFI) )
    {
-      if ( m_pCurrentItemForOperation->m_pMFI->m_eMergeOperation==eMergeToAB )
+      if ( pCurrentItemForOperation->m_pMFI->m_eMergeOperation==eMergeToAB )
       {
-         MergeFileInfos& mfi = *m_pCurrentItemForOperation->m_pMFI;
+         MergeFileInfos& mfi = *pCurrentItemForOperation->m_pMFI;
          bool bSuccess = copyFLD( fullNameB(mfi), fullNameA(mfi) );
          if (!bSuccess)
          {
-            KMessageBox::error(this, i18n("An error occurred while copying.\n"), "KDiff3: Error" );
-            m_pStatusInfo->setCaption("KDiff3: Merge-Error");
+            KMessageBox::error(this, i18n("An error occurred while copying.\n"), i18n("Error") );
+            m_pStatusInfo->setCaption(i18n("Merge Error"));
             m_pStatusInfo->show();
             if ( m_pStatusInfo->firstChild()!=0 )
                m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() );
             m_bError = true;
-            m_pCurrentItemForOperation->setText( s_OpStatusCol, "Error." );
+            pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Error.") );
             mfi.m_eMergeOperation = eCopyBToA;
             return;
          }
       }
-      m_pCurrentItemForOperation->setText( s_OpStatusCol, "Done." );
-      m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+      pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Done.") );
+      pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+      if ( m_mergeItemList.size()==1 )
+      {
+         m_mergeItemList.clear();
+         m_bRealMergeStarted=false;
+      }
    }
 
    emit updateAvailabilities();
@@ -1403,76 +1453,246 @@
    checkIfCanContinue( &bCanContinue );
    if ( bCanContinue && !m_bError )
    {
-      if ( m_bRealMergeStarted && m_pCurrentItemForOperation!=0  && ! m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
+      DirMergeItem* pCurrentItemForOperation =
+         (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() ) ? 0 : *m_currentItemForOperation;
+
+      if ( pCurrentItemForOperation!=0  && ! pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
       {
-         m_pCurrentItemForOperation->setText( s_OpStatusCol, "Not saved." );
-         m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+         pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Not saved.") );
+         pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+         if ( m_mergeItemList.size()==1 )
+         {
+            m_mergeItemList.clear();
+            m_bRealMergeStarted=false;
+         }
       }
    }
    return bCanContinue;
 }
 
-void DirectoryMergeWindow::mergeContinue()
+bool DirectoryMergeWindow::executeMergeOperation( MergeFileInfos& mfi, bool& bSingleFileMerge )
 {
-   if ( ! canContinue() ) return;
+   bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles;
+   // First decide destname
+   QString destName;
+   switch( mfi.m_eMergeOperation )
+   {
+   case eNoOperation: break;
+   case eDeleteAB:    break;
+   case eMergeToAB:   // let the user save in B. In mergeResultSaved() the file will be copied to A.
+   case eMergeToB:
+   case eDeleteB:
+   case eCopyAToB:    destName = fullNameB(mfi); break;
+   case eMergeToA:
+   case eDeleteA:
+   case eCopyBToA:    destName = fullNameA(mfi); break;
+   case eMergeABToDest:
+   case eMergeABCToDest:
+   case eCopyAToDest:
+   case eCopyBToDest:
+   case eCopyCToDest:
+   case eDeleteFromDest: destName = fullNameDest(mfi); break;
+   default:
+      KMessageBox::error( this, i18n("Unknown merge operation. (This must never happen!)"), i18n("Error") );
+      assert(false);
+   }
 
-   m_bSingleFileOperationStarted = false;
+   bool bSuccess = false;
+   bSingleFileMerge = false;
+   switch( mfi.m_eMergeOperation )
+   {
+   case eNoOperation: bSuccess = true; break;
+   case eCopyAToDest:
+   case eCopyAToB:    bSuccess = copyFLD( fullNameA(mfi), destName ); break;
+   case eCopyBToDest:
+   case eCopyBToA:    bSuccess = copyFLD( fullNameB(mfi), destName ); break;
+   case eCopyCToDest: bSuccess = copyFLD( fullNameC(mfi), destName ); break;
+   case eDeleteFromDest:
+   case eDeleteA:
+   case eDeleteB:     bSuccess = deleteFLD( destName, bCreateBackups ); break;
+   case eDeleteAB:    bSuccess = deleteFLD( fullNameA(mfi), bCreateBackups ) &&
+                                 deleteFLD( fullNameB(mfi), bCreateBackups ); break;
+   case eMergeABToDest:
+   case eMergeToA:
+   case eMergeToAB:
+   case eMergeToB:      bSuccess = mergeFLD( fullNameA(mfi), fullNameB(mfi), "",
+                                             destName, bSingleFileMerge );
+                        break;
+   case eMergeABCToDest:bSuccess = mergeFLD(
+                                    mfi.m_bExistsInA ? fullNameA(mfi) : QString(""),
+                                    mfi.m_bExistsInB ? fullNameB(mfi) : QString(""),
+                                    mfi.m_bExistsInC ? fullNameC(mfi) : QString(""),
+                                    destName, bSingleFileMerge );
+                        break;
+   default:
+      KMessageBox::error( this, i18n("Unknown merge operation."), i18n("Error") );
+      assert(false);
+   }
 
-   int nrOfItems = 0;
-   int nrOfCompletedItems = 0;
-   int nrOfCompletedSimItems = 0;
+   return bSuccess;
+}
 
-   if ( !m_bSimulatedMergeStarted && !m_bRealMergeStarted )
+
+// Check if the merge can start, and prepare the m_mergeItemList which then contains all
+// items that must be merged.
+void DirectoryMergeWindow::prepareMergeStart( QListViewItem* pBegin, QListViewItem* pEnd, bool bVerbose )
+{
+   if ( bVerbose )
    {
-      // First check if an invalid merge operations exist.
-      for( QListViewItem* p=firstChild(); p!=0; p = treeIterator( p ) )
+      int status = KMessageBox::warningYesNoCancel(this,
+         i18n("The merge is about to begin.\n\n"
+         "Choose \"Do it\" if you have read the instructions and know what you are doing.\n"
+         "Choosing \"Simulate it\" will tell you what would happen.\n\n"
+         "Be aware that this program still has beta status "
+         "and there is NO WARRANTY whatsoever! Make backups of your vital data!"),
+         i18n("Starting Merge"), i18n("Do It"), i18n("Simulate It") );
+      if (status==KMessageBox::Yes)      m_bRealMergeStarted = true;
+      else if (status==KMessageBox::No ) m_bSimulatedMergeStarted = true;
+      else return;
+   }
+   else
+   {
+      m_bRealMergeStarted = true;
+   }
+
+   m_mergeItemList.clear();
+   if (pBegin == 0)
+      return;
+
+   for( QListViewItem* p = pBegin; p!= pEnd; p = treeIterator( p ) )
+   {
+      DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
+
+      if ( ! pDMI->m_pMFI->m_bOperationComplete )
       {
-         DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
+         m_mergeItemList.push_back(pDMI);
+
          if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingFileTypes )
          {
             ensureItemVisible( pDMI );
             setSelected( pDMI, true );
-            KMessageBox::error(this, i18n("The highlighted item has a different type in the different directories. Select what to do."), "Error");
+            KMessageBox::error(this, i18n("The highlighted item has a different type in the different directories. Select what to do."), i18n("Error"));
+            m_mergeItemList.clear();
+            m_bRealMergeStarted=false;
             return;
          }
          if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingAges )
          {
             ensureItemVisible( pDMI );
             setSelected( pDMI, true );
-            KMessageBox::error(this, i18n("The modification dates of the file are equal but the files are not. Select what to do."), "Error");
+            KMessageBox::error(this, i18n("The modification dates of the file are equal but the files are not. Select what to do."), i18n("Error"));
+            m_mergeItemList.clear();
+            m_bRealMergeStarted=false;
             return;
          }
-         ++nrOfItems;
-         if ( pDMI->m_pMFI->m_bSimOpComplete )
-            ++nrOfCompletedSimItems;
-         if ( pDMI->m_pMFI->m_bOperationComplete )
-            ++nrOfCompletedItems;
       }
-
-      int status = KMessageBox::warningYesNoCancel(this,
-         i18n("The merge is about to begin.\n\n"
-         "Choose \"Do it\" if you have read the instructions and know what you are doing.\n"
-         "Choosing \"Simulate it\" will tell you what would happen.\n\n"
-         "Be aware that this program still has beta status "
-         "and there is NO WARRANTY whatsoever! Make backups of your vital data!"),
-         i18n("KDiff3: Starting the Merge"), i18n("Do it"), i18n("Simulate it") );
-      if (status==KMessageBox::Yes) m_bRealMergeStarted = true;
-      else if (status==KMessageBox::No ) m_bSimulatedMergeStarted = true;
-      else return;
-
-      m_pStatusInfo->hide();
-      m_pStatusInfo->clear();
    }
 
-   bool bContinueWithCurrentItem = false;
+   m_currentItemForOperation = m_mergeItemList.begin();
+   return;
+}
+
+void DirectoryMergeWindow::slotRunOperationForCurrentItem()
+{
+   if ( ! canContinue() ) return;
+
+   bool bVerbose = false;
+   if ( m_mergeItemList.empty() )
+   {
+      QListViewItem* pBegin = currentItem();
+
+      prepareMergeStart( pBegin, pBegin->nextSibling(), bVerbose );
+      mergeContinue(true, bVerbose);
+   }
+   else
+      mergeContinue(false, bVerbose);
+}
+
+void DirectoryMergeWindow::slotRunOperationForAllItems()
+{
+   if ( ! canContinue() ) return;
+
+   bool bVerbose = true;
+   if ( m_mergeItemList.empty() )
+   {
+      QListViewItem* pBegin = firstChild();
+
+      prepareMergeStart( pBegin, 0, bVerbose );
+      mergeContinue(true, bVerbose);
+   }
+   else
+      mergeContinue(false, bVerbose);
+}
+
+void DirectoryMergeWindow::mergeCurrentFile()
+{
+   if (!canContinue()) return;
+
+   if ( m_bRealMergeStarted )
+   {
+      KMessageBox::sorry(this,i18n("This operation is currently not possible because dir merge currently runs."),i18n("Operation Not Possible"));
+      return;
+   }
+
+   if ( isFileSelected() )
+   {
+      DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
+      if ( pDMI != 0 )
+      {
+         MergeFileInfos& mfi = *pDMI->m_pMFI;
+         m_mergeItemList.clear();
+         m_mergeItemList.push_back( pDMI );
+         m_currentItemForOperation=m_mergeItemList.begin();
+         bool bDummy=false;
+         mergeFLD(
+            mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : QString(""),
+            mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : QString(""),
+            mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : QString(""),
+            fullNameDest(mfi),
+            bDummy
+            );
+      }
+   }
+   emit updateAvailabilities();
+}
+
+
+// When bStart is true then m_currentItemForOperation must still be processed.
+// When bVerbose is true then a messagebox will tell when the merge is complete.
+void DirectoryMergeWindow::mergeContinue(bool bStart, bool bVerbose)
+{
+   if ( m_mergeItemList.empty() )
+      return;
+
+   int nrOfItems = 0;
+   int nrOfCompletedItems = 0;
+   int nrOfCompletedSimItems = 0;
+
+   // Count the number of completed items (for the progress bar).
+   for( MergeItemList::iterator i = m_mergeItemList.begin(); i!=m_mergeItemList.end(); ++i )
+   {
+      DirMergeItem* pDMI = static_cast<DirMergeItem*>(*i);
+      ++nrOfItems;
+      if ( pDMI->m_pMFI->m_bOperationComplete )
+         ++nrOfCompletedItems;
+      if ( pDMI->m_pMFI->m_bSimOpComplete )
+         ++nrOfCompletedSimItems;
+   }
+
+   m_pStatusInfo->hide();
+   m_pStatusInfo->clear();
+
+   DirMergeItem* pCurrentItemForOperation = m_currentItemForOperation==m_mergeItemList.end() ? 0 : *m_currentItemForOperation;
+
+   bool bContinueWithCurrentItem = bStart;  // true for first item, else false
    bool bSkipItem = false;
-   if ( m_bError && m_pCurrentItemForOperation!=0 )
+   if ( !bStart && m_bError && pCurrentItemForOperation!=0 )
    {
       int status = KMessageBox::warningYesNoCancel(this,
          i18n("There was an error in the last step.\n"
          "Do you want to continue with the item that caused the error or do you want to skip this item?"),
-         i18n("KDiff3: Continue merge after an error"), i18n("Continue with last item"), i18n("Skip item") );
-      if (status==KMessageBox::Yes) bContinueWithCurrentItem = true;
+         i18n("Continue merge after an error"), i18n("Continue With Last Item"), i18n("Skip Item") );
+      if      (status==KMessageBox::Yes) bContinueWithCurrentItem = true;
       else if (status==KMessageBox::No ) bSkipItem = true;
       else return;
       m_bError = false;
@@ -1485,89 +1705,87 @@
    bool bSim = m_bSimulatedMergeStarted;
    while( bSuccess )
    {
-      if ( m_pCurrentItemForOperation!=0 && !bContinueWithCurrentItem )
+      if ( pCurrentItemForOperation==0 )
+      {
+         m_mergeItemList.clear();
+         m_bRealMergeStarted=false;
+         break;
+      }
+
+      if ( pCurrentItemForOperation!=0 && !bContinueWithCurrentItem )
       {
          if ( bSim )
          {
-            if( m_pCurrentItemForOperation->firstChild()==0 )
+            if( pCurrentItemForOperation->firstChild()==0 )
             {
-               m_pCurrentItemForOperation->m_pMFI->m_bSimOpComplete = true;
+               pCurrentItemForOperation->m_pMFI->m_bSimOpComplete = true;
             }
          }
          else
          {
-            if( m_pCurrentItemForOperation->firstChild()==0 )
+            if( pCurrentItemForOperation->firstChild()==0 )
             {
-               if( !m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
+               if( !pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
                {
-                  m_pCurrentItemForOperation->setText( s_OpStatusCol, bSkipItem ? "Skipped." : "Done." );
-                  m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+                  pCurrentItemForOperation->setText( s_OpStatusCol, bSkipItem ? i18n("Skipped.") : i18n("Done.") );
+                  pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
                   bSkipItem = false;
                }
             }
             else
             {
-               m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
+               pCurrentItemForOperation->setText( s_OpStatusCol, i18n("In progress...") );
             }
          }
       }
 
-      if ( m_pCurrentItemForOperation==0 )
+      if ( ! bContinueWithCurrentItem )
       {
-         m_pCurrentItemForOperation = static_cast<DirMergeItem*>( firstChild() );
-      }
-      else
-      {
-         if ( ! bContinueWithCurrentItem )
+         // Depth first
+         QListViewItem* pPrevItem = pCurrentItemForOperation;
+         ++m_currentItemForOperation;
+         pCurrentItemForOperation = m_currentItemForOperation==m_mergeItemList.end() ? 0 : *m_currentItemForOperation;
+         if ( (pCurrentItemForOperation==0 || pCurrentItemForOperation->parent()!=pPrevItem->parent()) && pPrevItem->parent()!=0 )
          {
-            // Depth first
-            QListViewItem* pNextItem = m_pCurrentItemForOperation->firstChild();
-            QListViewItem* pCurrentItem = m_pCurrentItemForOperation;
-            while( pCurrentItem!=0 && pNextItem==0 )
+            // Check if the parent may be set to "Done"
+            QListViewItem* pParent = pPrevItem->parent();
+            bool bDone = true;
+            while ( bDone && pParent!=0 )
             {
-               // Find an item on this level that hasn't been operated yet. (Always start at beginning.)
-               if ( pCurrentItem->parent()==0 )
-                  pNextItem = firstChild();
-               else
-                  pNextItem = pCurrentItem->parent()->firstChild();
-
-               while( pNextItem!=0 && ( static_cast<DirMergeItem*>(pNextItem)->m_pMFI->m_bOperationComplete ||
-                               ( bSim && static_cast<DirMergeItem*>(pNextItem)->m_pMFI->m_bSimOpComplete ) ) )
+               for( QListViewItem* p = pParent->firstChild(); p!=0; p=p->nextSibling() )
                {
-                  pNextItem = pNextItem->nextSibling();
-               }
-
-               if ( pNextItem == 0 )
-               {
-                  pCurrentItem = pCurrentItem->parent();
-                  if ( pCurrentItem!=0 )
+                  DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
+                  if ( !bSim && ! pDMI->m_pMFI->m_bOperationComplete   ||  bSim && pDMI->m_pMFI->m_bSimOpComplete )
                   {
-                     if (bSim)
-                        static_cast<DirMergeItem*>(pCurrentItem)->m_pMFI->m_bSimOpComplete = true;
-                     else
-                     {
-                        pCurrentItem->setText( s_OpStatusCol, "Done." );
-                        static_cast<DirMergeItem*>(pCurrentItem)->m_pMFI->m_bOperationComplete = true;
-                     }
+                     bDone=false;
+                     break;
                   }
                }
+               if ( bDone )
+               {
+                  if (bSim)
+                     static_cast<DirMergeItem*>(pParent)->m_pMFI->m_bSimOpComplete = bDone;
+                  else
+                  {
+                     pParent->setText( s_OpStatusCol, i18n("Done.") );
+                     static_cast<DirMergeItem*>(pParent)->m_pMFI->m_bOperationComplete = bDone;
+                  }
+               }
+               pParent = pParent->parent();
             }
-            m_pCurrentItemForOperation = static_cast<DirMergeItem*>(pNextItem);
          }
       }
 
-      if( m_pCurrentItemForOperation !=0 &&
-         (bSim ? m_pCurrentItemForOperation->m_pMFI->m_bSimOpComplete :
-                 m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete ))
-         m_pCurrentItemForOperation = 0;
-
-      if ( m_pCurrentItemForOperation==0 )
+      if ( pCurrentItemForOperation == 0 ) // end?
       {
          if ( m_bRealMergeStarted )
          {
-            KMessageBox::information( this, "Merge operation complete.", "The merge is complete." );
+            if (bVerbose)
+            {
+               KMessageBox::information( this, i18n("Merge operation complete."), i18n("Merge Complete") );
+            }
             m_bRealMergeStarted = false;
-            m_pStatusInfo->setCaption("KDiff3: Merge complete.");
+            m_pStatusInfo->setCaption(i18n("Merge Complete"));
          }
          if ( m_bSimulatedMergeStarted )
          {
@@ -1576,104 +1794,61 @@
             {
                static_cast<DirMergeItem*>(p)->m_pMFI->m_bSimOpComplete = false;
             }
-            m_pStatusInfo->setCaption("KDiff3: Simulated merge complete: Check if you agree with the proposed operations.");
+            m_pStatusInfo->setCaption(i18n("Simulated merge complete: Check if you agree with the proposed operations."));
             m_pStatusInfo->show();
          }
          g_pProgressDialog->hide();
+         m_mergeItemList.clear();
+         m_bRealMergeStarted=false;
          return;
       }
 
-      MergeFileInfos& mfi = *m_pCurrentItemForOperation->m_pMFI;
-      bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles;
+      MergeFileInfos& mfi = *pCurrentItemForOperation->m_pMFI;
 
       g_pProgressDialog->setInformation( mfi.m_subPath,
          bSim ? double(nrOfCompletedSimItems)/nrOfItems : double(nrOfCompletedItems)/nrOfItems,
-         true
+         false // bRedrawUpdate
          );
       g_pProgressDialog->show();
 
-      // First decide destname
-      QString destName;
-      switch( mfi.m_eMergeOperation )
-      {
-      case eNoOperation: break;
-      case eDeleteAB:    break;
-      case eMergeToAB:   // let the user save in B. In mergeResultSaved() the file will be copied to A.
-      case eMergeToB:
-      case eDeleteB:
-      case eCopyAToB:    destName = fullNameB(mfi); break;
-      case eMergeToA:
-      case eDeleteA:
-      case eCopyBToA:    destName = fullNameA(mfi); break;
-      case eMergeABToDest:
-      case eMergeABCToDest:
-      case eCopyAToDest:
-      case eCopyBToDest:
-      case eCopyCToDest:
-      case eDeleteFromDest: destName = fullNameDest(mfi); break;
-      default:
-         KMessageBox::error( this, "Unknown merge operation.(This must never happen!)", "Error" );
-         assert(false);
-      }
+      bSuccess = executeMergeOperation( mfi, bSingleFileMerge );  // Here the real operation happens.
 
-      bSuccess = false;
-      bSingleFileMerge = false;
-      switch( mfi.m_eMergeOperation )
-      {
-      case eNoOperation: bSuccess = true; break;
-      case eCopyAToDest:
-      case eCopyAToB:    bSuccess = copyFLD( fullNameA(mfi), destName ); break;
-      case eCopyBToDest:
-      case eCopyBToA:    bSuccess = copyFLD( fullNameB(mfi), destName ); break;
-      case eCopyCToDest: bSuccess = copyFLD( fullNameC(mfi), destName ); break;
-      case eDeleteFromDest:
-      case eDeleteA:
-      case eDeleteB:     bSuccess = deleteFLD( destName, bCreateBackups ); break;
-      case eDeleteAB:    bSuccess = deleteFLD( fullNameA(mfi), bCreateBackups ) &&
-                                    deleteFLD( fullNameB(mfi), bCreateBackups ); break;
-      case eMergeABToDest:
-      case eMergeToA:
-      case eMergeToAB:
-      case eMergeToB:      bSuccess = mergeFLD( fullNameA(mfi), fullNameB(mfi), "",
-                                                destName, bSingleFileMerge );
-                           break;
-      case eMergeABCToDest:bSuccess = mergeFLD(
-                                         mfi.m_bExistsInA ? fullNameA(mfi) : QString(""),
-                                         mfi.m_bExistsInB ? fullNameB(mfi) : QString(""),
-                                         mfi.m_bExistsInC ? fullNameC(mfi) : QString(""),
-                                         destName, bSingleFileMerge );
-                           break;
-      default:
-         KMessageBox::error( this, "Unknown merge operation.", "Error" );
-         assert(false);
-      }
       if ( bSuccess )
       {
          if(bSim) ++nrOfCompletedSimItems;
          else     ++nrOfCompletedItems;
          bContinueWithCurrentItem = false;
       }
+
+      if( g_pProgressDialog->wasCancelled() )
+         break;
    }  // end while
 
    g_pProgressDialog->hide();
 
-   setCurrentItem( m_pCurrentItemForOperation );
-   ensureItemVisible( m_pCurrentItemForOperation );
+   setCurrentItem( pCurrentItemForOperation );
+   ensureItemVisible( pCurrentItemForOperation );
    if ( !bSuccess &&  !bSingleFileMerge )
    {
-      KMessageBox::error(this, i18n("An error occurred. Press OK to see detailed information.\n"), "KDiff3: Error" );
-      m_pStatusInfo->setCaption("KDiff3: Merge-Error");
+      KMessageBox::error(this, i18n("An error occurred. Press OK to see detailed information.\n"), i18n("Error") );
+      m_pStatusInfo->setCaption(i18n("Merge Error"));
       m_pStatusInfo->show();
       if ( m_pStatusInfo->firstChild()!=0 )
          m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() );
       m_bError = true;
-      m_pCurrentItemForOperation->setText( s_OpStatusCol, "Error." );
+      pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Error.") );
    }
    else
    {
       m_bError = false;
    }
    emit updateAvailabilities();
+
+   if ( m_currentItemForOperation==m_mergeItemList.end() )
+   {
+      m_mergeItemList.clear();
+      m_bRealMergeStarted=false;
+   }
 }
 
 void DirectoryMergeWindow::allowResizeEvents(bool bAllowResizeEvents )
@@ -1698,16 +1873,16 @@
       bool bSuccess = renameFLD( name, name+".orig" );
       if (!bSuccess)
       {
-         m_pStatusInfo->addText( "Error: While deleting "+name+": Creating backup failed." );
+         m_pStatusInfo->addText( i18n("Error: While deleting %1: Creating backup failed.").arg(name) );
          return false;
       }
    }
    else
    {
       if ( fi.isDir() && !fi.isSymLink() )
-         m_pStatusInfo->addText("delete directory recursively( "+name+" )");
+         m_pStatusInfo->addText(i18n("delete directory recursively( %1 )").arg(name));
       else
-         m_pStatusInfo->addText("delete( "+name+" )");
+         m_pStatusInfo->addText(i18n("delete( %1 )").arg(name));
 
       if ( m_bSimulatedMergeStarted )
       {
@@ -1722,7 +1897,7 @@
          if ( !bSuccess )
          {
              // No Permission to read directory or other error.
-             m_pStatusInfo->addText( "Error: delete dir operation failed while trying to read the directory." );
+             m_pStatusInfo->addText( i18n("Error: delete dir operation failed while trying to read the directory.") );
              return false;
          }
 
@@ -1741,7 +1916,7 @@
             bSuccess = FileAccess::removeDir( name );
             if ( !bSuccess )
             {
-               m_pStatusInfo->addText( "Error: rmdir( "+name+" ) operation failed." );
+               m_pStatusInfo->addText( i18n("Error: rmdir( %1 ) operation failed.").arg(name));
                return false;
             }
          }
@@ -1751,7 +1926,7 @@
          bool bSuccess = FileAccess::removeFile( name );
          if ( !bSuccess )
          {
-            m_pStatusInfo->addText( "Error: delete operation failed." );
+            m_pStatusInfo->addText( i18n("Error: delete operation failed.") );
             return false;
          }
       }
@@ -1777,16 +1952,16 @@
          return false;
    }
 
-   m_pStatusInfo->addText("manual merge( "+nameA+ ", "+nameB+","+nameC+" -> " + nameDest +" )" );
+   m_pStatusInfo->addText(i18n("manual merge( %1, %2, %3 -> %4)").arg(nameA).arg(nameB).arg(nameC).arg(nameDest));
    if ( m_bSimulatedMergeStarted )
    {
-      m_pStatusInfo->addText("     Note: After a manual merge the user should continue via F5." );
+      m_pStatusInfo->addText(i18n("     Note: After a manual merge the user should continue via F7.") );
       return true;
    }
 
    bSingleFileMerge = true;
-   m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
-   ensureItemVisible( m_pCurrentItemForOperation );
+   (*m_currentItemForOperation)->setText( s_OpStatusCol, i18n("In progress...") );
+   ensureItemVisible( *m_currentItemForOperation );
 
    emit startDiffMerge( nameA, nameB, nameC, nameDest, "","","" );
 
@@ -1803,8 +1978,8 @@
       bool bSuccess = deleteFLD( destName, m_pOptions->m_bDmCreateBakFiles );
       if ( !bSuccess )
       {
-         m_pStatusInfo->addText("Error: copy( "+srcName+ " -> " + destName +" ) failed."
-            "Deleting existing destination failed.");
+         m_pStatusInfo->addText(i18n("Error: copy( %1 -> %2 ) failed."
+            "Deleting existing destination failed.").arg(srcName).arg(destName));
          return false;
       }
    }
@@ -1813,7 +1988,7 @@
 
    if ( fi.isSymLink() && (fi.isDir() && !m_bFollowDirLinks  ||  !fi.isDir() && !m_bFollowDirLinks) )
    {
-      m_pStatusInfo->addText("copyLink( "+srcName+ " -> " + destName +" )");
+      m_pStatusInfo->addText(i18n("copyLink( %1 -> %2 )").arg(srcName).arg(destName));
 #ifdef _WIN32
       // What are links?
 #else
@@ -1824,13 +1999,13 @@
       FileAccess destFi(destName);
       if ( !destFi.isLocal() || !fi.isLocal() )
       {
-         m_pStatusInfo->addText("Error: copyLink failed: Remote links are not yet supported.");
+         m_pStatusInfo->addText(i18n("Error: copyLink failed: Remote links are not yet supported."));
          return false;
       }
       QString linkTarget = fi.readLink();
       bool bSuccess = FileAccess::symLink( linkTarget, destName );
       if (!bSuccess)
-         m_pStatusInfo->addText("Error: copyLink failed.");
+         m_pStatusInfo->addText(i18n("Error: copyLink failed."));
       return bSuccess;
 #endif
    }
@@ -1850,7 +2025,7 @@
          return false;
    }
 
-   m_pStatusInfo->addText("copy( "+srcName+ " -> " + destName +" )");
+   m_pStatusInfo->addText(i18n("copy( %1 -> %2 )").arg(srcName).arg(destName));
 
    if ( m_bSimulatedMergeStarted )
    {
@@ -1876,13 +2051,13 @@
       bool bSuccess = deleteFLD( destName, false /*no backup*/ );
       if (!bSuccess)
       {
-         m_pStatusInfo->addText( "Error during rename( "+srcName+" -> " + destName + " ): "
-                             "Cannot delete existing destination." );
+         m_pStatusInfo->addText( i18n("Error during rename( %1 -> %2 ): "
+                             "Cannot delete existing destination." ).arg(srcName).arg(destName));
          return false;
       }
    }
 
-   m_pStatusInfo->addText("rename( "+srcName+ " -> " + destName +" )");
+   m_pStatusInfo->addText(i18n("rename( %1 -> %2 )").arg(srcName).arg(destName))	;
    if ( m_bSimulatedMergeStarted )
    {
       return true;
@@ -1891,7 +2066,7 @@
    bool bSuccess = FileAccess( srcName ).rename( destName );
    if (!bSuccess)
    {
-      m_pStatusInfo->addText( "Error: Rename failed." );
+      m_pStatusInfo->addText( i18n("Error: Rename failed.") );
       return false;
    }
 
@@ -1909,8 +2084,8 @@
       bool bSuccess = deleteFLD( name, true );
       if (!bSuccess)
       {
-         m_pStatusInfo->addText( "Error during makeDir of "+name+
-                             "Cannot delete existing file." );
+         m_pStatusInfo->addText( i18n("Error during makeDir of %1. "
+                             "Cannot delete existing file." ).arg(name));
          return false;
       }
    }
@@ -1925,7 +2100,7 @@
    }
 
    if ( ! bQuiet )
-      m_pStatusInfo->addText("makeDir( " + name + " )");
+      m_pStatusInfo->addText(i18n("makeDir( %1 )").arg(name));
 
    if ( m_bSimulatedMergeStarted )
    {
@@ -1935,7 +2110,7 @@
    bool bSuccess = FileAccess::makeDir( name );
    if ( bSuccess == false )
    {
-      m_pStatusInfo->addText( "Error while creating directory." );
+      m_pStatusInfo->addText( i18n("Error while creating directory.") );
       return false;
    }
    return true;
@@ -1962,16 +2137,16 @@
    m_pInfoB = new QLabel(this);        grid->addWidget( m_pInfoB,line,1 ); ++line;
    m_pC = new QLabel("C",this);        grid->addWidget( m_pC,line, 0 );
    m_pInfoC = new QLabel(this);        grid->addWidget( m_pInfoC,line,1 ); ++line;
-   m_pDest = new QLabel("Dest",this);  grid->addWidget( m_pDest,line, 0 );
+   m_pDest = new QLabel(i18n("Dest"),this);  grid->addWidget( m_pDest,line, 0 );
    m_pInfoDest = new QLabel(this);     grid->addWidget( m_pInfoDest,line,1 ); ++line;
 
    m_pInfoList = new QListView(this);  topLayout->addWidget( m_pInfoList );
-   m_pInfoList->addColumn("Dir");
-   m_pInfoList->addColumn("Type");
-   m_pInfoList->addColumn("Size");
-   m_pInfoList->addColumn("Attr");
-   m_pInfoList->addColumn("Last Modification");
-   m_pInfoList->addColumn("Link-Destination");
+   m_pInfoList->addColumn(i18n("Dir"));
+   m_pInfoList->addColumn(i18n("Type"));
+   m_pInfoList->addColumn(i18n("Size"));
+   m_pInfoList->addColumn(i18n("Attr"));
+   m_pInfoList->addColumn(i18n("Last Modification"));
+   m_pInfoList->addColumn(i18n("Link-Destination"));
    setMinimumSize( 100,100 );
 }
 
@@ -1995,7 +2170,7 @@
          new QListViewItem(
             pListView,
             dir,
-            QString( fi.isDir() ? "Dir" : "File" ) + (fi.isSymLink() ? "-Link" : ""),
+            QString( fi.isDir() ? i18n("Dir") : i18n("File") ) + (fi.isSymLink() ? "-Link" : ""),
             QString::number(fi.size()),
             QString(fi.isReadable() ? "r" : " ") + (fi.isWritable()?"w" : " ")
 #ifdef _WIN32
@@ -2012,7 +2187,7 @@
          new QListViewItem(
             pListView,
             dir,
-            "not available",
+            i18n("not available"),
             "",
             "",
             "",
@@ -2032,16 +2207,16 @@
    bool bHideDest = false;
    if ( dirA.absFilePath()==dirDest.absFilePath() )
    {
-      m_pA->setText( "A (Dest): " );  bHideDest=true;
+      m_pA->setText( i18n("A (Dest): ") );  bHideDest=true;
    }
    else
-      m_pA->setText( !dirC.isValid() ? "A:    " : "A (Base): ");
+      m_pA->setText( !dirC.isValid() ? QString("A:    ") : i18n("A (Base): "));
 
    m_pInfoA->setText( dirA.prettyAbsPath() );
 
    if ( dirB.absFilePath()==dirDest.absFilePath() )
    {
-      m_pB->setText( "B (Dest): " );  bHideDest=true;
+      m_pB->setText( i18n("B (Dest): ") );  bHideDest=true;
    }
    else
       m_pB->setText( "B:    " );
@@ -2049,13 +2224,13 @@
 
    if ( dirC.absFilePath()==dirDest.absFilePath() )
    {
-      m_pC->setText( "C (Dest): " );  bHideDest=true;
+      m_pC->setText( i18n("C (Dest): ") );  bHideDest=true;
    }
    else
       m_pC->setText( "C:    " );
    m_pInfoC->setText( dirC.prettyAbsPath() );
 
-   m_pDest->setText( "Dest: " ); m_pInfoDest->setText( dirDest.prettyAbsPath() );
+   m_pDest->setText( i18n("Dest: ") ); m_pInfoDest->setText( dirDest.prettyAbsPath() );
 
    if (!dirC.isValid())    { m_pC->hide(); m_pInfoC->hide();   }
    else                     { m_pC->show(); m_pInfoC->show();   }
@@ -2070,8 +2245,95 @@
    if (!bHideDest)
    {
       FileAccess fiDest( dirDest.prettyAbsPath() + "/" + mfi.m_subPath, true );
-      addListViewItem( m_pInfoList, "Dest", dirDest.prettyAbsPath(), fiDest );
+      addListViewItem( m_pInfoList, i18n("Dest"), dirDest.prettyAbsPath(), fiDest );
    }
 }
 
+
+void DirectoryMergeWindow::initDirectoryMergeActions( QObject* pKDiff3App, KActionCollection* ac )
+{
+#include "xpm/startmerge.xpm"
+   DirectoryMergeWindow* p = this;
+
+   dirStartOperation = new KAction(i18n("Start/Continue Directory Merge"), Key_F7, p, SLOT(slotRunOperationForAllItems()), ac, "dir_start_operation");
+   dirRunOperationForCurrentItem = new KAction(i18n("Run Operation for Current Item"), Key_F6, p, SLOT(slotRunOperationForCurrentItem()), ac, "dir_run_operation_for_current_item");
+   dirCompareCurrent = new KAction(i18n("Compare Selected File"), 0, p, SLOT(compareCurrentFile()), ac, "dir_compare_current");
+   dirMergeCurrent = new KAction(i18n("Merge Current File"), QIconSet(QPixmap(startmerge)), 0, pKDiff3App, SLOT(slotMergeCurrentFile()), ac, "merge_current");
+   dirFoldAll = new KAction(i18n("Fold All Subdirs"), 0, p, SLOT(slotFoldAllSubdirs()), ac, "dir_fold_all");
+   dirUnfoldAll = new KAction(i18n("Unfold All Subdirs"), 0, p, SLOT(slotUnfoldAllSubdirs()), ac, "dir_unfold_all");
+   dirRescan = new KAction(i18n("Rescan"), 0, p, SLOT(reload()), ac, "dir_rescan");
+   dirChooseAEverywhere = new KAction(i18n("Choose A for All Items"), 0, p, SLOT(slotChooseAEverywhere()), ac, "dir_choose_a_everywhere");
+   dirChooseBEverywhere = new KAction(i18n("Choose B for All Items"), 0, p, SLOT(slotChooseBEverywhere()), ac, "dir_choose_b_everywhere");
+   dirChooseCEverywhere = new KAction(i18n("Choose C for All Items"), 0, p, SLOT(slotChooseCEverywhere()), ac, "dir_choose_c_everywhere");
+   dirAutoChoiceEverywhere = new KAction(i18n("Auto-Choose Operation for All Items"), 0, p, SLOT(slotAutoChooseEverywhere()), ac, "dir_autochoose_everywhere");
+   dirDoNothingEverywhere = new KAction(i18n("No Operation for All Items"), 0, p, SLOT(slotNoOpEverywhere()), ac, "dir_nothing_everywhere");
+
+   dirCurrentDoNothing = new KAction(i18n("Do Nothing"), 0, p, SLOT(slotCurrentDoNothing()), ac, "dir_current_do_nothing");
+   dirCurrentChooseA = new KAction(i18n("A"), 0, p, SLOT(slotCurrentChooseA()), ac, "dir_current_choose_a");
+   dirCurrentChooseB = new KAction(i18n("B"), 0, p, SLOT(slotCurrentChooseB()), ac, "dir_current_choose_b");
+   dirCurrentChooseC = new KAction(i18n("C"), 0, p, SLOT(slotCurrentChooseC()), ac, "dir_current_choose_c");
+   dirCurrentMerge   = new KAction(i18n("Merge"), 0, p, SLOT(slotCurrentMerge()), ac, "dir_current_merge");
+   dirCurrentDelete  = new KAction(i18n("Delete (If Exists)"), 0, p, SLOT(slotCurrentDelete()), ac, "dir_current_delete");
+
+   dirCurrentSyncDoNothing = new KAction(i18n("Do Nothing"), 0, p, SLOT(slotCurrentDoNothing()), ac, "dir_current_sync_do_nothing");
+   dirCurrentSyncCopyAToB = new KAction(i18n("Copy A to B"), 0, p, SLOT(slotCurrentCopyAToB()), ac, "dir_current_sync_copy_a_to_b" );
+   dirCurrentSyncCopyBToA = new KAction(i18n("Copy B to A"), 0, p, SLOT(slotCurrentCopyBToA()), ac, "dir_current_sync_copy_b_to_a" );
+   dirCurrentSyncDeleteA  = new KAction(i18n("Delete A"), 0, p, SLOT(slotCurrentDeleteA()), ac,"dir_current_sync_delete_a");
+   dirCurrentSyncDeleteB  = new KAction(i18n("Delete B"), 0, p, SLOT(slotCurrentDeleteB()), ac,"dir_current_sync_delete_b");
+   dirCurrentSyncDeleteAAndB  = new KAction(i18n("Delete A and B"), 0, p, SLOT(slotCurrentDeleteAAndB()), ac,"dir_current_sync_delete_a_and_b");
+   dirCurrentSyncMergeToA   = new KAction(i18n("Merge to A"), 0, p, SLOT(slotCurrentMergeToA()), ac,"dir_current_sync_merge_to_a");
+   dirCurrentSyncMergeToB   = new KAction(i18n("Merge to B"), 0, p, SLOT(slotCurrentMergeToB()), ac,"dir_current_sync_merge_to_b");
+   dirCurrentSyncMergeToAAndB   = new KAction(i18n("Merge to A and B"), 0, p, SLOT(slotCurrentMergeToAAndB()), ac,"dir_current_sync_merge_to_a_and_b");
+}
+
+
+void DirectoryMergeWindow::updateAvailabilities( bool bDirCompare, bool bDiffWindowVisible )
+{
+   dirStartOperation->setEnabled( bDirCompare );
+   dirRunOperationForCurrentItem->setEnabled( bDirCompare );
+   dirFoldAll->setEnabled( bDirCompare );
+   dirUnfoldAll->setEnabled( bDirCompare );
+
+   dirCompareCurrent->setEnabled( bDirCompare  &&  isVisible()  &&  isFileSelected() );
+
+   dirMergeCurrent->setEnabled( bDirCompare  &&  isVisible()  &&  isFileSelected()
+                                || bDiffWindowVisible );
+
+   dirRescan->setEnabled( bDirCompare );
+
+   dirAutoChoiceEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   dirDoNothingEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   dirChooseAEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   dirChooseBEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   dirChooseCEverywhere->setEnabled( bDirCompare &&  isVisible() );
+
+   bool bThreeDirs = m_dirC.isValid();
+
+   QListViewItem* lvi = currentItem();
+   DirMergeItem* pDMI = lvi==0 ? 0 : static_cast<DirMergeItem*>(lvi);
+   MergeFileInfos* pMFI = pDMI==0 ? 0 : pDMI->m_pMFI;
+
+   bool bItemActive = bDirCompare &&  isVisible() && pMFI!=0;//  &&  hasFocus();
+   bool bMergeMode = bThreeDirs || !m_bSyncMode;
+   bool bFTConflict = pMFI==0 ? false : conflictingFileTypes(*pMFI);
+
+   dirCurrentDoNothing->setEnabled( bItemActive && bMergeMode );
+   dirCurrentChooseA->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInA );
+   dirCurrentChooseB->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInB );
+   dirCurrentChooseC->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInC );
+   dirCurrentMerge->setEnabled( bItemActive && bMergeMode && !bFTConflict );
+   dirCurrentDelete->setEnabled( bItemActive && bMergeMode );
+
+   dirCurrentSyncDoNothing->setEnabled( bItemActive && !bMergeMode );
+   dirCurrentSyncCopyAToB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA );
+   dirCurrentSyncCopyBToA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB );
+   dirCurrentSyncDeleteA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA );
+   dirCurrentSyncDeleteB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB );
+   dirCurrentSyncDeleteAAndB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB && pMFI->m_bExistsInB );
+   dirCurrentSyncMergeToA->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
+   dirCurrentSyncMergeToB->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
+   dirCurrentSyncMergeToAAndB->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
+}
+
+
 #include "directorymergewindow.moc"