Solved

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

Posted on 2006-11-05
10
2,216 Views
Last Modified: 2012-06-27
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.
0
Comment
Question by:PeterdeB
  • 5
  • 2
  • 2
  • +1
10 Comments
 
LVL 11

Expert Comment

by:calinutz
ID: 17876163
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
 
LVL 11

Expert Comment

by:calinutz
ID: 17876216
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
 
LVL 27

Expert Comment

by:kretzschmar
ID: 17876242
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
Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

 
LVL 28

Expert Comment

by:TName
ID: 17876283
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
 
LVL 28

Expert Comment

by:TName
ID: 17876302
>except deleting when you click in the stringlist
Ok, I see calinutz's solution already provides that too...
0
 
LVL 28

Expert Comment

by:TName
ID: 17876540
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
 
LVL 28

Expert Comment

by:TName
ID: 17876563
>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
 

Author Comment

by:PeterdeB
ID: 17876840
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
 
LVL 28

Accepted Solution

by:
TName earned 500 total points
ID: 17877306
>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
 

Author Comment

by:PeterdeB
ID: 17892220
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

Featured Post

Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In a recent question (https://www.experts-exchange.com/questions/28997919/Pagination-in-Adobe-Acrobat.html) here at Experts Exchange, a member asked how to add page numbers to a PDF file using Adobe Acrobat XI Pro. This short video Micro Tutorial sh…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …

816 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now