joachim99@8: /*************************************************************************** joachim99@8: directorymergewindow.cpp joachim99@58: ----------------- joachim99@8: begin : Sat Oct 19 2002 joachim99@77: copyright : (C) 2002-2007 by Joachim Eibl joachim99@69: email : joachim.eibl at gmx.de joachim99@8: ***************************************************************************/ joachim99@8: joachim99@8: /*************************************************************************** joachim99@8: * * joachim99@8: * This program is free software; you can redistribute it and/or modify * joachim99@8: * it under the terms of the GNU General Public License as published by * joachim99@8: * the Free Software Foundation; either version 2 of the License, or * joachim99@8: * (at your option) any later version. * joachim99@8: * * joachim99@8: ***************************************************************************/ joachim99@8: joachim99@8: #include "directorymergewindow.h" joachim99@8: #include "optiondialog.h" joachim99@8: #include joachim99@8: #include joachim99@8: joachim99@75: #include joachim99@75: #include joachim99@75: #include joachim99@75: #include joachim99@70: #include joachim99@70: #include joachim99@75: #include joachim99@75: #include joachim99@75: #include joachim99@75: #include joachim99@75: #include joachim99@75: #include joachim99@75: #include joachim99@75: #include joachim99@75: joachim99@75: joachim99@80: #include joachim99@51: #include joachim99@8: #include joachim99@69: #include joachim99@8: #include joachim99@8: #include joachim99@80: #include joachim99@75: joachim99@8: #include joachim99@8: #include joachim99@73: //#include joachim99@8: joachim99@80: #include "guiutils.h" joachim99@80: joachim99@51: static bool conflictingFileTypes(MergeFileInfos& mfi); joachim99@80: joachim99@75: class StatusInfo : public QTextEdit joachim99@69: { joachim99@69: public: joachim99@75: StatusInfo(QWidget* pParent) : QTextEdit( pParent ) joachim99@69: { joachim99@75: setObjectName("StatusInfo"); joachim99@70: setWindowFlags(Qt::Dialog); joachim99@75: setWordWrapMode(QTextOption::NoWrap); joachim99@69: setReadOnly(true); joachim99@80: setWindowModality( Qt::ApplicationModal ); joachim99@77: //showMaximized(); joachim99@69: } joachim99@69: joachim99@75: bool isEmpty(){ joachim99@75: return toPlainText().isEmpty(); } joachim99@69: joachim99@69: void addText(const QString& s ) joachim99@69: { joachim99@69: append(s); joachim99@69: } joachim99@69: joachim99@80: void setVisible(bool bVisible) joachim99@69: { joachim99@80: if (bVisible) joachim99@80: { joachim99@80: moveCursor ( QTextCursor::End ); joachim99@80: moveCursor ( QTextCursor::StartOfLine ); joachim99@80: ensureCursorVisible(); joachim99@80: } joachim99@80: joachim99@80: QTextEdit::setVisible(bVisible); joachim99@69: } joachim99@69: }; joachim99@8: joachim99@8: joachim99@8: class TempRemover joachim99@8: { joachim99@8: public: joachim99@8: TempRemover( const QString& origName, FileAccess& fa ); joachim99@8: ~TempRemover(); joachim99@8: QString name() { return m_name; } joachim99@8: bool success() { return m_bSuccess; } joachim99@8: private: joachim99@8: QString m_name; joachim99@8: bool m_bTemp; joachim99@8: bool m_bSuccess; joachim99@8: }; joachim99@8: TempRemover::TempRemover(const QString& origName, FileAccess& fa) joachim99@8: { joachim99@8: if ( fa.isLocal() ) joachim99@8: { joachim99@8: m_name = origName; joachim99@8: m_bTemp = false; joachim99@8: m_bSuccess = true; joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: m_name = FileAccess::tempFileName(); joachim99@8: m_bSuccess = fa.copyFile( m_name ); joachim99@8: m_bTemp = m_bSuccess; joachim99@8: } joachim99@8: } joachim99@8: TempRemover::~TempRemover() joachim99@8: { joachim99@8: if ( m_bTemp && ! m_name.isEmpty() ) joachim99@73: FileAccess::removeTempFile(m_name); joachim99@8: } joachim99@8: joachim99@8: void DirectoryMergeWindow::fastFileComparison( joachim99@8: FileAccess& fi1, FileAccess& fi2, joachim99@8: bool& bEqual, bool& bError, QString& status ) joachim99@8: { joachim99@66: ProgressProxy pp; joachim99@8: status = ""; joachim99@8: bEqual = false; joachim99@8: bError = true; joachim99@8: joachim99@8: if ( !m_bFollowFileLinks ) joachim99@8: { joachim99@8: if ( fi1.isSymLink() != fi2.isSymLink() ) joachim99@8: { joachim99@51: status = i18n("Mix of links and normal files."); joachim99@8: return; joachim99@8: } joachim99@8: else if ( fi1.isSymLink() && fi2.isSymLink() ) joachim99@8: { joachim99@8: bError = false; joachim99@8: bEqual = fi1.readLink() == fi2.readLink(); joachim99@51: status = i18n("Link: "); joachim99@8: return; joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: if ( fi1.size()!=fi2.size() ) joachim99@8: { joachim99@8: bEqual = false; joachim99@51: status = i18n("Size. "); joachim99@51: return; joachim99@51: } joachim99@51: else if ( m_pOptions->m_bDmTrustSize ) joachim99@51: { joachim99@51: bEqual = true; joachim99@8: return; joachim99@8: } joachim99@8: joachim99@8: if ( m_pOptions->m_bDmTrustDate ) joachim99@8: { joachim99@8: bEqual = ( fi1.lastModified() == fi2.lastModified() && fi1.size()==fi2.size() ); joachim99@8: bError = false; joachim99@51: status = i18n("Date & Size: "); joachim99@8: return; joachim99@8: } joachim99@8: joachim99@77: if ( m_pOptions->m_bDmTrustDateFallbackToBinary ) joachim99@77: { joachim99@77: bEqual = ( fi1.lastModified() == fi2.lastModified() && fi1.size()==fi2.size() ); joachim99@77: if ( bEqual ) joachim99@77: { joachim99@77: bError = false; joachim99@77: status = i18n("Date & Size: "); joachim99@77: return; joachim99@77: } joachim99@77: } joachim99@77: joachim99@80: QString fileName1 = fi1.absoluteFilePath(); joachim99@80: QString fileName2 = fi2.absoluteFilePath(); joachim99@8: TempRemover tr1( fileName1, fi1 ); joachim99@8: if ( !tr1.success() ) joachim99@8: { joachim99@80: status = i18n("Creating temp copy of %1 failed.",fileName1); joachim99@8: return; joachim99@8: } joachim99@8: TempRemover tr2( fileName2, fi2 ); joachim99@8: if ( !tr2.success() ) joachim99@8: { joachim99@80: status = i18n("Creating temp copy of %1 failed.",fileName2); joachim99@8: return; joachim99@8: } joachim99@8: joachim99@8: std::vector buf1(100000); joachim99@8: std::vector buf2(buf1.size()); joachim99@8: joachim99@8: QFile file1( tr1.name() ); joachim99@8: joachim99@70: if ( ! file1.open(QIODevice::ReadOnly) ) joachim99@8: { joachim99@80: status = i18n("Opening %1 failed.",fileName1); joachim99@8: return; joachim99@8: } joachim99@8: joachim99@8: QFile file2( tr2.name() ); joachim99@8: joachim99@70: if ( ! file2.open(QIODevice::ReadOnly) ) joachim99@8: { joachim99@80: status = i18n("Opening %1 failed.",fileName2); joachim99@8: return; joachim99@8: } joachim99@8: joachim99@68: pp.setInformation( i18n("Comparing file..."), 0, false ); joachim99@75: typedef qint64 t_FileSize; joachim99@66: t_FileSize fullSize = file1.size(); joachim99@66: t_FileSize sizeLeft = fullSize; joachim99@8: joachim99@66: while( sizeLeft>0 && ! pp.wasCancelled() ) joachim99@8: { joachim99@66: int len = min2( sizeLeft, (t_FileSize)buf1.size() ); joachim99@75: if( len != file1.read( &buf1[0], len ) ) joachim99@8: { joachim99@80: status = i18n("Error reading from %1",fileName1); joachim99@8: return; joachim99@8: } joachim99@8: joachim99@75: if( len != file2.read( &buf2[0], len ) ) joachim99@8: { joachim99@80: status = i18n("Error reading from %1",fileName2); joachim99@8: return; joachim99@8: } joachim99@8: joachim99@8: if ( memcmp( &buf1[0], &buf2[0], len ) != 0 ) joachim99@8: { joachim99@8: bError = false; joachim99@8: return; joachim99@8: } joachim99@66: sizeLeft-=len; joachim99@66: pp.setCurrent(double(fullSize-sizeLeft)/fullSize, false ); joachim99@8: } joachim99@8: joachim99@8: // If the program really arrives here, then the files are really equal. joachim99@8: bError = false; joachim99@8: bEqual = true; joachim99@8: } joachim99@8: joachim99@75: static int s_NameCol = 0; joachim99@8: static int s_ACol = 1; joachim99@8: static int s_BCol = 2; joachim99@8: static int s_CCol = 3; joachim99@8: static int s_OpCol = 4; joachim99@8: static int s_OpStatusCol = 5; joachim99@66: static int s_UnsolvedCol = 6; // Nr of unsolved conflicts (for 3 input files) joachim99@66: static int s_SolvedCol = 7; // Nr of auto-solvable conflicts (for 3 input files) joachim99@66: static int s_NonWhiteCol = 8; // Nr of nonwhite deltas (for 2 input files) joachim99@66: static int s_WhiteCol = 9; // Nr of white deltas (for 2 input files) joachim99@75: joachim99@75: // Previously Q3ListViewItem::paintCell(p,cg,column,width,align); joachim99@75: class DirectoryMergeWindow::DirMergeItemDelegate : public QItemDelegate joachim99@75: { joachim99@75: DirectoryMergeWindow* m_pDMW; joachim99@75: public: joachim99@75: DirMergeItemDelegate(DirectoryMergeWindow* pParent) joachim99@75: : QItemDelegate(pParent), m_pDMW(pParent) joachim99@75: { joachim99@75: } joachim99@75: void paint( QPainter * p, const QStyleOptionViewItem & option, const QModelIndex & index ) const joachim99@75: { joachim99@75: int column = index.column(); joachim99@75: if (column == s_ACol || column == s_BCol || column == s_CCol ) joachim99@75: { joachim99@75: QVariant value = index.data( Qt::DecorationRole ); joachim99@75: QPixmap icon; joachim99@75: if ( value.isValid() ) joachim99@75: { joachim99@75: if (value.type() == QVariant::Icon) joachim99@75: { joachim99@75: icon = qvariant_cast(value).pixmap(16,16); joachim99@75: //icon = qvariant_cast(value); joachim99@75: //decorationRect = QRect(QPoint(0, 0), icon.actualSize(option.decorationSize, iconMode, iconState)); joachim99@75: } joachim99@75: else joachim99@75: { joachim99@75: icon = qvariant_cast(value); joachim99@75: //decorationRect = QRect(QPoint(0, 0), option.decorationSize).intersected(pixmap.rect()); joachim99@75: } joachim99@75: } joachim99@75: joachim99@75: int x = option.rect.left(); joachim99@75: int y = option.rect.top(); joachim99@75: //QPixmap icon = value.value(); //pixmap(column); joachim99@75: if ( !icon.isNull() ) joachim99@75: { joachim99@75: int yOffset = (sizeHint(option,index).height() - icon.height()) / 2; joachim99@75: p->drawPixmap( x+2, y+yOffset, icon ); joachim99@75: joachim99@75: QTreeWidgetItem* pTWI = reinterpret_cast( index.internalPointer() ); joachim99@75: DirMergeItem* pDMI = static_cast(pTWI); joachim99@75: int i = pDMI==m_pDMW->m_pSelection1Item && column == m_pDMW->m_selection1Column ? 1 : joachim99@75: pDMI==m_pDMW->m_pSelection2Item && column == m_pDMW->m_selection2Column ? 2 : joachim99@75: pDMI==m_pDMW->m_pSelection3Item && column == m_pDMW->m_selection3Column ? 3 : joachim99@75: 0; joachim99@75: if ( i!=0 ) joachim99@75: { joachim99@75: OptionDialog* pOD = m_pDMW->m_pOptions; joachim99@75: QColor c ( i==1 ? pOD->m_colorA : i==2 ? pOD->m_colorB : pOD->m_colorC ); joachim99@75: p->setPen( c );// highlight() ); joachim99@75: p->drawRect( x+2, y+yOffset, icon.width(), icon.height()); joachim99@75: p->setPen( QPen( c, 0, Qt::DotLine) ); joachim99@75: p->drawRect( x+1, y+yOffset-1, icon.width()+2, icon.height()+2); joachim99@75: p->setPen( Qt::white ); joachim99@75: QString s( QChar('A'+i-1) ); joachim99@75: p->drawText( x+2 + (icon.width() - p->fontMetrics().width(s))/2, joachim99@75: y+yOffset + (icon.height() + p->fontMetrics().ascent())/2-1, joachim99@75: s ); joachim99@75: } joachim99@75: else joachim99@75: { joachim99@75: p->setPen( m_pDMW->palette().background().color() ); joachim99@75: p->drawRect( x+1, y+yOffset-1, icon.width()+2, icon.height()+2); joachim99@75: } joachim99@75: return; joachim99@75: } joachim99@75: } joachim99@75: QStyleOptionViewItem option2 = option; joachim99@75: if ( column>=s_UnsolvedCol ) joachim99@75: { joachim99@75: option2.displayAlignment = Qt::AlignRight; joachim99@75: } joachim99@75: QItemDelegate::paint( p, option2, index ); joachim99@75: } joachim99@75: }; joachim99@75: joachim99@75: joachim99@8: DirectoryMergeWindow::DirectoryMergeWindow( QWidget* pParent, OptionDialog* pOptions, KIconLoader* pIconLoader ) joachim99@75: : QTreeWidget( pParent ) joachim99@8: { joachim99@75: setItemDelegate( new DirMergeItemDelegate(this) ); joachim99@75: connect( this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(onDoubleClick(QTreeWidgetItem*))); joachim99@75: connect( this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(onCurrentChanged(QTreeWidgetItem*))); joachim99@75: connect( this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(onExpanded())); joachim99@8: m_pOptions = pOptions; joachim99@8: m_pIconLoader = pIconLoader; joachim99@8: m_pDirectoryMergeInfo = 0; joachim99@8: m_bSimulatedMergeStarted=false; joachim99@8: m_bRealMergeStarted=false; joachim99@8: m_bError = false; joachim99@8: m_bSyncMode = false; joachim99@8: m_pStatusInfo = new StatusInfo(0); joachim99@8: m_pStatusInfo->hide(); joachim99@66: m_bScanning = false; joachim99@69: m_pSelection1Item = 0; joachim99@69: m_pSelection2Item = 0; joachim99@69: m_pSelection3Item = 0; joachim99@69: m_bCaseSensitive = true; joachim99@68: joachim99@75: QStringList sl; joachim99@75: sl << i18n("Name") << "A" << "B" << "C" << i18n("Operation") << i18n("Status") joachim99@75: << i18n("Unsolved") << i18n("Solved") << i18n("Nonwhite") << i18n("White") << ""; joachim99@75: setHeaderLabels(sl); joachim99@75: joachim99@75: //TODO setColumnAlignment( s_UnsolvedCol, Qt::AlignRight ); joachim99@75: //setColumnAlignment( s_SolvedCol, Qt::AlignRight ); joachim99@75: //setColumnAlignment( s_NonWhiteCol, Qt::AlignRight ); joachim99@75: //setColumnAlignment( s_WhiteCol, Qt::AlignRight ); joachim99@8: } joachim99@8: joachim99@8: DirectoryMergeWindow::~DirectoryMergeWindow() joachim99@8: { joachim99@8: } joachim99@8: joachim99@8: joachim99@8: int DirectoryMergeWindow::totalColumnWidth() joachim99@8: { joachim99@8: int w=0; joachim99@8: for (int i=0; itoImage().convertToFormat(QImage::Format_ARGB32); joachim99@75: QImage img2 = pm2->toImage().convertToFormat(QImage::Format_ARGB32); joachim99@8: joachim99@8: for (int y = 0; y < img1.height(); y++) joachim99@8: { joachim99@75: quint32 *line1 = reinterpret_cast(img1.scanLine(y)); joachim99@75: quint32 *line2 = reinterpret_cast(img2.scanLine(y)); joachim99@8: for (int x = 0; x < img1.width(); x++) joachim99@8: { joachim99@8: if ( qAlpha( line2[x] ) >0 ) joachim99@8: line1[x] = (line2[x] | 0xff000000); joachim99@8: } joachim99@8: } joachim99@75: return QPixmap::fromImage(img1); joachim99@8: } joachim99@8: joachim99@8: // like pixCombiner but let the pm1 color shine through joachim99@69: static QPixmap pixCombiner2( const QPixmap* pm1, const QPixmap* pm2 ) joachim99@8: { joachim99@75: QPixmap pix=*pm1; joachim99@75: QPainter p(&pix); joachim99@75: p.setOpacity(0.5); joachim99@75: p.drawPixmap( 0,0,*pm2 ); joachim99@75: p.end(); joachim99@75: joachim99@8: return pix; joachim99@8: } joachim99@8: joachim99@8: static void calcDirStatus( bool bThreeDirs, DirMergeItem* i, int& nofFiles, joachim99@8: int& nofDirs, int& nofEqualFiles, int& nofManualMerges ) joachim99@8: { joachim99@8: if ( i->m_pMFI->m_bDirA || i->m_pMFI->m_bDirB || i->m_pMFI->m_bDirC ) joachim99@8: { joachim99@8: ++nofDirs; joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: ++nofFiles; joachim99@8: if ( i->m_pMFI->m_bEqualAB && (!bThreeDirs || i->m_pMFI->m_bEqualAC )) joachim99@8: { joachim99@8: ++nofEqualFiles; joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: if ( i->m_pMFI->m_eMergeOperation==eMergeABCToDest || i->m_pMFI->m_eMergeOperation==eMergeABToDest ) joachim99@8: ++nofManualMerges; joachim99@8: } joachim99@8: } joachim99@75: for( int childIdx=0; childIdxchildCount(); ++childIdx ) joachim99@75: calcDirStatus( bThreeDirs, static_cast(i->child(childIdx)), nofFiles, nofDirs, nofEqualFiles, nofManualMerges ); joachim99@8: } joachim99@8: joachim99@69: static QString sortString(const QString& s, bool bCaseSensitive) joachim99@58: { joachim99@69: if (bCaseSensitive) joachim99@69: return s; joachim99@69: else joachim99@75: return s.toUpper(); joachim99@58: } joachim99@58: joachim99@77: struct t_ItemInfo joachim99@77: { joachim99@77: bool bExpanded; joachim99@77: bool bOperationComplete; joachim99@77: QString status; joachim99@77: e_MergeOperation eMergeOperation; joachim99@77: }; joachim99@77: joachim99@8: bool DirectoryMergeWindow::init joachim99@8: ( joachim99@8: FileAccess& dirA, joachim99@8: FileAccess& dirB, joachim99@8: FileAccess& dirC, joachim99@8: FileAccess& dirDest, joachim99@77: bool bDirectoryMerge, joachim99@77: bool bReload joachim99@8: ) joachim99@8: { joachim99@66: if ( m_pOptions->m_bDmFullAnalysis ) joachim99@66: { joachim99@68: // A full analysis uses the same ressources that a normal text-diff/merge uses. joachim99@66: // So make sure that the user saves his data first. joachim99@66: bool bCanContinue=false; joachim99@66: checkIfCanContinue( &bCanContinue ); joachim99@66: if ( !bCanContinue ) joachim99@66: return false; joachim99@68: startDiffMerge("","","","","","","",0); // hide main window joachim99@66: } joachim99@68: joachim99@66: show(); joachim99@80: setUpdatesEnabled(true); joachim99@66: joachim99@77: std::map expandedDirsMap; joachim99@77: joachim99@77: if ( bReload ) joachim99@77: { joachim99@77: // Remember expandes items joachim99@77: QTreeWidgetItemIterator it( this ); joachim99@77: while ( *it ) joachim99@77: { joachim99@77: DirMergeItem* pDMI = static_cast( *it ); joachim99@77: t_ItemInfo& ii = expandedDirsMap[ pDMI->m_pMFI->m_subPath ]; joachim99@77: ii.bExpanded = pDMI->isExpanded(); joachim99@77: ii.bOperationComplete = pDMI->m_pMFI->m_bOperationComplete; joachim99@77: ii.status = pDMI->text( s_OpStatusCol ); joachim99@77: ii.eMergeOperation = pDMI->m_pMFI->m_eMergeOperation; joachim99@77: ++it; joachim99@77: } joachim99@77: } joachim99@77: joachim99@66: ProgressProxy pp; joachim99@8: m_bFollowDirLinks = m_pOptions->m_bDmFollowDirLinks; joachim99@8: m_bFollowFileLinks = m_pOptions->m_bDmFollowFileLinks; joachim99@8: m_bSimulatedMergeStarted=false; joachim99@8: m_bRealMergeStarted=false; joachim99@8: m_bError=false; joachim99@8: m_bDirectoryMerge = bDirectoryMerge; joachim99@69: m_pSelection1Item = 0; joachim99@69: m_pSelection2Item = 0; joachim99@69: m_pSelection3Item = 0; joachim99@69: m_bCaseSensitive = m_pOptions->m_bDmCaseSensitiveFilenameComparison; joachim99@8: joachim99@8: clear(); joachim99@8: joachim99@53: m_mergeItemList.clear(); joachim99@51: m_currentItemForOperation = m_mergeItemList.end(); joachim99@8: joachim99@8: m_dirA = dirA; joachim99@8: m_dirB = dirB; joachim99@8: m_dirC = dirC; joachim99@8: m_dirDest = dirDest; joachim99@8: joachim99@77: if ( !bReload ) joachim99@77: { joachim99@77: m_pDirShowIdenticalFiles->setChecked(true); joachim99@77: m_pDirShowDifferentFiles->setChecked(true); joachim99@77: m_pDirShowFilesOnlyInA->setChecked(true); joachim99@77: m_pDirShowFilesOnlyInB->setChecked(true); joachim99@77: m_pDirShowFilesOnlyInC->setChecked(true); joachim99@77: } joachim99@69: joachim99@8: // Check if all input directories exist and are valid. The dest dir is not tested now. joachim99@8: // The test will happen only when we are going to write to it. joachim99@8: if ( !m_dirA.isDir() || !m_dirB.isDir() || joachim99@8: (m_dirC.isValid() && !m_dirC.isDir()) ) joachim99@8: { joachim99@8: QString text( i18n("Opening of directories failed:") ); joachim99@8: text += "\n\n"; joachim99@8: if ( !dirA.isDir() ) joachim99@80: { text += i18n("Dir A \"%1\" does not exist or is not a directory.\n",m_dirA.prettyAbsPath()); } joachim99@8: joachim99@8: if ( !dirB.isDir() ) joachim99@80: { text += i18n("Dir B \"%1\" does not exist or is not a directory.\n",m_dirB.prettyAbsPath()); } joachim99@8: joachim99@8: if ( m_dirC.isValid() && !m_dirC.isDir() ) joachim99@80: { text += i18n("Dir C \"%1\" does not exist or is not a directory.\n",m_dirC.prettyAbsPath()); } joachim99@8: joachim99@51: KMessageBox::sorry( this, text, i18n("Directory Open Error") ); joachim99@8: return false; joachim99@8: } joachim99@8: joachim99@8: if ( m_dirC.isValid() && joachim99@8: (m_dirDest.prettyAbsPath() == m_dirA.prettyAbsPath() || m_dirDest.prettyAbsPath()==m_dirB.prettyAbsPath() ) ) joachim99@8: { joachim99@8: KMessageBox::error(this, joachim99@53: i18n( "The destination directory must not be the same as A or B when " joachim99@8: "three directories are merged.\nCheck again before continuing."), joachim99@51: i18n("Parameter Warning")); joachim99@8: return false; joachim99@8: } joachim99@68: joachim99@66: m_bScanning = true; joachim99@68: statusBarMessage(i18n("Scanning directories...")); joachim99@8: joachim99@8: m_bSyncMode = m_pOptions->m_bDmSyncMode && !m_dirC.isValid() && !m_dirDest.isValid(); joachim99@8: joachim99@8: if ( m_dirDest.isValid() ) joachim99@8: m_dirDestInternal = m_dirDest; joachim99@8: else joachim99@8: m_dirDestInternal = m_dirC.isValid() ? m_dirC : m_dirB; joachim99@8: joachim99@75: QString origCurrentDirectory = QDir::currentPath(); joachim99@8: joachim99@8: m_fileMergeMap.clear(); joachim99@8: t_DirectoryList::iterator i; joachim99@8: joachim99@8: // calc how many directories will be read: joachim99@8: double nofScans = ( m_dirA.isValid() ? 1 : 0 )+( m_dirB.isValid() ? 1 : 0 )+( m_dirC.isValid() ? 1 : 0 ); joachim99@8: int currentScan = 0; joachim99@8: joachim99@75: //TODO setColumnWidthMode(s_UnsolvedCol, Q3ListView::Manual); joachim99@75: // setColumnWidthMode(s_SolvedCol, Q3ListView::Manual); joachim99@75: // setColumnWidthMode(s_WhiteCol, Q3ListView::Manual); joachim99@75: // setColumnWidthMode(s_NonWhiteCol, Q3ListView::Manual); joachim99@75: setColumnHidden( s_CCol, !m_dirC.isValid() ); joachim99@75: setColumnHidden( s_WhiteCol, !m_pOptions->m_bDmFullAnalysis ); joachim99@75: setColumnHidden( s_NonWhiteCol, !m_pOptions->m_bDmFullAnalysis ); joachim99@75: setColumnHidden( s_UnsolvedCol, !m_pOptions->m_bDmFullAnalysis ); joachim99@75: setColumnHidden( s_SolvedCol, !( m_pOptions->m_bDmFullAnalysis && m_dirC.isValid() ) ); joachim99@68: joachim99@8: bool bListDirSuccessA = true; joachim99@8: bool bListDirSuccessB = true; joachim99@8: bool bListDirSuccessC = true; joachim99@8: if ( m_dirA.isValid() ) joachim99@8: { joachim99@66: pp.setInformation(i18n("Reading Directory A")); joachim99@66: pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans); joachim99@8: ++currentScan; joachim99@8: joachim99@8: t_DirectoryList dirListA; joachim99@8: bListDirSuccessA = m_dirA.listDir( &dirListA, joachim99@8: m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden, joachim99@8: m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern, joachim99@8: m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks, joachim99@8: m_pOptions->m_bDmUseCvsIgnore); joachim99@8: joachim99@8: for (i=dirListA.begin(); i!=dirListA.end();++i ) joachim99@8: { joachim99@69: MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(), m_bCaseSensitive)]; joachim99@8: //std::cout <filePath()<m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden, joachim99@8: m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern, joachim99@8: m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks, joachim99@8: m_pOptions->m_bDmUseCvsIgnore); joachim99@8: joachim99@8: for (i=dirListB.begin(); i!=dirListB.end();++i ) joachim99@8: { joachim99@69: MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(), m_bCaseSensitive)]; joachim99@8: mfi.m_bExistsInB = true; joachim99@8: mfi.m_fileInfoB = *i; joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: e_MergeOperation eDefaultMergeOp; joachim99@8: if ( m_dirC.isValid() ) joachim99@8: { joachim99@66: pp.setInformation(i18n("Reading Directory C")); joachim99@66: pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans); joachim99@8: ++currentScan; joachim99@8: joachim99@8: t_DirectoryList dirListC; joachim99@8: bListDirSuccessC = m_dirC.listDir( &dirListC, joachim99@8: m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden, joachim99@8: m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern, joachim99@8: m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks, joachim99@8: m_pOptions->m_bDmUseCvsIgnore); joachim99@8: joachim99@8: for (i=dirListC.begin(); i!=dirListC.end();++i ) joachim99@8: { joachim99@69: MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(),m_bCaseSensitive)]; joachim99@8: mfi.m_bExistsInC = true; joachim99@8: mfi.m_fileInfoC = *i; joachim99@8: } joachim99@8: joachim99@8: eDefaultMergeOp = eMergeABCToDest; joachim99@8: } joachim99@8: else joachim99@8: eDefaultMergeOp = m_bSyncMode ? eMergeToAB : eMergeABToDest; joachim99@8: joachim99@8: bool bContinue = true; joachim99@8: if ( !bListDirSuccessA || !bListDirSuccessB || !bListDirSuccessC ) joachim99@8: { joachim99@8: QString s = i18n("Some subdirectories were not readable in"); joachim99@8: if ( !bListDirSuccessA ) s += "\nA: " + m_dirA.prettyAbsPath(); joachim99@8: if ( !bListDirSuccessB ) s += "\nB: " + m_dirB.prettyAbsPath(); joachim99@8: if ( !bListDirSuccessC ) s += "\nC: " + m_dirC.prettyAbsPath(); joachim99@8: s+="\n"; joachim99@8: s+= i18n("Check the permissions of the subdirectories."); joachim99@8: bContinue = KMessageBox::Continue == KMessageBox::warningContinueCancel( this, s ); joachim99@8: } joachim99@8: joachim99@8: if ( bContinue ) joachim99@8: { joachim99@66: prepareListView(pp); joachim99@8: joachim99@92: updateFileVisibilities(); joachim99@92: joachim99@92: for( int childIdx = 0; childIdx( topLevelItem(childIdx) ); joachim99@8: calcSuggestedOperation( *pDMI->m_pMFI, eDefaultMergeOp ); joachim99@8: } joachim99@8: } joachim99@92: joachim99@92: sortItems(0,Qt::AscendingOrder); joachim99@75: joachim99@75: for (int i=0;i(pParent); joachim99@8: if (pSplitter!=0) joachim99@8: { joachim99@75: QList sizes = pSplitter->sizes(); joachim99@8: int total = sizes[0] + sizes[1]; joachim99@92: if ( total < 10 ) joachim99@92: total = 100; joachim99@8: sizes[0]=total*6/10; joachim99@8: sizes[1]=total - sizes[0]; joachim99@8: pSplitter->setSizes( sizes ); joachim99@8: } joachim99@68: joachim99@92: QDir::setCurrent(origCurrentDirectory); joachim99@75: joachim99@66: m_bScanning = false; joachim99@66: statusBarMessage(i18n("Ready.")); joachim99@8: joachim99@8: if ( bContinue ) joachim99@8: { joachim99@8: // Generate a status report joachim99@8: int nofFiles=0; joachim99@8: int nofDirs=0; joachim99@8: int nofEqualFiles=0; joachim99@8: int nofManualMerges=0; joachim99@75: for( int childIdx = 0; childIdx(topLevelItem(childIdx)), joachim99@8: nofFiles, nofDirs, nofEqualFiles, nofManualMerges ); joachim99@8: joachim99@8: QString s; joachim99@51: s = i18n("Directory Comparison Status") + "\n\n" + joachim99@8: i18n("Number of subdirectories:") +" "+ QString::number(nofDirs) + "\n"+ joachim99@8: i18n("Number of equal files:") +" "+ QString::number(nofEqualFiles) + "\n"+ joachim99@8: i18n("Number of different files:") +" "+ QString::number(nofFiles-nofEqualFiles); joachim99@8: joachim99@8: if ( m_dirC.isValid() ) joachim99@8: s += "\n" + i18n("Number of manual merges:") +" "+ QString::number(nofManualMerges); joachim99@8: KMessageBox::information( this, s ); joachim99@75: if ( topLevelItemCount()>0 ) joachim99@98: { joachim99@75: topLevelItem(0)->setSelected(true); joachim99@98: setCurrentItem( topLevelItem(0) ); joachim99@98: } joachim99@8: } joachim99@68: joachim99@77: if ( bReload ) joachim99@77: { joachim99@92: // Remember expanded items joachim99@77: QTreeWidgetItemIterator it( this ); joachim99@77: while ( *it ) joachim99@77: { joachim99@77: DirMergeItem* pDMI = static_cast( *it ); joachim99@77: std::map::iterator i = expandedDirsMap.find( pDMI->m_pMFI->m_subPath ); joachim99@77: if ( i!=expandedDirsMap.end() ) joachim99@77: { joachim99@77: t_ItemInfo& ii = i->second; joachim99@77: pDMI->setExpanded( ii.bExpanded ); joachim99@92: //pDMI->m_pMFI->setMergeOperation( ii.eMergeOperation, false ); unsafe, might have changed joachim99@77: pDMI->m_pMFI->m_bOperationComplete = ii.bOperationComplete; joachim99@77: pDMI->setText( s_OpStatusCol, ii.status ); joachim99@77: } joachim99@77: ++it; joachim99@77: } joachim99@77: } joachim99@8: return true; joachim99@8: } joachim99@8: joachim99@75: void DirectoryMergeWindow::onExpanded() joachim99@75: { joachim99@75: resizeColumnToContents(s_NameCol); joachim99@75: } joachim99@8: joachim99@8: joachim99@8: void DirectoryMergeWindow::slotChooseAEverywhere(){ setAllMergeOperations( eCopyAToDest ); } joachim99@8: joachim99@8: void DirectoryMergeWindow::slotChooseBEverywhere(){ setAllMergeOperations( eCopyBToDest ); } joachim99@8: joachim99@8: void DirectoryMergeWindow::slotChooseCEverywhere(){ setAllMergeOperations( eCopyCToDest ); } joachim99@8: joachim99@8: void DirectoryMergeWindow::slotAutoChooseEverywhere() joachim99@8: { joachim99@8: e_MergeOperation eDefaultMergeOp = m_dirC.isValid() ? eMergeABCToDest : joachim99@8: m_bSyncMode ? eMergeToAB : eMergeABToDest; joachim99@8: setAllMergeOperations(eDefaultMergeOp ); joachim99@8: } joachim99@8: joachim99@8: void DirectoryMergeWindow::slotNoOpEverywhere(){ setAllMergeOperations(eNoOperation); } joachim99@8: joachim99@75: static void setListViewItemOpen( QTreeWidgetItem* p, bool bOpen ) joachim99@8: { joachim99@75: if ( p->childCount() > 0 ) joachim99@75: { joachim99@75: for( int childIdx=0; childIdxchildCount(); ++childIdx ) joachim99@75: setListViewItemOpen( p->child(childIdx), bOpen ); joachim99@75: joachim99@75: p->setExpanded( bOpen ); joachim99@75: } joachim99@8: } joachim99@8: joachim99@8: void DirectoryMergeWindow::slotFoldAllSubdirs() joachim99@8: { joachim99@75: for( int i=0; i(pLVI); joachim99@51: MergeFileInfos& mfi = *pDMI->m_pMFI; joachim99@51: joachim99@51: mfi.setMergeOperation(eMergeOp ); joachim99@51: } joachim99@51: joachim99@51: // Merge current item (merge mode) joachim99@51: void DirectoryMergeWindow::slotCurrentDoNothing() { setMergeOperation(currentItem(), eNoOperation ); } joachim99@53: void DirectoryMergeWindow::slotCurrentChooseA() { setMergeOperation(currentItem(), m_bSyncMode ? eCopyAToB : eCopyAToDest ); } joachim99@53: void DirectoryMergeWindow::slotCurrentChooseB() { setMergeOperation(currentItem(), m_bSyncMode ? eCopyBToA : eCopyBToDest ); } joachim99@51: void DirectoryMergeWindow::slotCurrentChooseC() { setMergeOperation(currentItem(), eCopyCToDest ); } joachim99@51: void DirectoryMergeWindow::slotCurrentMerge() joachim99@51: { joachim99@51: bool bThreeDirs = m_dirC.isValid(); joachim99@51: setMergeOperation(currentItem(), bThreeDirs ? eMergeABCToDest : eMergeABToDest ); joachim99@51: } joachim99@51: void DirectoryMergeWindow::slotCurrentDelete() { setMergeOperation(currentItem(), eDeleteFromDest ); } joachim99@51: // Sync current item joachim99@51: void DirectoryMergeWindow::slotCurrentCopyAToB() { setMergeOperation(currentItem(), eCopyAToB ); } joachim99@51: void DirectoryMergeWindow::slotCurrentCopyBToA() { setMergeOperation(currentItem(), eCopyBToA ); } joachim99@51: void DirectoryMergeWindow::slotCurrentDeleteA() { setMergeOperation(currentItem(), eDeleteA ); } joachim99@51: void DirectoryMergeWindow::slotCurrentDeleteB() { setMergeOperation(currentItem(), eDeleteB ); } joachim99@51: void DirectoryMergeWindow::slotCurrentDeleteAAndB() { setMergeOperation(currentItem(), eDeleteAB ); } joachim99@51: void DirectoryMergeWindow::slotCurrentMergeToA() { setMergeOperation(currentItem(), eMergeToA ); } joachim99@51: void DirectoryMergeWindow::slotCurrentMergeToB() { setMergeOperation(currentItem(), eMergeToB ); } joachim99@51: void DirectoryMergeWindow::slotCurrentMergeToAAndB() { setMergeOperation(currentItem(), eMergeToAB ); } joachim99@51: joachim99@51: joachim99@51: void DirectoryMergeWindow::keyPressEvent( QKeyEvent* e ) joachim99@51: { joachim99@75: if ( (e->QInputEvent::modifiers() & Qt::ControlModifier)!=0 ) joachim99@51: { joachim99@51: bool bThreeDirs = m_dirC.isValid(); joachim99@51: joachim99@75: QTreeWidgetItem* lvi = currentItem(); joachim99@51: DirMergeItem* pDMI = lvi==0 ? 0 : static_cast(lvi); joachim99@51: MergeFileInfos* pMFI = pDMI==0 ? 0 : pDMI->m_pMFI; joachim99@51: joachim99@51: if ( pMFI==0 ) return; joachim99@51: bool bMergeMode = bThreeDirs || !m_bSyncMode; joachim99@51: bool bFTConflict = pMFI==0 ? false : conflictingFileTypes(*pMFI); joachim99@51: joachim99@51: if ( bMergeMode ) joachim99@51: { joachim99@51: switch(e->key()) joachim99@51: { joachim99@70: case Qt::Key_1: if(pMFI->m_bExistsInA){ slotCurrentChooseA(); } return; joachim99@70: case Qt::Key_2: if(pMFI->m_bExistsInB){ slotCurrentChooseB(); } return; joachim99@70: case Qt::Key_3: if(pMFI->m_bExistsInC){ slotCurrentChooseC(); } return; joachim99@70: case Qt::Key_Space: slotCurrentDoNothing(); return; joachim99@70: case Qt::Key_4: if ( !bFTConflict ) { slotCurrentMerge(); } return; joachim99@70: case Qt::Key_Delete: slotCurrentDelete(); return; joachim99@51: default: break; joachim99@51: } joachim99@51: } joachim99@51: else joachim99@51: { joachim99@51: switch(e->key()) joachim99@51: { joachim99@70: case Qt::Key_1: if(pMFI->m_bExistsInA){ slotCurrentCopyAToB(); } return; joachim99@70: case Qt::Key_2: if(pMFI->m_bExistsInB){ slotCurrentCopyBToA(); } return; joachim99@70: case Qt::Key_Space: slotCurrentDoNothing(); return; joachim99@70: case Qt::Key_4: if ( !bFTConflict ) { slotCurrentMergeToAAndB(); } return; joachim99@70: case Qt::Key_Delete: if( pMFI->m_bExistsInA && pMFI->m_bExistsInB ) slotCurrentDeleteAAndB(); joachim99@51: else if( pMFI->m_bExistsInA ) slotCurrentDeleteA(); joachim99@51: else if( pMFI->m_bExistsInB ) slotCurrentDeleteB(); joachim99@51: return; joachim99@51: default: break; joachim99@51: } joachim99@51: } joachim99@51: } joachim99@75: else if ( e->key()==Qt::Key_Return || e->key()==Qt::Key_Enter ) joachim99@75: { joachim99@75: onDoubleClick( currentItem() ); joachim99@75: return; joachim99@75: } joachim99@75: joachim99@75: QTreeWidget::keyPressEvent(e); joachim99@51: } joachim99@51: joachim99@53: void DirectoryMergeWindow::focusInEvent(QFocusEvent*) joachim99@53: { joachim99@53: updateAvailabilities(); joachim99@53: } joachim99@53: void DirectoryMergeWindow::focusOutEvent(QFocusEvent*) joachim99@53: { joachim99@53: updateAvailabilities(); joachim99@53: } joachim99@51: joachim99@8: void DirectoryMergeWindow::setAllMergeOperations( e_MergeOperation eDefaultOperation ) joachim99@8: { joachim99@8: if ( KMessageBox::Yes == KMessageBox::warningYesNo(this, joachim99@8: i18n("This affects all merge operations."), joachim99@80: i18n("Changing All Merge Operations"), joachim99@80: KStandardGuiItem::cont(), joachim99@80: KStandardGuiItem::cancel() ) ) joachim99@8: { joachim99@75: for( int i=0; i( topLevelItem(i) ); joachim99@8: calcSuggestedOperation( *pDMI->m_pMFI, eDefaultOperation ); joachim99@8: } joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: joachim99@8: void DirectoryMergeWindow::compareFilesAndCalcAges( MergeFileInfos& mfi ) joachim99@8: { joachim99@8: std::map dateMap; joachim99@8: joachim99@8: if( mfi.m_bExistsInA ) joachim99@8: { joachim99@8: mfi.m_bLinkA = mfi.m_fileInfoA.isSymLink(); joachim99@8: mfi.m_bDirA = mfi.m_fileInfoA.isDir(); joachim99@8: dateMap[ mfi.m_fileInfoA.lastModified() ] = 0; joachim99@8: } joachim99@8: if( mfi.m_bExistsInB ) joachim99@8: { joachim99@8: mfi.m_bLinkB = mfi.m_fileInfoB.isSymLink(); joachim99@8: mfi.m_bDirB = mfi.m_fileInfoB.isDir(); joachim99@8: dateMap[ mfi.m_fileInfoB.lastModified() ] = 1; joachim99@8: } joachim99@8: if( mfi.m_bExistsInC ) joachim99@8: { joachim99@8: mfi.m_bLinkC = mfi.m_fileInfoC.isSymLink(); joachim99@8: mfi.m_bDirC = mfi.m_fileInfoC.isDir(); joachim99@8: dateMap[ mfi.m_fileInfoC.lastModified() ] = 2; joachim99@8: } joachim99@8: joachim99@66: if ( m_pOptions->m_bDmFullAnalysis ) joachim99@8: { joachim99@80: if( (mfi.m_bExistsInA && mfi.m_bDirA) || (mfi.m_bExistsInB && mfi.m_bDirB) || (mfi.m_bExistsInC && mfi.m_bDirC) ) joachim99@66: { joachim99@66: // If any input is a directory, don't start any comparison. joachim99@66: mfi.m_bEqualAB=mfi.m_bExistsInA && mfi.m_bExistsInB; joachim99@66: mfi.m_bEqualAC=mfi.m_bExistsInA && mfi.m_bExistsInC; joachim99@66: mfi.m_bEqualBC=mfi.m_bExistsInB && mfi.m_bExistsInC; joachim99@66: } joachim99@8: else joachim99@8: { joachim99@66: emit startDiffMerge( joachim99@80: mfi.m_bExistsInA ? mfi.m_fileInfoA.absoluteFilePath() : QString(""), joachim99@80: mfi.m_bExistsInB ? mfi.m_fileInfoB.absoluteFilePath() : QString(""), joachim99@80: mfi.m_bExistsInC ? mfi.m_fileInfoC.absoluteFilePath() : QString(""), joachim99@66: "", joachim99@66: "","","",&mfi.m_totalDiffStatus joachim99@66: ); joachim99@68: int nofNonwhiteConflicts = mfi.m_totalDiffStatus.nofUnsolvedConflicts + joachim99@68: mfi.m_totalDiffStatus.nofSolvedConflicts - mfi.m_totalDiffStatus.nofWhitespaceConflicts; joachim99@68: joachim99@68: if (m_pOptions->m_bDmWhiteSpaceEqual && nofNonwhiteConflicts == 0) joachim99@68: { joachim99@77: mfi.m_bEqualAB = mfi.m_bExistsInA && mfi.m_bExistsInB; joachim99@77: mfi.m_bEqualAC = mfi.m_bExistsInA && mfi.m_bExistsInC; joachim99@77: mfi.m_bEqualBC = mfi.m_bExistsInB && mfi.m_bExistsInC; joachim99@68: } joachim99@68: else joachim99@68: { joachim99@68: mfi.m_bEqualAB = mfi.m_totalDiffStatus.bBinaryAEqB; joachim99@68: mfi.m_bEqualBC = mfi.m_totalDiffStatus.bBinaryBEqC; joachim99@68: mfi.m_bEqualAC = mfi.m_totalDiffStatus.bBinaryAEqC; joachim99@68: } joachim99@66: } joachim99@66: } joachim99@66: else joachim99@68: { joachim99@66: bool bError; joachim99@66: QString eqStatus; joachim99@66: if( mfi.m_bExistsInA && mfi.m_bExistsInB ) joachim99@66: { joachim99@66: if( mfi.m_bDirA ) mfi.m_bEqualAB=true; joachim99@66: else fastFileComparison( mfi.m_fileInfoA, mfi.m_fileInfoB, mfi.m_bEqualAB, bError, eqStatus ); joachim99@66: } joachim99@66: if( mfi.m_bExistsInA && mfi.m_bExistsInC ) joachim99@66: { joachim99@66: if( mfi.m_bDirA ) mfi.m_bEqualAC=true; joachim99@66: else fastFileComparison( mfi.m_fileInfoA, mfi.m_fileInfoC, mfi.m_bEqualAC, bError, eqStatus ); joachim99@66: } joachim99@66: if( mfi.m_bExistsInB && mfi.m_bExistsInC ) joachim99@66: { joachim99@66: if (mfi.m_bEqualAB && mfi.m_bEqualAC) joachim99@66: mfi.m_bEqualBC = true; joachim99@66: else joachim99@66: { joachim99@66: if( mfi.m_bDirB ) mfi.m_bEqualBC=true; joachim99@66: else fastFileComparison( mfi.m_fileInfoB, mfi.m_fileInfoC, mfi.m_bEqualBC, bError, eqStatus ); joachim99@66: } joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: if (mfi.m_bLinkA!=mfi.m_bLinkB) mfi.m_bEqualAB=false; joachim99@8: if (mfi.m_bLinkA!=mfi.m_bLinkC) mfi.m_bEqualAC=false; joachim99@8: if (mfi.m_bLinkB!=mfi.m_bLinkC) mfi.m_bEqualBC=false; joachim99@8: joachim99@8: if (mfi.m_bDirA!=mfi.m_bDirB) mfi.m_bEqualAB=false; joachim99@8: if (mfi.m_bDirA!=mfi.m_bDirC) mfi.m_bEqualAC=false; joachim99@8: if (mfi.m_bDirB!=mfi.m_bDirC) mfi.m_bEqualBC=false; joachim99@8: joachim99@8: assert(eNew==0 && eMiddle==1 && eOld==2); joachim99@8: joachim99@8: // The map automatically sorts the keys. joachim99@8: int age = eNew; joachim99@8: std::map::reverse_iterator i; joachim99@8: for( i=dateMap.rbegin(); i!=dateMap.rend(); ++i ) joachim99@8: { joachim99@8: int n = i->second; joachim99@8: if ( n==0 && mfi.m_ageA==eNotThere ) joachim99@8: { joachim99@8: mfi.m_ageA = (e_Age)age; ++age; joachim99@8: if ( mfi.m_bEqualAB ) { mfi.m_ageB = mfi.m_ageA; ++age; } joachim99@8: if ( mfi.m_bEqualAC ) { mfi.m_ageC = mfi.m_ageA; ++age; } joachim99@8: } joachim99@8: else if ( n==1 && mfi.m_ageB==eNotThere ) joachim99@8: { joachim99@8: mfi.m_ageB = (e_Age)age; ++age; joachim99@8: if ( mfi.m_bEqualAB ) { mfi.m_ageA = mfi.m_ageB; ++age; } joachim99@8: if ( mfi.m_bEqualBC ) { mfi.m_ageC = mfi.m_ageB; ++age; } joachim99@8: } joachim99@8: else if ( n==2 && mfi.m_ageC==eNotThere) joachim99@8: { joachim99@8: mfi.m_ageC = (e_Age)age; ++age; joachim99@8: if ( mfi.m_bEqualAC ) { mfi.m_ageA = mfi.m_ageC; ++age; } joachim99@8: if ( mfi.m_bEqualBC ) { mfi.m_ageB = mfi.m_ageC; ++age; } joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: // The checks below are necessary when the dates of the file are equal but the joachim99@8: // files are not. One wouldn't expect this to happen, yet it happens sometimes. joachim99@8: if ( mfi.m_bExistsInC && mfi.m_ageC==eNotThere ) joachim99@8: { joachim99@8: mfi.m_ageC = (e_Age)age; ++age; joachim99@8: mfi.m_bConflictingAges = true; joachim99@8: } joachim99@8: if ( mfi.m_bExistsInB && mfi.m_ageB==eNotThere ) joachim99@8: { joachim99@8: mfi.m_ageB = (e_Age)age; ++age; joachim99@8: mfi.m_bConflictingAges = true; joachim99@8: } joachim99@8: if ( mfi.m_bExistsInA && mfi.m_ageA==eNotThere ) joachim99@8: { joachim99@8: mfi.m_ageA = (e_Age)age; ++age; joachim99@8: mfi.m_bConflictingAges = true; joachim99@8: } joachim99@8: joachim99@8: if ( mfi.m_ageA != eOld && mfi.m_ageB != eOld && mfi.m_ageC != eOld ) joachim99@8: { joachim99@8: if (mfi.m_ageA == eMiddle) mfi.m_ageA = eOld; joachim99@8: if (mfi.m_ageB == eMiddle) mfi.m_ageB = eOld; joachim99@8: if (mfi.m_ageC == eMiddle) mfi.m_ageC = eOld; joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: static QPixmap* s_pm_dir; joachim99@8: static QPixmap* s_pm_file; joachim99@8: joachim99@69: static QPixmap* pmNotThere; joachim99@69: static QPixmap* pmNew; joachim99@69: static QPixmap* pmOld; joachim99@69: static QPixmap* pmMiddle; joachim99@69: joachim99@69: static QPixmap* pmLink; joachim99@69: joachim99@69: static QPixmap* pmDirLink; joachim99@69: static QPixmap* pmFileLink; joachim99@69: joachim99@69: static QPixmap* pmNewLink; joachim99@69: static QPixmap* pmOldLink; joachim99@69: static QPixmap* pmMiddleLink; joachim99@69: joachim99@69: static QPixmap* pmNewDir; joachim99@69: static QPixmap* pmMiddleDir; joachim99@69: static QPixmap* pmOldDir; joachim99@69: joachim99@69: static QPixmap* pmNewDirLink; joachim99@69: static QPixmap* pmMiddleDirLink; joachim99@69: static QPixmap* pmOldDirLink; joachim99@69: joachim99@69: joachim99@69: static QPixmap colorToPixmap(QColor c) joachim99@69: { joachim99@69: QPixmap pm(16,16); joachim99@69: QPainter p(&pm); joachim99@69: p.setPen( Qt::black ); joachim99@69: p.setBrush( c ); joachim99@69: p.drawRect(0,0,pm.width(),pm.height()); joachim99@69: return pm; joachim99@69: } joachim99@69: joachim99@69: static void initPixmaps( QColor newest, QColor oldest, QColor middle, QColor notThere ) joachim99@69: { joachim99@69: if (pmNew==0) joachim99@69: { joachim99@69: pmNotThere = new QPixmap; joachim99@69: pmNew = new QPixmap; joachim99@69: pmOld = new QPixmap; joachim99@69: pmMiddle = new QPixmap; joachim99@69: joachim99@69: #include "xpm/link_arrow.xpm" joachim99@69: pmLink = new QPixmap(link_arrow); joachim99@69: joachim99@69: pmDirLink = new QPixmap; joachim99@69: pmFileLink = new QPixmap; joachim99@69: joachim99@69: pmNewLink = new QPixmap; joachim99@69: pmOldLink = new QPixmap; joachim99@69: pmMiddleLink = new QPixmap; joachim99@69: joachim99@69: pmNewDir = new QPixmap; joachim99@69: pmMiddleDir = new QPixmap; joachim99@69: pmOldDir = new QPixmap; joachim99@69: joachim99@69: pmNewDirLink = new QPixmap; joachim99@69: pmMiddleDirLink = new QPixmap; joachim99@69: pmOldDirLink = new QPixmap; joachim99@69: } joachim99@69: joachim99@69: joachim99@69: *pmNotThere = colorToPixmap(notThere); joachim99@69: *pmNew = colorToPixmap(newest); joachim99@69: *pmOld = colorToPixmap(oldest); joachim99@69: *pmMiddle = colorToPixmap(middle); joachim99@69: joachim99@69: *pmDirLink = pixCombiner( s_pm_dir, pmLink); joachim99@69: *pmFileLink = pixCombiner( s_pm_file, pmLink ); joachim99@69: joachim99@69: *pmNewLink = pixCombiner( pmNew, pmLink); joachim99@69: *pmOldLink = pixCombiner( pmOld, pmLink); joachim99@69: *pmMiddleLink = pixCombiner( pmMiddle, pmLink); joachim99@69: joachim99@69: *pmNewDir = pixCombiner2( pmNew, s_pm_dir); joachim99@69: *pmMiddleDir = pixCombiner2( pmMiddle, s_pm_dir); joachim99@69: *pmOldDir = pixCombiner2( pmOld, s_pm_dir); joachim99@69: joachim99@69: *pmNewDirLink = pixCombiner( pmNewDir, pmLink); joachim99@69: *pmMiddleDirLink = pixCombiner( pmMiddleDir, pmLink); joachim99@69: *pmOldDirLink = pixCombiner( pmOldDir, pmLink); joachim99@69: } joachim99@69: joachim99@69: joachim99@75: static void setOnePixmap( QTreeWidgetItem* pLVI, int col, e_Age eAge, bool bLink, bool bDir ) joachim99@8: { joachim99@69: static QPixmap* ageToPm[]= { pmNew, pmMiddle, pmOld, pmNotThere, s_pm_file }; joachim99@69: static QPixmap* ageToPmLink[]= { pmNewLink, pmMiddleLink, pmOldLink, pmNotThere, pmFileLink }; joachim99@69: static QPixmap* ageToPmDir[]= { pmNewDir, pmMiddleDir, pmOldDir, pmNotThere, s_pm_dir }; joachim99@69: static QPixmap* ageToPmDirLink[]={ pmNewDirLink, pmMiddleDirLink, pmOldDirLink, pmNotThere, pmDirLink }; joachim99@8: joachim99@8: QPixmap** ppPm = bDir ? ( bLink ? ageToPmDirLink : ageToPmDir ): joachim99@8: ( bLink ? ageToPmLink : ageToPm ); joachim99@8: joachim99@75: pLVI->setIcon( col, *ppPm[eAge] ); joachim99@8: } joachim99@8: joachim99@8: static void setPixmaps( MergeFileInfos& mfi, bool bCheckC ) joachim99@8: { joachim99@75: setOnePixmap( mfi.m_pDMI, s_NameCol, eAgeEnd, joachim99@8: mfi.m_bLinkA || mfi.m_bLinkB || mfi.m_bLinkC, joachim99@8: mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC joachim99@8: ); joachim99@8: joachim99@8: if ( mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC ) joachim99@8: { joachim99@8: mfi.m_ageA=eNotThere; joachim99@8: mfi.m_ageB=eNotThere; joachim99@8: mfi.m_ageC=eNotThere; joachim99@8: int age = eNew; joachim99@8: if ( mfi.m_bExistsInC ) joachim99@8: { joachim99@8: mfi.m_ageC = (e_Age)age; joachim99@8: if (mfi.m_bEqualAC) mfi.m_ageA = (e_Age)age; joachim99@8: if (mfi.m_bEqualBC) mfi.m_ageB = (e_Age)age; joachim99@8: ++age; joachim99@8: } joachim99@8: if ( mfi.m_bExistsInB && mfi.m_ageB==eNotThere ) joachim99@8: { joachim99@8: mfi.m_ageB = (e_Age)age; joachim99@8: if (mfi.m_bEqualAB) mfi.m_ageA = (e_Age)age; joachim99@8: ++age; joachim99@8: } joachim99@8: if ( mfi.m_bExistsInA && mfi.m_ageA==eNotThere ) joachim99@8: { joachim99@8: mfi.m_ageA = (e_Age)age; joachim99@8: } joachim99@8: if ( mfi.m_ageA != eOld && mfi.m_ageB != eOld && mfi.m_ageC != eOld ) joachim99@8: { joachim99@8: if (mfi.m_ageA == eMiddle) mfi.m_ageA = eOld; joachim99@8: if (mfi.m_ageB == eMiddle) mfi.m_ageB = eOld; joachim99@8: if (mfi.m_ageC == eMiddle) mfi.m_ageC = eOld; joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: setOnePixmap( mfi.m_pDMI, s_ACol, mfi.m_ageA, mfi.m_bLinkA, mfi.m_bDirA ); joachim99@8: setOnePixmap( mfi.m_pDMI, s_BCol, mfi.m_ageB, mfi.m_bLinkB, mfi.m_bDirB ); joachim99@8: if ( bCheckC ) joachim99@8: setOnePixmap( mfi.m_pDMI, s_CCol, mfi.m_ageC, mfi.m_bLinkC, mfi.m_bDirC ); joachim99@8: } joachim99@8: joachim99@75: static QTreeWidgetItem* nextSibling(const QTreeWidgetItem* p) joachim99@75: { joachim99@75: QTreeWidgetItem* pParent = p->parent(); joachim99@75: if ( pParent ) joachim99@75: { joachim99@75: int currentIdx = pParent->indexOfChild( const_cast(p) ); joachim99@75: if ( currentIdx+1 < pParent->childCount() ) joachim99@75: return pParent->child(currentIdx+1); joachim99@75: } joachim99@75: else joachim99@75: { joachim99@75: QTreeWidget* pParentTreeWidget = p->treeWidget(); joachim99@75: if ( pParentTreeWidget ) joachim99@75: { joachim99@75: int currentIdx = pParentTreeWidget->indexOfTopLevelItem( const_cast(p) ); joachim99@75: if ( currentIdx+1 < pParentTreeWidget->topLevelItemCount() ) joachim99@75: return pParentTreeWidget->topLevelItem(currentIdx+1); joachim99@75: } joachim99@75: } joachim99@75: return 0; joachim99@75: } joachim99@75: joachim99@8: // Iterate through the complete tree. Start by specifying QListView::firstChild(). joachim99@75: static QTreeWidgetItem* treeIterator( QTreeWidgetItem* p, bool bVisitChildren=true, bool bFindInvisible=false ) joachim99@8: { joachim99@8: if( p!=0 ) joachim99@8: { joachim99@69: do joachim99@8: { joachim99@75: if ( bVisitChildren && p->childCount() != 0 ) p = p->child(0); joachim99@75: else joachim99@8: { joachim99@75: QTreeWidgetItem* pNextSibling = nextSibling(p); joachim99@75: if ( pNextSibling ) joachim99@75: p = pNextSibling; joachim99@75: else joachim99@69: { joachim99@75: p = p->parent(); joachim99@75: while ( p!=0 ) joachim99@75: { joachim99@75: QTreeWidgetItem* pNextSibling = nextSibling(p); joachim99@75: if( pNextSibling ) { p = pNextSibling; break; } joachim99@75: else { p = p->parent(); } joachim99@75: } joachim99@69: } joachim99@8: } joachim99@8: } joachim99@75: while( p && p->isHidden() && !bFindInvisible ); joachim99@8: } joachim99@8: return p; joachim99@8: } joachim99@8: joachim99@66: void DirectoryMergeWindow::prepareListView( ProgressProxy& pp ) joachim99@8: { joachim99@8: static bool bFirstTime = true; joachim99@8: if (bFirstTime) joachim99@8: { joachim99@8: #include "xpm/file.xpm" joachim99@8: #include "xpm/folder.xpm" joachim99@80: // FIXME specify correct icon loader group joachim99@80: s_pm_dir = new QPixmap( m_pIconLoader->loadIcon("folder", KIconLoader::NoGroup, KIconLoader::Small ) ); joachim99@8: if (s_pm_dir->size()!=QSize(16,16)) joachim99@8: { joachim99@8: delete s_pm_dir; joachim99@8: s_pm_dir = new QPixmap( folder_pm ); joachim99@8: } joachim99@8: s_pm_file= new QPixmap( file_pm ); joachim99@8: bFirstTime=false; joachim99@8: } joachim99@8: joachim99@8: clear(); joachim99@69: initPixmaps( m_pOptions->m_newestFileColor, m_pOptions->m_oldestFileColor, joachim99@69: m_pOptions->m_midAgeFileColor, m_pOptions->m_missingFileColor ); joachim99@8: joachim99@8: setRootIsDecorated( true ); joachim99@8: joachim99@8: bool bCheckC = m_dirC.isValid(); joachim99@8: joachim99@8: std::map::iterator j; joachim99@8: int nrOfFiles = m_fileMergeMap.size(); joachim99@8: int currentIdx = 1; joachim99@8: QTime t; joachim99@8: t.start(); joachim99@8: for( j=m_fileMergeMap.begin(); j!=m_fileMergeMap.end(); ++j ) joachim99@8: { joachim99@8: MergeFileInfos& mfi = j->second; joachim99@8: joachim99@8: mfi.m_subPath = mfi.m_fileInfoA.exists() ? mfi.m_fileInfoA.filePath() : joachim99@8: mfi.m_fileInfoB.exists() ? mfi.m_fileInfoB.filePath() : joachim99@25: mfi.m_fileInfoC.exists() ? mfi.m_fileInfoC.filePath() : joachim99@25: QString(""); joachim99@8: joachim99@58: // const QString& fileName = j->first; joachim99@58: const QString& fileName = mfi.m_subPath; joachim99@58: joachim99@66: pp.setInformation( joachim99@51: i18n("Processing ") + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles) joachim99@8: +"\n" + fileName, double(currentIdx) / nrOfFiles, false ); joachim99@66: if ( pp.wasCancelled() ) break; joachim99@8: ++currentIdx; joachim99@8: joachim99@8: // The comparisons and calculations for each file take place here. joachim99@8: compareFilesAndCalcAges( mfi ); joachim99@8: joachim99@8: // Get dirname from fileName: Search for "/" from end: joachim99@75: int pos = fileName.lastIndexOf('/'); joachim99@8: QString dirPart; joachim99@8: QString filePart; joachim99@8: if (pos==-1) joachim99@8: { joachim99@8: // Top dir joachim99@8: filePart = fileName; joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: dirPart = fileName.left(pos); joachim99@8: filePart = fileName.mid(pos+1); joachim99@8: } joachim99@8: joachim99@8: if ( dirPart.isEmpty() ) // Top level joachim99@8: { joachim99@8: new DirMergeItem( this, filePart, &mfi ); joachim99@8: } joachim99@8: else joachim99@8: { joachim99@69: MergeFileInfos& dirMfi = m_fileMergeMap[sortString(dirPart, m_bCaseSensitive)]; // parent joachim99@8: assert(dirMfi.m_pDMI!=0); joachim99@8: new DirMergeItem( dirMfi.m_pDMI, filePart, &mfi ); joachim99@8: mfi.m_pParent = &dirMfi; joachim99@8: joachim99@92: // Equality for parent dirs is set in updateFileVisibilities() joachim99@8: } joachim99@8: joachim99@8: setPixmaps( mfi, bCheckC ); joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: static bool conflictingFileTypes(MergeFileInfos& mfi) joachim99@8: { joachim99@8: // Now check if file/dir-types fit. joachim99@8: if ( mfi.m_bLinkA || mfi.m_bLinkB || mfi.m_bLinkC ) joachim99@8: { joachim99@80: if ( (mfi.m_bExistsInA && ! mfi.m_bLinkA) || joachim99@80: (mfi.m_bExistsInB && ! mfi.m_bLinkB) || joachim99@80: (mfi.m_bExistsInC && ! mfi.m_bLinkC) ) joachim99@8: { joachim99@8: return true; joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: if ( mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC ) joachim99@8: { joachim99@80: if ( (mfi.m_bExistsInA && ! mfi.m_bDirA) || joachim99@80: (mfi.m_bExistsInB && ! mfi.m_bDirB) || joachim99@80: (mfi.m_bExistsInC && ! mfi.m_bDirC) ) joachim99@8: { joachim99@8: return true; joachim99@8: } joachim99@8: } joachim99@8: return false; joachim99@8: } joachim99@8: joachim99@8: void DirectoryMergeWindow::calcSuggestedOperation( MergeFileInfos& mfi, e_MergeOperation eDefaultMergeOp ) joachim99@8: { joachim99@8: bool bCheckC = m_dirC.isValid(); joachim99@8: bool bCopyNewer = m_pOptions->m_bDmCopyNewer; joachim99@80: bool bOtherDest = !( (m_dirDestInternal.absoluteFilePath() == m_dirA.absoluteFilePath()) || joachim99@80: (m_dirDestInternal.absoluteFilePath() == m_dirB.absoluteFilePath()) || joachim99@80: (bCheckC && m_dirDestInternal.absoluteFilePath() == m_dirC.absoluteFilePath()) ); joachim99@75: joachim99@8: joachim99@8: if ( eDefaultMergeOp == eMergeABCToDest && !bCheckC ) { eDefaultMergeOp = eMergeABToDest; } joachim99@8: if ( eDefaultMergeOp == eMergeToAB && bCheckC ) { assert(false); } joachim99@51: joachim99@8: if ( eDefaultMergeOp == eMergeToA || eDefaultMergeOp == eMergeToB || joachim99@8: eDefaultMergeOp == eMergeABCToDest || eDefaultMergeOp == eMergeABToDest || eDefaultMergeOp == eMergeToAB ) joachim99@51: { joachim99@8: if ( !bCheckC ) joachim99@8: { joachim99@8: if ( mfi.m_bEqualAB ) joachim99@8: { joachim99@75: mfi.setMergeOperation( bOtherDest ? eCopyBToDest : eNoOperation ); joachim99@8: } joachim99@8: else if ( mfi.m_bExistsInA && mfi.m_bExistsInB ) joachim99@8: { joachim99@8: if ( !bCopyNewer || mfi.m_bDirA ) joachim99@8: mfi.setMergeOperation( eDefaultMergeOp ); joachim99@8: else if ( bCopyNewer && mfi.m_bConflictingAges ) joachim99@8: { joachim99@8: mfi.setMergeOperation( eConflictingAges ); joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: if ( mfi.m_ageA == eNew ) joachim99@8: mfi.setMergeOperation( eDefaultMergeOp == eMergeToAB ? eCopyAToB : eCopyAToDest ); joachim99@8: else joachim99@8: mfi.setMergeOperation( eDefaultMergeOp == eMergeToAB ? eCopyBToA : eCopyBToDest ); joachim99@8: } joachim99@8: } joachim99@8: else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB ) joachim99@8: { joachim99@8: if ( eDefaultMergeOp==eMergeABToDest ) mfi.setMergeOperation( eCopyBToDest ); joachim99@8: else if ( eDefaultMergeOp==eMergeToB ) mfi.setMergeOperation( eNoOperation ); joachim99@8: else mfi.setMergeOperation( eCopyBToA ); joachim99@8: } joachim99@8: else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB ) joachim99@8: { joachim99@8: if ( eDefaultMergeOp==eMergeABToDest ) mfi.setMergeOperation( eCopyAToDest ); joachim99@8: else if ( eDefaultMergeOp==eMergeToA ) mfi.setMergeOperation( eNoOperation ); joachim99@8: else mfi.setMergeOperation( eCopyAToB ); joachim99@8: } joachim99@8: else //if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB ) joachim99@8: { joachim99@8: mfi.setMergeOperation( eNoOperation ); assert(false); joachim99@8: } joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: if ( mfi.m_bEqualAB && mfi.m_bEqualAC ) joachim99@8: { joachim99@75: mfi.setMergeOperation( bOtherDest ? eCopyCToDest : eNoOperation ); joachim99@8: } joachim99@8: else if ( mfi.m_bExistsInA && mfi.m_bExistsInB && mfi.m_bExistsInC) joachim99@8: { joachim99@8: if ( mfi.m_bEqualAB ) joachim99@8: mfi.setMergeOperation( eCopyCToDest ); joachim99@8: else if ( mfi.m_bEqualAC ) joachim99@8: mfi.setMergeOperation( eCopyBToDest ); joachim99@8: else if ( mfi.m_bEqualBC ) joachim99@8: mfi.setMergeOperation( eCopyCToDest ); joachim99@8: else joachim99@8: mfi.setMergeOperation( eMergeABCToDest ); joachim99@8: } joachim99@8: else if ( mfi.m_bExistsInA && mfi.m_bExistsInB && !mfi.m_bExistsInC ) joachim99@8: { joachim99@8: if ( mfi.m_bEqualAB ) joachim99@8: mfi.setMergeOperation( eDeleteFromDest ); joachim99@8: else joachim99@92: mfi.setMergeOperation( eChangedAndDeleted ); joachim99@8: } joachim99@8: else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB && mfi.m_bExistsInC ) joachim99@8: { joachim99@8: if ( mfi.m_bEqualAC ) joachim99@8: mfi.setMergeOperation( eDeleteFromDest ); joachim99@8: else joachim99@92: mfi.setMergeOperation( eChangedAndDeleted ); joachim99@8: } joachim99@8: else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB && mfi.m_bExistsInC ) joachim99@8: { joachim99@8: if ( mfi.m_bEqualBC ) joachim99@8: mfi.setMergeOperation( eCopyCToDest ); joachim99@8: else joachim99@8: mfi.setMergeOperation( eMergeABCToDest ); joachim99@8: } joachim99@8: else if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB && mfi.m_bExistsInC ) joachim99@8: { joachim99@8: mfi.setMergeOperation( eCopyCToDest ); joachim99@8: } joachim99@8: else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB && !mfi.m_bExistsInC ) joachim99@8: { joachim99@8: mfi.setMergeOperation( eCopyBToDest ); joachim99@8: } joachim99@8: else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB && !mfi.m_bExistsInC) joachim99@8: { joachim99@8: mfi.setMergeOperation( eDeleteFromDest ); joachim99@8: } joachim99@8: else //if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB && !mfi.m_bExistsInC ) joachim99@8: { joachim99@8: mfi.setMergeOperation( eNoOperation ); assert(false); joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: // Now check if file/dir-types fit. joachim99@8: if ( conflictingFileTypes(mfi) ) joachim99@8: { joachim99@8: mfi.setMergeOperation( eConflictingFileTypes ); joachim99@8: } joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: e_MergeOperation eMO = eDefaultMergeOp; joachim99@8: switch ( eDefaultMergeOp ) joachim99@8: { joachim99@8: case eConflictingFileTypes: joachim99@92: case eChangedAndDeleted: joachim99@8: case eConflictingAges: joachim99@8: case eDeleteA: joachim99@8: case eDeleteB: joachim99@8: case eDeleteAB: joachim99@8: case eDeleteFromDest: joachim99@8: case eNoOperation: break; joachim99@8: case eCopyAToB: if ( !mfi.m_bExistsInA ) { eMO = eDeleteB; } break; joachim99@8: case eCopyBToA: if ( !mfi.m_bExistsInB ) { eMO = eDeleteA; } break; joachim99@8: case eCopyAToDest: if ( !mfi.m_bExistsInA ) { eMO = eDeleteFromDest; } break; joachim99@8: case eCopyBToDest: if ( !mfi.m_bExistsInB ) { eMO = eDeleteFromDest; } break; joachim99@8: case eCopyCToDest: if ( !mfi.m_bExistsInC ) { eMO = eDeleteFromDest; } break; joachim99@8: joachim99@8: case eMergeToA: joachim99@8: case eMergeToB: joachim99@8: case eMergeToAB: joachim99@8: case eMergeABCToDest: joachim99@8: case eMergeABToDest: joachim99@8: default: joachim99@8: assert(false); joachim99@8: } joachim99@8: mfi.setMergeOperation( eMO ); joachim99@8: } joachim99@8: } joachim99@8: joachim99@75: void DirectoryMergeWindow::onDoubleClick( QTreeWidgetItem* lvi ) joachim99@8: { joachim99@8: if (lvi==0) return; joachim99@8: joachim99@8: if ( m_bDirectoryMerge ) joachim99@8: mergeCurrentFile(); joachim99@8: else joachim99@8: compareCurrentFile(); joachim99@8: } joachim99@8: joachim99@75: void DirectoryMergeWindow::onCurrentChanged(QTreeWidgetItem* lvi) joachim99@8: { joachim99@8: if ( lvi==0 ) return; joachim99@8: joachim99@8: DirMergeItem* pDMI = static_cast(lvi); joachim99@8: joachim99@8: MergeFileInfos& mfi = *pDMI->m_pMFI; joachim99@8: assert( mfi.m_pDMI==pDMI ); joachim99@8: joachim99@8: m_pDirectoryMergeInfo->setInfo( m_dirA, m_dirB, m_dirC, m_dirDestInternal, mfi ); joachim99@8: } joachim99@8: joachim99@75: void DirectoryMergeWindow::mousePressEvent( QMouseEvent* e ) joachim99@8: { joachim99@75: QTreeWidget::mousePressEvent(e); joachim99@75: int c = columnAt( e->x() ); joachim99@75: QTreeWidgetItem* lvi = itemAt( e->pos() ); joachim99@75: QPoint p = e->globalPos(); joachim99@8: if ( lvi==0 ) return; joachim99@8: joachim99@8: DirMergeItem* pDMI = static_cast(lvi); joachim99@8: joachim99@8: MergeFileInfos& mfi = *pDMI->m_pMFI; joachim99@8: assert( mfi.m_pDMI==pDMI ); joachim99@8: joachim99@69: if ( c==s_OpCol ) joachim99@8: { joachim99@69: bool bThreeDirs = m_dirC.isValid(); joachim99@69: joachim99@80: KMenu m(this); joachim99@69: if ( bThreeDirs ) joachim99@8: { joachim99@80: m.addAction( m_pDirCurrentDoNothing ); joachim99@69: int count=0; joachim99@80: if ( mfi.m_bExistsInA ) { m.addAction( m_pDirCurrentChooseA ); ++count; } joachim99@80: if ( mfi.m_bExistsInB ) { m.addAction( m_pDirCurrentChooseB ); ++count; } joachim99@80: if ( mfi.m_bExistsInC ) { m.addAction( m_pDirCurrentChooseC ); ++count; } joachim99@80: if ( !conflictingFileTypes(mfi) && count>1 ) m.addAction( m_pDirCurrentMerge ); joachim99@80: m.addAction( m_pDirCurrentDelete ); joachim99@69: } joachim99@69: else if ( m_bSyncMode ) joachim99@69: { joachim99@80: m.addAction( m_pDirCurrentSyncDoNothing ); joachim99@80: if ( mfi.m_bExistsInA ) m.addAction( m_pDirCurrentSyncCopyAToB ); joachim99@80: if ( mfi.m_bExistsInB ) m.addAction( m_pDirCurrentSyncCopyBToA ); joachim99@80: if ( mfi.m_bExistsInA ) m.addAction( m_pDirCurrentSyncDeleteA ); joachim99@80: if ( mfi.m_bExistsInB ) m.addAction( m_pDirCurrentSyncDeleteB ); joachim99@69: if ( mfi.m_bExistsInA && mfi.m_bExistsInB ) joachim99@8: { joachim99@80: m.addAction( m_pDirCurrentSyncDeleteAAndB ); joachim99@69: if ( !conflictingFileTypes(mfi)) joachim99@69: { joachim99@80: m.addAction( m_pDirCurrentSyncMergeToA ); joachim99@80: m.addAction( m_pDirCurrentSyncMergeToB ); joachim99@80: m.addAction( m_pDirCurrentSyncMergeToAAndB ); joachim99@69: } joachim99@8: } joachim99@8: } joachim99@69: else joachim99@69: { joachim99@80: m.addAction( m_pDirCurrentDoNothing ); joachim99@80: if ( mfi.m_bExistsInA ) { m.addAction( m_pDirCurrentChooseA ); } joachim99@80: if ( mfi.m_bExistsInB ) { m.addAction( m_pDirCurrentChooseB ); } joachim99@80: if ( !conflictingFileTypes(mfi) && mfi.m_bExistsInA && mfi.m_bExistsInB ) m.addAction( m_pDirCurrentMerge ); joachim99@80: m.addAction( m_pDirCurrentDelete ); joachim99@69: } joachim99@69: joachim99@69: m.exec( p ); joachim99@8: } joachim99@69: else if ( c == s_ACol || c==s_BCol || c==s_CCol ) joachim99@8: { joachim99@69: QString itemPath; joachim99@69: if ( c == s_ACol && mfi.m_bExistsInA ){ itemPath = fullNameA(mfi); } joachim99@69: else if ( c == s_BCol && mfi.m_bExistsInB ){ itemPath = fullNameB(mfi); } joachim99@69: else if ( c == s_CCol && mfi.m_bExistsInC ){ itemPath = fullNameC(mfi); } joachim99@69: joachim99@69: if (!itemPath.isEmpty()) joachim99@69: { joachim99@75: selectItemAndColumn( pDMI, c, e->button()==Qt::RightButton ); joachim99@69: } joachim99@8: } joachim99@69: } joachim99@69: joachim99@75: void DirectoryMergeWindow::contextMenuEvent(QContextMenuEvent* e) joachim99@69: { joachim99@75: QTreeWidgetItem* lvi = itemAt( e->pos() ); joachim99@75: int c = columnAt( e->x() ); joachim99@75: QPoint p = e->globalPos(); joachim99@69: if ( lvi==0 ) return; joachim99@69: joachim99@69: DirMergeItem* pDMI = static_cast(lvi); joachim99@69: joachim99@69: MergeFileInfos& mfi = *pDMI->m_pMFI; joachim99@69: assert( mfi.m_pDMI==pDMI ); joachim99@69: if ( c == s_ACol || c==s_BCol || c==s_CCol ) joachim99@69: { joachim99@69: QString itemPath; joachim99@69: if ( c == s_ACol && mfi.m_bExistsInA ){ itemPath = fullNameA(mfi); } joachim99@69: else if ( c == s_BCol && mfi.m_bExistsInB ){ itemPath = fullNameB(mfi); } joachim99@69: else if ( c == s_CCol && mfi.m_bExistsInC ){ itemPath = fullNameC(mfi); } joachim99@69: joachim99@69: if (!itemPath.isEmpty()) joachim99@69: { joachim99@69: selectItemAndColumn(pDMI, c, true); joachim99@80: KMenu m(this); joachim99@80: m.addAction( m_pDirCompareExplicit ); joachim99@80: m.addAction( m_pDirMergeExplicit ); joachim99@69: joachim99@69: #ifndef _WIN32 joachim99@69: m.exec( p ); joachim99@69: #else joachim99@70: void showShellContextMenu( const QString&, QPoint, QWidget*, QMenu* ); joachim99@69: showShellContextMenu( itemPath, p, this, &m ); joachim99@69: #endif joachim99@69: } joachim99@69: } joachim99@69: } joachim99@69: joachim99@69: static QString getFileName( DirMergeItem* pDMI, int column ) joachim99@69: { joachim99@69: if ( pDMI != 0 ) joachim99@69: { joachim99@69: MergeFileInfos& mfi = *pDMI->m_pMFI; joachim99@80: return column == s_ACol ? mfi.m_fileInfoA.absoluteFilePath() : joachim99@80: column == s_BCol ? mfi.m_fileInfoB.absoluteFilePath() : joachim99@80: column == s_CCol ? mfi.m_fileInfoC.absoluteFilePath() : joachim99@69: QString(""); joachim99@69: } joachim99@69: return ""; joachim99@69: } joachim99@69: joachim99@69: static bool isDir( DirMergeItem* pDMI, int column ) joachim99@69: { joachim99@69: if ( pDMI != 0 ) joachim99@69: { joachim99@69: MergeFileInfos& mfi = *pDMI->m_pMFI; joachim99@69: return column == s_ACol ? mfi.m_bDirA : joachim99@69: column == s_BCol ? mfi.m_bDirB : joachim99@69: mfi.m_bDirC; joachim99@69: } joachim99@69: return false; joachim99@69: } joachim99@69: joachim99@69: joachim99@69: void DirectoryMergeWindow::selectItemAndColumn(DirMergeItem* pDMI, int c, bool bContextMenu) joachim99@69: { joachim99@69: if ( bContextMenu && ( joachim99@80: (pDMI==m_pSelection1Item && c==m_selection1Column) || joachim99@80: (pDMI==m_pSelection2Item && c==m_selection2Column) || joachim99@80: (pDMI==m_pSelection3Item && c==m_selection3Column) ) ) joachim99@69: return; joachim99@69: joachim99@69: DirMergeItem* pOld1=m_pSelection1Item; joachim99@69: DirMergeItem* pOld2=m_pSelection2Item; joachim99@69: DirMergeItem* pOld3=m_pSelection3Item; joachim99@69: joachim99@69: bool bReset = false; joachim99@69: joachim99@69: if ( m_pSelection1Item ) joachim99@69: { joachim99@69: if (isDir( m_pSelection1Item, m_selection1Column )!=isDir( pDMI, c )) joachim99@69: bReset = true; joachim99@69: } joachim99@69: joachim99@69: if ( bReset || m_pSelection3Item!=0 || joachim99@80: (pDMI==m_pSelection1Item && c==m_selection1Column) || joachim99@80: (pDMI==m_pSelection2Item && c==m_selection2Column) || joachim99@80: (pDMI==m_pSelection3Item && c==m_selection3Column)) joachim99@69: { joachim99@69: m_pSelection1Item = 0; joachim99@69: m_pSelection2Item = 0; joachim99@69: m_pSelection3Item = 0; joachim99@69: } joachim99@69: else if ( m_pSelection1Item==0 ) joachim99@69: { joachim99@69: m_pSelection1Item = pDMI; joachim99@69: m_selection1Column = c; joachim99@69: m_pSelection2Item = 0; joachim99@69: m_pSelection3Item = 0; joachim99@69: } joachim99@69: else if ( m_pSelection2Item==0 ) joachim99@69: { joachim99@69: m_pSelection2Item = pDMI; joachim99@69: m_selection2Column = c; joachim99@69: m_pSelection3Item = 0; joachim99@69: } joachim99@69: else if ( m_pSelection3Item==0 ) joachim99@69: { joachim99@69: m_pSelection3Item = pDMI; joachim99@69: m_selection3Column = c; joachim99@69: } joachim99@75: if (pOld1) dataChanged( indexFromItem( pOld1, s_ACol ), indexFromItem( pOld1, s_CCol ) ); joachim99@75: if (pOld2) dataChanged( indexFromItem( pOld2, s_ACol ), indexFromItem( pOld2, s_CCol ) ); joachim99@75: if (pOld3) dataChanged( indexFromItem( pOld3, s_ACol ), indexFromItem( pOld3, s_CCol ) ); joachim99@75: if (m_pSelection1Item) dataChanged( indexFromItem( m_pSelection1Item, s_ACol ), indexFromItem( m_pSelection1Item, s_CCol ) ); joachim99@75: if (m_pSelection2Item) dataChanged( indexFromItem( m_pSelection2Item, s_ACol ), indexFromItem( m_pSelection2Item, s_CCol ) ); joachim99@75: if (m_pSelection3Item) dataChanged( indexFromItem( m_pSelection3Item, s_ACol ), indexFromItem( m_pSelection3Item, s_CCol ) ); joachim99@69: emit updateAvailabilities(); joachim99@8: } joachim99@8: joachim99@75: DirMergeItem::DirMergeItem( QTreeWidget* pParent, const QString& fileName, MergeFileInfos* pMFI ) joachim99@75: : QTreeWidgetItem( pParent, QStringList() << fileName << "" << "" << "" << i18n("To do.") << "" ) joachim99@66: { joachim99@66: init(pMFI); joachim99@66: } joachim99@66: joachim99@66: DirMergeItem::DirMergeItem( DirMergeItem* pParent, const QString& fileName, MergeFileInfos* pMFI ) joachim99@75: : QTreeWidgetItem( pParent, QStringList() << fileName << "" << "" << "" << i18n("To do.") << "" ) joachim99@66: { joachim99@66: init(pMFI); joachim99@66: } joachim99@66: joachim99@66: joachim99@66: void DirMergeItem::init(MergeFileInfos* pMFI) joachim99@8: { joachim99@8: pMFI->m_pDMI = this; joachim99@8: m_pMFI = pMFI; joachim99@66: TotalDiffStatus& tds = pMFI->m_totalDiffStatus; joachim99@66: if ( m_pMFI->m_bDirA || m_pMFI->m_bDirB || m_pMFI->m_bDirC ) joachim99@66: { joachim99@66: } joachim99@66: else joachim99@66: { joachim99@66: setText( s_UnsolvedCol, QString::number( tds.nofUnsolvedConflicts ) ); joachim99@66: setText( s_SolvedCol, QString::number( tds.nofSolvedConflicts ) ); joachim99@66: setText( s_NonWhiteCol, QString::number( tds.nofUnsolvedConflicts + tds.nofSolvedConflicts - tds.nofWhitespaceConflicts ) ); joachim99@66: setText( s_WhiteCol, QString::number( tds.nofWhitespaceConflicts ) ); joachim99@66: } joachim99@80: setSizeHint( s_ACol, QSize(17,17) ); // Iconsize joachim99@80: setSizeHint( s_BCol, QSize(17,17) ); // Iconsize joachim99@80: setSizeHint( s_CCol, QSize(17,17) ); // Iconsize joachim99@8: } joachim99@8: joachim99@75: bool DirMergeItem::operator<(const QTreeWidgetItem& i) const joachim99@8: { joachim99@75: int col = treeWidget()->sortColumn(); joachim99@75: const DirMergeItem* pDMI = static_cast(&i); joachim99@66: bool bDir1 = m_pMFI->m_bDirA || m_pMFI->m_bDirB || m_pMFI->m_bDirC; joachim99@66: bool bDir2 = pDMI->m_pMFI->m_bDirA || pDMI->m_pMFI->m_bDirB || pDMI->m_pMFI->m_bDirC; joachim99@66: if ( m_pMFI==0 || pDMI->m_pMFI==0 || bDir1 == bDir2 ) joachim99@66: { joachim99@66: if(col==s_UnsolvedCol || col==s_SolvedCol || col==s_NonWhiteCol || col==s_WhiteCol) joachim99@75: return text(col).toInt() > i.text(col).toInt(); joachim99@80: else if ( col == s_NameCol ) joachim99@80: return text(col).compare( i.text(col), Qt::CaseInsensitive )<0; joachim99@66: else joachim99@75: return QTreeWidgetItem::operator<(i); joachim99@80: joachim99@66: } joachim99@66: else joachim99@75: return bDir1; joachim99@8: } joachim99@8: joachim99@66: joachim99@8: DirMergeItem::~DirMergeItem() joachim99@8: { joachim99@8: m_pMFI->m_pDMI = 0; joachim99@8: } joachim99@8: joachim99@77: void MergeFileInfos::setMergeOperation( e_MergeOperation eMOp, bool bRecursive ) joachim99@8: { joachim99@51: if ( eMOp != m_eMergeOperation ) joachim99@51: { joachim99@51: m_bOperationComplete = false; joachim99@51: m_pDMI->setText( s_OpStatusCol, "" ); joachim99@51: } joachim99@51: joachim99@8: m_eMergeOperation = eMOp; joachim99@51: QString s; joachim99@8: bool bDir = m_bDirA || m_bDirB || m_bDirC; joachim99@8: if( m_pDMI!=0 ) joachim99@8: { joachim99@8: switch( m_eMergeOperation ) joachim99@8: { joachim99@8: case eNoOperation: s=""; m_pDMI->setText(s_OpCol,""); break; joachim99@51: case eCopyAToB: s=i18n("Copy A to B"); break; joachim99@51: case eCopyBToA: s=i18n("Copy B to A"); break; joachim99@51: case eDeleteA: s=i18n("Delete A"); break; joachim99@51: case eDeleteB: s=i18n("Delete B"); break; joachim99@51: case eDeleteAB: s=i18n("Delete A & B"); break; joachim99@51: case eMergeToA: s=i18n("Merge to A"); break; joachim99@51: case eMergeToB: s=i18n("Merge to B"); break; joachim99@51: case eMergeToAB: s=i18n("Merge to A & B"); break; joachim99@8: case eCopyAToDest: s="A"; break; joachim99@8: case eCopyBToDest: s="B"; break; joachim99@8: case eCopyCToDest: s="C"; break; joachim99@51: case eDeleteFromDest: s=i18n("Delete (if exists)"); break; joachim99@51: case eMergeABCToDest: s= bDir ? i18n("Merge") : i18n("Merge (manual)"); break; joachim99@51: case eMergeABToDest: s= bDir ? i18n("Merge") : i18n("Merge (manual)"); break; joachim99@51: case eConflictingFileTypes: s=i18n("Error: Conflicting File Types"); break; joachim99@92: case eChangedAndDeleted: s=i18n("Error: Changed and Deleted"); break; joachim99@51: case eConflictingAges: s=i18n("Error: Dates are equal but files are not."); break; joachim99@8: default: assert(false); break; joachim99@8: } joachim99@8: m_pDMI->setText(s_OpCol,s); joachim99@8: joachim99@77: if ( bRecursive ) joachim99@8: { joachim99@77: e_MergeOperation eChildrenMergeOp = m_eMergeOperation; joachim99@77: if ( eChildrenMergeOp == eConflictingFileTypes ) eChildrenMergeOp = eMergeABCToDest; joachim99@77: for( int childIdx=0; childIdxchildCount(); ++childIdx ) joachim99@77: { joachim99@77: QTreeWidgetItem* p = m_pDMI->child(childIdx); joachim99@77: DirMergeItem* pDMI = static_cast( p ); joachim99@77: DirectoryMergeWindow* pDMW = static_cast( p->treeWidget() ); joachim99@77: pDMW->calcSuggestedOperation( *pDMI->m_pMFI, eChildrenMergeOp ); joachim99@77: } joachim99@8: } joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: void DirectoryMergeWindow::compareCurrentFile() joachim99@8: { joachim99@8: if (!canContinue()) return; joachim99@8: joachim99@8: if ( m_bRealMergeStarted ) joachim99@8: { joachim99@51: KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible")); joachim99@8: return; joachim99@8: } joachim99@8: joachim99@75: if ( currentItem() != 0 ) joachim99@8: { joachim99@75: DirMergeItem* pDMI = static_cast( currentItem() ); joachim99@8: MergeFileInfos& mfi = *pDMI->m_pMFI; joachim99@8: if ( !(mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC) ) joachim99@8: { joachim99@8: emit startDiffMerge( joachim99@80: mfi.m_bExistsInA ? mfi.m_fileInfoA.absoluteFilePath() : QString(""), joachim99@80: mfi.m_bExistsInB ? mfi.m_fileInfoB.absoluteFilePath() : QString(""), joachim99@80: mfi.m_bExistsInC ? mfi.m_fileInfoC.absoluteFilePath() : QString(""), joachim99@8: "", joachim99@66: "","","",0 joachim99@8: ); joachim99@8: } joachim99@8: } joachim99@8: emit updateAvailabilities(); joachim99@8: } joachim99@8: joachim99@8: joachim99@69: void DirectoryMergeWindow::slotCompareExplicitlySelectedFiles() joachim99@69: { joachim99@69: if ( ! isDir(m_pSelection1Item,m_selection1Column) && !canContinue() ) return; joachim99@69: joachim99@69: if ( m_bRealMergeStarted ) joachim99@69: { joachim99@69: KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible")); joachim99@69: return; joachim99@69: } joachim99@69: joachim99@69: emit startDiffMerge( joachim99@69: getFileName( m_pSelection1Item, m_selection1Column ), joachim99@69: getFileName( m_pSelection2Item, m_selection2Column ), joachim99@69: getFileName( m_pSelection3Item, m_selection3Column ), joachim99@69: "", joachim99@69: "","","",0 joachim99@69: ); joachim99@69: m_pSelection1Item=0; joachim99@69: m_pSelection2Item=0; joachim99@69: m_pSelection3Item=0; joachim99@69: joachim99@69: emit updateAvailabilities(); joachim99@75: update(); joachim99@69: } joachim99@69: joachim99@69: void DirectoryMergeWindow::slotMergeExplicitlySelectedFiles() joachim99@69: { joachim99@69: if ( ! isDir(m_pSelection1Item,m_selection1Column) && !canContinue() ) return; joachim99@69: joachim99@69: if ( m_bRealMergeStarted ) joachim99@69: { joachim99@69: KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible")); joachim99@69: return; joachim99@69: } joachim99@69: joachim99@69: QString fn1 = getFileName( m_pSelection1Item, m_selection1Column ); joachim99@69: QString fn2 = getFileName( m_pSelection2Item, m_selection2Column ); joachim99@69: QString fn3 = getFileName( m_pSelection3Item, m_selection3Column ); joachim99@69: joachim99@69: emit startDiffMerge( fn1, fn2, fn3, joachim99@69: fn3.isEmpty() ? fn2 : fn3, joachim99@69: "","","",0 joachim99@69: ); joachim99@69: m_pSelection1Item=0; joachim99@69: m_pSelection2Item=0; joachim99@69: m_pSelection3Item=0; joachim99@69: joachim99@69: emit updateAvailabilities(); joachim99@75: update(); joachim99@69: } joachim99@8: joachim99@8: bool DirectoryMergeWindow::isFileSelected() joachim99@8: { joachim99@75: if ( currentItem() != 0 ) joachim99@8: { joachim99@75: DirMergeItem* pDMI = static_cast( currentItem() ); joachim99@8: MergeFileInfos& mfi = *pDMI->m_pMFI; joachim99@8: return ! (mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC || conflictingFileTypes(mfi) ); joachim99@8: } joachim99@8: return false; joachim99@8: } joachim99@8: joachim99@8: void DirectoryMergeWindow::mergeResultSaved(const QString& fileName) joachim99@8: { joachim99@51: DirMergeItem* pCurrentItemForOperation = (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() ) joachim99@51: ? 0 joachim99@51: : *m_currentItemForOperation; joachim99@51: joachim99@51: if ( pCurrentItemForOperation!=0 && pCurrentItemForOperation->m_pMFI==0 ) joachim99@8: { joachim99@51: 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") ); joachim99@8: return; joachim99@8: } joachim99@51: if ( pCurrentItemForOperation!=0 && fileName == fullNameDest(*pCurrentItemForOperation->m_pMFI) ) joachim99@8: { joachim99@51: if ( pCurrentItemForOperation->m_pMFI->m_eMergeOperation==eMergeToAB ) joachim99@8: { joachim99@51: MergeFileInfos& mfi = *pCurrentItemForOperation->m_pMFI; joachim99@8: bool bSuccess = copyFLD( fullNameB(mfi), fullNameA(mfi) ); joachim99@8: if (!bSuccess) joachim99@8: { joachim99@51: KMessageBox::error(this, i18n("An error occurred while copying.\n"), i18n("Error") ); joachim99@75: m_pStatusInfo->setWindowTitle(i18n("Merge Error")); joachim99@80: m_pStatusInfo->showMaximized(); joachim99@69: //if ( m_pStatusInfo->firstChild()!=0 ) joachim99@69: // m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() ); joachim99@8: m_bError = true; joachim99@51: pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Error.") ); joachim99@8: mfi.m_eMergeOperation = eCopyBToA; joachim99@8: return; joachim99@8: } joachim99@8: } joachim99@51: pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Done.") ); joachim99@51: pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true; joachim99@51: if ( m_mergeItemList.size()==1 ) joachim99@51: { joachim99@51: m_mergeItemList.clear(); joachim99@51: m_bRealMergeStarted=false; joachim99@51: } joachim99@8: } joachim99@8: joachim99@8: emit updateAvailabilities(); joachim99@8: } joachim99@8: joachim99@8: bool DirectoryMergeWindow::canContinue() joachim99@8: { joachim99@8: bool bCanContinue=false; joachim99@8: checkIfCanContinue( &bCanContinue ); joachim99@8: if ( bCanContinue && !m_bError ) joachim99@8: { joachim99@51: DirMergeItem* pCurrentItemForOperation = joachim99@51: (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() ) ? 0 : *m_currentItemForOperation; joachim99@51: joachim99@51: if ( pCurrentItemForOperation!=0 && ! pCurrentItemForOperation->m_pMFI->m_bOperationComplete ) joachim99@8: { joachim99@51: pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Not saved.") ); joachim99@51: pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true; joachim99@51: if ( m_mergeItemList.size()==1 ) joachim99@51: { joachim99@51: m_mergeItemList.clear(); joachim99@51: m_bRealMergeStarted=false; joachim99@51: } joachim99@8: } joachim99@8: } joachim99@8: return bCanContinue; joachim99@8: } joachim99@8: joachim99@51: bool DirectoryMergeWindow::executeMergeOperation( MergeFileInfos& mfi, bool& bSingleFileMerge ) joachim99@8: { joachim99@51: bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles; joachim99@51: // First decide destname joachim99@51: QString destName; joachim99@51: switch( mfi.m_eMergeOperation ) joachim99@51: { joachim99@51: case eNoOperation: break; joachim99@51: case eDeleteAB: break; joachim99@51: case eMergeToAB: // let the user save in B. In mergeResultSaved() the file will be copied to A. joachim99@51: case eMergeToB: joachim99@51: case eDeleteB: joachim99@51: case eCopyAToB: destName = fullNameB(mfi); break; joachim99@51: case eMergeToA: joachim99@51: case eDeleteA: joachim99@51: case eCopyBToA: destName = fullNameA(mfi); break; joachim99@51: case eMergeABToDest: joachim99@51: case eMergeABCToDest: joachim99@51: case eCopyAToDest: joachim99@51: case eCopyBToDest: joachim99@51: case eCopyCToDest: joachim99@51: case eDeleteFromDest: destName = fullNameDest(mfi); break; joachim99@51: default: joachim99@51: KMessageBox::error( this, i18n("Unknown merge operation. (This must never happen!)"), i18n("Error") ); joachim99@51: assert(false); joachim99@51: } joachim99@8: joachim99@51: bool bSuccess = false; joachim99@51: bSingleFileMerge = false; joachim99@51: switch( mfi.m_eMergeOperation ) joachim99@51: { joachim99@51: case eNoOperation: bSuccess = true; break; joachim99@51: case eCopyAToDest: joachim99@51: case eCopyAToB: bSuccess = copyFLD( fullNameA(mfi), destName ); break; joachim99@51: case eCopyBToDest: joachim99@51: case eCopyBToA: bSuccess = copyFLD( fullNameB(mfi), destName ); break; joachim99@51: case eCopyCToDest: bSuccess = copyFLD( fullNameC(mfi), destName ); break; joachim99@51: case eDeleteFromDest: joachim99@51: case eDeleteA: joachim99@51: case eDeleteB: bSuccess = deleteFLD( destName, bCreateBackups ); break; joachim99@51: case eDeleteAB: bSuccess = deleteFLD( fullNameA(mfi), bCreateBackups ) && joachim99@51: deleteFLD( fullNameB(mfi), bCreateBackups ); break; joachim99@51: case eMergeABToDest: joachim99@51: case eMergeToA: joachim99@51: case eMergeToAB: joachim99@51: case eMergeToB: bSuccess = mergeFLD( fullNameA(mfi), fullNameB(mfi), "", joachim99@51: destName, bSingleFileMerge ); joachim99@51: break; joachim99@51: case eMergeABCToDest:bSuccess = mergeFLD( joachim99@51: mfi.m_bExistsInA ? fullNameA(mfi) : QString(""), joachim99@51: mfi.m_bExistsInB ? fullNameB(mfi) : QString(""), joachim99@51: mfi.m_bExistsInC ? fullNameC(mfi) : QString(""), joachim99@51: destName, bSingleFileMerge ); joachim99@51: break; joachim99@51: default: joachim99@51: KMessageBox::error( this, i18n("Unknown merge operation."), i18n("Error") ); joachim99@51: assert(false); joachim99@51: } joachim99@8: joachim99@51: return bSuccess; joachim99@51: } joachim99@8: joachim99@51: joachim99@51: // Check if the merge can start, and prepare the m_mergeItemList which then contains all joachim99@51: // items that must be merged. joachim99@75: void DirectoryMergeWindow::prepareMergeStart( QTreeWidgetItem* pBegin, QTreeWidgetItem* pEnd, bool bVerbose ) joachim99@51: { joachim99@51: if ( bVerbose ) joachim99@8: { joachim99@51: int status = KMessageBox::warningYesNoCancel(this, joachim99@51: i18n("The merge is about to begin.\n\n" joachim99@51: "Choose \"Do it\" if you have read the instructions and know what you are doing.\n" joachim99@51: "Choosing \"Simulate it\" will tell you what would happen.\n\n" joachim99@51: "Be aware that this program still has beta status " joachim99@51: "and there is NO WARRANTY whatsoever! Make backups of your vital data!"), joachim99@80: i18n("Starting Merge"), joachim99@80: KGuiItem( i18n("Do It") ), joachim99@80: KGuiItem( i18n("Simulate It") ) ); joachim99@51: if (status==KMessageBox::Yes) m_bRealMergeStarted = true; joachim99@51: else if (status==KMessageBox::No ) m_bSimulatedMergeStarted = true; joachim99@51: else return; joachim99@51: } joachim99@51: else joachim99@51: { joachim99@51: m_bRealMergeStarted = true; joachim99@51: } joachim99@51: joachim99@51: m_mergeItemList.clear(); joachim99@51: if (pBegin == 0) joachim99@51: return; joachim99@51: joachim99@75: for( QTreeWidgetItem* p = pBegin; p!= pEnd; p = treeIterator( p ) ) joachim99@51: { joachim99@51: DirMergeItem* pDMI = static_cast(p); joachim99@51: joachim99@69: if ( pDMI && ! pDMI->m_pMFI->m_bOperationComplete ) joachim99@8: { joachim99@51: m_mergeItemList.push_back(pDMI); joachim99@51: joachim99@8: if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingFileTypes ) joachim99@8: { joachim99@75: scrollToItem( pDMI, QAbstractItemView::EnsureVisible ); joachim99@75: pDMI->setSelected( true ); joachim99@51: KMessageBox::error(this, i18n("The highlighted item has a different type in the different directories. Select what to do."), i18n("Error")); joachim99@51: m_mergeItemList.clear(); joachim99@51: m_bRealMergeStarted=false; joachim99@8: return; joachim99@8: } joachim99@8: if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingAges ) joachim99@8: { joachim99@75: scrollToItem ( pDMI, QAbstractItemView::EnsureVisible ); joachim99@75: pDMI->setSelected( true ); joachim99@51: KMessageBox::error(this, i18n("The modification dates of the file are equal but the files are not. Select what to do."), i18n("Error")); joachim99@51: m_mergeItemList.clear(); joachim99@51: m_bRealMergeStarted=false; joachim99@8: return; joachim99@8: } joachim99@92: if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eChangedAndDeleted ) joachim99@92: { joachim99@92: scrollToItem( pDMI, QAbstractItemView::EnsureVisible ); joachim99@92: pDMI->setSelected( true ); joachim99@92: KMessageBox::error(this, i18n("The highlighted item was changed in one directory and deleted in the other. Select what to do."), i18n("Error")); joachim99@92: m_mergeItemList.clear(); joachim99@92: m_bRealMergeStarted=false; joachim99@92: return; joachim99@92: } joachim99@8: } joachim99@8: } joachim99@8: joachim99@51: m_currentItemForOperation = m_mergeItemList.begin(); joachim99@51: return; joachim99@51: } joachim99@51: joachim99@51: void DirectoryMergeWindow::slotRunOperationForCurrentItem() joachim99@51: { joachim99@51: if ( ! canContinue() ) return; joachim99@51: joachim99@51: bool bVerbose = false; joachim99@51: if ( m_mergeItemList.empty() ) joachim99@51: { joachim99@75: QTreeWidgetItem* pBegin = currentItem(); joachim99@75: QTreeWidgetItem* pEnd = treeIterator(pBegin,false,false); // find next visible sibling (no children) joachim99@51: joachim99@53: prepareMergeStart( pBegin, pEnd, bVerbose ); joachim99@51: mergeContinue(true, bVerbose); joachim99@51: } joachim99@51: else joachim99@51: mergeContinue(false, bVerbose); joachim99@51: } joachim99@51: joachim99@51: void DirectoryMergeWindow::slotRunOperationForAllItems() joachim99@51: { joachim99@51: if ( ! canContinue() ) return; joachim99@51: joachim99@51: bool bVerbose = true; joachim99@51: if ( m_mergeItemList.empty() ) joachim99@51: { joachim99@75: QTreeWidgetItem* pBegin = topLevelItemCount()>0 ? topLevelItem(0) : 0; joachim99@51: joachim99@51: prepareMergeStart( pBegin, 0, bVerbose ); joachim99@51: mergeContinue(true, bVerbose); joachim99@51: } joachim99@51: else joachim99@51: mergeContinue(false, bVerbose); joachim99@51: } joachim99@51: joachim99@51: void DirectoryMergeWindow::mergeCurrentFile() joachim99@51: { joachim99@51: if (!canContinue()) return; joachim99@51: joachim99@51: if ( m_bRealMergeStarted ) joachim99@51: { joachim99@66: KMessageBox::sorry(this,i18n("This operation is currently not possible because directory merge is currently running."),i18n("Operation Not Possible")); joachim99@51: return; joachim99@51: } joachim99@51: joachim99@51: if ( isFileSelected() ) joachim99@51: { joachim99@75: DirMergeItem* pDMI = static_cast( currentItem() ); joachim99@51: if ( pDMI != 0 ) joachim99@51: { joachim99@51: MergeFileInfos& mfi = *pDMI->m_pMFI; joachim99@51: m_mergeItemList.clear(); joachim99@51: m_mergeItemList.push_back( pDMI ); joachim99@51: m_currentItemForOperation=m_mergeItemList.begin(); joachim99@51: bool bDummy=false; joachim99@51: mergeFLD( joachim99@80: mfi.m_bExistsInA ? mfi.m_fileInfoA.absoluteFilePath() : QString(""), joachim99@80: mfi.m_bExistsInB ? mfi.m_fileInfoB.absoluteFilePath() : QString(""), joachim99@80: mfi.m_bExistsInC ? mfi.m_fileInfoC.absoluteFilePath() : QString(""), joachim99@51: fullNameDest(mfi), joachim99@51: bDummy joachim99@51: ); joachim99@51: } joachim99@51: } joachim99@51: emit updateAvailabilities(); joachim99@51: } joachim99@51: joachim99@51: joachim99@51: // When bStart is true then m_currentItemForOperation must still be processed. joachim99@51: // When bVerbose is true then a messagebox will tell when the merge is complete. joachim99@51: void DirectoryMergeWindow::mergeContinue(bool bStart, bool bVerbose) joachim99@51: { joachim99@66: ProgressProxy pp; joachim99@51: if ( m_mergeItemList.empty() ) joachim99@51: return; joachim99@51: joachim99@51: int nrOfItems = 0; joachim99@51: int nrOfCompletedItems = 0; joachim99@51: int nrOfCompletedSimItems = 0; joachim99@51: joachim99@51: // Count the number of completed items (for the progress bar). joachim99@51: for( MergeItemList::iterator i = m_mergeItemList.begin(); i!=m_mergeItemList.end(); ++i ) joachim99@51: { joachim99@53: DirMergeItem* pDMI = *i; joachim99@51: ++nrOfItems; joachim99@51: if ( pDMI->m_pMFI->m_bOperationComplete ) joachim99@51: ++nrOfCompletedItems; joachim99@51: if ( pDMI->m_pMFI->m_bSimOpComplete ) joachim99@51: ++nrOfCompletedSimItems; joachim99@51: } joachim99@51: joachim99@51: m_pStatusInfo->hide(); joachim99@51: m_pStatusInfo->clear(); joachim99@51: joachim99@51: DirMergeItem* pCurrentItemForOperation = m_currentItemForOperation==m_mergeItemList.end() ? 0 : *m_currentItemForOperation; joachim99@51: joachim99@51: bool bContinueWithCurrentItem = bStart; // true for first item, else false joachim99@8: bool bSkipItem = false; joachim99@51: if ( !bStart && m_bError && pCurrentItemForOperation!=0 ) joachim99@8: { joachim99@8: int status = KMessageBox::warningYesNoCancel(this, joachim99@8: i18n("There was an error in the last step.\n" joachim99@8: "Do you want to continue with the item that caused the error or do you want to skip this item?"), joachim99@80: i18n("Continue merge after an error"), joachim99@80: KGuiItem( i18n("Continue With Last Item") ), joachim99@80: KGuiItem( i18n("Skip Item") ) ); joachim99@51: if (status==KMessageBox::Yes) bContinueWithCurrentItem = true; joachim99@8: else if (status==KMessageBox::No ) bSkipItem = true; joachim99@8: else return; joachim99@8: m_bError = false; joachim99@8: } joachim99@8: joachim99@8: bool bSuccess = true; joachim99@8: bool bSingleFileMerge = false; joachim99@8: bool bSim = m_bSimulatedMergeStarted; joachim99@8: while( bSuccess ) joachim99@8: { joachim99@51: if ( pCurrentItemForOperation==0 ) joachim99@51: { joachim99@51: m_mergeItemList.clear(); joachim99@51: m_bRealMergeStarted=false; joachim99@51: break; joachim99@51: } joachim99@51: joachim99@51: if ( pCurrentItemForOperation!=0 && !bContinueWithCurrentItem ) joachim99@8: { joachim99@8: if ( bSim ) joachim99@8: { joachim99@75: if( pCurrentItemForOperation->childCount()==0 ) joachim99@8: { joachim99@51: pCurrentItemForOperation->m_pMFI->m_bSimOpComplete = true; joachim99@8: } joachim99@8: } joachim99@8: else joachim99@8: { joachim99@75: if( pCurrentItemForOperation->childCount()==0 ) joachim99@8: { joachim99@51: if( !pCurrentItemForOperation->m_pMFI->m_bOperationComplete ) joachim99@8: { joachim99@51: pCurrentItemForOperation->setText( s_OpStatusCol, bSkipItem ? i18n("Skipped.") : i18n("Done.") ); joachim99@51: pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true; joachim99@8: bSkipItem = false; joachim99@8: } joachim99@8: } joachim99@8: else joachim99@8: { joachim99@51: pCurrentItemForOperation->setText( s_OpStatusCol, i18n("In progress...") ); joachim99@8: } joachim99@8: } joachim99@8: } joachim99@8: joachim99@51: if ( ! bContinueWithCurrentItem ) joachim99@8: { joachim99@51: // Depth first joachim99@75: QTreeWidgetItem* pPrevItem = pCurrentItemForOperation; joachim99@51: ++m_currentItemForOperation; joachim99@51: pCurrentItemForOperation = m_currentItemForOperation==m_mergeItemList.end() ? 0 : *m_currentItemForOperation; joachim99@51: if ( (pCurrentItemForOperation==0 || pCurrentItemForOperation->parent()!=pPrevItem->parent()) && pPrevItem->parent()!=0 ) joachim99@8: { joachim99@51: // Check if the parent may be set to "Done" joachim99@75: QTreeWidgetItem* pParent = pPrevItem->parent(); joachim99@51: bool bDone = true; joachim99@51: while ( bDone && pParent!=0 ) joachim99@8: { joachim99@75: for( int childIdx = 0; childIdxchildCount(); ++childIdx ) joachim99@8: { joachim99@75: DirMergeItem* pDMI = static_cast(pParent->child(childIdx)); joachim99@80: if ( (!bSim && ! pDMI->m_pMFI->m_bOperationComplete) || (bSim && pDMI->m_pMFI->m_bSimOpComplete) ) joachim99@8: { joachim99@51: bDone=false; joachim99@51: break; joachim99@8: } joachim99@8: } joachim99@51: if ( bDone ) joachim99@51: { joachim99@51: if (bSim) joachim99@51: static_cast(pParent)->m_pMFI->m_bSimOpComplete = bDone; joachim99@51: else joachim99@51: { joachim99@51: pParent->setText( s_OpStatusCol, i18n("Done.") ); joachim99@51: static_cast(pParent)->m_pMFI->m_bOperationComplete = bDone; joachim99@51: } joachim99@51: } joachim99@51: pParent = pParent->parent(); joachim99@8: } joachim99@8: } joachim99@8: } joachim99@8: joachim99@51: if ( pCurrentItemForOperation == 0 ) // end? joachim99@8: { joachim99@8: if ( m_bRealMergeStarted ) joachim99@8: { joachim99@51: if (bVerbose) joachim99@51: { joachim99@51: KMessageBox::information( this, i18n("Merge operation complete."), i18n("Merge Complete") ); joachim99@51: } joachim99@8: m_bRealMergeStarted = false; joachim99@75: m_pStatusInfo->setWindowTitle(i18n("Merge Complete")); joachim99@8: } joachim99@8: if ( m_bSimulatedMergeStarted ) joachim99@8: { joachim99@8: m_bSimulatedMergeStarted = false; joachim99@75: QTreeWidgetItem* p = topLevelItemCount()>0 ? topLevelItem(0) : 0; joachim99@75: for( ; p!=0; p=treeIterator(p) ) joachim99@8: { joachim99@8: static_cast(p)->m_pMFI->m_bSimOpComplete = false; joachim99@8: } joachim99@75: m_pStatusInfo->setWindowTitle(i18n("Simulated merge complete: Check if you agree with the proposed operations.")); joachim99@80: m_pStatusInfo->showMaximized(); joachim99@8: } joachim99@51: m_mergeItemList.clear(); joachim99@51: m_bRealMergeStarted=false; joachim99@8: return; joachim99@8: } joachim99@8: joachim99@51: MergeFileInfos& mfi = *pCurrentItemForOperation->m_pMFI; joachim99@8: joachim99@66: pp.setInformation( mfi.m_subPath, joachim99@8: bSim ? double(nrOfCompletedSimItems)/nrOfItems : double(nrOfCompletedItems)/nrOfItems, joachim99@51: false // bRedrawUpdate joachim99@8: ); joachim99@8: joachim99@51: bSuccess = executeMergeOperation( mfi, bSingleFileMerge ); // Here the real operation happens. joachim99@8: joachim99@8: if ( bSuccess ) joachim99@8: { joachim99@8: if(bSim) ++nrOfCompletedSimItems; joachim99@8: else ++nrOfCompletedItems; joachim99@8: bContinueWithCurrentItem = false; joachim99@8: } joachim99@51: joachim99@66: if( pp.wasCancelled() ) joachim99@51: break; joachim99@8: } // end while joachim99@8: joachim99@66: //g_pProgressDialog->hide(); joachim99@8: joachim99@51: setCurrentItem( pCurrentItemForOperation ); joachim99@75: scrollToItem( pCurrentItemForOperation, EnsureVisible ); joachim99@8: if ( !bSuccess && !bSingleFileMerge ) joachim99@8: { joachim99@51: KMessageBox::error(this, i18n("An error occurred. Press OK to see detailed information.\n"), i18n("Error") ); joachim99@75: m_pStatusInfo->setWindowTitle(i18n("Merge Error")); joachim99@80: m_pStatusInfo->showMaximized(); joachim99@69: //if ( m_pStatusInfo->firstChild()!=0 ) joachim99@69: // m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() ); joachim99@8: m_bError = true; joachim99@51: pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Error.") ); joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: m_bError = false; joachim99@8: } joachim99@8: emit updateAvailabilities(); joachim99@51: joachim99@51: if ( m_currentItemForOperation==m_mergeItemList.end() ) joachim99@51: { joachim99@51: m_mergeItemList.clear(); joachim99@51: m_bRealMergeStarted=false; joachim99@51: } joachim99@8: } joachim99@8: joachim99@8: bool DirectoryMergeWindow::deleteFLD( const QString& name, bool bCreateBackup ) joachim99@8: { joachim99@8: FileAccess fi(name, true); joachim99@8: if ( !fi.exists() ) joachim99@8: return true; joachim99@8: joachim99@8: if ( bCreateBackup ) joachim99@8: { joachim99@8: bool bSuccess = renameFLD( name, name+".orig" ); joachim99@8: if (!bSuccess) joachim99@8: { joachim99@80: m_pStatusInfo->addText( i18n("Error: While deleting %1: Creating backup failed.",name) ); joachim99@8: return false; joachim99@8: } joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: if ( fi.isDir() && !fi.isSymLink() ) joachim99@80: m_pStatusInfo->addText(i18n("delete directory recursively( %1 )",name)); joachim99@8: else joachim99@80: m_pStatusInfo->addText(i18n("delete( %1 )",name)); joachim99@8: joachim99@8: if ( m_bSimulatedMergeStarted ) joachim99@8: { joachim99@8: return true; joachim99@8: } joachim99@8: joachim99@8: if ( fi.isDir() && !fi.isSymLink() )// recursive directory delete only for real dirs, not symlinks joachim99@8: { joachim99@8: t_DirectoryList dirList; joachim99@8: bool bSuccess = fi.listDir( &dirList, false, true, "*", "", "", false, false ); // not recursive, find hidden files joachim99@8: joachim99@8: if ( !bSuccess ) joachim99@8: { joachim99@8: // No Permission to read directory or other error. joachim99@51: m_pStatusInfo->addText( i18n("Error: delete dir operation failed while trying to read the directory.") ); joachim99@8: return false; joachim99@8: } joachim99@8: joachim99@8: t_DirectoryList::iterator it; // create list iterator joachim99@8: joachim99@8: for ( it=dirList.begin(); it!=dirList.end(); ++it ) // for each file... joachim99@8: { joachim99@8: FileAccess& fi2 = *it; joachim99@8: if ( fi2.fileName() == "." || fi2.fileName()==".." ) joachim99@8: continue; joachim99@80: bSuccess = deleteFLD( fi2.absoluteFilePath(), false ); joachim99@8: if (!bSuccess) break; joachim99@8: } joachim99@8: if (bSuccess) joachim99@8: { joachim99@8: bSuccess = FileAccess::removeDir( name ); joachim99@8: if ( !bSuccess ) joachim99@8: { joachim99@80: m_pStatusInfo->addText( i18n("Error: rmdir( %1 ) operation failed.",name)); joachim99@8: return false; joachim99@8: } joachim99@8: } joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: bool bSuccess = FileAccess::removeFile( name ); joachim99@8: if ( !bSuccess ) joachim99@8: { joachim99@51: m_pStatusInfo->addText( i18n("Error: delete operation failed.") ); joachim99@8: return false; joachim99@8: } joachim99@8: } joachim99@8: } joachim99@8: return true; joachim99@8: } joachim99@8: joachim99@8: bool DirectoryMergeWindow::mergeFLD( const QString& nameA,const QString& nameB,const QString& nameC,const QString& nameDest, bool& bSingleFileMerge ) joachim99@8: { joachim99@8: FileAccess fi(nameA); joachim99@8: if (fi.isDir()) joachim99@8: { joachim99@8: return makeDir(nameDest); joachim99@8: } joachim99@8: joachim99@8: // Make sure that the dir exists, into which we will save the file later. joachim99@75: int pos=nameDest.lastIndexOf('/'); joachim99@8: if ( pos>0 ) joachim99@8: { joachim99@8: QString parentName = nameDest.left(pos); joachim99@8: bool bSuccess = makeDir(parentName, true /*quiet*/); joachim99@8: if (!bSuccess) joachim99@8: return false; joachim99@8: } joachim99@8: joachim99@80: m_pStatusInfo->addText(i18n("manual merge( %1, %2, %3 -> %4)",nameA,nameB,nameC,nameDest)); joachim99@8: if ( m_bSimulatedMergeStarted ) joachim99@8: { joachim99@66: m_pStatusInfo->addText(i18n(" Note: After a manual merge the user should continue by pressing F7.") ); joachim99@8: return true; joachim99@8: } joachim99@8: joachim99@8: bSingleFileMerge = true; joachim99@51: (*m_currentItemForOperation)->setText( s_OpStatusCol, i18n("In progress...") ); joachim99@75: scrollToItem( *m_currentItemForOperation, EnsureVisible ); joachim99@8: joachim99@66: emit startDiffMerge( nameA, nameB, nameC, nameDest, "","","",0 ); joachim99@8: joachim99@8: return false; joachim99@8: } joachim99@8: joachim99@8: bool DirectoryMergeWindow::copyFLD( const QString& srcName, const QString& destName ) joachim99@8: { joachim99@8: if ( srcName == destName ) joachim99@8: return true; joachim99@8: joachim99@96: FileAccess fi( srcName ); joachim99@96: FileAccess faDest(destName, true); joachim99@96: if ( faDest.exists() && !( fi.isDir() && faDest.isDir() && (fi.isSymLink()==faDest.isSymLink())) ) joachim99@8: { joachim99@8: bool bSuccess = deleteFLD( destName, m_pOptions->m_bDmCreateBakFiles ); joachim99@8: if ( !bSuccess ) joachim99@8: { joachim99@51: m_pStatusInfo->addText(i18n("Error: copy( %1 -> %2 ) failed." joachim99@80: "Deleting existing destination failed.",srcName,destName)); joachim99@8: return false; joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: joachim99@80: if ( fi.isSymLink() && ((fi.isDir() && !m_bFollowDirLinks) || (!fi.isDir() && !m_bFollowFileLinks)) ) joachim99@8: { joachim99@80: m_pStatusInfo->addText(i18n("copyLink( %1 -> %2 )",srcName,destName)); joachim99@95: #if defined(_WIN32) || defined(Q_OS_OS2) joachim99@8: // What are links? joachim99@8: #else joachim99@8: if ( m_bSimulatedMergeStarted ) joachim99@8: { joachim99@8: return true; joachim99@8: } joachim99@8: FileAccess destFi(destName); joachim99@8: if ( !destFi.isLocal() || !fi.isLocal() ) joachim99@8: { joachim99@51: m_pStatusInfo->addText(i18n("Error: copyLink failed: Remote links are not yet supported.")); joachim99@8: return false; joachim99@8: } joachim99@8: QString linkTarget = fi.readLink(); joachim99@8: bool bSuccess = FileAccess::symLink( linkTarget, destName ); joachim99@8: if (!bSuccess) joachim99@51: m_pStatusInfo->addText(i18n("Error: copyLink failed.")); joachim99@8: return bSuccess; joachim99@8: #endif joachim99@8: } joachim99@8: joachim99@8: if ( fi.isDir() ) joachim99@8: { joachim99@96: if ( faDest.exists() ) joachim99@96: return true; joachim99@96: else joachim99@96: { joachim99@96: bool bSuccess = makeDir( destName ); joachim99@96: return bSuccess; joachim99@96: } joachim99@8: } joachim99@8: joachim99@75: int pos=destName.lastIndexOf('/'); joachim99@8: if ( pos>0 ) joachim99@8: { joachim99@8: QString parentName = destName.left(pos); joachim99@8: bool bSuccess = makeDir(parentName, true /*quiet*/); joachim99@8: if (!bSuccess) joachim99@8: return false; joachim99@8: } joachim99@8: joachim99@80: m_pStatusInfo->addText(i18n("copy( %1 -> %2 )",srcName,destName)); joachim99@8: joachim99@8: if ( m_bSimulatedMergeStarted ) joachim99@8: { joachim99@8: return true; joachim99@8: } joachim99@8: joachim99@8: FileAccess faSrc ( srcName ); joachim99@8: bool bSuccess = faSrc.copyFile( destName ); joachim99@8: if (! bSuccess ) m_pStatusInfo->addText( faSrc.getStatusText() ); joachim99@8: return bSuccess; joachim99@8: } joachim99@8: joachim99@8: // Rename is not an operation that can be selected by the user. joachim99@8: // It will only be used to create backups. joachim99@8: // Hence it will delete an existing destination without making a backup (of the old backup.) joachim99@8: bool DirectoryMergeWindow::renameFLD( const QString& srcName, const QString& destName ) joachim99@8: { joachim99@8: if ( srcName == destName ) joachim99@8: return true; joachim99@8: joachim99@8: if ( FileAccess(destName, true).exists() ) joachim99@8: { joachim99@8: bool bSuccess = deleteFLD( destName, false /*no backup*/ ); joachim99@8: if (!bSuccess) joachim99@8: { joachim99@51: m_pStatusInfo->addText( i18n("Error during rename( %1 -> %2 ): " joachim99@80: "Cannot delete existing destination." ,srcName,destName)); joachim99@8: return false; joachim99@8: } joachim99@8: } joachim99@8: joachim99@80: m_pStatusInfo->addText(i18n("rename( %1 -> %2 )",srcName,destName)); joachim99@8: if ( m_bSimulatedMergeStarted ) joachim99@8: { joachim99@8: return true; joachim99@8: } joachim99@8: joachim99@8: bool bSuccess = FileAccess( srcName ).rename( destName ); joachim99@8: if (!bSuccess) joachim99@8: { joachim99@51: m_pStatusInfo->addText( i18n("Error: Rename failed.") ); joachim99@8: return false; joachim99@8: } joachim99@8: joachim99@8: return true; joachim99@8: } joachim99@8: joachim99@8: bool DirectoryMergeWindow::makeDir( const QString& name, bool bQuiet ) joachim99@8: { joachim99@8: FileAccess fi(name, true); joachim99@8: if( fi.exists() && fi.isDir() ) joachim99@8: return true; joachim99@8: joachim99@8: if( fi.exists() && !fi.isDir() ) joachim99@8: { joachim99@8: bool bSuccess = deleteFLD( name, true ); joachim99@8: if (!bSuccess) joachim99@8: { joachim99@51: m_pStatusInfo->addText( i18n("Error during makeDir of %1. " joachim99@80: "Cannot delete existing file." ,name)); joachim99@8: return false; joachim99@8: } joachim99@8: } joachim99@8: joachim99@75: int pos=name.lastIndexOf('/'); joachim99@8: if ( pos>0 ) joachim99@8: { joachim99@8: QString parentName = name.left(pos); joachim99@8: bool bSuccess = makeDir(parentName,true); joachim99@8: if (!bSuccess) joachim99@8: return false; joachim99@8: } joachim99@8: joachim99@8: if ( ! bQuiet ) joachim99@80: m_pStatusInfo->addText(i18n("makeDir( %1 )",name)); joachim99@8: joachim99@8: if ( m_bSimulatedMergeStarted ) joachim99@8: { joachim99@8: return true; joachim99@8: } joachim99@8: joachim99@8: bool bSuccess = FileAccess::makeDir( name ); joachim99@8: if ( bSuccess == false ) joachim99@8: { joachim99@51: m_pStatusInfo->addText( i18n("Error while creating directory.") ); joachim99@8: return false; joachim99@8: } joachim99@8: return true; joachim99@8: } joachim99@8: joachim99@8: joachim99@8: DirectoryMergeInfo::DirectoryMergeInfo( QWidget* pParent ) joachim99@75: : QFrame(pParent) joachim99@8: { joachim99@75: QVBoxLayout *topLayout = new QVBoxLayout( this ); joachim99@75: topLayout->setMargin(0); joachim99@75: joachim99@75: QGridLayout *grid = new QGridLayout(); joachim99@75: topLayout->addLayout(grid); joachim99@75: grid->setColumnStretch(1,10); joachim99@8: joachim99@8: int line=0; joachim99@8: joachim99@8: m_pA = new QLabel("A",this); grid->addWidget( m_pA,line, 0 ); joachim99@8: m_pInfoA = new QLabel(this); grid->addWidget( m_pInfoA,line,1 ); ++line; joachim99@8: m_pB = new QLabel("B",this); grid->addWidget( m_pB,line, 0 ); joachim99@8: m_pInfoB = new QLabel(this); grid->addWidget( m_pInfoB,line,1 ); ++line; joachim99@8: m_pC = new QLabel("C",this); grid->addWidget( m_pC,line, 0 ); joachim99@8: m_pInfoC = new QLabel(this); grid->addWidget( m_pInfoC,line,1 ); ++line; joachim99@51: m_pDest = new QLabel(i18n("Dest"),this); grid->addWidget( m_pDest,line, 0 ); joachim99@8: m_pInfoDest = new QLabel(this); grid->addWidget( m_pInfoDest,line,1 ); ++line; joachim99@8: joachim99@75: m_pInfoList = new QTreeWidget(this); topLayout->addWidget( m_pInfoList ); joachim99@75: m_pInfoList->setHeaderLabels( QStringList() << i18n("Dir") << i18n("Type") << i18n("Size") joachim99@75: << i18n("Attr") << i18n("Last Modification") << i18n("Link-Destination") ); joachim99@8: setMinimumSize( 100,100 ); joachim99@68: joachim99@66: m_pInfoList->installEventFilter(this); joachim99@75: m_pInfoList->setRootIsDecorated( false ); joachim99@66: } joachim99@66: joachim99@66: bool DirectoryMergeInfo::eventFilter(QObject*o, QEvent* e) joachim99@66: { joachim99@66: if ( e->type()==QEvent::FocusIn && o==m_pInfoList ) joachim99@66: emit gotFocus(); joachim99@66: return false; joachim99@8: } joachim99@8: joachim99@75: static void addListViewItem( QTreeWidget* pListView, const QString& dir, joachim99@8: const QString& basePath, FileAccess& fi ) joachim99@8: { joachim99@8: if ( basePath.isEmpty() ) joachim99@8: { joachim99@8: return; joachim99@8: } joachim99@8: else joachim99@8: { joachim99@8: if ( fi.exists() ) joachim99@8: { joachim99@8: QString dateString = fi.lastModified().toString("yyyy-MM-dd hh:mm:ss"); joachim99@75: joachim99@75: new QTreeWidgetItem( joachim99@8: pListView, joachim99@75: QStringList() << dir << joachim99@75: QString( fi.isDir() ? i18n("Dir") : i18n("File") ) + (fi.isSymLink() ? "-Link" : "") << joachim99@75: QString::number(fi.size()) << joachim99@8: QString(fi.isReadable() ? "r" : " ") + (fi.isWritable()?"w" : " ") joachim99@8: #ifdef _WIN32 joachim99@75: /*Future: Use GetFileAttributes()*/ << joachim99@8: #else joachim99@75: + (fi.isExecutable()?"x" : " ") << joachim99@8: #endif joachim99@75: dateString << joachim99@8: QString(fi.isSymLink() ? (" -> " + fi.readLink()) : QString("")) joachim99@8: ); joachim99@8: } joachim99@8: else joachim99@8: { joachim99@75: new QTreeWidgetItem( joachim99@8: pListView, joachim99@75: QStringList() << dir << joachim99@75: i18n("not available") << joachim99@75: "" << joachim99@75: "" << joachim99@75: "" << joachim99@8: "" joachim99@8: ); joachim99@8: } joachim99@8: } joachim99@8: } joachim99@8: joachim99@8: void DirectoryMergeInfo::setInfo( joachim99@8: const FileAccess& dirA, joachim99@8: const FileAccess& dirB, joachim99@8: const FileAccess& dirC, joachim99@8: const FileAccess& dirDest, joachim99@8: MergeFileInfos& mfi ) joachim99@8: { joachim99@8: bool bHideDest = false; joachim99@80: if ( dirA.absoluteFilePath()==dirDest.absoluteFilePath() ) joachim99@8: { joachim99@51: m_pA->setText( i18n("A (Dest): ") ); bHideDest=true; joachim99@8: } joachim99@8: else joachim99@51: m_pA->setText( !dirC.isValid() ? QString("A: ") : i18n("A (Base): ")); joachim99@8: joachim99@8: m_pInfoA->setText( dirA.prettyAbsPath() ); joachim99@8: joachim99@80: if ( dirB.absoluteFilePath()==dirDest.absoluteFilePath() ) joachim99@8: { joachim99@51: m_pB->setText( i18n("B (Dest): ") ); bHideDest=true; joachim99@8: } joachim99@8: else joachim99@8: m_pB->setText( "B: " ); joachim99@8: m_pInfoB->setText( dirB.prettyAbsPath() ); joachim99@8: joachim99@80: if ( dirC.absoluteFilePath()==dirDest.absoluteFilePath() ) joachim99@8: { joachim99@51: m_pC->setText( i18n("C (Dest): ") ); bHideDest=true; joachim99@8: } joachim99@8: else joachim99@8: m_pC->setText( "C: " ); joachim99@8: m_pInfoC->setText( dirC.prettyAbsPath() ); joachim99@8: joachim99@51: m_pDest->setText( i18n("Dest: ") ); m_pInfoDest->setText( dirDest.prettyAbsPath() ); joachim99@8: joachim99@8: if (!dirC.isValid()) { m_pC->hide(); m_pInfoC->hide(); } joachim99@8: else { m_pC->show(); m_pInfoC->show(); } joachim99@8: joachim99@8: if (!dirDest.isValid()||bHideDest) { m_pDest->hide(); m_pInfoDest->hide(); } joachim99@8: else { m_pDest->show(); m_pInfoDest->show(); } joachim99@8: joachim99@8: m_pInfoList->clear(); joachim99@8: addListViewItem( m_pInfoList, "A", dirA.prettyAbsPath(), mfi.m_fileInfoA ); joachim99@8: addListViewItem( m_pInfoList, "B", dirB.prettyAbsPath(), mfi.m_fileInfoB ); joachim99@8: addListViewItem( m_pInfoList, "C", dirC.prettyAbsPath(), mfi.m_fileInfoC ); joachim99@8: if (!bHideDest) joachim99@8: { joachim99@8: FileAccess fiDest( dirDest.prettyAbsPath() + "/" + mfi.m_subPath, true ); joachim99@51: addListViewItem( m_pInfoList, i18n("Dest"), dirDest.prettyAbsPath(), fiDest ); joachim99@8: } joachim99@75: for (int i=0;icolumnCount();++i) joachim99@75: m_pInfoList->resizeColumnToContents ( i ); joachim99@8: } joachim99@8: joachim99@69: QTextStream& operator<<( QTextStream& ts, MergeFileInfos& mfi ) joachim99@69: { joachim99@69: ts << "{\n"; joachim99@69: ValueMap vm; joachim99@69: vm.writeEntry( "SubPath", mfi.m_subPath ); joachim99@69: vm.writeEntry( "ExistsInA", mfi.m_bExistsInA ); joachim99@69: vm.writeEntry( "ExistsInB", mfi.m_bExistsInB ); joachim99@69: vm.writeEntry( "ExistsInC", mfi.m_bExistsInC ); joachim99@69: vm.writeEntry( "EqualAB", mfi.m_bEqualAB ); joachim99@69: vm.writeEntry( "EqualAC", mfi.m_bEqualAC ); joachim99@69: vm.writeEntry( "EqualBC", mfi.m_bEqualBC ); joachim99@69: //DirMergeItem* m_pDMI; joachim99@69: //MergeFileInfos* m_pParent; joachim99@69: vm.writeEntry( "MergeOperation", (int) mfi.m_eMergeOperation ); joachim99@69: vm.writeEntry( "DirA", mfi.m_bDirA ); joachim99@69: vm.writeEntry( "DirB", mfi.m_bDirB ); joachim99@69: vm.writeEntry( "DirC", mfi.m_bDirC ); joachim99@69: vm.writeEntry( "LinkA", mfi.m_bLinkA ); joachim99@69: vm.writeEntry( "LinkB", mfi.m_bLinkB ); joachim99@69: vm.writeEntry( "LinkC", mfi.m_bLinkC ); joachim99@69: vm.writeEntry( "OperationComplete", mfi.m_bOperationComplete ); joachim99@69: //bool m_bSimOpComplete ); joachim99@69: joachim99@69: vm.writeEntry( "AgeA", (int) mfi.m_ageA ); joachim99@69: vm.writeEntry( "AgeB", (int) mfi.m_ageB ); joachim99@69: vm.writeEntry( "AgeC", (int) mfi.m_ageC ); joachim99@69: vm.writeEntry( "ConflictingAges", mfi.m_bConflictingAges ); // Equal age but files are not! joachim99@69: joachim99@69: //FileAccess m_fileInfoA; joachim99@69: //FileAccess m_fileInfoB; joachim99@69: //FileAccess m_fileInfoC; joachim99@69: joachim99@69: //TotalDiffStatus m_totalDiffStatus; joachim99@69: joachim99@69: vm.save(ts); joachim99@69: joachim99@69: ts << "}\n"; joachim99@69: joachim99@69: return ts; joachim99@69: } joachim99@69: joachim99@69: void DirectoryMergeWindow::slotSaveMergeState() joachim99@69: { joachim99@69: //slotStatusMsg(i18n("Saving Directory Merge State ...")); joachim99@69: joachim99@80: //QString s = KFileDialog::getSaveUrl( QDir::currentPath(), 0, this, i18n("Save As...") ).url(); joachim99@75: QString s = KFileDialog::getSaveFileName( QDir::currentPath(), 0, this, i18n("Save Directory Merge State As...") ); joachim99@69: if(!s.isEmpty()) joachim99@69: { joachim99@69: m_dirMergeStateFilename = s; joachim99@69: joachim99@69: joachim99@69: QFile file(m_dirMergeStateFilename); joachim99@70: bool bSuccess = file.open( QIODevice::WriteOnly ); joachim99@69: if ( bSuccess ) joachim99@69: { joachim99@69: QTextStream ts( &file ); joachim99@69: joachim99@75: QTreeWidgetItemIterator it( this ); joachim99@75: while ( *it ) { joachim99@75: DirMergeItem* item = static_cast(*it); joachim99@69: MergeFileInfos* pMFI = item->m_pMFI; joachim99@69: ts << *pMFI; joachim99@69: ++it; joachim99@69: } joachim99@69: } joachim99@69: } joachim99@69: joachim99@69: //slotStatusMsg(i18n("Ready.")); joachim99@69: joachim99@69: } joachim99@69: joachim99@69: void DirectoryMergeWindow::slotLoadMergeState() joachim99@69: { joachim99@69: } joachim99@69: joachim99@69: void DirectoryMergeWindow::updateFileVisibilities() joachim99@69: { joachim99@69: bool bShowIdentical = m_pDirShowIdenticalFiles->isChecked(); joachim99@69: bool bShowDifferent = m_pDirShowDifferentFiles->isChecked(); joachim99@69: bool bShowOnlyInA = m_pDirShowFilesOnlyInA->isChecked(); joachim99@69: bool bShowOnlyInB = m_pDirShowFilesOnlyInB->isChecked(); joachim99@69: bool bShowOnlyInC = m_pDirShowFilesOnlyInC->isChecked(); joachim99@69: bool bThreeDirs = m_dirC.isValid(); joachim99@69: m_pSelection1Item = 0; joachim99@69: m_pSelection2Item = 0; joachim99@69: m_pSelection3Item = 0; joachim99@69: joachim99@92: // in first run set all dirs to equal and determine if they are not equal. joachim99@92: // on second run don't change the equal-status anymore; it is needed to joachim99@92: // set the visibility (when bShowIdentical is false). joachim99@92: for( int loop=0; loop<2; ++loop ) joachim99@69: { joachim99@92: QTreeWidgetItem* p = topLevelItemCount()>0 ? topLevelItem(0) : 0; joachim99@92: while(p) joachim99@92: { joachim99@92: DirMergeItem* pDMI = static_cast(p); joachim99@92: MergeFileInfos* pMFI = pDMI->m_pMFI; joachim99@92: bool bDir = pMFI->m_bDirA || pMFI->m_bDirB || pMFI->m_bDirC; joachim99@92: if ( loop==0 && bDir ) joachim99@92: { joachim99@92: bool bChange = false; joachim99@92: if ( !pMFI->m_bEqualAB ){ pMFI->m_bEqualAB = true; bChange=true; } joachim99@92: if ( !pMFI->m_bEqualBC ){ pMFI->m_bEqualBC = true; bChange=true; } joachim99@92: if ( !pMFI->m_bEqualAC ){ pMFI->m_bEqualAC = true; bChange=true; } joachim99@92: joachim99@92: if ( bChange ) joachim99@92: setPixmaps( *pMFI, bThreeDirs ); joachim99@92: } joachim99@92: bool bExistsEverywhere = pMFI->m_bExistsInA && pMFI->m_bExistsInB && (pMFI->m_bExistsInC || !bThreeDirs); joachim99@92: int existCount = int(pMFI->m_bExistsInA) + int(pMFI->m_bExistsInB) + int(pMFI->m_bExistsInC); joachim99@92: bool bVisible = joachim99@92: ( bShowIdentical && bExistsEverywhere && pMFI->m_bEqualAB && (pMFI->m_bEqualAC || !bThreeDirs) ) joachim99@92: || ( (bShowDifferent||bDir) && existCount>=2 && (!pMFI->m_bEqualAB || !(pMFI->m_bEqualAC || !bThreeDirs))) joachim99@92: || ( bShowOnlyInA && pMFI->m_bExistsInA && !pMFI->m_bExistsInB && !pMFI->m_bExistsInC ) joachim99@92: || ( bShowOnlyInB && !pMFI->m_bExistsInA && pMFI->m_bExistsInB && !pMFI->m_bExistsInC ) joachim99@92: || ( bShowOnlyInC && !pMFI->m_bExistsInA && !pMFI->m_bExistsInB && pMFI->m_bExistsInC ); joachim99@92: joachim99@92: QString fileName = pMFI->m_subPath.section( '/', -1 ); joachim99@92: bVisible = bVisible && ( joachim99@92: (bDir && ! wildcardMultiMatch( m_pOptions->m_DmDirAntiPattern, fileName, m_bCaseSensitive )) joachim99@92: || (wildcardMultiMatch( m_pOptions->m_DmFilePattern, fileName, m_bCaseSensitive ) joachim99@92: && !wildcardMultiMatch( m_pOptions->m_DmFileAntiPattern, fileName, m_bCaseSensitive )) ); joachim99@92: joachim99@92: p->setHidden(!bVisible); joachim99@92: joachim99@92: bool bEqual = bThreeDirs ? pMFI->m_bEqualAB && pMFI->m_bEqualAC : pMFI->m_bEqualAB; joachim99@92: if ( !bEqual && bVisible && loop==0 ) // Set all parents to "not equal" joachim99@92: { joachim99@92: MergeFileInfos* p2 = pMFI->m_pParent; joachim99@92: while(p2!=0) joachim99@92: { joachim99@92: bool bChange = false; joachim99@92: if ( !pMFI->m_bEqualAB && p2->m_bEqualAB ){ p2->m_bEqualAB = false; bChange=true; } joachim99@92: if ( !pMFI->m_bEqualAC && p2->m_bEqualAC ){ p2->m_bEqualAC = false; bChange=true; } joachim99@92: if ( !pMFI->m_bEqualBC && p2->m_bEqualBC ){ p2->m_bEqualBC = false; bChange=true; } joachim99@92: joachim99@92: if ( bChange ) joachim99@92: setPixmaps( *p2, bThreeDirs ); joachim99@92: else joachim99@92: break; joachim99@92: joachim99@92: p2 = p2->m_pParent; joachim99@92: } joachim99@92: } joachim99@92: p = treeIterator( p, true, true ); joachim99@92: } joachim99@69: } joachim99@69: } joachim99@69: joachim99@69: void DirectoryMergeWindow::slotShowIdenticalFiles() { m_pOptions->m_bDmShowIdenticalFiles=m_pDirShowIdenticalFiles->isChecked(); joachim99@69: updateFileVisibilities(); } joachim99@69: void DirectoryMergeWindow::slotShowDifferentFiles() { updateFileVisibilities(); } joachim99@69: void DirectoryMergeWindow::slotShowFilesOnlyInA() { updateFileVisibilities(); } joachim99@69: void DirectoryMergeWindow::slotShowFilesOnlyInB() { updateFileVisibilities(); } joachim99@69: void DirectoryMergeWindow::slotShowFilesOnlyInC() { updateFileVisibilities(); } joachim99@69: joachim99@69: void DirectoryMergeWindow::slotSynchronizeDirectories() { } joachim99@69: void DirectoryMergeWindow::slotChooseNewerFiles() { } joachim99@51: joachim99@51: void DirectoryMergeWindow::initDirectoryMergeActions( QObject* pKDiff3App, KActionCollection* ac ) joachim99@51: { joachim99@51: #include "xpm/startmerge.xpm" joachim99@69: #include "xpm/showequalfiles.xpm" joachim99@69: #include "xpm/showfilesonlyina.xpm" joachim99@69: #include "xpm/showfilesonlyinb.xpm" joachim99@69: #include "xpm/showfilesonlyinc.xpm" joachim99@51: DirectoryMergeWindow* p = this; joachim99@51: joachim99@80: m_pDirStartOperation = KDiff3::createAction< KAction >(i18n("Start/Continue Directory Merge"), KShortcut( Qt::Key_F7 ), p, SLOT(slotRunOperationForAllItems()), ac, "dir_start_operation"); joachim99@80: m_pDirRunOperationForCurrentItem = KDiff3::createAction< KAction >(i18n("Run Operation for Current Item"), KShortcut( Qt::Key_F6 ), p, SLOT(slotRunOperationForCurrentItem()), ac, "dir_run_operation_for_current_item"); joachim99@80: m_pDirCompareCurrent = KDiff3::createAction< KAction >(i18n("Compare Selected File"), p, SLOT(compareCurrentFile()), ac, "dir_compare_current"); joachim99@80: m_pDirMergeCurrent = KDiff3::createAction< KAction >(i18n("Merge Current File"), QIcon(QPixmap(startmerge)), i18n("Merge\nFile"), pKDiff3App, SLOT(slotMergeCurrentFile()), ac, "merge_current"); joachim99@80: m_pDirFoldAll = KDiff3::createAction< KAction >(i18n("Fold All Subdirs"), p, SLOT(slotFoldAllSubdirs()), ac, "dir_fold_all"); joachim99@80: m_pDirUnfoldAll = KDiff3::createAction< KAction >(i18n("Unfold All Subdirs"), p, SLOT(slotUnfoldAllSubdirs()), ac, "dir_unfold_all"); joachim99@80: m_pDirRescan = KDiff3::createAction< KAction >(i18n("Rescan"), KShortcut( Qt::SHIFT+Qt::Key_F5 ), p, SLOT(reload()), ac, "dir_rescan"); joachim99@80: m_pDirSaveMergeState = 0; //KDiff3::createAction< KAction >(i18n("Save Directory Merge State ..."), 0, p, SLOT(slotSaveMergeState()), ac, "dir_save_merge_state"); joachim99@80: m_pDirLoadMergeState = 0; //KDiff3::createAction< KAction >(i18n("Load Directory Merge State ..."), 0, p, SLOT(slotLoadMergeState()), ac, "dir_load_merge_state"); joachim99@80: m_pDirChooseAEverywhere = KDiff3::createAction< KAction >(i18n("Choose A for All Items"), p, SLOT(slotChooseAEverywhere()), ac, "dir_choose_a_everywhere"); joachim99@80: m_pDirChooseBEverywhere = KDiff3::createAction< KAction >(i18n("Choose B for All Items"), p, SLOT(slotChooseBEverywhere()), ac, "dir_choose_b_everywhere"); joachim99@80: m_pDirChooseCEverywhere = KDiff3::createAction< KAction >(i18n("Choose C for All Items"), p, SLOT(slotChooseCEverywhere()), ac, "dir_choose_c_everywhere"); joachim99@80: m_pDirAutoChoiceEverywhere = KDiff3::createAction< KAction >(i18n("Auto-Choose Operation for All Items"), p, SLOT(slotAutoChooseEverywhere()), ac, "dir_autochoose_everywhere"); joachim99@80: m_pDirDoNothingEverywhere = KDiff3::createAction< KAction >(i18n("No Operation for All Items"), p, SLOT(slotNoOpEverywhere()), ac, "dir_nothing_everywhere"); joachim99@80: joachim99@80: // m_pDirSynchronizeDirectories = KDiff3::createAction< KToggleAction >(i18n("Synchronize Directories"), 0, this, SLOT(slotSynchronizeDirectories()), ac, "dir_synchronize_directories"); joachim99@80: // m_pDirChooseNewerFiles = KDiff3::createAction< KToggleAction >(i18n("Copy Newer Files Instead of Merging"), 0, this, SLOT(slotChooseNewerFiles()), ac, "dir_choose_newer_files"); joachim99@80: joachim99@80: m_pDirShowIdenticalFiles = KDiff3::createAction< KToggleAction >(i18n("Show Identical Files"), QIcon(QPixmap(showequalfiles)), i18n("Identical\nFiles"), this, SLOT(slotShowIdenticalFiles()), ac, "dir_show_identical_files"); joachim99@80: m_pDirShowDifferentFiles = KDiff3::createAction< KToggleAction >(i18n("Show Different Files"), this, SLOT(slotShowDifferentFiles()), ac, "dir_show_different_files"); joachim99@80: m_pDirShowFilesOnlyInA = KDiff3::createAction< KToggleAction >(i18n("Show Files only in A"), QIcon(QPixmap(showfilesonlyina)), i18n("Files\nonly in A"), this, SLOT(slotShowFilesOnlyInA()), ac, "dir_show_files_only_in_a"); joachim99@80: m_pDirShowFilesOnlyInB = KDiff3::createAction< KToggleAction >(i18n("Show Files only in B"), QIcon(QPixmap(showfilesonlyinb)), i18n("Files\nonly in B"), this, SLOT(slotShowFilesOnlyInB()), ac, "dir_show_files_only_in_b"); joachim99@80: m_pDirShowFilesOnlyInC = KDiff3::createAction< KToggleAction >(i18n("Show Files only in C"), QIcon(QPixmap(showfilesonlyinc)), i18n("Files\nonly in C"), this, SLOT(slotShowFilesOnlyInC()), ac, "dir_show_files_only_in_c"); joachim99@69: joachim99@69: m_pDirShowIdenticalFiles->setChecked( m_pOptions->m_bDmShowIdenticalFiles ); joachim99@69: joachim99@80: m_pDirCompareExplicit = KDiff3::createAction< KAction >(i18n("Compare Explicitly Selected Files"), p, SLOT(slotCompareExplicitlySelectedFiles()), ac, "dir_compare_explicitly_selected_files"); joachim99@80: m_pDirMergeExplicit = KDiff3::createAction< KAction >(i18n("Merge Explicitly Selected Files"), p, SLOT(slotMergeExplicitlySelectedFiles()), ac, "dir_merge_explicitly_selected_files"); joachim99@80: joachim99@80: m_pDirCurrentDoNothing = KDiff3::createAction< KAction >(i18n("Do Nothing"), p, SLOT(slotCurrentDoNothing()), ac, "dir_current_do_nothing"); joachim99@80: m_pDirCurrentChooseA = KDiff3::createAction< KAction >(i18n("A"), p, SLOT(slotCurrentChooseA()), ac, "dir_current_choose_a"); joachim99@80: m_pDirCurrentChooseB = KDiff3::createAction< KAction >(i18n("B"), p, SLOT(slotCurrentChooseB()), ac, "dir_current_choose_b"); joachim99@80: m_pDirCurrentChooseC = KDiff3::createAction< KAction >(i18n("C"), p, SLOT(slotCurrentChooseC()), ac, "dir_current_choose_c"); joachim99@80: m_pDirCurrentMerge = KDiff3::createAction< KAction >(i18n("Merge"), p, SLOT(slotCurrentMerge()), ac, "dir_current_merge"); joachim99@80: m_pDirCurrentDelete = KDiff3::createAction< KAction >(i18n("Delete (if exists)"), p, SLOT(slotCurrentDelete()), ac, "dir_current_delete"); joachim99@80: joachim99@80: m_pDirCurrentSyncDoNothing = KDiff3::createAction< KAction >(i18n("Do Nothing"), p, SLOT(slotCurrentDoNothing()), ac, "dir_current_sync_do_nothing"); joachim99@80: m_pDirCurrentSyncCopyAToB = KDiff3::createAction< KAction >(i18n("Copy A to B"), p, SLOT(slotCurrentCopyAToB()), ac, "dir_current_sync_copy_a_to_b" ); joachim99@80: m_pDirCurrentSyncCopyBToA = KDiff3::createAction< KAction >(i18n("Copy B to A"), p, SLOT(slotCurrentCopyBToA()), ac, "dir_current_sync_copy_b_to_a" ); joachim99@80: m_pDirCurrentSyncDeleteA = KDiff3::createAction< KAction >(i18n("Delete A"), p, SLOT(slotCurrentDeleteA()), ac,"dir_current_sync_delete_a"); joachim99@80: m_pDirCurrentSyncDeleteB = KDiff3::createAction< KAction >(i18n("Delete B"), p, SLOT(slotCurrentDeleteB()), ac,"dir_current_sync_delete_b"); joachim99@80: m_pDirCurrentSyncDeleteAAndB = KDiff3::createAction< KAction >(i18n("Delete A && B"), p, SLOT(slotCurrentDeleteAAndB()), ac,"dir_current_sync_delete_a_and_b"); joachim99@80: m_pDirCurrentSyncMergeToA = KDiff3::createAction< KAction >(i18n("Merge to A"), p, SLOT(slotCurrentMergeToA()), ac,"dir_current_sync_merge_to_a"); joachim99@80: m_pDirCurrentSyncMergeToB = KDiff3::createAction< KAction >(i18n("Merge to B"), p, SLOT(slotCurrentMergeToB()), ac,"dir_current_sync_merge_to_b"); joachim99@80: m_pDirCurrentSyncMergeToAAndB = KDiff3::createAction< KAction >(i18n("Merge to A && B"), p, SLOT(slotCurrentMergeToAAndB()), ac,"dir_current_sync_merge_to_a_and_b"); joachim99@51: } joachim99@51: joachim99@51: joachim99@53: void DirectoryMergeWindow::updateAvailabilities( bool bDirCompare, bool bDiffWindowVisible, joachim99@53: KToggleAction* chooseA, KToggleAction* chooseB, KToggleAction* chooseC ) joachim99@51: { joachim99@69: m_pDirStartOperation->setEnabled( bDirCompare ); joachim99@69: m_pDirRunOperationForCurrentItem->setEnabled( bDirCompare ); joachim99@69: m_pDirFoldAll->setEnabled( bDirCompare ); joachim99@69: m_pDirUnfoldAll->setEnabled( bDirCompare ); joachim99@69: joachim99@69: m_pDirCompareCurrent->setEnabled( bDirCompare && isVisible() && isFileSelected() ); joachim99@69: joachim99@80: m_pDirMergeCurrent->setEnabled( (bDirCompare && isVisible() && isFileSelected()) joachim99@51: || bDiffWindowVisible ); joachim99@51: joachim99@69: m_pDirRescan->setEnabled( bDirCompare ); joachim99@69: joachim99@69: m_pDirAutoChoiceEverywhere->setEnabled( bDirCompare && isVisible() ); joachim99@69: m_pDirDoNothingEverywhere->setEnabled( bDirCompare && isVisible() ); joachim99@69: m_pDirChooseAEverywhere->setEnabled( bDirCompare && isVisible() ); joachim99@69: m_pDirChooseBEverywhere->setEnabled( bDirCompare && isVisible() ); joachim99@69: m_pDirChooseCEverywhere->setEnabled( bDirCompare && isVisible() ); joachim99@51: joachim99@51: bool bThreeDirs = m_dirC.isValid(); joachim99@51: joachim99@75: QTreeWidgetItem* lvi = currentItem(); joachim99@51: DirMergeItem* pDMI = lvi==0 ? 0 : static_cast(lvi); joachim99@51: MergeFileInfos* pMFI = pDMI==0 ? 0 : pDMI->m_pMFI; joachim99@51: joachim99@51: bool bItemActive = bDirCompare && isVisible() && pMFI!=0;// && hasFocus(); joachim99@51: bool bMergeMode = bThreeDirs || !m_bSyncMode; joachim99@51: bool bFTConflict = pMFI==0 ? false : conflictingFileTypes(*pMFI); joachim99@51: joachim99@53: bool bDirWindowHasFocus = isVisible() && hasFocus(); joachim99@68: joachim99@69: m_pDirShowIdenticalFiles->setEnabled( bDirCompare && isVisible() ); joachim99@69: m_pDirShowDifferentFiles->setEnabled( bDirCompare && isVisible() ); joachim99@69: m_pDirShowFilesOnlyInA->setEnabled( bDirCompare && isVisible() ); joachim99@69: m_pDirShowFilesOnlyInB->setEnabled( bDirCompare && isVisible() ); joachim99@69: m_pDirShowFilesOnlyInC->setEnabled( bDirCompare && isVisible() && bThreeDirs ); joachim99@69: joachim99@69: m_pDirCompareExplicit->setEnabled( bDirCompare && isVisible() && m_pSelection2Item!=0 ); joachim99@69: m_pDirMergeExplicit->setEnabled( bDirCompare && isVisible() && m_pSelection2Item!=0 ); joachim99@69: joachim99@69: m_pDirCurrentDoNothing->setEnabled( bItemActive && bMergeMode ); joachim99@69: m_pDirCurrentChooseA->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInA ); joachim99@69: m_pDirCurrentChooseB->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInB ); joachim99@69: m_pDirCurrentChooseC->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInC ); joachim99@69: m_pDirCurrentMerge->setEnabled( bItemActive && bMergeMode && !bFTConflict ); joachim99@69: m_pDirCurrentDelete->setEnabled( bItemActive && bMergeMode ); joachim99@53: if ( bDirWindowHasFocus ) joachim99@53: { joachim99@53: chooseA->setEnabled( bItemActive && pMFI->m_bExistsInA ); joachim99@53: chooseB->setEnabled( bItemActive && pMFI->m_bExistsInB ); joachim99@53: chooseC->setEnabled( bItemActive && pMFI->m_bExistsInC ); joachim99@53: chooseA->setChecked( false ); joachim99@53: chooseB->setChecked( false ); joachim99@53: chooseC->setChecked( false ); joachim99@53: } joachim99@68: joachim99@69: m_pDirCurrentSyncDoNothing->setEnabled( bItemActive && !bMergeMode ); joachim99@69: m_pDirCurrentSyncCopyAToB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA ); joachim99@69: m_pDirCurrentSyncCopyBToA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB ); joachim99@69: m_pDirCurrentSyncDeleteA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA ); joachim99@69: m_pDirCurrentSyncDeleteB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB ); joachim99@69: m_pDirCurrentSyncDeleteAAndB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB && pMFI->m_bExistsInB ); joachim99@69: m_pDirCurrentSyncMergeToA->setEnabled( bItemActive && !bMergeMode && !bFTConflict ); joachim99@69: m_pDirCurrentSyncMergeToB->setEnabled( bItemActive && !bMergeMode && !bFTConflict ); joachim99@69: m_pDirCurrentSyncMergeToAAndB->setEnabled( bItemActive && !bMergeMode && !bFTConflict ); joachim99@51: } joachim99@51: joachim99@51: joachim99@70: //#include "directorymergewindow.moc"