Recent

Author Topic: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)  (Read 3606 times)

TRon

  • Hero Member
  • *****
  • Posts: 4141
Re: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)
« Reply #15 on: January 27, 2025, 05:21:04 pm »
Is this not due to
Code: Pascal  [Select][+][-]
  1. if not FileExists(CurrentNodePath) then
  2.  
It is after all a directory not a file ?
Today is tomorrow's yesterday.

jipété

  • Full Member
  • ***
  • Posts: 191
Re: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)
« Reply #16 on: January 28, 2025, 12:02:16 pm »
Please post a small project demonstrating the issue.

It is the shelltreeview_custom.zip as found in https://forum.lazarus.freepascal.org/index.php/topic,61347.msg462091.html#msg462091.

Just replaced the last begin-end part of the original procedure TCustomShellTreeView.DoSelectionChanged; with this one :
Code: Pascal  [Select][+][-]
  1. procedure TCustomShellTreeView.DoSelectionChanged;
  2. ...
  3.     begin
  4. showmessage(CurrentNodePath); // OK
  5. //      if not FileExistsUtf8(CurrentNodePath) then // commented out for test
  6.       if not FileExists(CurrentNodePath) then // but same bad result
  7.         Raise EShellCtrl.CreateFmt(sShellCtrlsSelectedItemDoesNotExists,[CurrentNodePath]);
  8.       if Assigned(Anode.Parent) then
  9.         FShellListView.Root := GetPathFromNode(ANode.Parent)
  10.       else
  11.         FShellListView.Root := '';
  12.     end;
  13.   end;
  14. end;

and then, after reading the TRon post, simply comment out the
Code: Pascal  [Select][+][-]
  1. if not FileExists(CurrentNodePath) then
line and add below
Code: Pascal  [Select][+][-]
  1. if not DirectoryExists(CurrentNodePath) then // new, better
Now it runs OK but with strange results : after F9 I see one ShowMessage with the ShellTreeview.root string but anywhere else I click I don't see other ShowMessage.
If I click on 6_fonts_Vista folder, I don't see a sorted result.

If I ask Linux to sort by name in the pcmanfm ExplorerFile, of course the result begins with calibri.ttf (bottom of img, "6_fonts_Vista"), but it is not or badly sorted in the top window ("Form1") from shelltreeview_custom.zip.

It is after all a directory not a file ?
I remember that sentence, "in Linux everything is file".
After all, a directory is just a special file, isn't it ?
Regards,
« Last Edit: January 28, 2025, 12:10:27 pm by jipété »

wp

  • Hero Member
  • *****
  • Posts: 12682
Re: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)
« Reply #17 on: January 28, 2025, 01:52:37 pm »
Now I can reproduce the issue. I am on Windows, though, with some chance that things may be different. But the issue seems to be that the root node is not detected as a directory which forced the code into the file branch of the "if".

I'd ask you to try the following modification in TShellTreeNode.IsDirectory, and to report back:

Code: Pascal  [Select][+][-]
  1.  function TShellTreeNode.IsDirectory: Boolean;
  2. begin
  3.   Result := (Owner.GetFirstNode = self) or ((FFileInfo.Attr and faDirectory) > 0);   // Added "(...) or"
  4. end;  
« Last Edit: January 28, 2025, 03:12:09 pm by wp »

TRon

  • Hero Member
  • *****
  • Posts: 4141
Re: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)
« Reply #18 on: January 28, 2025, 03:11:56 pm »
It is after all a directory not a file ?
I remember that sentence, "in Linux everything is file".
After all, a directory is just a special file, isn't it ?
Yes and no  :)

But, to be fair, the behaviour for FPC changed over the years. It is now required to use the functions FileExists and DirectoryExists as intended.
Today is tomorrow's yesterday.

wp

  • Hero Member
  • *****
  • Posts: 12682
Re: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)
« Reply #19 on: January 28, 2025, 04:11:03 pm »
... try the following modification in TShellTreeNode.IsDirectory...
I think now that this is just a workaround without solving the real issue. TShellTreeView creates nodes of its own type, TShellTreeNode, which contain the searchrecord (FileInfo) found during populating the tree. The problem is that there are places in the code where the searchrecord is not assigned to the TShellTreeNode.FileInfo, and this happens when custom sorting is active and the root node is not the root of the file system.

