You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3045 lines
104 KiB
3045 lines
104 KiB
/***************************************************************************
|
|
directorymergewindow.cpp
|
|
-----------------
|
|
begin : Sat Oct 19 2002
|
|
copyright : (C) 2002-2007 by Joachim Eibl
|
|
email : joachim.eibl at gmx.de
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "directorymergewindow.h"
|
|
#include "optiondialog.h"
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
#include <tqdir.h>
|
|
#include <tqapplication.h>
|
|
#include <tqpixmap.h>
|
|
#include <tqimage.h>
|
|
#include <kpopupmenu.h>
|
|
#include <kaction.h>
|
|
#include <tqregexp.h>
|
|
#include <tqmessagebox.h>
|
|
#include <tqlayout.h>
|
|
#include <tqlabel.h>
|
|
#include <tqtable.h>
|
|
#include <tqsplitter.h>
|
|
#include <tqtextedit.h>
|
|
#include <tqprogressdialog.h>
|
|
#include <kmessagebox.h>
|
|
#include <kfiledialog.h>
|
|
#include <kiconloader.h>
|
|
#include <klocale.h>
|
|
#include <iostream>
|
|
#include <assert.h>
|
|
//#include <konq_popupmenu.h>
|
|
|
|
static bool conflictingFileTypes(MergeFileInfos& mfi);
|
|
/*
|
|
class StatusInfo : public TQListView
|
|
{
|
|
public:
|
|
StatusInfo(TQWidget* pParent) : TQListView( pParent, "StatusInfo", TQt::WShowModal )
|
|
{
|
|
addColumn("");
|
|
setSorting(-1); //disable sorting
|
|
}
|
|
|
|
TQListViewItem* m_pLast;
|
|
TQListViewItem* last()
|
|
{
|
|
if (firstChild()==0) return 0;
|
|
else return m_pLast;
|
|
}
|
|
|
|
void addText(const TQString& s )
|
|
{
|
|
if (firstChild()==0) m_pLast = new TQListViewItem( this, s );
|
|
else m_pLast = new TQListViewItem( this, last(), s );
|
|
}
|
|
};
|
|
*/
|
|
class StatusInfo : public TQTextEdit
|
|
{
|
|
public:
|
|
StatusInfo(TQWidget* pParent) : TQTextEdit( pParent, "StatusInfo" )
|
|
{
|
|
setWFlags(TQt::WShowModal);
|
|
setWordWrap(TQTextEdit::NoWrap);
|
|
setReadOnly(true);
|
|
//showMaximized();
|
|
}
|
|
|
|
bool isEmpty(){ return text().isEmpty(); }
|
|
|
|
void addText(const TQString& s )
|
|
{
|
|
append(s);
|
|
}
|
|
|
|
void show()
|
|
{
|
|
scrollToBottom();
|
|
TQTextEdit::show();
|
|
}
|
|
};
|
|
|
|
|
|
class TempRemover
|
|
{
|
|
public:
|
|
TempRemover( const TQString& origName, FileAccess& fa );
|
|
~TempRemover();
|
|
TQString name() { return m_name; }
|
|
bool success() { return m_bSuccess; }
|
|
private:
|
|
TQString m_name;
|
|
bool m_bTemp;
|
|
bool m_bSuccess;
|
|
};
|
|
TempRemover::TempRemover(const TQString& origName, FileAccess& fa)
|
|
{
|
|
if ( fa.isLocal() )
|
|
{
|
|
m_name = origName;
|
|
m_bTemp = false;
|
|
m_bSuccess = true;
|
|
}
|
|
else
|
|
{
|
|
m_name = FileAccess::tempFileName();
|
|
m_bSuccess = fa.copyFile( m_name );
|
|
m_bTemp = m_bSuccess;
|
|
}
|
|
}
|
|
TempRemover::~TempRemover()
|
|
{
|
|
if ( m_bTemp && ! m_name.isEmpty() )
|
|
FileAccess::removeTempFile(m_name);
|
|
}
|
|
|
|
void DirectoryMergeWindow::fastFileComparison(
|
|
FileAccess& fi1, FileAccess& fi2,
|
|
bool& bEqual, bool& bError, TQString& status )
|
|
{
|
|
ProgressProxy pp;
|
|
status = "";
|
|
bEqual = false;
|
|
bError = true;
|
|
|
|
if ( !m_bFollowFileLinks )
|
|
{
|
|
if ( fi1.isSymLink() != fi2.isSymLink() )
|
|
{
|
|
status = i18n("Mix of links and normal files.");
|
|
return;
|
|
}
|
|
else if ( fi1.isSymLink() && fi2.isSymLink() )
|
|
{
|
|
bError = false;
|
|
bEqual = fi1.readLink() == fi2.readLink();
|
|
status = i18n("Link: ");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( fi1.size()!=fi2.size() )
|
|
{
|
|
bEqual = false;
|
|
status = i18n("Size. ");
|
|
return;
|
|
}
|
|
else if ( m_pOptions->m_bDmTrustSize )
|
|
{
|
|
bEqual = true;
|
|
return;
|
|
}
|
|
|
|
if ( m_pOptions->m_bDmTrustDate )
|
|
{
|
|
bEqual = ( fi1.lastModified() == fi2.lastModified() && fi1.size()==fi2.size() );
|
|
bError = false;
|
|
status = i18n("Date & Size: ");
|
|
return;
|
|
}
|
|
|
|
if ( m_pOptions->m_bDmTrustDateFallbackToBinary )
|
|
{
|
|
bEqual = ( fi1.lastModified() == fi2.lastModified() && fi1.size()==fi2.size() );
|
|
if ( bEqual )
|
|
{
|
|
bError = false;
|
|
status = i18n("Date & Size: ");
|
|
return;
|
|
}
|
|
}
|
|
|
|
TQString fileName1 = fi1.absFilePath();
|
|
TQString fileName2 = fi2.absFilePath();
|
|
TempRemover tr1( fileName1, fi1 );
|
|
if ( !tr1.success() )
|
|
{
|
|
status = i18n("Creating temp copy of %1 failed.").tqarg(fileName1);
|
|
return;
|
|
}
|
|
TempRemover tr2( fileName2, fi2 );
|
|
if ( !tr2.success() )
|
|
{
|
|
status = i18n("Creating temp copy of %1 failed.").tqarg(fileName2);
|
|
return;
|
|
}
|
|
|
|
std::vector<char> buf1(100000);
|
|
std::vector<char> buf2(buf1.size());
|
|
|
|
TQFile file1( tr1.name() );
|
|
|
|
if ( ! file1.open(IO_ReadOnly) )
|
|
{
|
|
status = i18n("Opening %1 failed.").tqarg(fileName1);
|
|
return;
|
|
}
|
|
|
|
TQFile file2( tr2.name() );
|
|
|
|
if ( ! file2.open(IO_ReadOnly) )
|
|
{
|
|
status = i18n("Opening %1 failed.").tqarg(fileName2);
|
|
return;
|
|
}
|
|
|
|
pp.setInformation( i18n("Comparing file..."), 0, false );
|
|
#ifdef USE_QT4
|
|
typedef qint64 t_FileSize;
|
|
#else // USE_QT4
|
|
typedef TQFile::Offset t_FileSize;
|
|
#endif // USE_QT4
|
|
t_FileSize fullSize = file1.size();
|
|
t_FileSize sizeLeft = fullSize;
|
|
|
|
while( sizeLeft>0 && ! pp.wasCancelled() )
|
|
{
|
|
int len = min2( sizeLeft, (t_FileSize)buf1.size() );
|
|
if( len != file1.readBlock( &buf1[0], len ) )
|
|
{
|
|
status = i18n("Error reading from %1").tqarg(fileName1);
|
|
return;
|
|
}
|
|
|
|
if( len != file2.readBlock( &buf2[0], len ) )
|
|
{
|
|
status = i18n("Error reading from %1").tqarg(fileName2);
|
|
return;
|
|
}
|
|
|
|
if ( memcmp( &buf1[0], &buf2[0], len ) != 0 )
|
|
{
|
|
bError = false;
|
|
return;
|
|
}
|
|
sizeLeft-=len;
|
|
pp.setCurrent(double(fullSize-sizeLeft)/fullSize, false );
|
|
}
|
|
|
|
// If the program really arrives here, then the files are really equal.
|
|
bError = false;
|
|
bEqual = true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int s_nameCol = 0;
|
|
static int s_ACol = 1;
|
|
static int s_BCol = 2;
|
|
static int s_CCol = 3;
|
|
static int s_OpCol = 4;
|
|
static int s_OpStatusCol = 5;
|
|
static int s_UnsolvedCol = 6; // Nr of unsolved conflicts (for 3 input files)
|
|
static int s_SolvedCol = 7; // Nr of auto-solvable conflicts (for 3 input files)
|
|
static int s_NonWhiteCol = 8; // Nr of nonwhite deltas (for 2 input files)
|
|
static int s_WhiteCol = 9; // Nr of white deltas (for 2 input files)
|
|
DirectoryMergeWindow::DirectoryMergeWindow( TQWidget* pParent, OptionDialog* pOptions, KIconLoader* pIconLoader )
|
|
: TQListView( pParent )
|
|
{
|
|
connect( TQT_TQOBJECT(this), TQT_SIGNAL(doubleClicked(TQListViewItem*)), TQT_TQOBJECT(this), TQT_SLOT(onDoubleClick(TQListViewItem*)));
|
|
connect( TQT_TQOBJECT(this), TQT_SIGNAL(returnPressed(TQListViewItem*)), TQT_TQOBJECT(this), TQT_SLOT(onDoubleClick(TQListViewItem*)));
|
|
connect( TQT_TQOBJECT(this), TQT_SIGNAL( mouseButtonPressed(int,TQListViewItem*,const TQPoint&, int)),
|
|
TQT_TQOBJECT(this), TQT_SLOT( onClick(int,TQListViewItem*,const TQPoint&, int)) );
|
|
connect( TQT_TQOBJECT(this), TQT_SIGNAL(contextMenuRequested(TQListViewItem*,const TQPoint &,int)),
|
|
TQT_TQOBJECT(this), TQT_SLOT( slotShowContextMenu(TQListViewItem*,const TQPoint &,int)));
|
|
connect( TQT_TQOBJECT(this), TQT_SIGNAL(selectionChanged(TQListViewItem*)), TQT_TQOBJECT(this), TQT_SLOT(onSelectionChanged(TQListViewItem*)));
|
|
m_pOptions = pOptions;
|
|
m_pIconLoader = pIconLoader;
|
|
m_pDirectoryMergeInfo = 0;
|
|
m_bAllowResizeEvents = true;
|
|
m_bSimulatedMergeStarted=false;
|
|
m_bRealMergeStarted=false;
|
|
m_bError = false;
|
|
m_bSyncMode = false;
|
|
m_pStatusInfo = new StatusInfo(0);
|
|
m_pStatusInfo->hide();
|
|
m_bScanning = false;
|
|
m_pSelection1Item = 0;
|
|
m_pSelection2Item = 0;
|
|
m_pSelection3Item = 0;
|
|
m_bCaseSensitive = true;
|
|
|
|
addColumn(i18n("Name"));
|
|
addColumn("A");
|
|
addColumn("B");
|
|
addColumn("C");
|
|
addColumn(i18n("Operation"));
|
|
addColumn(i18n("tqStatus"));
|
|
addColumn(i18n("Unsolved"));
|
|
addColumn(i18n("Solved"));
|
|
addColumn(i18n("Nonwhite"));
|
|
addColumn(i18n("White"));
|
|
|
|
setColumnAlignment( s_UnsolvedCol, TQt::AlignRight );
|
|
setColumnAlignment( s_SolvedCol, TQt::AlignRight );
|
|
setColumnAlignment( s_NonWhiteCol, TQt::AlignRight );
|
|
setColumnAlignment( s_WhiteCol, TQt::AlignRight );
|
|
}
|
|
|
|
DirectoryMergeWindow::~DirectoryMergeWindow()
|
|
{
|
|
}
|
|
|
|
|
|
int DirectoryMergeWindow::totalColumnWidth()
|
|
{
|
|
int w=0;
|
|
for (int i=0; i<s_OpStatusCol; ++i)
|
|
{
|
|
w += columnWidth(i);
|
|
}
|
|
return w;
|
|
}
|
|
|
|
void DirectoryMergeWindow::reload()
|
|
{
|
|
if ( isDirectoryMergeInProgress() )
|
|
{
|
|
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("Rescan"), i18n("Continue Merging") );
|
|
if ( result!=KMessageBox::Yes )
|
|
return;
|
|
}
|
|
|
|
init( m_dirA, m_dirB, m_dirC, m_dirDest, m_bDirectoryMerge, true );
|
|
}
|
|
|
|
// Copy pm2 onto pm1, but preserve the alpha value from pm1 where pm2 is transparent.
|
|
static TQPixmap pixCombiner( const TQPixmap* pm1, const TQPixmap* pm2 )
|
|
{
|
|
TQImage img1 = pm1->convertToImage().convertDepth(32);
|
|
TQImage img2 = pm2->convertToImage().convertDepth(32);
|
|
|
|
for (int y = 0; y < img1.height(); y++)
|
|
{
|
|
TQ_UINT32 *line1 = reinterpret_cast<TQ_UINT32 *>(img1.scanLine(y));
|
|
TQ_UINT32 *line2 = reinterpret_cast<TQ_UINT32 *>(img2.scanLine(y));
|
|
for (int x = 0; x < img1.width(); x++)
|
|
{
|
|
if ( tqAlpha( line2[x] ) >0 )
|
|
line1[x] = (line2[x] | 0xff000000);
|
|
}
|
|
}
|
|
TQPixmap pix;
|
|
pix.convertFromImage(img1);
|
|
return pix;
|
|
}
|
|
|
|
// like pixCombiner but let the pm1 color shine through
|
|
static TQPixmap pixCombiner2( const TQPixmap* pm1, const TQPixmap* pm2 )
|
|
{
|
|
TQImage img1 = pm1->convertToImage().convertDepth(32);
|
|
TQImage img2 = pm2->convertToImage().convertDepth(32);
|
|
|
|
for (int y = 0; y < img1.height(); y++)
|
|
{
|
|
TQ_UINT32 *line1 = reinterpret_cast<TQ_UINT32 *>(img1.scanLine(y));
|
|
TQ_UINT32 *line2 = reinterpret_cast<TQ_UINT32 *>(img2.scanLine(y));
|
|
for (int x = 0; x < img1.width(); x++)
|
|
{
|
|
if ( tqAlpha( line2[x] ) >0 )
|
|
{
|
|
int r = ( tqRed( line1[x] ) + tqRed( line2[x] ))/2;
|
|
int g = ( tqGreen( line1[x] ) + tqGreen( line2[x] ))/2;
|
|
int b = ( tqBlue( line1[x] ) + tqBlue( line2[x] ))/2;
|
|
line1[x] = tqRgba( r,g,b, 0xff );
|
|
}
|
|
}
|
|
}
|
|
TQPixmap pix;
|
|
pix.convertFromImage(img1);
|
|
return pix;
|
|
}
|
|
|
|
static void calcDirtqStatus( bool bThreeDirs, DirMergeItem* i, int& nofFiles,
|
|
int& nofDirs, int& nofEqualFiles, int& nofManualMerges )
|
|
{
|
|
if ( i->m_pMFI->m_bDirA || i->m_pMFI->m_bDirB || i->m_pMFI->m_bDirC )
|
|
{
|
|
++nofDirs;
|
|
}
|
|
else
|
|
{
|
|
++nofFiles;
|
|
if ( i->m_pMFI->m_bEqualAB && (!bThreeDirs || i->m_pMFI->m_bEqualAC ))
|
|
{
|
|
++nofEqualFiles;
|
|
}
|
|
else
|
|
{
|
|
if ( i->m_pMFI->m_eMergeOperation==eMergeABCToDest || i->m_pMFI->m_eMergeOperation==eMergeABToDest )
|
|
++nofManualMerges;
|
|
}
|
|
}
|
|
for( TQListViewItem* p = i->firstChild(); p!=0; p = p->nextSibling() )
|
|
calcDirtqStatus( bThreeDirs, static_cast<DirMergeItem*>(p), nofFiles, nofDirs, nofEqualFiles, nofManualMerges );
|
|
}
|
|
|
|
static TQString sortString(const TQString& s, bool bCaseSensitive)
|
|
{
|
|
if (bCaseSensitive)
|
|
return s;
|
|
else
|
|
return s.upper();
|
|
}
|
|
|
|
struct t_ItemInfo
|
|
{
|
|
bool bExpanded;
|
|
bool bOperationComplete;
|
|
TQString status;
|
|
e_MergeOperation eMergeOperation;
|
|
};
|
|
|
|
bool DirectoryMergeWindow::init
|
|
(
|
|
FileAccess& dirA,
|
|
FileAccess& dirB,
|
|
FileAccess& dirC,
|
|
FileAccess& dirDest,
|
|
bool bDirectoryMerge,
|
|
bool bReload
|
|
)
|
|
{
|
|
if ( m_pOptions->m_bDmFullAnalysis )
|
|
{
|
|
// A full analysis uses the same ressources that a normal text-diff/merge uses.
|
|
// So make sure that the user saves his data first.
|
|
bool bCanContinue=false;
|
|
checkIfCanContinue( &bCanContinue );
|
|
if ( !bCanContinue )
|
|
return false;
|
|
startDiffMerge("","","","","","","",0); // hide main window
|
|
}
|
|
|
|
show();
|
|
|
|
std::map<TQString,t_ItemInfo> expandedDirsMap;
|
|
|
|
if ( bReload )
|
|
{
|
|
// Remember expandes items
|
|
TQListViewItemIterator it( this );
|
|
while ( it.current() )
|
|
{
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>( it.current() );
|
|
t_ItemInfo& ii = expandedDirsMap[ pDMI->m_pMFI->m_subPath ];
|
|
ii.bExpanded = pDMI->isOpen();
|
|
ii.bOperationComplete = pDMI->m_pMFI->m_bOperationComplete;
|
|
ii.status = pDMI->text( s_OpStatusCol );
|
|
ii.eMergeOperation = pDMI->m_pMFI->m_eMergeOperation;
|
|
++it;
|
|
}
|
|
}
|
|
|
|
ProgressProxy pp;
|
|
m_bFollowDirLinks = m_pOptions->m_bDmFollowDirLinks;
|
|
m_bFollowFileLinks = m_pOptions->m_bDmFollowFileLinks;
|
|
m_bSimulatedMergeStarted=false;
|
|
m_bRealMergeStarted=false;
|
|
m_bError=false;
|
|
m_bDirectoryMerge = bDirectoryMerge;
|
|
m_pSelection1Item = 0;
|
|
m_pSelection2Item = 0;
|
|
m_pSelection3Item = 0;
|
|
m_bCaseSensitive = m_pOptions->m_bDmCaseSensitiveFilenameComparison;
|
|
|
|
clear();
|
|
|
|
m_mergeItemList.clear();
|
|
m_currentItemForOperation = m_mergeItemList.end();
|
|
|
|
m_dirA = dirA;
|
|
m_dirB = dirB;
|
|
m_dirC = dirC;
|
|
m_dirDest = dirDest;
|
|
|
|
if ( !bReload )
|
|
{
|
|
m_pDirShowIdenticalFiles->setChecked(true);
|
|
m_pDirShowDifferentFiles->setChecked(true);
|
|
m_pDirShowFilesOnlyInA->setChecked(true);
|
|
m_pDirShowFilesOnlyInB->setChecked(true);
|
|
m_pDirShowFilesOnlyInC->setChecked(true);
|
|
}
|
|
|
|
// Check if all input directories exist and are valid. The dest dir is not tested now.
|
|
// The test will happen only when we are going to write to it.
|
|
if ( !m_dirA.isDir() || !m_dirB.isDir() ||
|
|
(m_dirC.isValid() && !m_dirC.isDir()) )
|
|
{
|
|
TQString text( i18n("Opening of directories failed:") );
|
|
text += "\n\n";
|
|
if ( !dirA.isDir() )
|
|
{ text += i18n("Dir A \"%1\" does not exist or is not a directory.\n").tqarg(m_dirA.prettyAbsPath()); }
|
|
|
|
if ( !dirB.isDir() )
|
|
{ text += i18n("Dir B \"%1\" does not exist or is not a directory.\n").tqarg(m_dirB.prettyAbsPath()); }
|
|
|
|
if ( m_dirC.isValid() && !m_dirC.isDir() )
|
|
{ text += i18n("Dir C \"%1\" does not exist or is not a directory.\n").tqarg(m_dirC.prettyAbsPath()); }
|
|
|
|
KMessageBox::sorry( this, text, i18n("Directory Open Error") );
|
|
return false;
|
|
}
|
|
|
|
if ( m_dirC.isValid() &&
|
|
(m_dirDest.prettyAbsPath() == m_dirA.prettyAbsPath() || m_dirDest.prettyAbsPath()==m_dirB.prettyAbsPath() ) )
|
|
{
|
|
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."),
|
|
i18n("Parameter Warning"));
|
|
return false;
|
|
}
|
|
|
|
m_bScanning = true;
|
|
statusBarMessage(i18n("Scanning directories..."));
|
|
|
|
m_bSyncMode = m_pOptions->m_bDmSyncMode && !m_dirC.isValid() && !m_dirDest.isValid();
|
|
|
|
if ( m_dirDest.isValid() )
|
|
m_dirDestInternal = m_dirDest;
|
|
else
|
|
m_dirDestInternal = m_dirC.isValid() ? m_dirC : m_dirB;
|
|
|
|
TQString origCurrentDirectory = TQDir::currentDirPath();
|
|
|
|
m_fileMergeMap.clear();
|
|
t_DirectoryList::iterator i;
|
|
|
|
// calc how many directories will be read:
|
|
double nofScans = ( m_dirA.isValid() ? 1 : 0 )+( m_dirB.isValid() ? 1 : 0 )+( m_dirC.isValid() ? 1 : 0 );
|
|
int currentScan = 0;
|
|
|
|
setColumnWidthMode(s_UnsolvedCol, TQListView::Manual);
|
|
setColumnWidthMode(s_SolvedCol, TQListView::Manual);
|
|
setColumnWidthMode(s_WhiteCol, TQListView::Manual);
|
|
setColumnWidthMode(s_NonWhiteCol, TQListView::Manual);
|
|
if ( !m_pOptions->m_bDmFullAnalysis )
|
|
{
|
|
setColumnWidth( s_WhiteCol, 0 );
|
|
setColumnWidth( s_NonWhiteCol, 0 );
|
|
setColumnWidth( s_UnsolvedCol, 0 );
|
|
setColumnWidth( s_SolvedCol, 0 );
|
|
}
|
|
else if ( m_dirC.isValid() )
|
|
{
|
|
setColumnWidth(s_WhiteCol, 50 );
|
|
setColumnWidth(s_NonWhiteCol, 50 );
|
|
setColumnWidth(s_UnsolvedCol, 50 );
|
|
setColumnWidth(s_SolvedCol, 50 );
|
|
}
|
|
else
|
|
{
|
|
setColumnWidth(s_WhiteCol, 50 );
|
|
setColumnWidth(s_NonWhiteCol, 50 );
|
|
setColumnWidth(s_UnsolvedCol, 50 );
|
|
setColumnWidth(s_SolvedCol, 0 );
|
|
}
|
|
|
|
bool bListDirSuccessA = true;
|
|
bool bListDirSuccessB = true;
|
|
bool bListDirSuccessC = true;
|
|
if ( m_dirA.isValid() )
|
|
{
|
|
pp.setInformation(i18n("Reading Directory A"));
|
|
pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
|
|
++currentScan;
|
|
|
|
t_DirectoryList dirListA;
|
|
bListDirSuccessA = m_dirA.listDir( &dirListA,
|
|
m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden,
|
|
m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern,
|
|
m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks,
|
|
m_pOptions->m_bDmUseCvsIgnore);
|
|
|
|
for (i=dirListA.begin(); i!=dirListA.end();++i )
|
|
{
|
|
MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(), m_bCaseSensitive)];
|
|
//std::cout <<i->filePath()<<std::endl;
|
|
mfi.m_bExistsInA = true;
|
|
mfi.m_fileInfoA = *i;
|
|
}
|
|
}
|
|
|
|
if ( m_dirB.isValid() )
|
|
{
|
|
pp.setInformation(i18n("Reading Directory B"));
|
|
pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
|
|
++currentScan;
|
|
|
|
t_DirectoryList dirListB;
|
|
bListDirSuccessB = m_dirB.listDir( &dirListB,
|
|
m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden,
|
|
m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern,
|
|
m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks,
|
|
m_pOptions->m_bDmUseCvsIgnore);
|
|
|
|
for (i=dirListB.begin(); i!=dirListB.end();++i )
|
|
{
|
|
MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(), m_bCaseSensitive)];
|
|
mfi.m_bExistsInB = true;
|
|
mfi.m_fileInfoB = *i;
|
|
}
|
|
}
|
|
|
|
e_MergeOperation eDefaultMergeOp;
|
|
if ( m_dirC.isValid() )
|
|
{
|
|
pp.setInformation(i18n("Reading Directory C"));
|
|
pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
|
|
++currentScan;
|
|
|
|
t_DirectoryList dirListC;
|
|
bListDirSuccessC = m_dirC.listDir( &dirListC,
|
|
m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden,
|
|
m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern,
|
|
m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks,
|
|
m_pOptions->m_bDmUseCvsIgnore);
|
|
|
|
for (i=dirListC.begin(); i!=dirListC.end();++i )
|
|
{
|
|
MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(),m_bCaseSensitive)];
|
|
mfi.m_bExistsInC = true;
|
|
mfi.m_fileInfoC = *i;
|
|
}
|
|
|
|
eDefaultMergeOp = eMergeABCToDest;
|
|
}
|
|
else
|
|
eDefaultMergeOp = m_bSyncMode ? eMergeToAB : eMergeABToDest;
|
|
|
|
bool bContinue = true;
|
|
if ( !bListDirSuccessA || !bListDirSuccessB || !bListDirSuccessC )
|
|
{
|
|
TQString s = i18n("Some subdirectories were not readable in");
|
|
if ( !bListDirSuccessA ) s += "\nA: " + m_dirA.prettyAbsPath();
|
|
if ( !bListDirSuccessB ) s += "\nB: " + m_dirB.prettyAbsPath();
|
|
if ( !bListDirSuccessC ) s += "\nC: " + m_dirC.prettyAbsPath();
|
|
s+="\n";
|
|
s+= i18n("Check the permissions of the subdirectories.");
|
|
bContinue = KMessageBox::Continue == KMessageBox::warningContinueCancel( this, s );
|
|
}
|
|
|
|
if ( bContinue )
|
|
{
|
|
prepareListView(pp);
|
|
|
|
for( TQListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
|
|
{
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>( p );
|
|
calcSuggestedOperation( *pDMI->m_pMFI, eDefaultMergeOp );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setSelected( 0, true );
|
|
}
|
|
|
|
TQDir::setCurrent(origCurrentDirectory);
|
|
|
|
// Try to improve the view a little bit.
|
|
TQWidget* pParent = parentWidget();
|
|
TQSplitter* pSplitter = static_cast<TQSplitter*>(pParent);
|
|
if (pSplitter!=0)
|
|
{
|
|
TQValueList<int> sizes = pSplitter->sizes();
|
|
int total = sizes[0] + sizes[1];
|
|
sizes[0]=total*6/10;
|
|
sizes[1]=total - sizes[0];
|
|
pSplitter->setSizes( sizes );
|
|
}
|
|
|
|
m_bScanning = false;
|
|
statusBarMessage(i18n("Ready."));
|
|
|
|
if ( bContinue )
|
|
{
|
|
// Generate a status report
|
|
int nofFiles=0;
|
|
int nofDirs=0;
|
|
int nofEqualFiles=0;
|
|
int nofManualMerges=0;
|
|
for( TQListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
|
|
calcDirtqStatus( m_dirC.isValid(), static_cast<DirMergeItem*>(p),
|
|
nofFiles, nofDirs, nofEqualFiles, nofManualMerges );
|
|
|
|
TQString s;
|
|
s = i18n("Directory Comparison tqStatus") + "\n\n" +
|
|
i18n("Number of subdirectories:") +" "+ TQString::number(nofDirs) + "\n"+
|
|
i18n("Number of equal files:") +" "+ TQString::number(nofEqualFiles) + "\n"+
|
|
i18n("Number of different files:") +" "+ TQString::number(nofFiles-nofEqualFiles);
|
|
|
|
if ( m_dirC.isValid() )
|
|
s += "\n" + i18n("Number of manual merges:") +" "+ TQString::number(nofManualMerges);
|
|
KMessageBox::information( this, s );
|
|
setSelected( firstChild(), true );
|
|
}
|
|
|
|
updateFileVisibilities();
|
|
if ( bReload )
|
|
{
|
|
// Remember expandes items
|
|
TQListViewItemIterator it( this );
|
|
while ( it.current() )
|
|
{
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>( it.current() );
|
|
std::map<TQString,t_ItemInfo>::iterator i = expandedDirsMap.find( pDMI->m_pMFI->m_subPath );
|
|
if ( i!=expandedDirsMap.end() )
|
|
{
|
|
t_ItemInfo& ii = i->second;
|
|
pDMI->setOpen( ii.bExpanded );
|
|
pDMI->m_pMFI->setMergeOperation( ii.eMergeOperation, false );
|
|
pDMI->m_pMFI->m_bOperationComplete = ii.bOperationComplete;
|
|
pDMI->setText( s_OpStatusCol, ii.status );
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
void DirectoryMergeWindow::slotChooseAEverywhere(){ setAllMergeOperations( eCopyAToDest ); }
|
|
|
|
void DirectoryMergeWindow::slotChooseBEverywhere(){ setAllMergeOperations( eCopyBToDest ); }
|
|
|
|
void DirectoryMergeWindow::slotChooseCEverywhere(){ setAllMergeOperations( eCopyCToDest ); }
|
|
|
|
void DirectoryMergeWindow::slotAutoChooseEverywhere()
|
|
{
|
|
e_MergeOperation eDefaultMergeOp = m_dirC.isValid() ? eMergeABCToDest :
|
|
m_bSyncMode ? eMergeToAB : eMergeABToDest;
|
|
setAllMergeOperations(eDefaultMergeOp );
|
|
}
|
|
|
|
void DirectoryMergeWindow::slotNoOpEverywhere(){ setAllMergeOperations(eNoOperation); }
|
|
|
|
static void setListViewItemOpen( TQListViewItem* p, bool bOpen )
|
|
{
|
|
for( TQListViewItem* pChild = p->firstChild(); pChild!=0; pChild = pChild->nextSibling() )
|
|
setListViewItemOpen( pChild, bOpen );
|
|
|
|
p->setOpen( bOpen );
|
|
}
|
|
|
|
void DirectoryMergeWindow::slotFoldAllSubdirs()
|
|
{
|
|
for( TQListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
|
|
setListViewItemOpen( p, false );
|
|
}
|
|
|
|
void DirectoryMergeWindow::slotUnfoldAllSubdirs()
|
|
{
|
|
for( TQListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
|
|
setListViewItemOpen( p, true );
|
|
}
|
|
|
|
static void setMergeOperation( TQListViewItem* 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(), m_bSyncMode ? eCopyAToB : eCopyAToDest ); }
|
|
void DirectoryMergeWindow::slotCurrentChooseB() { setMergeOperation(currentItem(), m_bSyncMode ? eCopyBToA : 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( TQKeyEvent* e )
|
|
{
|
|
if ( (e->state() & TQt::ControlButton)!=0 )
|
|
{
|
|
bool bThreeDirs = m_dirC.isValid();
|
|
|
|
TQListViewItem* 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
TQListView::keyPressEvent(e);
|
|
}
|
|
|
|
void DirectoryMergeWindow::focusInEvent(TQFocusEvent*)
|
|
{
|
|
updateAvailabilities();
|
|
}
|
|
void DirectoryMergeWindow::focusOutEvent(TQFocusEvent*)
|
|
{
|
|
updateAvailabilities();
|
|
}
|
|
|
|
void DirectoryMergeWindow::setAllMergeOperations( e_MergeOperation eDefaultOperation )
|
|
{
|
|
if ( KMessageBox::Yes == KMessageBox::warningYesNo(this,
|
|
i18n("This affects all merge operations."),
|
|
i18n("Changing All Merge Operations"),i18n("C&ontinue"), i18n("&Cancel") ) )
|
|
{
|
|
for( TQListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
|
|
{
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>( p );
|
|
calcSuggestedOperation( *pDMI->m_pMFI, eDefaultOperation );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void DirectoryMergeWindow::compareFilesAndCalcAges( MergeFileInfos& mfi )
|
|
{
|
|
std::map<TQDateTime,int> dateMap;
|
|
|
|
if( mfi.m_bExistsInA )
|
|
{
|
|
mfi.m_bLinkA = mfi.m_fileInfoA.isSymLink();
|
|
mfi.m_bDirA = mfi.m_fileInfoA.isDir();
|
|
dateMap[ mfi.m_fileInfoA.lastModified() ] = 0;
|
|
}
|
|
if( mfi.m_bExistsInB )
|
|
{
|
|
mfi.m_bLinkB = mfi.m_fileInfoB.isSymLink();
|
|
mfi.m_bDirB = mfi.m_fileInfoB.isDir();
|
|
dateMap[ mfi.m_fileInfoB.lastModified() ] = 1;
|
|
}
|
|
if( mfi.m_bExistsInC )
|
|
{
|
|
mfi.m_bLinkC = mfi.m_fileInfoC.isSymLink();
|
|
mfi.m_bDirC = mfi.m_fileInfoC.isDir();
|
|
dateMap[ mfi.m_fileInfoC.lastModified() ] = 2;
|
|
}
|
|
|
|
if ( m_pOptions->m_bDmFullAnalysis )
|
|
{
|
|
if( mfi.m_bExistsInA && mfi.m_bDirA || mfi.m_bExistsInB && mfi.m_bDirB || mfi.m_bExistsInC && mfi.m_bDirC )
|
|
{
|
|
// If any input is a directory, don't start any comparison.
|
|
mfi.m_bEqualAB=mfi.m_bExistsInA && mfi.m_bExistsInB;
|
|
mfi.m_bEqualAC=mfi.m_bExistsInA && mfi.m_bExistsInC;
|
|
mfi.m_bEqualBC=mfi.m_bExistsInB && mfi.m_bExistsInC;
|
|
}
|
|
else
|
|
{
|
|
emit startDiffMerge(
|
|
mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : TQString(""),
|
|
mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : TQString(""),
|
|
mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : TQString(""),
|
|
"",
|
|
"","","",&mfi.m_totalDifftqStatus
|
|
);
|
|
int nofNonwhiteConflicts = mfi.m_totalDifftqStatus.nofUnsolvedConflicts +
|
|
mfi.m_totalDifftqStatus.nofSolvedConflicts - mfi.m_totalDifftqStatus.nofWhitespaceConflicts;
|
|
|
|
if (m_pOptions->m_bDmWhiteSpaceEqual && nofNonwhiteConflicts == 0)
|
|
{
|
|
mfi.m_bEqualAB = mfi.m_bExistsInA && mfi.m_bExistsInB;
|
|
mfi.m_bEqualAC = mfi.m_bExistsInA && mfi.m_bExistsInC;
|
|
mfi.m_bEqualBC = mfi.m_bExistsInB && mfi.m_bExistsInC;
|
|
}
|
|
else
|
|
{
|
|
mfi.m_bEqualAB = mfi.m_totalDifftqStatus.bBinaryAEqB;
|
|
mfi.m_bEqualBC = mfi.m_totalDifftqStatus.bBinaryBEqC;
|
|
mfi.m_bEqualAC = mfi.m_totalDifftqStatus.bBinaryAEqC;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool bError;
|
|
TQString eqtqStatus;
|
|
if( mfi.m_bExistsInA && mfi.m_bExistsInB )
|
|
{
|
|
if( mfi.m_bDirA ) mfi.m_bEqualAB=true;
|
|
else fastFileComparison( mfi.m_fileInfoA, mfi.m_fileInfoB, mfi.m_bEqualAB, bError, eqtqStatus );
|
|
}
|
|
if( mfi.m_bExistsInA && mfi.m_bExistsInC )
|
|
{
|
|
if( mfi.m_bDirA ) mfi.m_bEqualAC=true;
|
|
else fastFileComparison( mfi.m_fileInfoA, mfi.m_fileInfoC, mfi.m_bEqualAC, bError, eqtqStatus );
|
|
}
|
|
if( mfi.m_bExistsInB && mfi.m_bExistsInC )
|
|
{
|
|
if (mfi.m_bEqualAB && mfi.m_bEqualAC)
|
|
mfi.m_bEqualBC = true;
|
|
else
|
|
{
|
|
if( mfi.m_bDirB ) mfi.m_bEqualBC=true;
|
|
else fastFileComparison( mfi.m_fileInfoB, mfi.m_fileInfoC, mfi.m_bEqualBC, bError, eqtqStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mfi.m_bLinkA!=mfi.m_bLinkB) mfi.m_bEqualAB=false;
|
|
if (mfi.m_bLinkA!=mfi.m_bLinkC) mfi.m_bEqualAC=false;
|
|
if (mfi.m_bLinkB!=mfi.m_bLinkC) mfi.m_bEqualBC=false;
|
|
|
|
if (mfi.m_bDirA!=mfi.m_bDirB) mfi.m_bEqualAB=false;
|
|
if (mfi.m_bDirA!=mfi.m_bDirC) mfi.m_bEqualAC=false;
|
|
if (mfi.m_bDirB!=mfi.m_bDirC) mfi.m_bEqualBC=false;
|
|
|
|
assert(eNew==0 && eMiddle==1 && eOld==2);
|
|
|
|
// The map automatically sorts the keys.
|
|
int age = eNew;
|
|
std::map<TQDateTime,int>::reverse_iterator i;
|
|
for( i=dateMap.rbegin(); i!=dateMap.rend(); ++i )
|
|
{
|
|
int n = i->second;
|
|
if ( n==0 && mfi.m_ageA==eNotThere )
|
|
{
|
|
mfi.m_ageA = (e_Age)age; ++age;
|
|
if ( mfi.m_bEqualAB ) { mfi.m_ageB = mfi.m_ageA; ++age; }
|
|
if ( mfi.m_bEqualAC ) { mfi.m_ageC = mfi.m_ageA; ++age; }
|
|
}
|
|
else if ( n==1 && mfi.m_ageB==eNotThere )
|
|
{
|
|
mfi.m_ageB = (e_Age)age; ++age;
|
|
if ( mfi.m_bEqualAB ) { mfi.m_ageA = mfi.m_ageB; ++age; }
|
|
if ( mfi.m_bEqualBC ) { mfi.m_ageC = mfi.m_ageB; ++age; }
|
|
}
|
|
else if ( n==2 && mfi.m_ageC==eNotThere)
|
|
{
|
|
mfi.m_ageC = (e_Age)age; ++age;
|
|
if ( mfi.m_bEqualAC ) { mfi.m_ageA = mfi.m_ageC; ++age; }
|
|
if ( mfi.m_bEqualBC ) { mfi.m_ageB = mfi.m_ageC; ++age; }
|
|
}
|
|
}
|
|
|
|
// The checks below are necessary when the dates of the file are equal but the
|
|
// files are not. One wouldn't expect this to happen, yet it happens sometimes.
|
|
if ( mfi.m_bExistsInC && mfi.m_ageC==eNotThere )
|
|
{
|
|
mfi.m_ageC = (e_Age)age; ++age;
|
|
mfi.m_bConflictingAges = true;
|
|
}
|
|
if ( mfi.m_bExistsInB && mfi.m_ageB==eNotThere )
|
|
{
|
|
mfi.m_ageB = (e_Age)age; ++age;
|
|
mfi.m_bConflictingAges = true;
|
|
}
|
|
if ( mfi.m_bExistsInA && mfi.m_ageA==eNotThere )
|
|
{
|
|
mfi.m_ageA = (e_Age)age; ++age;
|
|
mfi.m_bConflictingAges = true;
|
|
}
|
|
|
|
if ( mfi.m_ageA != eOld && mfi.m_ageB != eOld && mfi.m_ageC != eOld )
|
|
{
|
|
if (mfi.m_ageA == eMiddle) mfi.m_ageA = eOld;
|
|
if (mfi.m_ageB == eMiddle) mfi.m_ageB = eOld;
|
|
if (mfi.m_ageC == eMiddle) mfi.m_ageC = eOld;
|
|
}
|
|
}
|
|
|
|
static TQPixmap* s_pm_dir;
|
|
static TQPixmap* s_pm_file;
|
|
|
|
static TQPixmap* pmNotThere;
|
|
static TQPixmap* pmNew;
|
|
static TQPixmap* pmOld;
|
|
static TQPixmap* pmMiddle;
|
|
|
|
static TQPixmap* pmLink;
|
|
|
|
static TQPixmap* pmDirLink;
|
|
static TQPixmap* pmFileLink;
|
|
|
|
static TQPixmap* pmNewLink;
|
|
static TQPixmap* pmOldLink;
|
|
static TQPixmap* pmMiddleLink;
|
|
|
|
static TQPixmap* pmNewDir;
|
|
static TQPixmap* pmMiddleDir;
|
|
static TQPixmap* pmOldDir;
|
|
|
|
static TQPixmap* pmNewDirLink;
|
|
static TQPixmap* pmMiddleDirLink;
|
|
static TQPixmap* pmOldDirLink;
|
|
|
|
|
|
static TQPixmap colorToPixmap(TQColor c)
|
|
{
|
|
TQPixmap pm(16,16);
|
|
TQPainter p(&pm);
|
|
p.setPen( TQt::black );
|
|
p.setBrush( c );
|
|
p.drawRect(0,0,pm.width(),pm.height());
|
|
return pm;
|
|
}
|
|
|
|
static void initPixmaps( TQColor newest, TQColor oldest, TQColor middle, TQColor notThere )
|
|
{
|
|
if (pmNew==0)
|
|
{
|
|
pmNotThere = new TQPixmap;
|
|
pmNew = new TQPixmap;
|
|
pmOld = new TQPixmap;
|
|
pmMiddle = new TQPixmap;
|
|
|
|
#include "xpm/link_arrow.xpm"
|
|
pmLink = new TQPixmap(link_arrow);
|
|
|
|
pmDirLink = new TQPixmap;
|
|
pmFileLink = new TQPixmap;
|
|
|
|
pmNewLink = new TQPixmap;
|
|
pmOldLink = new TQPixmap;
|
|
pmMiddleLink = new TQPixmap;
|
|
|
|
pmNewDir = new TQPixmap;
|
|
pmMiddleDir = new TQPixmap;
|
|
pmOldDir = new TQPixmap;
|
|
|
|
pmNewDirLink = new TQPixmap;
|
|
pmMiddleDirLink = new TQPixmap;
|
|
pmOldDirLink = new TQPixmap;
|
|
}
|
|
|
|
|
|
*pmNotThere = colorToPixmap(notThere);
|
|
*pmNew = colorToPixmap(newest);
|
|
*pmOld = colorToPixmap(oldest);
|
|
*pmMiddle = colorToPixmap(middle);
|
|
|
|
*pmDirLink = pixCombiner( s_pm_dir, pmLink);
|
|
*pmFileLink = pixCombiner( s_pm_file, pmLink );
|
|
|
|
*pmNewLink = pixCombiner( pmNew, pmLink);
|
|
*pmOldLink = pixCombiner( pmOld, pmLink);
|
|
*pmMiddleLink = pixCombiner( pmMiddle, pmLink);
|
|
|
|
*pmNewDir = pixCombiner2( pmNew, s_pm_dir);
|
|
*pmMiddleDir = pixCombiner2( pmMiddle, s_pm_dir);
|
|
*pmOldDir = pixCombiner2( pmOld, s_pm_dir);
|
|
|
|
*pmNewDirLink = pixCombiner( pmNewDir, pmLink);
|
|
*pmMiddleDirLink = pixCombiner( pmMiddleDir, pmLink);
|
|
*pmOldDirLink = pixCombiner( pmOldDir, pmLink);
|
|
}
|
|
|
|
|
|
static void setOnePixmap( TQListViewItem* pLVI, int col, e_Age eAge, bool bLink, bool bDir )
|
|
{
|
|
static TQPixmap* ageToPm[]= { pmNew, pmMiddle, pmOld, pmNotThere, s_pm_file };
|
|
static TQPixmap* ageToPmLink[]= { pmNewLink, pmMiddleLink, pmOldLink, pmNotThere, pmFileLink };
|
|
static TQPixmap* ageToPmDir[]= { pmNewDir, pmMiddleDir, pmOldDir, pmNotThere, s_pm_dir };
|
|
static TQPixmap* ageToPmDirLink[]={ pmNewDirLink, pmMiddleDirLink, pmOldDirLink, pmNotThere, pmDirLink };
|
|
|
|
TQPixmap** ppPm = bDir ? ( bLink ? ageToPmDirLink : ageToPmDir ):
|
|
( bLink ? ageToPmLink : ageToPm );
|
|
|
|
pLVI->setPixmap( col, *ppPm[eAge] );
|
|
}
|
|
|
|
static void setPixmaps( MergeFileInfos& mfi, bool bCheckC )
|
|
{
|
|
setOnePixmap( mfi.m_pDMI, s_nameCol, eAgeEnd,
|
|
mfi.m_bLinkA || mfi.m_bLinkB || mfi.m_bLinkC,
|
|
mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC
|
|
);
|
|
|
|
if ( mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC )
|
|
{
|
|
mfi.m_ageA=eNotThere;
|
|
mfi.m_ageB=eNotThere;
|
|
mfi.m_ageC=eNotThere;
|
|
int age = eNew;
|
|
if ( mfi.m_bExistsInC )
|
|
{
|
|
mfi.m_ageC = (e_Age)age;
|
|
if (mfi.m_bEqualAC) mfi.m_ageA = (e_Age)age;
|
|
if (mfi.m_bEqualBC) mfi.m_ageB = (e_Age)age;
|
|
++age;
|
|
}
|
|
if ( mfi.m_bExistsInB && mfi.m_ageB==eNotThere )
|
|
{
|
|
mfi.m_ageB = (e_Age)age;
|
|
if (mfi.m_bEqualAB) mfi.m_ageA = (e_Age)age;
|
|
++age;
|
|
}
|
|
if ( mfi.m_bExistsInA && mfi.m_ageA==eNotThere )
|
|
{
|
|
mfi.m_ageA = (e_Age)age;
|
|
}
|
|
if ( mfi.m_ageA != eOld && mfi.m_ageB != eOld && mfi.m_ageC != eOld )
|
|
{
|
|
if (mfi.m_ageA == eMiddle) mfi.m_ageA = eOld;
|
|
if (mfi.m_ageB == eMiddle) mfi.m_ageB = eOld;
|
|
if (mfi.m_ageC == eMiddle) mfi.m_ageC = eOld;
|
|
}
|
|
}
|
|
|
|
setOnePixmap( mfi.m_pDMI, s_ACol, mfi.m_ageA, mfi.m_bLinkA, mfi.m_bDirA );
|
|
setOnePixmap( mfi.m_pDMI, s_BCol, mfi.m_ageB, mfi.m_bLinkB, mfi.m_bDirB );
|
|
if ( bCheckC )
|
|
setOnePixmap( mfi.m_pDMI, s_CCol, mfi.m_ageC, mfi.m_bLinkC, mfi.m_bDirC );
|
|
}
|
|
|
|
// Iterate through the complete tree. Start by specifying TQListView::firstChild().
|
|
static TQListViewItem* treeIterator( TQListViewItem* p, bool bVisitChildren=true, bool bFindInvisible=false )
|
|
{
|
|
if( p!=0 )
|
|
{
|
|
do
|
|
{
|
|
if ( bVisitChildren && p->firstChild() != 0 ) p = p->firstChild();
|
|
else if ( p->nextSibling() !=0 ) p = p->nextSibling();
|
|
else
|
|
{
|
|
p = p->tqparent();
|
|
while ( p!=0 )
|
|
{
|
|
if( p->nextSibling()!=0 ) { p = p->nextSibling(); break; }
|
|
else { p = p->tqparent(); }
|
|
}
|
|
}
|
|
}
|
|
while( p && !(p->isVisible() || bFindInvisible) );
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void DirectoryMergeWindow::prepareListView( ProgressProxy& pp )
|
|
{
|
|
static bool bFirstTime = true;
|
|
if (bFirstTime)
|
|
{
|
|
#include "xpm/file.xpm"
|
|
#include "xpm/folder.xpm"
|
|
s_pm_dir = new TQPixmap( m_pIconLoader->loadIcon("folder", KIcon::Small ) );
|
|
if (s_pm_dir->size()!=TQSize(16,16))
|
|
{
|
|
delete s_pm_dir;
|
|
s_pm_dir = new TQPixmap( folder_pm );
|
|
}
|
|
s_pm_file= new TQPixmap( file_pm );
|
|
bFirstTime=false;
|
|
}
|
|
|
|
clear();
|
|
initPixmaps( m_pOptions->m_newestFileColor, m_pOptions->m_oldestFileColor,
|
|
m_pOptions->m_midAgeFileColor, m_pOptions->m_missingFileColor );
|
|
|
|
setRootIsDecorated( true );
|
|
|
|
bool bCheckC = m_dirC.isValid();
|
|
|
|
std::map<TQString, MergeFileInfos>::iterator j;
|
|
int nrOfFiles = m_fileMergeMap.size();
|
|
int currentIdx = 1;
|
|
TQTime t;
|
|
t.start();
|
|
for( j=m_fileMergeMap.begin(); j!=m_fileMergeMap.end(); ++j )
|
|
{
|
|
MergeFileInfos& mfi = j->second;
|
|
|
|
mfi.m_subPath = mfi.m_fileInfoA.exists() ? mfi.m_fileInfoA.filePath() :
|
|
mfi.m_fileInfoB.exists() ? mfi.m_fileInfoB.filePath() :
|
|
mfi.m_fileInfoC.exists() ? mfi.m_fileInfoC.filePath() :
|
|
TQString("");
|
|
|
|
// const TQString& fileName = j->first;
|
|
const TQString& fileName = mfi.m_subPath;
|
|
|
|
pp.setInformation(
|
|
i18n("Processing ") + TQString::number(currentIdx) +" / "+ TQString::number(nrOfFiles)
|
|
+"\n" + fileName, double(currentIdx) / nrOfFiles, false );
|
|
if ( pp.wasCancelled() ) break;
|
|
++currentIdx;
|
|
|
|
|
|
// The comparisons and calculations for each file take place here.
|
|
compareFilesAndCalcAges( mfi );
|
|
|
|
bool bEqual = bCheckC ? mfi.m_bEqualAB && mfi.m_bEqualAC : mfi.m_bEqualAB;
|
|
//bool bDir = mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC;
|
|
|
|
//if ( m_pOptions->m_bDmShowOnlyDeltas && !bDir && bEqual )
|
|
// continue;
|
|
|
|
// Get dirname from fileName: Search for "/" from end:
|
|
int pos = fileName.findRev('/');
|
|
TQString dirPart;
|
|
TQString filePart;
|
|
if (pos==-1)
|
|
{
|
|
// Top dir
|
|
filePart = fileName;
|
|
}
|
|
else
|
|
{
|
|
dirPart = fileName.left(pos);
|
|
filePart = fileName.mid(pos+1);
|
|
}
|
|
|
|
if ( dirPart.isEmpty() ) // Top level
|
|
{
|
|
new DirMergeItem( this, filePart, &mfi );
|
|
}
|
|
else
|
|
{
|
|
MergeFileInfos& dirMfi = m_fileMergeMap[sortString(dirPart, m_bCaseSensitive)]; // tqparent
|
|
assert(dirMfi.m_pDMI!=0);
|
|
new DirMergeItem( dirMfi.m_pDMI, filePart, &mfi );
|
|
mfi.m_pParent = &dirMfi;
|
|
|
|
if ( !bEqual ) // Set all parents to "not equal"
|
|
{
|
|
MergeFileInfos* p = mfi.m_pParent;
|
|
while(p!=0)
|
|
{
|
|
bool bChange = false;
|
|
if ( !mfi.m_bEqualAB && p->m_bEqualAB ){ p->m_bEqualAB = false; bChange=true; }
|
|
if ( !mfi.m_bEqualAC && p->m_bEqualAC ){ p->m_bEqualAC = false; bChange=true; }
|
|
if ( !mfi.m_bEqualBC && p->m_bEqualBC ){ p->m_bEqualBC = false; bChange=true; }
|
|
|
|
if ( bChange )
|
|
setPixmaps( *p, bCheckC );
|
|
else
|
|
break;
|
|
|
|
p = p->m_pParent;
|
|
}
|
|
}
|
|
}
|
|
|
|
setPixmaps( mfi, bCheckC );
|
|
}
|
|
|
|
/*if ( m_pOptions->m_bDmShowOnlyDeltas )
|
|
{
|
|
// Remove all equals. (Search tree depth first)
|
|
TQListViewItem* p = firstChild();
|
|
while( p!=0 && firstChild() != 0 )
|
|
{
|
|
TQListViewItem* pParent = p->tqparent();
|
|
TQListViewItem* pNextSibling = p->nextSibling();
|
|
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
|
|
bool bDirEqual = bCheckC ? pDMI->m_pMFI->m_bEqualAB && pDMI->m_pMFI->m_bEqualAC
|
|
: pDMI->m_pMFI->m_bEqualAB;
|
|
if ( pDMI!=0 && pDMI->m_pMFI->m_bDirA && bDirEqual )
|
|
{
|
|
delete p;
|
|
p=0;
|
|
}
|
|
|
|
if ( p!=0 && p->firstChild() != 0 ) p = p->firstChild();
|
|
else if ( pNextSibling!=0 ) p = pNextSibling;
|
|
else
|
|
{
|
|
p=pParent;
|
|
while ( p!=0 )
|
|
{
|
|
if( p->nextSibling()!=0 ) { p = p->nextSibling(); break; }
|
|
else { p = p->tqparent(); }
|
|
}
|
|
}
|
|
}
|
|
}*/
|
|
}
|
|
|
|
static bool conflictingFileTypes(MergeFileInfos& mfi)
|
|
{
|
|
// Now check if file/dir-types fit.
|
|
if ( mfi.m_bLinkA || mfi.m_bLinkB || mfi.m_bLinkC )
|
|
{
|
|
if ( mfi.m_bExistsInA && ! mfi.m_bLinkA ||
|
|
mfi.m_bExistsInB && ! mfi.m_bLinkB ||
|
|
mfi.m_bExistsInC && ! mfi.m_bLinkC )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if ( mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC )
|
|
{
|
|
if ( mfi.m_bExistsInA && ! mfi.m_bDirA ||
|
|
mfi.m_bExistsInB && ! mfi.m_bDirB ||
|
|
mfi.m_bExistsInC && ! mfi.m_bDirC )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void DirectoryMergeWindow::calcSuggestedOperation( MergeFileInfos& mfi, e_MergeOperation eDefaultMergeOp )
|
|
{
|
|
bool bCheckC = m_dirC.isValid();
|
|
bool bCopyNewer = m_pOptions->m_bDmCopyNewer;
|
|
bool bOtherDest = !( m_dirDestInternal.absFilePath() == m_dirA.absFilePath() ||
|
|
m_dirDestInternal.absFilePath() == m_dirB.absFilePath() ||
|
|
bCheckC && m_dirDestInternal.absFilePath() == m_dirC.absFilePath() );
|
|
|
|
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 )
|
|
{
|
|
mfi.setMergeOperation( bOtherDest ? eCopyBToDest : eNoOperation );
|
|
}
|
|
else if ( mfi.m_bExistsInA && mfi.m_bExistsInB )
|
|
{
|
|
if ( !bCopyNewer || mfi.m_bDirA )
|
|
mfi.setMergeOperation( eDefaultMergeOp );
|
|
else if ( bCopyNewer && mfi.m_bConflictingAges )
|
|
{
|
|
mfi.setMergeOperation( eConflictingAges );
|
|
}
|
|
else
|
|
{
|
|
if ( mfi.m_ageA == eNew )
|
|
mfi.setMergeOperation( eDefaultMergeOp == eMergeToAB ? eCopyAToB : eCopyAToDest );
|
|
else
|
|
mfi.setMergeOperation( eDefaultMergeOp == eMergeToAB ? eCopyBToA : eCopyBToDest );
|
|
}
|
|
}
|
|
else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB )
|
|
{
|
|
if ( eDefaultMergeOp==eMergeABToDest ) mfi.setMergeOperation( eCopyBToDest );
|
|
else if ( eDefaultMergeOp==eMergeToB ) mfi.setMergeOperation( eNoOperation );
|
|
else mfi.setMergeOperation( eCopyBToA );
|
|
}
|
|
else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB )
|
|
{
|
|
if ( eDefaultMergeOp==eMergeABToDest ) mfi.setMergeOperation( eCopyAToDest );
|
|
else if ( eDefaultMergeOp==eMergeToA ) mfi.setMergeOperation( eNoOperation );
|
|
else mfi.setMergeOperation( eCopyAToB );
|
|
}
|
|
else //if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB )
|
|
{
|
|
mfi.setMergeOperation( eNoOperation ); assert(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( mfi.m_bEqualAB && mfi.m_bEqualAC )
|
|
{
|
|
mfi.setMergeOperation( bOtherDest ? eCopyCToDest : eNoOperation );
|
|
}
|
|
else if ( mfi.m_bExistsInA && mfi.m_bExistsInB && mfi.m_bExistsInC)
|
|
{
|
|
if ( mfi.m_bEqualAB )
|
|
mfi.setMergeOperation( eCopyCToDest );
|
|
else if ( mfi.m_bEqualAC )
|
|
mfi.setMergeOperation( eCopyBToDest );
|
|
else if ( mfi.m_bEqualBC )
|
|
mfi.setMergeOperation( eCopyCToDest );
|
|
else
|
|
mfi.setMergeOperation( eMergeABCToDest );
|
|
}
|
|
else if ( mfi.m_bExistsInA && mfi.m_bExistsInB && !mfi.m_bExistsInC )
|
|
{
|
|
if ( mfi.m_bEqualAB )
|
|
mfi.setMergeOperation( eDeleteFromDest );
|
|
else
|
|
mfi.setMergeOperation( eCopyBToDest );
|
|
}
|
|
else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB && mfi.m_bExistsInC )
|
|
{
|
|
if ( mfi.m_bEqualAC )
|
|
mfi.setMergeOperation( eDeleteFromDest );
|
|
else
|
|
mfi.setMergeOperation( eCopyCToDest );
|
|
}
|
|
else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB && mfi.m_bExistsInC )
|
|
{
|
|
if ( mfi.m_bEqualBC )
|
|
mfi.setMergeOperation( eCopyCToDest );
|
|
else
|
|
mfi.setMergeOperation( eMergeABCToDest );
|
|
}
|
|
else if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB && mfi.m_bExistsInC )
|
|
{
|
|
mfi.setMergeOperation( eCopyCToDest );
|
|
}
|
|
else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB && !mfi.m_bExistsInC )
|
|
{
|
|
mfi.setMergeOperation( eCopyBToDest );
|
|
}
|
|
else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB && !mfi.m_bExistsInC)
|
|
{
|
|
mfi.setMergeOperation( eDeleteFromDest );
|
|
}
|
|
else //if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB && !mfi.m_bExistsInC )
|
|
{
|
|
mfi.setMergeOperation( eNoOperation ); assert(false);
|
|
}
|
|
}
|
|
|
|
// Now check if file/dir-types fit.
|
|
if ( conflictingFileTypes(mfi) )
|
|
{
|
|
mfi.setMergeOperation( eConflictingFileTypes );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
e_MergeOperation eMO = eDefaultMergeOp;
|
|
switch ( eDefaultMergeOp )
|
|
{
|
|
case eConflictingFileTypes:
|
|
case eConflictingAges:
|
|
case eDeleteA:
|
|
case eDeleteB:
|
|
case eDeleteAB:
|
|
case eDeleteFromDest:
|
|
case eNoOperation: break;
|
|
case eCopyAToB: if ( !mfi.m_bExistsInA ) { eMO = eDeleteB; } break;
|
|
case eCopyBToA: if ( !mfi.m_bExistsInB ) { eMO = eDeleteA; } break;
|
|
case eCopyAToDest: if ( !mfi.m_bExistsInA ) { eMO = eDeleteFromDest; } break;
|
|
case eCopyBToDest: if ( !mfi.m_bExistsInB ) { eMO = eDeleteFromDest; } break;
|
|
case eCopyCToDest: if ( !mfi.m_bExistsInC ) { eMO = eDeleteFromDest; } break;
|
|
|
|
case eMergeToA:
|
|
case eMergeToB:
|
|
case eMergeToAB:
|
|
case eMergeABCToDest:
|
|
case eMergeABToDest:
|
|
default:
|
|
assert(false);
|
|
}
|
|
mfi.setMergeOperation( eMO );
|
|
}
|
|
}
|
|
|
|
void DirectoryMergeWindow::onDoubleClick( TQListViewItem* lvi )
|
|
{
|
|
if (lvi==0) return;
|
|
|
|
if ( m_bDirectoryMerge )
|
|
mergeCurrentFile();
|
|
else
|
|
compareCurrentFile();
|
|
}
|
|
|
|
void DirectoryMergeWindow::onSelectionChanged( TQListViewItem* lvi )
|
|
{
|
|
if ( lvi==0 ) return;
|
|
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi);
|
|
|
|
MergeFileInfos& mfi = *pDMI->m_pMFI;
|
|
assert( mfi.m_pDMI==pDMI );
|
|
|
|
m_pDirectoryMergeInfo->setInfo( m_dirA, m_dirB, m_dirC, m_dirDestInternal, mfi );
|
|
}
|
|
|
|
void DirectoryMergeWindow::onClick( int button, TQListViewItem* lvi, const TQPoint& p, int c )
|
|
{
|
|
if ( lvi==0 ) return;
|
|
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi);
|
|
|
|
MergeFileInfos& mfi = *pDMI->m_pMFI;
|
|
assert( mfi.m_pDMI==pDMI );
|
|
|
|
if ( c==s_OpCol )
|
|
{
|
|
bool bThreeDirs = m_dirC.isValid();
|
|
|
|
KPopupMenu m(this);
|
|
if ( bThreeDirs )
|
|
{
|
|
m_pDirCurrentDoNothing->plug(&m);
|
|
int count=0;
|
|
if ( mfi.m_bExistsInA ) { m_pDirCurrentChooseA->plug(&m); ++count; }
|
|
if ( mfi.m_bExistsInB ) { m_pDirCurrentChooseB->plug(&m); ++count; }
|
|
if ( mfi.m_bExistsInC ) { m_pDirCurrentChooseC->plug(&m); ++count; }
|
|
if ( !conflictingFileTypes(mfi) && count>1 ) m_pDirCurrentMerge->plug(&m);
|
|
m_pDirCurrentDelete->plug(&m);
|
|
}
|
|
else if ( m_bSyncMode )
|
|
{
|
|
m_pDirCurrentSyncDoNothing->plug(&m);
|
|
if ( mfi.m_bExistsInA ) m_pDirCurrentSyncCopyAToB->plug(&m);
|
|
if ( mfi.m_bExistsInB ) m_pDirCurrentSyncCopyBToA->plug(&m);
|
|
if ( mfi.m_bExistsInA ) m_pDirCurrentSyncDeleteA->plug(&m);
|
|
if ( mfi.m_bExistsInB ) m_pDirCurrentSyncDeleteB->plug(&m);
|
|
if ( mfi.m_bExistsInA && mfi.m_bExistsInB )
|
|
{
|
|
m_pDirCurrentSyncDeleteAAndB->plug(&m);
|
|
if ( !conflictingFileTypes(mfi))
|
|
{
|
|
m_pDirCurrentSyncMergeToA->plug(&m);
|
|
m_pDirCurrentSyncMergeToB->plug(&m);
|
|
m_pDirCurrentSyncMergeToAAndB->plug(&m);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pDirCurrentDoNothing->plug(&m);
|
|
if ( mfi.m_bExistsInA ) { m_pDirCurrentChooseA->plug(&m); }
|
|
if ( mfi.m_bExistsInB ) { m_pDirCurrentChooseB->plug(&m); }
|
|
if ( !conflictingFileTypes(mfi) && mfi.m_bExistsInA && mfi.m_bExistsInB ) m_pDirCurrentMerge->plug(&m);
|
|
m_pDirCurrentDelete->plug(&m);
|
|
}
|
|
|
|
m.exec( p );
|
|
}
|
|
else if ( c == s_ACol || c==s_BCol || c==s_CCol )
|
|
{
|
|
TQString itemPath;
|
|
if ( c == s_ACol && mfi.m_bExistsInA ){ itemPath = fullNameA(mfi); }
|
|
else if ( c == s_BCol && mfi.m_bExistsInB ){ itemPath = fullNameB(mfi); }
|
|
else if ( c == s_CCol && mfi.m_bExistsInC ){ itemPath = fullNameC(mfi); }
|
|
|
|
if (!itemPath.isEmpty())
|
|
{
|
|
selectItemAndColumn( pDMI, c, button==Qt::RightButton );
|
|
}
|
|
}
|
|
}
|
|
|
|
void DirectoryMergeWindow::slotShowContextMenu(TQListViewItem* lvi,const TQPoint & p,int c)
|
|
{
|
|
if ( lvi==0 ) return;
|
|
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi);
|
|
|
|
MergeFileInfos& mfi = *pDMI->m_pMFI;
|
|
assert( mfi.m_pDMI==pDMI );
|
|
if ( c == s_ACol || c==s_BCol || c==s_CCol )
|
|
{
|
|
TQString itemPath;
|
|
if ( c == s_ACol && mfi.m_bExistsInA ){ itemPath = fullNameA(mfi); }
|
|
else if ( c == s_BCol && mfi.m_bExistsInB ){ itemPath = fullNameB(mfi); }
|
|
else if ( c == s_CCol && mfi.m_bExistsInC ){ itemPath = fullNameC(mfi); }
|
|
|
|
if (!itemPath.isEmpty())
|
|
{
|
|
selectItemAndColumn(pDMI, c, true);
|
|
KPopupMenu m(this);
|
|
m_pDirCompareExplicit->plug(&m);
|
|
m_pDirMergeExplicit->plug(&m);
|
|
|
|
#ifndef _WIN32
|
|
m.exec( p );
|
|
#else
|
|
void showShellContextMenu( const TQString&, TQPoint, TQWidget*, TQPopupMenu* );
|
|
showShellContextMenu( itemPath, p, this, &m );
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
static TQString getFileName( DirMergeItem* pDMI, int column )
|
|
{
|
|
if ( pDMI != 0 )
|
|
{
|
|
MergeFileInfos& mfi = *pDMI->m_pMFI;
|
|
return column == s_ACol ? mfi.m_fileInfoA.absFilePath() :
|
|
column == s_BCol ? mfi.m_fileInfoB.absFilePath() :
|
|
column == s_CCol ? mfi.m_fileInfoC.absFilePath() :
|
|
TQString("");
|
|
}
|
|
return "";
|
|
}
|
|
|
|
static bool isDir( DirMergeItem* pDMI, int column )
|
|
{
|
|
if ( pDMI != 0 )
|
|
{
|
|
MergeFileInfos& mfi = *pDMI->m_pMFI;
|
|
return column == s_ACol ? mfi.m_bDirA :
|
|
column == s_BCol ? mfi.m_bDirB :
|
|
mfi.m_bDirC;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void DirectoryMergeWindow::selectItemAndColumn(DirMergeItem* pDMI, int c, bool bContextMenu)
|
|
{
|
|
if ( bContextMenu && (
|
|
pDMI==m_pSelection1Item && c==m_selection1Column ||
|
|
pDMI==m_pSelection2Item && c==m_selection2Column ||
|
|
pDMI==m_pSelection3Item && c==m_selection3Column ) )
|
|
return;
|
|
|
|
DirMergeItem* pOld1=m_pSelection1Item;
|
|
DirMergeItem* pOld2=m_pSelection2Item;
|
|
DirMergeItem* pOld3=m_pSelection3Item;
|
|
|
|
bool bReset = false;
|
|
|
|
if ( m_pSelection1Item )
|
|
{
|
|
if (isDir( m_pSelection1Item, m_selection1Column )!=isDir( pDMI, c ))
|
|
bReset = true;
|
|
}
|
|
|
|
if ( bReset || m_pSelection3Item!=0 ||
|
|
pDMI==m_pSelection1Item && c==m_selection1Column ||
|
|
pDMI==m_pSelection2Item && c==m_selection2Column ||
|
|
pDMI==m_pSelection3Item && c==m_selection3Column)
|
|
{
|
|
m_pSelection1Item = 0;
|
|
m_pSelection2Item = 0;
|
|
m_pSelection3Item = 0;
|
|
}
|
|
else if ( m_pSelection1Item==0 )
|
|
{
|
|
m_pSelection1Item = pDMI;
|
|
m_selection1Column = c;
|
|
m_pSelection2Item = 0;
|
|
m_pSelection3Item = 0;
|
|
}
|
|
else if ( m_pSelection2Item==0 )
|
|
{
|
|
m_pSelection2Item = pDMI;
|
|
m_selection2Column = c;
|
|
m_pSelection3Item = 0;
|
|
}
|
|
else if ( m_pSelection3Item==0 )
|
|
{
|
|
m_pSelection3Item = pDMI;
|
|
m_selection3Column = c;
|
|
}
|
|
if (pOld1) repaintItem( pOld1 );
|
|
if (pOld2) repaintItem( pOld2 );
|
|
if (pOld3) repaintItem( pOld3 );
|
|
if (m_pSelection1Item) repaintItem( m_pSelection1Item );
|
|
if (m_pSelection2Item) repaintItem( m_pSelection2Item );
|
|
if (m_pSelection3Item) repaintItem( m_pSelection3Item );
|
|
emit updateAvailabilities();
|
|
}
|
|
|
|
// Since TQt 2.3.0 doesn't allow the specification of a compare operator, this trick emulates it.
|
|
#define DIRSORT(x) x
|
|
|
|
DirMergeItem::DirMergeItem( TQListView* pParent, const TQString& fileName, MergeFileInfos* pMFI )
|
|
: TQListViewItem( pParent, DIRSORT( fileName ), "","","", i18n("To do."), "" )
|
|
{
|
|
init(pMFI);
|
|
}
|
|
|
|
DirMergeItem::DirMergeItem( DirMergeItem* pParent, const TQString& fileName, MergeFileInfos* pMFI )
|
|
: TQListViewItem( pParent, DIRSORT( fileName ), "","","", i18n("To do."), "" )
|
|
{
|
|
init(pMFI);
|
|
}
|
|
|
|
|
|
void DirMergeItem::init(MergeFileInfos* pMFI)
|
|
{
|
|
pMFI->m_pDMI = this;
|
|
m_pMFI = pMFI;
|
|
TotalDifftqStatus& tds = pMFI->m_totalDifftqStatus;
|
|
if ( m_pMFI->m_bDirA || m_pMFI->m_bDirB || m_pMFI->m_bDirC )
|
|
{
|
|
}
|
|
else
|
|
{
|
|
setText( s_UnsolvedCol, TQString::number( tds.nofUnsolvedConflicts ) );
|
|
setText( s_SolvedCol, TQString::number( tds.nofSolvedConflicts ) );
|
|
setText( s_NonWhiteCol, TQString::number( tds.nofUnsolvedConflicts + tds.nofSolvedConflicts - tds.nofWhitespaceConflicts ) );
|
|
setText( s_WhiteCol, TQString::number( tds.nofWhitespaceConflicts ) );
|
|
}
|
|
}
|
|
|
|
int DirMergeItem::compare(TQListViewItem *i, int col, bool ascending) const
|
|
{
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>(i);
|
|
bool bDir1 = m_pMFI->m_bDirA || m_pMFI->m_bDirB || m_pMFI->m_bDirC;
|
|
bool bDir2 = pDMI->m_pMFI->m_bDirA || pDMI->m_pMFI->m_bDirB || pDMI->m_pMFI->m_bDirC;
|
|
if ( m_pMFI==0 || pDMI->m_pMFI==0 || bDir1 == bDir2 )
|
|
{
|
|
if(col==s_UnsolvedCol || col==s_SolvedCol || col==s_NonWhiteCol || col==s_WhiteCol)
|
|
return key(col,ascending).toInt() > i->key(col,ascending).toInt() ? -1 : 1;
|
|
else
|
|
return TQListViewItem::compare( i, col, ascending );
|
|
}
|
|
else
|
|
return bDir1 ? -1 : 1;
|
|
}
|
|
|
|
void DirMergeItem::paintCell(TQPainter * p, const TQColorGroup & cg, int column, int width, int align )
|
|
{
|
|
if (column == s_ACol || column == s_BCol || column == s_CCol )
|
|
{
|
|
const TQPixmap* icon = pixmap(column);
|
|
if ( icon )
|
|
{
|
|
int yOffset = (height() - icon->height()) / 2;
|
|
p->fillRect( 0, 0, width, height(), cg.base() );
|
|
p->drawPixmap( 2, yOffset, *icon );
|
|
if ( listView() )
|
|
{
|
|
DirectoryMergeWindow* pDMW = static_cast<DirectoryMergeWindow*>(listView());
|
|
int i = this==pDMW->m_pSelection1Item && column == pDMW->m_selection1Column ? 1 :
|
|
this==pDMW->m_pSelection2Item && column == pDMW->m_selection2Column ? 2 :
|
|
this==pDMW->m_pSelection3Item && column == pDMW->m_selection3Column ? 3 :
|
|
0;
|
|
if ( i!=0 )
|
|
{
|
|
OptionDialog* pOD = pDMW->m_pOptions;
|
|
TQColor c ( i==1 ? pOD->m_colorA : i==2 ? pOD->m_colorB : pOD->m_colorC );
|
|
p->setPen( c );// highlight() );
|
|
p->drawRect( 2, yOffset, icon->width(), icon->height());
|
|
p->setPen( TQPen( c, 0, TQt::DotLine) );
|
|
p->drawRect( 1, yOffset-1, icon->width()+2, icon->height()+2);
|
|
p->setPen( cg.background() );
|
|
TQString s( TQChar('A'+i-1) );
|
|
p->drawText( 2 + (icon->width() - p->fontMetrics().width(s))/2,
|
|
yOffset + (icon->height() + p->fontMetrics().ascent())/2-1,
|
|
s );
|
|
}
|
|
else
|
|
{
|
|
p->setPen( cg.background() );
|
|
p->drawRect( 1, yOffset-1, icon->width()+2, icon->height()+2);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
TQListViewItem::paintCell(p,cg,column,width,align);
|
|
}
|
|
|
|
DirMergeItem::~DirMergeItem()
|
|
{
|
|
m_pMFI->m_pDMI = 0;
|
|
}
|
|
|
|
void MergeFileInfos::setMergeOperation( e_MergeOperation eMOp, bool bRecursive )
|
|
{
|
|
if ( eMOp != m_eMergeOperation )
|
|
{
|
|
m_bOperationComplete = false;
|
|
m_pDMI->setText( s_OpStatusCol, "" );
|
|
}
|
|
|
|
m_eMergeOperation = eMOp;
|
|
TQString 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=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=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);
|
|
|
|
if ( bRecursive )
|
|
{
|
|
e_MergeOperation eChildrenMergeOp = m_eMergeOperation;
|
|
if ( eChildrenMergeOp == eConflictingFileTypes ) eChildrenMergeOp = eMergeABCToDest;
|
|
TQListViewItem* p = m_pDMI->firstChild();
|
|
while ( p!=0 )
|
|
{
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>( p );
|
|
DirectoryMergeWindow* pDMW = static_cast<DirectoryMergeWindow*>( p->listView() );
|
|
pDMW->calcSuggestedOperation( *pDMI->m_pMFI, eChildrenMergeOp );
|
|
p = p->nextSibling();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DirectoryMergeWindow::compareCurrentFile()
|
|
{
|
|
if (!canContinue()) return;
|
|
|
|
if ( m_bRealMergeStarted )
|
|
{
|
|
KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible"));
|
|
return;
|
|
}
|
|
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
|
|
if ( pDMI != 0 )
|
|
{
|
|
MergeFileInfos& mfi = *pDMI->m_pMFI;
|
|
if ( !(mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC) )
|
|
{
|
|
emit startDiffMerge(
|
|
mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : TQString(""),
|
|
mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : TQString(""),
|
|
mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : TQString(""),
|
|
"",
|
|
"","","",0
|
|
);
|
|
}
|
|
}
|
|
emit updateAvailabilities();
|
|
}
|
|
|
|
|
|
void DirectoryMergeWindow::slotCompareExplicitlySelectedFiles()
|
|
{
|
|
if ( ! isDir(m_pSelection1Item,m_selection1Column) && !canContinue() ) return;
|
|
|
|
if ( m_bRealMergeStarted )
|
|
{
|
|
KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible"));
|
|
return;
|
|
}
|
|
|
|
emit startDiffMerge(
|
|
getFileName( m_pSelection1Item, m_selection1Column ),
|
|
getFileName( m_pSelection2Item, m_selection2Column ),
|
|
getFileName( m_pSelection3Item, m_selection3Column ),
|
|
"",
|
|
"","","",0
|
|
);
|
|
m_pSelection1Item=0;
|
|
m_pSelection2Item=0;
|
|
m_pSelection3Item=0;
|
|
|
|
emit updateAvailabilities();
|
|
triggerUpdate();
|
|
}
|
|
|
|
void DirectoryMergeWindow::slotMergeExplicitlySelectedFiles()
|
|
{
|
|
if ( ! isDir(m_pSelection1Item,m_selection1Column) && !canContinue() ) return;
|
|
|
|
if ( m_bRealMergeStarted )
|
|
{
|
|
KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible"));
|
|
return;
|
|
}
|
|
|
|
TQString fn1 = getFileName( m_pSelection1Item, m_selection1Column );
|
|
TQString fn2 = getFileName( m_pSelection2Item, m_selection2Column );
|
|
TQString fn3 = getFileName( m_pSelection3Item, m_selection3Column );
|
|
|
|
emit startDiffMerge( fn1, fn2, fn3,
|
|
fn3.isEmpty() ? fn2 : fn3,
|
|
"","","",0
|
|
);
|
|
m_pSelection1Item=0;
|
|
m_pSelection2Item=0;
|
|
m_pSelection3Item=0;
|
|
|
|
emit updateAvailabilities();
|
|
triggerUpdate();
|
|
}
|
|
|
|
bool DirectoryMergeWindow::isFileSelected()
|
|
{
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
|
|
if ( pDMI != 0 )
|
|
{
|
|
MergeFileInfos& mfi = *pDMI->m_pMFI;
|
|
return ! (mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC || conflictingFileTypes(mfi) );
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void DirectoryMergeWindow::mergeResultSaved(const TQString& fileName)
|
|
{
|
|
DirMergeItem* pCurrentItemForOperation = (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() )
|
|
? 0
|
|
: *m_currentItemForOperation;
|
|
|
|
if ( pCurrentItemForOperation!=0 && pCurrentItemForOperation->m_pMFI==0 )
|
|
{
|
|
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 ( pCurrentItemForOperation!=0 && fileName == fullNameDest(*pCurrentItemForOperation->m_pMFI) )
|
|
{
|
|
if ( pCurrentItemForOperation->m_pMFI->m_eMergeOperation==eMergeToAB )
|
|
{
|
|
MergeFileInfos& mfi = *pCurrentItemForOperation->m_pMFI;
|
|
bool bSuccess = copyFLD( fullNameB(mfi), fullNameA(mfi) );
|
|
if (!bSuccess)
|
|
{
|
|
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;
|
|
pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Error.") );
|
|
mfi.m_eMergeOperation = eCopyBToA;
|
|
return;
|
|
}
|
|
}
|
|
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();
|
|
}
|
|
|
|
bool DirectoryMergeWindow::canContinue()
|
|
{
|
|
bool bCanContinue=false;
|
|
checkIfCanContinue( &bCanContinue );
|
|
if ( bCanContinue && !m_bError )
|
|
{
|
|
DirMergeItem* pCurrentItemForOperation =
|
|
(m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() ) ? 0 : *m_currentItemForOperation;
|
|
|
|
if ( pCurrentItemForOperation!=0 && ! pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
|
|
{
|
|
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;
|
|
}
|
|
|
|
bool DirectoryMergeWindow::executeMergeOperation( MergeFileInfos& mfi, bool& bSingleFileMerge )
|
|
{
|
|
bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles;
|
|
// First decide destname
|
|
TQString 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);
|
|
}
|
|
|
|
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) : TQString(""),
|
|
mfi.m_bExistsInB ? fullNameB(mfi) : TQString(""),
|
|
mfi.m_bExistsInC ? fullNameC(mfi) : TQString(""),
|
|
destName, bSingleFileMerge );
|
|
break;
|
|
default:
|
|
KMessageBox::error( this, i18n("Unknown merge operation."), i18n("Error") );
|
|
assert(false);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
// Check if the merge can start, and prepare the m_mergeItemList which then contains all
|
|
// items that must be merged.
|
|
void DirectoryMergeWindow::prepareMergeStart( TQListViewItem* pBegin, TQListViewItem* pEnd, bool bVerbose )
|
|
{
|
|
if ( bVerbose )
|
|
{
|
|
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( TQListViewItem* p = pBegin; p!= pEnd; p = treeIterator( p ) )
|
|
{
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
|
|
|
|
if ( pDMI && ! pDMI->m_pMFI->m_bOperationComplete )
|
|
{
|
|
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."), 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."), i18n("Error"));
|
|
m_mergeItemList.clear();
|
|
m_bRealMergeStarted=false;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_currentItemForOperation = m_mergeItemList.begin();
|
|
return;
|
|
}
|
|
|
|
void DirectoryMergeWindow::slotRunOperationForCurrentItem()
|
|
{
|
|
if ( ! canContinue() ) return;
|
|
|
|
bool bVerbose = false;
|
|
if ( m_mergeItemList.empty() )
|
|
{
|
|
TQListViewItem* pBegin = currentItem();
|
|
TQListViewItem* pEnd = treeIterator(pBegin,false,false); // find next visible sibling (no tqchildren)
|
|
|
|
prepareMergeStart( pBegin, pEnd, bVerbose );
|
|
mergeContinue(true, bVerbose);
|
|
}
|
|
else
|
|
mergeContinue(false, bVerbose);
|
|
}
|
|
|
|
void DirectoryMergeWindow::slotRunOperationForAllItems()
|
|
{
|
|
if ( ! canContinue() ) return;
|
|
|
|
bool bVerbose = true;
|
|
if ( m_mergeItemList.empty() )
|
|
{
|
|
TQListViewItem* 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 directory merge is currently running."),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() : TQString(""),
|
|
mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : TQString(""),
|
|
mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : TQString(""),
|
|
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)
|
|
{
|
|
ProgressProxy pp;
|
|
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 = *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 ( !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("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;
|
|
}
|
|
|
|
bool bSuccess = true;
|
|
bool bSingleFileMerge = false;
|
|
bool bSim = m_bSimulatedMergeStarted;
|
|
while( bSuccess )
|
|
{
|
|
if ( pCurrentItemForOperation==0 )
|
|
{
|
|
m_mergeItemList.clear();
|
|
m_bRealMergeStarted=false;
|
|
break;
|
|
}
|
|
|
|
if ( pCurrentItemForOperation!=0 && !bContinueWithCurrentItem )
|
|
{
|
|
if ( bSim )
|
|
{
|
|
if( pCurrentItemForOperation->firstChild()==0 )
|
|
{
|
|
pCurrentItemForOperation->m_pMFI->m_bSimOpComplete = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pCurrentItemForOperation->firstChild()==0 )
|
|
{
|
|
if( !pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
|
|
{
|
|
pCurrentItemForOperation->setText( s_OpStatusCol, bSkipItem ? i18n("Skipped.") : i18n("Done.") );
|
|
pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
|
|
bSkipItem = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCurrentItemForOperation->setText( s_OpStatusCol, i18n("In progress...") );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ! bContinueWithCurrentItem )
|
|
{
|
|
// Depth first
|
|
TQListViewItem* pPrevItem = pCurrentItemForOperation;
|
|
++m_currentItemForOperation;
|
|
pCurrentItemForOperation = m_currentItemForOperation==m_mergeItemList.end() ? 0 : *m_currentItemForOperation;
|
|
if ( (pCurrentItemForOperation==0 || pCurrentItemForOperation->tqparent()!=pPrevItem->tqparent()) && pPrevItem->tqparent()!=0 )
|
|
{
|
|
// Check if the tqparent may be set to "Done"
|
|
TQListViewItem* pParent = pPrevItem->tqparent();
|
|
bool bDone = true;
|
|
while ( bDone && pParent!=0 )
|
|
{
|
|
for( TQListViewItem* p = pParent->firstChild(); p!=0; p=p->nextSibling() )
|
|
{
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
|
|
if ( !bSim && ! pDMI->m_pMFI->m_bOperationComplete || bSim && pDMI->m_pMFI->m_bSimOpComplete )
|
|
{
|
|
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->tqparent();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pCurrentItemForOperation == 0 ) // end?
|
|
{
|
|
if ( m_bRealMergeStarted )
|
|
{
|
|
if (bVerbose)
|
|
{
|
|
KMessageBox::information( this, i18n("Merge operation complete."), i18n("Merge Complete") );
|
|
}
|
|
m_bRealMergeStarted = false;
|
|
m_pStatusInfo->setCaption(i18n("Merge Complete"));
|
|
}
|
|
if ( m_bSimulatedMergeStarted )
|
|
{
|
|
m_bSimulatedMergeStarted = false;
|
|
for( TQListViewItem* p=firstChild(); p!=0; p=treeIterator(p) )
|
|
{
|
|
static_cast<DirMergeItem*>(p)->m_pMFI->m_bSimOpComplete = false;
|
|
}
|
|
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 = *pCurrentItemForOperation->m_pMFI;
|
|
|
|
pp.setInformation( mfi.m_subPath,
|
|
bSim ? double(nrOfCompletedSimItems)/nrOfItems : double(nrOfCompletedItems)/nrOfItems,
|
|
false // bRedrawUpdate
|
|
);
|
|
//g_pProgressDialog->show();
|
|
|
|
bSuccess = executeMergeOperation( mfi, bSingleFileMerge ); // Here the real operation happens.
|
|
|
|
if ( bSuccess )
|
|
{
|
|
if(bSim) ++nrOfCompletedSimItems;
|
|
else ++nrOfCompletedItems;
|
|
bContinueWithCurrentItem = false;
|
|
}
|
|
|
|
if( pp.wasCancelled() )
|
|
break;
|
|
} // end while
|
|
|
|
//g_pProgressDialog->hide();
|
|
|
|
setCurrentItem( pCurrentItemForOperation );
|
|
ensureItemVisible( pCurrentItemForOperation );
|
|
if ( !bSuccess && !bSingleFileMerge )
|
|
{
|
|
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;
|
|
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 )
|
|
{
|
|
m_bAllowResizeEvents = bAllowResizeEvents;
|
|
}
|
|
|
|
void DirectoryMergeWindow::resizeEvent( TQResizeEvent* e )
|
|
{
|
|
if (m_bAllowResizeEvents)
|
|
TQListView::resizeEvent(e);
|
|
}
|
|
|
|
bool DirectoryMergeWindow::deleteFLD( const TQString& name, bool bCreateBackup )
|
|
{
|
|
FileAccess fi(name, true);
|
|
if ( !fi.exists() )
|
|
return true;
|
|
|
|
if ( bCreateBackup )
|
|
{
|
|
bool bSuccess = renameFLD( name, name+".orig" );
|
|
if (!bSuccess)
|
|
{
|
|
m_pStatusInfo->addText( i18n("Error: While deleting %1: Creating backup failed.").tqarg(name) );
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( fi.isDir() && !fi.isSymLink() )
|
|
m_pStatusInfo->addText(i18n("delete directory recursively( %1 )").tqarg(name));
|
|
else
|
|
m_pStatusInfo->addText(i18n("delete( %1 )").tqarg(name));
|
|
|
|
if ( m_bSimulatedMergeStarted )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ( fi.isDir() && !fi.isSymLink() )// recursive directory delete only for real dirs, not symlinks
|
|
{
|
|
t_DirectoryList dirList;
|
|
bool bSuccess = fi.listDir( &dirList, false, true, "*", "", "", false, false ); // not recursive, find hidden files
|
|
|
|
if ( !bSuccess )
|
|
{
|
|
// No Permission to read directory or other error.
|
|
m_pStatusInfo->addText( i18n("Error: delete dir operation failed while trying to read the directory.") );
|
|
return false;
|
|
}
|
|
|
|
t_DirectoryList::iterator it; // create list iterator
|
|
|
|
for ( it=dirList.begin(); it!=dirList.end(); ++it ) // for each file...
|
|
{
|
|
FileAccess& fi2 = *it;
|
|
if ( fi2.fileName() == "." || fi2.fileName()==".." )
|
|
continue;
|
|
bSuccess = deleteFLD( fi2.absFilePath(), false );
|
|
if (!bSuccess) break;
|
|
}
|
|
if (bSuccess)
|
|
{
|
|
bSuccess = FileAccess::removeDir( name );
|
|
if ( !bSuccess )
|
|
{
|
|
m_pStatusInfo->addText( i18n("Error: rmdir( %1 ) operation failed.").tqarg(name));
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool bSuccess = FileAccess::removeFile( name );
|
|
if ( !bSuccess )
|
|
{
|
|
m_pStatusInfo->addText( i18n("Error: delete operation failed.") );
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool DirectoryMergeWindow::mergeFLD( const TQString& nameA,const TQString& nameB,const TQString& nameC,const TQString& nameDest, bool& bSingleFileMerge )
|
|
{
|
|
FileAccess fi(nameA);
|
|
if (fi.isDir())
|
|
{
|
|
return makeDir(nameDest);
|
|
}
|
|
|
|
// Make sure that the dir exists, into which we will save the file later.
|
|
int pos=nameDest.findRev('/');
|
|
if ( pos>0 )
|
|
{
|
|
TQString parentName = nameDest.left(pos);
|
|
bool bSuccess = makeDir(parentName, true /*quiet*/);
|
|
if (!bSuccess)
|
|
return false;
|
|
}
|
|
|
|
m_pStatusInfo->addText(i18n("manual merge( %1, %2, %3 -> %4)").tqarg(nameA).tqarg(nameB).tqarg(nameC).tqarg(nameDest));
|
|
if ( m_bSimulatedMergeStarted )
|
|
{
|
|
m_pStatusInfo->addText(i18n(" Note: After a manual merge the user should continue by pressing F7.") );
|
|
return true;
|
|
}
|
|
|
|
bSingleFileMerge = true;
|
|
(*m_currentItemForOperation)->setText( s_OpStatusCol, i18n("In progress...") );
|
|
ensureItemVisible( *m_currentItemForOperation );
|
|
|
|
emit startDiffMerge( nameA, nameB, nameC, nameDest, "","","",0 );
|
|
|
|
return false;
|
|
}
|
|
|
|
bool DirectoryMergeWindow::copyFLD( const TQString& srcName, const TQString& destName )
|
|
{
|
|
if ( srcName == destName )
|
|
return true;
|
|
|
|
if ( FileAccess(destName, true).exists() )
|
|
{
|
|
bool bSuccess = deleteFLD( destName, m_pOptions->m_bDmCreateBakFiles );
|
|
if ( !bSuccess )
|
|
{
|
|
m_pStatusInfo->addText(i18n("Error: copy( %1 -> %2 ) failed."
|
|
"Deleting existing destination failed.").tqarg(srcName).tqarg(destName));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
FileAccess fi( srcName );
|
|
|
|
if ( fi.isSymLink() && (fi.isDir() && !m_bFollowDirLinks || !fi.isDir() && !m_bFollowFileLinks) )
|
|
{
|
|
m_pStatusInfo->addText(i18n("copyLink( %1 -> %2 )").tqarg(srcName).tqarg(destName));
|
|
#ifdef _WIN32
|
|
// What are links?
|
|
#else
|
|
if ( m_bSimulatedMergeStarted )
|
|
{
|
|
return true;
|
|
}
|
|
FileAccess destFi(destName);
|
|
if ( !destFi.isLocal() || !fi.isLocal() )
|
|
{
|
|
m_pStatusInfo->addText(i18n("Error: copyLink failed: Remote links are not yet supported."));
|
|
return false;
|
|
}
|
|
TQString linkTarget = fi.readLink();
|
|
bool bSuccess = FileAccess::symLink( linkTarget, destName );
|
|
if (!bSuccess)
|
|
m_pStatusInfo->addText(i18n("Error: copyLink failed."));
|
|
return bSuccess;
|
|
#endif
|
|
}
|
|
|
|
if ( fi.isDir() )
|
|
{
|
|
bool bSuccess = makeDir( destName );
|
|
return bSuccess;
|
|
}
|
|
|
|
int pos=destName.findRev('/');
|
|
if ( pos>0 )
|
|
{
|
|
TQString parentName = destName.left(pos);
|
|
bool bSuccess = makeDir(parentName, true /*quiet*/);
|
|
if (!bSuccess)
|
|
return false;
|
|
}
|
|
|
|
m_pStatusInfo->addText(i18n("copy( %1 -> %2 )").tqarg(srcName).tqarg(destName));
|
|
|
|
if ( m_bSimulatedMergeStarted )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
FileAccess faSrc ( srcName );
|
|
bool bSuccess = faSrc.copyFile( destName );
|
|
if (! bSuccess ) m_pStatusInfo->addText( faSrc.getStatusText() );
|
|
return bSuccess;
|
|
}
|
|
|
|
// Rename is not an operation that can be selected by the user.
|
|
// It will only be used to create backups.
|
|
// Hence it will delete an existing destination without making a backup (of the old backup.)
|
|
bool DirectoryMergeWindow::renameFLD( const TQString& srcName, const TQString& destName )
|
|
{
|
|
if ( srcName == destName )
|
|
return true;
|
|
|
|
if ( FileAccess(destName, true).exists() )
|
|
{
|
|
bool bSuccess = deleteFLD( destName, false /*no backup*/ );
|
|
if (!bSuccess)
|
|
{
|
|
m_pStatusInfo->addText( i18n("Error during rename( %1 -> %2 ): "
|
|
"Cannot delete existing destination." ).tqarg(srcName).tqarg(destName));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
m_pStatusInfo->addText(i18n("rename( %1 -> %2 )").tqarg(srcName).tqarg(destName));
|
|
if ( m_bSimulatedMergeStarted )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool bSuccess = FileAccess( srcName ).rename( destName );
|
|
if (!bSuccess)
|
|
{
|
|
m_pStatusInfo->addText( i18n("Error: Rename failed.") );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DirectoryMergeWindow::makeDir( const TQString& name, bool bQuiet )
|
|
{
|
|
FileAccess fi(name, true);
|
|
if( fi.exists() && fi.isDir() )
|
|
return true;
|
|
|
|
if( fi.exists() && !fi.isDir() )
|
|
{
|
|
bool bSuccess = deleteFLD( name, true );
|
|
if (!bSuccess)
|
|
{
|
|
m_pStatusInfo->addText( i18n("Error during makeDir of %1. "
|
|
"Cannot delete existing file." ).tqarg(name));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int pos=name.findRev('/');
|
|
if ( pos>0 )
|
|
{
|
|
TQString parentName = name.left(pos);
|
|
bool bSuccess = makeDir(parentName,true);
|
|
if (!bSuccess)
|
|
return false;
|
|
}
|
|
|
|
if ( ! bQuiet )
|
|
m_pStatusInfo->addText(i18n("makeDir( %1 )").tqarg(name));
|
|
|
|
if ( m_bSimulatedMergeStarted )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool bSuccess = FileAccess::makeDir( name );
|
|
if ( bSuccess == false )
|
|
{
|
|
m_pStatusInfo->addText( i18n("Error while creating directory.") );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
DirectoryMergeInfo::DirectoryMergeInfo( TQWidget* pParent )
|
|
: TQFrame(pParent)
|
|
{
|
|
TQVBoxLayout *topLayout = new TQVBoxLayout( this );
|
|
|
|
TQGridLayout *grid = new TQGridLayout( topLayout );
|
|
grid->setColStretch(1,10);
|
|
|
|
int line=0;
|
|
|
|
m_pA = new TQLabel("A",this); grid->addWidget( m_pA,line, 0 );
|
|
m_pInfoA = new TQLabel(this); grid->addWidget( m_pInfoA,line,1 ); ++line;
|
|
m_pB = new TQLabel("B",this); grid->addWidget( m_pB,line, 0 );
|
|
m_pInfoB = new TQLabel(this); grid->addWidget( m_pInfoB,line,1 ); ++line;
|
|
m_pC = new TQLabel("C",this); grid->addWidget( m_pC,line, 0 );
|
|
m_pInfoC = new TQLabel(this); grid->addWidget( m_pInfoC,line,1 ); ++line;
|
|
m_pDest = new TQLabel(i18n("Dest"),this); grid->addWidget( m_pDest,line, 0 );
|
|
m_pInfoDest = new TQLabel(this); grid->addWidget( m_pInfoDest,line,1 ); ++line;
|
|
|
|
m_pInfoList = new TQListView(this); topLayout->addWidget( m_pInfoList );
|
|
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 );
|
|
|
|
m_pInfoList->installEventFilter(this);
|
|
}
|
|
|
|
bool DirectoryMergeInfo::eventFilter(TQObject*o, TQEvent* e)
|
|
{
|
|
if ( e->type()==TQEvent::FocusIn && TQT_BASE_OBJECT(o)==TQT_BASE_OBJECT(m_pInfoList) )
|
|
emit gotFocus();
|
|
return false;
|
|
}
|
|
|
|
static void addListViewItem( TQListView* pListView, const TQString& dir,
|
|
const TQString& basePath, FileAccess& fi )
|
|
{
|
|
if ( basePath.isEmpty() )
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if ( fi.exists() )
|
|
{
|
|
TQString dateString = fi.lastModified().toString("yyyy-MM-dd hh:mm:ss");
|
|
|
|
new TQListViewItem(
|
|
pListView,
|
|
dir,
|
|
TQString( fi.isDir() ? i18n("Dir") : i18n("File") ) + (fi.isSymLink() ? "-Link" : ""),
|
|
TQString::number(fi.size()),
|
|
TQString(fi.isReadable() ? "r" : " ") + (fi.isWritable()?"w" : " ")
|
|
#ifdef _WIN32
|
|
/*Future: Use GetFileAttributes()*/,
|
|
#else
|
|
+ (fi.isExecutable()?"x" : " "),
|
|
#endif
|
|
dateString,
|
|
TQString(fi.isSymLink() ? (" -> " + fi.readLink()) : TQString(""))
|
|
);
|
|
}
|
|
else
|
|
{
|
|
new TQListViewItem(
|
|
pListView,
|
|
dir,
|
|
i18n("not available"),
|
|
"",
|
|
"",
|
|
"",
|
|
""
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DirectoryMergeInfo::setInfo(
|
|
const FileAccess& dirA,
|
|
const FileAccess& dirB,
|
|
const FileAccess& dirC,
|
|
const FileAccess& dirDest,
|
|
MergeFileInfos& mfi )
|
|
{
|
|
bool bHideDest = false;
|
|
if ( dirA.absFilePath()==dirDest.absFilePath() )
|
|
{
|
|
m_pA->setText( i18n("A (Dest): ") ); bHideDest=true;
|
|
}
|
|
else
|
|
m_pA->setText( !dirC.isValid() ? TQString("A: ") : i18n("A (Base): "));
|
|
|
|
m_pInfoA->setText( dirA.prettyAbsPath() );
|
|
|
|
if ( dirB.absFilePath()==dirDest.absFilePath() )
|
|
{
|
|
m_pB->setText( i18n("B (Dest): ") ); bHideDest=true;
|
|
}
|
|
else
|
|
m_pB->setText( "B: " );
|
|
m_pInfoB->setText( dirB.prettyAbsPath() );
|
|
|
|
if ( dirC.absFilePath()==dirDest.absFilePath() )
|
|
{
|
|
m_pC->setText( i18n("C (Dest): ") ); bHideDest=true;
|
|
}
|
|
else
|
|
m_pC->setText( "C: " );
|
|
m_pInfoC->setText( dirC.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(); }
|
|
|
|
if (!dirDest.isValid()||bHideDest) { m_pDest->hide(); m_pInfoDest->hide(); }
|
|
else { m_pDest->show(); m_pInfoDest->show(); }
|
|
|
|
m_pInfoList->clear();
|
|
addListViewItem( m_pInfoList, "A", dirA.prettyAbsPath(), mfi.m_fileInfoA );
|
|
addListViewItem( m_pInfoList, "B", dirB.prettyAbsPath(), mfi.m_fileInfoB );
|
|
addListViewItem( m_pInfoList, "C", dirC.prettyAbsPath(), mfi.m_fileInfoC );
|
|
if (!bHideDest)
|
|
{
|
|
FileAccess fiDest( dirDest.prettyAbsPath() + "/" + mfi.m_subPath, true );
|
|
addListViewItem( m_pInfoList, i18n("Dest"), dirDest.prettyAbsPath(), fiDest );
|
|
}
|
|
}
|
|
|
|
TQTextStream& operator<<( TQTextStream& ts, MergeFileInfos& mfi )
|
|
{
|
|
ts << "{\n";
|
|
ValueMap vm;
|
|
vm.writeEntry( "SubPath", mfi.m_subPath );
|
|
vm.writeEntry( "ExistsInA", mfi.m_bExistsInA );
|
|
vm.writeEntry( "ExistsInB", mfi.m_bExistsInB );
|
|
vm.writeEntry( "ExistsInC", mfi.m_bExistsInC );
|
|
vm.writeEntry( "EqualAB", mfi.m_bEqualAB );
|
|
vm.writeEntry( "EqualAC", mfi.m_bEqualAC );
|
|
vm.writeEntry( "EqualBC", mfi.m_bEqualBC );
|
|
//DirMergeItem* m_pDMI;
|
|
//MergeFileInfos* m_pParent;
|
|
vm.writeEntry( "MergeOperation", (int) mfi.m_eMergeOperation );
|
|
vm.writeEntry( "DirA", mfi.m_bDirA );
|
|
vm.writeEntry( "DirB", mfi.m_bDirB );
|
|
vm.writeEntry( "DirC", mfi.m_bDirC );
|
|
vm.writeEntry( "LinkA", mfi.m_bLinkA );
|
|
vm.writeEntry( "LinkB", mfi.m_bLinkB );
|
|
vm.writeEntry( "LinkC", mfi.m_bLinkC );
|
|
vm.writeEntry( "OperationComplete", mfi.m_bOperationComplete );
|
|
//bool m_bSimOpComplete );
|
|
|
|
vm.writeEntry( "AgeA", (int) mfi.m_ageA );
|
|
vm.writeEntry( "AgeB", (int) mfi.m_ageB );
|
|
vm.writeEntry( "AgeC", (int) mfi.m_ageC );
|
|
vm.writeEntry( "ConflictingAges", mfi.m_bConflictingAges ); // Equal age but files are not!
|
|
|
|
//FileAccess m_fileInfoA;
|
|
//FileAccess m_fileInfoB;
|
|
//FileAccess m_fileInfoC;
|
|
|
|
//TotalDifftqStatus m_totalDifftqStatus;
|
|
|
|
vm.save(ts);
|
|
|
|
ts << "}\n";
|
|
|
|
return ts;
|
|
}
|
|
|
|
void DirectoryMergeWindow::slotSaveMergeState()
|
|
{
|
|
//slotStatusMsg(i18n("Saving Directory Merge State ..."));
|
|
|
|
//TQString s = KFileDialog::getSaveURL( TQDir::currentDirPath(), 0, this, i18n("Save As...") ).url();
|
|
TQString s = KFileDialog::getSaveFileName( TQDir::currentDirPath(), 0, this, i18n("Save Directory Merge State As...") );
|
|
if(!s.isEmpty())
|
|
{
|
|
m_dirMergeStateFilename = s;
|
|
|
|
|
|
TQFile file(m_dirMergeStateFilename);
|
|
bool bSuccess = file.open( IO_WriteOnly );
|
|
if ( bSuccess )
|
|
{
|
|
TQTextStream ts( &file );
|
|
|
|
TQListViewItemIterator it( this );
|
|
while ( it.current() ) {
|
|
DirMergeItem* item = static_cast<DirMergeItem*>(it.current());
|
|
MergeFileInfos* pMFI = item->m_pMFI;
|
|
ts << *pMFI;
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
//slotStatusMsg(i18n("Ready."));
|
|
|
|
}
|
|
|
|
void DirectoryMergeWindow::slotLoadMergeState()
|
|
{
|
|
}
|
|
|
|
void DirectoryMergeWindow::updateFileVisibilities()
|
|
{
|
|
bool bShowIdentical = m_pDirShowIdenticalFiles->isChecked();
|
|
bool bShowDifferent = m_pDirShowDifferentFiles->isChecked();
|
|
bool bShowOnlyInA = m_pDirShowFilesOnlyInA->isChecked();
|
|
bool bShowOnlyInB = m_pDirShowFilesOnlyInB->isChecked();
|
|
bool bShowOnlyInC = m_pDirShowFilesOnlyInC->isChecked();
|
|
bool bThreeDirs = m_dirC.isValid();
|
|
m_pSelection1Item = 0;
|
|
m_pSelection2Item = 0;
|
|
m_pSelection3Item = 0;
|
|
|
|
TQListViewItem* p = firstChild();
|
|
while(p)
|
|
{
|
|
DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
|
|
MergeFileInfos* pMFI = pDMI->m_pMFI;
|
|
bool bDir = pMFI->m_bDirA || pMFI->m_bDirB || pMFI->m_bDirC;
|
|
bool bExistsEverywhere = pMFI->m_bExistsInA && pMFI->m_bExistsInB && (pMFI->m_bExistsInC || !bThreeDirs);
|
|
int existCount = int(pMFI->m_bExistsInA) + int(pMFI->m_bExistsInB) + int(pMFI->m_bExistsInC);
|
|
bool bVisible =
|
|
( bShowIdentical && bExistsEverywhere && pMFI->m_bEqualAB && (pMFI->m_bEqualAC || !bThreeDirs) )
|
|
|| ( (bShowDifferent||bDir) && existCount>=2 && (!pMFI->m_bEqualAB || !(pMFI->m_bEqualAC || !bThreeDirs)))
|
|
|| ( bShowOnlyInA && pMFI->m_bExistsInA && !pMFI->m_bExistsInB && !pMFI->m_bExistsInC )
|
|
|| ( bShowOnlyInB && !pMFI->m_bExistsInA && pMFI->m_bExistsInB && !pMFI->m_bExistsInC )
|
|
|| ( bShowOnlyInC && !pMFI->m_bExistsInA && !pMFI->m_bExistsInB && pMFI->m_bExistsInC );
|
|
|
|
TQString fileName = pMFI->m_subPath.section( '/', -1 );
|
|
bVisible = bVisible && (
|
|
bDir && ! wildcardMultiMatch( m_pOptions->m_DmDirAntiPattern, fileName, m_bCaseSensitive )
|
|
|| wildcardMultiMatch( m_pOptions->m_DmFilePattern, fileName, m_bCaseSensitive )
|
|
&& !wildcardMultiMatch( m_pOptions->m_DmFileAntiPattern, fileName, m_bCaseSensitive ) );
|
|
|
|
p->setVisible(bVisible);
|
|
p = treeIterator( p, true, true );
|
|
}
|
|
}
|
|
|
|
void DirectoryMergeWindow::slotShowIdenticalFiles() { m_pOptions->m_bDmShowIdenticalFiles=m_pDirShowIdenticalFiles->isChecked();
|
|
updateFileVisibilities(); }
|
|
void DirectoryMergeWindow::slotShowDifferentFiles() { updateFileVisibilities(); }
|
|
void DirectoryMergeWindow::slotShowFilesOnlyInA() { updateFileVisibilities(); }
|
|
void DirectoryMergeWindow::slotShowFilesOnlyInB() { updateFileVisibilities(); }
|
|
void DirectoryMergeWindow::slotShowFilesOnlyInC() { updateFileVisibilities(); }
|
|
|
|
void DirectoryMergeWindow::slotSynchronizeDirectories() { }
|
|
void DirectoryMergeWindow::slotChooseNewerFiles() { }
|
|
|
|
void DirectoryMergeWindow::initDirectoryMergeActions( TQObject* pKDiff3App, KActionCollection* ac )
|
|
{
|
|
#include "xpm/startmerge.xpm"
|
|
#include "xpm/showequalfiles.xpm"
|
|
#include "xpm/showfilesonlyina.xpm"
|
|
#include "xpm/showfilesonlyinb.xpm"
|
|
#include "xpm/showfilesonlyinc.xpm"
|
|
DirectoryMergeWindow* p = this;
|
|
|
|
m_pDirStartOperation = new KAction(i18n("Start/Continue Directory Merge"), TQt::Key_F7, TQT_TQOBJECT(p), TQT_SLOT(slotRunOperationForAllItems()), ac, "dir_start_operation");
|
|
m_pDirRunOperationForCurrentItem = new KAction(i18n("Run Operation for Current Item"), TQt::Key_F6, TQT_TQOBJECT(p), TQT_SLOT(slotRunOperationForCurrentItem()), ac, "dir_run_operation_for_current_item");
|
|
m_pDirCompareCurrent = new KAction(i18n("Compare Selected File"), 0, TQT_TQOBJECT(p), TQT_SLOT(compareCurrentFile()), ac, "dir_compare_current");
|
|
m_pDirMergeCurrent = new KAction(i18n("Merge Current File"), TQIconSet(TQPixmap(startmerge)), 0, TQT_TQOBJECT(pKDiff3App), TQT_SLOT(slotMergeCurrentFile()), ac, "merge_current");
|
|
m_pDirFoldAll = new KAction(i18n("Fold All Subdirs"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotFoldAllSubdirs()), ac, "dir_fold_all");
|
|
m_pDirUnfoldAll = new KAction(i18n("Unfold All Subdirs"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotUnfoldAllSubdirs()), ac, "dir_unfold_all");
|
|
m_pDirRescan = new KAction(i18n("Rescan"), TQt::SHIFT+TQt::Key_F5, TQT_TQOBJECT(p), TQT_SLOT(reload()), ac, "dir_rescan");
|
|
m_pDirSaveMergeState = 0; //new KAction(i18n("Save Directory Merge State ..."), 0, TQT_TQOBJECT(p), TQT_SLOT(slotSaveMergeState()), ac, "dir_save_merge_state");
|
|
m_pDirLoadMergeState = 0; //new KAction(i18n("Load Directory Merge State ..."), 0, TQT_TQOBJECT(p), TQT_SLOT(slotLoadMergeState()), ac, "dir_load_merge_state");
|
|
m_pDirChooseAEverywhere = new KAction(i18n("Choose A for All Items"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotChooseAEverywhere()), ac, "dir_choose_a_everywhere");
|
|
m_pDirChooseBEverywhere = new KAction(i18n("Choose B for All Items"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotChooseBEverywhere()), ac, "dir_choose_b_everywhere");
|
|
m_pDirChooseCEverywhere = new KAction(i18n("Choose C for All Items"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotChooseCEverywhere()), ac, "dir_choose_c_everywhere");
|
|
m_pDirAutoChoiceEverywhere = new KAction(i18n("Auto-Choose Operation for All Items"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotAutoChooseEverywhere()), ac, "dir_autochoose_everywhere");
|
|
m_pDirDoNothingEverywhere = new KAction(i18n("No Operation for All Items"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotNoOpEverywhere()), ac, "dir_nothing_everywhere");
|
|
|
|
// m_pDirSynchronizeDirectories = new KToggleAction(i18n("Synchronize Directories"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotSynchronizeDirectories()), ac, "dir_synchronize_directories");
|
|
// m_pDirChooseNewerFiles = new KToggleAction(i18n("Copy Newer Files Instead of Merging"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotChooseNewerFiles()), ac, "dir_choose_newer_files");
|
|
|
|
m_pDirShowIdenticalFiles = new KToggleAction(i18n("Show Identical Files"), TQIconSet(TQPixmap(showequalfiles)), 0, TQT_TQOBJECT(this), TQT_SLOT(slotShowIdenticalFiles()), ac, "dir_show_identical_files");
|
|
m_pDirShowDifferentFiles = new KToggleAction(i18n("Show Different Files"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotShowDifferentFiles()), ac, "dir_show_different_files");
|
|
m_pDirShowFilesOnlyInA = new KToggleAction(i18n("Show Files only in A"), TQIconSet(TQPixmap(showfilesonlyina)), 0, TQT_TQOBJECT(this), TQT_SLOT(slotShowFilesOnlyInA()), ac, "dir_show_files_only_in_a");
|
|
m_pDirShowFilesOnlyInB = new KToggleAction(i18n("Show Files only in B"), TQIconSet(TQPixmap(showfilesonlyinb)), 0, TQT_TQOBJECT(this), TQT_SLOT(slotShowFilesOnlyInB()), ac, "dir_show_files_only_in_b");
|
|
m_pDirShowFilesOnlyInC = new KToggleAction(i18n("Show Files only in C"), TQIconSet(TQPixmap(showfilesonlyinc)), 0, TQT_TQOBJECT(this), TQT_SLOT(slotShowFilesOnlyInC()), ac, "dir_show_files_only_in_c");
|
|
|
|
m_pDirShowIdenticalFiles->setChecked( m_pOptions->m_bDmShowIdenticalFiles );
|
|
|
|
m_pDirCompareExplicit = new KAction(i18n("Compare Explicitly Selected Files"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCompareExplicitlySelectedFiles()), ac, "dir_compare_explicitly_selected_files");
|
|
m_pDirMergeExplicit = new KAction(i18n("Merge Explicitly Selected Files"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotMergeExplicitlySelectedFiles()), ac, "dir_merge_explicitly_selected_files");
|
|
|
|
m_pDirCurrentDoNothing = new KAction(i18n("Do Nothing"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentDoNothing()), ac, "dir_current_do_nothing");
|
|
m_pDirCurrentChooseA = new KAction(i18n("A"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentChooseA()), ac, "dir_current_choose_a");
|
|
m_pDirCurrentChooseB = new KAction(i18n("B"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentChooseB()), ac, "dir_current_choose_b");
|
|
m_pDirCurrentChooseC = new KAction(i18n("C"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentChooseC()), ac, "dir_current_choose_c");
|
|
m_pDirCurrentMerge = new KAction(i18n("Merge"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentMerge()), ac, "dir_current_merge");
|
|
m_pDirCurrentDelete = new KAction(i18n("Delete (if exists)"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentDelete()), ac, "dir_current_delete");
|
|
|
|
m_pDirCurrentSyncDoNothing = new KAction(i18n("Do Nothing"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentDoNothing()), ac, "dir_current_sync_do_nothing");
|
|
m_pDirCurrentSyncCopyAToB = new KAction(i18n("Copy A to B"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentCopyAToB()), ac, "dir_current_sync_copy_a_to_b" );
|
|
m_pDirCurrentSyncCopyBToA = new KAction(i18n("Copy B to A"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentCopyBToA()), ac, "dir_current_sync_copy_b_to_a" );
|
|
m_pDirCurrentSyncDeleteA = new KAction(i18n("Delete A"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentDeleteA()), ac,"dir_current_sync_delete_a");
|
|
m_pDirCurrentSyncDeleteB = new KAction(i18n("Delete B"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentDeleteB()), ac,"dir_current_sync_delete_b");
|
|
m_pDirCurrentSyncDeleteAAndB = new KAction(i18n("Delete A && B"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentDeleteAAndB()), ac,"dir_current_sync_delete_a_and_b");
|
|
m_pDirCurrentSyncMergeToA = new KAction(i18n("Merge to A"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentMergeToA()), ac,"dir_current_sync_merge_to_a");
|
|
m_pDirCurrentSyncMergeToB = new KAction(i18n("Merge to B"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentMergeToB()), ac,"dir_current_sync_merge_to_b");
|
|
m_pDirCurrentSyncMergeToAAndB = new KAction(i18n("Merge to A && B"), 0, TQT_TQOBJECT(p), TQT_SLOT(slotCurrentMergeToAAndB()), ac,"dir_current_sync_merge_to_a_and_b");
|
|
|
|
|
|
}
|
|
|
|
|
|
void DirectoryMergeWindow::updateAvailabilities( bool bDirCompare, bool bDiffWindowVisible,
|
|
KToggleAction* chooseA, KToggleAction* chooseB, KToggleAction* chooseC )
|
|
{
|
|
m_pDirStartOperation->setEnabled( bDirCompare );
|
|
m_pDirRunOperationForCurrentItem->setEnabled( bDirCompare );
|
|
m_pDirFoldAll->setEnabled( bDirCompare );
|
|
m_pDirUnfoldAll->setEnabled( bDirCompare );
|
|
|
|
m_pDirCompareCurrent->setEnabled( bDirCompare && isVisible() && isFileSelected() );
|
|
|
|
m_pDirMergeCurrent->setEnabled( bDirCompare && isVisible() && isFileSelected()
|
|
|| bDiffWindowVisible );
|
|
|
|
m_pDirRescan->setEnabled( bDirCompare );
|
|
|
|
m_pDirAutoChoiceEverywhere->setEnabled( bDirCompare && isVisible() );
|
|
m_pDirDoNothingEverywhere->setEnabled( bDirCompare && isVisible() );
|
|
m_pDirChooseAEverywhere->setEnabled( bDirCompare && isVisible() );
|
|
m_pDirChooseBEverywhere->setEnabled( bDirCompare && isVisible() );
|
|
m_pDirChooseCEverywhere->setEnabled( bDirCompare && isVisible() );
|
|
|
|
bool bThreeDirs = m_dirC.isValid();
|
|
|
|
TQListViewItem* 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);
|
|
|
|
bool bDirWindowHasFocus = isVisible() && hasFocus();
|
|
|
|
m_pDirShowIdenticalFiles->setEnabled( bDirCompare && isVisible() );
|
|
m_pDirShowDifferentFiles->setEnabled( bDirCompare && isVisible() );
|
|
m_pDirShowFilesOnlyInA->setEnabled( bDirCompare && isVisible() );
|
|
m_pDirShowFilesOnlyInB->setEnabled( bDirCompare && isVisible() );
|
|
m_pDirShowFilesOnlyInC->setEnabled( bDirCompare && isVisible() && bThreeDirs );
|
|
|
|
m_pDirCompareExplicit->setEnabled( bDirCompare && isVisible() && m_pSelection2Item!=0 );
|
|
m_pDirMergeExplicit->setEnabled( bDirCompare && isVisible() && m_pSelection2Item!=0 );
|
|
|
|
m_pDirCurrentDoNothing->setEnabled( bItemActive && bMergeMode );
|
|
m_pDirCurrentChooseA->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInA );
|
|
m_pDirCurrentChooseB->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInB );
|
|
m_pDirCurrentChooseC->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInC );
|
|
m_pDirCurrentMerge->setEnabled( bItemActive && bMergeMode && !bFTConflict );
|
|
m_pDirCurrentDelete->setEnabled( bItemActive && bMergeMode );
|
|
if ( bDirWindowHasFocus )
|
|
{
|
|
chooseA->setEnabled( bItemActive && pMFI->m_bExistsInA );
|
|
chooseB->setEnabled( bItemActive && pMFI->m_bExistsInB );
|
|
chooseC->setEnabled( bItemActive && pMFI->m_bExistsInC );
|
|
chooseA->setChecked( false );
|
|
chooseB->setChecked( false );
|
|
chooseC->setChecked( false );
|
|
}
|
|
|
|
m_pDirCurrentSyncDoNothing->setEnabled( bItemActive && !bMergeMode );
|
|
m_pDirCurrentSyncCopyAToB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA );
|
|
m_pDirCurrentSyncCopyBToA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB );
|
|
m_pDirCurrentSyncDeleteA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA );
|
|
m_pDirCurrentSyncDeleteB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB );
|
|
m_pDirCurrentSyncDeleteAAndB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB && pMFI->m_bExistsInB );
|
|
m_pDirCurrentSyncMergeToA->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
|
|
m_pDirCurrentSyncMergeToB->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
|
|
m_pDirCurrentSyncMergeToAAndB->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
|
|
}
|
|
|
|
|
|
#include "directorymergewindow.moc"
|