Forum > LCL

[Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)

(1/3) > >>

d7_2_laz:
I think about for certain use cases to use more the Shell Controls instead of self written  stuff.
Because it's easy, slim and fast to use without much overhead. Nowadays even with builtin system icons ...
Actually i stumble across two things though. One is this small one:

Regarding folders as well as files, differently from common used file explorers / windows items beginning with underbar ("_") are sorted at the end, not at the beginning:
I noticed that because i'm using the underscore oftenly to bring some items in a certain attention:
__savedVersions
_tempStuff
Work1

I'd suggest that the comps follow the established sorting rules, eg. shown by Windows explorer, or others.

On the other hand:
for the shell listview i assume that using the OnCompare callback resp. some customsort rules possibly could customize that on app level-
But: the shell treeview does not expose such an OnCompare, right??
It seems to use "CompareText" and this returns:
CompareText ('a', 'b')    -1  (negative value) 'a' is smaller thand 'b'
CompareText ('_', 'b')    30  (positive value) '_' is greater than 'a'

Rrenark:
AnsiCompareText instead would deliver the desired result. I don't know if it can ssen as a good solution.  but at least it does met the expectation (i tried it with the ShellViewEx demo that was contributed times ago within the forum (fantasic demo!). That uses self-coded "GetFiles" (virtual paradigm, OwnerData) for to gain speed. And it exposes a sort routine that i could adapt and test.

However, AnsiCompareText seems to slowdown the process here, as i could see (nearly doubled speed loss) . A conditional usage of this function does solve that effect sufficiently.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---function Compare(Item1, Item2: Pointer): Integer;var FileData1: PFileData; FileData2: PFileData; S1, S2: String;begin  FileData1 := PFileData(Item1);  FileData2 := PFileData(Item2);  if (FileData1^.FIsDir = FileData2^.FIsDir) then begin        S1 := FileData1^.FName;        S2 := FileData2^.FName;        if ((Pos('_', S1) > 0) Or (Pos('_', S2) > 0)) then           Compare := AnsiCompareText(S1, S2)        else           Compare := CompareText(S1, S2);  end  else    Compare := Ord(FileData2^.FIsDir) - Ord(FileData1^.FIsDir)end;
But how to apply that sort override to the shell treeview?

d7_2_laz:
For the ShellTreeView, it would work just as expected, if the function FilesSortAlphabet would be changed as:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---function FilesSortAlphabet(p1, p2: Pointer): Integer;var  f1, f2: TFileItem; S1, S2: String;begin  f1:=TFileItem(p1);  f2:=TFileItem(p2);  // Replace:  //Result:=CompareText(f1.FileInfo.Name, f2.FileInfo.Name);  // By:  S1 := f1.FileInfo.Name;  S2 := f2.FileInfo.Name;  if ((Pos('_', S1) > 0) Or (Pos('_', S2) > 0)) then     Result := AnsiCompareText(S1, S2)  else     Result := CompareText(S1, S2);end; (when FileSortType is set to  fstAlphabet)

wp:

--- Quote from: d7_2_laz on November 25, 2022, 02:52:09 pm ---i'm using the underscore oftenly to bring some items in a certain attention:
__savedVersions
_tempStuff
Work1
--- End quote ---
I do that too, and find it very convenient. However, this seems to be windows-only. When I look at these folder from a VM with Linux I see a different sort order in the file managers which simply ignores the underscores (see attachment). So, we must be careful to not change the default order people are accustomed to. Therefore, I am afraid that hacking the FilesSortAlphabet function is not an allowed option.

TShellTreeView has built-in sorting, defined by the FileSortType = (fstNone, fstAlphabet, fstFoldersFirst). For the latter two cases, the files are sorted in the implementation-only procedure GetFilesInDir. This procedure uses an internal TList to store the relevant data of each file in an instance of a TFileItem class containing the SearchRec and the base path. Sorting uses the pointers to these objects as arguments in the compare functions. The problem is that TFileItem is an internal class and cannot be accessed from outside the unit.

Therefore, it is not possible to extend TFileSortType by some fstCustom option and give GetfilesInDir an additional optional CompareFunc parameter... That was my first idea. I am afraid that all other solutions will require deeper changes in the ShellTreeView internals.

d7_2_laz:
Yes, i understand these points (and feared this a bit).

So even no chance to open the access to  this function incl. TFileItem for a class helper? Tthat wouldn't change any existing behaviour, but could give an app a chance to modify it.
(I'd guess it's rather not possible and i'd need to patch the shellctrls.pas each time)

wp:
Ignoring the compare function which you'd have to write anyway, here's a one-liner to sort the nodes of the shelltreeview in your preferred way:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---function TForm1.TreeViewCompare(Node1, Node2: TTreeNode): Integer;var  fn1, fn2: String;begin  fn1 := Node1.Text;  fn2 := Node2.Text;  if ((Pos('_', fn1) > 0) or (Pos('_', fn2) > 0)) then     Result := AnsiCompareText(fn1, fn2)  else     Result := CompareText(fn1, fn2);end; procedure TForm1.ShellTreeView1Expanded(Sender: TObject; Node: TTreeNode);begin  Node.CustomSort(@TreeViewCompare);end;
Keep ShellTreeView.FileSortType at fstNone to avoid duplicate sorting.

Navigation

[0] Message Index

[#] Next page

Go to full version