As "real" fix please make the following modifications
  • Add a new method CreateRootNode to the private section of TCustomShellTreeView and implement it as follows below
  • Call it in TCustomShellTreeView.SetRoot, .SetFileSortType, and .SetOnSortCompare to replace the currently used RootNode := Items.AddChild(nil, APath), and remove the following assignments to TShellTreeNode(RootNode) since they are already contained in CreateRootNode
Code: Pascal  [Select][+][-]
  1. function TCustomShellTreeView.CreateRootNode(const APath: string): TTreeNode;
  2. var
  3.   dirInfo: TSearchRec;
  4. begin
  5.   Result := Items.AddChild(nil, APath);
  6.   TShellTreeNode(Result).SetBasePath('');
  7.   FindFirstUTF8(APath, faAnyFile, dirInfo);
  8.   TShellTreeNode(Result).FFileInfo := dirInfo;
  9.   FindCloseUTF8(dirInfo);
  10.   Result.HasChildren := True;
  11.   Result.Expand(False);
  12. end;
  13.  
  14. procedure TCustomShellTreeView.SetRoot(const AValue: string);
  15. ...
  16.     //Add a node for Root and expand it (issue #0024230)
  17.     //Make FRoot contain fully qualified pathname, we need it later in GetPathFromNode()
  18.     FRoot := ExpandFileNameUtf8(FRoot);
  19.     //Set RootNode.Text to AValue so user can choose if text is fully qualified path or not
  20.     RootNode := CreateRootNode(AValue);
  21.   end;
  22.   if Assigned(ShellListView) then
  23.     ShellListView.Root := FRoot;
  24. end;
  25.  
  26. procedure TCustomShellTreeView.SetFileSortType(const AValue: TFileSortType);
  27. ...
  28.     else
  29.     begin
  30.       RootNode := CreateRootNode(FRoot);
  31.       if ExistsAndIsValid(CurrPath) then
  32.         SetPath(CurrPath);
  33.     end;
  34.   finally
  35.     EndUpdate;
  36.   end;
  37. end;  
  38.  
  39. procedure TCustomShellTreeView.SetOnSortCompare(AValue: TFileItemCompareEvent);
  40. ...
  41.     else
  42.     begin
  43.       RootNode := CreateRootNode(FRoot);
  44.       if ExistsAndIsValid(Currpath) then
  45.         SetPath(CurrPath);
  46.     end;
  47.   finally
  48.     EndUpdate;
  49.   end;
  50. end;  

I am not sure about the consequences of the SetRoot "Set RootNode.Text to AValue so user can choose if text is fully qualified path or not" since the "AValue" used in SetRoot has been replaced by the fully qualified root path in SetFileSortType and SetOnSortCompare.



Filed a bug report https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/41373
« Last Edit: January 28, 2025, 07:26:28 pm by wp »

jipété

  • Full Member
  • ***
  • Posts: 191
Re: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)
« Reply #20 on: January 28, 2025, 07:49:17 pm »
Hi !

I can't answer your request because your code relies on a function that I don't have: ExistsAndIsValid, and yet I just upgraded to Laz 3.8.

I don't know what to do.

wp

  • Hero Member
  • *****
  • Posts: 12682
Re: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)
« Reply #21 on: January 28, 2025, 08:22:48 pm »
Where do you need ExistsAndIsValid? You cannot apply the bugreport patch to Laz 3.8 because it depends on Laz/main, but you can follow the verbal description.

