summaryrefslogtreecommitdiffstats
path: root/src/directorymergewindow.h
blob: 77b09fdd39d133a6f1974ce34903716b4b830fc4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/***************************************************************************
                          directorymergewindow.h
                             -------------------
    begin                : Sat Oct 19 2002
    copyright            : (C) 2002-2007 by Joachim Eibl
    email                : joachim.eibl at gmx.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef DIRECTORY_MERGE_WINDOW_H
#define DIRECTORY_MERGE_WINDOW_H

#include <qfileinfo.h>
#include <qlistview.h>
#include <qtimer.h>
#include <qdir.h>
#include <list>
#include <map>
#include "common.h"
#include "fileaccess.h"
#include "diff.h" //TotalDiffStatus

class OptionDialog;
class KIconLoader;
class StatusInfo;
class DirectoryMergeInfo;
class OneDirectoryInfo;
class QLabel;
class KAction;
class KToggleAction;
class KActionCollection;
class TotalDiffStatus;

enum e_MergeOperation
{
   eTitleId,
   eNoOperation,
   // Operations in sync mode (with only two directories):
   eCopyAToB, eCopyBToA, eDeleteA, eDeleteB, eDeleteAB, eMergeToA, eMergeToB, eMergeToAB,

   // Operations in merge mode (with two or three directories)
   eCopyAToDest, eCopyBToDest, eCopyCToDest, eDeleteFromDest, eMergeABCToDest,
   eMergeABToDest,
   eConflictingFileTypes, // Error
   eConflictingAges       // Equal age but files are not!
};

class DirMergeItem;

enum e_Age { eNew, eMiddle, eOld, eNotThere, eAgeEnd };

class MergeFileInfos
{
public:
   MergeFileInfos(){ m_bEqualAB=false; m_bEqualAC=false; m_bEqualBC=false;
                     m_pDMI=0; m_pParent=0;
                     m_bExistsInA=false;m_bExistsInB=false;m_bExistsInC=false;
                     m_bDirA=false;  m_bDirB=false;  m_bDirC=false;
                     m_bLinkA=false; m_bLinkB=false; m_bLinkC=false;
                     m_bOperationComplete=false; m_bSimOpComplete = false;
                     m_eMergeOperation=eNoOperation;
                     m_ageA = eNotThere; m_ageB=eNotThere; m_ageC=eNotThere;
                     m_bConflictingAges=false; }
   bool operator>( const MergeFileInfos& );
   QString m_subPath;

   bool m_bExistsInA;
   bool m_bExistsInB;
   bool m_bExistsInC;
   bool m_bEqualAB;
   bool m_bEqualAC;
   bool m_bEqualBC;
   DirMergeItem* m_pDMI;
   MergeFileInfos* m_pParent;
   e_MergeOperation m_eMergeOperation;
   void setMergeOperation( e_MergeOperation eMOp, bool bRecursive=true );
   bool m_bDirA;
   bool m_bDirB;
   bool m_bDirC;
   bool m_bLinkA;
   bool m_bLinkB;
   bool m_bLinkC;
   bool m_bOperationComplete;
   bool m_bSimOpComplete;
   e_Age m_ageA;
   e_Age m_ageB;
   e_Age m_ageC;
   bool m_bConflictingAges;       // Equal age but files are not!

   FileAccess m_fileInfoA;
   FileAccess m_fileInfoB;
   FileAccess m_fileInfoC;

   TotalDiffStatus m_totalDiffStatus;   
};

class DirMergeItem : public QListViewItem
{
public:
   DirMergeItem( QListView* pParent, const QString&, MergeFileInfos*);
   DirMergeItem( DirMergeItem* pParent, const QString&, MergeFileInfos*);
   ~DirMergeItem();
   MergeFileInfos* m_pMFI;
   virtual int compare(QListViewItem *i, int col, bool ascending) const;
   virtual void paintCell(QPainter * p, const QColorGroup & cg, int column, int width, int align );
   void init(MergeFileInfos* pMFI);
};

class DirectoryMergeWindow : public QListView
{
   Q_OBJECT
public:
   DirectoryMergeWindow( QWidget* pParent, OptionDialog* pOptions, KIconLoader* pIconLoader );
   ~DirectoryMergeWindow();
   void setDirectoryMergeInfo(DirectoryMergeInfo* p){ m_pDirectoryMergeInfo=p; }
   bool init(
      FileAccess& dirA,
      FileAccess& dirB,
      FileAccess& dirC,
      FileAccess& dirDest,
      bool bDirectoryMerge,
      bool bReload = false
   );
   bool isFileSelected();
   void allowResizeEvents(bool bAllowResizeEvents);
   bool isDirectoryMergeInProgress() { return m_bRealMergeStarted; }
   int totalColumnWidth();
   bool isSyncMode() { return m_bSyncMode; }
   bool isScanning() { return m_bScanning; }
   void initDirectoryMergeActions( QObject* pKDiff3App, KActionCollection* ac );
   void updateAvailabilities( bool bDirCompare, bool bDiffWindowVisible,
      KToggleAction* chooseA, KToggleAction* chooseB, KToggleAction* chooseC );
   void updateFileVisibilities();

   virtual void keyPressEvent( QKeyEvent* e );
   virtual void focusInEvent( QFocusEvent* e );
   virtual void focusOutEvent( QFocusEvent* e );

   QString getDirNameA(){ return m_dirA.prettyAbsPath(); }
   QString getDirNameB(){ return m_dirB.prettyAbsPath(); }
   QString getDirNameC(){ return m_dirC.prettyAbsPath(); }
   QString getDirNameDest(){ return m_dirDest.prettyAbsPath(); }

public slots:
   void reload();
   void mergeCurrentFile();
   void compareCurrentFile();
   void slotRunOperationForAllItems();
   void slotRunOperationForCurrentItem();
   void mergeResultSaved(const QString& fileName);
   void slotChooseAEverywhere();
   void slotChooseBEverywhere();
   void slotChooseCEverywhere();
   void slotAutoChooseEverywhere();
   void slotNoOpEverywhere();
   void slotFoldAllSubdirs();
   void slotUnfoldAllSubdirs();
   void slotShowIdenticalFiles();
   void slotShowDifferentFiles();
   void slotShowFilesOnlyInA();
   void slotShowFilesOnlyInB();
   void slotShowFilesOnlyInC();

   void slotSynchronizeDirectories();
   void slotChooseNewerFiles();

   void slotCompareExplicitlySelectedFiles();
   void slotMergeExplicitlySelectedFiles();

   // Merge current item (merge mode)
   void slotCurrentDoNothing();
   void slotCurrentChooseA();
   void slotCurrentChooseB();
   void slotCurrentChooseC();
   void slotCurrentMerge();
   void slotCurrentDelete();
   // Sync current item
   void slotCurrentCopyAToB();
   void slotCurrentCopyBToA();
   void slotCurrentDeleteA();
   void slotCurrentDeleteB();
   void slotCurrentDeleteAAndB();
   void slotCurrentMergeToA();
   void slotCurrentMergeToB();
   void slotCurrentMergeToAAndB();

   void slotSaveMergeState();
   void slotLoadMergeState();

protected:
   void mergeContinue( bool bStart, bool bVerbose );
   void resizeEvent(QResizeEvent* e);
   bool m_bAllowResizeEvents;

   void prepareListView(ProgressProxy& pp);
   void calcSuggestedOperation( MergeFileInfos& mfi, e_MergeOperation eDefaultOperation );
   void setAllMergeOperations( e_MergeOperation eDefaultOperation );
   friend class MergeFileInfos;

   bool canContinue();
   void prepareMergeStart( QListViewItem* pBegin, QListViewItem* pEnd, bool bVerbose );
   bool executeMergeOperation( MergeFileInfos& mfi, bool& bSingleFileMerge );

   void scanDirectory( const QString& dirName, t_DirectoryList& dirList );
   void scanLocalDirectory( const QString& dirName, t_DirectoryList& dirList );
   void fastFileComparison( FileAccess& fi1, FileAccess& fi2,
                            bool& bEqual, bool& bError, QString& status );
   void compareFilesAndCalcAges( MergeFileInfos& mfi );

   QString fullNameA( const MergeFileInfos& mfi )
   { return mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : m_dirA.absFilePath() + "/" + mfi.m_subPath; }
   QString fullNameB( const MergeFileInfos& mfi )
   { return mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : m_dirB.absFilePath() + "/" + mfi.m_subPath; }
   QString fullNameC( const MergeFileInfos& mfi )
   { return mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : m_dirC.absFilePath() + "/" + mfi.m_subPath; }
   QString fullNameDest( const MergeFileInfos& mfi )
   { if       ( m_dirDestInternal.prettyAbsPath() == m_dirC.prettyAbsPath() ) return fullNameC(mfi);
     else if ( m_dirDestInternal.prettyAbsPath() == m_dirB.prettyAbsPath() ) return fullNameB(mfi);
     else return m_dirDestInternal.absFilePath() + "/" + mfi.m_subPath; 
   }

   bool copyFLD( const QString& srcName, const QString& destName );
   bool deleteFLD( const QString& name, bool bCreateBackup );
   bool makeDir( const QString& name, bool bQuiet=false );
   bool renameFLD( const QString& srcName, const QString& destName );
   bool mergeFLD( const QString& nameA,const QString& nameB,const QString& nameC,
                  const QString& nameDest, bool& bSingleFileMerge );

   FileAccess m_dirA;
   FileAccess m_dirB;
   FileAccess m_dirC;
   FileAccess m_dirDest;
   FileAccess m_dirDestInternal;

   QString m_dirMergeStateFilename;

   std::map<QString, MergeFileInfos> m_fileMergeMap;

   bool m_bFollowDirLinks;
   bool m_bFollowFileLinks;
   bool m_bSimulatedMergeStarted;
   bool m_bRealMergeStarted;
   bool m_bError;
   bool m_bSyncMode;
   bool m_bDirectoryMerge; // if true, then merge is the default operation, otherwise it's diff.
   bool m_bCaseSensitive;
   
   bool m_bScanning; // true while in init()

   OptionDialog* m_pOptions;
   KIconLoader* m_pIconLoader;
   DirectoryMergeInfo* m_pDirectoryMergeInfo;
   StatusInfo* m_pStatusInfo;

   typedef std::list<DirMergeItem*> MergeItemList;
   MergeItemList m_mergeItemList;
   MergeItemList::iterator m_currentItemForOperation;

   DirMergeItem* m_pSelection1Item;
   int m_selection1Column;
   DirMergeItem* m_pSelection2Item;
   int m_selection2Column;
   DirMergeItem* m_pSelection3Item;
   int m_selection3Column;
   void selectItemAndColumn(DirMergeItem* pDMI, int c, bool bContextMenu);
   friend class DirMergeItem;

   KAction* m_pDirStartOperation;
   KAction* m_pDirRunOperationForCurrentItem;
   KAction* m_pDirCompareCurrent;
   KAction* m_pDirMergeCurrent;
   KAction* m_pDirRescan;
   KAction* m_pDirChooseAEverywhere;
   KAction* m_pDirChooseBEverywhere;
   KAction* m_pDirChooseCEverywhere;
   KAction* m_pDirAutoChoiceEverywhere;
   KAction* m_pDirDoNothingEverywhere;
   KAction* m_pDirFoldAll;
   KAction* m_pDirUnfoldAll;

   KToggleAction* m_pDirShowIdenticalFiles;
   KToggleAction* m_pDirShowDifferentFiles;
   KToggleAction* m_pDirShowFilesOnlyInA;
   KToggleAction* m_pDirShowFilesOnlyInB;
   KToggleAction* m_pDirShowFilesOnlyInC;

   KToggleAction* m_pDirSynchronizeDirectories;
   KToggleAction* m_pDirChooseNewerFiles;

   KAction* m_pDirCompareExplicit;
   KAction* m_pDirMergeExplicit;

   KAction* m_pDirCurrentDoNothing;
   KAction* m_pDirCurrentChooseA;
   KAction* m_pDirCurrentChooseB;
   KAction* m_pDirCurrentChooseC;
   KAction* m_pDirCurrentMerge;
   KAction* m_pDirCurrentDelete;

   KAction* m_pDirCurrentSyncDoNothing;
   KAction* m_pDirCurrentSyncCopyAToB;
   KAction* m_pDirCurrentSyncCopyBToA;
   KAction* m_pDirCurrentSyncDeleteA;
   KAction* m_pDirCurrentSyncDeleteB;
   KAction* m_pDirCurrentSyncDeleteAAndB;
   KAction* m_pDirCurrentSyncMergeToA;
   KAction* m_pDirCurrentSyncMergeToB;
   KAction* m_pDirCurrentSyncMergeToAAndB;

   KAction* m_pDirSaveMergeState;
   KAction* m_pDirLoadMergeState;
signals:
   void startDiffMerge(QString fn1,QString fn2, QString fn3, QString ofn, QString,QString,QString,TotalDiffStatus*);
   void checkIfCanContinue( bool* pbContinue );
   void updateAvailabilities();
   void statusBarMessage( const QString& msg );
protected slots:
   void onDoubleClick( QListViewItem* lvi );
   void onClick( int button, QListViewItem* lvi, const QPoint&, int c );
   void slotShowContextMenu(QListViewItem* lvi,const QPoint &,int c);
   void onSelectionChanged(QListViewItem* lvi);
};

class DirectoryMergeInfo : public QFrame
{
   Q_OBJECT
public:
   DirectoryMergeInfo( QWidget* pParent );
   void setInfo(
      const FileAccess& APath,
      const FileAccess& BPath,
      const FileAccess& CPath,
      const FileAccess& DestPath,
      MergeFileInfos& mfi );
   QListView* getInfoList() {return m_pInfoList;}
   virtual bool eventFilter( QObject* o, QEvent* e );
signals:
   void gotFocus();
private:
   QLabel* m_pInfoA;
   QLabel* m_pInfoB;
   QLabel* m_pInfoC;
   QLabel* m_pInfoDest;

   QLabel* m_pA;
   QLabel* m_pB;
   QLabel* m_pC;
   QLabel* m_pDest;

   QListView* m_pInfoList;
};


#endif