summaryrefslogtreecommitdiff
path: root/packages/fv/src/stddlg.pas
diff options
context:
space:
mode:
Diffstat (limited to 'packages/fv/src/stddlg.pas')
-rw-r--r--packages/fv/src/stddlg.pas2770
1 files changed, 2770 insertions, 0 deletions
diff --git a/packages/fv/src/stddlg.pas b/packages/fv/src/stddlg.pas
new file mode 100644
index 0000000000..4b584e4e62
--- /dev/null
+++ b/packages/fv/src/stddlg.pas
@@ -0,0 +1,2770 @@
+{*******************************************************}
+{ Free Vision Runtime Library }
+{ StdDlg Unit }
+{ Version: 0.1.0 }
+{ Release Date: July 23, 1998 }
+{ }
+{*******************************************************}
+{ }
+{ This unit is a port of Borland International's }
+{ StdDlg.pas unit. It is for distribution with the }
+{ Free Pascal (FPK) Compiler as part of the 32-bit }
+{ Free Vision library. The unit is still fully }
+{ functional under BP7 by using the tp compiler }
+{ directive when rebuilding the library. }
+{ }
+{*******************************************************}
+
+{ Revision History
+
+1.1a (97/12/29)
+ - fixed bug in TFileDialog.HandleEvent that prevented the user from being
+ able to have an action taken automatically when the FileList was
+ selected and kbEnter pressed
+
+1.1
+ - modified OpenNewFile to take a history list ID
+ - implemented OpenNewFile
+
+1.0 (1992)
+ - original implementation }
+
+unit StdDlg;
+
+{
+ This unit has been modified to make some functions global, apply patches
+ from version 3.1 of the TVBUGS list, added TEditChDirDialog, and added
+ several new global functions and procedures.
+}
+
+{$i platform.inc}
+
+{$ifdef PPC_FPC}
+ {$H-}
+{$else}
+ {$F+,O+,E+,N+}
+{$endif}
+{$X+,R-,I-,Q-,V-}
+{$ifndef OS_UNIX}
+ {$S-}
+{$endif}
+{$ifdef OS_DOS}
+ {$define HAS_DOS_DRIVES}
+{$endif}
+{$ifdef OS_WINDOWS}
+ {$define HAS_DOS_DRIVES}
+{$endif}
+{$ifdef OS_OS2}
+ {$define HAS_DOS_DRIVES}
+{$endif}
+
+{2.0 compatibility}
+{$ifdef VER2_0}
+ {$macro on}
+ {$define resourcestring := const}
+{$endif}
+
+interface
+
+uses
+ FVConsts, Objects, Drivers, Views, Dialogs, Validate, Dos;
+
+const
+ MaxDir = 255; { Maximum length of a DirStr. }
+ MaxFName = 255; { Maximum length of a FNameStr. }
+
+ DirSeparator : Char = system.DirectorySeparator;
+
+{$ifdef Unix}
+ AllFiles = '*';
+{$else}
+ AllFiles = '*.*';
+{$endif}
+
+type
+ { TSearchRec }
+
+ { Record used to store directory information by TFileDialog
+ This is a part of Dos.Searchrec for Bp !! }
+
+ TSearchRec =
+{$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
+ packed
+{$endif FPC_REQUIRES_PROPER_ALIGNMENT}
+ record
+ Attr: Longint;
+ Time: Longint;
+ Size: Longint;
+ Name: string[MaxFName];
+ end;
+ PSearchRec = ^TSearchRec;
+
+type
+
+ { TFileInputLine is a special input line that is used by }
+ { TFileDialog that will update its contents in response to a }
+ { cmFileFocused command from a TFileList. }
+
+ PFileInputLine = ^TFileInputLine;
+ TFileInputLine = object(TInputLine)
+ constructor Init(var Bounds: TRect; AMaxLen: Sw_Integer);
+ procedure HandleEvent(var Event: TEvent); virtual;
+ end;
+
+ { TFileCollection is a collection of TSearchRec's. }
+
+ PFileCollection = ^TFileCollection;
+ TFileCollection = object(TSortedCollection)
+ function Compare(Key1, Key2: Pointer): Sw_Integer; virtual;
+ procedure FreeItem(Item: Pointer); virtual;
+ function GetItem(var S: TStream): Pointer; virtual;
+ procedure PutItem(var S: TStream; Item: Pointer); virtual;
+ end;
+
+ {#Z+}
+ PFileValidator = ^TFileValidator;
+ {#Z-}
+ TFileValidator = Object(TValidator)
+ end; { of TFileValidator }
+
+ { TSortedListBox is a TListBox that assumes it has a }
+ { TStoredCollection instead of just a TCollection. It will }
+ { perform an incremental search on the contents. }
+
+ PSortedListBox = ^TSortedListBox;
+ TSortedListBox = object(TListBox)
+ SearchPos: Byte;
+ {ShiftState: Byte;}
+ HandleDir : boolean;
+ constructor Init(var Bounds: TRect; ANumCols: Sw_Word;
+ AScrollBar: PScrollBar);
+ procedure HandleEvent(var Event: TEvent); virtual;
+ function GetKey(var S: String): Pointer; virtual;
+ procedure NewList(AList: PCollection); virtual;
+ end;
+
+ { TFileList is a TSortedList box that assumes it contains }
+ { a TFileCollection as its collection. It also communicates }
+ { through broadcast messages to TFileInput and TInfoPane }
+ { what file is currently selected. }
+
+ PFileList = ^TFileList;
+ TFileList = object(TSortedListBox)
+ constructor Init(var Bounds: TRect; AScrollBar: PScrollBar);
+ destructor Done; virtual;
+ function DataSize: Sw_Word; virtual;
+ procedure FocusItem(Item: Sw_Integer); virtual;
+ procedure GetData(var Rec); virtual;
+ function GetText(Item,MaxLen: Sw_Integer): String; virtual;
+ function GetKey(var S: String): Pointer; virtual;
+ procedure HandleEvent(var Event: TEvent); virtual;
+ procedure ReadDirectory(AWildCard: PathStr);
+ procedure SetData(var Rec); virtual;
+ end;
+
+ { TFileInfoPane is a TView that displays the information }
+ { about the currently selected file in the TFileList }
+ { of a TFileDialog. }
+
+ PFileInfoPane = ^TFileInfoPane;
+ TFileInfoPane = object(TView)
+ S: TSearchRec;
+ constructor Init(var Bounds: TRect);
+ procedure Draw; virtual;
+ function GetPalette: PPalette; virtual;
+ procedure HandleEvent(var Event: TEvent); virtual;
+ end;
+
+ { TFileDialog is a standard file name input dialog }
+
+ TWildStr = PathStr;
+
+const
+ fdOkButton = $0001; { Put an OK button in the dialog }
+ fdOpenButton = $0002; { Put an Open button in the dialog }
+ fdReplaceButton = $0004; { Put a Replace button in the dialog }
+ fdClearButton = $0008; { Put a Clear button in the dialog }
+ fdHelpButton = $0010; { Put a Help button in the dialog }
+ fdNoLoadDir = $0100; { Do not load the current directory }
+ { contents into the dialog at Init. }
+ { This means you intend to change the }
+ { WildCard by using SetData or store }
+ { the dialog on a stream. }
+
+type
+
+ PFileHistory = ^TFileHistory;
+ TFileHistory = object(THistory)
+ CurDir : PString;
+ procedure HandleEvent(var Event: TEvent);virtual;
+ destructor Done; virtual;
+ procedure AdaptHistoryToDir(Dir : string);
+ end;
+
+ PFileDialog = ^TFileDialog;
+ TFileDialog = object(TDialog)
+ FileName: PFileInputLine;
+ FileList: PFileList;
+ FileHistory: PFileHistory;
+ WildCard: TWildStr;
+ Directory: PString;
+ constructor Init(AWildCard: TWildStr; const ATitle,
+ InputName: String; AOptions: Word; HistoryId: Byte);
+ constructor Load(var S: TStream);
+ destructor Done; virtual;
+ procedure GetData(var Rec); virtual;
+ procedure GetFileName(var S: PathStr);
+ procedure HandleEvent(var Event: TEvent); virtual;
+ procedure SetData(var Rec); virtual;
+ procedure Store(var S: TStream);
+ function Valid(Command: Word): Boolean; virtual;
+ private
+ procedure ReadDirectory;
+ end;
+
+ { TDirEntry }
+
+ PDirEntry = ^TDirEntry;
+ TDirEntry = record
+ DisplayText: PString;
+ Directory: PString;
+ end; { of TDirEntry }
+
+ { TDirCollection is a collection of TDirEntry's used by }
+ { TDirListBox. }
+
+ PDirCollection = ^TDirCollection;
+ TDirCollection = object(TCollection)
+ function GetItem(var S: TStream): Pointer; virtual;
+ procedure FreeItem(Item: Pointer); virtual;
+ procedure PutItem(var S: TStream; Item: Pointer); virtual;
+ end;
+
+ { TDirListBox displays a tree of directories for use in the }
+ { TChDirDialog. }
+
+ PDirListBox = ^TDirListBox;
+ TDirListBox = object(TListBox)
+ Dir: DirStr;
+ Cur: Word;
+ constructor Init(var Bounds: TRect; AScrollBar: PScrollBar);
+ destructor Done; virtual;
+ function GetText(Item,MaxLen: Sw_Integer): String; virtual;
+ procedure HandleEvent(var Event: TEvent); virtual;
+ function IsSelected(Item: Sw_Integer): Boolean; virtual;
+ procedure NewDirectory(var ADir: DirStr);
+ procedure SetState(AState: Word; Enable: Boolean); virtual;
+ end;
+
+ { TChDirDialog is a standard change directory dialog. }
+
+const
+ cdNormal = $0000; { Option to use dialog immediately }
+ cdNoLoadDir = $0001; { Option to init the dialog to store on a stream }
+ cdHelpButton = $0002; { Put a help button in the dialog }
+
+type
+
+ PChDirDialog = ^TChDirDialog;
+ TChDirDialog = object(TDialog)
+ DirInput: PInputLine;
+ DirList: PDirListBox;
+ OkButton: PButton;
+ ChDirButton: PButton;
+ constructor Init(AOptions: Word; HistoryId: Sw_Word);
+ constructor Load(var S: TStream);
+ function DataSize: Sw_Word; virtual;
+ procedure GetData(var Rec); virtual;
+ procedure HandleEvent(var Event: TEvent); virtual;
+ procedure SetData(var Rec); virtual;
+ procedure Store(var S: TStream);
+ function Valid(Command: Word): Boolean; virtual;
+ private
+ procedure SetUpDialog;
+ end;
+
+ PEditChDirDialog = ^TEditChDirDialog;
+ TEditChDirDialog = Object(TChDirDialog)
+ { TEditChDirDialog allows setting/getting the starting directory. The
+ transfer record is a DirStr. }
+ function DataSize : Sw_Word; virtual;
+ procedure GetData (var Rec); virtual;
+ procedure SetData (var Rec); virtual;
+ end; { of TEditChDirDialog }
+
+
+ {#Z+}
+ PDirValidator = ^TDirValidator;
+ {#Z-}
+ TDirValidator = Object(TFilterValidator)
+ constructor Init;
+ function IsValid(const S: string): Boolean; virtual;
+ function IsValidInput(var S: string; SuppressFill: Boolean): Boolean;
+ virtual;
+ end; { of TDirValidator }
+
+
+ FileConfirmFunc = function (AFile : FNameStr) : Boolean;
+ { Functions of type FileConfirmFunc's are used to prompt the end user for
+ confirmation of an operation.
+
+ FileConfirmFunc's should ask the user whether to perform the desired
+ action on the file named AFile. If the user elects to perform the
+ function FileConfirmFunc's return True, otherwise they return False.
+
+ Using FileConfirmFunc's allows routines to be coded independant of the
+ user interface implemented. OWL and TurboVision are supported through
+ conditional defines. If you do not use either user interface you must
+ compile this unit with the conditional define cdNoMessages and set all
+ FileConfirmFunc variables to a valid function prior to calling any
+ routines in this unit. }
+ {#X ReplaceFile DeleteFile }
+
+
+var
+
+ ReplaceFile : FileConfirmFunc;
+ { ReplaceFile returns True if the end user elects to replace the existing
+ file with the new file, otherwise it returns False.
+
+ ReplaceFile is only called when #CheckOnReplace# is True. }
+ {#X DeleteFile }
+
+ DeleteFile : FileConfirmFunc;
+ { DeleteFile returns True if the end user elects to delete the file,
+ otherwise it returns False.
+
+ DeleteFile is only called when #CheckOnDelete# is True. }
+ {#X ReplaceFile }
+
+
+const
+
+ CInfoPane = #30;
+
+ { TStream registration records }
+
+function Contains(S1, S2: String): Boolean;
+ { Contains returns true if S1 contains any characters in S2. }
+
+function DriveValid(Drive: Char): Boolean;
+ { DriveValid returns True if Drive is a valid DOS drive. Drive valid works
+ by attempting to change the current directory to Drive, then restoring
+ the original directory. }
+
+function ExtractDir(AFile: FNameStr): DirStr;
+ { ExtractDir returns the path of AFile terminated with a trailing '\'. If
+ AFile contains no directory information, an empty string is returned. }
+
+function ExtractFileName(AFile: FNameStr): NameStr;
+ { ExtractFileName returns the file name without any directory or file
+ extension information. }
+
+function Equal(const S1, S2: String; Count: Sw_word): Boolean;
+ { Equal returns True if S1 equals S2 for up to Count characters. Equal is
+ case-insensitive. }
+
+function FileExists (AFile : FNameStr) : Boolean;
+ { FileExists looks for the file specified in AFile. If AFile is present
+ FileExists returns true, otherwise FileExists returns False.
+
+ The search is performed relative to the current system directory, but
+ other directories may be searched by prefacing a file name with a valid
+ directory path.
+
+ There is no check for a vaild file name or drive. Errrors are handled
+ internally and not reported in DosError. Critical errors are left to
+ the system's critical error handler. }
+ {#X OpenFile }
+
+function GetCurDir: DirStr;
+ { GetCurDir returns the current directory. The directory returned always
+ ends with a trailing backslash '\'. }
+
+function GetCurDrive: Char;
+ { GetCurDrive returns the letter of the current drive as reported by the
+ operating system. }
+
+function IsWild(const S: String): Boolean;
+ { IsWild returns True if S contains a question mark (?) or asterix (*). }
+
+function IsList(const S: String): Boolean;
+ { IsList returns True if S contains list separator (;) char }
+
+function IsDir(const S: String): Boolean;
+ { IsDir returns True if S is a valid DOS directory. }
+
+{procedure MakeResources;}
+ { MakeResources places a language specific version of all resources
+ needed for the StdDlg unit to function on the RezFile using the string
+ constants and variables in the Resource unit. The Resource unit and the
+ appropriate string lists must be initialized prior to calling this
+ procedure. }
+
+function NoWildChars(S: String): String;
+ { NoWildChars deletes the wild card characters ? and * from the string S
+ and returns the result. }
+
+function OpenFile (var AFile : FNameStr; HistoryID : Byte) : Boolean;
+ { OpenFile prompts the user to select a file using the file specifications
+ in AFile as the starting file and path. Wildcards are accepted. If the
+ user accepts a file OpenFile returns True, otherwise OpenFile returns
+ False.
+
+ Note: The file returned may or may not exist. }
+
+function OpenNewFile (var AFile: FNameStr; HistoryID: Byte): Boolean;
+ { OpenNewFile allows the user to select a directory from disk and enter a
+ new file name. If the file name entered is an existing file the user is
+ optionally prompted for confirmation of replacing the file based on the
+ value in #CheckOnReplace#. If a file name is successfully entered,
+ OpenNewFile returns True. }
+ {#X OpenFile }
+
+function PathValid(var Path: PathStr): Boolean;
+ { PathValid returns True if Path is a valid DOS path name. Path may be a
+ file or directory name. Trailing '\'s are removed. }
+
+procedure RegisterStdDlg;
+ { RegisterStdDlg registers all objects in the StdDlg unit for stream
+ usage. }
+
+function SaveAs (var AFile : FNameStr; HistoryID : Word) : Boolean;
+ { SaveAs prompts the user for a file name using AFile as a template. If
+ AFile already exists and CheckOnReplace is True, the user is prompted
+ to replace the file.
+
+ If a valid file name is entered SaveAs returns True, other SaveAs returns
+ False. }
+
+function SelectDir (var ADir : DirStr; HistoryID : Byte) : Boolean;
+ { SelectDir prompts the user to select a directory using ADir as the
+ starting directory. If a directory is selected, SelectDir returns True.
+ The directory returned is gauranteed to exist. }
+
+function ShrinkPath (AFile : FNameStr; MaxLen : Byte) : FNameStr;
+ { ShrinkPath returns a file name with a maximu length of MaxLen.
+ Internal directories are removed and replaced with elipses as needed to
+ make the file name fit in MaxLen.
+
+ AFile must be a valid path name. }
+
+function StdDeleteFile (AFile : FNameStr) : Boolean;
+ { StdDeleteFile returns True if the end user elects to delete the file,
+ otherwise it returns False.
+
+ DeleteFile is only called when CheckOnDelete is True. }
+
+function StdReplaceFile (AFile : FNameStr) : Boolean;
+ { StdReplaceFile returns True if the end user elects to replace the existing
+ AFile with the new AFile, otherwise it returns False.
+
+ ReplaceFile is only called when CheckOnReplace is True. }
+
+function ValidFileName(var FileName: PathStr): Boolean;
+ { ValidFileName returns True if FileName is a valid DOS file name. }
+
+
+const
+ CheckOnReplace : Boolean = True;
+ { CheckOnReplace is used by file functions. If a file exists, it is
+ optionally replaced based on the value of CheckOnReplace.
+
+ If CheckOnReplace is False the file is replaced without asking the
+ user. If CheckOnReplace is True, the end user is asked to replace the
+ file using a call to ReplaceFile.
+
+ CheckOnReplace is set to True by default. }
+
+ CheckOnDelete : Boolean = True;
+ { CheckOnDelete is used by file and directory functions. If a file
+ exists, it is optionally deleted based on the value of CheckOnDelete.
+
+ If CheckOnDelete is False the file or directory is deleted without
+ asking the user. If CheckOnDelete is True, the end user is asked to
+ delete the file/directory using a call to DeleteFile.
+
+ CheckOnDelete is set to True by default. }
+
+
+
+const
+ RFileInputLine: TStreamRec = (
+ ObjType: idFileInputLine;
+ VmtLink: Ofs(TypeOf(TFileInputLine)^);
+ Load: @TFileInputLine.Load;
+ Store: @TFileInputLine.Store
+ );
+
+ RFileCollection: TStreamRec = (
+ ObjType: idFileCollection;
+ VmtLink: Ofs(TypeOf(TFileCollection)^);
+ Load: @TFileCollection.Load;
+ Store: @TFileCollection.Store
+ );
+
+ RFileList: TStreamRec = (
+ ObjType: idFileList;
+ VmtLink: Ofs(TypeOf(TFileList)^);
+ Load: @TFileList.Load;
+ Store: @TFileList.Store
+ );
+
+ RFileInfoPane: TStreamRec = (
+ ObjType: idFileInfoPane;
+ VmtLink: Ofs(TypeOf(TFileInfoPane)^);
+ Load: @TFileInfoPane.Load;
+ Store: @TFileInfoPane.Store
+ );
+
+ RFileDialog: TStreamRec = (
+ ObjType: idFileDialog;
+ VmtLink: Ofs(TypeOf(TFileDialog)^);
+ Load: @TFileDialog.Load;
+ Store: @TFileDialog.Store
+ );
+
+ RDirCollection: TStreamRec = (
+ ObjType: idDirCollection;
+ VmtLink: Ofs(TypeOf(TDirCollection)^);
+ Load: @TDirCollection.Load;
+ Store: @TDirCollection.Store
+ );
+
+ RDirListBox: TStreamRec = (
+ ObjType: idDirListBox;
+ VmtLink: Ofs(TypeOf(TDirListBox)^);
+ Load: @TDirListBox.Load;
+ Store: @TDirListBox.Store
+ );
+
+ RChDirDialog: TStreamRec = (
+ ObjType: idChDirDialog;
+ VmtLink: Ofs(TypeOf(TChDirDialog)^);
+ Load: @TChDirDialog.Load;
+ Store: @TChDirDialog.Store
+ );
+
+ RSortedListBox: TStreamRec = (
+ ObjType: idSortedListBox;
+ VmtLink: Ofs(TypeOf(TSortedListBox)^);
+ Load: @TSortedListBox.Load;
+ Store: @TSortedListBox.Store
+ );
+
+ REditChDirDialog : TStreamRec = (
+ ObjType : idEditChDirDialog;
+ VmtLink : Ofs(TypeOf(TEditChDirDialog)^);
+ Load : @TEditChDirDialog.Load;
+ Store : @TEditChDirDialog.Store);
+
+
+implementation
+
+{****************************************************************************}
+{ Local Declarations }
+{****************************************************************************}
+
+uses
+ App, {Memory,} HistList, MsgBox{, Resource};
+
+type
+
+ PStringRec = record
+ { PStringRec is needed for properly displaying PStrings using
+ MessageBox. }
+ AString : PString;
+ end;
+
+resourcestring sChangeDirectory='Change Directory';
+ sDeleteFile='Delete file?'#13#10#13#3'%s';
+ sDirectory='Directory';
+ sDrives='Drives';
+ sInvalidDirectory='Invalid directory.';
+ sInvalidDriveOrDir='Invalid drive or directory.';
+ sInvalidFileName='Invalid file name.';
+ sOpen='Open';
+ sReplaceFile='Replace file?'#13#10#13#3'%s';
+ sSaveAs='Save As';
+ sTooManyFiles='Too many files.';
+
+ smApr='Apr';
+ smAug='Aug';
+ smDec='Dec';
+ smFeb='Feb';
+ smJan='Jan';
+ smJul='Jul';
+ smJun='Jun';
+ smMar='Mar';
+ smMay='May';
+ smNov='Nov';
+ smOct='Oct';
+ smSep='Sep';
+
+ slChDir='~C~hdir';
+ slClear='C~l~ear';
+ slDirectoryName='Directory ~n~ame';
+ slDirectoryTree='Directory ~t~ree';
+ slFiles='~F~iles';
+ slReplace='~R~eplace';
+ slRevert='~R~evert';
+
+{****************************************************************************}
+{ PathValid }
+{****************************************************************************}
+{$ifdef go32v2}
+{$define NetDrive}
+{$endif go32v2}
+{$ifdef win32}
+{$define NetDrive}
+{$endif win32}
+
+procedure RemoveDoubleDirSep(var ExpPath : PathStr);
+var
+ p: longint;
+{$ifdef NetDrive}
+ OneDirSepRemoved: boolean;
+{$endif NetDrive}
+begin
+ p:=pos(DirSeparator+DirSeparator,ExpPath);
+{$ifdef NetDrive}
+ if p=1 then
+ begin
+ ExpPath:=Copy(ExpPath,1,high(ExpPath));
+ OneDirSepRemoved:=true;
+ p:=pos(DirSeparator+DirSeparator,ExpPath);
+ end
+ else
+ OneDirSepRemoved:=false;
+{$endif NetDrive}
+ while p>0 do
+ begin
+ ExpPath:=Copy(ExpPath,1,p)+Copy(ExpPath,p+2,high(ExpPath));
+ p:=pos(DirSeparator+DirSeparator,ExpPath);
+ end;
+{$ifdef NetDrive}
+ if OneDirSepRemoved then
+ ExpPath:=DirSeparator+ExpPath;
+{$endif NetDrive}
+end;
+
+function PathValid (var Path: PathStr): Boolean;
+var
+ ExpPath: PathStr;
+ SR: SearchRec;
+begin
+ RemoveDoubleDirSep(Path);
+ ExpPath := FExpand(Path);
+{$ifdef HAS_DOS_DRIVES}
+ if (Length(ExpPath) <= 3) then
+ PathValid := DriveValid(ExpPath[1])
+ else
+{$endif}
+ begin
+ { do not change '/' into '' }
+ if (Length(ExpPath)>1) and (ExpPath[Length(ExpPath)] = DirSeparator) then
+ Dec(ExpPath[0]);
+ FindFirst(ExpPath, Directory, SR);
+ PathValid := (DosError = 0) and (SR.Attr and Directory <> 0);
+{$ifdef NetDrive}
+ if (DosError<>0) and (length(ExpPath)>2) and
+ (ExpPath[1]='\') and (ExpPath[2]='\')then
+ begin
+ { Checking '\\machine\sharedfolder' directly always fails..
+ rather try '\\machine\sharedfolder\*' PM }
+ {$ifdef fpc}
+ FindClose(SR);
+ {$endif}
+ FindFirst(ExpPath+'\*',AnyFile,SR);
+ PathValid:=(DosError = 0);
+ end;
+{$endif NetDrive}
+ {$ifdef fpc}
+ FindClose(SR);
+ {$endif}
+ end;
+end;
+
+{****************************************************************************}
+{ TDirValidator Object }
+{****************************************************************************}
+{****************************************************************************}
+{ TDirValidator.Init }
+{****************************************************************************}
+constructor TDirValidator.Init;
+const { What should this list be? The commented one doesn't allow home,
+ end, right arrow, left arrow, Ctrl+XXXX, etc. }
+ Chars: TCharSet = ['A'..'Z','a'..'z','.','~',':','_','-'];
+{ Chars: TCharSet = [#0..#255]; }
+begin
+ Chars := Chars + [DirSeparator];
+ if not inherited Init(Chars) then
+ Fail;
+end;
+
+{****************************************************************************}
+{ TDirValidator.IsValid }
+{****************************************************************************}
+function TDirValidator.IsValid(const S: string): Boolean;
+begin
+{ IsValid := False; }
+ IsValid := True;
+end;
+
+{****************************************************************************}
+{ TDirValidator.IsValidInput }
+{****************************************************************************}
+function TDirValidator.IsValidInput(var S: string; SuppressFill: Boolean): Boolean;
+begin
+{ IsValid := False; }
+ IsValidInput := True;
+end;
+
+{****************************************************************************}
+{ TFileInputLine Object }
+{****************************************************************************}
+{****************************************************************************}
+{ TFileInputLine.Init }
+{****************************************************************************}
+constructor TFileInputLine.Init(var Bounds: TRect; AMaxLen: Sw_Integer);
+begin
+ TInputLine.Init(Bounds, AMaxLen);
+ EventMask := EventMask or evBroadcast;
+end;
+
+{****************************************************************************}
+{ TFileInputLine.HandleEvent }
+{****************************************************************************}
+procedure TFileInputLine.HandleEvent(var Event: TEvent);
+begin
+ TInputLine.HandleEvent(Event);
+ if (Event.What = evBroadcast) and (Event.Command = cmFileFocused) and
+ (State and sfSelected = 0) then
+ begin
+ if PSearchRec(Event.InfoPtr)^.Attr and Directory <> 0 then
+ begin
+ Data^ := PSearchRec(Event.InfoPtr)^.Name + DirSeparator +
+ PFileDialog(Owner)^.WildCard;
+ { PFileDialog(Owner)^.FileHistory^.AdaptHistoryToDir(
+ PSearchRec(Event.InfoPtr)^.Name+DirSeparator);}
+ end
+ else Data^ := PSearchRec(Event.InfoPtr)^.Name;
+ DrawView;
+ end;
+end;
+
+{****************************************************************************}
+{ TFileCollection Object }
+{****************************************************************************}
+{****************************************************************************}
+{ TFileCollection.Compare }
+{****************************************************************************}
+ function uppername(const s : string) : string;
+ var
+ i : Sw_integer;
+ in_name : boolean;
+ begin
+ in_name:=true;
+ for i:=length(s) downto 1 do
+ if in_name and (s[i] in ['a'..'z']) then
+ uppername[i]:=char(byte(s[i])-32)
+ else
+ begin
+ uppername[i]:=s[i];
+ if s[i] = DirSeparator then
+ in_name:=false;
+ end;
+ uppername[0]:=s[0];
+ end;
+
+function TFileCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
+begin
+ if PSearchRec(Key1)^.Name = PSearchRec(Key2)^.Name then Compare := 0
+ else if PSearchRec(Key1)^.Name = '..' then Compare := 1
+ else if PSearchRec(Key2)^.Name = '..' then Compare := -1
+ else if (PSearchRec(Key1)^.Attr and Directory <> 0) and
+ (PSearchRec(Key2)^.Attr and Directory = 0) then Compare := 1
+ else if (PSearchRec(Key2)^.Attr and Directory <> 0) and
+ (PSearchRec(Key1)^.Attr and Directory = 0) then Compare := -1
+ else if UpperName(PSearchRec(Key1)^.Name) > UpperName(PSearchRec(Key2)^.Name) then
+ Compare := 1
+{$ifdef unix}
+ else if UpperName(PSearchRec(Key1)^.Name) < UpperName(PSearchRec(Key2)^.Name) then
+ Compare := -1
+ else if PSearchRec(Key1)^.Name > PSearchRec(Key2)^.Name then
+ Compare := 1
+{$endif def unix}
+ else
+ Compare := -1;
+end;
+
+{****************************************************************************}
+{ TFileCollection.FreeItem }
+{****************************************************************************}
+procedure TFileCollection.FreeItem(Item: Pointer);
+begin
+ Dispose(PSearchRec(Item));
+end;
+
+{****************************************************************************}
+{ TFileCollection.GetItem }
+{****************************************************************************}
+function TFileCollection.GetItem(var S: TStream): Pointer;
+var
+ Item: PSearchRec;
+begin
+ New(Item);
+ S.Read(Item^, SizeOf(TSearchRec));
+ GetItem := Item;
+end;
+
+{****************************************************************************}
+{ TFileCollection.PutItem }
+{****************************************************************************}
+procedure TFileCollection.PutItem(var S: TStream; Item: Pointer);
+begin
+ S.Write(Item^, SizeOf(TSearchRec));
+end;
+
+
+{*****************************************************************************
+ TFileList
+*****************************************************************************}
+
+const
+ ListSeparator=';';
+
+function MatchesMask(What, Mask: string): boolean;
+
+ function upper(const s : string) : string;
+ var
+ i : Sw_integer;
+ begin
+ for i:=1 to length(s) do
+ if s[i] in ['a'..'z'] then
+ upper[i]:=char(byte(s[i])-32)
+ else
+ upper[i]:=s[i];
+ upper[0]:=s[0];
+ end;
+
+ Function CmpStr(const hstr1,hstr2:string):boolean;
+ var
+ found : boolean;
+ i1,i2 : Sw_integer;
+ begin
+ i1:=0;
+ i2:=0;
+ if hstr1='' then
+ begin
+ CmpStr:=(hstr2='');
+ exit;
+ end;
+ found:=true;
+ repeat
+ inc(i1);
+ if (i1>length(hstr1)) then
+ break;
+ inc(i2);
+ if (i2>length(hstr2)) then
+ break;
+ case hstr1[i1] of
+ '?' :
+ found:=true;
+ '*' :
+ begin
+ found:=true;
+ if (i1=length(hstr1)) then
+ i2:=length(hstr2)
+ else
+ if (i1<length(hstr1)) and (hstr1[i1+1]<>hstr2[i2]) then
+ begin
+ if i2<length(hstr2) then
+ dec(i1)
+ end
+ else
+ if i2>1 then
+ dec(i2);
+ end;
+ else
+ found:=(hstr1[i1]=hstr2[i2]) or (hstr2[i2]='?');
+ end;
+ until not found;
+ if found then
+ begin
+ found:=(i2>=length(hstr2)) and
+ (
+ (i1>length(hstr1)) or
+ ((i1=length(hstr1)) and
+ (hstr1[i1]='*'))
+ );
+ end;
+ CmpStr:=found;
+ end;
+
+var
+ D1,D2 : DirStr;
+ N1,N2 : NameStr;
+ E1,E2 : Extstr;
+begin
+{$ifdef Unix}
+ FSplit(What,D1,N1,E1);
+ FSplit(Mask,D2,N2,E2);
+{$else}
+ FSplit(Upper(What),D1,N1,E1);
+ FSplit(Upper(Mask),D2,N2,E2);
+{$endif}
+ MatchesMask:=CmpStr(N2,N1) and CmpStr(E2,E1);
+end;
+
+function MatchesMaskList(What, MaskList: string): boolean;
+var P: integer;
+ Match: boolean;
+begin
+ Match:=false;
+ if What<>'' then
+ repeat
+ P:=Pos(ListSeparator, MaskList);
+ if P=0 then P:=length(MaskList)+1;
+ Match:=MatchesMask(What,copy(MaskList,1,P-1));
+ Delete(MaskList,1,P);
+ until Match or (MaskList='');
+ MatchesMaskList:=Match;
+end;
+
+constructor TFileList.Init(var Bounds: TRect; AScrollBar: PScrollBar);
+begin
+ TSortedListBox.Init(Bounds, 2, AScrollBar);
+end;
+
+destructor TFileList.Done;
+begin
+ if List <> nil then Dispose(List, Done);
+ TListBox.Done;
+end;
+
+function TFileList.DataSize: Sw_Word;
+begin
+ DataSize := 0;
+end;
+
+procedure TFileList.FocusItem(Item: Sw_Integer);
+begin
+ TSortedListBox.FocusItem(Item);
+ if (List^.Count > 0) then
+ Message(Owner, evBroadcast, cmFileFocused, List^.At(Item));
+end;
+
+procedure TFileList.GetData(var Rec);
+begin
+end;
+
+function TFileList.GetKey(var S: String): Pointer;
+const
+ SR: TSearchRec = ();
+
+procedure UpStr(var S: String);
+var
+ I: Sw_Integer;
+begin
+ for I := 1 to Length(S) do S[I] := UpCase(S[I]);
+end;
+
+begin
+ if (HandleDir{ShiftState and $03 <> 0}) or ((S <> '') and (S[1]='.')) then
+ SR.Attr := Directory
+ else SR.Attr := 0;
+ SR.Name := S;
+{$ifndef Unix}
+ UpStr(SR.Name);
+{$endif Unix}
+ GetKey := @SR;
+end;
+
+function TFileList.GetText(Item,MaxLen: Sw_Integer): String;
+var
+ S: String;
+ SR: PSearchRec;
+begin
+ SR := PSearchRec(List^.At(Item));
+ S := SR^.Name;
+ if SR^.Attr and Directory <> 0 then
+ begin
+ S[Length(S)+1] := DirSeparator;
+ Inc(S[0]);
+ end;
+ GetText := S;
+end;
+
+procedure TFileList.HandleEvent(var Event: TEvent);
+var
+ S : String;
+ K : pointer;
+ Value : Sw_integer;
+begin
+ if (Event.What = evMouseDown) and (Event.Double) then
+ begin
+ Event.What := evCommand;
+ Event.Command := cmOK;
+ PutEvent(Event);
+ ClearEvent(Event);
+ end
+ else if (Event.What = evKeyDown) and (Event.CharCode='<') then
+ begin
+ { select '..' }
+ S := '..';
+ K := GetKey(S);
+ If PSortedCollection(List)^.Search(K, Value) then
+ FocusItem(Value);
+ end
+ else TSortedListBox.HandleEvent(Event);
+end;
+
+procedure TFileList.ReadDirectory(AWildCard: PathStr);
+const
+ FindAttr = ReadOnly + Archive;
+ PrevDir = '..';
+var
+ S: SearchRec;
+ P: PSearchRec;
+ FileList: PFileCollection;
+ NumFiles: Word;
+ FindStr,
+ WildName : string;
+ Dir: DirStr;
+ Ext: ExtStr;
+ Name: NameStr;
+ Event : TEvent;
+ Tmp: PathStr;
+begin
+ NumFiles := 0;
+ FileList := New(PFileCollection, Init(5, 5));
+ AWildCard := FExpand(AWildCard);
+ FSplit(AWildCard, Dir, Name, Ext);
+ if pos(ListSeparator,AWildCard)>0 then
+ begin
+ WildName:=Copy(AWildCard,length(Dir)+1,255);
+ FindStr:=Dir+AllFiles;
+ end
+ else
+ begin
+ WildName:=Name+Ext;
+ FindStr:=AWildCard;
+ end;
+ FindFirst(FindStr, FindAttr, S);
+ P := PSearchRec(@P);
+ while assigned(P) and (DosError = 0) do
+ begin
+ if (S.Attr and Directory = 0) and
+ MatchesMaskList(S.Name,WildName) then
+ begin
+{ P := MemAlloc(SizeOf(P^));
+ if assigned(P) then
+ begin}
+ new(P);
+ P^.Attr:=S.Attr;
+ P^.Time:=S.Time;
+ P^.Size:=S.Size;
+ P^.Name:=S.Name;
+ FileList^.Insert(P);
+{ end;}
+ end;
+ FindNext(S);
+ end;
+ {$ifdef fpc}
+ FindClose(S);
+ {$endif}
+
+ Tmp := Dir + AllFiles;
+ FindFirst(Tmp, Directory, S);
+ while (P <> nil) and (DosError = 0) do
+ begin
+ if (S.Attr and Directory <> 0) and (S.Name <> '.') and (S.Name <> '..') then
+ begin
+{ P := MemAlloc(SizeOf(P^));
+ if P <> nil then
+ begin}
+ new(p);
+ P^.Attr:=S.Attr;
+ P^.Time:=S.Time;
+ P^.Size:=S.Size;
+ P^.Name:=S.Name;
+ FileList^.Insert(P);
+{ end;}
+ end;
+ FindNext(S);
+ end;
+ {$ifdef fpc}
+ FindClose(S);
+ {$endif}
+ {$ifndef Unix}
+ if Length(Dir) > 4 then
+ {$endif not Unix}
+ begin
+{
+ P := MemAlloc(SizeOf(P^));
+ if P <> nil then
+ begin}
+ new(p);
+ FindFirst(Tmp, Directory, S);
+ FindNext(S);
+ if (DosError = 0) and (S.Name = PrevDir) then
+ begin
+ P^.Attr:=S.Attr;
+ P^.Time:=S.Time;
+ P^.Size:=S.Size;
+ P^.Name:=S.Name;
+ end
+ else
+ begin
+ P^.Name := PrevDir;
+ P^.Size := 0;
+ P^.Time := $210000;
+ P^.Attr := Directory;
+ end;
+ FileList^.Insert(PSearchRec(P));
+ {$ifdef fpc}
+ FindClose(S);
+ {$endif}
+{ end;}
+ end;
+ if P = nil then
+ MessageBox(sTooManyFiles, nil, mfOkButton + mfWarning);
+ NewList(FileList);
+ if List^.Count > 0 then
+ begin
+ Event.What := evBroadcast;
+ Event.Command := cmFileFocused;
+ Event.InfoPtr := List^.At(0);
+ Owner^.HandleEvent(Event);
+ end;
+end;
+
+procedure TFileList.SetData(var Rec);
+begin
+ with PFileDialog(Owner)^ do
+ Self.ReadDirectory(Directory^ + WildCard);
+end;
+
+{****************************************************************************}
+{ TFileInfoPane Object }
+{****************************************************************************}
+{****************************************************************************}
+{ TFileInfoPane.Init }
+{****************************************************************************}
+constructor TFileInfoPane.Init(var Bounds: TRect);
+begin
+ TView.Init(Bounds);
+ FillChar(S,SizeOf(S),#0);
+ EventMask := EventMask or evBroadcast;
+end;
+
+{****************************************************************************}
+{ TFileInfoPane.Draw }
+{****************************************************************************}
+procedure TFileInfoPane.Draw;
+var
+ B: TDrawBuffer;
+ D: String[9];
+ M: String[3];
+ PM: Boolean;
+ Color: Word;
+ Time: DateTime;
+ Path: PathStr;
+ FmtId: String;
+ Params: array[0..7] of PtruInt;
+ Str: String[80];
+const
+ sDirectoryLine = ' %-12s %-9s %3s %2d, %4d %2d:%02d%cm';
+ sFileLine = ' %-12s %-9d %3s %2d, %4d %2d:%02d%cm';
+ InValidFiles : array[0..2] of string[12] = ('','.','..');
+var
+ Month: array[1..12] of String[3];
+begin
+ Month[1] := smJan;
+ Month[2] := smFeb;
+ Month[3] := smMar;
+ Month[4] := smApr;
+ Month[5] := smMay;
+ Month[6] := smJun;
+ Month[7] := smJul;
+ Month[8] := smAug;
+ Month[9] := smSep;
+ Month[10] := smOct;
+ Month[11] := smNov;
+ Month[12] := smDec;
+ { Display path }
+ if (PFileDialog(Owner)^.Directory <> nil) then
+ Path := PFileDialog(Owner)^.Directory^
+ else Path := '';
+ Path := FExpand(Path+PFileDialog(Owner)^.WildCard);
+ { avoid B Buffer overflow PM }
+ Path := ShrinkPath(Path, Size.X - 1);
+ Color := GetColor($01);
+ MoveChar(B, ' ', Color, Size.X); { fill with empty spaces }
+ WriteLine(0, 0, Size.X, Size.Y, B);
+ MoveStr(B[1], Path, Color);
+ WriteLine(0, 0, Size.X, 1, B);
+ if (S.Name = InValidFiles[0]) or (S.Name = InValidFiles[1]) or
+ (S.Name = InValidFiles[2]) then
+ Exit;
+
+ { Display file }
+ Params[0] := ptruint(@S.Name);
+ if S.Attr and Directory <> 0 then
+ begin
+ FmtId := sDirectoryLine;
+ D := sDirectory;
+ Params[1] := ptruint(@D);
+ end else
+ begin
+ FmtId := sFileLine;
+ Params[1] := S.Size;
+ end;
+ UnpackTime(S.Time, Time);
+ M := Month[Time.Month];
+ Params[2] := ptruint(@M);
+ Params[3] := Time.Day;
+ Params[4] := Time.Year;
+ PM := Time.Hour >= 12;
+ Time.Hour := Time.Hour mod 12;
+ if Time.Hour = 0 then Time.Hour := 12;
+ Params[5] := Time.Hour;
+ Params[6] := Time.Min;
+ if PM then
+ Params[7] := Byte('p')
+ else Params[7] := Byte('a');
+ FormatStr(Str, FmtId, Params);
+ MoveStr(B, Str, Color);
+ WriteLine(0, 1, Size.X, 1, B);
+
+ { Fill in rest of rectangle }
+ MoveChar(B, ' ', Color, Size.X);
+ WriteLine(0, 2, Size.X, Size.Y-2, B);
+end;
+
+function TFileInfoPane.GetPalette: PPalette;
+const
+ P: String[Length(CInfoPane)] = CInfoPane;
+begin
+ GetPalette := PPalette(@P);
+end;
+
+procedure TFileInfoPane.HandleEvent(var Event: TEvent);
+begin
+ TView.HandleEvent(Event);
+ if (Event.What = evBroadcast) and (Event.Command = cmFileFocused) then
+ begin
+ S := PSearchRec(Event.InfoPtr)^;
+ DrawView;
+ end;
+end;
+
+{****************************************************************************
+ TFileHistory
+****************************************************************************}
+
+ function LTrim(const S: String): String;
+ var
+ I: Sw_Integer;
+ begin
+ I := 1;
+ while (I < Length(S)) and (S[I] = ' ') do Inc(I);
+ LTrim := Copy(S, I, 255);
+ end;
+
+ function RTrim(const S: String): String;
+ var
+ I: Sw_Integer;
+ begin
+ I := Length(S);
+ while S[I] = ' ' do Dec(I);
+ RTrim := Copy(S, 1, I);
+ end;
+
+ function RelativePath(var S: PathStr): Boolean;
+ begin
+ S := LTrim(RTrim(S));
+ RelativePath := not ((S <> '') and ((S[1] = DirSeparator) or (S[2] = ':')));
+ end;
+
+{ try to reduce the length of S+dir as a file path+pattern }
+
+ function Simplify (var S,Dir : string) : string;
+ var i : sw_integer;
+ begin
+ if RelativePath(Dir) then
+ begin
+ if (S<>'') and (Copy(Dir,1,3)='..'+DirSeparator) then
+ begin
+ i:=Length(S);
+ for i:=Length(S)-1 downto 1 do
+ if S[i]=DirSeparator then
+ break;
+ if S[i]=DirSeparator then
+ Simplify:=Copy(S,1,i)+Copy(Dir,4,255)
+ else
+ Simplify:=S+Dir;
+ end
+ else
+ Simplify:=S+Dir;
+ end
+ else
+ Simplify:=Dir;
+ end;
+
+{****************************************************************************}
+{ TFileHistory.HandleEvent }
+{****************************************************************************}
+
+procedure TFileHistory.HandleEvent(var Event: TEvent);
+var
+ HistoryWindow: PHistoryWindow;
+ R,P: TRect;
+ C: Word;
+ Rslt: String;
+begin
+ TView.HandleEvent(Event);
+ if (Event.What = evMouseDown) or
+ ((Event.What = evKeyDown) and (CtrlToArrow(Event.KeyCode) = kbDown) and
+ (Link^.State and sfFocused <> 0)) then
+ begin
+ if not Link^.Focus then
+ begin
+ ClearEvent(Event);
+ Exit;
+ end;
+ if assigned(CurDir) then
+ Rslt:=CurDir^
+ else
+ Rslt:='';
+ Rslt:=Simplify(Rslt,Link^.Data^);
+ RemoveDoubleDirSep(Rslt);
+ If IsWild(Rslt) then
+ RecordHistory(Rslt);
+ Link^.GetBounds(R);
+ Dec(R.A.X); Inc(R.B.X); Inc(R.B.Y,7); Dec(R.A.Y,1);
+ Owner^.GetExtent(P);
+ R.Intersect(P);
+ Dec(R.B.Y,1);
+ HistoryWindow := InitHistoryWindow(R);
+ if HistoryWindow <> nil then
+ begin
+ C := Owner^.ExecView(HistoryWindow);
+ if C = cmOk then
+ begin
+ Rslt := HistoryWindow^.GetSelection;
+ if Length(Rslt) > Link^.MaxLen then Rslt[0] := Char(Link^.MaxLen);
+ Link^.Data^ := Rslt;
+ Link^.SelectAll(True);
+ Link^.DrawView;
+ end;
+ Dispose(HistoryWindow, Done);
+ end;
+ ClearEvent(Event);
+ end
+ else if (Event.What = evBroadcast) then
+ if ((Event.Command = cmReleasedFocus) and (Event.InfoPtr = Link))
+ or (Event.Command = cmRecordHistory) then
+ begin
+ if assigned(CurDir) then
+ Rslt:=CurDir^
+ else
+ Rslt:='';
+ Rslt:=Simplify(Rslt,Link^.Data^);
+ RemoveDoubleDirSep(Rslt);
+ If IsWild(Rslt) then
+ RecordHistory(Rslt);
+ end;
+end;
+
+procedure TFileHistory.AdaptHistoryToDir(Dir : string);
+ var S,S2 : String;
+ i,Count : Sw_word;
+begin
+ if assigned(CurDir) then
+ begin
+ S:=CurDir^;
+ if S=Dir then
+ exit;
+ DisposeStr(CurDir);
+ end
+ else
+ S:='';
+ CurDir:=NewStr(Simplify(S,Dir));
+
+ Count:=HistoryCount(HistoryId);
+ for i:=1 to count do
+ begin
+ S2:=HistoryStr(HistoryId,1);
+ HistoryRemove(HistoryId,1);
+ if RelativePath(S2) then
+ if S<>'' then
+ S2:=S+S2
+ else
+ S2:=FExpand(S2);
+ { simply full path
+ we should simplify relative to Dir ! }
+ HistoryAdd(HistoryId,S2);
+ end;
+
+end;
+
+destructor TFileHistory.Done;
+begin
+ If assigned(CurDir) then
+ DisposeStr(CurDir);
+ Inherited Done;
+end;
+
+{****************************************************************************
+ TFileDialog
+****************************************************************************}
+
+constructor TFileDialog.Init(AWildCard: TWildStr; const ATitle,
+ InputName: String; AOptions: Word; HistoryId: Byte);
+var
+ Control: PView;
+ R: TRect;
+ Opt: Word;
+begin
+ R.Assign(15,1,64,20);
+ TDialog.Init(R, ATitle);
+ Options := Options or ofCentered;
+ WildCard := AWildCard;
+
+ R.Assign(3,3,31,4);
+ FileName := New(PFileInputLine, Init(R, 79));
+ FileName^.Data^ := WildCard;
+ Insert(FileName);
+ R.Assign(2,2,3+CStrLen(InputName),3);
+ Control := New(PLabel, Init(R, InputName, FileName));
+ Insert(Control);
+ R.Assign(31,3,34,4);
+ FileHistory := New(PFileHistory, Init(R, FileName, HistoryId));
+ Insert(FileHistory);
+
+ R.Assign(3,14,34,15);
+ Control := New(PScrollBar, Init(R));
+ Insert(Control);
+ R.Assign(3,6,34,14);
+ FileList := New(PFileList, Init(R, PScrollBar(Control)));
+ Insert(FileList);
+ R.Assign(2,5,8,6);
+ Control := New(PLabel, Init(R, slFiles, FileList));
+ Insert(Control);
+
+ R.Assign(35,3,46,5);
+ Opt := bfDefault;
+ if AOptions and fdOpenButton <> 0 then
+ begin
+ Insert(New(PButton, Init(R,slOpen, cmFileOpen, Opt)));
+ Opt := bfNormal;
+ Inc(R.A.Y,3); Inc(R.B.Y,3);
+ end;
+ if AOptions and fdOkButton <> 0 then
+ begin
+ Insert(New(PButton, Init(R,slOk, cmFileOpen, Opt)));
+ Opt := bfNormal;
+ Inc(R.A.Y,3); Inc(R.B.Y,3);
+ end;
+ if AOptions and fdReplaceButton <> 0 then
+ begin
+ Insert(New(PButton, Init(R, slReplace,cmFileReplace, Opt)));
+ Opt := bfNormal;
+ Inc(R.A.Y,3); Inc(R.B.Y,3);
+ end;
+ if AOptions and fdClearButton <> 0 then
+ begin
+ Insert(New(PButton, Init(R, slClear,cmFileClear, Opt)));
+ Opt := bfNormal;
+ Inc(R.A.Y,3); Inc(R.B.Y,3);
+ end;
+ Insert(New(PButton, Init(R, slCancel, cmCancel, bfNormal)));
+ Inc(R.A.Y,3); Inc(R.B.Y,3);
+ if AOptions and fdHelpButton <> 0 then
+ begin
+ Insert(New(PButton, Init(R,slHelp,cmHelp, bfNormal)));
+ Inc(R.A.Y,3); Inc(R.B.Y,3);
+ end;
+
+ R.Assign(1,16,48,18);
+ Control := New(PFileInfoPane, Init(R));
+ Insert(Control);
+
+ SelectNext(False);
+
+ if AOptions and fdNoLoadDir = 0 then ReadDirectory;
+end;
+
+constructor TFileDialog.Load(var S: TStream);
+begin
+ if not TDialog.Load(S) then
+ Fail;
+ S.Read(WildCard, SizeOf(WildCard));
+ if (S.Status <> stOk) then
+ begin
+ TDialog.Done;
+ Fail;
+ end;
+ GetSubViewPtr(S, FileName);
+ GetSubViewPtr(S, FileList);
+ GetSubViewPtr(S, FileHistory);
+ ReadDirectory;
+ if (DosError <> 0) then
+ begin
+ TDialog.Done;
+ Fail;
+ end;
+end;
+
+destructor TFileDialog.Done;
+begin
+ DisposeStr(Directory);
+ TDialog.Done;
+end;
+
+procedure TFileDialog.GetData(var Rec);
+begin
+ GetFilename(PathStr(Rec));
+end;
+
+procedure TFileDialog.GetFileName(var S: PathStr);
+
+var
+ Path: PathStr;
+ Name: NameStr;
+ Ext: ExtStr;
+ TWild : string;
+ TPath: PathStr;
+ TName: NameStr;
+ TExt: NameStr;
+ i : Sw_integer;
+begin
+ S := FileName^.Data^;
+ if RelativePath(S) then
+ begin
+ if (Directory <> nil) then
+ S := FExpand(Directory^ + S);
+ end
+ else
+ S := FExpand(S);
+ if Pos(ListSeparator,S)=0 then
+ begin
+ If FileExists(S) then
+ exit;
+ FSplit(S, Path, Name, Ext);
+ if ((Name = '') or (Ext = '')) and not IsDir(S) then
+ begin
+ TWild:=WildCard;
+ repeat
+ i:=Pos(ListSeparator,TWild);
+ if i=0 then
+ i:=length(TWild)+1;
+ FSplit(Copy(TWild,1,i-1), TPath, TName, TExt);
+ if ((Name = '') and (Ext = '')) then
+ S := Path + TName + TExt
+ else
+ if Name = '' then
+ S := Path + TName + Ext
+ else
+ if Ext = '' then
+ begin
+ if IsWild(Name) then
+ S := Path + Name + TExt
+ else
+ S := Path + Name + NoWildChars(TExt);
+ end;
+ if FileExists(S) then
+ break;
+ System.Delete(TWild,1,i);
+ until TWild='';
+ if TWild='' then
+ S := Path + Name + Ext;
+ end;
+ end;
+end;
+
+procedure TFileDialog.HandleEvent(var Event: TEvent);
+begin
+ if (Event.What and evBroadcast <> 0) and
+ (Event.Command = cmListItemSelected) then
+ begin
+ EndModal(cmFileOpen);
+ ClearEvent(Event);
+ end;
+ TDialog.HandleEvent(Event);
+ if Event.What = evCommand then
+ case Event.Command of
+ cmFileOpen, cmFileReplace, cmFileClear:
+ begin
+ EndModal(Event.Command);
+ ClearEvent(Event);
+ end;
+ end;
+end;
+
+procedure TFileDialog.SetData(var Rec);
+begin
+ TDialog.SetData(Rec);
+ if (PathStr(Rec) <> '') and (IsWild(TWildStr(Rec))) then
+ begin
+ Valid(cmFileInit);
+ FileName^.Select;
+ end;
+end;
+
+procedure TFileDialog.ReadDirectory;
+begin
+ FileList^.ReadDirectory(WildCard);
+ FileHistory^.AdaptHistoryToDir(GetCurDir);
+ Directory := NewStr(GetCurDir);
+end;
+
+procedure TFileDialog.Store(var S: TStream);
+begin
+ TDialog.Store(S);
+ S.Write(WildCard, SizeOf(WildCard));
+ PutSubViewPtr(S, FileName);
+ PutSubViewPtr(S, FileList);
+ PutSubViewPtr(S, FileHistory);
+end;
+
+function TFileDialog.Valid(Command: Word): Boolean;
+var
+ FName: PathStr;
+ Dir: DirStr;
+ Name: NameStr;
+ Ext: ExtStr;
+
+ function CheckDirectory(var S: PathStr): Boolean;
+ begin
+ if not PathValid(S) then
+ begin
+ MessageBox(sInvalidDriveOrDir, nil, mfError + mfOkButton);
+ FileName^.Select;
+ CheckDirectory := False;
+ end else CheckDirectory := True;
+ end;
+
+ function CompleteDir(const Path: string): string;
+ begin
+ { keep c: untouched PM }
+ if (Path<>'') and (Path[Length(Path)]<>DirSeparator) and
+ (Path[Length(Path)]<>':') then
+ CompleteDir:=Path+DirSeparator
+ else
+ CompleteDir:=Path;
+ end;
+
+ function NormalizeDir(const Path: string): string;
+ var Root: boolean;
+ begin
+ Root:=false;
+ {$ifdef Unix}
+ if Path=DirSeparator then Root:=true;
+ {$else}
+ if (length(Path)=3) and (Upcase(Path[1]) in['A'..'Z']) and
+ (Path[2]=':') and (Path[3]=DirSeparator) then
+ Root:=true;
+ {$endif}
+ if (Root=false) and (copy(Path,length(Path),1)=DirSeparator) then
+ NormalizeDir:=copy(Path,1,length(Path)-1)
+ else
+ NormalizeDir:=Path;
+ end;
+function NormalizeDirF(var S: openstring): boolean;
+begin
+ S:=NormalizeDir(S);
+ NormalizeDirF:=true;
+end;
+
+begin
+ if Command = 0 then
+ begin
+ Valid := True;
+ Exit;
+ end
+ else Valid := False;
+ if TDialog.Valid(Command) then
+ begin
+ GetFileName(FName);
+ if (Command <> cmCancel) and (Command <> cmFileClear) then
+ begin
+ if IsWild(FName) or IsList(FName) then
+ begin
+ FSplit(FName, Dir, Name, Ext);
+ if CheckDirectory(Dir) then
+ begin
+ FileHistory^.AdaptHistoryToDir(Dir);
+ DisposeStr(Directory);
+ Directory := NewStr(Dir);
+ if Pos(ListSeparator,FName)>0 then
+ WildCard:=Copy(FName,length(Dir)+1,255)
+ else
+ WildCard := Name+Ext;
+ if Command <> cmFileInit then
+ FileList^.Select;
+ FileList^.ReadDirectory(Directory^+WildCard);
+ end;
+ end
+ else
+ if NormalizeDirF(FName) then
+ { ^^ this is just a dummy if construct (the func always returns true,
+ it's just there, 'coz I don't want to rearrange the following "if"s... }
+ if IsDir(FName) then
+ begin
+ if CheckDirectory(FName) then
+ begin
+ FileHistory^.AdaptHistoryToDir(CompleteDir(FName));
+ DisposeStr(Directory);
+ Directory := NewSTr(CompleteDir(FName));
+ if Command <> cmFileInit then FileList^.Select;
+ FileList^.ReadDirectory(Directory^+WildCard);
+ end
+ end
+ else
+ if ValidFileName(FName) then
+ Valid := True
+ else
+ begin
+ MessageBox(^C + sInvalidFileName, nil, mfError + mfOkButton);
+ Valid := False;
+ end;
+ end
+ else Valid := True;
+ end;
+end;
+
+{ TDirCollection }
+
+function TDirCollection.GetItem(var S: TStream): Pointer;
+var
+ DirItem: PDirEntry;
+begin
+ New(DirItem);
+ DirItem^.DisplayText := S.ReadStr;
+ DirItem^.Directory := S.ReadStr;
+ GetItem := DirItem;
+end;
+
+procedure TDirCollection.FreeItem(Item: Pointer);
+var
+ DirItem: PDirEntry absolute Item;
+begin
+ DisposeStr(DirItem^.DisplayText);
+ DisposeStr(DirItem^.Directory);
+ Dispose(DirItem);
+end;
+
+procedure TDirCollection.PutItem(var S: TStream; Item: Pointer);
+var
+ DirItem: PDirEntry absolute Item;
+begin
+ S.WriteStr(DirItem^.DisplayText);
+ S.WriteStr(DirItem^.Directory);
+end;
+
+{ TDirListBox }
+
+const
+ DrivesS: String = '';
+ Drives: PString = @DrivesS;
+
+constructor TDirListBox.Init(var Bounds: TRect; AScrollBar:
+ PScrollBar);
+begin
+ DrivesS := sDrives;
+ TListBox.Init(Bounds, 1, AScrollBar);
+ Dir := '';
+end;
+
+destructor TDirListBox.Done;
+begin
+ if (List <> nil) then
+ Dispose(List,Done);
+ TListBox.Done;
+end;
+
+function TDirListBox.GetText(Item,MaxLen: Sw_Integer): String;
+begin
+ GetText := PDirEntry(List^.At(Item))^.DisplayText^;
+end;
+
+procedure TDirListBox.HandleEvent(var Event: TEvent);
+begin
+ case Event.What of
+ evMouseDown:
+ if Event.Double then
+ begin
+ Event.What := evCommand;
+ Event.Command := cmChangeDir;
+ PutEvent(Event);
+ ClearEvent(Event);
+ end;
+ evKeyboard:
+ if (Event.CharCode = ' ') and
+ (PSearchRec(List^.At(Focused))^.Name = '..') then
+ NewDirectory(PSearchRec(List^.At(Focused))^.Name);
+ end;
+ TListBox.HandleEvent(Event);
+end;
+
+function TDirListBox.IsSelected(Item: Sw_Integer): Boolean;
+begin
+{ IsSelected := Item = Cur; }
+ IsSelected := Inherited IsSelected(Item);
+end;
+
+procedure TDirListBox.NewDirectory(var ADir: DirStr);
+const
+ PathDir = 'ÀÄÂ';
+ FirstDir = 'ÀÂÄ';
+ MiddleDir = ' ÃÄ';
+ LastDir = ' ÀÄ';
+ IndentSize = ' ';
+var
+ AList: PCollection;
+ NewDir, Dirct: DirStr;
+ C, OldC: Char;
+ S, Indent: String[80];
+ P: PString;
+ NewCur: Word;
+ isFirst: Boolean;
+ SR: SearchRec;
+ I: Sw_Integer;
+
+ function NewDirEntry(const DisplayText, Directory: String): PDirEntry;{$ifdef PPC_BP}near;{$endif}
+ var
+ DirEntry: PDirEntry;
+ begin
+ New(DirEntry);
+ DirEntry^.DisplayText := NewStr(DisplayText);
+ If Directory='' then
+ DirEntry^.Directory := NewStr(DirSeparator)
+ else
+ DirEntry^.Directory := NewStr(Directory);
+ NewDirEntry := DirEntry;
+ end;
+
+begin
+ Dir := ADir;
+ AList := New(PDirCollection, Init(5,5));
+{$ifdef HAS_DOS_DRIVES}
+ AList^.Insert(NewDirEntry(Drives^,Drives^));
+ if Dir = Drives^ then
+ begin
+ isFirst := True;
+ OldC := ' ';
+ for C := 'A' to 'Z' do
+ begin
+ if (C < 'C') or DriveValid(C) then
+ begin
+ if OldC <> ' ' then
+ begin
+ if isFirst then
+ begin
+ S := FirstDir + OldC;
+ isFirst := False;
+ end
+ else S := MiddleDir + OldC;
+ AList^.Insert(NewDirEntry(S, OldC + ':' + DirSeparator));
+ end;
+ if C = GetCurDrive then NewCur := AList^.Count;
+ OldC := C;
+ end;
+ end;
+ if OldC <> ' ' then
+ AList^.Insert(NewDirEntry(LastDir + OldC, OldC + ':' + DirSeparator));
+ end
+ else
+{$endif HAS_DOS_DRIVES}
+ begin
+ Indent := IndentSize;
+ NewDir := Dir;
+{$ifdef HAS_DOS_DRIVES}
+ Dirct := Copy(NewDir,1,3);
+ AList^.Insert(NewDirEntry(PathDir + Dirct, Dirct));
+ NewDir := Copy(NewDir,4,255);
+{$else HAS_DOS_DRIVES}
+ Dirct := '';
+{$endif HAS_DOS_DRIVES}
+ while NewDir <> '' do
+ begin
+ I := Pos(DirSeparator,NewDir);
+ if I <> 0 then
+ begin
+ S := Copy(NewDir,1,I-1);
+ Dirct := Dirct + S;
+ AList^.Insert(NewDirEntry(Indent + PathDir + S, Dirct));
+ NewDir := Copy(NewDir,I+1,255);
+ end
+ else
+ begin
+ Dirct := Dirct + NewDir;
+ AList^.Insert(NewDirEntry(Indent + PathDir + NewDir, Dirct));
+ NewDir := '';
+ end;
+ Indent := Indent + IndentSize;
+ Dirct := Dirct + DirSeparator;
+ end;
+ NewCur := AList^.Count-1;
+ isFirst := True;
+ NewDir := Dirct + AllFiles;
+ FindFirst(NewDir, Directory, SR);
+ while DosError = 0 do
+ begin
+ if (SR.Attr and Directory <> 0) and
+ (SR.Name <> '.') and (SR.Name <> '..') then
+ begin
+ if isFirst then
+ begin
+ S := FirstDir;
+ isFirst := False;
+ end else S := MiddleDir;
+ AList^.Insert(NewDirEntry(Indent + S + SR.Name, Dirct + SR.Name));
+ end;
+ FindNext(SR);
+ end;
+ FindClose(SR);
+ P := PDirEntry(AList^.At(AList^.Count-1))^.DisplayText;
+ I := Pos('À',P^);
+ if I = 0 then
+ begin
+ I := Pos('Ã',P^);
+ if I <> 0 then P^[I] := 'À';
+ end else
+ begin
+ P^[I+1] := 'Ä';
+ P^[I+2] := 'Ä';
+ end;
+ end;
+ NewList(AList);
+ FocusItem(NewCur);
+ Cur:=NewCur;
+end;
+
+procedure TDirListBox.SetState(AState: Word; Enable: Boolean);
+begin
+ TListBox.SetState(AState, Enable);
+ if AState and sfFocused <> 0 then
+ PChDirDialog(Owner)^.ChDirButton^.MakeDefault(Enable);
+end;
+
+{****************************************************************************}
+{ TChDirDialog Object }
+{****************************************************************************}
+{****************************************************************************}
+{ TChDirDialog.Init }
+{****************************************************************************}
+constructor TChDirDialog.Init(AOptions: Word; HistoryId: Sw_Word);
+var
+ R: TRect;
+ Control: PView;
+begin
+ R.Assign(16, 2, 64, 20);
+ TDialog.Init(R,sChangeDirectory);
+
+ Options := Options or ofCentered;
+
+ R.Assign(3, 3, 30, 4);
+ DirInput := New(PInputLine, Init(R, FileNameLen+4));
+ Insert(DirInput);
+ R.Assign(2, 2, 17, 3);
+ Control := New(PLabel, Init(R,slDirectoryName, DirInput));
+ Insert(Control);
+ R.Assign(30, 3, 33, 4);
+ Control := New(PHistory, Init(R, DirInput, HistoryId));
+ Insert(Control);
+
+ R.Assign(32, 6, 33, 16);
+ Control := New(PScrollBar, Init(R));
+ Insert(Control);
+ R.Assign(3, 6, 32, 16);
+ DirList := New(PDirListBox, Init(R, PScrollBar(Control)));
+ Insert(DirList);
+ R.Assign(2, 5, 17, 6);
+ Control := New(PLabel, Init(R, slDirectoryTree, DirList));
+ Insert(Control);
+
+ R.Assign(35, 6, 45, 8);
+ OkButton := New(PButton, Init(R, slOk, cmOK, bfDefault));
+ Insert(OkButton);
+ Inc(R.A.Y,3); Inc(R.B.Y,3);
+ ChDirButton := New(PButton,Init(R,slChDir,cmChangeDir,
+ bfNormal));
+ Insert(ChDirButton);
+ Inc(R.A.Y,3); Inc(R.B.Y,3);
+ Insert(New(PButton, Init(R,slRevert, cmRevert, bfNormal)));
+ if AOptions and cdHelpButton <> 0 then
+ begin
+ Inc(R.A.Y,3); Inc(R.B.Y,3);
+ Insert(New(PButton, Init(R,slHelp, cmHelp, bfNormal)));
+ end;
+
+ if AOptions and cdNoLoadDir = 0 then SetUpDialog;
+
+ SelectNext(False);
+end;
+
+{****************************************************************************}
+{ TChDirDialog.Load }
+{****************************************************************************}
+constructor TChDirDialog.Load(var S: TStream);
+begin
+ TDialog.Load(S);
+ GetSubViewPtr(S, DirList);
+ GetSubViewPtr(S, DirInput);
+ GetSubViewPtr(S, OkButton);
+ GetSubViewPtr(S, ChDirbutton);
+ SetUpDialog;
+end;
+
+{****************************************************************************}
+{ TChDirDialog.DataSize }
+{****************************************************************************}
+function TChDirDialog.DataSize: Sw_Word;
+begin
+ DataSize := 0;
+end;
+
+{****************************************************************************}
+{ TChDirDialog.GetData }
+{****************************************************************************}
+procedure TChDirDialog.GetData(var Rec);
+begin
+end;
+
+{****************************************************************************}
+{ TChDirDialog.HandleEvent }
+{****************************************************************************}
+procedure TChDirDialog.HandleEvent(var Event: TEvent);
+var
+ CurDir: DirStr;
+ P: PDirEntry;
+begin
+ TDialog.HandleEvent(Event);
+ case Event.What of
+ evCommand:
+ begin
+ case Event.Command of
+ cmRevert: GetDir(0,CurDir);
+ cmChangeDir:
+ begin
+ P := DirList^.List^.At(DirList^.Focused);
+ if (P^.Directory^ = Drives^)
+ or DriveValid(P^.Directory^[1]) then
+ CurDir := P^.Directory^
+ else Exit;
+ end;
+ else
+ Exit;
+ end;
+ if (Length(CurDir) > 3) and
+ (CurDir[Length(CurDir)] = DirSeparator) then
+ CurDir := Copy(CurDir,1,Length(CurDir)-1);
+ DirList^.NewDirectory(CurDir);
+ DirInput^.Data^ := CurDir;
+ DirInput^.DrawView;
+ DirList^.Select;
+ ClearEvent(Event);
+ end;
+ end;
+end;
+
+{****************************************************************************}
+{ TChDirDialog.SetData }
+{****************************************************************************}
+procedure TChDirDialog.SetData(var Rec);
+begin
+end;
+
+{****************************************************************************}
+{ TChDirDialog.SetUpDialog }
+{****************************************************************************}
+procedure TChDirDialog.SetUpDialog;
+var
+ CurDir: DirStr;
+begin
+ if DirList <> nil then
+ begin
+ CurDir := GetCurDir;
+ DirList^.NewDirectory(CurDir);
+ if (Length(CurDir) > 3) and (CurDir[Length(CurDir)] = DirSeparator) then
+ CurDir := Copy(CurDir,1,Length(CurDir)-1);
+ if DirInput <> nil then
+ begin
+ DirInput^.Data^ := CurDir;
+ DirInput^.DrawView;
+ end;
+ end;
+end;
+
+{****************************************************************************}
+{ TChDirDialog.Store }
+{****************************************************************************}
+procedure TChDirDialog.Store(var S: TStream);
+begin
+ TDialog.Store(S);
+ PutSubViewPtr(S, DirList);
+ PutSubViewPtr(S, DirInput);
+ PutSubViewPtr(S, OkButton);
+ PutSubViewPtr(S, ChDirButton);
+end;
+
+{****************************************************************************}
+{ TChDirDialog.Valid }
+{****************************************************************************}
+function TChDirDialog.Valid(Command: Word): Boolean;
+var
+ P: PathStr;
+begin
+ Valid := True;
+ if Command = cmOk then
+ begin
+ P := FExpand(DirInput^.Data^);
+ if (Length(P) > 3) and (P[Length(P)] = DirSeparator) then
+ Dec(P[0]);
+ {$I-}
+ ChDir(P);
+ if (IOResult <> 0) then
+ begin
+ MessageBox(sInvalidDirectory, nil, mfError + mfOkButton);
+ Valid := False;
+ end;
+ {$I+}
+ end;
+end;
+
+{****************************************************************************}
+{ TEditChDirDialog Object }
+{****************************************************************************}
+{****************************************************************************}
+{ TEditChDirDialog.DataSize }
+{****************************************************************************}
+function TEditChDirDialog.DataSize : Sw_Word;
+begin
+ DataSize := SizeOf(DirStr);
+end;
+
+{****************************************************************************}
+{ TEditChDirDialog.GetData }
+{****************************************************************************}
+procedure TEditChDirDialog.GetData (var Rec);
+var
+ CurDir : DirStr absolute Rec;
+begin
+ if (DirInput = nil) then
+ CurDir := ''
+ else begin
+ CurDir := DirInput^.Data^;
+ if (CurDir[Length(CurDir)] <> DirSeparator) then
+ CurDir := CurDir + DirSeparator;
+ end;
+end;
+
+{****************************************************************************}
+{ TEditChDirDialog.SetData }
+{****************************************************************************}
+procedure TEditChDirDialog.SetData (var Rec);
+var
+ CurDir : DirStr absolute Rec;
+begin
+ if DirList <> nil then
+ begin
+ DirList^.NewDirectory(CurDir);
+ if DirInput <> nil then
+ begin
+ if (Length(CurDir) > 3) and (CurDir[Length(CurDir)] = DirSeparator) then
+ DirInput^.Data^ := Copy(CurDir,1,Length(CurDir)-1)
+ else DirInput^.Data^ := CurDir;
+ DirInput^.DrawView;
+ end;
+ end;
+end;
+
+{****************************************************************************}
+{ TSortedListBox Object }
+{****************************************************************************}
+{****************************************************************************}
+{ TSortedListBox.Init }
+{****************************************************************************}
+constructor TSortedListBox.Init(var Bounds: TRect; ANumCols: Sw_Word;
+ AScrollBar: PScrollBar);
+begin
+ TListBox.Init(Bounds, ANumCols, AScrollBar);
+ SearchPos := 0;
+ ShowCursor;
+ SetCursor(1,0);
+end;
+
+{****************************************************************************}
+{ TSortedListBox.HandleEvent }
+{****************************************************************************}
+procedure TSortedListBox.HandleEvent(var Event: TEvent);
+const
+ SpecialChars: set of Char = [#0,#9,#27];
+var
+ CurString, NewString: String;
+ K: Pointer;
+ Value : Sw_integer;
+ OldPos, OldValue: Sw_Integer;
+ T: Boolean;
+begin
+ OldValue := Focused;
+ TListBox.HandleEvent(Event);
+ if (OldValue <> Focused) or
+ ((Event.What = evBroadcast) and (Event.InfoPtr = @Self) and
+ (Event.Command = cmReleasedFocus)) then
+ SearchPos := 0;
+ if Event.What = evKeyDown then
+ begin
+ { patched to prevent error when no or empty list or Escape pressed }
+ if (not (Event.CharCode in SpecialChars)) and
+ (List <> nil) and (List^.Count > 0) then
+ begin
+ Value := Focused;
+ if Value < Range then
+ CurString := GetText(Value, 255)
+ else
+ CurString := '';
+ OldPos := SearchPos;
+ if Event.KeyCode = kbBack then
+ begin
+ if SearchPos = 0 then Exit;
+ Dec(SearchPos);
+ if SearchPos = 0 then
+ HandleDir:= ((GetShiftState and $3) <> 0) or (Event.CharCode in ['A'..'Z']);
+ CurString[0] := Char(SearchPos);
+ end
+ else if (Event.CharCode = '.') then
+ SearchPos := Pos('.',CurString)
+ else
+ begin
+ Inc(SearchPos);
+ if SearchPos = 1 then
+ HandleDir := ((GetShiftState and 3) <> 0) or (Event.CharCode in ['A'..'Z']);
+ CurString[0] := Char(SearchPos);
+ CurString[SearchPos] := Event.CharCode;
+ end;
+ K := GetKey(CurString);
+ T := PSortedCollection(List)^.Search(K, Value);
+ if Value < Range then
+ begin
+ if Value < Range then
+ NewString := GetText(Value, 255)
+ else
+ NewString := '';
+ if Equal(NewString, CurString, SearchPos) then
+ begin
+ if Value <> OldValue then
+ begin
+ FocusItem(Value);
+ { Assumes ListControl will set the cursor to the first character }
+ { of the sfFocused item }
+ SetCursor(Cursor.X+SearchPos, Cursor.Y);
+ end
+ else
+ SetCursor(Cursor.X+(SearchPos-OldPos), Cursor.Y);
+ end
+ else
+ SearchPos := OldPos;
+ end
+ else SearchPos := OldPos;
+ if (SearchPos <> OldPos) or (Event.CharCode in ['A'..'Z','a'..'z']) then
+ ClearEvent(Event);
+ end;
+ end;
+end;
+
+function TSortedListBox.GetKey(var S: String): Pointer;
+begin
+ GetKey := @S;
+end;
+
+procedure TSortedListBox.NewList(AList: PCollection);
+begin
+ TListBox.NewList(AList);
+ SearchPos := 0;
+end;
+
+{****************************************************************************}
+{ Global Procedures and Functions }
+{****************************************************************************}
+
+{****************************************************************************}
+{ Contains }
+{****************************************************************************}
+function Contains(S1, S2: String): Boolean;
+ { Contains returns true if S1 contains any characters in S2. }
+var
+ i : Byte;
+begin
+ Contains := True;
+ i := 1;
+ while ((i < Length(S2)) and (i < Length(S1))) do
+ if (Upcase(S1[i]) = Upcase(S2[i])) then
+ Exit
+ else Inc(i);
+ Contains := False;
+end;
+
+{****************************************************************************}
+{ StdDeleteFile }
+{****************************************************************************}
+function StdDeleteFile (AFile : FNameStr) : Boolean;
+var
+ Rec : PStringRec;
+begin
+ if CheckOnDelete then
+ begin
+ AFile := ShrinkPath(AFile,33);
+ Rec.AString := PString(@AFile);
+ StdDeleteFile := (MessageBox(^C + sDeleteFile,
+ @Rec,mfConfirmation or mfOkCancel) = cmOk);
+ end
+ else StdDeleteFile := False;
+end;
+
+{****************************************************************************}
+{ DriveValid }
+{****************************************************************************}
+function DriveValid(Drive: Char): Boolean;
+{$ifdef HAS_DOS_DRIVES}
+var
+ D: Char;
+begin
+ D := GetCurDrive;
+ {$I-}
+ ChDir(Drive+':');
+ if (IOResult = 0) then
+ begin
+ DriveValid := True;
+ ChDir(D+':')
+ end
+ else DriveValid := False;
+ {$I+}
+end;
+{$else HAS_DOS_DRIVES}
+begin
+ DriveValid:=true;
+end;
+{$endif HAS_DOS_DRIVES}
+
+{****************************************************************************}
+{ Equal }
+{****************************************************************************}
+function Equal(const S1, S2: String; Count: Sw_word): Boolean;
+var
+ i: Sw_Word;
+begin
+ Equal := False;
+ if (Length(S1) < Count) or (Length(S2) < Count) then
+ Exit;
+ for i := 1 to Count do
+ if UpCase(S1[I]) <> UpCase(S2[I]) then
+ Exit;
+ Equal := True;
+end;
+
+{****************************************************************************}
+{ ExtractDir }
+{****************************************************************************}
+function ExtractDir(AFile: FNameStr): DirStr;
+ { ExtractDir returns the path of AFile terminated with a trailing '\'. If
+ AFile contains no directory information, an empty string is returned. }
+var
+ D: DirStr;
+ N: NameStr;
+ E: ExtStr;
+begin
+ FSplit(AFile,D,N,E);
+ if D = '' then
+ begin
+ ExtractDir := '';
+ Exit;
+ end;
+ if D[Byte(D[0])] <> DirSeparator then
+ D := D + DirSeparator;
+ ExtractDir := D;
+end;
+
+{****************************************************************************}
+{ ExtractFileName }
+{****************************************************************************}
+function ExtractFileName(AFile: FNameStr): NameStr;
+var
+ D: DirStr;
+ N: NameStr;
+ E: ExtStr;
+begin
+ FSplit(AFile,D,N,E);
+ ExtractFileName := N;
+end;
+
+{****************************************************************************}
+{ FileExists }
+{****************************************************************************}
+function FileExists (AFile : FNameStr) : Boolean;
+begin
+ FileExists := (FSearch(AFile,'') <> '');
+end;
+
+{****************************************************************************}
+{ GetCurDir }
+{****************************************************************************}
+function GetCurDir: DirStr;
+var
+ CurDir: DirStr;
+begin
+ GetDir(0, CurDir);
+ if (Length(CurDir) > 3) then
+ begin
+ Inc(CurDir[0]);
+ CurDir[Length(CurDir)] := DirSeparator;
+ end;
+ GetCurDir := CurDir;
+end;
+
+{****************************************************************************}
+{ GetCurDrive }
+{****************************************************************************}
+function GetCurDrive: Char;
+{$ifdef go32v2}
+var
+ Regs : Registers;
+begin
+ Regs.AH := $19;
+ Intr($21,Regs);
+ GetCurDrive := Char(Regs.AL + Byte('A'));
+end;
+{$else not go32v2}
+var
+ D : DirStr;
+begin
+ D:=GetCurDir;
+ if (Length(D)>1) and (D[2]=':') then
+ begin
+ if (D[1]>='a') and (D[1]<='z') then
+ GetCurDrive:=Char(Byte(D[1])+Byte('A')-Byte('a'))
+ else
+ GetCurDrive:=D[1];
+ end
+ else
+ GetCurDrive:='C';
+end;
+{$endif not go32v2}
+
+{****************************************************************************}
+{ IsDir }
+{****************************************************************************}
+function IsDir(const S: String): Boolean;
+var
+ SR: SearchRec;
+ Is: boolean;
+begin
+ Is:=false;
+{$ifdef Unix}
+ Is:=(S=DirSeparator); { handle root }
+{$else}
+ Is:=(length(S)=3) and (Upcase(S[1]) in['A'..'Z']) and (S[2]=':') and (S[3]=DirSeparator);
+ { handle root dirs }
+{$endif}
+ if Is=false then
+ begin
+ FindFirst(S, Directory, SR);
+ if DosError = 0 then
+ Is := (SR.Attr and Directory) <> 0
+ else
+ Is := False;
+ {$ifdef fpc}
+ FindClose(SR);
+ {$endif}
+ end;
+ IsDir:=Is;
+end;
+
+{****************************************************************************}
+{ IsWild }
+{****************************************************************************}
+function IsWild(const S: String): Boolean;
+begin
+ IsWild := (Pos('?',S) > 0) or (Pos('*',S) > 0);
+end;
+
+{****************************************************************************}
+{ IsList }
+{****************************************************************************}
+function IsList(const S: String): Boolean;
+begin
+ IsList := (Pos(ListSeparator,S) > 0);
+end;
+
+{****************************************************************************}
+{ MakeResources }
+{****************************************************************************}
+(*
+procedure MakeResources;
+var
+ Dlg : PDialog;
+ Key : String;
+ i : Word;
+begin
+ for i := 0 to 1 do
+ begin
+ case i of
+ 0 : begin
+ Key := reOpenDlg;
+ Dlg := New(PFileDialog,Init('*.*',sOpen,slName,
+ fdOkButton or fdHelpButton or fdNoLoadDir,0));
+ end;
+ 1 : begin
+ Key := reSaveAsDlg;
+ Dlg := New(PFileDialog,Init('*.*',sSaveAs,slName,
+ fdOkButton or fdHelpButton or fdNoLoadDir,0));
+ end;
+ 2 : begin
+ Key := reEditChDirDialog;
+ Dlg := New(PEditChDirDialog,Init(cdHelpButton,
+ hiCurrentDirectories));
+ end;
+ end;
+ if Dlg = nil then
+ begin
+ PrintStr('Error initializing dialog ' + Key);
+ Halt;
+ end
+ else begin
+ RezFile^.Put(Dlg,Key);
+ if (RezFile^.Stream^.Status <> stOk) then
+ begin
+ PrintStr('Error writing dialog ' + Key + ' to the resource file.');
+ Halt;
+ end;
+ end;
+ end;
+end;
+*)
+{****************************************************************************}
+{ NoWildChars }
+{****************************************************************************}
+function NoWildChars(S: String): String;
+const
+ WildChars : array[0..1] of Char = ('?','*');
+var
+ i : Sw_Word;
+begin
+ repeat
+ i := Pos('?',S);
+ if (i > 0) then
+ System.Delete(S,i,1);
+ until (i = 0);
+ repeat
+ i := Pos('*',S);
+ if (i > 0) then
+ System.Delete(S,i,1);
+ until (i = 0);
+ NoWildChars:=S;
+end;
+
+{****************************************************************************}
+{ OpenFile }
+{****************************************************************************}
+function OpenFile (var AFile : FNameStr; HistoryID : Byte) : Boolean;
+var
+ Dlg : PFileDialog;
+begin
+ {$ifdef cdResource}
+ Dlg := PFileDialog(RezFile^.Get(reOpenDlg));
+ {$else}
+ Dlg := New(PFileDialog,Init('*.*',sOpen,slName,
+ fdOkButton or fdHelpButton,0));
+ {$endif cdResource}
+ { this might not work }
+ PHistory(Dlg^.FileName^.Next^.Next)^.HistoryID := HistoryID;
+ OpenFile := (Application^.ExecuteDialog(Dlg,@AFile) = cmFileOpen);
+end;
+
+{****************************************************************************}
+{ OpenNewFile }
+{****************************************************************************}
+function OpenNewFile (var AFile: FNameStr; HistoryID: Byte): Boolean;
+ { OpenNewFile allows the user to select a directory from disk and enter a
+ new file name. If the file name entered is an existing file the user is
+ optionally prompted for confirmation of replacing the file based on the
+ value in #CheckOnReplace#. If a file name is successfully entered,
+ OpenNewFile returns True. }
+ {#X OpenFile }
+begin
+ OpenNewFile := False;
+ if OpenFile(AFile,HistoryID) then
+ begin
+ if not ValidFileName(AFile) then
+ Exit;
+ if FileExists(AFile) then
+ if (not CheckOnReplace) or (not ReplaceFile(AFile)) then
+ Exit;
+ OpenNewFile := True;
+ end;
+end;
+
+{****************************************************************************}
+{ RegisterStdDlg }
+{****************************************************************************}
+procedure RegisterStdDlg;
+begin
+ RegisterType(RFileInputLine);
+ RegisterType(RFileCollection);
+ RegisterType(RFileList);
+ RegisterType(RFileInfoPane);
+ RegisterType(RFileDialog);
+ RegisterType(RDirCollection);
+ RegisterType(RDirListBox);
+ RegisterType(RSortedListBox);
+ RegisterType(RChDirDialog);
+end;
+
+{****************************************************************************}
+{ StdReplaceFile }
+{****************************************************************************}
+function StdReplaceFile (AFile : FNameStr) : Boolean;
+var
+ Rec : PStringRec;
+begin
+ if CheckOnReplace then
+ begin
+ AFile := ShrinkPath(AFile,33);
+ Rec.AString := PString(@AFile);
+ StdReplaceFile :=
+ (MessageBox(^C + sReplaceFile,
+ @Rec,mfConfirmation or mfOkCancel) = cmOk);
+ end
+ else StdReplaceFile := True;
+end;
+
+{****************************************************************************}
+{ SaveAs }
+{****************************************************************************}
+function SaveAs (var AFile : FNameStr; HistoryID : Word) : Boolean;
+var
+ Dlg : PFileDialog;
+begin
+ SaveAs := False;
+ Dlg := New(PFileDialog,Init('*.*',sSaveAs,slSaveAs,
+ fdOkButton or fdHelpButton,0));
+ { this might not work }
+ PHistory(Dlg^.FileName^.Next^.Next)^.HistoryID := HistoryID;
+ Dlg^.HelpCtx := hcSaveAs;
+ if (Application^.ExecuteDialog(Dlg,@AFile) = cmFileOpen) and
+ ((not FileExists(AFile)) or ReplaceFile(AFile)) then
+ SaveAs := True;
+end;
+
+{****************************************************************************}
+{ SelectDir }
+{****************************************************************************}
+function SelectDir (var ADir : DirStr; HistoryID : Byte) : Boolean;
+var
+ Dir: DirStr;
+ Dlg : PEditChDirDialog;
+ Rec : DirStr;
+begin
+ {$I-}
+ GetDir(0,Dir);
+ {$I+}
+ Rec := FExpand(ADir);
+ Dlg := New(PEditChDirDialog,Init(cdHelpButton,HistoryID));
+ if (Application^.ExecuteDialog(Dlg,@Rec) = cmOk) then
+ begin
+ SelectDir := True;
+ ADir := Rec;
+ end
+ else SelectDir := False;
+ {$I-}
+ ChDir(Dir);
+ {$I+}
+end;
+
+{****************************************************************************}
+{ ShrinkPath }
+{****************************************************************************}
+function ShrinkPath (AFile : FNameStr; MaxLen : Byte) : FNameStr;
+var
+ Filler: string;
+ D1 : DirStr;
+ N1 : NameStr;
+ E1 : ExtStr;
+ i : Sw_Word;
+
+begin
+ if Length(AFile) > MaxLen then
+ begin
+ FSplit(FExpand(AFile),D1,N1,E1);
+ AFile := Copy(D1,1,3) + '..' + DirSeparator;
+ i := Pred(Length(D1));
+ while (i > 0) and (D1[i] <> DirSeparator) do
+ Dec(i);
+ if (i = 0) then
+ AFile := AFile + D1
+ else AFile := AFile + Copy(D1,Succ(i),Length(D1)-i);
+ if AFile[Length(AFile)] <> DirSeparator then
+ AFile := AFile + DirSeparator;
+ if Length(AFile)+Length(N1)+Length(E1) <= MaxLen then
+ AFile := AFile + N1 + E1
+ else
+ begin
+ Filler := '...' + DirSeparator;
+ AFile:=Copy(Afile,1,MaxLen-Length(Filler)-Length(N1)-Length(E1))
+ +Filler+N1+E1;
+ end;
+ end;
+ ShrinkPath := AFile;
+end;
+
+{****************************************************************************}
+{ ValidFileName }
+{****************************************************************************}
+function ValidFileName(var FileName: PathStr): Boolean;
+var
+ IllegalChars: string[12];
+ Dir: DirStr;
+ Name: NameStr;
+ Ext: ExtStr;
+begin
+{$ifdef PPC_FPC}
+{$ifdef go32v2}
+ { spaces are allowed if LFN is supported }
+ if LFNSupport then
+ IllegalChars := ';,=+<>|"[]'+DirSeparator
+ else
+ IllegalChars := ';,=+<>|"[] '+DirSeparator;
+{$else not go32v2}
+{$ifdef win32}
+ IllegalChars := ';,=+<>|"[]'+DirSeparator;
+{$else not go32v2 and not win32 }
+ IllegalChars := ';,=+<>|"[] '+DirSeparator;
+{$endif not win32}
+{$endif not go32v2}
+{$else not PPC_FPC}
+ IllegalChars := ';,=+<>|"[] '+DirSeparator;
+{$endif PPC_FPC}
+ ValidFileName := True;
+ FSplit(FileName, Dir, Name, Ext);
+ if not ((Dir = '') or PathValid(Dir)) or
+ Contains(Name, IllegalChars) or
+ Contains(Dir, IllegalChars) then
+ ValidFileName := False;
+end;
+
+{****************************************************************************}
+{ Unit Initialization Section }
+{****************************************************************************}
+begin
+{$ifdef PPC_BP}
+ ReplaceFile := StdReplaceFile;
+ DeleteFile := StdDeleteFile;
+{$else}
+ ReplaceFile := @StdReplaceFile;
+ DeleteFile := @StdDeleteFile;
+{$endif PPC_BP}
+end.