1 #include "filezilla.h"
2 #include "listingcomparison.h"
3 #include "filelistctrl.h"
4 #include "Options.h"
5 #include "state.h"
6 #include "../commonui/filter.h"
7
CComparableListing(wxWindow * pParent)8 CComparableListing::CComparableListing(wxWindow* pParent)
9 {
10 m_pParent = pParent;
11
12 // Init backgrounds for directory comparison
13 InitColors();
14 }
15
InitColors()16 void CComparableListing::InitColors()
17 {
18 wxColour background = m_pParent->GetBackgroundColour();
19 if (background.Red() + background.Green() + background.Blue() >= 384) {
20 // Light background
21 m_comparisonBackgrounds[0].SetBackgroundColour(wxColour(255, 128, 128));
22 m_comparisonBackgrounds[1].SetBackgroundColour(wxColour(255, 255, 128));
23 m_comparisonBackgrounds[2].SetBackgroundColour(wxColour(128, 255, 128));
24 }
25 else {
26 // Light background
27 m_comparisonBackgrounds[0].SetBackgroundColour(wxColour(192, 64, 64));
28 m_comparisonBackgrounds[1].SetBackgroundColour(wxColour(192, 192, 64));
29 m_comparisonBackgrounds[2].SetBackgroundColour(wxColour(64, 192, 64));
30 }
31 }
32
IsComparing() const33 bool CComparableListing::IsComparing() const
34 {
35 if (!m_pComparisonManager) {
36 return false;
37 }
38
39 return m_pComparisonManager->IsComparing();
40 }
41
ExitComparisonMode()42 void CComparableListing::ExitComparisonMode()
43 {
44 if (!m_pComparisonManager) {
45 return;
46 }
47
48 m_pComparisonManager->ExitComparisonMode();
49 }
50
RefreshComparison()51 void CComparableListing::RefreshComparison()
52 {
53 if (!m_pComparisonManager) {
54 return;
55 }
56
57 if (!IsComparing()) {
58 return;
59 }
60
61 if (!CanStartComparison() || !GetOther() || !GetOther()->CanStartComparison()) {
62 return;
63 }
64
65 m_pComparisonManager->CompareListings();
66 }
67
CompareListings()68 bool CComparisonManager::CompareListings()
69 {
70 if (!m_pLeft || !m_pRight) {
71 return false;
72 }
73
74 CFilterManager filters;
75 if (filters.HasActiveFilters() && !filters.HasSameLocalAndRemoteFilters()) {
76 m_state.NotifyHandlers(STATECHANGE_COMPARISON);
77 wxMessageBoxEx(_("Cannot compare directories, different filters for local and remote directories are enabled"), _("Directory comparison failed"), wxICON_EXCLAMATION);
78 return false;
79 }
80
81 m_isComparing = true;
82 m_pLeft->m_pComparisonManager = this;
83 m_pRight->m_pComparisonManager = this;
84
85 m_state.NotifyHandlers(STATECHANGE_COMPARISON);
86
87 if (!m_pLeft->CanStartComparison() || !m_pRight->CanStartComparison()) {
88 return true;
89 }
90
91 fz::duration const threshold = fz::duration::from_minutes( COptions::Get()->get_int(OPTION_COMPARISON_THRESHOLD) );
92
93 m_pLeft->StartComparison();
94 m_pRight->StartComparison();
95
96 std::wstring localPath, remotePath;
97 std::wstring_view localFile, remoteFile;
98 bool localDir = false;
99 bool remoteDir = false;
100 int64_t localSize, remoteSize;
101 fz::datetime localDate, remoteDate;
102
103 int const dirSortMode = COptions::Get()->get_int(OPTION_FILELIST_DIRSORT);
104 auto const nameSortMode = static_cast<NameSortMode>(COptions::Get()->get_int(OPTION_FILELIST_NAMESORT));
105
106 bool gotLocal = m_pLeft->get_next_file(localFile, localPath, localDir, localSize, localDate);
107 bool gotRemote = m_pRight->get_next_file(remoteFile, remotePath, remoteDir, remoteSize, remoteDate);
108
109 while (gotLocal && gotRemote) {
110 int cmp = CompareFiles(dirSortMode, nameSortMode, localPath, localFile, remotePath, remoteFile, localDir, remoteDir);
111 if (!cmp) {
112 if (!m_comparisonMode) {
113 const CComparableListing::t_fileEntryFlags flag = (localDir || localSize == remoteSize) ? CComparableListing::normal : CComparableListing::different;
114
115 if (!m_hideIdentical || flag != CComparableListing::normal || localFile == L"..") {
116 m_pLeft->CompareAddFile(flag);
117 m_pRight->CompareAddFile(flag);
118 }
119 }
120 else {
121 if (localDate.empty() || remoteDate.empty()) {
122 if (!m_hideIdentical || !localDate.empty() || !remoteDate.empty() || localFile == L"..") {
123 const CComparableListing::t_fileEntryFlags flag = CComparableListing::normal;
124 m_pLeft->CompareAddFile(flag);
125 m_pRight->CompareAddFile(flag);
126 }
127 }
128 else {
129 CComparableListing::t_fileEntryFlags localFlag, remoteFlag;
130
131 int dateCmp = localDate.compare(remoteDate);
132 if (dateCmp < 0) {
133 localDate += threshold;
134 }
135 else if (dateCmp > 0 ) {
136 remoteDate += threshold;
137 }
138 int adjustedDateCmp = localDate.compare(remoteDate);
139 if (dateCmp && dateCmp == -adjustedDateCmp) {
140 dateCmp = 0;
141 }
142
143 localFlag = CComparableListing::normal;
144 remoteFlag = CComparableListing::normal;
145 if (dateCmp < 0 ) {
146 remoteFlag = CComparableListing::newer;
147 }
148 else if (dateCmp > 0) {
149 localFlag = CComparableListing::newer;
150 }
151 if (!m_hideIdentical || localFlag != CComparableListing::normal || remoteFlag != CComparableListing::normal || localFile == L"..") {
152 m_pLeft->CompareAddFile(localFlag);
153 m_pRight->CompareAddFile(remoteFlag);
154 }
155 }
156 }
157 gotLocal = m_pLeft->get_next_file(localFile, localPath, localDir, localSize, localDate);
158 gotRemote = m_pRight->get_next_file(remoteFile, remotePath, remoteDir, remoteSize, remoteDate);
159 continue;
160 }
161
162 if (cmp < 0) {
163 m_pLeft->CompareAddFile(CComparableListing::lonely);
164 m_pRight->CompareAddFile(CComparableListing::fill);
165 gotLocal = m_pLeft->get_next_file(localFile, localPath, localDir, localSize, localDate);
166 }
167 else {
168 m_pLeft->CompareAddFile(CComparableListing::fill);
169 m_pRight->CompareAddFile(CComparableListing::lonely);
170 gotRemote = m_pRight->get_next_file(remoteFile, remotePath, remoteDir, remoteSize, remoteDate);
171 }
172 }
173 while (gotLocal) {
174 m_pLeft->CompareAddFile(CComparableListing::lonely);
175 m_pRight->CompareAddFile(CComparableListing::fill);
176 gotLocal = m_pLeft->get_next_file(localFile, localPath, localDir, localSize, localDate);
177 }
178 while (gotRemote) {
179 m_pLeft->CompareAddFile(CComparableListing::fill);
180 m_pRight->CompareAddFile(CComparableListing::lonely);
181 gotRemote = m_pRight->get_next_file(remoteFile, remotePath, remoteDir, remoteSize, remoteDate);
182 }
183
184 m_pRight->FinishComparison();
185 m_pLeft->FinishComparison();
186
187 return true;
188 }
189
CompareFiles(int const dirSortMode,NameSortMode const nameSortMode,std::wstring_view const & local_path,std::wstring_view const & local,std::wstring_view const & remote_path,std::wstring_view const & remote,bool localDir,bool remoteDir)190 int CComparisonManager::CompareFiles(int const dirSortMode, NameSortMode const nameSortMode, std::wstring_view const& local_path, std::wstring_view const& local, std::wstring_view const& remote_path, std::wstring_view const& remote, bool localDir, bool remoteDir)
191 {
192 switch (dirSortMode)
193 {
194 default:
195 if (localDir) {
196 if (!remoteDir) {
197 return -1;
198 }
199 }
200 else if (remoteDir) {
201 return 1;
202 }
203 break;
204 case 2:
205 // Inline
206 break;
207 }
208
209 auto const f = CFileListCtrlSortBase::GetCmpFunction(nameSortMode);
210 auto cmp = f(local, remote);
211 if (!cmp) {
212 return f(local_path, remote_path);
213 }
214 return cmp;
215 }
216
CComparisonManager(CState & state)217 CComparisonManager::CComparisonManager(CState& state)
218 : m_state(state)
219 {
220 m_comparisonMode = COptions::Get()->get_int(OPTION_COMPARISONMODE);
221 m_hideIdentical = COptions::Get()->get_int(OPTION_COMPARE_HIDEIDENTICAL) != 0;
222 }
223
SetListings(CComparableListing * pLeft,CComparableListing * pRight)224 void CComparisonManager::SetListings(CComparableListing* pLeft, CComparableListing* pRight)
225 {
226 wxASSERT((pLeft && pRight) || (!pLeft && !pRight));
227
228 if (IsComparing()) {
229 ExitComparisonMode();
230 }
231
232 if (m_pLeft) {
233 m_pLeft->SetOther(0);
234 }
235 if (m_pRight) {
236 m_pRight->SetOther(0);
237 }
238
239 m_pLeft = pLeft;
240 m_pRight = pRight;
241
242 if (m_pLeft) {
243 m_pLeft->SetOther(m_pRight);
244 }
245 if (m_pRight) {
246 m_pRight->SetOther(m_pLeft);
247 }
248 }
249
ExitComparisonMode()250 void CComparisonManager::ExitComparisonMode()
251 {
252 if (!IsComparing()) {
253 return;
254 }
255
256 m_isComparing = false;
257 if (m_pLeft) {
258 m_pLeft->OnExitComparisonMode();
259 }
260 if (m_pRight) {
261 m_pRight->OnExitComparisonMode();
262 }
263
264 m_state.NotifyHandlers(STATECHANGE_COMPARISON);
265 }
266