Recent

Author Topic: [SOLVED]TShellTreeView - how to rename a folder  (Read 5665 times)

petevick

  • Sr. Member
  • ****
  • Posts: 419
[SOLVED]TShellTreeView - how to rename a folder
« on: February 02, 2022, 07:16:18 pm »
I have a TShellTreeView in a small test project. With the ReadOnly property set to False, you can appear to edit/rename a folder caption by double clicking with a delay. This all looked good for renaming, but when the TShellTreeView is refreshed, the folder caption is not renamed. Have I missed some other property ??
I've even tried a simplistic way of renaming the folder......
Code: Pascal  [Select][+][-]
  1. TreeView.Selected.Text := 'Lets try this';
...but that doesn't work either.  %)
« Last Edit: February 02, 2022, 09:27:14 pm by petevick »
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

wp

  • Hero Member
  • *****
  • Posts: 13264
Re: TShellTreeView - how to rename a folder
« Reply #1 on: February 02, 2022, 07:19:15 pm »
The ShellTreeView does not propagate the renaming action to the file system. You must rename the file/directory yourself.
« Last Edit: February 02, 2022, 08:00:46 pm by wp »

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: TShellTreeView - how to rename a folder
« Reply #2 on: February 02, 2022, 07:26:17 pm »
The ShellTreeView does not propage the renaming action to the file system. You must rename the file/directory yourself.
Thanks for the reply. So how would one go about that  :-[
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

balazsszekely

  • Guest
Re: TShellTreeView - how to rename a folder
« Reply #3 on: February 02, 2022, 08:48:27 pm »
Create an OnEdited event for the tree:
Code: Pascal  [Select][+][-]
  1. uses LazFileUtils, StrUtils;
  2.  
  3. procedure TForm1.ShellTreeView1Edited(Sender: TObject; Node: TTreeNode;
  4.   var S: string);
  5. var
  6.   OldPath: String;
  7.   NewPath: String;
  8.   P: Integer;
  9. begin
  10.   OldPath := AppendPathDelim(Node.GetTextPath);
  11.   OldPath := StringReplace(OldPath, '/', DirectorySeparator, [rfReplaceAll]);
  12.   NewPath := ReverseString(OldPath);
  13.   Delete(NewPath, 1, 1);
  14.   P := Pos(DirectorySeparator, NewPath);
  15.   Delete(NewPath, 1, P - 1);
  16.   NewPath := AppendPathDelim(ReverseString(NewPath) + S);
  17.   ShowMessage('Old path: ' + OldPath + sLineBreak +
  18.               'New path: ' + Newpath);
  19. end;    

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: TShellTreeView - how to rename a folder
« Reply #4 on: February 02, 2022, 09:01:56 pm »
Thanks for the reply GetMem, I'll take a look later when I've got time to properly understand the code  :)
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: TShellTreeView - how to rename a folder
« Reply #5 on: February 02, 2022, 09:15:08 pm »
Create an OnEdited event for the tree:
Unfortunately GetMem it's not working. It all seems to work, OldPath and Newpath variables display correctly, as does the folder text in the tree after closing the message dialog. But after a refresh of the tree the folder text reverts back to OldPath  :(
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

balazsszekely

  • Guest
Re: TShellTreeView - how to rename a folder
« Reply #6 on: February 02, 2022, 09:19:23 pm »
@petevick
Quote
Unfortunately GetMem it's not working. It all seems to work, OldPath and Newpath variables display correctly, as does the folder text in the tree after closing the message dialog. But after a refresh of the tree the folder text reverts back to OldPath

Well I assumed that you will do the renaming. Anyways instead of  the last liine(Showmessage...), you need:
Code: Pascal  [Select][+][-]
  1. if RenameFile(OldPath, NewPath) then
  2.   //success
  3. else
  4.   //error handling

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: TShellTreeView - how to rename a folder
« Reply #7 on: February 02, 2022, 09:26:45 pm »
Well I assumed that you will do the renaming. Anyways instead of  the last liine(Showmessage...), you need:
Code: Pascal  [Select][+][-]
  1. if RenameFile(OldPath, NewPath) then
  2.   //success
  3. else
  4.   //error handling
