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