Mercurial > hg > easyhg-kdiff3
comparison kdiff3/src-QT4/directorymergewindow.cpp @ 75:08ea9b86c12c
KDiff3-0.9.91
author | joachim99 |
---|---|
date | Sat, 04 Nov 2006 00:05:00 +0000 |
parents | kdiff3/src/directorymergewindow.cpp@f7dad0aa6146 |
children | 1184fc843210 |
comparison
equal
deleted
inserted
replaced
74:069521efec1a | 75:08ea9b86c12c |
---|---|
1 /*************************************************************************** | |
2 directorymergewindow.cpp | |
3 ----------------- | |
4 begin : Sat Oct 19 2002 | |
5 copyright : (C) 2002-2005 by Joachim Eibl | |
6 email : joachim.eibl at gmx.de | |
7 ***************************************************************************/ | |
8 | |
9 /*************************************************************************** | |
10 * * | |
11 * This program is free software; you can redistribute it and/or modify * | |
12 * it under the terms of the GNU General Public License as published by * | |
13 * the Free Software Foundation; either version 2 of the License, or * | |
14 * (at your option) any later version. * | |
15 * * | |
16 ***************************************************************************/ | |
17 | |
18 #include "directorymergewindow.h" | |
19 #include "optiondialog.h" | |
20 #include <vector> | |
21 #include <map> | |
22 | |
23 #include <QDir> | |
24 #include <QApplication> | |
25 #include <QPixmap> | |
26 #include <QImage> | |
27 #include <QTextStream> | |
28 #include <QKeyEvent> | |
29 #include <QMenu> | |
30 #include <QRegExp> | |
31 #include <QMessageBox> | |
32 #include <QLayout> | |
33 #include <QLabel> | |
34 #include <QSplitter> | |
35 #include <QTextEdit> | |
36 #include <QItemDelegate> | |
37 | |
38 | |
39 #include <kpopupmenu.h> | |
40 #include <kaction.h> | |
41 #include <kmessagebox.h> | |
42 #include <kfiledialog.h> | |
43 #include <kiconloader.h> | |
44 #include <klocale.h> | |
45 | |
46 #include <iostream> | |
47 #include <assert.h> | |
48 //#include <konq_popupmenu.h> | |
49 | |
50 static bool conflictingFileTypes(MergeFileInfos& mfi); | |
51 /* | |
52 class StatusInfo : public QListView | |
53 { | |
54 public: | |
55 StatusInfo(QWidget* pParent) : QListView( pParent, "StatusInfo", Qt::WShowModal ) | |
56 { | |
57 addColumn(""); | |
58 setSorting(-1); //disable sorting | |
59 } | |
60 | |
61 QListViewItem* m_pLast; | |
62 QListViewItem* last() | |
63 { | |
64 if (firstChild()==0) return 0; | |
65 else return m_pLast; | |
66 } | |
67 | |
68 void addText(const QString& s ) | |
69 { | |
70 if (firstChild()==0) m_pLast = new QListViewItem( this, s ); | |
71 else m_pLast = new QListViewItem( this, last(), s ); | |
72 } | |
73 }; | |
74 */ | |
75 class StatusInfo : public QTextEdit | |
76 { | |
77 public: | |
78 StatusInfo(QWidget* pParent) : QTextEdit( pParent ) | |
79 { | |
80 setObjectName("StatusInfo"); | |
81 setWindowFlags(Qt::Dialog); | |
82 setWordWrapMode(QTextOption::NoWrap); | |
83 setReadOnly(true); | |
84 showMaximized(); | |
85 } | |
86 | |
87 bool isEmpty(){ | |
88 return toPlainText().isEmpty(); } | |
89 | |
90 void addText(const QString& s ) | |
91 { | |
92 append(s); | |
93 } | |
94 | |
95 void show() | |
96 { | |
97 moveCursor ( QTextCursor::End ); | |
98 ensureCursorVisible(); | |
99 | |
100 QTextEdit::show(); | |
101 } | |
102 }; | |
103 | |
104 | |
105 class TempRemover | |
106 { | |
107 public: | |
108 TempRemover( const QString& origName, FileAccess& fa ); | |
109 ~TempRemover(); | |
110 QString name() { return m_name; } | |
111 bool success() { return m_bSuccess; } | |
112 private: | |
113 QString m_name; | |
114 bool m_bTemp; | |
115 bool m_bSuccess; | |
116 }; | |
117 TempRemover::TempRemover(const QString& origName, FileAccess& fa) | |
118 { | |
119 if ( fa.isLocal() ) | |
120 { | |
121 m_name = origName; | |
122 m_bTemp = false; | |
123 m_bSuccess = true; | |
124 } | |
125 else | |
126 { | |
127 m_name = FileAccess::tempFileName(); | |
128 m_bSuccess = fa.copyFile( m_name ); | |
129 m_bTemp = m_bSuccess; | |
130 } | |
131 } | |
132 TempRemover::~TempRemover() | |
133 { | |
134 if ( m_bTemp && ! m_name.isEmpty() ) | |
135 FileAccess::removeTempFile(m_name); | |
136 } | |
137 | |
138 void DirectoryMergeWindow::fastFileComparison( | |
139 FileAccess& fi1, FileAccess& fi2, | |
140 bool& bEqual, bool& bError, QString& status ) | |
141 { | |
142 ProgressProxy pp; | |
143 status = ""; | |
144 bEqual = false; | |
145 bError = true; | |
146 | |
147 if ( !m_bFollowFileLinks ) | |
148 { | |
149 if ( fi1.isSymLink() != fi2.isSymLink() ) | |
150 { | |
151 status = i18n("Mix of links and normal files."); | |
152 return; | |
153 } | |
154 else if ( fi1.isSymLink() && fi2.isSymLink() ) | |
155 { | |
156 bError = false; | |
157 bEqual = fi1.readLink() == fi2.readLink(); | |
158 status = i18n("Link: "); | |
159 return; | |
160 } | |
161 } | |
162 | |
163 if ( fi1.size()!=fi2.size() ) | |
164 { | |
165 bEqual = false; | |
166 status = i18n("Size. "); | |
167 return; | |
168 } | |
169 else if ( m_pOptions->m_bDmTrustSize ) | |
170 { | |
171 bEqual = true; | |
172 return; | |
173 } | |
174 | |
175 if ( m_pOptions->m_bDmTrustDate ) | |
176 { | |
177 bEqual = ( fi1.lastModified() == fi2.lastModified() && fi1.size()==fi2.size() ); | |
178 bError = false; | |
179 status = i18n("Date & Size: "); | |
180 return; | |
181 } | |
182 | |
183 QString fileName1 = fi1.absFilePath(); | |
184 QString fileName2 = fi2.absFilePath(); | |
185 TempRemover tr1( fileName1, fi1 ); | |
186 if ( !tr1.success() ) | |
187 { | |
188 status = i18n("Creating temp copy of %1 failed.").arg(fileName1); | |
189 return; | |
190 } | |
191 TempRemover tr2( fileName2, fi2 ); | |
192 if ( !tr2.success() ) | |
193 { | |
194 status = i18n("Creating temp copy of %1 failed.").arg(fileName2); | |
195 return; | |
196 } | |
197 | |
198 std::vector<char> buf1(100000); | |
199 std::vector<char> buf2(buf1.size()); | |
200 | |
201 QFile file1( tr1.name() ); | |
202 | |
203 if ( ! file1.open(QIODevice::ReadOnly) ) | |
204 { | |
205 status = i18n("Opening %1 failed.").arg(fileName1); | |
206 return; | |
207 } | |
208 | |
209 QFile file2( tr2.name() ); | |
210 | |
211 if ( ! file2.open(QIODevice::ReadOnly) ) | |
212 { | |
213 status = i18n("Opening %1 failed.").arg(fileName2); | |
214 return; | |
215 } | |
216 | |
217 pp.setInformation( i18n("Comparing file..."), 0, false ); | |
218 typedef qint64 t_FileSize; | |
219 t_FileSize fullSize = file1.size(); | |
220 t_FileSize sizeLeft = fullSize; | |
221 | |
222 while( sizeLeft>0 && ! pp.wasCancelled() ) | |
223 { | |
224 int len = min2( sizeLeft, (t_FileSize)buf1.size() ); | |
225 if( len != file1.read( &buf1[0], len ) ) | |
226 { | |
227 status = i18n("Error reading from %1").arg(fileName1); | |
228 return; | |
229 } | |
230 | |
231 if( len != file2.read( &buf2[0], len ) ) | |
232 { | |
233 status = i18n("Error reading from %1").arg(fileName2); | |
234 return; | |
235 } | |
236 | |
237 if ( memcmp( &buf1[0], &buf2[0], len ) != 0 ) | |
238 { | |
239 bError = false; | |
240 return; | |
241 } | |
242 sizeLeft-=len; | |
243 pp.setCurrent(double(fullSize-sizeLeft)/fullSize, false ); | |
244 } | |
245 | |
246 // If the program really arrives here, then the files are really equal. | |
247 bError = false; | |
248 bEqual = true; | |
249 } | |
250 | |
251 static int s_NameCol = 0; | |
252 static int s_ACol = 1; | |
253 static int s_BCol = 2; | |
254 static int s_CCol = 3; | |
255 static int s_OpCol = 4; | |
256 static int s_OpStatusCol = 5; | |
257 static int s_UnsolvedCol = 6; // Nr of unsolved conflicts (for 3 input files) | |
258 static int s_SolvedCol = 7; // Nr of auto-solvable conflicts (for 3 input files) | |
259 static int s_NonWhiteCol = 8; // Nr of nonwhite deltas (for 2 input files) | |
260 static int s_WhiteCol = 9; // Nr of white deltas (for 2 input files) | |
261 | |
262 // Previously Q3ListViewItem::paintCell(p,cg,column,width,align); | |
263 class DirectoryMergeWindow::DirMergeItemDelegate : public QItemDelegate | |
264 { | |
265 DirectoryMergeWindow* m_pDMW; | |
266 public: | |
267 DirMergeItemDelegate(DirectoryMergeWindow* pParent) | |
268 : QItemDelegate(pParent), m_pDMW(pParent) | |
269 { | |
270 } | |
271 void paint( QPainter * p, const QStyleOptionViewItem & option, const QModelIndex & index ) const | |
272 { | |
273 int column = index.column(); | |
274 if (column == s_ACol || column == s_BCol || column == s_CCol ) | |
275 { | |
276 QVariant value = index.data( Qt::DecorationRole ); | |
277 QPixmap icon; | |
278 if ( value.isValid() ) | |
279 { | |
280 if (value.type() == QVariant::Icon) | |
281 { | |
282 icon = qvariant_cast<QIcon>(value).pixmap(16,16); | |
283 //icon = qvariant_cast<QIcon>(value); | |
284 //decorationRect = QRect(QPoint(0, 0), icon.actualSize(option.decorationSize, iconMode, iconState)); | |
285 } | |
286 else | |
287 { | |
288 icon = qvariant_cast<QPixmap>(value); | |
289 //decorationRect = QRect(QPoint(0, 0), option.decorationSize).intersected(pixmap.rect()); | |
290 } | |
291 } | |
292 | |
293 int x = option.rect.left(); | |
294 int y = option.rect.top(); | |
295 //QPixmap icon = value.value<QPixmap>(); //pixmap(column); | |
296 if ( !icon.isNull() ) | |
297 { | |
298 int yOffset = (sizeHint(option,index).height() - icon.height()) / 2; | |
299 p->drawPixmap( x+2, y+yOffset, icon ); | |
300 | |
301 QTreeWidgetItem* pTWI = reinterpret_cast<QTreeWidgetItem*>( index.internalPointer() ); | |
302 DirMergeItem* pDMI = static_cast<DirMergeItem*>(pTWI); | |
303 int i = pDMI==m_pDMW->m_pSelection1Item && column == m_pDMW->m_selection1Column ? 1 : | |
304 pDMI==m_pDMW->m_pSelection2Item && column == m_pDMW->m_selection2Column ? 2 : | |
305 pDMI==m_pDMW->m_pSelection3Item && column == m_pDMW->m_selection3Column ? 3 : | |
306 0; | |
307 if ( i!=0 ) | |
308 { | |
309 OptionDialog* pOD = m_pDMW->m_pOptions; | |
310 QColor c ( i==1 ? pOD->m_colorA : i==2 ? pOD->m_colorB : pOD->m_colorC ); | |
311 p->setPen( c );// highlight() ); | |
312 p->drawRect( x+2, y+yOffset, icon.width(), icon.height()); | |
313 p->setPen( QPen( c, 0, Qt::DotLine) ); | |
314 p->drawRect( x+1, y+yOffset-1, icon.width()+2, icon.height()+2); | |
315 p->setPen( Qt::white ); | |
316 QString s( QChar('A'+i-1) ); | |
317 p->drawText( x+2 + (icon.width() - p->fontMetrics().width(s))/2, | |
318 y+yOffset + (icon.height() + p->fontMetrics().ascent())/2-1, | |
319 s ); | |
320 } | |
321 else | |
322 { | |
323 p->setPen( m_pDMW->palette().background().color() ); | |
324 p->drawRect( x+1, y+yOffset-1, icon.width()+2, icon.height()+2); | |
325 } | |
326 return; | |
327 } | |
328 } | |
329 QStyleOptionViewItem option2 = option; | |
330 if ( column>=s_UnsolvedCol ) | |
331 { | |
332 option2.displayAlignment = Qt::AlignRight; | |
333 } | |
334 QItemDelegate::paint( p, option2, index ); | |
335 } | |
336 }; | |
337 | |
338 | |
339 DirectoryMergeWindow::DirectoryMergeWindow( QWidget* pParent, OptionDialog* pOptions, KIconLoader* pIconLoader ) | |
340 : QTreeWidget( pParent ) | |
341 { | |
342 setItemDelegate( new DirMergeItemDelegate(this) ); | |
343 connect( this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(onDoubleClick(QTreeWidgetItem*))); | |
344 connect( this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(onCurrentChanged(QTreeWidgetItem*))); | |
345 connect( this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(onExpanded())); | |
346 m_pOptions = pOptions; | |
347 m_pIconLoader = pIconLoader; | |
348 m_pDirectoryMergeInfo = 0; | |
349 m_bAllowResizeEvents = true; | |
350 m_bSimulatedMergeStarted=false; | |
351 m_bRealMergeStarted=false; | |
352 m_bError = false; | |
353 m_bSyncMode = false; | |
354 m_pStatusInfo = new StatusInfo(0); | |
355 m_pStatusInfo->hide(); | |
356 m_bScanning = false; | |
357 m_pSelection1Item = 0; | |
358 m_pSelection2Item = 0; | |
359 m_pSelection3Item = 0; | |
360 m_bCaseSensitive = true; | |
361 | |
362 QStringList sl; | |
363 sl << i18n("Name") << "A" << "B" << "C" << i18n("Operation") << i18n("Status") | |
364 << i18n("Unsolved") << i18n("Solved") << i18n("Nonwhite") << i18n("White") << ""; | |
365 setHeaderLabels(sl); | |
366 | |
367 //TODO setColumnAlignment( s_UnsolvedCol, Qt::AlignRight ); | |
368 //setColumnAlignment( s_SolvedCol, Qt::AlignRight ); | |
369 //setColumnAlignment( s_NonWhiteCol, Qt::AlignRight ); | |
370 //setColumnAlignment( s_WhiteCol, Qt::AlignRight ); | |
371 } | |
372 | |
373 DirectoryMergeWindow::~DirectoryMergeWindow() | |
374 { | |
375 } | |
376 | |
377 | |
378 int DirectoryMergeWindow::totalColumnWidth() | |
379 { | |
380 int w=0; | |
381 for (int i=0; i<s_OpStatusCol; ++i) | |
382 { | |
383 w += columnWidth(i); | |
384 } | |
385 return w; | |
386 } | |
387 | |
388 void DirectoryMergeWindow::reload() | |
389 { | |
390 if ( isDirectoryMergeInProgress() ) | |
391 { | |
392 int result = KMessageBox::warningYesNo(this, | |
393 i18n("You are currently doing a directory merge. Are you sure, you want to abort the merge and rescan the directory?"), | |
394 i18n("Warning"), i18n("Rescan"), i18n("Continue Merging") ); | |
395 if ( result!=KMessageBox::Yes ) | |
396 return; | |
397 } | |
398 | |
399 init( m_dirA, m_dirB, m_dirC, m_dirDest, m_bDirectoryMerge ); | |
400 } | |
401 | |
402 // Copy pm2 onto pm1, but preserve the alpha value from pm1 where pm2 is transparent. | |
403 static QPixmap pixCombiner( const QPixmap* pm1, const QPixmap* pm2 ) | |
404 { | |
405 QImage img1 = pm1->toImage().convertToFormat(QImage::Format_ARGB32); | |
406 QImage img2 = pm2->toImage().convertToFormat(QImage::Format_ARGB32); | |
407 | |
408 for (int y = 0; y < img1.height(); y++) | |
409 { | |
410 quint32 *line1 = reinterpret_cast<quint32 *>(img1.scanLine(y)); | |
411 quint32 *line2 = reinterpret_cast<quint32 *>(img2.scanLine(y)); | |
412 for (int x = 0; x < img1.width(); x++) | |
413 { | |
414 if ( qAlpha( line2[x] ) >0 ) | |
415 line1[x] = (line2[x] | 0xff000000); | |
416 } | |
417 } | |
418 return QPixmap::fromImage(img1); | |
419 } | |
420 | |
421 // like pixCombiner but let the pm1 color shine through | |
422 static QPixmap pixCombiner2( const QPixmap* pm1, const QPixmap* pm2 ) | |
423 { | |
424 QPixmap pix=*pm1; | |
425 QPainter p(&pix); | |
426 p.setOpacity(0.5); | |
427 p.drawPixmap( 0,0,*pm2 ); | |
428 p.end(); | |
429 | |
430 return pix; | |
431 } | |
432 | |
433 static void calcDirStatus( bool bThreeDirs, DirMergeItem* i, int& nofFiles, | |
434 int& nofDirs, int& nofEqualFiles, int& nofManualMerges ) | |
435 { | |
436 if ( i->m_pMFI->m_bDirA || i->m_pMFI->m_bDirB || i->m_pMFI->m_bDirC ) | |
437 { | |
438 ++nofDirs; | |
439 } | |
440 else | |
441 { | |
442 ++nofFiles; | |
443 if ( i->m_pMFI->m_bEqualAB && (!bThreeDirs || i->m_pMFI->m_bEqualAC )) | |
444 { | |
445 ++nofEqualFiles; | |
446 } | |
447 else | |
448 { | |
449 if ( i->m_pMFI->m_eMergeOperation==eMergeABCToDest || i->m_pMFI->m_eMergeOperation==eMergeABToDest ) | |
450 ++nofManualMerges; | |
451 } | |
452 } | |
453 for( int childIdx=0; childIdx<i->childCount(); ++childIdx ) | |
454 calcDirStatus( bThreeDirs, static_cast<DirMergeItem*>(i->child(childIdx)), nofFiles, nofDirs, nofEqualFiles, nofManualMerges ); | |
455 } | |
456 | |
457 static QString sortString(const QString& s, bool bCaseSensitive) | |
458 { | |
459 if (bCaseSensitive) | |
460 return s; | |
461 else | |
462 return s.toUpper(); | |
463 } | |
464 | |
465 bool DirectoryMergeWindow::init | |
466 ( | |
467 FileAccess& dirA, | |
468 FileAccess& dirB, | |
469 FileAccess& dirC, | |
470 FileAccess& dirDest, | |
471 bool bDirectoryMerge | |
472 ) | |
473 { | |
474 if ( m_pOptions->m_bDmFullAnalysis ) | |
475 { | |
476 // A full analysis uses the same ressources that a normal text-diff/merge uses. | |
477 // So make sure that the user saves his data first. | |
478 bool bCanContinue=false; | |
479 checkIfCanContinue( &bCanContinue ); | |
480 if ( !bCanContinue ) | |
481 return false; | |
482 startDiffMerge("","","","","","","",0); // hide main window | |
483 } | |
484 | |
485 show(); | |
486 | |
487 ProgressProxy pp; | |
488 m_bFollowDirLinks = m_pOptions->m_bDmFollowDirLinks; | |
489 m_bFollowFileLinks = m_pOptions->m_bDmFollowFileLinks; | |
490 m_bSimulatedMergeStarted=false; | |
491 m_bRealMergeStarted=false; | |
492 m_bError=false; | |
493 m_bDirectoryMerge = bDirectoryMerge; | |
494 m_pSelection1Item = 0; | |
495 m_pSelection2Item = 0; | |
496 m_pSelection3Item = 0; | |
497 m_bCaseSensitive = m_pOptions->m_bDmCaseSensitiveFilenameComparison; | |
498 | |
499 clear(); | |
500 | |
501 m_mergeItemList.clear(); | |
502 m_currentItemForOperation = m_mergeItemList.end(); | |
503 | |
504 m_dirA = dirA; | |
505 m_dirB = dirB; | |
506 m_dirC = dirC; | |
507 m_dirDest = dirDest; | |
508 | |
509 m_pDirShowIdenticalFiles->setChecked(true); | |
510 m_pDirShowDifferentFiles->setChecked(true); | |
511 m_pDirShowFilesOnlyInA->setChecked(true); | |
512 m_pDirShowFilesOnlyInB->setChecked(true); | |
513 m_pDirShowFilesOnlyInC->setChecked(true); | |
514 | |
515 // Check if all input directories exist and are valid. The dest dir is not tested now. | |
516 // The test will happen only when we are going to write to it. | |
517 if ( !m_dirA.isDir() || !m_dirB.isDir() || | |
518 (m_dirC.isValid() && !m_dirC.isDir()) ) | |
519 { | |
520 QString text( i18n("Opening of directories failed:") ); | |
521 text += "\n\n"; | |
522 if ( !dirA.isDir() ) | |
523 { text += i18n("Dir A \"%1\" does not exist or is not a directory.\n").arg(m_dirA.prettyAbsPath()); } | |
524 | |
525 if ( !dirB.isDir() ) | |
526 { text += i18n("Dir B \"%1\" does not exist or is not a directory.\n").arg(m_dirB.prettyAbsPath()); } | |
527 | |
528 if ( m_dirC.isValid() && !m_dirC.isDir() ) | |
529 { text += i18n("Dir C \"%1\" does not exist or is not a directory.\n").arg(m_dirC.prettyAbsPath()); } | |
530 | |
531 KMessageBox::sorry( this, text, i18n("Directory Open Error") ); | |
532 return false; | |
533 } | |
534 | |
535 if ( m_dirC.isValid() && | |
536 (m_dirDest.prettyAbsPath() == m_dirA.prettyAbsPath() || m_dirDest.prettyAbsPath()==m_dirB.prettyAbsPath() ) ) | |
537 { | |
538 KMessageBox::error(this, | |
539 i18n( "The destination directory must not be the same as A or B when " | |
540 "three directories are merged.\nCheck again before continuing."), | |
541 i18n("Parameter Warning")); | |
542 return false; | |
543 } | |
544 | |
545 m_bScanning = true; | |
546 statusBarMessage(i18n("Scanning directories...")); | |
547 | |
548 m_bSyncMode = m_pOptions->m_bDmSyncMode && !m_dirC.isValid() && !m_dirDest.isValid(); | |
549 | |
550 if ( m_dirDest.isValid() ) | |
551 m_dirDestInternal = m_dirDest; | |
552 else | |
553 m_dirDestInternal = m_dirC.isValid() ? m_dirC : m_dirB; | |
554 | |
555 QString origCurrentDirectory = QDir::currentPath(); | |
556 | |
557 m_fileMergeMap.clear(); | |
558 t_DirectoryList::iterator i; | |
559 | |
560 // calc how many directories will be read: | |
561 double nofScans = ( m_dirA.isValid() ? 1 : 0 )+( m_dirB.isValid() ? 1 : 0 )+( m_dirC.isValid() ? 1 : 0 ); | |
562 int currentScan = 0; | |
563 | |
564 //TODO setColumnWidthMode(s_UnsolvedCol, Q3ListView::Manual); | |
565 // setColumnWidthMode(s_SolvedCol, Q3ListView::Manual); | |
566 // setColumnWidthMode(s_WhiteCol, Q3ListView::Manual); | |
567 // setColumnWidthMode(s_NonWhiteCol, Q3ListView::Manual); | |
568 setColumnHidden( s_CCol, !m_dirC.isValid() ); | |
569 setColumnHidden( s_WhiteCol, !m_pOptions->m_bDmFullAnalysis ); | |
570 setColumnHidden( s_NonWhiteCol, !m_pOptions->m_bDmFullAnalysis ); | |
571 setColumnHidden( s_UnsolvedCol, !m_pOptions->m_bDmFullAnalysis ); | |
572 setColumnHidden( s_SolvedCol, !( m_pOptions->m_bDmFullAnalysis && m_dirC.isValid() ) ); | |
573 | |
574 bool bListDirSuccessA = true; | |
575 bool bListDirSuccessB = true; | |
576 bool bListDirSuccessC = true; | |
577 if ( m_dirA.isValid() ) | |
578 { | |
579 pp.setInformation(i18n("Reading Directory A")); | |
580 pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans); | |
581 ++currentScan; | |
582 | |
583 t_DirectoryList dirListA; | |
584 bListDirSuccessA = m_dirA.listDir( &dirListA, | |
585 m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden, | |
586 m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern, | |
587 m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks, | |
588 m_pOptions->m_bDmUseCvsIgnore); | |
589 | |
590 for (i=dirListA.begin(); i!=dirListA.end();++i ) | |
591 { | |
592 MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(), m_bCaseSensitive)]; | |
593 //std::cout <<i->filePath()<<std::endl; | |
594 mfi.m_bExistsInA = true; | |
595 mfi.m_fileInfoA = *i; | |
596 } | |
597 } | |
598 | |
599 if ( m_dirB.isValid() ) | |
600 { | |
601 pp.setInformation(i18n("Reading Directory B")); | |
602 pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans); | |
603 ++currentScan; | |
604 | |
605 t_DirectoryList dirListB; | |
606 bListDirSuccessB = m_dirB.listDir( &dirListB, | |
607 m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden, | |
608 m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern, | |
609 m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks, | |
610 m_pOptions->m_bDmUseCvsIgnore); | |
611 | |
612 for (i=dirListB.begin(); i!=dirListB.end();++i ) | |
613 { | |
614 MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(), m_bCaseSensitive)]; | |
615 mfi.m_bExistsInB = true; | |
616 mfi.m_fileInfoB = *i; | |
617 } | |
618 } | |
619 | |
620 e_MergeOperation eDefaultMergeOp; | |
621 if ( m_dirC.isValid() ) | |
622 { | |
623 pp.setInformation(i18n("Reading Directory C")); | |
624 pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans); | |
625 ++currentScan; | |
626 | |
627 t_DirectoryList dirListC; | |
628 bListDirSuccessC = m_dirC.listDir( &dirListC, | |
629 m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden, | |
630 m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern, | |
631 m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks, | |
632 m_pOptions->m_bDmUseCvsIgnore); | |
633 | |
634 for (i=dirListC.begin(); i!=dirListC.end();++i ) | |
635 { | |
636 MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(),m_bCaseSensitive)]; | |
637 mfi.m_bExistsInC = true; | |
638 mfi.m_fileInfoC = *i; | |
639 } | |
640 | |
641 eDefaultMergeOp = eMergeABCToDest; | |
642 } | |
643 else | |
644 eDefaultMergeOp = m_bSyncMode ? eMergeToAB : eMergeABToDest; | |
645 | |
646 bool bContinue = true; | |
647 if ( !bListDirSuccessA || !bListDirSuccessB || !bListDirSuccessC ) | |
648 { | |
649 QString s = i18n("Some subdirectories were not readable in"); | |
650 if ( !bListDirSuccessA ) s += "\nA: " + m_dirA.prettyAbsPath(); | |
651 if ( !bListDirSuccessB ) s += "\nB: " + m_dirB.prettyAbsPath(); | |
652 if ( !bListDirSuccessC ) s += "\nC: " + m_dirC.prettyAbsPath(); | |
653 s+="\n"; | |
654 s+= i18n("Check the permissions of the subdirectories."); | |
655 bContinue = KMessageBox::Continue == KMessageBox::warningContinueCancel( this, s ); | |
656 } | |
657 | |
658 if ( bContinue ) | |
659 { | |
660 prepareListView(pp); | |
661 | |
662 for( int childIdx = 0; childIdx<topLevelItemCount(); ++childIdx )//Q3ListViewItem* p = firstChild(); p!=0; p = p->nextSibling() ) | |
663 { | |
664 DirMergeItem* pDMI = static_cast<DirMergeItem*>( topLevelItem(childIdx) ); | |
665 calcSuggestedOperation( *pDMI->m_pMFI, eDefaultMergeOp ); | |
666 } | |
667 } | |
668 //else | |
669 //{ | |
670 // setSelected( 0, true ); | |
671 //} | |
672 | |
673 for (int i=0;i<columnCount();++i) | |
674 resizeColumnToContents(i); | |
675 | |
676 QDir::setCurrent(origCurrentDirectory); | |
677 | |
678 // Try to improve the view a little bit. | |
679 QWidget* pParent = parentWidget(); | |
680 QSplitter* pSplitter = static_cast<QSplitter*>(pParent); | |
681 if (pSplitter!=0) | |
682 { | |
683 QList<int> sizes = pSplitter->sizes(); | |
684 int total = sizes[0] + sizes[1]; | |
685 sizes[0]=total*6/10; | |
686 sizes[1]=total - sizes[0]; | |
687 pSplitter->setSizes( sizes ); | |
688 } | |
689 | |
690 sortItems(0,Qt::AscendingOrder); | |
691 | |
692 m_bScanning = false; | |
693 statusBarMessage(i18n("Ready.")); | |
694 | |
695 if ( bContinue ) | |
696 { | |
697 // Generate a status report | |
698 int nofFiles=0; | |
699 int nofDirs=0; | |
700 int nofEqualFiles=0; | |
701 int nofManualMerges=0; | |
702 for( int childIdx = 0; childIdx<topLevelItemCount(); ++childIdx ) | |
703 calcDirStatus( m_dirC.isValid(), static_cast<DirMergeItem*>(topLevelItem(childIdx)), | |
704 nofFiles, nofDirs, nofEqualFiles, nofManualMerges ); | |
705 | |
706 QString s; | |
707 s = i18n("Directory Comparison Status") + "\n\n" + | |
708 i18n("Number of subdirectories:") +" "+ QString::number(nofDirs) + "\n"+ | |
709 i18n("Number of equal files:") +" "+ QString::number(nofEqualFiles) + "\n"+ | |
710 i18n("Number of different files:") +" "+ QString::number(nofFiles-nofEqualFiles); | |
711 | |
712 if ( m_dirC.isValid() ) | |
713 s += "\n" + i18n("Number of manual merges:") +" "+ QString::number(nofManualMerges); | |
714 KMessageBox::information( this, s ); | |
715 if ( topLevelItemCount()>0 ) | |
716 topLevelItem(0)->setSelected(true); | |
717 } | |
718 | |
719 return true; | |
720 } | |
721 | |
722 void DirectoryMergeWindow::onExpanded() | |
723 { | |
724 resizeColumnToContents(s_NameCol); | |
725 } | |
726 | |
727 | |
728 void DirectoryMergeWindow::slotChooseAEverywhere(){ setAllMergeOperations( eCopyAToDest ); } | |
729 | |
730 void DirectoryMergeWindow::slotChooseBEverywhere(){ setAllMergeOperations( eCopyBToDest ); } | |
731 | |
732 void DirectoryMergeWindow::slotChooseCEverywhere(){ setAllMergeOperations( eCopyCToDest ); } | |
733 | |
734 void DirectoryMergeWindow::slotAutoChooseEverywhere() | |
735 { | |
736 e_MergeOperation eDefaultMergeOp = m_dirC.isValid() ? eMergeABCToDest : | |
737 m_bSyncMode ? eMergeToAB : eMergeABToDest; | |
738 setAllMergeOperations(eDefaultMergeOp ); | |
739 } | |
740 | |
741 void DirectoryMergeWindow::slotNoOpEverywhere(){ setAllMergeOperations(eNoOperation); } | |
742 | |
743 static void setListViewItemOpen( QTreeWidgetItem* p, bool bOpen ) | |
744 { | |
745 if ( p->childCount() > 0 ) | |
746 { | |
747 for( int childIdx=0; childIdx<p->childCount(); ++childIdx ) | |
748 setListViewItemOpen( p->child(childIdx), bOpen ); | |
749 | |
750 p->setExpanded( bOpen ); | |
751 } | |
752 } | |
753 | |
754 void DirectoryMergeWindow::slotFoldAllSubdirs() | |
755 { | |
756 for( int i=0; i<topLevelItemCount(); ++i ) | |
757 setListViewItemOpen( topLevelItem(i), false ); | |
758 } | |
759 | |
760 void DirectoryMergeWindow::slotUnfoldAllSubdirs() | |
761 { | |
762 for( int i=0; i<topLevelItemCount(); ++i ) | |
763 setListViewItemOpen( topLevelItem(i), true ); | |
764 } | |
765 | |
766 static void setMergeOperation( QTreeWidgetItem* pLVI, e_MergeOperation eMergeOp ) | |
767 { | |
768 if ( pLVI==0 ) return; | |
769 | |
770 DirMergeItem* pDMI = static_cast<DirMergeItem*>(pLVI); | |
771 MergeFileInfos& mfi = *pDMI->m_pMFI; | |
772 | |
773 mfi.setMergeOperation(eMergeOp ); | |
774 } | |
775 | |
776 // Merge current item (merge mode) | |
777 void DirectoryMergeWindow::slotCurrentDoNothing() { setMergeOperation(currentItem(), eNoOperation ); } | |
778 void DirectoryMergeWindow::slotCurrentChooseA() { setMergeOperation(currentItem(), m_bSyncMode ? eCopyAToB : eCopyAToDest ); } | |
779 void DirectoryMergeWindow::slotCurrentChooseB() { setMergeOperation(currentItem(), m_bSyncMode ? eCopyBToA : eCopyBToDest ); } | |
780 void DirectoryMergeWindow::slotCurrentChooseC() { setMergeOperation(currentItem(), eCopyCToDest ); } | |
781 void DirectoryMergeWindow::slotCurrentMerge() | |
782 { | |
783 bool bThreeDirs = m_dirC.isValid(); | |
784 setMergeOperation(currentItem(), bThreeDirs ? eMergeABCToDest : eMergeABToDest ); | |
785 } | |
786 void DirectoryMergeWindow::slotCurrentDelete() { setMergeOperation(currentItem(), eDeleteFromDest ); } | |
787 // Sync current item | |
788 void DirectoryMergeWindow::slotCurrentCopyAToB() { setMergeOperation(currentItem(), eCopyAToB ); } | |
789 void DirectoryMergeWindow::slotCurrentCopyBToA() { setMergeOperation(currentItem(), eCopyBToA ); } | |
790 void DirectoryMergeWindow::slotCurrentDeleteA() { setMergeOperation(currentItem(), eDeleteA ); } | |
791 void DirectoryMergeWindow::slotCurrentDeleteB() { setMergeOperation(currentItem(), eDeleteB ); } | |
792 void DirectoryMergeWindow::slotCurrentDeleteAAndB() { setMergeOperation(currentItem(), eDeleteAB ); } | |
793 void DirectoryMergeWindow::slotCurrentMergeToA() { setMergeOperation(currentItem(), eMergeToA ); } | |
794 void DirectoryMergeWindow::slotCurrentMergeToB() { setMergeOperation(currentItem(), eMergeToB ); } | |
795 void DirectoryMergeWindow::slotCurrentMergeToAAndB() { setMergeOperation(currentItem(), eMergeToAB ); } | |
796 | |
797 | |
798 void DirectoryMergeWindow::keyPressEvent( QKeyEvent* e ) | |
799 { | |
800 if ( (e->QInputEvent::modifiers() & Qt::ControlModifier)!=0 ) | |
801 { | |
802 bool bThreeDirs = m_dirC.isValid(); | |
803 | |
804 QTreeWidgetItem* lvi = currentItem(); | |
805 DirMergeItem* pDMI = lvi==0 ? 0 : static_cast<DirMergeItem*>(lvi); | |
806 MergeFileInfos* pMFI = pDMI==0 ? 0 : pDMI->m_pMFI; | |
807 | |
808 if ( pMFI==0 ) return; | |
809 bool bMergeMode = bThreeDirs || !m_bSyncMode; | |
810 bool bFTConflict = pMFI==0 ? false : conflictingFileTypes(*pMFI); | |
811 | |
812 if ( bMergeMode ) | |
813 { | |
814 switch(e->key()) | |
815 { | |
816 case Qt::Key_1: if(pMFI->m_bExistsInA){ slotCurrentChooseA(); } return; | |
817 case Qt::Key_2: if(pMFI->m_bExistsInB){ slotCurrentChooseB(); } return; | |
818 case Qt::Key_3: if(pMFI->m_bExistsInC){ slotCurrentChooseC(); } return; | |
819 case Qt::Key_Space: slotCurrentDoNothing(); return; | |
820 case Qt::Key_4: if ( !bFTConflict ) { slotCurrentMerge(); } return; | |
821 case Qt::Key_Delete: slotCurrentDelete(); return; | |
822 default: break; | |
823 } | |
824 } | |
825 else | |
826 { | |
827 switch(e->key()) | |
828 { | |
829 case Qt::Key_1: if(pMFI->m_bExistsInA){ slotCurrentCopyAToB(); } return; | |
830 case Qt::Key_2: if(pMFI->m_bExistsInB){ slotCurrentCopyBToA(); } return; | |
831 case Qt::Key_Space: slotCurrentDoNothing(); return; | |
832 case Qt::Key_4: if ( !bFTConflict ) { slotCurrentMergeToAAndB(); } return; | |
833 case Qt::Key_Delete: if( pMFI->m_bExistsInA && pMFI->m_bExistsInB ) slotCurrentDeleteAAndB(); | |
834 else if( pMFI->m_bExistsInA ) slotCurrentDeleteA(); | |
835 else if( pMFI->m_bExistsInB ) slotCurrentDeleteB(); | |
836 return; | |
837 default: break; | |
838 } | |
839 } | |
840 } | |
841 else if ( e->key()==Qt::Key_Return || e->key()==Qt::Key_Enter ) | |
842 { | |
843 onDoubleClick( currentItem() ); | |
844 return; | |
845 } | |
846 | |
847 QTreeWidget::keyPressEvent(e); | |
848 } | |
849 | |
850 void DirectoryMergeWindow::focusInEvent(QFocusEvent*) | |
851 { | |
852 updateAvailabilities(); | |
853 } | |
854 void DirectoryMergeWindow::focusOutEvent(QFocusEvent*) | |
855 { | |
856 updateAvailabilities(); | |
857 } | |
858 | |
859 void DirectoryMergeWindow::setAllMergeOperations( e_MergeOperation eDefaultOperation ) | |
860 { | |
861 if ( KMessageBox::Yes == KMessageBox::warningYesNo(this, | |
862 i18n("This affects all merge operations."), | |
863 i18n("Changing All Merge Operations"),i18n("C&ontinue"), i18n("&Cancel") ) ) | |
864 { | |
865 for( int i=0; i<topLevelItemCount(); ++i ) | |
866 { | |
867 DirMergeItem* pDMI = static_cast<DirMergeItem*>( topLevelItem(i) ); | |
868 calcSuggestedOperation( *pDMI->m_pMFI, eDefaultOperation ); | |
869 } | |
870 } | |
871 } | |
872 | |
873 | |
874 void DirectoryMergeWindow::compareFilesAndCalcAges( MergeFileInfos& mfi ) | |
875 { | |
876 std::map<QDateTime,int> dateMap; | |
877 | |
878 if( mfi.m_bExistsInA ) | |
879 { | |
880 mfi.m_bLinkA = mfi.m_fileInfoA.isSymLink(); | |
881 mfi.m_bDirA = mfi.m_fileInfoA.isDir(); | |
882 dateMap[ mfi.m_fileInfoA.lastModified() ] = 0; | |
883 } | |
884 if( mfi.m_bExistsInB ) | |
885 { | |
886 mfi.m_bLinkB = mfi.m_fileInfoB.isSymLink(); | |
887 mfi.m_bDirB = mfi.m_fileInfoB.isDir(); | |
888 dateMap[ mfi.m_fileInfoB.lastModified() ] = 1; | |
889 } | |
890 if( mfi.m_bExistsInC ) | |
891 { | |
892 mfi.m_bLinkC = mfi.m_fileInfoC.isSymLink(); | |
893 mfi.m_bDirC = mfi.m_fileInfoC.isDir(); | |
894 dateMap[ mfi.m_fileInfoC.lastModified() ] = 2; | |
895 } | |
896 | |
897 if ( m_pOptions->m_bDmFullAnalysis ) | |
898 { | |
899 if( mfi.m_bExistsInA && mfi.m_bDirA || mfi.m_bExistsInB && mfi.m_bDirB || mfi.m_bExistsInC && mfi.m_bDirC ) | |
900 { | |
901 // If any input is a directory, don't start any comparison. | |
902 mfi.m_bEqualAB=mfi.m_bExistsInA && mfi.m_bExistsInB; | |
903 mfi.m_bEqualAC=mfi.m_bExistsInA && mfi.m_bExistsInC; | |
904 mfi.m_bEqualBC=mfi.m_bExistsInB && mfi.m_bExistsInC; | |
905 } | |
906 else | |
907 { | |
908 emit startDiffMerge( | |
909 mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : QString(""), | |
910 mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : QString(""), | |
911 mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : QString(""), | |
912 "", | |
913 "","","",&mfi.m_totalDiffStatus | |
914 ); | |
915 int nofNonwhiteConflicts = mfi.m_totalDiffStatus.nofUnsolvedConflicts + | |
916 mfi.m_totalDiffStatus.nofSolvedConflicts - mfi.m_totalDiffStatus.nofWhitespaceConflicts; | |
917 | |
918 if (m_pOptions->m_bDmWhiteSpaceEqual && nofNonwhiteConflicts == 0) | |
919 { | |
920 mfi.m_bEqualAB = mfi.m_bEqualBC = mfi.m_bEqualAC = true; | |
921 } | |
922 else | |
923 { | |
924 mfi.m_bEqualAB = mfi.m_totalDiffStatus.bBinaryAEqB; | |
925 mfi.m_bEqualBC = mfi.m_totalDiffStatus.bBinaryBEqC; | |
926 mfi.m_bEqualAC = mfi.m_totalDiffStatus.bBinaryAEqC; | |
927 } | |
928 } | |
929 } | |
930 else | |
931 { | |
932 bool bError; | |
933 QString eqStatus; | |
934 if( mfi.m_bExistsInA && mfi.m_bExistsInB ) | |
935 { | |
936 if( mfi.m_bDirA ) mfi.m_bEqualAB=true; | |
937 else fastFileComparison( mfi.m_fileInfoA, mfi.m_fileInfoB, mfi.m_bEqualAB, bError, eqStatus ); | |
938 } | |
939 if( mfi.m_bExistsInA && mfi.m_bExistsInC ) | |
940 { | |
941 if( mfi.m_bDirA ) mfi.m_bEqualAC=true; | |
942 else fastFileComparison( mfi.m_fileInfoA, mfi.m_fileInfoC, mfi.m_bEqualAC, bError, eqStatus ); | |
943 } | |
944 if( mfi.m_bExistsInB && mfi.m_bExistsInC ) | |
945 { | |
946 if (mfi.m_bEqualAB && mfi.m_bEqualAC) | |
947 mfi.m_bEqualBC = true; | |
948 else | |
949 { | |
950 if( mfi.m_bDirB ) mfi.m_bEqualBC=true; | |
951 else fastFileComparison( mfi.m_fileInfoB, mfi.m_fileInfoC, mfi.m_bEqualBC, bError, eqStatus ); | |
952 } | |
953 } | |
954 } | |
955 | |
956 if (mfi.m_bLinkA!=mfi.m_bLinkB) mfi.m_bEqualAB=false; | |
957 if (mfi.m_bLinkA!=mfi.m_bLinkC) mfi.m_bEqualAC=false; | |
958 if (mfi.m_bLinkB!=mfi.m_bLinkC) mfi.m_bEqualBC=false; | |
959 | |
960 if (mfi.m_bDirA!=mfi.m_bDirB) mfi.m_bEqualAB=false; | |
961 if (mfi.m_bDirA!=mfi.m_bDirC) mfi.m_bEqualAC=false; | |
962 if (mfi.m_bDirB!=mfi.m_bDirC) mfi.m_bEqualBC=false; | |
963 | |
964 assert(eNew==0 && eMiddle==1 && eOld==2); | |
965 | |
966 // The map automatically sorts the keys. | |
967 int age = eNew; | |
968 std::map<QDateTime,int>::reverse_iterator i; | |
969 for( i=dateMap.rbegin(); i!=dateMap.rend(); ++i ) | |
970 { | |
971 int n = i->second; | |
972 if ( n==0 && mfi.m_ageA==eNotThere ) | |
973 { | |
974 mfi.m_ageA = (e_Age)age; ++age; | |
975 if ( mfi.m_bEqualAB ) { mfi.m_ageB = mfi.m_ageA; ++age; } | |
976 if ( mfi.m_bEqualAC ) { mfi.m_ageC = mfi.m_ageA; ++age; } | |
977 } | |
978 else if ( n==1 && mfi.m_ageB==eNotThere ) | |
979 { | |
980 mfi.m_ageB = (e_Age)age; ++age; | |
981 if ( mfi.m_bEqualAB ) { mfi.m_ageA = mfi.m_ageB; ++age; } | |
982 if ( mfi.m_bEqualBC ) { mfi.m_ageC = mfi.m_ageB; ++age; } | |
983 } | |
984 else if ( n==2 && mfi.m_ageC==eNotThere) | |
985 { | |
986 mfi.m_ageC = (e_Age)age; ++age; | |
987 if ( mfi.m_bEqualAC ) { mfi.m_ageA = mfi.m_ageC; ++age; } | |
988 if ( mfi.m_bEqualBC ) { mfi.m_ageB = mfi.m_ageC; ++age; } | |
989 } | |
990 } | |
991 | |
992 // The checks below are necessary when the dates of the file are equal but the | |
993 // files are not. One wouldn't expect this to happen, yet it happens sometimes. | |
994 if ( mfi.m_bExistsInC && mfi.m_ageC==eNotThere ) | |
995 { | |
996 mfi.m_ageC = (e_Age)age; ++age; | |
997 mfi.m_bConflictingAges = true; | |
998 } | |
999 if ( mfi.m_bExistsInB && mfi.m_ageB==eNotThere ) | |
1000 { | |
1001 mfi.m_ageB = (e_Age)age; ++age; | |
1002 mfi.m_bConflictingAges = true; | |
1003 } | |
1004 if ( mfi.m_bExistsInA && mfi.m_ageA==eNotThere ) | |
1005 { | |
1006 mfi.m_ageA = (e_Age)age; ++age; | |
1007 mfi.m_bConflictingAges = true; | |
1008 } | |
1009 | |
1010 if ( mfi.m_ageA != eOld && mfi.m_ageB != eOld && mfi.m_ageC != eOld ) | |
1011 { | |
1012 if (mfi.m_ageA == eMiddle) mfi.m_ageA = eOld; | |
1013 if (mfi.m_ageB == eMiddle) mfi.m_ageB = eOld; | |
1014 if (mfi.m_ageC == eMiddle) mfi.m_ageC = eOld; | |
1015 } | |
1016 } | |
1017 | |
1018 static QPixmap* s_pm_dir; | |
1019 static QPixmap* s_pm_file; | |
1020 | |
1021 static QPixmap* pmNotThere; | |
1022 static QPixmap* pmNew; | |
1023 static QPixmap* pmOld; | |
1024 static QPixmap* pmMiddle; | |
1025 | |
1026 static QPixmap* pmLink; | |
1027 | |
1028 static QPixmap* pmDirLink; | |
1029 static QPixmap* pmFileLink; | |
1030 | |
1031 static QPixmap* pmNewLink; | |
1032 static QPixmap* pmOldLink; | |
1033 static QPixmap* pmMiddleLink; | |
1034 | |
1035 static QPixmap* pmNewDir; | |
1036 static QPixmap* pmMiddleDir; | |
1037 static QPixmap* pmOldDir; | |
1038 | |
1039 static QPixmap* pmNewDirLink; | |
1040 static QPixmap* pmMiddleDirLink; | |
1041 static QPixmap* pmOldDirLink; | |
1042 | |
1043 | |
1044 static QPixmap colorToPixmap(QColor c) | |
1045 { | |
1046 QPixmap pm(16,16); | |
1047 QPainter p(&pm); | |
1048 p.setPen( Qt::black ); | |
1049 p.setBrush( c ); | |
1050 p.drawRect(0,0,pm.width(),pm.height()); | |
1051 return pm; | |
1052 } | |
1053 | |
1054 static void initPixmaps( QColor newest, QColor oldest, QColor middle, QColor notThere ) | |
1055 { | |
1056 if (pmNew==0) | |
1057 { | |
1058 pmNotThere = new QPixmap; | |
1059 pmNew = new QPixmap; | |
1060 pmOld = new QPixmap; | |
1061 pmMiddle = new QPixmap; | |
1062 | |
1063 #include "xpm/link_arrow.xpm" | |
1064 pmLink = new QPixmap(link_arrow); | |
1065 | |
1066 pmDirLink = new QPixmap; | |
1067 pmFileLink = new QPixmap; | |
1068 | |
1069 pmNewLink = new QPixmap; | |
1070 pmOldLink = new QPixmap; | |
1071 pmMiddleLink = new QPixmap; | |
1072 | |
1073 pmNewDir = new QPixmap; | |
1074 pmMiddleDir = new QPixmap; | |
1075 pmOldDir = new QPixmap; | |
1076 | |
1077 pmNewDirLink = new QPixmap; | |
1078 pmMiddleDirLink = new QPixmap; | |
1079 pmOldDirLink = new QPixmap; | |
1080 } | |
1081 | |
1082 | |
1083 *pmNotThere = colorToPixmap(notThere); | |
1084 *pmNew = colorToPixmap(newest); | |
1085 *pmOld = colorToPixmap(oldest); | |
1086 *pmMiddle = colorToPixmap(middle); | |
1087 | |
1088 *pmDirLink = pixCombiner( s_pm_dir, pmLink); | |
1089 *pmFileLink = pixCombiner( s_pm_file, pmLink ); | |
1090 | |
1091 *pmNewLink = pixCombiner( pmNew, pmLink); | |
1092 *pmOldLink = pixCombiner( pmOld, pmLink); | |
1093 *pmMiddleLink = pixCombiner( pmMiddle, pmLink); | |
1094 | |
1095 *pmNewDir = pixCombiner2( pmNew, s_pm_dir); | |
1096 *pmMiddleDir = pixCombiner2( pmMiddle, s_pm_dir); | |
1097 *pmOldDir = pixCombiner2( pmOld, s_pm_dir); | |
1098 | |
1099 *pmNewDirLink = pixCombiner( pmNewDir, pmLink); | |
1100 *pmMiddleDirLink = pixCombiner( pmMiddleDir, pmLink); | |
1101 *pmOldDirLink = pixCombiner( pmOldDir, pmLink); | |
1102 } | |
1103 | |
1104 | |
1105 static void setOnePixmap( QTreeWidgetItem* pLVI, int col, e_Age eAge, bool bLink, bool bDir ) | |
1106 { | |
1107 static QPixmap* ageToPm[]= { pmNew, pmMiddle, pmOld, pmNotThere, s_pm_file }; | |
1108 static QPixmap* ageToPmLink[]= { pmNewLink, pmMiddleLink, pmOldLink, pmNotThere, pmFileLink }; | |
1109 static QPixmap* ageToPmDir[]= { pmNewDir, pmMiddleDir, pmOldDir, pmNotThere, s_pm_dir }; | |
1110 static QPixmap* ageToPmDirLink[]={ pmNewDirLink, pmMiddleDirLink, pmOldDirLink, pmNotThere, pmDirLink }; | |
1111 | |
1112 QPixmap** ppPm = bDir ? ( bLink ? ageToPmDirLink : ageToPmDir ): | |
1113 ( bLink ? ageToPmLink : ageToPm ); | |
1114 | |
1115 pLVI->setIcon( col, *ppPm[eAge] ); | |
1116 } | |
1117 | |
1118 static void setPixmaps( MergeFileInfos& mfi, bool bCheckC ) | |
1119 { | |
1120 setOnePixmap( mfi.m_pDMI, s_NameCol, eAgeEnd, | |
1121 mfi.m_bLinkA || mfi.m_bLinkB || mfi.m_bLinkC, | |
1122 mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC | |
1123 ); | |
1124 | |
1125 if ( mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC ) | |
1126 { | |
1127 mfi.m_ageA=eNotThere; | |
1128 mfi.m_ageB=eNotThere; | |
1129 mfi.m_ageC=eNotThere; | |
1130 int age = eNew; | |
1131 if ( mfi.m_bExistsInC ) | |
1132 { | |
1133 mfi.m_ageC = (e_Age)age; | |
1134 if (mfi.m_bEqualAC) mfi.m_ageA = (e_Age)age; | |
1135 if (mfi.m_bEqualBC) mfi.m_ageB = (e_Age)age; | |
1136 ++age; | |
1137 } | |
1138 if ( mfi.m_bExistsInB && mfi.m_ageB==eNotThere ) | |
1139 { | |
1140 mfi.m_ageB = (e_Age)age; | |
1141 if (mfi.m_bEqualAB) mfi.m_ageA = (e_Age)age; | |
1142 ++age; | |
1143 } | |
1144 if ( mfi.m_bExistsInA && mfi.m_ageA==eNotThere ) | |
1145 { | |
1146 mfi.m_ageA = (e_Age)age; | |
1147 } | |
1148 if ( mfi.m_ageA != eOld && mfi.m_ageB != eOld && mfi.m_ageC != eOld ) | |
1149 { | |
1150 if (mfi.m_ageA == eMiddle) mfi.m_ageA = eOld; | |
1151 if (mfi.m_ageB == eMiddle) mfi.m_ageB = eOld; | |
1152 if (mfi.m_ageC == eMiddle) mfi.m_ageC = eOld; | |
1153 } | |
1154 } | |
1155 | |
1156 setOnePixmap( mfi.m_pDMI, s_ACol, mfi.m_ageA, mfi.m_bLinkA, mfi.m_bDirA ); | |
1157 setOnePixmap( mfi.m_pDMI, s_BCol, mfi.m_ageB, mfi.m_bLinkB, mfi.m_bDirB ); | |
1158 if ( bCheckC ) | |
1159 setOnePixmap( mfi.m_pDMI, s_CCol, mfi.m_ageC, mfi.m_bLinkC, mfi.m_bDirC ); | |
1160 } | |
1161 | |
1162 static QTreeWidgetItem* nextSibling(const QTreeWidgetItem* p) | |
1163 { | |
1164 QTreeWidgetItem* pParent = p->parent(); | |
1165 if ( pParent ) | |
1166 { | |
1167 int currentIdx = pParent->indexOfChild( const_cast<QTreeWidgetItem*>(p) ); | |
1168 if ( currentIdx+1 < pParent->childCount() ) | |
1169 return pParent->child(currentIdx+1); | |
1170 } | |
1171 else | |
1172 { | |
1173 QTreeWidget* pParentTreeWidget = p->treeWidget(); | |
1174 if ( pParentTreeWidget ) | |
1175 { | |
1176 int currentIdx = pParentTreeWidget->indexOfTopLevelItem( const_cast<QTreeWidgetItem*>(p) ); | |
1177 if ( currentIdx+1 < pParentTreeWidget->topLevelItemCount() ) | |
1178 return pParentTreeWidget->topLevelItem(currentIdx+1); | |
1179 } | |
1180 } | |
1181 return 0; | |
1182 } | |
1183 | |
1184 // Iterate through the complete tree. Start by specifying QListView::firstChild(). | |
1185 static QTreeWidgetItem* treeIterator( QTreeWidgetItem* p, bool bVisitChildren=true, bool bFindInvisible=false ) | |
1186 { | |
1187 if( p!=0 ) | |
1188 { | |
1189 do | |
1190 { | |
1191 if ( bVisitChildren && p->childCount() != 0 ) p = p->child(0); | |
1192 else | |
1193 { | |
1194 QTreeWidgetItem* pNextSibling = nextSibling(p); | |
1195 if ( pNextSibling ) | |
1196 p = pNextSibling; | |
1197 else | |
1198 { | |
1199 p = p->parent(); | |
1200 while ( p!=0 ) | |
1201 { | |
1202 QTreeWidgetItem* pNextSibling = nextSibling(p); | |
1203 if( pNextSibling ) { p = pNextSibling; break; } | |
1204 else { p = p->parent(); } | |
1205 } | |
1206 } | |
1207 } | |
1208 } | |
1209 while( p && p->isHidden() && !bFindInvisible ); | |
1210 } | |
1211 return p; | |
1212 } | |
1213 | |
1214 void DirectoryMergeWindow::prepareListView( ProgressProxy& pp ) | |
1215 { | |
1216 static bool bFirstTime = true; | |
1217 if (bFirstTime) | |
1218 { | |
1219 #include "xpm/file.xpm" | |
1220 #include "xpm/folder.xpm" | |
1221 s_pm_dir = new QPixmap( m_pIconLoader->loadIcon("folder", KIcon::Small ) ); | |
1222 if (s_pm_dir->size()!=QSize(16,16)) | |
1223 { | |
1224 delete s_pm_dir; | |
1225 s_pm_dir = new QPixmap( folder_pm ); | |
1226 } | |
1227 s_pm_file= new QPixmap( file_pm ); | |
1228 bFirstTime=false; | |
1229 } | |
1230 | |
1231 clear(); | |
1232 initPixmaps( m_pOptions->m_newestFileColor, m_pOptions->m_oldestFileColor, | |
1233 m_pOptions->m_midAgeFileColor, m_pOptions->m_missingFileColor ); | |
1234 | |
1235 setRootIsDecorated( true ); | |
1236 | |
1237 bool bCheckC = m_dirC.isValid(); | |
1238 | |
1239 std::map<QString, MergeFileInfos>::iterator j; | |
1240 int nrOfFiles = m_fileMergeMap.size(); | |
1241 int currentIdx = 1; | |
1242 QTime t; | |
1243 t.start(); | |
1244 for( j=m_fileMergeMap.begin(); j!=m_fileMergeMap.end(); ++j ) | |
1245 { | |
1246 MergeFileInfos& mfi = j->second; | |
1247 | |
1248 mfi.m_subPath = mfi.m_fileInfoA.exists() ? mfi.m_fileInfoA.filePath() : | |
1249 mfi.m_fileInfoB.exists() ? mfi.m_fileInfoB.filePath() : | |
1250 mfi.m_fileInfoC.exists() ? mfi.m_fileInfoC.filePath() : | |
1251 QString(""); | |
1252 | |
1253 // const QString& fileName = j->first; | |
1254 const QString& fileName = mfi.m_subPath; | |
1255 | |
1256 pp.setInformation( | |
1257 i18n("Processing ") + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles) | |
1258 +"\n" + fileName, double(currentIdx) / nrOfFiles, false ); | |
1259 if ( pp.wasCancelled() ) break; | |
1260 ++currentIdx; | |
1261 | |
1262 | |
1263 // The comparisons and calculations for each file take place here. | |
1264 compareFilesAndCalcAges( mfi ); | |
1265 | |
1266 bool bEqual = bCheckC ? mfi.m_bEqualAB && mfi.m_bEqualAC : mfi.m_bEqualAB; | |
1267 //bool bDir = mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC; | |
1268 | |
1269 //if ( m_pOptions->m_bDmShowOnlyDeltas && !bDir && bEqual ) | |
1270 // continue; | |
1271 | |
1272 // Get dirname from fileName: Search for "/" from end: | |
1273 int pos = fileName.lastIndexOf('/'); | |
1274 QString dirPart; | |
1275 QString filePart; | |
1276 if (pos==-1) | |
1277 { | |
1278 // Top dir | |
1279 filePart = fileName; | |
1280 } | |
1281 else | |
1282 { | |
1283 dirPart = fileName.left(pos); | |
1284 filePart = fileName.mid(pos+1); | |
1285 } | |
1286 | |
1287 if ( dirPart.isEmpty() ) // Top level | |
1288 { | |
1289 new DirMergeItem( this, filePart, &mfi ); | |
1290 } | |
1291 else | |
1292 { | |
1293 MergeFileInfos& dirMfi = m_fileMergeMap[sortString(dirPart, m_bCaseSensitive)]; // parent | |
1294 assert(dirMfi.m_pDMI!=0); | |
1295 new DirMergeItem( dirMfi.m_pDMI, filePart, &mfi ); | |
1296 mfi.m_pParent = &dirMfi; | |
1297 | |
1298 if ( !bEqual ) // Set all parents to "not equal" | |
1299 { | |
1300 MergeFileInfos* p = mfi.m_pParent; | |
1301 while(p!=0) | |
1302 { | |
1303 bool bChange = false; | |
1304 if ( !mfi.m_bEqualAB && p->m_bEqualAB ){ p->m_bEqualAB = false; bChange=true; } | |
1305 if ( !mfi.m_bEqualAC && p->m_bEqualAC ){ p->m_bEqualAC = false; bChange=true; } | |
1306 if ( !mfi.m_bEqualBC && p->m_bEqualBC ){ p->m_bEqualBC = false; bChange=true; } | |
1307 | |
1308 if ( bChange ) | |
1309 setPixmaps( *p, bCheckC ); | |
1310 else | |
1311 break; | |
1312 | |
1313 p = p->m_pParent; | |
1314 } | |
1315 } | |
1316 } | |
1317 | |
1318 setPixmaps( mfi, bCheckC ); | |
1319 } | |
1320 | |
1321 /*if ( m_pOptions->m_bDmShowOnlyDeltas ) | |
1322 { | |
1323 // Remove all equals. (Search tree depth first) | |
1324 QListViewItem* p = firstChild(); | |
1325 while( p!=0 && firstChild() != 0 ) | |
1326 { | |
1327 QListViewItem* pParent = p->parent(); | |
1328 QListViewItem* pNextSibling = p->nextSibling(); | |
1329 | |
1330 DirMergeItem* pDMI = static_cast<DirMergeItem*>(p); | |
1331 bool bDirEqual = bCheckC ? pDMI->m_pMFI->m_bEqualAB && pDMI->m_pMFI->m_bEqualAC | |
1332 : pDMI->m_pMFI->m_bEqualAB; | |
1333 if ( pDMI!=0 && pDMI->m_pMFI->m_bDirA && bDirEqual ) | |
1334 { | |
1335 delete p; | |
1336 p=0; | |
1337 } | |
1338 | |
1339 if ( p!=0 && p->firstChild() != 0 ) p = p->firstChild(); | |
1340 else if ( pNextSibling!=0 ) p = pNextSibling; | |
1341 else | |
1342 { | |
1343 p=pParent; | |
1344 while ( p!=0 ) | |
1345 { | |
1346 if( p->nextSibling()!=0 ) { p = p->nextSibling(); break; } | |
1347 else { p = p->parent(); } | |
1348 } | |
1349 } | |
1350 } | |
1351 }*/ | |
1352 } | |
1353 | |
1354 static bool conflictingFileTypes(MergeFileInfos& mfi) | |
1355 { | |
1356 // Now check if file/dir-types fit. | |
1357 if ( mfi.m_bLinkA || mfi.m_bLinkB || mfi.m_bLinkC ) | |
1358 { | |
1359 if ( mfi.m_bExistsInA && ! mfi.m_bLinkA || | |
1360 mfi.m_bExistsInB && ! mfi.m_bLinkB || | |
1361 mfi.m_bExistsInC && ! mfi.m_bLinkC ) | |
1362 { | |
1363 return true; | |
1364 } | |
1365 } | |
1366 | |
1367 if ( mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC ) | |
1368 { | |
1369 if ( mfi.m_bExistsInA && ! mfi.m_bDirA || | |
1370 mfi.m_bExistsInB && ! mfi.m_bDirB || | |
1371 mfi.m_bExistsInC && ! mfi.m_bDirC ) | |
1372 { | |
1373 return true; | |
1374 } | |
1375 } | |
1376 return false; | |
1377 } | |
1378 | |
1379 void DirectoryMergeWindow::calcSuggestedOperation( MergeFileInfos& mfi, e_MergeOperation eDefaultMergeOp ) | |
1380 { | |
1381 bool bCheckC = m_dirC.isValid(); | |
1382 bool bCopyNewer = m_pOptions->m_bDmCopyNewer; | |
1383 bool bOtherDest = !( m_dirDestInternal.absFilePath() == m_dirA.absFilePath() || | |
1384 m_dirDestInternal.absFilePath() == m_dirB.absFilePath() || | |
1385 bCheckC && m_dirDestInternal.absFilePath() == m_dirC.absFilePath() ); | |
1386 | |
1387 | |
1388 if ( eDefaultMergeOp == eMergeABCToDest && !bCheckC ) { eDefaultMergeOp = eMergeABToDest; } | |
1389 if ( eDefaultMergeOp == eMergeToAB && bCheckC ) { assert(false); } | |
1390 | |
1391 if ( eDefaultMergeOp == eMergeToA || eDefaultMergeOp == eMergeToB || | |
1392 eDefaultMergeOp == eMergeABCToDest || eDefaultMergeOp == eMergeABToDest || eDefaultMergeOp == eMergeToAB ) | |
1393 { | |
1394 if ( !bCheckC ) | |
1395 { | |
1396 if ( mfi.m_bEqualAB ) | |
1397 { | |
1398 mfi.setMergeOperation( bOtherDest ? eCopyBToDest : eNoOperation ); | |
1399 } | |
1400 else if ( mfi.m_bExistsInA && mfi.m_bExistsInB ) | |
1401 { | |
1402 if ( !bCopyNewer || mfi.m_bDirA ) | |
1403 mfi.setMergeOperation( eDefaultMergeOp ); | |
1404 else if ( bCopyNewer && mfi.m_bConflictingAges ) | |
1405 { | |
1406 mfi.setMergeOperation( eConflictingAges ); | |
1407 } | |
1408 else | |
1409 { | |
1410 if ( mfi.m_ageA == eNew ) | |
1411 mfi.setMergeOperation( eDefaultMergeOp == eMergeToAB ? eCopyAToB : eCopyAToDest ); | |
1412 else | |
1413 mfi.setMergeOperation( eDefaultMergeOp == eMergeToAB ? eCopyBToA : eCopyBToDest ); | |
1414 } | |
1415 } | |
1416 else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB ) | |
1417 { | |
1418 if ( eDefaultMergeOp==eMergeABToDest ) mfi.setMergeOperation( eCopyBToDest ); | |
1419 else if ( eDefaultMergeOp==eMergeToB ) mfi.setMergeOperation( eNoOperation ); | |
1420 else mfi.setMergeOperation( eCopyBToA ); | |
1421 } | |
1422 else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB ) | |
1423 { | |
1424 if ( eDefaultMergeOp==eMergeABToDest ) mfi.setMergeOperation( eCopyAToDest ); | |
1425 else if ( eDefaultMergeOp==eMergeToA ) mfi.setMergeOperation( eNoOperation ); | |
1426 else mfi.setMergeOperation( eCopyAToB ); | |
1427 } | |
1428 else //if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB ) | |
1429 { | |
1430 mfi.setMergeOperation( eNoOperation ); assert(false); | |
1431 } | |
1432 } | |
1433 else | |
1434 { | |
1435 if ( mfi.m_bEqualAB && mfi.m_bEqualAC ) | |
1436 { | |
1437 mfi.setMergeOperation( bOtherDest ? eCopyCToDest : eNoOperation ); | |
1438 } | |
1439 else if ( mfi.m_bExistsInA && mfi.m_bExistsInB && mfi.m_bExistsInC) | |
1440 { | |
1441 if ( mfi.m_bEqualAB ) | |
1442 mfi.setMergeOperation( eCopyCToDest ); | |
1443 else if ( mfi.m_bEqualAC ) | |
1444 mfi.setMergeOperation( eCopyBToDest ); | |
1445 else if ( mfi.m_bEqualBC ) | |
1446 mfi.setMergeOperation( eCopyCToDest ); | |
1447 else | |
1448 mfi.setMergeOperation( eMergeABCToDest ); | |
1449 } | |
1450 else if ( mfi.m_bExistsInA && mfi.m_bExistsInB && !mfi.m_bExistsInC ) | |
1451 { | |
1452 if ( mfi.m_bEqualAB ) | |
1453 mfi.setMergeOperation( eDeleteFromDest ); | |
1454 else | |
1455 mfi.setMergeOperation( eCopyBToDest ); | |
1456 } | |
1457 else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB && mfi.m_bExistsInC ) | |
1458 { | |
1459 if ( mfi.m_bEqualAC ) | |
1460 mfi.setMergeOperation( eDeleteFromDest ); | |
1461 else | |
1462 mfi.setMergeOperation( eCopyCToDest ); | |
1463 } | |
1464 else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB && mfi.m_bExistsInC ) | |
1465 { | |
1466 if ( mfi.m_bEqualBC ) | |
1467 mfi.setMergeOperation( eCopyCToDest ); | |
1468 else | |
1469 mfi.setMergeOperation( eMergeABCToDest ); | |
1470 } | |
1471 else if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB && mfi.m_bExistsInC ) | |
1472 { | |
1473 mfi.setMergeOperation( eCopyCToDest ); | |
1474 } | |
1475 else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB && !mfi.m_bExistsInC ) | |
1476 { | |
1477 mfi.setMergeOperation( eCopyBToDest ); | |
1478 } | |
1479 else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB && !mfi.m_bExistsInC) | |
1480 { | |
1481 mfi.setMergeOperation( eDeleteFromDest ); | |
1482 } | |
1483 else //if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB && !mfi.m_bExistsInC ) | |
1484 { | |
1485 mfi.setMergeOperation( eNoOperation ); assert(false); | |
1486 } | |
1487 } | |
1488 | |
1489 // Now check if file/dir-types fit. | |
1490 if ( conflictingFileTypes(mfi) ) | |
1491 { | |
1492 mfi.setMergeOperation( eConflictingFileTypes ); | |
1493 } | |
1494 } | |
1495 else | |
1496 { | |
1497 e_MergeOperation eMO = eDefaultMergeOp; | |
1498 switch ( eDefaultMergeOp ) | |
1499 { | |
1500 case eConflictingFileTypes: | |
1501 case eConflictingAges: | |
1502 case eDeleteA: | |
1503 case eDeleteB: | |
1504 case eDeleteAB: | |
1505 case eDeleteFromDest: | |
1506 case eNoOperation: break; | |
1507 case eCopyAToB: if ( !mfi.m_bExistsInA ) { eMO = eDeleteB; } break; | |
1508 case eCopyBToA: if ( !mfi.m_bExistsInB ) { eMO = eDeleteA; } break; | |
1509 case eCopyAToDest: if ( !mfi.m_bExistsInA ) { eMO = eDeleteFromDest; } break; | |
1510 case eCopyBToDest: if ( !mfi.m_bExistsInB ) { eMO = eDeleteFromDest; } break; | |
1511 case eCopyCToDest: if ( !mfi.m_bExistsInC ) { eMO = eDeleteFromDest; } break; | |
1512 | |
1513 case eMergeToA: | |
1514 case eMergeToB: | |
1515 case eMergeToAB: | |
1516 case eMergeABCToDest: | |
1517 case eMergeABToDest: | |
1518 default: | |
1519 assert(false); | |
1520 } | |
1521 mfi.setMergeOperation( eMO ); | |
1522 } | |
1523 } | |
1524 | |
1525 void DirectoryMergeWindow::onDoubleClick( QTreeWidgetItem* lvi ) | |
1526 { | |
1527 if (lvi==0) return; | |
1528 | |
1529 if ( m_bDirectoryMerge ) | |
1530 mergeCurrentFile(); | |
1531 else | |
1532 compareCurrentFile(); | |
1533 } | |
1534 | |
1535 void DirectoryMergeWindow::onCurrentChanged(QTreeWidgetItem* lvi) | |
1536 { | |
1537 if ( lvi==0 ) return; | |
1538 | |
1539 DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi); | |
1540 | |
1541 MergeFileInfos& mfi = *pDMI->m_pMFI; | |
1542 assert( mfi.m_pDMI==pDMI ); | |
1543 | |
1544 m_pDirectoryMergeInfo->setInfo( m_dirA, m_dirB, m_dirC, m_dirDestInternal, mfi ); | |
1545 } | |
1546 | |
1547 void DirectoryMergeWindow::mousePressEvent( QMouseEvent* e ) | |
1548 { | |
1549 QTreeWidget::mousePressEvent(e); | |
1550 int c = columnAt( e->x() ); | |
1551 QTreeWidgetItem* lvi = itemAt( e->pos() ); | |
1552 QPoint p = e->globalPos(); | |
1553 if ( lvi==0 ) return; | |
1554 | |
1555 DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi); | |
1556 | |
1557 MergeFileInfos& mfi = *pDMI->m_pMFI; | |
1558 assert( mfi.m_pDMI==pDMI ); | |
1559 | |
1560 if ( c==s_OpCol ) | |
1561 { | |
1562 bool bThreeDirs = m_dirC.isValid(); | |
1563 | |
1564 KPopupMenu m(this); | |
1565 if ( bThreeDirs ) | |
1566 { | |
1567 m_pDirCurrentDoNothing->plug(&m); | |
1568 int count=0; | |
1569 if ( mfi.m_bExistsInA ) { m_pDirCurrentChooseA->plug(&m); ++count; } | |
1570 if ( mfi.m_bExistsInB ) { m_pDirCurrentChooseB->plug(&m); ++count; } | |
1571 if ( mfi.m_bExistsInC ) { m_pDirCurrentChooseC->plug(&m); ++count; } | |
1572 if ( !conflictingFileTypes(mfi) && count>1 ) m_pDirCurrentMerge->plug(&m); | |
1573 m_pDirCurrentDelete->plug(&m); | |
1574 } | |
1575 else if ( m_bSyncMode ) | |
1576 { | |
1577 m_pDirCurrentSyncDoNothing->plug(&m); | |
1578 if ( mfi.m_bExistsInA ) m_pDirCurrentSyncCopyAToB->plug(&m); | |
1579 if ( mfi.m_bExistsInB ) m_pDirCurrentSyncCopyBToA->plug(&m); | |
1580 if ( mfi.m_bExistsInA ) m_pDirCurrentSyncDeleteA->plug(&m); | |
1581 if ( mfi.m_bExistsInB ) m_pDirCurrentSyncDeleteB->plug(&m); | |
1582 if ( mfi.m_bExistsInA && mfi.m_bExistsInB ) | |
1583 { | |
1584 m_pDirCurrentSyncDeleteAAndB->plug(&m); | |
1585 if ( !conflictingFileTypes(mfi)) | |
1586 { | |
1587 m_pDirCurrentSyncMergeToA->plug(&m); | |
1588 m_pDirCurrentSyncMergeToB->plug(&m); | |
1589 m_pDirCurrentSyncMergeToAAndB->plug(&m); | |
1590 } | |
1591 } | |
1592 } | |
1593 else | |
1594 { | |
1595 m_pDirCurrentDoNothing->plug(&m); | |
1596 if ( mfi.m_bExistsInA ) { m_pDirCurrentChooseA->plug(&m); } | |
1597 if ( mfi.m_bExistsInB ) { m_pDirCurrentChooseB->plug(&m); } | |
1598 if ( !conflictingFileTypes(mfi) && mfi.m_bExistsInA && mfi.m_bExistsInB ) m_pDirCurrentMerge->plug(&m); | |
1599 m_pDirCurrentDelete->plug(&m); | |
1600 } | |
1601 | |
1602 m.exec( p ); | |
1603 } | |
1604 else if ( c == s_ACol || c==s_BCol || c==s_CCol ) | |
1605 { | |
1606 QString itemPath; | |
1607 if ( c == s_ACol && mfi.m_bExistsInA ){ itemPath = fullNameA(mfi); } | |
1608 else if ( c == s_BCol && mfi.m_bExistsInB ){ itemPath = fullNameB(mfi); } | |
1609 else if ( c == s_CCol && mfi.m_bExistsInC ){ itemPath = fullNameC(mfi); } | |
1610 | |
1611 if (!itemPath.isEmpty()) | |
1612 { | |
1613 selectItemAndColumn( pDMI, c, e->button()==Qt::RightButton ); | |
1614 } | |
1615 } | |
1616 } | |
1617 | |
1618 void DirectoryMergeWindow::contextMenuEvent(QContextMenuEvent* e) | |
1619 { | |
1620 QTreeWidgetItem* lvi = itemAt( e->pos() ); | |
1621 int c = columnAt( e->x() ); | |
1622 QPoint p = e->globalPos(); | |
1623 if ( lvi==0 ) return; | |
1624 | |
1625 DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi); | |
1626 | |
1627 MergeFileInfos& mfi = *pDMI->m_pMFI; | |
1628 assert( mfi.m_pDMI==pDMI ); | |
1629 if ( c == s_ACol || c==s_BCol || c==s_CCol ) | |
1630 { | |
1631 QString itemPath; | |
1632 if ( c == s_ACol && mfi.m_bExistsInA ){ itemPath = fullNameA(mfi); } | |
1633 else if ( c == s_BCol && mfi.m_bExistsInB ){ itemPath = fullNameB(mfi); } | |
1634 else if ( c == s_CCol && mfi.m_bExistsInC ){ itemPath = fullNameC(mfi); } | |
1635 | |
1636 if (!itemPath.isEmpty()) | |
1637 { | |
1638 selectItemAndColumn(pDMI, c, true); | |
1639 KPopupMenu m(this); | |
1640 m_pDirCompareExplicit->plug(&m); | |
1641 m_pDirMergeExplicit->plug(&m); | |
1642 | |
1643 #ifndef _WIN32 | |
1644 m.exec( p ); | |
1645 #else | |
1646 void showShellContextMenu( const QString&, QPoint, QWidget*, QMenu* ); | |
1647 showShellContextMenu( itemPath, p, this, &m ); | |
1648 #endif | |
1649 } | |
1650 } | |
1651 } | |
1652 | |
1653 static QString getFileName( DirMergeItem* pDMI, int column ) | |
1654 { | |
1655 if ( pDMI != 0 ) | |
1656 { | |
1657 MergeFileInfos& mfi = *pDMI->m_pMFI; | |
1658 return column == s_ACol ? mfi.m_fileInfoA.absFilePath() : | |
1659 column == s_BCol ? mfi.m_fileInfoB.absFilePath() : | |
1660 column == s_CCol ? mfi.m_fileInfoC.absFilePath() : | |
1661 QString(""); | |
1662 } | |
1663 return ""; | |
1664 } | |
1665 | |
1666 static bool isDir( DirMergeItem* pDMI, int column ) | |
1667 { | |
1668 if ( pDMI != 0 ) | |
1669 { | |
1670 MergeFileInfos& mfi = *pDMI->m_pMFI; | |
1671 return column == s_ACol ? mfi.m_bDirA : | |
1672 column == s_BCol ? mfi.m_bDirB : | |
1673 mfi.m_bDirC; | |
1674 } | |
1675 return false; | |
1676 } | |
1677 | |
1678 | |
1679 void DirectoryMergeWindow::selectItemAndColumn(DirMergeItem* pDMI, int c, bool bContextMenu) | |
1680 { | |
1681 if ( bContextMenu && ( | |
1682 pDMI==m_pSelection1Item && c==m_selection1Column && m_pSelection2Item==0 || | |
1683 pDMI==m_pSelection2Item && c==m_selection2Column && m_pSelection3Item==0 || | |
1684 pDMI==m_pSelection3Item && c==m_selection3Column ) ) | |
1685 return; | |
1686 | |
1687 DirMergeItem* pOld1=m_pSelection1Item; | |
1688 DirMergeItem* pOld2=m_pSelection2Item; | |
1689 DirMergeItem* pOld3=m_pSelection3Item; | |
1690 | |
1691 bool bReset = false; | |
1692 | |
1693 if ( m_pSelection1Item ) | |
1694 { | |
1695 if (isDir( m_pSelection1Item, m_selection1Column )!=isDir( pDMI, c )) | |
1696 bReset = true; | |
1697 } | |
1698 | |
1699 if ( bReset || m_pSelection3Item!=0 || | |
1700 pDMI==m_pSelection1Item && c==m_selection1Column || | |
1701 pDMI==m_pSelection2Item && c==m_selection2Column || | |
1702 pDMI==m_pSelection3Item && c==m_selection3Column) | |
1703 { | |
1704 m_pSelection1Item = 0; | |
1705 m_pSelection2Item = 0; | |
1706 m_pSelection3Item = 0; | |
1707 } | |
1708 else if ( m_pSelection1Item==0 ) | |
1709 { | |
1710 m_pSelection1Item = pDMI; | |
1711 m_selection1Column = c; | |
1712 m_pSelection2Item = 0; | |
1713 m_pSelection3Item = 0; | |
1714 } | |
1715 else if ( m_pSelection2Item==0 ) | |
1716 { | |
1717 m_pSelection2Item = pDMI; | |
1718 m_selection2Column = c; | |
1719 m_pSelection3Item = 0; | |
1720 } | |
1721 else if ( m_pSelection3Item==0 ) | |
1722 { | |
1723 m_pSelection3Item = pDMI; | |
1724 m_selection3Column = c; | |
1725 } | |
1726 if (pOld1) dataChanged( indexFromItem( pOld1, s_ACol ), indexFromItem( pOld1, s_CCol ) ); | |
1727 if (pOld2) dataChanged( indexFromItem( pOld2, s_ACol ), indexFromItem( pOld2, s_CCol ) ); | |
1728 if (pOld3) dataChanged( indexFromItem( pOld3, s_ACol ), indexFromItem( pOld3, s_CCol ) ); | |
1729 if (m_pSelection1Item) dataChanged( indexFromItem( m_pSelection1Item, s_ACol ), indexFromItem( m_pSelection1Item, s_CCol ) ); | |
1730 if (m_pSelection2Item) dataChanged( indexFromItem( m_pSelection2Item, s_ACol ), indexFromItem( m_pSelection2Item, s_CCol ) ); | |
1731 if (m_pSelection3Item) dataChanged( indexFromItem( m_pSelection3Item, s_ACol ), indexFromItem( m_pSelection3Item, s_CCol ) ); | |
1732 emit updateAvailabilities(); | |
1733 } | |
1734 | |
1735 DirMergeItem::DirMergeItem( QTreeWidget* pParent, const QString& fileName, MergeFileInfos* pMFI ) | |
1736 : QTreeWidgetItem( pParent, QStringList() << fileName << "" << "" << "" << i18n("To do.") << "" ) | |
1737 { | |
1738 init(pMFI); | |
1739 } | |
1740 | |
1741 DirMergeItem::DirMergeItem( DirMergeItem* pParent, const QString& fileName, MergeFileInfos* pMFI ) | |
1742 : QTreeWidgetItem( pParent, QStringList() << fileName << "" << "" << "" << i18n("To do.") << "" ) | |
1743 { | |
1744 init(pMFI); | |
1745 } | |
1746 | |
1747 | |
1748 void DirMergeItem::init(MergeFileInfos* pMFI) | |
1749 { | |
1750 pMFI->m_pDMI = this; | |
1751 m_pMFI = pMFI; | |
1752 TotalDiffStatus& tds = pMFI->m_totalDiffStatus; | |
1753 if ( m_pMFI->m_bDirA || m_pMFI->m_bDirB || m_pMFI->m_bDirC ) | |
1754 { | |
1755 } | |
1756 else | |
1757 { | |
1758 setText( s_UnsolvedCol, QString::number( tds.nofUnsolvedConflicts ) ); | |
1759 setText( s_SolvedCol, QString::number( tds.nofSolvedConflicts ) ); | |
1760 setText( s_NonWhiteCol, QString::number( tds.nofUnsolvedConflicts + tds.nofSolvedConflicts - tds.nofWhitespaceConflicts ) ); | |
1761 setText( s_WhiteCol, QString::number( tds.nofWhitespaceConflicts ) ); | |
1762 } | |
1763 } | |
1764 | |
1765 bool DirMergeItem::operator<(const QTreeWidgetItem& i) const | |
1766 { | |
1767 int col = treeWidget()->sortColumn(); | |
1768 const DirMergeItem* pDMI = static_cast<const DirMergeItem*>(&i); | |
1769 bool bDir1 = m_pMFI->m_bDirA || m_pMFI->m_bDirB || m_pMFI->m_bDirC; | |
1770 bool bDir2 = pDMI->m_pMFI->m_bDirA || pDMI->m_pMFI->m_bDirB || pDMI->m_pMFI->m_bDirC; | |
1771 if ( m_pMFI==0 || pDMI->m_pMFI==0 || bDir1 == bDir2 ) | |
1772 { | |
1773 if(col==s_UnsolvedCol || col==s_SolvedCol || col==s_NonWhiteCol || col==s_WhiteCol) | |
1774 return text(col).toInt() > i.text(col).toInt(); | |
1775 else | |
1776 return QTreeWidgetItem::operator<(i); | |
1777 } | |
1778 else | |
1779 return bDir1; | |
1780 } | |
1781 | |
1782 | |
1783 DirMergeItem::~DirMergeItem() | |
1784 { | |
1785 m_pMFI->m_pDMI = 0; | |
1786 } | |
1787 | |
1788 void MergeFileInfos::setMergeOperation( e_MergeOperation eMOp ) | |
1789 { | |
1790 if ( eMOp != m_eMergeOperation ) | |
1791 { | |
1792 m_bOperationComplete = false; | |
1793 m_pDMI->setText( s_OpStatusCol, "" ); | |
1794 } | |
1795 | |
1796 m_eMergeOperation = eMOp; | |
1797 QString s; | |
1798 bool bDir = m_bDirA || m_bDirB || m_bDirC; | |
1799 if( m_pDMI!=0 ) | |
1800 { | |
1801 switch( m_eMergeOperation ) | |
1802 { | |
1803 case eNoOperation: s=""; m_pDMI->setText(s_OpCol,""); break; | |
1804 case eCopyAToB: s=i18n("Copy A to B"); break; | |
1805 case eCopyBToA: s=i18n("Copy B to A"); break; | |
1806 case eDeleteA: s=i18n("Delete A"); break; | |
1807 case eDeleteB: s=i18n("Delete B"); break; | |
1808 case eDeleteAB: s=i18n("Delete A & B"); break; | |
1809 case eMergeToA: s=i18n("Merge to A"); break; | |
1810 case eMergeToB: s=i18n("Merge to B"); break; | |
1811 case eMergeToAB: s=i18n("Merge to A & B"); break; | |
1812 case eCopyAToDest: s="A"; break; | |
1813 case eCopyBToDest: s="B"; break; | |
1814 case eCopyCToDest: s="C"; break; | |
1815 case eDeleteFromDest: s=i18n("Delete (if exists)"); break; | |
1816 case eMergeABCToDest: s= bDir ? i18n("Merge") : i18n("Merge (manual)"); break; | |
1817 case eMergeABToDest: s= bDir ? i18n("Merge") : i18n("Merge (manual)"); break; | |
1818 case eConflictingFileTypes: s=i18n("Error: Conflicting File Types"); break; | |
1819 case eConflictingAges: s=i18n("Error: Dates are equal but files are not."); break; | |
1820 default: assert(false); break; | |
1821 } | |
1822 m_pDMI->setText(s_OpCol,s); | |
1823 | |
1824 e_MergeOperation eChildrenMergeOp = m_eMergeOperation; | |
1825 if ( eChildrenMergeOp == eConflictingFileTypes ) eChildrenMergeOp = eMergeABCToDest; | |
1826 for( int childIdx=0; childIdx<m_pDMI->childCount(); ++childIdx ) | |
1827 { | |
1828 QTreeWidgetItem* p = m_pDMI->child(childIdx); | |
1829 DirMergeItem* pDMI = static_cast<DirMergeItem*>( p ); | |
1830 DirectoryMergeWindow* pDMW = static_cast<DirectoryMergeWindow*>( p->treeWidget() ); | |
1831 pDMW->calcSuggestedOperation( *pDMI->m_pMFI, eChildrenMergeOp ); | |
1832 } | |
1833 } | |
1834 } | |
1835 | |
1836 void DirectoryMergeWindow::compareCurrentFile() | |
1837 { | |
1838 if (!canContinue()) return; | |
1839 | |
1840 if ( m_bRealMergeStarted ) | |
1841 { | |
1842 KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible")); | |
1843 return; | |
1844 } | |
1845 | |
1846 if ( currentItem() != 0 ) | |
1847 { | |
1848 DirMergeItem* pDMI = static_cast<DirMergeItem*>( currentItem() ); | |
1849 MergeFileInfos& mfi = *pDMI->m_pMFI; | |
1850 if ( !(mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC) ) | |
1851 { | |
1852 emit startDiffMerge( | |
1853 mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : QString(""), | |
1854 mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : QString(""), | |
1855 mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : QString(""), | |
1856 "", | |
1857 "","","",0 | |
1858 ); | |
1859 } | |
1860 } | |
1861 emit updateAvailabilities(); | |
1862 } | |
1863 | |
1864 | |
1865 void DirectoryMergeWindow::slotCompareExplicitlySelectedFiles() | |
1866 { | |
1867 if ( ! isDir(m_pSelection1Item,m_selection1Column) && !canContinue() ) return; | |
1868 | |
1869 if ( m_bRealMergeStarted ) | |
1870 { | |
1871 KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible")); | |
1872 return; | |
1873 } | |
1874 | |
1875 emit startDiffMerge( | |
1876 getFileName( m_pSelection1Item, m_selection1Column ), | |
1877 getFileName( m_pSelection2Item, m_selection2Column ), | |
1878 getFileName( m_pSelection3Item, m_selection3Column ), | |
1879 "", | |
1880 "","","",0 | |
1881 ); | |
1882 m_pSelection1Item=0; | |
1883 m_pSelection2Item=0; | |
1884 m_pSelection3Item=0; | |
1885 | |
1886 emit updateAvailabilities(); | |
1887 update(); | |
1888 } | |
1889 | |
1890 void DirectoryMergeWindow::slotMergeExplicitlySelectedFiles() | |
1891 { | |
1892 if ( ! isDir(m_pSelection1Item,m_selection1Column) && !canContinue() ) return; | |
1893 | |
1894 if ( m_bRealMergeStarted ) | |
1895 { | |
1896 KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible")); | |
1897 return; | |
1898 } | |
1899 | |
1900 QString fn1 = getFileName( m_pSelection1Item, m_selection1Column ); | |
1901 QString fn2 = getFileName( m_pSelection2Item, m_selection2Column ); | |
1902 QString fn3 = getFileName( m_pSelection3Item, m_selection3Column ); | |
1903 | |
1904 emit startDiffMerge( fn1, fn2, fn3, | |
1905 fn3.isEmpty() ? fn2 : fn3, | |
1906 "","","",0 | |
1907 ); | |
1908 m_pSelection1Item=0; | |
1909 m_pSelection2Item=0; | |
1910 m_pSelection3Item=0; | |
1911 | |
1912 emit updateAvailabilities(); | |
1913 update(); | |
1914 } | |
1915 | |
1916 bool DirectoryMergeWindow::isFileSelected() | |
1917 { | |
1918 if ( currentItem() != 0 ) | |
1919 { | |
1920 DirMergeItem* pDMI = static_cast<DirMergeItem*>( currentItem() ); | |
1921 MergeFileInfos& mfi = *pDMI->m_pMFI; | |
1922 return ! (mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC || conflictingFileTypes(mfi) ); | |
1923 } | |
1924 return false; | |
1925 } | |
1926 | |
1927 void DirectoryMergeWindow::mergeResultSaved(const QString& fileName) | |
1928 { | |
1929 DirMergeItem* pCurrentItemForOperation = (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() ) | |
1930 ? 0 | |
1931 : *m_currentItemForOperation; | |
1932 | |
1933 if ( pCurrentItemForOperation!=0 && pCurrentItemForOperation->m_pMFI==0 ) | |
1934 { | |
1935 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") ); | |
1936 return; | |
1937 } | |
1938 if ( pCurrentItemForOperation!=0 && fileName == fullNameDest(*pCurrentItemForOperation->m_pMFI) ) | |
1939 { | |
1940 if ( pCurrentItemForOperation->m_pMFI->m_eMergeOperation==eMergeToAB ) | |
1941 { | |
1942 MergeFileInfos& mfi = *pCurrentItemForOperation->m_pMFI; | |
1943 bool bSuccess = copyFLD( fullNameB(mfi), fullNameA(mfi) ); | |
1944 if (!bSuccess) | |
1945 { | |
1946 KMessageBox::error(this, i18n("An error occurred while copying.\n"), i18n("Error") ); | |
1947 m_pStatusInfo->setWindowTitle(i18n("Merge Error")); | |
1948 m_pStatusInfo->show(); | |
1949 //if ( m_pStatusInfo->firstChild()!=0 ) | |
1950 // m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() ); | |
1951 m_bError = true; | |
1952 pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Error.") ); | |
1953 mfi.m_eMergeOperation = eCopyBToA; | |
1954 return; | |
1955 } | |
1956 } | |
1957 pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Done.") ); | |
1958 pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true; | |
1959 if ( m_mergeItemList.size()==1 ) | |
1960 { | |
1961 m_mergeItemList.clear(); | |
1962 m_bRealMergeStarted=false; | |
1963 } | |
1964 } | |
1965 | |
1966 emit updateAvailabilities(); | |
1967 } | |
1968 | |
1969 bool DirectoryMergeWindow::canContinue() | |
1970 { | |
1971 bool bCanContinue=false; | |
1972 checkIfCanContinue( &bCanContinue ); | |
1973 if ( bCanContinue && !m_bError ) | |
1974 { | |
1975 DirMergeItem* pCurrentItemForOperation = | |
1976 (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() ) ? 0 : *m_currentItemForOperation; | |
1977 | |
1978 if ( pCurrentItemForOperation!=0 && ! pCurrentItemForOperation->m_pMFI->m_bOperationComplete ) | |
1979 { | |
1980 pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Not saved.") ); | |
1981 pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true; | |
1982 if ( m_mergeItemList.size()==1 ) | |
1983 { | |
1984 m_mergeItemList.clear(); | |
1985 m_bRealMergeStarted=false; | |
1986 } | |
1987 } | |
1988 } | |
1989 return bCanContinue; | |
1990 } | |
1991 | |
1992 bool DirectoryMergeWindow::executeMergeOperation( MergeFileInfos& mfi, bool& bSingleFileMerge ) | |
1993 { | |
1994 bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles; | |
1995 // First decide destname | |
1996 QString destName; | |
1997 switch( mfi.m_eMergeOperation ) | |
1998 { | |
1999 case eNoOperation: break; | |
2000 case eDeleteAB: break; | |
2001 case eMergeToAB: // let the user save in B. In mergeResultSaved() the file will be copied to A. | |
2002 case eMergeToB: | |
2003 case eDeleteB: | |
2004 case eCopyAToB: destName = fullNameB(mfi); break; | |
2005 case eMergeToA: | |
2006 case eDeleteA: | |
2007 case eCopyBToA: destName = fullNameA(mfi); break; | |
2008 case eMergeABToDest: | |
2009 case eMergeABCToDest: | |
2010 case eCopyAToDest: | |
2011 case eCopyBToDest: | |
2012 case eCopyCToDest: | |
2013 case eDeleteFromDest: destName = fullNameDest(mfi); break; | |
2014 default: | |
2015 KMessageBox::error( this, i18n("Unknown merge operation. (This must never happen!)"), i18n("Error") ); | |
2016 assert(false); | |
2017 } | |
2018 | |
2019 bool bSuccess = false; | |
2020 bSingleFileMerge = false; | |
2021 switch( mfi.m_eMergeOperation ) | |
2022 { | |
2023 case eNoOperation: bSuccess = true; break; | |
2024 case eCopyAToDest: | |
2025 case eCopyAToB: bSuccess = copyFLD( fullNameA(mfi), destName ); break; | |
2026 case eCopyBToDest: | |
2027 case eCopyBToA: bSuccess = copyFLD( fullNameB(mfi), destName ); break; | |
2028 case eCopyCToDest: bSuccess = copyFLD( fullNameC(mfi), destName ); break; | |
2029 case eDeleteFromDest: | |
2030 case eDeleteA: | |
2031 case eDeleteB: bSuccess = deleteFLD( destName, bCreateBackups ); break; | |
2032 case eDeleteAB: bSuccess = deleteFLD( fullNameA(mfi), bCreateBackups ) && | |
2033 deleteFLD( fullNameB(mfi), bCreateBackups ); break; | |
2034 case eMergeABToDest: | |
2035 case eMergeToA: | |
2036 case eMergeToAB: | |
2037 case eMergeToB: bSuccess = mergeFLD( fullNameA(mfi), fullNameB(mfi), "", | |
2038 destName, bSingleFileMerge ); | |
2039 break; | |
2040 case eMergeABCToDest:bSuccess = mergeFLD( | |
2041 mfi.m_bExistsInA ? fullNameA(mfi) : QString(""), | |
2042 mfi.m_bExistsInB ? fullNameB(mfi) : QString(""), | |
2043 mfi.m_bExistsInC ? fullNameC(mfi) : QString(""), | |
2044 destName, bSingleFileMerge ); | |
2045 break; | |
2046 default: | |
2047 KMessageBox::error( this, i18n("Unknown merge operation."), i18n("Error") ); | |
2048 assert(false); | |
2049 } | |
2050 | |
2051 return bSuccess; | |
2052 } | |
2053 | |
2054 | |
2055 // Check if the merge can start, and prepare the m_mergeItemList which then contains all | |
2056 // items that must be merged. | |
2057 void DirectoryMergeWindow::prepareMergeStart( QTreeWidgetItem* pBegin, QTreeWidgetItem* pEnd, bool bVerbose ) | |
2058 { | |
2059 if ( bVerbose ) | |
2060 { | |
2061 int status = KMessageBox::warningYesNoCancel(this, | |
2062 i18n("The merge is about to begin.\n\n" | |
2063 "Choose \"Do it\" if you have read the instructions and know what you are doing.\n" | |
2064 "Choosing \"Simulate it\" will tell you what would happen.\n\n" | |
2065 "Be aware that this program still has beta status " | |
2066 "and there is NO WARRANTY whatsoever! Make backups of your vital data!"), | |
2067 i18n("Starting Merge"), i18n("Do It"), i18n("Simulate It") ); | |
2068 if (status==KMessageBox::Yes) m_bRealMergeStarted = true; | |
2069 else if (status==KMessageBox::No ) m_bSimulatedMergeStarted = true; | |
2070 else return; | |
2071 } | |
2072 else | |
2073 { | |
2074 m_bRealMergeStarted = true; | |
2075 } | |
2076 | |
2077 m_mergeItemList.clear(); | |
2078 if (pBegin == 0) | |
2079 return; | |
2080 | |
2081 for( QTreeWidgetItem* p = pBegin; p!= pEnd; p = treeIterator( p ) ) | |
2082 { | |
2083 DirMergeItem* pDMI = static_cast<DirMergeItem*>(p); | |
2084 | |
2085 if ( pDMI && ! pDMI->m_pMFI->m_bOperationComplete ) | |
2086 { | |
2087 m_mergeItemList.push_back(pDMI); | |
2088 | |
2089 if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingFileTypes ) | |
2090 { | |
2091 scrollToItem( pDMI, QAbstractItemView::EnsureVisible ); | |
2092 pDMI->setSelected( true ); | |
2093 KMessageBox::error(this, i18n("The highlighted item has a different type in the different directories. Select what to do."), i18n("Error")); | |
2094 m_mergeItemList.clear(); | |
2095 m_bRealMergeStarted=false; | |
2096 return; | |
2097 } | |
2098 if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingAges ) | |
2099 { | |
2100 scrollToItem ( pDMI, QAbstractItemView::EnsureVisible ); | |
2101 pDMI->setSelected( true ); | |
2102 KMessageBox::error(this, i18n("The modification dates of the file are equal but the files are not. Select what to do."), i18n("Error")); | |
2103 m_mergeItemList.clear(); | |
2104 m_bRealMergeStarted=false; | |
2105 return; | |
2106 } | |
2107 } | |
2108 } | |
2109 | |
2110 m_currentItemForOperation = m_mergeItemList.begin(); | |
2111 return; | |
2112 } | |
2113 | |
2114 void DirectoryMergeWindow::slotRunOperationForCurrentItem() | |
2115 { | |
2116 if ( ! canContinue() ) return; | |
2117 | |
2118 bool bVerbose = false; | |
2119 if ( m_mergeItemList.empty() ) | |
2120 { | |
2121 QTreeWidgetItem* pBegin = currentItem(); | |
2122 QTreeWidgetItem* pEnd = treeIterator(pBegin,false,false); // find next visible sibling (no children) | |
2123 | |
2124 prepareMergeStart( pBegin, pEnd, bVerbose ); | |
2125 mergeContinue(true, bVerbose); | |
2126 } | |
2127 else | |
2128 mergeContinue(false, bVerbose); | |
2129 } | |
2130 | |
2131 void DirectoryMergeWindow::slotRunOperationForAllItems() | |
2132 { | |
2133 if ( ! canContinue() ) return; | |
2134 | |
2135 bool bVerbose = true; | |
2136 if ( m_mergeItemList.empty() ) | |
2137 { | |
2138 QTreeWidgetItem* pBegin = topLevelItemCount()>0 ? topLevelItem(0) : 0; | |
2139 | |
2140 prepareMergeStart( pBegin, 0, bVerbose ); | |
2141 mergeContinue(true, bVerbose); | |
2142 } | |
2143 else | |
2144 mergeContinue(false, bVerbose); | |
2145 } | |
2146 | |
2147 void DirectoryMergeWindow::mergeCurrentFile() | |
2148 { | |
2149 if (!canContinue()) return; | |
2150 | |
2151 if ( m_bRealMergeStarted ) | |
2152 { | |
2153 KMessageBox::sorry(this,i18n("This operation is currently not possible because directory merge is currently running."),i18n("Operation Not Possible")); | |
2154 return; | |
2155 } | |
2156 | |
2157 if ( isFileSelected() ) | |
2158 { | |
2159 DirMergeItem* pDMI = static_cast<DirMergeItem*>( currentItem() ); | |
2160 if ( pDMI != 0 ) | |
2161 { | |
2162 MergeFileInfos& mfi = *pDMI->m_pMFI; | |
2163 m_mergeItemList.clear(); | |
2164 m_mergeItemList.push_back( pDMI ); | |
2165 m_currentItemForOperation=m_mergeItemList.begin(); | |
2166 bool bDummy=false; | |
2167 mergeFLD( | |
2168 mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : QString(""), | |
2169 mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : QString(""), | |
2170 mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : QString(""), | |
2171 fullNameDest(mfi), | |
2172 bDummy | |
2173 ); | |
2174 } | |
2175 } | |
2176 emit updateAvailabilities(); | |
2177 } | |
2178 | |
2179 | |
2180 // When bStart is true then m_currentItemForOperation must still be processed. | |
2181 // When bVerbose is true then a messagebox will tell when the merge is complete. | |
2182 void DirectoryMergeWindow::mergeContinue(bool bStart, bool bVerbose) | |
2183 { | |
2184 ProgressProxy pp; | |
2185 if ( m_mergeItemList.empty() ) | |
2186 return; | |
2187 | |
2188 int nrOfItems = 0; | |
2189 int nrOfCompletedItems = 0; | |
2190 int nrOfCompletedSimItems = 0; | |
2191 | |
2192 // Count the number of completed items (for the progress bar). | |
2193 for( MergeItemList::iterator i = m_mergeItemList.begin(); i!=m_mergeItemList.end(); ++i ) | |
2194 { | |
2195 DirMergeItem* pDMI = *i; | |
2196 ++nrOfItems; | |
2197 if ( pDMI->m_pMFI->m_bOperationComplete ) | |
2198 ++nrOfCompletedItems; | |
2199 if ( pDMI->m_pMFI->m_bSimOpComplete ) | |
2200 ++nrOfCompletedSimItems; | |
2201 } | |
2202 | |
2203 m_pStatusInfo->hide(); | |
2204 m_pStatusInfo->clear(); | |
2205 | |
2206 DirMergeItem* pCurrentItemForOperation = m_currentItemForOperation==m_mergeItemList.end() ? 0 : *m_currentItemForOperation; | |
2207 | |
2208 bool bContinueWithCurrentItem = bStart; // true for first item, else false | |
2209 bool bSkipItem = false; | |
2210 if ( !bStart && m_bError && pCurrentItemForOperation!=0 ) | |
2211 { | |
2212 int status = KMessageBox::warningYesNoCancel(this, | |
2213 i18n("There was an error in the last step.\n" | |
2214 "Do you want to continue with the item that caused the error or do you want to skip this item?"), | |
2215 i18n("Continue merge after an error"), i18n("Continue With Last Item"), i18n("Skip Item") ); | |
2216 if (status==KMessageBox::Yes) bContinueWithCurrentItem = true; | |
2217 else if (status==KMessageBox::No ) bSkipItem = true; | |
2218 else return; | |
2219 m_bError = false; | |
2220 } | |
2221 | |
2222 bool bSuccess = true; | |
2223 bool bSingleFileMerge = false; | |
2224 bool bSim = m_bSimulatedMergeStarted; | |
2225 while( bSuccess ) | |
2226 { | |
2227 if ( pCurrentItemForOperation==0 ) | |
2228 { | |
2229 m_mergeItemList.clear(); | |
2230 m_bRealMergeStarted=false; | |
2231 break; | |
2232 } | |
2233 | |
2234 if ( pCurrentItemForOperation!=0 && !bContinueWithCurrentItem ) | |
2235 { | |
2236 if ( bSim ) | |
2237 { | |
2238 if( pCurrentItemForOperation->childCount()==0 ) | |
2239 { | |
2240 pCurrentItemForOperation->m_pMFI->m_bSimOpComplete = true; | |
2241 } | |
2242 } | |
2243 else | |
2244 { | |
2245 if( pCurrentItemForOperation->childCount()==0 ) | |
2246 { | |
2247 if( !pCurrentItemForOperation->m_pMFI->m_bOperationComplete ) | |
2248 { | |
2249 pCurrentItemForOperation->setText( s_OpStatusCol, bSkipItem ? i18n("Skipped.") : i18n("Done.") ); | |
2250 pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true; | |
2251 bSkipItem = false; | |
2252 } | |
2253 } | |
2254 else | |
2255 { | |
2256 pCurrentItemForOperation->setText( s_OpStatusCol, i18n("In progress...") ); | |
2257 } | |
2258 } | |
2259 } | |
2260 | |
2261 if ( ! bContinueWithCurrentItem ) | |
2262 { | |
2263 // Depth first | |
2264 QTreeWidgetItem* pPrevItem = pCurrentItemForOperation; | |
2265 ++m_currentItemForOperation; | |
2266 pCurrentItemForOperation = m_currentItemForOperation==m_mergeItemList.end() ? 0 : *m_currentItemForOperation; | |
2267 if ( (pCurrentItemForOperation==0 || pCurrentItemForOperation->parent()!=pPrevItem->parent()) && pPrevItem->parent()!=0 ) | |
2268 { | |
2269 // Check if the parent may be set to "Done" | |
2270 QTreeWidgetItem* pParent = pPrevItem->parent(); | |
2271 bool bDone = true; | |
2272 while ( bDone && pParent!=0 ) | |
2273 { | |
2274 for( int childIdx = 0; childIdx<pParent->childCount(); ++childIdx ) | |
2275 { | |
2276 DirMergeItem* pDMI = static_cast<DirMergeItem*>(pParent->child(childIdx)); | |
2277 if ( !bSim && ! pDMI->m_pMFI->m_bOperationComplete || bSim && pDMI->m_pMFI->m_bSimOpComplete ) | |
2278 { | |
2279 bDone=false; | |
2280 break; | |
2281 } | |
2282 } | |
2283 if ( bDone ) | |
2284 { | |
2285 if (bSim) | |
2286 static_cast<DirMergeItem*>(pParent)->m_pMFI->m_bSimOpComplete = bDone; | |
2287 else | |
2288 { | |
2289 pParent->setText( s_OpStatusCol, i18n("Done.") ); | |
2290 static_cast<DirMergeItem*>(pParent)->m_pMFI->m_bOperationComplete = bDone; | |
2291 } | |
2292 } | |
2293 pParent = pParent->parent(); | |
2294 } | |
2295 } | |
2296 } | |
2297 | |
2298 if ( pCurrentItemForOperation == 0 ) // end? | |
2299 { | |
2300 if ( m_bRealMergeStarted ) | |
2301 { | |
2302 if (bVerbose) | |
2303 { | |
2304 KMessageBox::information( this, i18n("Merge operation complete."), i18n("Merge Complete") ); | |
2305 } | |
2306 m_bRealMergeStarted = false; | |
2307 m_pStatusInfo->setWindowTitle(i18n("Merge Complete")); | |
2308 } | |
2309 if ( m_bSimulatedMergeStarted ) | |
2310 { | |
2311 m_bSimulatedMergeStarted = false; | |
2312 QTreeWidgetItem* p = topLevelItemCount()>0 ? topLevelItem(0) : 0; | |
2313 for( ; p!=0; p=treeIterator(p) ) | |
2314 { | |
2315 static_cast<DirMergeItem*>(p)->m_pMFI->m_bSimOpComplete = false; | |
2316 } | |
2317 m_pStatusInfo->setWindowTitle(i18n("Simulated merge complete: Check if you agree with the proposed operations.")); | |
2318 m_pStatusInfo->show(); | |
2319 } | |
2320 m_mergeItemList.clear(); | |
2321 m_bRealMergeStarted=false; | |
2322 return; | |
2323 } | |
2324 | |
2325 MergeFileInfos& mfi = *pCurrentItemForOperation->m_pMFI; | |
2326 | |
2327 pp.setInformation( mfi.m_subPath, | |
2328 bSim ? double(nrOfCompletedSimItems)/nrOfItems : double(nrOfCompletedItems)/nrOfItems, | |
2329 false // bRedrawUpdate | |
2330 ); | |
2331 | |
2332 bSuccess = executeMergeOperation( mfi, bSingleFileMerge ); // Here the real operation happens. | |
2333 | |
2334 if ( bSuccess ) | |
2335 { | |
2336 if(bSim) ++nrOfCompletedSimItems; | |
2337 else ++nrOfCompletedItems; | |
2338 bContinueWithCurrentItem = false; | |
2339 } | |
2340 | |
2341 if( pp.wasCancelled() ) | |
2342 break; | |
2343 } // end while | |
2344 | |
2345 //g_pProgressDialog->hide(); | |
2346 | |
2347 setCurrentItem( pCurrentItemForOperation ); | |
2348 scrollToItem( pCurrentItemForOperation, EnsureVisible ); | |
2349 if ( !bSuccess && !bSingleFileMerge ) | |
2350 { | |
2351 KMessageBox::error(this, i18n("An error occurred. Press OK to see detailed information.\n"), i18n("Error") ); | |
2352 m_pStatusInfo->setWindowTitle(i18n("Merge Error")); | |
2353 m_pStatusInfo->show(); | |
2354 //if ( m_pStatusInfo->firstChild()!=0 ) | |
2355 // m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() ); | |
2356 m_bError = true; | |
2357 pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Error.") ); | |
2358 } | |
2359 else | |
2360 { | |
2361 m_bError = false; | |
2362 } | |
2363 emit updateAvailabilities(); | |
2364 | |
2365 if ( m_currentItemForOperation==m_mergeItemList.end() ) | |
2366 { | |
2367 m_mergeItemList.clear(); | |
2368 m_bRealMergeStarted=false; | |
2369 } | |
2370 } | |
2371 | |
2372 void DirectoryMergeWindow::allowResizeEvents(bool bAllowResizeEvents ) | |
2373 { | |
2374 m_bAllowResizeEvents = bAllowResizeEvents; | |
2375 } | |
2376 | |
2377 void DirectoryMergeWindow::resizeEvent( QResizeEvent* e ) | |
2378 { | |
2379 if (m_bAllowResizeEvents) | |
2380 QTreeWidget::resizeEvent(e); | |
2381 } | |
2382 | |
2383 bool DirectoryMergeWindow::deleteFLD( const QString& name, bool bCreateBackup ) | |
2384 { | |
2385 FileAccess fi(name, true); | |
2386 if ( !fi.exists() ) | |
2387 return true; | |
2388 | |
2389 if ( bCreateBackup ) | |
2390 { | |
2391 bool bSuccess = renameFLD( name, name+".orig" ); | |
2392 if (!bSuccess) | |
2393 { | |
2394 m_pStatusInfo->addText( i18n("Error: While deleting %1: Creating backup failed.").arg(name) ); | |
2395 return false; | |
2396 } | |
2397 } | |
2398 else | |
2399 { | |
2400 if ( fi.isDir() && !fi.isSymLink() ) | |
2401 m_pStatusInfo->addText(i18n("delete directory recursively( %1 )").arg(name)); | |
2402 else | |
2403 m_pStatusInfo->addText(i18n("delete( %1 )").arg(name)); | |
2404 | |
2405 if ( m_bSimulatedMergeStarted ) | |
2406 { | |
2407 return true; | |
2408 } | |
2409 | |
2410 if ( fi.isDir() && !fi.isSymLink() )// recursive directory delete only for real dirs, not symlinks | |
2411 { | |
2412 t_DirectoryList dirList; | |
2413 bool bSuccess = fi.listDir( &dirList, false, true, "*", "", "", false, false ); // not recursive, find hidden files | |
2414 | |
2415 if ( !bSuccess ) | |
2416 { | |
2417 // No Permission to read directory or other error. | |
2418 m_pStatusInfo->addText( i18n("Error: delete dir operation failed while trying to read the directory.") ); | |
2419 return false; | |
2420 } | |
2421 | |
2422 t_DirectoryList::iterator it; // create list iterator | |
2423 | |
2424 for ( it=dirList.begin(); it!=dirList.end(); ++it ) // for each file... | |
2425 { | |
2426 FileAccess& fi2 = *it; | |
2427 if ( fi2.fileName() == "." || fi2.fileName()==".." ) | |
2428 continue; | |
2429 bSuccess = deleteFLD( fi2.absFilePath(), false ); | |
2430 if (!bSuccess) break; | |
2431 } | |
2432 if (bSuccess) | |
2433 { | |
2434 bSuccess = FileAccess::removeDir( name ); | |
2435 if ( !bSuccess ) | |
2436 { | |
2437 m_pStatusInfo->addText( i18n("Error: rmdir( %1 ) operation failed.").arg(name)); | |
2438 return false; | |
2439 } | |
2440 } | |
2441 } | |
2442 else | |
2443 { | |
2444 bool bSuccess = FileAccess::removeFile( name ); | |
2445 if ( !bSuccess ) | |
2446 { | |
2447 m_pStatusInfo->addText( i18n("Error: delete operation failed.") ); | |
2448 return false; | |
2449 } | |
2450 } | |
2451 } | |
2452 return true; | |
2453 } | |
2454 | |
2455 bool DirectoryMergeWindow::mergeFLD( const QString& nameA,const QString& nameB,const QString& nameC,const QString& nameDest, bool& bSingleFileMerge ) | |
2456 { | |
2457 FileAccess fi(nameA); | |
2458 if (fi.isDir()) | |
2459 { | |
2460 return makeDir(nameDest); | |
2461 } | |
2462 | |
2463 // Make sure that the dir exists, into which we will save the file later. | |
2464 int pos=nameDest.lastIndexOf('/'); | |
2465 if ( pos>0 ) | |
2466 { | |
2467 QString parentName = nameDest.left(pos); | |
2468 bool bSuccess = makeDir(parentName, true /*quiet*/); | |
2469 if (!bSuccess) | |
2470 return false; | |
2471 } | |
2472 | |
2473 m_pStatusInfo->addText(i18n("manual merge( %1, %2, %3 -> %4)").arg(nameA).arg(nameB).arg(nameC).arg(nameDest)); | |
2474 if ( m_bSimulatedMergeStarted ) | |
2475 { | |
2476 m_pStatusInfo->addText(i18n(" Note: After a manual merge the user should continue by pressing F7.") ); | |
2477 return true; | |
2478 } | |
2479 | |
2480 bSingleFileMerge = true; | |
2481 (*m_currentItemForOperation)->setText( s_OpStatusCol, i18n("In progress...") ); | |
2482 scrollToItem( *m_currentItemForOperation, EnsureVisible ); | |
2483 | |
2484 emit startDiffMerge( nameA, nameB, nameC, nameDest, "","","",0 ); | |
2485 | |
2486 return false; | |
2487 } | |
2488 | |
2489 bool DirectoryMergeWindow::copyFLD( const QString& srcName, const QString& destName ) | |
2490 { | |
2491 if ( srcName == destName ) | |
2492 return true; | |
2493 | |
2494 if ( FileAccess(destName, true).exists() ) | |
2495 { | |
2496 bool bSuccess = deleteFLD( destName, m_pOptions->m_bDmCreateBakFiles ); | |
2497 if ( !bSuccess ) | |
2498 { | |
2499 m_pStatusInfo->addText(i18n("Error: copy( %1 -> %2 ) failed." | |
2500 "Deleting existing destination failed.").arg(srcName).arg(destName)); | |
2501 return false; | |
2502 } | |
2503 } | |
2504 | |
2505 FileAccess fi( srcName ); | |
2506 | |
2507 if ( fi.isSymLink() && (fi.isDir() && !m_bFollowDirLinks || !fi.isDir() && !m_bFollowFileLinks) ) | |
2508 { | |
2509 m_pStatusInfo->addText(i18n("copyLink( %1 -> %2 )").arg(srcName).arg(destName)); | |
2510 #ifdef _WIN32 | |
2511 // What are links? | |
2512 #else | |
2513 if ( m_bSimulatedMergeStarted ) | |
2514 { | |
2515 return true; | |
2516 } | |
2517 FileAccess destFi(destName); | |
2518 if ( !destFi.isLocal() || !fi.isLocal() ) | |
2519 { | |
2520 m_pStatusInfo->addText(i18n("Error: copyLink failed: Remote links are not yet supported.")); | |
2521 return false; | |
2522 } | |
2523 QString linkTarget = fi.readLink(); | |
2524 bool bSuccess = FileAccess::symLink( linkTarget, destName ); | |
2525 if (!bSuccess) | |
2526 m_pStatusInfo->addText(i18n("Error: copyLink failed.")); | |
2527 return bSuccess; | |
2528 #endif | |
2529 } | |
2530 | |
2531 if ( fi.isDir() ) | |
2532 { | |
2533 bool bSuccess = makeDir( destName ); | |
2534 return bSuccess; | |
2535 } | |
2536 | |
2537 int pos=destName.lastIndexOf('/'); | |
2538 if ( pos>0 ) | |
2539 { | |
2540 QString parentName = destName.left(pos); | |
2541 bool bSuccess = makeDir(parentName, true /*quiet*/); | |
2542 if (!bSuccess) | |
2543 return false; | |
2544 } | |
2545 | |
2546 m_pStatusInfo->addText(i18n("copy( %1 -> %2 )").arg(srcName).arg(destName)); | |
2547 | |
2548 if ( m_bSimulatedMergeStarted ) | |
2549 { | |
2550 return true; | |
2551 } | |
2552 | |
2553 FileAccess faSrc ( srcName ); | |
2554 bool bSuccess = faSrc.copyFile( destName ); | |
2555 if (! bSuccess ) m_pStatusInfo->addText( faSrc.getStatusText() ); | |
2556 return bSuccess; | |
2557 } | |
2558 | |
2559 // Rename is not an operation that can be selected by the user. | |
2560 // It will only be used to create backups. | |
2561 // Hence it will delete an existing destination without making a backup (of the old backup.) | |
2562 bool DirectoryMergeWindow::renameFLD( const QString& srcName, const QString& destName ) | |
2563 { | |
2564 if ( srcName == destName ) | |
2565 return true; | |
2566 | |
2567 if ( FileAccess(destName, true).exists() ) | |
2568 { | |
2569 bool bSuccess = deleteFLD( destName, false /*no backup*/ ); | |
2570 if (!bSuccess) | |
2571 { | |
2572 m_pStatusInfo->addText( i18n("Error during rename( %1 -> %2 ): " | |
2573 "Cannot delete existing destination." ).arg(srcName).arg(destName)); | |
2574 return false; | |
2575 } | |
2576 } | |
2577 | |
2578 m_pStatusInfo->addText(i18n("rename( %1 -> %2 )").arg(srcName).arg(destName)); | |
2579 if ( m_bSimulatedMergeStarted ) | |
2580 { | |
2581 return true; | |
2582 } | |
2583 | |
2584 bool bSuccess = FileAccess( srcName ).rename( destName ); | |
2585 if (!bSuccess) | |
2586 { | |
2587 m_pStatusInfo->addText( i18n("Error: Rename failed.") ); | |
2588 return false; | |
2589 } | |
2590 | |
2591 return true; | |
2592 } | |
2593 | |
2594 bool DirectoryMergeWindow::makeDir( const QString& name, bool bQuiet ) | |
2595 { | |
2596 FileAccess fi(name, true); | |
2597 if( fi.exists() && fi.isDir() ) | |
2598 return true; | |
2599 | |
2600 if( fi.exists() && !fi.isDir() ) | |
2601 { | |
2602 bool bSuccess = deleteFLD( name, true ); | |
2603 if (!bSuccess) | |
2604 { | |
2605 m_pStatusInfo->addText( i18n("Error during makeDir of %1. " | |
2606 "Cannot delete existing file." ).arg(name)); | |
2607 return false; | |
2608 } | |
2609 } | |
2610 | |
2611 int pos=name.lastIndexOf('/'); | |
2612 if ( pos>0 ) | |
2613 { | |
2614 QString parentName = name.left(pos); | |
2615 bool bSuccess = makeDir(parentName,true); | |
2616 if (!bSuccess) | |
2617 return false; | |
2618 } | |
2619 | |
2620 if ( ! bQuiet ) | |
2621 m_pStatusInfo->addText(i18n("makeDir( %1 )").arg(name)); | |
2622 | |
2623 if ( m_bSimulatedMergeStarted ) | |
2624 { | |
2625 return true; | |
2626 } | |
2627 | |
2628 bool bSuccess = FileAccess::makeDir( name ); | |
2629 if ( bSuccess == false ) | |
2630 { | |
2631 m_pStatusInfo->addText( i18n("Error while creating directory.") ); | |
2632 return false; | |
2633 } | |
2634 return true; | |
2635 } | |
2636 | |
2637 | |
2638 DirectoryMergeInfo::DirectoryMergeInfo( QWidget* pParent ) | |
2639 : QFrame(pParent) | |
2640 { | |
2641 QVBoxLayout *topLayout = new QVBoxLayout( this ); | |
2642 topLayout->setMargin(0); | |
2643 | |
2644 QGridLayout *grid = new QGridLayout(); | |
2645 topLayout->addLayout(grid); | |
2646 grid->setColumnStretch(1,10); | |
2647 | |
2648 int line=0; | |
2649 | |
2650 m_pA = new QLabel("A",this); grid->addWidget( m_pA,line, 0 ); | |
2651 m_pInfoA = new QLabel(this); grid->addWidget( m_pInfoA,line,1 ); ++line; | |
2652 m_pB = new QLabel("B",this); grid->addWidget( m_pB,line, 0 ); | |
2653 m_pInfoB = new QLabel(this); grid->addWidget( m_pInfoB,line,1 ); ++line; | |
2654 m_pC = new QLabel("C",this); grid->addWidget( m_pC,line, 0 ); | |
2655 m_pInfoC = new QLabel(this); grid->addWidget( m_pInfoC,line,1 ); ++line; | |
2656 m_pDest = new QLabel(i18n("Dest"),this); grid->addWidget( m_pDest,line, 0 ); | |
2657 m_pInfoDest = new QLabel(this); grid->addWidget( m_pInfoDest,line,1 ); ++line; | |
2658 | |
2659 m_pInfoList = new QTreeWidget(this); topLayout->addWidget( m_pInfoList ); | |
2660 m_pInfoList->setHeaderLabels( QStringList() << i18n("Dir") << i18n("Type") << i18n("Size") | |
2661 << i18n("Attr") << i18n("Last Modification") << i18n("Link-Destination") ); | |
2662 setMinimumSize( 100,100 ); | |
2663 | |
2664 m_pInfoList->installEventFilter(this); | |
2665 m_pInfoList->setRootIsDecorated( false ); | |
2666 } | |
2667 | |
2668 bool DirectoryMergeInfo::eventFilter(QObject*o, QEvent* e) | |
2669 { | |
2670 if ( e->type()==QEvent::FocusIn && o==m_pInfoList ) | |
2671 emit gotFocus(); | |
2672 return false; | |
2673 } | |
2674 | |
2675 static void addListViewItem( QTreeWidget* pListView, const QString& dir, | |
2676 const QString& basePath, FileAccess& fi ) | |
2677 { | |
2678 if ( basePath.isEmpty() ) | |
2679 { | |
2680 return; | |
2681 } | |
2682 else | |
2683 { | |
2684 if ( fi.exists() ) | |
2685 { | |
2686 QString dateString = fi.lastModified().toString("yyyy-MM-dd hh:mm:ss"); | |
2687 | |
2688 new QTreeWidgetItem( | |
2689 pListView, | |
2690 QStringList() << dir << | |
2691 QString( fi.isDir() ? i18n("Dir") : i18n("File") ) + (fi.isSymLink() ? "-Link" : "") << | |
2692 QString::number(fi.size()) << | |
2693 QString(fi.isReadable() ? "r" : " ") + (fi.isWritable()?"w" : " ") | |
2694 #ifdef _WIN32 | |
2695 /*Future: Use GetFileAttributes()*/ << | |
2696 #else | |
2697 + (fi.isExecutable()?"x" : " ") << | |
2698 #endif | |
2699 dateString << | |
2700 QString(fi.isSymLink() ? (" -> " + fi.readLink()) : QString("")) | |
2701 ); | |
2702 } | |
2703 else | |
2704 { | |
2705 new QTreeWidgetItem( | |
2706 pListView, | |
2707 QStringList() << dir << | |
2708 i18n("not available") << | |
2709 "" << | |
2710 "" << | |
2711 "" << | |
2712 "" | |
2713 ); | |
2714 } | |
2715 } | |
2716 } | |
2717 | |
2718 void DirectoryMergeInfo::setInfo( | |
2719 const FileAccess& dirA, | |
2720 const FileAccess& dirB, | |
2721 const FileAccess& dirC, | |
2722 const FileAccess& dirDest, | |
2723 MergeFileInfos& mfi ) | |
2724 { | |
2725 bool bHideDest = false; | |
2726 if ( dirA.absFilePath()==dirDest.absFilePath() ) | |
2727 { | |
2728 m_pA->setText( i18n("A (Dest): ") ); bHideDest=true; | |
2729 } | |
2730 else | |
2731 m_pA->setText( !dirC.isValid() ? QString("A: ") : i18n("A (Base): ")); | |
2732 | |
2733 m_pInfoA->setText( dirA.prettyAbsPath() ); | |
2734 | |
2735 if ( dirB.absFilePath()==dirDest.absFilePath() ) | |
2736 { | |
2737 m_pB->setText( i18n("B (Dest): ") ); bHideDest=true; | |
2738 } | |
2739 else | |
2740 m_pB->setText( "B: " ); | |
2741 m_pInfoB->setText( dirB.prettyAbsPath() ); | |
2742 | |
2743 if ( dirC.absFilePath()==dirDest.absFilePath() ) | |
2744 { | |
2745 m_pC->setText( i18n("C (Dest): ") ); bHideDest=true; | |
2746 } | |
2747 else | |
2748 m_pC->setText( "C: " ); | |
2749 m_pInfoC->setText( dirC.prettyAbsPath() ); | |
2750 | |
2751 m_pDest->setText( i18n("Dest: ") ); m_pInfoDest->setText( dirDest.prettyAbsPath() ); | |
2752 | |
2753 if (!dirC.isValid()) { m_pC->hide(); m_pInfoC->hide(); } | |
2754 else { m_pC->show(); m_pInfoC->show(); } | |
2755 | |
2756 if (!dirDest.isValid()||bHideDest) { m_pDest->hide(); m_pInfoDest->hide(); } | |
2757 else { m_pDest->show(); m_pInfoDest->show(); } | |
2758 | |
2759 m_pInfoList->clear(); | |
2760 addListViewItem( m_pInfoList, "A", dirA.prettyAbsPath(), mfi.m_fileInfoA ); | |
2761 addListViewItem( m_pInfoList, "B", dirB.prettyAbsPath(), mfi.m_fileInfoB ); | |
2762 addListViewItem( m_pInfoList, "C", dirC.prettyAbsPath(), mfi.m_fileInfoC ); | |
2763 if (!bHideDest) | |
2764 { | |
2765 FileAccess fiDest( dirDest.prettyAbsPath() + "/" + mfi.m_subPath, true ); | |
2766 addListViewItem( m_pInfoList, i18n("Dest"), dirDest.prettyAbsPath(), fiDest ); | |
2767 } | |
2768 for (int i=0;i<m_pInfoList->columnCount();++i) | |
2769 m_pInfoList->resizeColumnToContents ( i ); | |
2770 } | |
2771 | |
2772 QTextStream& operator<<( QTextStream& ts, MergeFileInfos& mfi ) | |
2773 { | |
2774 ts << "{\n"; | |
2775 ValueMap vm; | |
2776 vm.writeEntry( "SubPath", mfi.m_subPath ); | |
2777 vm.writeEntry( "ExistsInA", mfi.m_bExistsInA ); | |
2778 vm.writeEntry( "ExistsInB", mfi.m_bExistsInB ); | |
2779 vm.writeEntry( "ExistsInC", mfi.m_bExistsInC ); | |
2780 vm.writeEntry( "EqualAB", mfi.m_bEqualAB ); | |
2781 vm.writeEntry( "EqualAC", mfi.m_bEqualAC ); | |
2782 vm.writeEntry( "EqualBC", mfi.m_bEqualBC ); | |
2783 //DirMergeItem* m_pDMI; | |
2784 //MergeFileInfos* m_pParent; | |
2785 vm.writeEntry( "MergeOperation", (int) mfi.m_eMergeOperation ); | |
2786 vm.writeEntry( "DirA", mfi.m_bDirA ); | |
2787 vm.writeEntry( "DirB", mfi.m_bDirB ); | |
2788 vm.writeEntry( "DirC", mfi.m_bDirC ); | |
2789 vm.writeEntry( "LinkA", mfi.m_bLinkA ); | |
2790 vm.writeEntry( "LinkB", mfi.m_bLinkB ); | |
2791 vm.writeEntry( "LinkC", mfi.m_bLinkC ); | |
2792 vm.writeEntry( "OperationComplete", mfi.m_bOperationComplete ); | |
2793 //bool m_bSimOpComplete ); | |
2794 | |
2795 vm.writeEntry( "AgeA", (int) mfi.m_ageA ); | |
2796 vm.writeEntry( "AgeB", (int) mfi.m_ageB ); | |
2797 vm.writeEntry( "AgeC", (int) mfi.m_ageC ); | |
2798 vm.writeEntry( "ConflictingAges", mfi.m_bConflictingAges ); // Equal age but files are not! | |
2799 | |
2800 //FileAccess m_fileInfoA; | |
2801 //FileAccess m_fileInfoB; | |
2802 //FileAccess m_fileInfoC; | |
2803 | |
2804 //TotalDiffStatus m_totalDiffStatus; | |
2805 | |
2806 vm.save(ts); | |
2807 | |
2808 ts << "}\n"; | |
2809 | |
2810 return ts; | |
2811 } | |
2812 | |
2813 void DirectoryMergeWindow::slotSaveMergeState() | |
2814 { | |
2815 //slotStatusMsg(i18n("Saving Directory Merge State ...")); | |
2816 | |
2817 //QString s = KFileDialog::getSaveURL( QDir::currentDirPath(), 0, this, i18n("Save As...") ).url(); | |
2818 QString s = KFileDialog::getSaveFileName( QDir::currentPath(), 0, this, i18n("Save Directory Merge State As...") ); | |
2819 if(!s.isEmpty()) | |
2820 { | |
2821 m_dirMergeStateFilename = s; | |
2822 | |
2823 | |
2824 QFile file(m_dirMergeStateFilename); | |
2825 bool bSuccess = file.open( QIODevice::WriteOnly ); | |
2826 if ( bSuccess ) | |
2827 { | |
2828 QTextStream ts( &file ); | |
2829 | |
2830 QTreeWidgetItemIterator it( this ); | |
2831 while ( *it ) { | |
2832 DirMergeItem* item = static_cast<DirMergeItem*>(*it); | |
2833 MergeFileInfos* pMFI = item->m_pMFI; | |
2834 ts << *pMFI; | |
2835 ++it; | |
2836 } | |
2837 } | |
2838 } | |
2839 | |
2840 //slotStatusMsg(i18n("Ready.")); | |
2841 | |
2842 } | |
2843 | |
2844 void DirectoryMergeWindow::slotLoadMergeState() | |
2845 { | |
2846 } | |
2847 | |
2848 void DirectoryMergeWindow::updateFileVisibilities() | |
2849 { | |
2850 bool bShowIdentical = m_pDirShowIdenticalFiles->isChecked(); | |
2851 bool bShowDifferent = m_pDirShowDifferentFiles->isChecked(); | |
2852 bool bShowOnlyInA = m_pDirShowFilesOnlyInA->isChecked(); | |
2853 bool bShowOnlyInB = m_pDirShowFilesOnlyInB->isChecked(); | |
2854 bool bShowOnlyInC = m_pDirShowFilesOnlyInC->isChecked(); | |
2855 bool bThreeDirs = m_dirC.isValid(); | |
2856 m_pSelection1Item = 0; | |
2857 m_pSelection2Item = 0; | |
2858 m_pSelection3Item = 0; | |
2859 | |
2860 QTreeWidgetItem* p = topLevelItemCount()>0 ? topLevelItem(0) : 0; | |
2861 while(p) | |
2862 { | |
2863 DirMergeItem* pDMI = static_cast<DirMergeItem*>(p); | |
2864 MergeFileInfos* pMFI = pDMI->m_pMFI; | |
2865 bool bDir = pMFI->m_bDirA || pMFI->m_bDirB || pMFI->m_bDirC; | |
2866 bool bExistsEverywhere = pMFI->m_bExistsInA && pMFI->m_bExistsInB && (pMFI->m_bExistsInC || !bThreeDirs); | |
2867 int existCount = int(pMFI->m_bExistsInA) + int(pMFI->m_bExistsInB) + int(pMFI->m_bExistsInC); | |
2868 bool bVisible = | |
2869 ( bShowIdentical && bExistsEverywhere && pMFI->m_bEqualAB && (pMFI->m_bEqualAC || !bThreeDirs) ) | |
2870 || ( (bShowDifferent||bDir) && existCount>=2 && (!pMFI->m_bEqualAB || !(pMFI->m_bEqualAC || !bThreeDirs))) | |
2871 || ( bShowOnlyInA && pMFI->m_bExistsInA && !pMFI->m_bExistsInB && !pMFI->m_bExistsInC ) | |
2872 || ( bShowOnlyInB && !pMFI->m_bExistsInA && pMFI->m_bExistsInB && !pMFI->m_bExistsInC ) | |
2873 || ( bShowOnlyInC && !pMFI->m_bExistsInA && !pMFI->m_bExistsInB && pMFI->m_bExistsInC ); | |
2874 | |
2875 QString fileName = pMFI->m_subPath.section( '/', -1 ); | |
2876 bVisible = bVisible && ( | |
2877 bDir && ! wildcardMultiMatch( m_pOptions->m_DmDirAntiPattern, fileName, m_bCaseSensitive ) | |
2878 || wildcardMultiMatch( m_pOptions->m_DmFilePattern, fileName, m_bCaseSensitive ) | |
2879 && !wildcardMultiMatch( m_pOptions->m_DmFileAntiPattern, fileName, m_bCaseSensitive ) ); | |
2880 | |
2881 p->setHidden(!bVisible); | |
2882 p = treeIterator( p, true, true ); | |
2883 } | |
2884 } | |
2885 | |
2886 void DirectoryMergeWindow::slotShowIdenticalFiles() { m_pOptions->m_bDmShowIdenticalFiles=m_pDirShowIdenticalFiles->isChecked(); | |
2887 updateFileVisibilities(); } | |
2888 void DirectoryMergeWindow::slotShowDifferentFiles() { updateFileVisibilities(); } | |
2889 void DirectoryMergeWindow::slotShowFilesOnlyInA() { updateFileVisibilities(); } | |
2890 void DirectoryMergeWindow::slotShowFilesOnlyInB() { updateFileVisibilities(); } | |
2891 void DirectoryMergeWindow::slotShowFilesOnlyInC() { updateFileVisibilities(); } | |
2892 | |
2893 void DirectoryMergeWindow::slotSynchronizeDirectories() { } | |
2894 void DirectoryMergeWindow::slotChooseNewerFiles() { } | |
2895 | |
2896 void DirectoryMergeWindow::initDirectoryMergeActions( QObject* pKDiff3App, KActionCollection* ac ) | |
2897 { | |
2898 #include "xpm/startmerge.xpm" | |
2899 #include "xpm/showequalfiles.xpm" | |
2900 #include "xpm/showfilesonlyina.xpm" | |
2901 #include "xpm/showfilesonlyinb.xpm" | |
2902 #include "xpm/showfilesonlyinc.xpm" | |
2903 DirectoryMergeWindow* p = this; | |
2904 | |
2905 m_pDirStartOperation = new KAction(i18n("Start/Continue Directory Merge"), Qt::Key_F7, p, SLOT(slotRunOperationForAllItems()), ac, "dir_start_operation"); | |
2906 m_pDirRunOperationForCurrentItem = new KAction(i18n("Run Operation for Current Item"), Qt::Key_F6, p, SLOT(slotRunOperationForCurrentItem()), ac, "dir_run_operation_for_current_item"); | |
2907 m_pDirCompareCurrent = new KAction(i18n("Compare Selected File"), 0, p, SLOT(compareCurrentFile()), ac, "dir_compare_current"); | |
2908 m_pDirMergeCurrent = new KAction(i18n("Merge Current File"), QIcon(QPixmap(startmerge)), 0, pKDiff3App, SLOT(slotMergeCurrentFile()), ac, "merge_current"); | |
2909 m_pDirFoldAll = new KAction(i18n("Fold All Subdirs"), 0, p, SLOT(slotFoldAllSubdirs()), ac, "dir_fold_all"); | |
2910 m_pDirUnfoldAll = new KAction(i18n("Unfold All Subdirs"), 0, p, SLOT(slotUnfoldAllSubdirs()), ac, "dir_unfold_all"); | |
2911 m_pDirRescan = new KAction(i18n("Rescan"), Qt::SHIFT+Qt::Key_F5, p, SLOT(reload()), ac, "dir_rescan"); | |
2912 m_pDirSaveMergeState = 0; //new KAction(i18n("Save Directory Merge State ..."), 0, p, SLOT(slotSaveMergeState()), ac, "dir_save_merge_state"); | |
2913 m_pDirLoadMergeState = 0; //new KAction(i18n("Load Directory Merge State ..."), 0, p, SLOT(slotLoadMergeState()), ac, "dir_load_merge_state"); | |
2914 m_pDirChooseAEverywhere = new KAction(i18n("Choose A for All Items"), 0, p, SLOT(slotChooseAEverywhere()), ac, "dir_choose_a_everywhere"); | |
2915 m_pDirChooseBEverywhere = new KAction(i18n("Choose B for All Items"), 0, p, SLOT(slotChooseBEverywhere()), ac, "dir_choose_b_everywhere"); | |
2916 m_pDirChooseCEverywhere = new KAction(i18n("Choose C for All Items"), 0, p, SLOT(slotChooseCEverywhere()), ac, "dir_choose_c_everywhere"); | |
2917 m_pDirAutoChoiceEverywhere = new KAction(i18n("Auto-Choose Operation for All Items"), 0, p, SLOT(slotAutoChooseEverywhere()), ac, "dir_autochoose_everywhere"); | |
2918 m_pDirDoNothingEverywhere = new KAction(i18n("No Operation for All Items"), 0, p, SLOT(slotNoOpEverywhere()), ac, "dir_nothing_everywhere"); | |
2919 | |
2920 // m_pDirSynchronizeDirectories = new KToggleAction(i18n("Synchronize Directories"), 0, this, SLOT(slotSynchronizeDirectories()), ac, "dir_synchronize_directories"); | |
2921 // m_pDirChooseNewerFiles = new KToggleAction(i18n("Copy Newer Files Instead of Merging"), 0, this, SLOT(slotChooseNewerFiles()), ac, "dir_choose_newer_files"); | |
2922 | |
2923 m_pDirShowIdenticalFiles = new KToggleAction(i18n("Show Identical Files"), QIcon(QPixmap(showequalfiles)), 0, this, SLOT(slotShowIdenticalFiles()), ac, "dir_show_identical_files"); | |
2924 m_pDirShowDifferentFiles = new KToggleAction(i18n("Show Different Files"), 0, this, SLOT(slotShowDifferentFiles()), ac, "dir_show_different_files"); | |
2925 m_pDirShowFilesOnlyInA = new KToggleAction(i18n("Show Files only in A"), QIcon(QPixmap(showfilesonlyina)), 0, this, SLOT(slotShowFilesOnlyInA()), ac, "dir_show_files_only_in_a"); | |
2926 m_pDirShowFilesOnlyInB = new KToggleAction(i18n("Show Files only in B"), QIcon(QPixmap(showfilesonlyinb)), 0, this, SLOT(slotShowFilesOnlyInB()), ac, "dir_show_files_only_in_b"); | |
2927 m_pDirShowFilesOnlyInC = new KToggleAction(i18n("Show Files only in C"), QIcon(QPixmap(showfilesonlyinc)), 0, this, SLOT(slotShowFilesOnlyInC()), ac, "dir_show_files_only_in_c"); | |
2928 | |
2929 m_pDirShowIdenticalFiles->setChecked( m_pOptions->m_bDmShowIdenticalFiles ); | |
2930 | |
2931 m_pDirCompareExplicit = new KAction(i18n("Compare Explicitly Selected Files"), 0, p, SLOT(slotCompareExplicitlySelectedFiles()), ac, "dir_compare_explicitly_selected_files"); | |
2932 m_pDirMergeExplicit = new KAction(i18n("Merge Explicitly Selected Files"), 0, p, SLOT(slotMergeExplicitlySelectedFiles()), ac, "dir_merge_explicitly_selected_files"); | |
2933 | |
2934 m_pDirCurrentDoNothing = new KAction(i18n("Do Nothing"), 0, p, SLOT(slotCurrentDoNothing()), ac, "dir_current_do_nothing"); | |
2935 m_pDirCurrentChooseA = new KAction(i18n("A"), 0, p, SLOT(slotCurrentChooseA()), ac, "dir_current_choose_a"); | |
2936 m_pDirCurrentChooseB = new KAction(i18n("B"), 0, p, SLOT(slotCurrentChooseB()), ac, "dir_current_choose_b"); | |
2937 m_pDirCurrentChooseC = new KAction(i18n("C"), 0, p, SLOT(slotCurrentChooseC()), ac, "dir_current_choose_c"); | |
2938 m_pDirCurrentMerge = new KAction(i18n("Merge"), 0, p, SLOT(slotCurrentMerge()), ac, "dir_current_merge"); | |
2939 m_pDirCurrentDelete = new KAction(i18n("Delete (if exists)"), 0, p, SLOT(slotCurrentDelete()), ac, "dir_current_delete"); | |
2940 | |
2941 m_pDirCurrentSyncDoNothing = new KAction(i18n("Do Nothing"), 0, p, SLOT(slotCurrentDoNothing()), ac, "dir_current_sync_do_nothing"); | |
2942 m_pDirCurrentSyncCopyAToB = new KAction(i18n("Copy A to B"), 0, p, SLOT(slotCurrentCopyAToB()), ac, "dir_current_sync_copy_a_to_b" ); | |
2943 m_pDirCurrentSyncCopyBToA = new KAction(i18n("Copy B to A"), 0, p, SLOT(slotCurrentCopyBToA()), ac, "dir_current_sync_copy_b_to_a" ); | |
2944 m_pDirCurrentSyncDeleteA = new KAction(i18n("Delete A"), 0, p, SLOT(slotCurrentDeleteA()), ac,"dir_current_sync_delete_a"); | |
2945 m_pDirCurrentSyncDeleteB = new KAction(i18n("Delete B"), 0, p, SLOT(slotCurrentDeleteB()), ac,"dir_current_sync_delete_b"); | |
2946 m_pDirCurrentSyncDeleteAAndB = new KAction(i18n("Delete A && B"), 0, p, SLOT(slotCurrentDeleteAAndB()), ac,"dir_current_sync_delete_a_and_b"); | |
2947 m_pDirCurrentSyncMergeToA = new KAction(i18n("Merge to A"), 0, p, SLOT(slotCurrentMergeToA()), ac,"dir_current_sync_merge_to_a"); | |
2948 m_pDirCurrentSyncMergeToB = new KAction(i18n("Merge to B"), 0, p, SLOT(slotCurrentMergeToB()), ac,"dir_current_sync_merge_to_b"); | |
2949 m_pDirCurrentSyncMergeToAAndB = new KAction(i18n("Merge to A && B"), 0, p, SLOT(slotCurrentMergeToAAndB()), ac,"dir_current_sync_merge_to_a_and_b"); | |
2950 | |
2951 | |
2952 } | |
2953 | |
2954 | |
2955 void DirectoryMergeWindow::updateAvailabilities( bool bDirCompare, bool bDiffWindowVisible, | |
2956 KToggleAction* chooseA, KToggleAction* chooseB, KToggleAction* chooseC ) | |
2957 { | |
2958 m_pDirStartOperation->setEnabled( bDirCompare ); | |
2959 m_pDirRunOperationForCurrentItem->setEnabled( bDirCompare ); | |
2960 m_pDirFoldAll->setEnabled( bDirCompare ); | |
2961 m_pDirUnfoldAll->setEnabled( bDirCompare ); | |
2962 | |
2963 m_pDirCompareCurrent->setEnabled( bDirCompare && isVisible() && isFileSelected() ); | |
2964 | |
2965 m_pDirMergeCurrent->setEnabled( bDirCompare && isVisible() && isFileSelected() | |
2966 || bDiffWindowVisible ); | |
2967 | |
2968 m_pDirRescan->setEnabled( bDirCompare ); | |
2969 | |
2970 m_pDirAutoChoiceEverywhere->setEnabled( bDirCompare && isVisible() ); | |
2971 m_pDirDoNothingEverywhere->setEnabled( bDirCompare && isVisible() ); | |
2972 m_pDirChooseAEverywhere->setEnabled( bDirCompare && isVisible() ); | |
2973 m_pDirChooseBEverywhere->setEnabled( bDirCompare && isVisible() ); | |
2974 m_pDirChooseCEverywhere->setEnabled( bDirCompare && isVisible() ); | |
2975 | |
2976 bool bThreeDirs = m_dirC.isValid(); | |
2977 | |
2978 QTreeWidgetItem* lvi = currentItem(); | |
2979 DirMergeItem* pDMI = lvi==0 ? 0 : static_cast<DirMergeItem*>(lvi); | |
2980 MergeFileInfos* pMFI = pDMI==0 ? 0 : pDMI->m_pMFI; | |
2981 | |
2982 bool bItemActive = bDirCompare && isVisible() && pMFI!=0;// && hasFocus(); | |
2983 bool bMergeMode = bThreeDirs || !m_bSyncMode; | |
2984 bool bFTConflict = pMFI==0 ? false : conflictingFileTypes(*pMFI); | |
2985 | |
2986 bool bDirWindowHasFocus = isVisible() && hasFocus(); | |
2987 | |
2988 m_pDirShowIdenticalFiles->setEnabled( bDirCompare && isVisible() ); | |
2989 m_pDirShowDifferentFiles->setEnabled( bDirCompare && isVisible() ); | |
2990 m_pDirShowFilesOnlyInA->setEnabled( bDirCompare && isVisible() ); | |
2991 m_pDirShowFilesOnlyInB->setEnabled( bDirCompare && isVisible() ); | |
2992 m_pDirShowFilesOnlyInC->setEnabled( bDirCompare && isVisible() && bThreeDirs ); | |
2993 | |
2994 m_pDirCompareExplicit->setEnabled( bDirCompare && isVisible() && m_pSelection2Item!=0 ); | |
2995 m_pDirMergeExplicit->setEnabled( bDirCompare && isVisible() && m_pSelection2Item!=0 ); | |
2996 | |
2997 m_pDirCurrentDoNothing->setEnabled( bItemActive && bMergeMode ); | |
2998 m_pDirCurrentChooseA->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInA ); | |
2999 m_pDirCurrentChooseB->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInB ); | |
3000 m_pDirCurrentChooseC->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInC ); | |
3001 m_pDirCurrentMerge->setEnabled( bItemActive && bMergeMode && !bFTConflict ); | |
3002 m_pDirCurrentDelete->setEnabled( bItemActive && bMergeMode ); | |
3003 if ( bDirWindowHasFocus ) | |
3004 { | |
3005 chooseA->setEnabled( bItemActive && pMFI->m_bExistsInA ); | |
3006 chooseB->setEnabled( bItemActive && pMFI->m_bExistsInB ); | |
3007 chooseC->setEnabled( bItemActive && pMFI->m_bExistsInC ); | |
3008 chooseA->setChecked( false ); | |
3009 chooseB->setChecked( false ); | |
3010 chooseC->setChecked( false ); | |
3011 } | |
3012 | |
3013 m_pDirCurrentSyncDoNothing->setEnabled( bItemActive && !bMergeMode ); | |
3014 m_pDirCurrentSyncCopyAToB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA ); | |
3015 m_pDirCurrentSyncCopyBToA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB ); | |
3016 m_pDirCurrentSyncDeleteA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA ); | |
3017 m_pDirCurrentSyncDeleteB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB ); | |
3018 m_pDirCurrentSyncDeleteAAndB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB && pMFI->m_bExistsInB ); | |
3019 m_pDirCurrentSyncMergeToA->setEnabled( bItemActive && !bMergeMode && !bFTConflict ); | |
3020 m_pDirCurrentSyncMergeToB->setEnabled( bItemActive && !bMergeMode && !bFTConflict ); | |
3021 m_pDirCurrentSyncMergeToAAndB->setEnabled( bItemActive && !bMergeMode && !bFTConflict ); | |
3022 } | |
3023 | |
3024 | |
3025 //#include "directorymergewindow.moc" |