p7zip-rar/CPP/7zip/UI/FileManager/PanelSort.cpp
2017-10-11 12:40:22 +02:00

287 lines
7.0 KiB
C++

// PanelSort.cpp
#include "StdAfx.h"
#include "../../../../C/CpuArch.h"
#include "../../../Windows/PropVariant.h"
#include "../../PropID.h"
#include "Panel.h"
using namespace NWindows;
int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2)
{
for (;;)
{
wchar_t c1 = *s1;
wchar_t c2 = *s2;
if ((c1 >= '0' && c1 <= '9') &&
(c2 >= '0' && c2 <= '9'))
{
for (; *s1 == '0'; s1++);
for (; *s2 == '0'; s2++);
size_t len1 = 0;
size_t len2 = 0;
for (; (s1[len1] >= '0' && s1[len1] <= '9'); len1++);
for (; (s2[len2] >= '0' && s2[len2] <= '9'); len2++);
if (len1 < len2) return -1;
if (len1 > len2) return 1;
for (; len1 > 0; s1++, s2++, len1--)
{
if (*s1 == *s2) continue;
return (*s1 < *s2) ? -1 : 1;
}
c1 = *s1;
c2 = *s2;
}
s1++;
s2++;
if (c1 != c2)
{
// Probably we need to change the order for special characters like in Explorer.
wchar_t u1 = MyCharUpper(c1);
wchar_t u2 = MyCharUpper(c2);
if (u1 < u2) return -1;
if (u1 > u2) return 1;
}
if (c1 == 0) return 0;
}
}
static int CompareFileNames_Le16(const Byte *s1, unsigned size1, const Byte *s2, unsigned size2)
{
size1 &= ~1;
size2 &= ~1;
for (unsigned i = 0;; i += 2)
{
if (i >= size1)
return (i >= size2) ? 0 : -1;
if (i >= size2)
return 1;
UInt16 c1 = GetUi16(s1 + i);
UInt16 c2 = GetUi16(s2 + i);
if (c1 == c2)
{
if (c1 == 0)
return 0;
continue;
}
if (c1 < c2)
return -1;
return 1;
}
}
static inline const wchar_t *GetExtensionPtr(const UString &name)
{
int dotPos = name.ReverseFind_Dot();
return name.Ptr((dotPos < 0) ? name.Len() : dotPos);
}
void CPanel::SetSortRawStatus()
{
_isRawSortProp = false;
FOR_VECTOR (i, _properties)
{
const CItemProperty &prop = _properties[i];
if (prop.ID == _sortID)
{
_isRawSortProp = prop.IsRawProp ? 1 : 0;
return;
}
}
}
int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
{
if (lpData == 0)
return 0;
CPanel *panel = (CPanel*)lpData;
PROPID propID = panel->_sortID;
if (propID == kpidNoProperty)
return MyCompare(lParam1, lParam2);
if (panel->_isRawSortProp)
{
// Sha1, NtSecurity, NtReparse
const void *data1;
const void *data2;
UInt32 dataSize1;
UInt32 dataSize2;
UInt32 propType1;
UInt32 propType2;
if (panel->_folderRawProps->GetRawProp((UInt32)lParam1, propID, &data1, &dataSize1, &propType1) != 0) return 0;
if (panel->_folderRawProps->GetRawProp((UInt32)lParam2, propID, &data2, &dataSize2, &propType2) != 0) return 0;
if (dataSize1 == 0)
return (dataSize2 == 0) ? 0 : -1;
if (dataSize2 == 0)
return 1;
if (propType1 != NPropDataType::kRaw) return 0;
if (propType2 != NPropDataType::kRaw) return 0;
#ifdef _WIN32
if (propID == kpidNtReparse)
{
NFile::CReparseShortInfo r1; r1.Parse((const Byte *)data1, dataSize1);
NFile::CReparseShortInfo r2; r2.Parse((const Byte *)data2, dataSize2);
return CompareFileNames_Le16(
(const Byte *)data1 + r1.Offset, r1.Size,
(const Byte *)data2 + r2.Offset, r2.Size);
}
#endif
}
if (panel->_folderCompare)
return panel->_folderCompare->CompareItems((UInt32)lParam1, (UInt32)lParam2, propID, panel->_isRawSortProp);
switch (propID)
{
// if (panel->_sortIndex == 0)
case kpidName:
{
const UString name1 = panel->GetItemName((int)lParam1);
const UString name2 = panel->GetItemName((int)lParam2);
int res = CompareFileNames_ForFolderList(name1, name2);
/*
if (res != 0 || !panel->_flatMode)
return res;
const UString prefix1 = panel->GetItemPrefix(lParam1);
const UString prefix2 = panel->GetItemPrefix(lParam2);
return res = CompareFileNames_ForFolderList(prefix1, prefix2);
*/
return res;
}
case kpidExtension:
{
const UString name1 = panel->GetItemName((int)lParam1);
const UString name2 = panel->GetItemName((int)lParam2);
return CompareFileNames_ForFolderList(
GetExtensionPtr(name1),
GetExtensionPtr(name2));
}
}
/*
if (panel->_sortIndex == 1)
return MyCompare(file1.Size, file2.Size);
return ::CompareFileTime(&file1.MTime, &file2.MTime);
*/
// PROPID propID = panel->_properties[panel->_sortIndex].ID;
NCOM::CPropVariant prop1, prop2;
// Name must be first property
panel->_folder->GetProperty((UInt32)lParam1, propID, &prop1);
panel->_folder->GetProperty((UInt32)lParam2, propID, &prop2);
if (prop1.vt != prop2.vt)
{
return MyCompare(prop1.vt, prop2.vt);
}
if (prop1.vt == VT_BSTR)
{
return _wcsicmp(prop1.bstrVal, prop2.bstrVal);
}
return prop1.Compare(prop2);
// return 0;
}
int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
{
if (lpData == 0) return 0;
if (lParam1 == kParentIndex) return -1;
if (lParam2 == kParentIndex) return 1;
CPanel *panel = (CPanel*)lpData;
bool isDir1 = panel->IsItem_Folder((int)lParam1);
bool isDir2 = panel->IsItem_Folder((int)lParam2);
if (isDir1 && !isDir2) return -1;
if (isDir2 && !isDir1) return 1;
int result = CompareItems2(lParam1, lParam2, lpData);
return panel->_ascending ? result: (-result);
}
int
#if defined(__WIN32__) && !defined(__WXMICROWIN__) // FIXME
wxCALLBACK
#endif
CompareItems_WX(long item1, long item2, long sortData)
{
return CompareItems(item1,item2,sortData);
}
/*
void CPanel::SortItems(int index)
{
if (index == _sortIndex)
_ascending = !_ascending;
else
{
_sortIndex = index;
_ascending = true;
switch (_properties[_sortIndex].ID)
{
case kpidSize:
case kpidPackedSize:
case kpidCTime:
case kpidATime:
case kpidMTime:
_ascending = false;
break;
}
}
_listView.SortItems(CompareItems, (LPARAM)this);
_listView.EnsureVisible(_listView.GetFocusedItem(), false);
}
void CPanel::SortItemsWithPropID(PROPID propID)
{
int index = _properties.FindItemWithID(propID);
if (index >= 0)
SortItems(index);
}
*/
void CPanel::SortItemsWithPropID(PROPID propID)
{
if (propID == _sortID)
_ascending = !_ascending;
else
{
_sortID = propID;
_ascending = true;
switch (propID)
{
case kpidSize:
case kpidPackSize:
case kpidCTime:
case kpidATime:
case kpidMTime:
_ascending = false;
break;
}
}
SetSortRawStatus();
if (sizeof(long) != sizeof(LPARAM)) {
printf("INTERNAL ERROR : sizeof(long) != sizeof(LPARAM)\n");
exit(-1);
}
_listView.SortItems(CompareItems_WX, (LPARAM)this); // FIXED _listView.SortItems(CompareItems, (LPARAM)this);
_listView.EnsureVisible(_listView.GetFocusedItem(), false);
}
void CPanel::OnColumnClick(LPNMLISTVIEW info)
{
/*
int index = _properties.FindItemWithID(_visibleProperties[info->iSubItem].ID);
SortItems(index);
*/
SortItemsWithPropID(_visibleProperties[info->iSubItem].ID);
}