Here are the new CreateRootNode method (which you should declare in the private or protected section of TCustomShellTreeView), as well as the fully patched SetFileSortType and SetOnSortCompare methods (which you just copy over the existing ones). There is no immediate need to patch SetRoot (I just included it in my patch because it contains duplicated code).
Code: Pascal  [Select][+][-]
  1. function TCustomShellTreeView.CreateRootNode(const APath: string): TTreeNode; TCustomShellTreeView
  2. var
  3.   dirInfo: TSearchRec;
  4. begin
  5.   Result := Items.AddChild(nil, APath);
  6.   TShellTreeNode(Result).SetBasePath('');
  7.   FindFirstUTF8(APath, faAnyFile, dirInfo);
  8.   TShellTreeNode(Result).FFileInfo := dirInfo;
  9.   FindCloseUTF8(dirInfo);
  10.   Result.HasChildren := True;
  11.   Result.Expand(False);
  12. end;
  13.  
  14. procedure TCustomShellTreeView.SetFileSortType(const AValue: TFileSortType);
  15. var
  16.   RootNode: TTreeNode;
  17.   CurrPath: String;
  18. begin
  19.   if FFileSortType=AValue then exit;
  20.   FFileSortType:=AValue;
  21.   if (([csLoading,csDesigning] * ComponentState) <> []) then Exit;
  22.   CurrPath := GetPath;
  23.   try
  24.     BeginUpdate;
  25.     Items.Clear;
  26.     if FRoot = '' then
  27.       PopulateWithBaseFiles()
  28.     else
  29.     begin
  30.       RootNode := CreateRootNode(FRoot);
  31.       if ExistsAndIsValid(CurrPath) then
  32.         SetPath(CurrPath);
  33.     end;
  34.   finally
  35.     EndUpdate;
  36.   end;
  37. end;
  38.  
  39. procedure TCustomShellTreeView.SetOnSortCompare(AValue: TFileItemCompareEvent);
  40. var
  41.   RootNode: TTreeNode;
  42.   CurrPath: String;
  43. begin
  44.   if TMethod(AValue) = TMethod(FOnSortCompare) then
  45.     Exit;
  46.  
  47.   FOnSortCompare := AValue;
  48.  
  49.   if (([csLoading,csDesigning] * ComponentState) <> []) or (FFileSortType <> fstCustom) then
  50.     Exit;
  51.  
  52.   CurrPath := GetPath;
  53.   try
  54.     BeginUpdate;
  55.     Items.Clear;
  56.     if FRoot = '' then
  57.       PopulateWithBaseFiles()
  58.     else
  59.     begin
  60.       RootNode := CreateRootNode(FRoot);
  61.       if ExistsAndIsValid(Currpath) then
  62.         SetPath(CurrPath);
  63.     end;
  64.   finally
  65.     EndUpdate;
  66.   end;
  67. end;

With these changes the bug is gone in Laz 3.6.

But make a backup copy of the shellctrls.pas file before changing it.

jipété

  • Full Member
  • ***
  • Posts: 191
Re: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)
« Reply #22 on: January 29, 2025, 10:14:59 am »
Where do you need ExistsAndIsValid?
Yesterday, see yesterday.png

you can follow the verbal description.
dunno where to get that.

With these changes the bug is gone in Laz 3.6.
or 3.8 but I cannot apply the changes, my Lazarus 3.8 complains about ExistsAndIsValid.
see ExistsAndIsValid.png

But make a backup copy of the shellctrls.pas file before changing it.
As usual.

My original shellctrls.pas version 3.8 has 54513 bytes, the one I find here https://gitlab.com/freepascal.org/lazarus/lazarus/-/blob/b1d3af8d2155442a1fda2ffa1d04c5f00c711a2c/lcl/shellctrls.pas has 59341 bytes.
So I tried to replace mine with this one from gitlab, still bugged... On the 1137 line I get a SigSegv.
See sigsegv.png

Maybe I must apply the lines from your last post ?

Well, shellctrls.pas is a nightmare !
and version control is a disgrace...

wp

  • Hero Member
  • *****
  • Posts: 12682
Re: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)
« Reply #23 on: January 29, 2025, 11:04:58 am »
shellctrls.pas is not a nightmare. The problem is that I (working with Laz main) included the neighbouring line around the patch locations to help you find the location to be changed, and these neighbouring lines (if ExistsAndIsValid) are not available in Laz 3.8.

I installed a fresh Laz 3.8 and patched the shellctrls.pas for you. Just unzip the attachment and copy the unit over its original in folder lcl of your Laz 3.8 installation.

jipété

  • Full Member
  • ***
  • Posts: 191
Re: [Solved] Shell controls sorting rule (CompareText vs. AnsiCompareText)
« Reply #24 on: January 29, 2025, 11:58:12 am »
I installed a fresh Laz 3.8 and patched the shellctrls.pas for you. Just unzip the attachment and copy the unit over its original in folder lcl of your Laz 3.8 installation.
Thanks for your efforts.

Now it works.

But in the Lazarus way, that is to say that the one holding the mouse does not understand the results displayed, for example, the sorts "by Name" and "custom (by size)" return the same results, when there are only folders.
If there are also files, ok, they are sorted but just on the left, not on the right, in the Listview, where it would be useful to find the size if we have chosen a sort by size, for example.

Have a nice day.

 

TinyPortal © 2005-2018