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
CompareFileNames_ForFolderList(const wchar_t * s1,const wchar_t * s2)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
CompareFileNames_Le16(const Byte * s1,unsigned size1,const Byte * s2,unsigned size2)53 static int CompareFileNames_Le16(const Byte *s1, unsigned size1, const Byte *s2, unsigned size2)
54 {
55 size1 &= ~1u;
56 size2 &= ~1u;
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
GetExtensionPtr(const UString & name)77 static inline const wchar_t *GetExtensionPtr(const UString &name)
78 {
79 const int dotPos = name.ReverseFind_Dot();
80 return name.Ptr(dotPos < 0 ? name.Len() : (unsigned)dotPos);
81 }
82
SetSortRawStatus()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
CompareItems2(LPARAM lParam1,LPARAM lParam2,LPARAM lpData)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((unsigned)lParam1);
146 const UString name2 = panel->GetItemName((unsigned)lParam2);
147 const 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((unsigned)lParam1);
160 const UString name2 = panel->GetItemName((unsigned)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);
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 == (int)kParentIndex) return -1;
190 if (lParam2 == (int)kParentIndex) return 1;
191
192 CPanel *panel = (CPanel*)lpData;
193
194 const bool isDir1 = panel->IsItem_Folder((unsigned)lParam1);
195 const bool isDir2 = panel->IsItem_Folder((unsigned)lParam2);
196
197 if (isDir1 && !isDir2) return -1;
198 if (isDir2 && !isDir1) return 1;
199
200 const 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
SortItemsWithPropID(PROPID propID)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
OnColumnClick(LPNMLISTVIEW info)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 }
270