diff options
Diffstat (limited to 'CPP/7zip/UI/FileManager/PanelSort.cpp')
-rw-r--r-- | CPP/7zip/UI/FileManager/PanelSort.cpp | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/CPP/7zip/UI/FileManager/PanelSort.cpp b/CPP/7zip/UI/FileManager/PanelSort.cpp new file mode 100644 index 0000000..d26acb7 --- /dev/null +++ b/CPP/7zip/UI/FileManager/PanelSort.cpp | |||
@@ -0,0 +1,269 @@ | |||
1 | // PanelSort.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../../../C/CpuArch.h" | ||
6 | #include "../../../Windows/PropVariant.h" | ||
7 | |||
8 | #include "../../PropID.h" | ||
9 | |||
10 | #include "Panel.h" | ||
11 | |||
12 | using namespace NWindows; | ||
13 | |||
14 | int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2) | ||
15 | { | ||
16 | for (;;) | ||
17 | { | ||
18 | wchar_t c1 = *s1; | ||
19 | wchar_t c2 = *s2; | ||
20 | if ((c1 >= '0' && c1 <= '9') && | ||
21 | (c2 >= '0' && c2 <= '9')) | ||
22 | { | ||
23 | for (; *s1 == '0'; s1++); | ||
24 | for (; *s2 == '0'; s2++); | ||
25 | size_t len1 = 0; | ||
26 | size_t len2 = 0; | ||
27 | for (; (s1[len1] >= '0' && s1[len1] <= '9'); len1++); | ||
28 | for (; (s2[len2] >= '0' && s2[len2] <= '9'); len2++); | ||
29 | if (len1 < len2) return -1; | ||
30 | if (len1 > len2) return 1; | ||
31 | for (; len1 > 0; s1++, s2++, len1--) | ||
32 | { | ||
33 | if (*s1 == *s2) continue; | ||
34 | return (*s1 < *s2) ? -1 : 1; | ||
35 | } | ||
36 | c1 = *s1; | ||
37 | c2 = *s2; | ||
38 | } | ||
39 | s1++; | ||
40 | s2++; | ||
41 | if (c1 != c2) | ||
42 | { | ||
43 | // Probably we need to change the order for special characters like in Explorer. | ||
44 | wchar_t u1 = MyCharUpper(c1); | ||
45 | wchar_t u2 = MyCharUpper(c2); | ||
46 | if (u1 < u2) return -1; | ||
47 | if (u1 > u2) return 1; | ||
48 | } | ||
49 | if (c1 == 0) return 0; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | static int CompareFileNames_Le16(const Byte *s1, unsigned size1, const Byte *s2, unsigned size2) | ||
54 | { | ||
55 | size1 &= ~1; | ||
56 | size2 &= ~1; | ||
57 | for (unsigned i = 0;; i += 2) | ||
58 | { | ||
59 | if (i >= size1) | ||
60 | return (i >= size2) ? 0 : -1; | ||
61 | if (i >= size2) | ||
62 | return 1; | ||
63 | UInt16 c1 = GetUi16(s1 + i); | ||
64 | UInt16 c2 = GetUi16(s2 + i); | ||
65 | if (c1 == c2) | ||
66 | { | ||
67 | if (c1 == 0) | ||
68 | return 0; | ||
69 | continue; | ||
70 | } | ||
71 | if (c1 < c2) | ||
72 | return -1; | ||
73 | return 1; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | static inline const wchar_t *GetExtensionPtr(const UString &name) | ||
78 | { | ||
79 | int dotPos = name.ReverseFind_Dot(); | ||
80 | return name.Ptr((dotPos < 0) ? name.Len() : dotPos); | ||
81 | } | ||
82 | |||
83 | void CPanel::SetSortRawStatus() | ||
84 | { | ||
85 | _isRawSortProp = false; | ||
86 | FOR_VECTOR (i, _columns) | ||
87 | { | ||
88 | const CPropColumn &prop = _columns[i]; | ||
89 | if (prop.ID == _sortID) | ||
90 | { | ||
91 | _isRawSortProp = prop.IsRawProp ? 1 : 0; | ||
92 | return; | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | |||
97 | |||
98 | static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) | ||
99 | { | ||
100 | if (lpData == 0) | ||
101 | return 0; | ||
102 | CPanel *panel = (CPanel*)lpData; | ||
103 | |||
104 | |||
105 | PROPID propID = panel->_sortID; | ||
106 | |||
107 | if (propID == kpidNoProperty) | ||
108 | return MyCompare(lParam1, lParam2); | ||
109 | |||
110 | if (panel->_isRawSortProp) | ||
111 | { | ||
112 | // Sha1, NtSecurity, NtReparse | ||
113 | const void *data1; | ||
114 | const void *data2; | ||
115 | UInt32 dataSize1; | ||
116 | UInt32 dataSize2; | ||
117 | UInt32 propType1; | ||
118 | UInt32 propType2; | ||
119 | if (panel->_folderRawProps->GetRawProp((UInt32)lParam1, propID, &data1, &dataSize1, &propType1) != 0) return 0; | ||
120 | if (panel->_folderRawProps->GetRawProp((UInt32)lParam2, propID, &data2, &dataSize2, &propType2) != 0) return 0; | ||
121 | if (dataSize1 == 0) | ||
122 | return (dataSize2 == 0) ? 0 : -1; | ||
123 | if (dataSize2 == 0) | ||
124 | return 1; | ||
125 | if (propType1 != NPropDataType::kRaw) return 0; | ||
126 | if (propType2 != NPropDataType::kRaw) return 0; | ||
127 | if (propID == kpidNtReparse) | ||
128 | { | ||
129 | NFile::CReparseShortInfo r1; r1.Parse((const Byte *)data1, dataSize1); | ||
130 | NFile::CReparseShortInfo r2; r2.Parse((const Byte *)data2, dataSize2); | ||
131 | return CompareFileNames_Le16( | ||
132 | (const Byte *)data1 + r1.Offset, r1.Size, | ||
133 | (const Byte *)data2 + r2.Offset, r2.Size); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | if (panel->_folderCompare) | ||
138 | return panel->_folderCompare->CompareItems((UInt32)lParam1, (UInt32)lParam2, propID, panel->_isRawSortProp); | ||
139 | |||
140 | switch (propID) | ||
141 | { | ||
142 | // if (panel->_sortIndex == 0) | ||
143 | case kpidName: | ||
144 | { | ||
145 | const UString name1 = panel->GetItemName((int)lParam1); | ||
146 | const UString name2 = panel->GetItemName((int)lParam2); | ||
147 | int res = CompareFileNames_ForFolderList(name1, name2); | ||
148 | /* | ||
149 | if (res != 0 || !panel->_flatMode) | ||
150 | return res; | ||
151 | const UString prefix1 = panel->GetItemPrefix(lParam1); | ||
152 | const UString prefix2 = panel->GetItemPrefix(lParam2); | ||
153 | return res = CompareFileNames_ForFolderList(prefix1, prefix2); | ||
154 | */ | ||
155 | return res; | ||
156 | } | ||
157 | case kpidExtension: | ||
158 | { | ||
159 | const UString name1 = panel->GetItemName((int)lParam1); | ||
160 | const UString name2 = panel->GetItemName((int)lParam2); | ||
161 | return CompareFileNames_ForFolderList( | ||
162 | GetExtensionPtr(name1), | ||
163 | GetExtensionPtr(name2)); | ||
164 | } | ||
165 | } | ||
166 | /* | ||
167 | if (panel->_sortIndex == 1) | ||
168 | return MyCompare(file1.Size, file2.Size); | ||
169 | return ::CompareFileTime(&file1.MTime, &file2.MTime); | ||
170 | */ | ||
171 | |||
172 | // PROPID propID = panel->_columns[panel->_sortIndex].ID; | ||
173 | |||
174 | NCOM::CPropVariant prop1, prop2; | ||
175 | // Name must be first property | ||
176 | panel->_folder->GetProperty((UInt32)lParam1, propID, &prop1); | ||
177 | panel->_folder->GetProperty((UInt32)lParam2, propID, &prop2); | ||
178 | if (prop1.vt != prop2.vt) | ||
179 | return MyCompare(prop1.vt, prop2.vt); | ||
180 | if (prop1.vt == VT_BSTR) | ||
181 | return MyStringCompareNoCase(prop1.bstrVal, prop2.bstrVal); | ||
182 | return prop1.Compare(prop2); | ||
183 | } | ||
184 | |||
185 | int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData); | ||
186 | int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) | ||
187 | { | ||
188 | if (lpData == 0) return 0; | ||
189 | if (lParam1 == kParentIndex) return -1; | ||
190 | if (lParam2 == kParentIndex) return 1; | ||
191 | |||
192 | CPanel *panel = (CPanel*)lpData; | ||
193 | |||
194 | bool isDir1 = panel->IsItem_Folder((int)lParam1); | ||
195 | bool isDir2 = panel->IsItem_Folder((int)lParam2); | ||
196 | |||
197 | if (isDir1 && !isDir2) return -1; | ||
198 | if (isDir2 && !isDir1) return 1; | ||
199 | |||
200 | int result = CompareItems2(lParam1, lParam2, lpData); | ||
201 | return panel->_ascending ? result: (-result); | ||
202 | } | ||
203 | |||
204 | |||
205 | /* | ||
206 | void CPanel::SortItems(int index) | ||
207 | { | ||
208 | if (index == _sortIndex) | ||
209 | _ascending = !_ascending; | ||
210 | else | ||
211 | { | ||
212 | _sortIndex = index; | ||
213 | _ascending = true; | ||
214 | switch (_columns[_sortIndex].ID) | ||
215 | { | ||
216 | case kpidSize: | ||
217 | case kpidPackedSize: | ||
218 | case kpidCTime: | ||
219 | case kpidATime: | ||
220 | case kpidMTime: | ||
221 | _ascending = false; | ||
222 | break; | ||
223 | } | ||
224 | } | ||
225 | _listView.SortItems(CompareItems, (LPARAM)this); | ||
226 | _listView.EnsureVisible(_listView.GetFocusedItem(), false); | ||
227 | } | ||
228 | |||
229 | void CPanel::SortItemsWithPropID(PROPID propID) | ||
230 | { | ||
231 | int index = _columns.FindItem_for_PropID(propID); | ||
232 | if (index >= 0) | ||
233 | SortItems(index); | ||
234 | } | ||
235 | */ | ||
236 | |||
237 | void CPanel::SortItemsWithPropID(PROPID propID) | ||
238 | { | ||
239 | if (propID == _sortID) | ||
240 | _ascending = !_ascending; | ||
241 | else | ||
242 | { | ||
243 | _sortID = propID; | ||
244 | _ascending = true; | ||
245 | switch (propID) | ||
246 | { | ||
247 | case kpidSize: | ||
248 | case kpidPackSize: | ||
249 | case kpidCTime: | ||
250 | case kpidATime: | ||
251 | case kpidMTime: | ||
252 | _ascending = false; | ||
253 | break; | ||
254 | } | ||
255 | } | ||
256 | SetSortRawStatus(); | ||
257 | _listView.SortItems(CompareItems, (LPARAM)this); | ||
258 | _listView.EnsureVisible(_listView.GetFocusedItem(), false); | ||
259 | } | ||
260 | |||
261 | |||
262 | void CPanel::OnColumnClick(LPNMLISTVIEW info) | ||
263 | { | ||
264 | /* | ||
265 | int index = _columns.FindItem_for_PropID(_visibleColumns[info->iSubItem].ID); | ||
266 | SortItems(index); | ||
267 | */ | ||
268 | SortItemsWithPropID(_visibleColumns[info->iSubItem].ID); | ||
269 | } | ||