How to copy folders to another location while adding the paths to a listbox?

Hi my friends!

Here's what I would like to do >

By a buttonclick I want to pop up the browseforfolder dialog and copy the selected folder + contents to another predefined location while adding the  path to a listbox.
My predefined location will be: D:\Data.
My listbox is empty.
I select the folder C:\Blahblah and then its contents is copied to D:\Data\Blahblah and my listbox holds one item > D:\Data\Blahblah. Adding or deleting an item from the listbox should result in adding or deleting the folder it references.

Ofcourse I could also first copy all folders to the D:\Data folder and afterwards collect the references and feed them to the listbox. What would be teh best approach?

Kind regards,

Paul

Ps working samples do the trick..

Oh btw > Afterwards I want all the references in a comma seperated list.
PeterdeBAsked:
Who is Participating?
 
TNameConnect With a Mentor Commented:
>So when I add or delete something from the listbox, the item should be removed from the data folder as well and vice versa.

I understand the delete part. What I don't quite understand is the add part.
If you add a filename/path to the listbox other than with the procedures provided  in this thread, how do you tell the listbox where the folder is originally located? (see comment in code)
The example below intercepts the add/delete messages for listbox1 to implement the changes in D:\Data ("add" not implemented for the reasons mentioned above). If you shift-click on an item, the corresponding folder will be deleted (this is just to test the delete functionality). Even if you delete a Listbox item by other means, it will try to delete the folder. Again: Test carefully!


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, FileCtrl, StdCtrls, ShellAPI;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure ListBox1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    function DelDir(DirName : string): Boolean;
    procedure MoveDir(FromDir,ToDir:String);
    procedure CopyFolder(SrcFolder, ToFolder : String);
  public
    OldLBWndProc: TWndMethod;
    procedure LBWndProc(var Message: TMessage);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  OldLBWndProc := ListBox1.WindowProc;
  ListBox1.WindowProc := LBWndProc;
end;

procedure TForm1.LBWndProc(var Message: TMessage);
begin
  case Message.Msg of
    LB_DELETESTRING: begin
                       try
                          DelDir(ListBox1.Items[Message.WParam])
                       except
                         ShowMessage('Could not delete folder');
                       end;
                     end;
    //LB_ADDSTRING   : ShowMessage(string(Message.LParam));
    // How do you know where the folder is initially located?
    // LB_ADDSTRING   : MoveDir(?????,string(Message.LParam));
  end;
  OldLBWndProc(Message);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  DirSelected, NewName: string;
