Menu

[r3166]: / trunk / Src / UUserDBMove.pas  Maximize  Restore  History

Download this file

224 lines (193 with data), 7.4 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
{
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/
*
* Copyright (C) 2013, Peter Johnson (www.delphidabbler.com).
*
* $Rev$
* $Date$
*
* Implements a class that moves the user defined database to a new location.
}
unit UUserDBMove;
interface
uses
// Delphi
Classes;
type
/// <summary>Class that moves the user defined database to a new location.
/// </summary>
TUserDBMove = class(TObject)
public
type
/// <summary>Type of event triggered by TUserDBMove to report progress
/// when moving the database files.</summary>
/// <param name="Sender">TObject [in] TUserDBMove instance that triggered
/// the event.</param>
/// <param name="Percent">Byte [in] Percentage of operation that has been
/// completed.</param>
TProgress = procedure(Sender: TObject; const Percent: Byte)
of object;
strict private
var
/// <summary>Reference to event handler for OnCopyFile event.</summary>
fOnCopyFile: TProgress;
/// <summary>Reference to event handler for OnDeleteFile event.</summary>
fOnDeleteFile: TProgress;
/// <summary>List of files in the database.</summary>
fDBFiles: TStrings;
/// <summary>Directory of existing user database.</summary>
fSourceDir: string;
/// <summary>Required new database directory.</summary>
fDestDir: string;
/// <summary>Triggers OnCopyFile event, with a percentage completeness
/// based on the given number of files copied.</summary>
procedure NotifyCopyFile(FileCount: Cardinal);
/// <summary>Triggers OnDeleteFile event, with a percentage completeness
/// based on the given number of files deleted.</summary>
procedure NotifyDeleteFile(FileCount: Cardinal);
/// <summary>Validates source and destination directories.</summary>
/// <exceptions>Raises EInOutError exception if either directory is not
/// valid.</exceptions>
procedure ValidateDirectories;
/// <summary>Calculates a returns percentage progress of towards a goal.
/// </summary>
/// <param name="Count">Cardinal [in] Number of transactions completed
/// towards goal.</param>
/// <param name="Goal">Cardinal [in] Number of transactions required to
/// reach goal.</param>
function GetProgress(Count, Goal: Cardinal): Byte;
/// <summary>Performs database move operation and records new location.
/// </summary>
procedure DoMove;
/// <summary>Copies database file with given index in file list from old to
/// new database directories.</summary>
/// <remarks>Triggers OnCopyFile event when the file has been copied.
/// </remarks>
procedure CopyFile(const FileIdx: Cardinal);
/// <summary>Deletes database file with given index in file list from old
/// database directory.</summary>
/// <remarks>Triggers OnDeleteFile event when the file has been deleted.
/// </remarks>
procedure DeleteFile(const FileIdx: Cardinal);
public
/// <summary>Constructs and initialises new object instance.</summary>
constructor Create;
/// <summary>Destroys current object instance.</summary>
destructor Destroy; override;
/// <summary>Moves user database from its current directory to the given
/// new directory.</summary>
/// <exceptions>Raises EInOutError exceptions if an error occurs.
/// </exceptions>
procedure MoveTo(const ADirectory: string);
/// <summary>Event triggered just before file copying begins and once for
/// each file copied. Reports progress towards completion of copy
/// operation.</summary>
property OnCopyFile: TProgress read fOnCopyFile write fOnCopyFile;
/// <summary>Event triggered just before file deletion begins and once for
/// each file deleted. Reports progress towards completion of delete
/// operation.</summary>
property OnDeleteFile: TProgress read fOnDeleteFile write fOnDeleteFile;
end;
implementation
uses
// Delphi
SysUtils, IOUtils, Math, Windows {for inlining},
// Project
UAppInfo, UDOSDateTime, UIOUtils, UStrUtils, UUtils;
{ TUserDBMove }
procedure TUserDBMove.CopyFile(const FileIdx: Cardinal);
var
SrcFile, DestFile: string;
FileDate: IDOSDateTime;
begin
SrcFile := fSourceDir + PathDelim + fDBFiles[FileIdx];
DestFile := fDestDir + PathDelim + fDBFiles[FileIdx];
FileDate := TDOSDateTimeFactory.CreateFromFile(SrcFile);
TFileIO.CopyFile(SrcFile, DestFile);
FileDate.ApplyToFile(DestFile);
NotifyCopyFile(FileIdx);
end;
constructor TUserDBMove.Create;
begin
inherited Create;
fDBFiles := TStringList.Create;
end;
procedure TUserDBMove.DeleteFile(const FileIdx: Cardinal);
begin
SysUtils.DeleteFile(fSourceDir + PathDelim + fDBFiles[FileIdx]);
NotifyDeleteFile(FileIdx);
end;
destructor TUserDBMove.Destroy;
begin
fDBFiles.Free;
inherited;
end;
procedure TUserDBMove.DoMove;
var
FileIdx: Cardinal;
begin
fDBFiles.Clear;
ListFiles(fSourceDir, '*.*', fDBFiles, False, True);
// copy files
NotifyCopyFile(0);
EnsureFolders(fDestDir);
for FileIdx := 0 to Pred(fDBFiles.Count) do
CopyFile(FileIdx);
// record new location BEFORE deleting old directory
TAppInfo.ChangeUserDataDir(fDestDir);
// delete files
NotifyDeleteFile(0);
for FileIdx := 0 to Pred(fDBFiles.Count) do
DeleteFile(FileIdx);
SysUtils.RemoveDir(fSourceDir);
end;
function TUserDBMove.GetProgress(Count, Goal: Cardinal): Byte;
begin
Assert(Goal > 0, ClassName + '.GetProgress: Goal is zero');
Count := Min(Goal, Count);
Result := Round(100 * Count / Goal);
end;
procedure TUserDBMove.MoveTo(const ADirectory: string);
begin
fSourceDir := ExcludeTrailingPathDelimiter(TAppInfo.UserDataDir);
fDestDir := ExcludeTrailingPathDelimiter(ADirectory);
ValidateDirectories;
DoMove;
end;
procedure TUserDBMove.NotifyCopyFile(FileCount: Cardinal);
begin
if Assigned(fOnCopyFile) then
fOnCopyFile(Self, GetProgress(FileCount, fDBFiles.Count));
end;
procedure TUserDBMove.NotifyDeleteFile(FileCount: Cardinal);
begin
if Assigned(fOnDeleteFile) then
fOnDeleteFile(Self, GetProgress(FileCount, fDBFiles.Count));
end;
procedure TUserDBMove.ValidateDirectories;
resourcestring
sSameNames = 'The new database directory is the same as the current '
+ 'directory.';
sSourceMissing = 'No user database found';
sCantMoveToSubDir = 'Can''t move database into a sub-directory of the '
+ 'existing database directory';
sDestMustBeRooted = 'A full path to the new database directory must be '
+ 'provided.';
sDestMustBeEmpty = 'The new database directory must be empty';
begin
if not TPath.IsPathRooted(fDestDir) then
raise EInOutError.Create(sDestMustBeRooted);
if not TDirectory.Exists(fSourceDir) or TDirectory.IsEmpty(fSourceDir) then
raise EInOutError.Create(sSourceMissing);
if TDirectory.Exists(fDestDir) and not TDirectory.IsEmpty(fDestDir) then
raise EInOutError.Create(sDestMustBeEmpty);
if SameFileName(fSourceDir, fDestDir) then
raise EInOutError.Create(sSameNames);
if StrStartsText(
IncludeTrailingPathDelimiter(TAppInfo.UserDataDir), fDestDir
) then
raise EInOutError.Create(sCantMoveToSubDir);
end;
end.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.