515 lines
12 KiB
Plaintext
515 lines
12 KiB
Plaintext
{************************************************}
|
|
{ }
|
|
{ Turbo Vision File Manager Demo }
|
|
{ Copyright (c) 1992 by Borland International }
|
|
{ }
|
|
{************************************************}
|
|
|
|
{$X+,V-}
|
|
|
|
unit Globals;
|
|
|
|
interface
|
|
|
|
uses Objects, Drivers, App, Views, Menus, Dialogs, Dos, DragDrop;
|
|
|
|
type
|
|
|
|
TConfigRec = record
|
|
FileMask: string[12];
|
|
ShowHidden: Word;
|
|
SortField: Word;
|
|
SortDir: Word;
|
|
DisplayCase: Word;
|
|
DisplayFields: Word;
|
|
Video: Word;
|
|
end;
|
|
|
|
{ Event.InfoPtr points to a TScanInfo record if the when cmScanComplete
|
|
is broadcast }
|
|
|
|
PScanInfo = ^TScanInfo;
|
|
TScanInfo = record
|
|
ScanCount: LongInt;
|
|
ScanBytes: LongInt;
|
|
end;
|
|
|
|
PTextCollection = ^TTextCollection;
|
|
TTextCollection = object(TCollection)
|
|
procedure FreeItem(Item: pointer); virtual;
|
|
end;
|
|
|
|
PProtectedStream = ^TProtectedStream;
|
|
TProtectedStream = object(TBufStream)
|
|
procedure Error(Code, Info: Integer); virtual;
|
|
end;
|
|
|
|
{ THCStatusLine is a help context sensitive status line }
|
|
|
|
PHCStatusLine = ^THCStatusLine;
|
|
THCStatusLine = object(TStatusLine)
|
|
function Hint(AHelpCtx: Word): String; virtual;
|
|
end;
|
|
|
|
{ record used to identify a file by name only }
|
|
PFileNameRec = ^TFileNameRec;
|
|
TFileNameRec = record
|
|
Dir: DirStr;
|
|
Name: NameStr;
|
|
Ext: ExtStr;
|
|
end;
|
|
|
|
{ represents a single file in a file list }
|
|
PFileRec = ^TFileRec;
|
|
TFileRec = object(TObject)
|
|
Tagged: Boolean;
|
|
Name: NameStr;
|
|
Ext: ExtStr;
|
|
Attr: Byte;
|
|
Size: Longint;
|
|
Time: Longint;
|
|
constructor Init(const S: SearchRec);
|
|
procedure Toggle;
|
|
end;
|
|
|
|
{ moving view while files are being dragged }
|
|
PFileMover = ^TFileMover;
|
|
TFileMover = object(TMover)
|
|
procedure Draw; virtual;
|
|
end;
|
|
|
|
{ sorted collection that sorts according to the ConfigRec settings. }
|
|
PFileList = ^TFileList;
|
|
TFileList = object(TSortedCollection)
|
|
function Compare(Key1, Key2: Pointer): Integer; virtual;
|
|
procedure ReOrder;
|
|
end;
|
|
|
|
TSortFunc = function(P1, P2: PFileRec): Integer;
|
|
|
|
{ dialog to handle file renaming }
|
|
PRenameDialog = ^TRenameDialog;
|
|
TRenameDialog = object(TDialog)
|
|
TheName: PathStr;
|
|
NewName: PathStr;
|
|
constructor Init(const FileName:PathStr);
|
|
function Valid(Command: Word): Boolean; virtual;
|
|
end;
|
|
|
|
{ dialog to handle changing file attributes }
|
|
PAttrDialog = ^TAttrDialog;
|
|
TAttrDialog = object(TDialog)
|
|
TheName: PathStr;
|
|
NewAttr: Word;
|
|
constructor Init(const FileName:PathStr);
|
|
function Valid(Command: Word): Boolean; virtual;
|
|
end;
|
|
|
|
{ TDeviceRec holds a single redirected device (net drives) }
|
|
PDeviceRec = ^TDeviceRec;
|
|
TDeviceRec = record
|
|
LocalName: Char;
|
|
NetworkName: PString;
|
|
end;
|
|
|
|
{ TDeviceCollection is a collection of TDeviceRecs }
|
|
PDeviceCollection = ^TDeviceCollection;
|
|
TDeviceCollection = object(TCollection)
|
|
procedure FreeItem(Item: Pointer); virtual;
|
|
end;
|
|
|
|
procedure RegisterGlobals;
|
|
function WaitDialog(const Msg: String) : PDialog;
|
|
|
|
var
|
|
RezFile: TResourceFile;
|
|
RezStream: PStream;
|
|
RezStrings: PStringList;
|
|
|
|
const
|
|
|
|
ConfigRec: TConfigRec =
|
|
(FileMask:'*.*'; ShowHidden:$00; SortField:$00; SortDir:$00;
|
|
DisplayCase:$00; DisplayFields:$FF; Video:0);
|
|
|
|
ConfirmDelete: Boolean = True;
|
|
Viewer: PathStr = '';
|
|
|
|
EXEName = 'TVFM.EXE';
|
|
CFGExt = '.CFG';
|
|
TagChar = #251;
|
|
|
|
UnwantedFiles: Word = VolumeID or Directory or SysFile or Hidden;
|
|
|
|
implementation
|
|
|
|
uses MsgBox, FileCopy, Equ;
|
|
|
|
const
|
|
RHCStatusLine : TStreamRec = (
|
|
ObjType : 100;
|
|
VmtLink : Ofs(TypeOf(THCStatusLine)^);
|
|
Load : @THCStatusLine.Load;
|
|
Store : @THCStatusLine.Store
|
|
);
|
|
|
|
|
|
{ ----------- General Purpose Routines -------------------- }
|
|
|
|
procedure RegisterGlobals;
|
|
begin
|
|
RegisterType(RHCStatusLine);
|
|
end;
|
|
|
|
function WaitDialog(const Msg: String) : PDialog;
|
|
var
|
|
R: TRect;
|
|
D: PDialog;
|
|
Width: Integer;
|
|
XPos: Integer;
|
|
begin
|
|
if Length(Msg) > 40 then Width := Length(Msg) + 4
|
|
else Width := 40;
|
|
XPos := (Width div 2) - (Length(Msg) div 2) - 1;
|
|
|
|
R.Assign(0, 0, Width, 7);
|
|
D := New(PDialog, Init(R, RezStrings^.Get(sPleaseWait)));
|
|
with D^ do
|
|
begin
|
|
Options := Options or ofCentered;
|
|
Flags := Flags and (not wfClose) and (not wfMove);
|
|
R.Assign(XPos, 3, XPos+Length(Msg)+1, 4);
|
|
Insert(New(PStaticText,Init(R, Msg)));
|
|
end;
|
|
WaitDialog := D;
|
|
end;
|
|
|
|
{ TTextCollection }
|
|
procedure TTextCollection.FreeItem(Item: pointer);
|
|
begin
|
|
DisposeStr(Item);
|
|
end;
|
|
|
|
|
|
{ TProtectedStream }
|
|
|
|
procedure TProtectedStream.Error(Code, Info: Integer);
|
|
begin
|
|
Writeln('Error in stream: Code = ', Code, ' Info = ', Info);
|
|
Halt(1);
|
|
end;
|
|
|
|
|
|
{ THCStatusLine }
|
|
|
|
function THCStatusLine.Hint(AHelpCtx: Word) :String;
|
|
begin
|
|
Hint := RezStrings^.Get(AHelpCtx);
|
|
end;
|
|
|
|
{ TFileRec }
|
|
|
|
constructor TFileRec.Init(const S: SearchRec);
|
|
var
|
|
T: PathStr;
|
|
begin
|
|
inherited Init;
|
|
Tagged := False;
|
|
FSplit(S.Name, T, Name, Ext);
|
|
|
|
{ fix up directory names without extensions }
|
|
if (S.Attr and Directory <> 0) and (Name = '') then
|
|
begin
|
|
Name := Ext;
|
|
Ext := '';
|
|
end;
|
|
Attr := S.Attr;
|
|
Size := S.Size;
|
|
Time := S.Time;
|
|
end;
|
|
|
|
procedure TFileRec.Toggle;
|
|
begin
|
|
Tagged := not Tagged;
|
|
end;
|
|
|
|
|
|
{ Sort functions for TFileList }
|
|
|
|
function SortByName(P1, P2: PFileRec): Integer; far;
|
|
begin
|
|
if P1^.Name < P2^.Name then SortByName := -1
|
|
else if P1^.Name > P2^.Name then SortByName := 1
|
|
else SortByName := 0;
|
|
end;
|
|
|
|
function SortByExt(P1, P2: PFileRec): Integer; far;
|
|
begin
|
|
if P1^.Ext < P2^.Ext then SortByExt := -1
|
|
else if P1^.Ext > P2^.Ext then SortByExt := 1
|
|
else SortByExt := 0;
|
|
end;
|
|
|
|
function SortBySize(P1, P2: PFileRec): Integer; far;
|
|
begin
|
|
if P1^.Size < P2^.Size then SortBySize := -1
|
|
else if P1^.Size > P2^.Size then SortBySize := 1
|
|
else SortBySize := 0;
|
|
end;
|
|
|
|
function SortByTime(P1, P2: PFileRec): Integer; far;
|
|
begin
|
|
if P1^.Time < P2^.Time then SortByTime := -1
|
|
else if P1^.Time > P2^.Time then SortByTime := 1
|
|
else SortByTime := 0;
|
|
end;
|
|
|
|
{ TFileMover }
|
|
procedure TFileMover.Draw;
|
|
var
|
|
B: TDrawBuffer;
|
|
C: Word;
|
|
F: PFileRec;
|
|
begin
|
|
C := GetColor(1);
|
|
{ always draw at least the first entry in the collection }
|
|
F := Items^.At(0);
|
|
MoveChar(B, #32, C, Size.X);
|
|
MoveStr(B, F^.Name + F^.Ext, C);
|
|
WriteLine(0,0,Size.X,1,B);
|
|
|
|
if Items^.Count > 1 then
|
|
begin
|
|
F := Items^.At(Items^.Count - 1); { last item in list }
|
|
MoveChar(B, #32, C, Size.X);
|
|
MoveStr(B, F^.Name + F^.Ext, C);
|
|
if Items^.Count > 2 then
|
|
begin
|
|
WriteLine(0,2,Size.X,1,B);
|
|
if Items^.Count = 3 then
|
|
begin
|
|
F := Items^.At(1);
|
|
MoveChar(B, #32, C, Size.X);
|
|
MoveStr(B, F^.Name + F^.Ext, C);
|
|
end
|
|
else
|
|
begin
|
|
MoveChar(B, #32, C, Size.X);
|
|
MoveChar(B[4], #250, C, 4);
|
|
end;
|
|
WriteLine(0,1,Size.X,1,B);
|
|
end
|
|
else
|
|
WriteLine(0,1,Size.X,1,B);
|
|
end;
|
|
end;
|
|
|
|
{ TFileList }
|
|
|
|
function TFileList.Compare(Key1, Key2: Pointer): Integer;
|
|
const
|
|
Sorts : array[0..3] of TSortFunc =
|
|
(SortByName, SortByExt, SortBySize, SortByTime);
|
|
var
|
|
Result: Integer;
|
|
I: Integer;
|
|
begin
|
|
|
|
if Key2 = nil then
|
|
begin
|
|
Compare := 0;
|
|
Exit;
|
|
end;
|
|
|
|
Result := Sorts[ConfigRec.SortField](Key1, Key2);
|
|
I := 0;
|
|
while (Result = 0) and (I <= 3) do
|
|
begin
|
|
Result := Sorts[I](Key1, Key2);
|
|
Inc(I);
|
|
end;
|
|
|
|
{ if the sort is descending, then reverse the Result variable }
|
|
if (ConfigRec.SortDir <> 0) and (Result <> 0) then
|
|
Result := Result * -1;
|
|
|
|
Compare := Result;
|
|
end;
|
|
|
|
procedure TFileList.ReOrder;
|
|
|
|
procedure Sort(l, r: Integer);
|
|
var
|
|
i, j: Integer;
|
|
x, p: Pointer;
|
|
begin
|
|
repeat
|
|
i := l; j := r;
|
|
x := KeyOf(Items^[(l + r) div 2]);
|
|
repeat
|
|
while Compare(KeyOf(Items^[i]), x) = -1 do Inc(i);
|
|
while Compare(x, KeyOf(Items^[j])) = -1 do Dec(j);
|
|
if i <= j then
|
|
begin
|
|
if i < j then
|
|
begin
|
|
p := Items^[i];
|
|
Items^[i] := Items^[j];
|
|
Items^[j] := p;
|
|
end;
|
|
Inc(i); Dec(j);
|
|
end;
|
|
until i > j;
|
|
if l < j then Sort(l, j);
|
|
l := i;
|
|
until l >= r;
|
|
end;
|
|
|
|
begin
|
|
if Count > 1 then Sort(0, Count - 1);
|
|
end;
|
|
|
|
|
|
{ TRenameDialog }
|
|
constructor TRenameDialog.Init(const FileName: PathStr);
|
|
var
|
|
R: TRect;
|
|
P: PView;
|
|
D: DirStr;
|
|
N: NameStr;
|
|
E: ExtStr;
|
|
begin
|
|
R.Assign(0,0,40,7);
|
|
inherited Init(R, 'Rename File');
|
|
Options := Options or ofCentered;
|
|
|
|
TheName := FileName;
|
|
FSplit(TheName, D, N, E);
|
|
D := N + E;
|
|
R.Assign(2,2,18,3);
|
|
Insert(New(PLabel, Init(R, '~' + D + '~ to ', nil)));
|
|
R.Assign(19,2,33,3);
|
|
Insert(New(PInputLine, Init(R, 12)));
|
|
R.Assign(4,4,16,6);
|
|
Insert(New(PButton, Init(R, '~O~K', cmOK, bfDefault)));
|
|
R.Move(16,0);
|
|
Insert(New(PButton, Init(R, '~C~ancel', cmCancel, bfNormal)));
|
|
SelectNext(False);
|
|
D := '';
|
|
SetData(D);
|
|
end;
|
|
|
|
function TRenameDialog.Valid(Command: Word): Boolean;
|
|
var
|
|
L: Longint;
|
|
TheFile: File;
|
|
D: DirStr;
|
|
N: NameStr;
|
|
E: ExtStr;
|
|
I: Integer;
|
|
begin
|
|
Valid := True;
|
|
if (Command = cmCancel) or (Command = cmValid) then Exit;
|
|
GetData(NewName);
|
|
for I:= 1 to Length(NewName) do NewName[I] := UpCase(NewName[I]);
|
|
FSplit(TheName, D, N, E);
|
|
|
|
{ check for duplicate name }
|
|
if D + NewName = TheName then
|
|
begin
|
|
MessageBox(RezStrings^.Get(sSameNameErr), nil, mfError+mfOKButton);
|
|
Valid := False;
|
|
Exit;
|
|
end;
|
|
Assign(TheFile, TheName);
|
|
{$I-}
|
|
Rename(TheFile, D + NewName);
|
|
{$I+}
|
|
L := IOResult;
|
|
if L <> 0 then
|
|
begin
|
|
MessageBox(RezStrings^.Get(sRenameErr), @L, mfError+mfOKButton);
|
|
Valid := False;
|
|
end;
|
|
end;
|
|
|
|
{ TAttrDialog }
|
|
constructor TAttrDialog.Init(const FileName:PathStr);
|
|
var
|
|
R: TRect;
|
|
P: PView;
|
|
Attr: Word;
|
|
XFer: Word;
|
|
TheFile: File;
|
|
begin
|
|
R.Assign(0,0,40,12);
|
|
inherited Init(R, 'Change Attributes');
|
|
Options := Options or ofCentered;
|
|
|
|
TheName := FileName;
|
|
Assign(TheFile, TheName);
|
|
GetFAttr(TheFile, Attr);
|
|
if DosError <> 0 then Fail;
|
|
|
|
R.Assign(0,2,Length(FileName),3);
|
|
P:=New(PStaticText, Init(R, FileName));
|
|
P^.Options := P^.Options or ofCenterX;
|
|
Insert(P);
|
|
R.Assign(0,4,15,8);
|
|
P := New(PCheckBoxes, Init(R, NewSItem('~A~rchive',
|
|
NewSItem('~R~ead-Only',
|
|
NewSItem('~S~ystem',
|
|
NewSItem('~H~idden',
|
|
nil))))));
|
|
P^.Options := P^.Options or ofCenterX;
|
|
Insert(P);
|
|
R.Assign(4,9,16,11);
|
|
Insert(New(PButton, Init(R, '~O~K', cmOK, bfDefault)));
|
|
R.Move(16,0);
|
|
Insert(New(PButton, Init(R, '~C~ancel', cmCancel, bfNormal)));
|
|
SelectNext(False);
|
|
XFer := 0;
|
|
if Attr and Archive <> 0 then XFer := $01;
|
|
if Attr and ReadOnly <> 0 then XFer := XFer or $02;
|
|
if Attr and SysFile <> 0 then XFer := XFer or $04;
|
|
if Attr and Hidden <> 0 then XFer := XFer or $08;
|
|
SetData(XFer);
|
|
end;
|
|
|
|
function TAttrDialog.Valid(Command: Word): Boolean;
|
|
var
|
|
XFer : Word;
|
|
L: array[0..1] of Longint;
|
|
TheFile: File;
|
|
begin
|
|
Valid := True;
|
|
if (Command = cmCancel) or (Command = cmValid) then Exit;
|
|
GetData(XFer);
|
|
NewAttr := 0;
|
|
if XFer and $01 <> 0 then NewAttr := Archive;
|
|
if XFer and $02 <> 0 then NewAttr := NewAttr or ReadOnly;
|
|
if XFer and $04 <> 0 then NewAttr := NewAttr or SysFile;
|
|
if XFer and $08 <> 0 then NewAttr := NewAttr or Hidden;
|
|
Assign(TheFile, TheName);
|
|
SetFAttr(TheFile, NewAttr);
|
|
if DosError <> 0 then
|
|
begin
|
|
L[0] := DosError;
|
|
L[1] := Longint(@TheName);
|
|
MessageBox(RezStrings^.Get(sSetAttrErr), @L, mfError+mfOKButton);
|
|
Valid := False;
|
|
end;
|
|
end;
|
|
|
|
{ TDeviceCollection }
|
|
procedure TDeviceCollection.FreeItem(Item: Pointer);
|
|
var
|
|
DeviceRec : PDeviceRec absolute Item;
|
|
begin
|
|
DisposeStr(DeviceRec^.NetworkName);
|
|
Dispose(DeviceRec);
|
|
end;
|
|
|
|
|
|
end. { unit }
|