:-[ :-[  ermm yes, well, that would have helped I guess........well would you look at that works just fine.
I blame it on a brain fart moment  :-[


Thanks again GetMem  ;D
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

balazsszekely

  • Guest
Re: [SOLVED]TShellTreeView - how to rename a folder
« Reply #8 on: February 03, 2022, 08:59:11 am »
@petevick

I forgot that you can also add files to TShellTreeView, so a better and more simplistic approach would be something like this:
Code: Pascal  [Select][+][-]
  1. uses LazFileUtils;
  2.  
  3. procedure TForm1.ShellTreeView1Edited(Sender: TObject; Node: TTreeNode;
  4.   var S: string);
  5. var
  6.   OldPath: String;
  7.   NewPath: String;
  8. begin
  9.   OldPath := TShellTreeNode(Node).FullFilename;
  10.   NewPath := TShellTreeNode(Node).BasePath + S;
  11.   if TShellTreeNode(Node).IsDirectory then
  12.   begin
  13.     OldPath := AppendPathDelim(OldPath);
  14.     NewPath := AppendPathDelim(NewPath);
  15.   end;
  16.  
  17.   if not RenameFile(OldPath, NewPath) then
  18.   begin
  19.     S := Node.Text;
  20.     MessageDlg('Cannot rename object! Error message:'  + sLineBreak + '"' + SysErrorMessage(GetLastOSError) + '"', mtError, [mbOK], 0);
  21.   end
  22. end;

Unfortunately both method fail on windows. The issue is related to the newly introduced shell icons. After renaming the node, the tree will try to load the icons from the old file, which is no longer exists(unit: win32wsshellctrls , method: TWin32WSCustomShellTreeView.DrawBuiltInIcon).

petevick

  • Sr. Member
  • ****
  • Posts: 419
Re: [SOLVED]TShellTreeView - how to rename a folder
« Reply #9 on: February 03, 2022, 10:40:51 am »
Unfortunately both method fail on windows. The issue is related to the newly introduced shell icons. After renaming the node, the tree will try to load the icons from the old file, which is no longer exists(unit: win32wsshellctrls , method: TWin32WSCustomShellTreeView.DrawBuiltInIcon).
Thanks for the updated code GetMem. I'm a bit confused though, both this and the previous version work in my Windows 10 VM  :-\
Pete Vickerstaff
Linux Mint 21.2 Cinnamon, Windows 10, Lazarus 3.2, FPC 3.2.2

balazsszekely

  • Guest
Re: [SOLVED]TShellTreeView - how to rename a folder
« Reply #10 on: February 03, 2022, 02:59:12 pm »
Quote
I'm a bit confused though, both this and the previous version work in my Windows 10 VM
I'm working with Lazarus trunk, where the issue is clearly visible.

wp

  • Hero Member
  • *****
  • Posts: 13264
Re: [SOLVED]TShellTreeView - how to rename a folder
« Reply #11 on: February 03, 2022, 04:58:48 pm »
Unfortunately both method fail on windows. The issue is related to the newly introduced shell icons. After renaming the node, the tree will try to load the icons from the old file, which is no longer exists(unit: win32wsshellctrls , method: TWin32WSCustomShellTreeView.DrawBuiltInIcon).
GetMem, being the author of the ShellTreeView icons on Windows I feel responsible for this. Can you post a project so that I can see the issue?

balazsszekely

  • Guest
Re: [SOLVED]TShellTreeView - how to rename a folder
« Reply #12 on: February 03, 2022, 05:21:04 pm »
@wp
Quote
GetMem, being the author of the ShellTreeView icons on Windows I feel responsible for this. Can you post a project so that I can see the issue?
Please run attached project, then edit a node(make sure you edit a dummy folder node, since the changes will be propagated back to the filesystem). An exception should occur in unit win32wsshellctrls , method TWin32WSCustomShellTreeView.DrawBuiltInIcon. The icon is not found since the tree is looking for the old file name, not the new one.

wp

  • Hero Member
  • *****
  • Posts: 13264
Re: [SOLVED]TShellTreeView - how to rename a folder
« Reply #13 on: February 03, 2022, 09:11:13 pm »
Thank you. The problem is that the text displayed in the node is not the true filename which is stored in the internal FileInfo record of the TShellTreeNode. So, when a node is renamed in the tree, only the Node.Text is changed, but not the filename in the FileInfo.

Unfortunately, the FileInfo is pretty well-sealed within the TShellTreeNode from the outside world, and I am afraid that the issue can only be solved within the ShellTreeViews unit. For test purposes, I added the following public method

Code: Pascal  [Select][+][-]
  1. function TCustomShellTreeView.Rename(ANode: TTreeNode; ANewName: String): Boolean;
  2. var
  3.   oldFullName, newFullName: String;
  4. begin
  5.   oldFullName := TShellTreeNode(ANode).FullFilename;
  6.   newFullName := TShellTreeNode(ANode).BasePath + ANewName;
  7.   if TShellTreeNode(ANode).IsDirectory then
  8.   begin
  9.     oldFullName := AppendPathDelim(oldFullName);
  10.     newFullname := AppendPathDelim(newFullName);
  11.   end;
  12.   Result := RenameFile(oldFullName, newFullName);
  13.   if Result then
  14.   begin
  15.     TShellTreeNode(ANode).FFileInfo.Name := ANewName;
  16.     ANode.Text := ANewName;
  17.   end;
  18. end;

And the event handler of your code would be
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ShellTreeView1Edited(Sender: TObject; Node: TTreeNode;
  2.   var S: string);
  3. begin
  4.   if not ShellTreeView1.Rename(Node, S) then
  5.   begin
  6.     S := Node.Text;
  7.     MessageDlg('Cannot rename object! Error message:'  + sLineBreak + '"' + SysErrorMessage(GetLastOSError) + '"', mtError, [mbOK], 0);
  8.   end
  9. end;

This works correctly in my tests. What I don't like is that the user probably expects that the ANewName argument could contain a full path in order to move the file to a different directory. However, if this were allowed the node would have to be moved to a completely different parent node, but it is not guaranteed that the new parent node exists in the tree at all.

Another, more elegant solution would be to override the setter for the node's Text property so that it automatically updates the internal FileInfo field. But this would require to declare the SetText method as virtual. And at the moment I don't overlook the issues that might occur when a new node is getting its caption for the first time. I also could imagine that there are use cases in which the displayed node text should be different from the filename.

balazsszekely

  • Guest
Re: [SOLVED]TShellTreeView - how to rename a folder
« Reply #14 on: February 03, 2022, 09:49:05 pm »
Quote
This works correctly in my tests. What I don't like is that the user probably expects that the ANewName argument could contain a full path in order to move the file to a different directory. However, if this were allowed the node would have to be moved to a completely different parent node, but it is not guaranteed that the new parent node exists in the tree at all.
TCustomShellTreeView.Rename looks good and in my opinion is not confusing at all, however if we allow rename to propagate to the filesystem, we should also allow delete/new to do the same. I'm afraid we gonna open Pandora's box. Better we leave the filesystem and the tree disconnected. Can you prevent the exception by checking if Ico <> nil? Perhaps load a default dir icon when GetShellIcon fails.
« Last Edit: February 03, 2022, 10:19:42 pm by GetMem »

 

TinyPortal © 2005-2018