begin
  if SelectDirectory('Select a folder:', 'C:\', DirSelected) then begin
    NewName:='D:\Data\'+ExtractFileName(DirSelected);
    MoveDir(DirSelected,NewName);
  end
  else
    ShowMessage('No folder selected');
end;

procedure TForm1.MoveDir(FromDir,ToDir:String);
begin
    ListBox1.AddItem(ToDir,nil);
    CopyFolder(FromDir,ToDir);
    DelDir(FromDir);
end;

function TForm1.DelDir(DirName : string): Boolean;
var
  SHFileOpStruct : TSHFileOpStruct;
  Buffer : array [0..255] of Char;
begin
  try
   Fillchar(SHFileOpStruct,Sizeof(SHFileOpStruct),0) ;
   FillChar(Buffer, Sizeof(Buffer), 0 ) ;
   StrPCopy(Buffer, DirName) ;
   with SHFileOpStruct do begin
    Wnd := 0;
    pFrom := @Buffer;
    wFunc := FO_DELETE;
    fFlags := FOF_ALLOWUNDO;
    fFlags := fFlags or FOF_NOCONFIRMATION;
    fFlags := fFlags or FOF_SILENT;
   end;
    Result := (SHFileOperation(SHFileOpStruct) = 0) ;
   except
    Result := False;
  end;
end;

procedure TForm1.CopyFolder(SrcFolder, ToFolder : String);
var
  SearchRec : TSearchRec;
  Src, Dst     : String;

begin
  Src := IncludeTrailingBackslash(SrcFolder);
  Dst := IncludeTrailingBackslash(ToFolder);
  ForceDirectories(Dst);
   if FindFirst(Src + '*', faAnyFile, SearchRec) = 0 then
    try
      repeat
        with SearchRec do
          if (Name <> '.') and (Name <> '..') then
            if (Attr and faDirectory) > 0 then
              CopyFolder(Src + Name, Dst + Name)
            else
              CopyFile(Pchar(Src + Name), PChar(Dst + Name), True);
      until FindNext(SearchRec) <> 0;
    finally
      FindClose(SearchRec);
    end;
end;

procedure TForm1.ListBox1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
  var
  i:Integer;
begin
 i:=ListBox1.ItemAtPos(Point(X,Y),True);
 if (i>=0) and (ssCtrl in Shift) then begin
    ListBox1.Items.Delete(i);
 end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ListBox1.WindowProc:=OldLBWndProc;
end;

end.
0
 
calinutzCommented:
The best approach would be to add the path everytime you do a copying. The browseforFolder dialog is unknown for me , do you mean the jedi jvBrowseForFolderDialog.
Is this what you want to achieve ?(with OpenDialog)
If OpenDialog1.Execute then
begin
   filename := OpenDialog1.FileName;
  // here the copying files part
  ListBox1.Items.Add(ExtractFileDir(filename));
end;
 

0
 
calinutzCommented:
more with this using jedi's component:

// first a procedure to copy contents of a source folder to a destination folder:
procedure CopyDir(SourceDirPath, DestDirPath: String);
var f: TSearchRec;
    IntFileAttribute: Integer;
begin
  if not (SourceDirPath[Length(SourceDirPath)] = '\')
    then SourceDirPath := SourceDirPath + '\';

  if not (DestDirPath[Length(DestDirPath)] = '\')
    then DestDirPath := DestDirPath + '\';

  FileMode:=0;
  if FindFirst(SourceDirPath + '*.*', faAnyFile, f) = 0 then
  begin
  repeat
       try
        if (f.Attr and faDirectory ) < $00000008 then
        begin
          CopyFile(PChar(SourceDirPath+f.Name),PChar (DestDirPath+f.Name),True);
          IntFileAttribute := FileGetAttr(DestDirPath + f.Name);
          FileSetAttr(DestDirPath + f.Name, IntFileAttribute);
        end;
       except
        on e: exception do
          ShowMessage(E.Message);
       end;
  until findNext(f) <> 0;
  FindClose(f);
  end;
end;


// then have a procedure that deletes the files from the used default destination folder of yours (that you could alter and put the destination folder to be variable....)

procedure DelDir(SourceDirPath: String);
var f: TSearchRec;
begin
  if not (SourceDirPath[Length(SourceDirPath)] = '\')
    then SourceDirPath := SourceDirPath + '\';

  FileMode:=0;
  if FindFirst(SourceDirPath + '*.*', faAnyFile, f) = 0 then
  begin
  repeat
       try
        if (f.Attr and faDirectory ) < $00000008 then
        begin
          DeleteFile(PChar(SourceDirPath+f.Name));
        end;
       except
        on e: exception do
          ShowMessage(E.Message);
       end;
  until findNext(f) <> 0;
  FindClose(f);
RemoveDir(SourceDirPath);
  end;
end;

//  this is not tested... but it should work. Anyway you should get the ideea afterall
// and then the events... for the button and for the ListBox:

//For the button (where Dialog1 = jvBrowseForFolderDialog)
   if Dialog1.Execute then
   begin
     If DirectoryExists('D:\Data')=false then CreateDir('D:\Data');
   CopyDir(Dialog1.Directory,'D:\Data');
   ListBox1.Items.Add(Dialog1.Directory);
   end;

// and for the onKeyUp event of the ListBox:

If Key=VK_DELETE then
begin
  ShowMessage(ListBox1.Items[ListBox1.SelCount]);
  Deldir(ListBox1.Items[ListBox1.SelCount]);
  ListBox1.DeleteSelected;
  end;
end;

This last one needs work but as I said before You should get the ideea (there's not much work to do left)
The ideea is that
1. You should make the copyfolder procedure create a text file (maybe an ini file) in the destination folder that would gather the copied filenames and assign to them the old path. Something like:
myfile.pdf - c:\FolderX\FolderY\myfile.pdf
myfile2.exe - c:\FolderX\FolderY\myfile2.exe
...

the deletefolder procedure should look inside this file and check which files corespond to the path that the item is showing.
And that would be all

Regards
0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

 
kretzschmarCommented:
from my paq:

u can use the shell-api,
to display the os-progress

sample

uses shellapi;

//moving file or dir with simple progress
procedure TForm1.Button1Click(Sender: TObject);
var I : Integer;
    opInfo : _SHFILEOPSTRUCT;
begin
  opInfo.pFrom := 'd:\TmpFolder';
  opInfo.pTo   := 'u:\';
  opInfo.wFunc := FO_MOVE;
  opInfo.fFlags := FOF_NOCONFIRMATION  or
                   FOF_NOCONFIRMMKDIR or
                   FOF_RENAMEONCOLLISION or
                   FOF_SIMPLEPROGRESS;
  opInfo.hNameMappings := nil;
  opInfo.fAnyOperationsAborted := False;
  opInfo.lpszProgressTitle := 'Moving . . .';
  opInfo.Wnd := self.handle;
  SHFileOperation(opInfo);
end;

//copy file or dir with simple progress
procedure TForm1.Button2Click(Sender: TObject);
var I : Integer;
    opInfo : _SHFILEOPSTRUCT;
begin
  opInfo.pFrom := 'd:\Programme\Borland\delphi5\help\del5vcl.hlp';
  opInfo.pTo   := 'u:\';
  opInfo.wFunc := FO_COPY;
  opInfo.fFlags := FOF_NOCONFIRMATION  or
                   FOF_NOCONFIRMMKDIR or
                   FOF_RENAMEONCOLLISION or
                   FOF_SIMPLEPROGRESS;
  opInfo.hNameMappings := nil;
  opInfo.fAnyOperationsAborted := False;
  opInfo.lpszProgressTitle := 'Copying . . .';
  opInfo.Wnd := self.handle;
  SHFileOperation(opInfo);
end;

meikl ;-)
0
 
TNameCommented:
Hi, this does everything except deleting when you click in the stringlist.
Will post that in a follow up.
Not fully tested. Take care what you click on in the browse for folder dialog. No confirmation before deleting!

Put a listbox and a button on a form:


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, FileCtrl, StdCtrls, ShellAPI;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    function DelDir(DirName : string): Boolean;
    procedure CopyFolder(SrcFolder, ToFolder : String);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  DirSelected, NewName: string;

begin
  if SelectDirectory('Select a folder:', 'C:\', DirSelected) then begin
    NewName:='D:\Data\'+ExtractFileName(DirSelected);
    ListBox1.AddItem(NewName,nil);
    CopyFolder(DirSelected,NewName);
    DelDir(DirSelected);
  end
  else
    ShowMessage('No folder selected');
end;


function TForm1.DelDir(DirName : string): Boolean;
var
  SHFileOpStruct : TSHFileOpStruct;
  Buffer : array [0..255] of Char;
begin
  try
   Fillchar(SHFileOpStruct,Sizeof(SHFileOpStruct),0) ;
   FillChar(Buffer, Sizeof(Buffer), 0 ) ;
   StrPCopy(Buffer, DirName) ;
   with SHFileOpStruct do begin
    Wnd := 0;
    pFrom := @Buffer;
    wFunc := FO_DELETE;
    fFlags := FOF_ALLOWUNDO;
    fFlags := fFlags or FOF_NOCONFIRMATION;
    fFlags := fFlags or FOF_SILENT;
   end;
    Result := (SHFileOperation(SHFileOpStruct) = 0) ;
   except
    Result := False;
  end;
end;

procedure TForm1.CopyFolder(SrcFolder, ToFolder : String);
var
  SearchRec : TSearchRec;
  Src, Dst     : String;

begin
  Src := IncludeTrailingBackslash(SrcFolder);
  Dst := IncludeTrailingBackslash(ToFolder);
  ForceDirectories(Dst);
   if FindFirst(Src + '*', faAnyFile, SearchRec) = 0 then
    try
      repeat
        with SearchRec do
          if (Name <> '.') and (Name <> '..') then
            if (Attr and faDirectory) > 0 then
              CopyFolder(Src + Name, Dst + Name)
            else
              CopyFile(Pchar(Src + Name), PChar(Dst + Name), True);
      until FindNext(SearchRec) <> 0;
    finally
      FindClose(SearchRec);
    end ;
end;


end.
0
 
TNameCommented:
>except deleting when you click in the stringlist
Ok, I see calinutz's solution already provides that too...
0
 
TNameCommented:
Well, just for the record  ;)

procedure TForm1.ListBox1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
  var
  i:Integer;
begin
 i:=ListBox1.ItemAtPos(Point(X,Y),True);
 if i>=0 then begin
   DelDir(ListBox1.Items[i]);
   ListBox1.Items.Delete(i);
 end;
end;
0
 
TNameCommented:
>Adding or deleting an item from the listbox should result in adding or deleting the folder it references.

Forget my last post, it deletes the entry you click on, I somehow misunderstood it.
And I'm still not sure what this means "should result in adding or deleting the folder it references"...
Add from where? Do you add items to the listbox manually also? But maybe someone else did alredy understand your intentions better... :)
0
 
PeterdeBAuthor Commented:
Hi TName!

The listbox should reflect the data folders content. So when I add or delete something from the listbox, the item should be removed from the data folder as well and vice versa.

Kind regards,

Paul
0
 
PeterdeBAuthor Commented:
Hi my friend!

I just noticed your tremendous reply! I tried it...it works...not sure what your question regarindg adding is about....

My kind regards,

Paul :)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.