stddlg.pas 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733
  1. {*******************************************************}
  2. { Free Vision Runtime Library }
  3. { StdDlg Unit }
  4. { Version: 0.1.0 }
  5. { Release Date: July 23, 1998 }
  6. { }
  7. {*******************************************************}
  8. { }
  9. { This unit is a port of Borland International's }
  10. { StdDlg.pas unit. It is for distribution with the }
  11. { Free Pascal (FPK) Compiler as part of the 32-bit }
  12. { Free Vision library. The unit is still fully }
  13. { functional under BP7 by using the tp compiler }
  14. { directive when rebuilding the library. }
  15. { }
  16. {*******************************************************}
  17. { Revision History
  18. 1.1a (97/12/29)
  19. - fixed bug in TFileDialog.HandleEvent that prevented the user from being
  20. able to have an action taken automatically when the FileList was
  21. selected and kbEnter pressed
  22. 1.1
  23. - modified OpenNewFile to take a history list ID
  24. - implemented OpenNewFile
  25. 1.0 (1992)
  26. - original implementation }
  27. unit StdDlg;
  28. {
  29. This unit has been modified to make some functions global, apply patches
  30. from version 3.1 of the TVBUGS list, added TEditChDirDialog, and added
  31. several new global functions and procedures.
  32. }
  33. {$i platform.inc}
  34. {$ifdef PPC_FPC}
  35. {$H-}
  36. {$else}
  37. {$F+,O+,E+,N+}
  38. {$endif}
  39. {$X+,R-,I-,Q-,V-}
  40. {$ifndef OS_UNIX}
  41. {$S-}
  42. {$endif}
  43. {$ifdef OS_DOS}
  44. {$define HAS_DOS_DRIVES}
  45. {$endif}
  46. {$ifdef OS_WINDOWS}
  47. {$define HAS_DOS_DRIVES}
  48. {$endif}
  49. {$ifdef OS_OS2}
  50. {$define HAS_DOS_DRIVES}
  51. {$endif}
  52. interface
  53. uses
  54. FVConsts, Objects, Drivers, Views, Dialogs, Validate, Dos;
  55. const
  56. MaxDir = 255; { Maximum length of a DirStr. }
  57. MaxFName = 255; { Maximum length of a FNameStr. }
  58. DirSeparator : Char = system.DirectorySeparator;
  59. {$ifdef Unix}
  60. AllFiles = '*';
  61. {$else}
  62. AllFiles = '*.*';
  63. {$endif}
  64. type
  65. { TSearchRec }
  66. { Record used to store directory information by TFileDialog
  67. This is a part of Dos.Searchrec for Bp !! }
  68. TSearchRec =
  69. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  70. packed
  71. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  72. record
  73. Attr: Longint;
  74. Time: Longint;
  75. Size: Longint;
  76. Name: string[MaxFName];
  77. end;
  78. PSearchRec = ^TSearchRec;
  79. type
  80. { TFileInputLine is a special input line that is used by }
  81. { TFileDialog that will update its contents in response to a }
  82. { cmFileFocused command from a TFileList. }
  83. PFileInputLine = ^TFileInputLine;
  84. TFileInputLine = object(TInputLine)
  85. constructor Init(var Bounds: TRect; AMaxLen: Sw_Integer);
  86. procedure HandleEvent(var Event: TEvent); virtual;
  87. end;
  88. { TFileCollection is a collection of TSearchRec's. }
  89. PFileCollection = ^TFileCollection;
  90. TFileCollection = object(TSortedCollection)
  91. function Compare(Key1, Key2: Pointer): Sw_Integer; virtual;
  92. procedure FreeItem(Item: Pointer); virtual;
  93. function GetItem(var S: TStream): Pointer; virtual;
  94. procedure PutItem(var S: TStream; Item: Pointer); virtual;
  95. end;
  96. {#Z+}
  97. PFileValidator = ^TFileValidator;
  98. {#Z-}
  99. TFileValidator = Object(TValidator)
  100. end; { of TFileValidator }
  101. { TSortedListBox is a TListBox that assumes it has a }
  102. { TStoredCollection instead of just a TCollection. It will }
  103. { perform an incremental search on the contents. }
  104. PSortedListBox = ^TSortedListBox;
  105. TSortedListBox = object(TListBox)
  106. SearchPos: Byte;
  107. {ShiftState: Byte;}
  108. HandleDir : boolean;
  109. constructor Init(var Bounds: TRect; ANumCols: Sw_Word;
  110. AScrollBar: PScrollBar);
  111. procedure HandleEvent(var Event: TEvent); virtual;
  112. function GetKey(var S: String): Pointer; virtual;
  113. procedure NewList(AList: PCollection); virtual;
  114. end;
  115. { TFileList is a TSortedList box that assumes it contains }
  116. { a TFileCollection as its collection. It also communicates }
  117. { through broadcast messages to TFileInput and TInfoPane }
  118. { what file is currently selected. }
  119. PFileList = ^TFileList;
  120. TFileList = object(TSortedListBox)
  121. constructor Init(var Bounds: TRect; AScrollBar: PScrollBar);
  122. destructor Done; virtual;
  123. function DataSize: Sw_Word; virtual;
  124. procedure FocusItem(Item: Sw_Integer); virtual;
  125. procedure GetData(var Rec); virtual;
  126. function GetText(Item,MaxLen: Sw_Integer): String; virtual;
  127. function GetKey(var S: String): Pointer; virtual;
  128. procedure HandleEvent(var Event: TEvent); virtual;
  129. procedure ReadDirectory(AWildCard: PathStr);
  130. procedure SetData(var Rec); virtual;
  131. end;
  132. { TFileInfoPane is a TView that displays the information }
  133. { about the currently selected file in the TFileList }
  134. { of a TFileDialog. }
  135. PFileInfoPane = ^TFileInfoPane;
  136. TFileInfoPane = object(TView)
  137. S: TSearchRec;
  138. constructor Init(var Bounds: TRect);
  139. procedure Draw; virtual;
  140. function GetPalette: PPalette; virtual;
  141. procedure HandleEvent(var Event: TEvent); virtual;
  142. end;
  143. { TFileDialog is a standard file name input dialog }
  144. TWildStr = PathStr;
  145. const
  146. fdOkButton = $0001; { Put an OK button in the dialog }
  147. fdOpenButton = $0002; { Put an Open button in the dialog }
  148. fdReplaceButton = $0004; { Put a Replace button in the dialog }
  149. fdClearButton = $0008; { Put a Clear button in the dialog }
  150. fdHelpButton = $0010; { Put a Help button in the dialog }
  151. fdNoLoadDir = $0100; { Do not load the current directory }
  152. { contents into the dialog at Init. }
  153. { This means you intend to change the }
  154. { WildCard by using SetData or store }
  155. { the dialog on a stream. }
  156. type
  157. PFileHistory = ^TFileHistory;
  158. TFileHistory = object(THistory)
  159. CurDir : PString;
  160. procedure HandleEvent(var Event: TEvent);virtual;
  161. destructor Done; virtual;
  162. procedure AdaptHistoryToDir(Dir : string);
  163. end;
  164. PFileDialog = ^TFileDialog;
  165. TFileDialog = object(TDialog)
  166. FileName: PFileInputLine;
  167. FileList: PFileList;
  168. FileHistory: PFileHistory;
  169. WildCard: TWildStr;
  170. Directory: PString;
  171. constructor Init(AWildCard: TWildStr; const ATitle,
  172. InputName: String; AOptions: Word; HistoryId: Byte);
  173. constructor Load(var S: TStream);
  174. destructor Done; virtual;
  175. procedure GetData(var Rec); virtual;
  176. procedure GetFileName(var S: PathStr);
  177. procedure HandleEvent(var Event: TEvent); virtual;
  178. procedure SetData(var Rec); virtual;
  179. procedure Store(var S: TStream);
  180. function Valid(Command: Word): Boolean; virtual;
  181. private
  182. procedure ReadDirectory;
  183. end;
  184. { TDirEntry }
  185. PDirEntry = ^TDirEntry;
  186. TDirEntry = record
  187. DisplayText: PString;
  188. Directory: PString;
  189. end; { of TDirEntry }
  190. { TDirCollection is a collection of TDirEntry's used by }
  191. { TDirListBox. }
  192. PDirCollection = ^TDirCollection;
  193. TDirCollection = object(TCollection)
  194. function GetItem(var S: TStream): Pointer; virtual;
  195. procedure FreeItem(Item: Pointer); virtual;
  196. procedure PutItem(var S: TStream; Item: Pointer); virtual;
  197. end;
  198. { TDirListBox displays a tree of directories for use in the }
  199. { TChDirDialog. }
  200. PDirListBox = ^TDirListBox;
  201. TDirListBox = object(TListBox)
  202. Dir: DirStr;
  203. Cur: Word;
  204. constructor Init(var Bounds: TRect; AScrollBar: PScrollBar);
  205. destructor Done; virtual;
  206. function GetText(Item,MaxLen: Sw_Integer): String; virtual;
  207. procedure HandleEvent(var Event: TEvent); virtual;
  208. function IsSelected(Item: Sw_Integer): Boolean; virtual;
  209. procedure NewDirectory(var ADir: DirStr);
  210. procedure SetState(AState: Word; Enable: Boolean); virtual;
  211. end;
  212. { TChDirDialog is a standard change directory dialog. }
  213. const
  214. cdNormal = $0000; { Option to use dialog immediately }
  215. cdNoLoadDir = $0001; { Option to init the dialog to store on a stream }
  216. cdHelpButton = $0002; { Put a help button in the dialog }
  217. type
  218. PChDirDialog = ^TChDirDialog;
  219. TChDirDialog = object(TDialog)
  220. DirInput: PInputLine;
  221. DirList: PDirListBox;
  222. OkButton: PButton;
  223. ChDirButton: PButton;
  224. constructor Init(AOptions: Word; HistoryId: Sw_Word);
  225. constructor Load(var S: TStream);
  226. function DataSize: Sw_Word; virtual;
  227. procedure GetData(var Rec); virtual;
  228. procedure HandleEvent(var Event: TEvent); virtual;
  229. procedure SetData(var Rec); virtual;
  230. procedure Store(var S: TStream);
  231. function Valid(Command: Word): Boolean; virtual;
  232. private
  233. procedure SetUpDialog;
  234. end;
  235. PEditChDirDialog = ^TEditChDirDialog;
  236. TEditChDirDialog = Object(TChDirDialog)
  237. { TEditChDirDialog allows setting/getting the starting directory. The
  238. transfer record is a DirStr. }
  239. function DataSize : Sw_Word; virtual;
  240. procedure GetData (var Rec); virtual;
  241. procedure SetData (var Rec); virtual;
  242. end; { of TEditChDirDialog }
  243. {#Z+}
  244. PDirValidator = ^TDirValidator;
  245. {#Z-}
  246. TDirValidator = Object(TFilterValidator)
  247. constructor Init;
  248. function IsValid(const S: string): Boolean; virtual;
  249. function IsValidInput(var S: string; SuppressFill: Boolean): Boolean;
  250. virtual;
  251. end; { of TDirValidator }
  252. FileConfirmFunc = function (AFile : FNameStr) : Boolean;
  253. { Functions of type FileConfirmFunc's are used to prompt the end user for
  254. confirmation of an operation.
  255. FileConfirmFunc's should ask the user whether to perform the desired
  256. action on the file named AFile. If the user elects to perform the
  257. function FileConfirmFunc's return True, otherwise they return False.
  258. Using FileConfirmFunc's allows routines to be coded independant of the
  259. user interface implemented. OWL and TurboVision are supported through
  260. conditional defines. If you do not use either user interface you must
  261. compile this unit with the conditional define cdNoMessages and set all
  262. FileConfirmFunc variables to a valid function prior to calling any
  263. routines in this unit. }
  264. {#X ReplaceFile DeleteFile }
  265. var
  266. ReplaceFile : FileConfirmFunc;
  267. { ReplaceFile returns True if the end user elects to replace the existing
  268. file with the new file, otherwise it returns False.
  269. ReplaceFile is only called when #CheckOnReplace# is True. }
  270. {#X DeleteFile }
  271. DeleteFile : FileConfirmFunc;
  272. { DeleteFile returns True if the end user elects to delete the file,
  273. otherwise it returns False.
  274. DeleteFile is only called when #CheckOnDelete# is True. }
  275. {#X ReplaceFile }
  276. const
  277. CInfoPane = #30;
  278. { TStream registration records }
  279. function Contains(S1, S2: String): Boolean;
  280. { Contains returns true if S1 contains any characters in S2. }
  281. function DriveValid(Drive: Char): Boolean;
  282. { DriveValid returns True if Drive is a valid DOS drive. Drive valid works
  283. by attempting to change the current directory to Drive, then restoring
  284. the original directory. }
  285. function ExtractDir(AFile: FNameStr): DirStr;
  286. { ExtractDir returns the path of AFile terminated with a trailing '\'. If
  287. AFile contains no directory information, an empty string is returned. }
  288. function ExtractFileName(AFile: FNameStr): NameStr;
  289. { ExtractFileName returns the file name without any directory or file
  290. extension information. }
  291. function Equal(const S1, S2: String; Count: Sw_word): Boolean;
  292. { Equal returns True if S1 equals S2 for up to Count characters. Equal is
  293. case-insensitive. }
  294. function FileExists (AFile : FNameStr) : Boolean;
  295. { FileExists looks for the file specified in AFile. If AFile is present
  296. FileExists returns true, otherwise FileExists returns False.
  297. The search is performed relative to the current system directory, but
  298. other directories may be searched by prefacing a file name with a valid
  299. directory path.
  300. There is no check for a vaild file name or drive. Errrors are handled
  301. internally and not reported in DosError. Critical errors are left to
  302. the system's critical error handler. }
  303. {#X OpenFile }
  304. function GetCurDir: DirStr;
  305. { GetCurDir returns the current directory. The directory returned always
  306. ends with a trailing backslash '\'. }
  307. function GetCurDrive: Char;
  308. { GetCurDrive returns the letter of the current drive as reported by the
  309. operating system. }
  310. function IsWild(const S: String): Boolean;
  311. { IsWild returns True if S contains a question mark (?) or asterix (*). }
  312. function IsList(const S: String): Boolean;
  313. { IsList returns True if S contains list separator (;) char }
  314. function IsDir(const S: String): Boolean;
  315. { IsDir returns True if S is a valid DOS directory. }
  316. procedure MakeResources;
  317. { MakeResources places a language specific version of all resources
  318. needed for the StdDlg unit to function on the RezFile using the string
  319. constants and variables in the Resource unit. The Resource unit and the
  320. appropriate string lists must be initialized prior to calling this
  321. procedure. }
  322. function NoWildChars(S: String): String;
  323. { NoWildChars deletes the wild card characters ? and * from the string S
  324. and returns the result. }
  325. function OpenFile (var AFile : FNameStr; HistoryID : Byte) : Boolean;
  326. { OpenFile prompts the user to select a file using the file specifications
  327. in AFile as the starting file and path. Wildcards are accepted. If the
  328. user accepts a file OpenFile returns True, otherwise OpenFile returns
  329. False.
  330. Note: The file returned may or may not exist. }
  331. function OpenNewFile (var AFile: FNameStr; HistoryID: Byte): Boolean;
  332. { OpenNewFile allows the user to select a directory from disk and enter a
  333. new file name. If the file name entered is an existing file the user is
  334. optionally prompted for confirmation of replacing the file based on the
  335. value in #CheckOnReplace#. If a file name is successfully entered,
  336. OpenNewFile returns True. }
  337. {#X OpenFile }
  338. function PathValid(var Path: PathStr): Boolean;
  339. { PathValid returns True if Path is a valid DOS path name. Path may be a
  340. file or directory name. Trailing '\'s are removed. }
  341. procedure RegisterStdDlg;
  342. { RegisterStdDlg registers all objects in the StdDlg unit for stream
  343. usage. }
  344. function SaveAs (var AFile : FNameStr; HistoryID : Word) : Boolean;
  345. { SaveAs prompts the user for a file name using AFile as a template. If
  346. AFile already exists and CheckOnReplace is True, the user is prompted
  347. to replace the file.
  348. If a valid file name is entered SaveAs returns True, other SaveAs returns
  349. False. }
  350. function SelectDir (var ADir : DirStr; HistoryID : Byte) : Boolean;
  351. { SelectDir prompts the user to select a directory using ADir as the
  352. starting directory. If a directory is selected, SelectDir returns True.
  353. The directory returned is gauranteed to exist. }
  354. function ShrinkPath (AFile : FNameStr; MaxLen : Byte) : FNameStr;
  355. { ShrinkPath returns a file name with a maximu length of MaxLen.
  356. Internal directories are removed and replaced with elipses as needed to
  357. make the file name fit in MaxLen.
  358. AFile must be a valid path name. }
  359. function StdDeleteFile (AFile : FNameStr) : Boolean;
  360. { StdDeleteFile returns True if the end user elects to delete the file,
  361. otherwise it returns False.
  362. DeleteFile is only called when CheckOnDelete is True. }
  363. function StdReplaceFile (AFile : FNameStr) : Boolean;
  364. { StdReplaceFile returns True if the end user elects to replace the existing
  365. AFile with the new AFile, otherwise it returns False.
  366. ReplaceFile is only called when CheckOnReplace is True. }
  367. function ValidFileName(var FileName: PathStr): Boolean;
  368. { ValidFileName returns True if FileName is a valid DOS file name. }
  369. const
  370. CheckOnReplace : Boolean = True;
  371. { CheckOnReplace is used by file functions. If a file exists, it is
  372. optionally replaced based on the value of CheckOnReplace.
  373. If CheckOnReplace is False the file is replaced without asking the
  374. user. If CheckOnReplace is True, the end user is asked to replace the
  375. file using a call to ReplaceFile.
  376. CheckOnReplace is set to True by default. }
  377. CheckOnDelete : Boolean = True;
  378. { CheckOnDelete is used by file and directory functions. If a file
  379. exists, it is optionally deleted based on the value of CheckOnDelete.
  380. If CheckOnDelete is False the file or directory is deleted without
  381. asking the user. If CheckOnDelete is True, the end user is asked to
  382. delete the file/directory using a call to DeleteFile.
  383. CheckOnDelete is set to True by default. }
  384. const
  385. RFileInputLine: TStreamRec = (
  386. ObjType: idFileInputLine;
  387. VmtLink: Ofs(TypeOf(TFileInputLine)^);
  388. Load: @TFileInputLine.Load;
  389. Store: @TFileInputLine.Store
  390. );
  391. RFileCollection: TStreamRec = (
  392. ObjType: idFileCollection;
  393. VmtLink: Ofs(TypeOf(TFileCollection)^);
  394. Load: @TFileCollection.Load;
  395. Store: @TFileCollection.Store
  396. );
  397. RFileList: TStreamRec = (
  398. ObjType: idFileList;
  399. VmtLink: Ofs(TypeOf(TFileList)^);
  400. Load: @TFileList.Load;
  401. Store: @TFileList.Store
  402. );
  403. RFileInfoPane: TStreamRec = (
  404. ObjType: idFileInfoPane;
  405. VmtLink: Ofs(TypeOf(TFileInfoPane)^);
  406. Load: @TFileInfoPane.Load;
  407. Store: @TFileInfoPane.Store
  408. );
  409. RFileDialog: TStreamRec = (
  410. ObjType: idFileDialog;
  411. VmtLink: Ofs(TypeOf(TFileDialog)^);
  412. Load: @TFileDialog.Load;
  413. Store: @TFileDialog.Store
  414. );
  415. RDirCollection: TStreamRec = (
  416. ObjType: idDirCollection;
  417. VmtLink: Ofs(TypeOf(TDirCollection)^);
  418. Load: @TDirCollection.Load;
  419. Store: @TDirCollection.Store
  420. );
  421. RDirListBox: TStreamRec = (
  422. ObjType: idDirListBox;
  423. VmtLink: Ofs(TypeOf(TDirListBox)^);
  424. Load: @TDirListBox.Load;
  425. Store: @TDirListBox.Store
  426. );
  427. RChDirDialog: TStreamRec = (
  428. ObjType: idChDirDialog;
  429. VmtLink: Ofs(TypeOf(TChDirDialog)^);
  430. Load: @TChDirDialog.Load;
  431. Store: @TChDirDialog.Store
  432. );
  433. RSortedListBox: TStreamRec = (
  434. ObjType: idSortedListBox;
  435. VmtLink: Ofs(TypeOf(TSortedListBox)^);
  436. Load: @TSortedListBox.Load;
  437. Store: @TSortedListBox.Store
  438. );
  439. REditChDirDialog : TStreamRec = (
  440. ObjType : idEditChDirDialog;
  441. VmtLink : Ofs(TypeOf(TEditChDirDialog)^);
  442. Load : @TEditChDirDialog.Load;
  443. Store : @TEditChDirDialog.Store);
  444. implementation
  445. {****************************************************************************}
  446. { Local Declarations }
  447. {****************************************************************************}
  448. uses
  449. App, {Memory,} HistList, MsgBox, Resource;
  450. type
  451. PStringRec = record
  452. { PStringRec is needed for properly displaying PStrings using
  453. MessageBox. }
  454. AString : PString;
  455. end;
  456. {****************************************************************************}
  457. { PathValid }
  458. {****************************************************************************}
  459. {$ifdef go32v2}
  460. {$define NetDrive}
  461. {$endif go32v2}
  462. {$ifdef win32}
  463. {$define NetDrive}
  464. {$endif win32}
  465. procedure RemoveDoubleDirSep(var ExpPath : PathStr);
  466. var
  467. p: longint;
  468. {$ifdef NetDrive}
  469. OneDirSepRemoved: boolean;
  470. {$endif NetDrive}
  471. begin
  472. p:=pos(DirSeparator+DirSeparator,ExpPath);
  473. {$ifdef NetDrive}
  474. if p=1 then
  475. begin
  476. ExpPath:=Copy(ExpPath,1,high(ExpPath));
  477. OneDirSepRemoved:=true;
  478. p:=pos(DirSeparator+DirSeparator,ExpPath);
  479. end
  480. else
  481. OneDirSepRemoved:=false;
  482. {$endif NetDrive}
  483. while p>0 do
  484. begin
  485. ExpPath:=Copy(ExpPath,1,p)+Copy(ExpPath,p+2,high(ExpPath));
  486. p:=pos(DirSeparator+DirSeparator,ExpPath);
  487. end;
  488. {$ifdef NetDrive}
  489. if OneDirSepRemoved then
  490. ExpPath:=DirSeparator+ExpPath;
  491. {$endif NetDrive}
  492. end;
  493. function PathValid (var Path: PathStr): Boolean;
  494. var
  495. ExpPath: PathStr;
  496. SR: SearchRec;
  497. begin
  498. RemoveDoubleDirSep(Path);
  499. ExpPath := FExpand(Path);
  500. {$ifdef HAS_DOS_DRIVES}
  501. if (Length(ExpPath) <= 3) then
  502. PathValid := DriveValid(ExpPath[1])
  503. else
  504. {$endif}
  505. begin
  506. { do not change '/' into '' }
  507. if (Length(ExpPath)>1) and (ExpPath[Length(ExpPath)] = DirSeparator) then
  508. Dec(ExpPath[0]);
  509. FindFirst(ExpPath, Directory, SR);
  510. PathValid := (DosError = 0) and (SR.Attr and Directory <> 0);
  511. {$ifdef NetDrive}
  512. if (DosError<>0) and (length(ExpPath)>2) and
  513. (ExpPath[1]='\') and (ExpPath[2]='\')then
  514. begin
  515. { Checking '\\machine\sharedfolder' directly always fails..
  516. rather try '\\machine\sharedfolder\*' PM }
  517. {$ifdef fpc}
  518. FindClose(SR);
  519. {$endif}
  520. FindFirst(ExpPath+'\*',AnyFile,SR);
  521. PathValid:=(DosError = 0);
  522. end;
  523. {$endif NetDrive}
  524. {$ifdef fpc}
  525. FindClose(SR);
  526. {$endif}
  527. end;
  528. end;
  529. {****************************************************************************}
  530. { TDirValidator Object }
  531. {****************************************************************************}
  532. {****************************************************************************}
  533. { TDirValidator.Init }
  534. {****************************************************************************}
  535. constructor TDirValidator.Init;
  536. const { What should this list be? The commented one doesn't allow home,
  537. end, right arrow, left arrow, Ctrl+XXXX, etc. }
  538. Chars: TCharSet = ['A'..'Z','a'..'z','.','~',':','_','-'];
  539. { Chars: TCharSet = [#0..#255]; }
  540. begin
  541. Chars := Chars + [DirSeparator];
  542. if not inherited Init(Chars) then
  543. Fail;
  544. end;
  545. {****************************************************************************}
  546. { TDirValidator.IsValid }
  547. {****************************************************************************}
  548. function TDirValidator.IsValid(const S: string): Boolean;
  549. begin
  550. { IsValid := False; }
  551. IsValid := True;
  552. end;
  553. {****************************************************************************}
  554. { TDirValidator.IsValidInput }
  555. {****************************************************************************}
  556. function TDirValidator.IsValidInput(var S: string; SuppressFill: Boolean): Boolean;
  557. begin
  558. { IsValid := False; }
  559. IsValidInput := True;
  560. end;
  561. {****************************************************************************}
  562. { TFileInputLine Object }
  563. {****************************************************************************}
  564. {****************************************************************************}
  565. { TFileInputLine.Init }
  566. {****************************************************************************}
  567. constructor TFileInputLine.Init(var Bounds: TRect; AMaxLen: Sw_Integer);
  568. begin
  569. TInputLine.Init(Bounds, AMaxLen);
  570. EventMask := EventMask or evBroadcast;
  571. end;
  572. {****************************************************************************}
  573. { TFileInputLine.HandleEvent }
  574. {****************************************************************************}
  575. procedure TFileInputLine.HandleEvent(var Event: TEvent);
  576. begin
  577. TInputLine.HandleEvent(Event);
  578. if (Event.What = evBroadcast) and (Event.Command = cmFileFocused) and
  579. (State and sfSelected = 0) then
  580. begin
  581. if PSearchRec(Event.InfoPtr)^.Attr and Directory <> 0 then
  582. begin
  583. Data^ := PSearchRec(Event.InfoPtr)^.Name + DirSeparator +
  584. PFileDialog(Owner)^.WildCard;
  585. { PFileDialog(Owner)^.FileHistory^.AdaptHistoryToDir(
  586. PSearchRec(Event.InfoPtr)^.Name+DirSeparator);}
  587. end
  588. else Data^ := PSearchRec(Event.InfoPtr)^.Name;
  589. DrawView;
  590. end;
  591. end;
  592. {****************************************************************************}
  593. { TFileCollection Object }
  594. {****************************************************************************}
  595. {****************************************************************************}
  596. { TFileCollection.Compare }
  597. {****************************************************************************}
  598. function uppername(const s : string) : string;
  599. var
  600. i : Sw_integer;
  601. in_name : boolean;
  602. begin
  603. in_name:=true;
  604. for i:=length(s) downto 1 do
  605. if in_name and (s[i] in ['a'..'z']) then
  606. uppername[i]:=char(byte(s[i])-32)
  607. else
  608. begin
  609. uppername[i]:=s[i];
  610. if s[i] = DirSeparator then
  611. in_name:=false;
  612. end;
  613. uppername[0]:=s[0];
  614. end;
  615. function TFileCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
  616. begin
  617. if PSearchRec(Key1)^.Name = PSearchRec(Key2)^.Name then Compare := 0
  618. else if PSearchRec(Key1)^.Name = '..' then Compare := 1
  619. else if PSearchRec(Key2)^.Name = '..' then Compare := -1
  620. else if (PSearchRec(Key1)^.Attr and Directory <> 0) and
  621. (PSearchRec(Key2)^.Attr and Directory = 0) then Compare := 1
  622. else if (PSearchRec(Key2)^.Attr and Directory <> 0) and
  623. (PSearchRec(Key1)^.Attr and Directory = 0) then Compare := -1
  624. else if UpperName(PSearchRec(Key1)^.Name) > UpperName(PSearchRec(Key2)^.Name) then
  625. Compare := 1
  626. {$ifdef unix}
  627. else if UpperName(PSearchRec(Key1)^.Name) < UpperName(PSearchRec(Key2)^.Name) then
  628. Compare := -1
  629. else if PSearchRec(Key1)^.Name > PSearchRec(Key2)^.Name then
  630. Compare := 1
  631. {$endif def unix}
  632. else
  633. Compare := -1;
  634. end;
  635. {****************************************************************************}
  636. { TFileCollection.FreeItem }
  637. {****************************************************************************}
  638. procedure TFileCollection.FreeItem(Item: Pointer);
  639. begin
  640. Dispose(PSearchRec(Item));
  641. end;
  642. {****************************************************************************}
  643. { TFileCollection.GetItem }
  644. {****************************************************************************}
  645. function TFileCollection.GetItem(var S: TStream): Pointer;
  646. var
  647. Item: PSearchRec;
  648. begin
  649. New(Item);
  650. S.Read(Item^, SizeOf(TSearchRec));
  651. GetItem := Item;
  652. end;
  653. {****************************************************************************}
  654. { TFileCollection.PutItem }
  655. {****************************************************************************}
  656. procedure TFileCollection.PutItem(var S: TStream; Item: Pointer);
  657. begin
  658. S.Write(Item^, SizeOf(TSearchRec));
  659. end;
  660. {*****************************************************************************
  661. TFileList
  662. *****************************************************************************}
  663. const
  664. ListSeparator=';';
  665. function MatchesMask(What, Mask: string): boolean;
  666. function upper(const s : string) : string;
  667. var
  668. i : Sw_integer;
  669. begin
  670. for i:=1 to length(s) do
  671. if s[i] in ['a'..'z'] then
  672. upper[i]:=char(byte(s[i])-32)
  673. else
  674. upper[i]:=s[i];
  675. upper[0]:=s[0];
  676. end;
  677. Function CmpStr(const hstr1,hstr2:string):boolean;
  678. var
  679. found : boolean;
  680. i1,i2 : Sw_integer;
  681. begin
  682. i1:=0;
  683. i2:=0;
  684. if hstr1='' then
  685. begin
  686. CmpStr:=(hstr2='');
  687. exit;
  688. end;
  689. found:=true;
  690. repeat
  691. inc(i1);
  692. if (i1>length(hstr1)) then
  693. break;
  694. inc(i2);
  695. if (i2>length(hstr2)) then
  696. break;
  697. case hstr1[i1] of
  698. '?' :
  699. found:=true;
  700. '*' :
  701. begin
  702. found:=true;
  703. if (i1=length(hstr1)) then
  704. i2:=length(hstr2)
  705. else
  706. if (i1<length(hstr1)) and (hstr1[i1+1]<>hstr2[i2]) then
  707. begin
  708. if i2<length(hstr2) then
  709. dec(i1)
  710. end
  711. else
  712. if i2>1 then
  713. dec(i2);
  714. end;
  715. else
  716. found:=(hstr1[i1]=hstr2[i2]) or (hstr2[i2]='?');
  717. end;
  718. until not found;
  719. if found then
  720. begin
  721. found:=(i2>=length(hstr2)) and
  722. (
  723. (i1>length(hstr1)) or
  724. ((i1=length(hstr1)) and
  725. (hstr1[i1]='*'))
  726. );
  727. end;
  728. CmpStr:=found;
  729. end;
  730. var
  731. D1,D2 : DirStr;
  732. N1,N2 : NameStr;
  733. E1,E2 : Extstr;
  734. begin
  735. {$ifdef Unix}
  736. FSplit(What,D1,N1,E1);
  737. FSplit(Mask,D2,N2,E2);
  738. {$else}
  739. FSplit(Upper(What),D1,N1,E1);
  740. FSplit(Upper(Mask),D2,N2,E2);
  741. {$endif}
  742. MatchesMask:=CmpStr(N2,N1) and CmpStr(E2,E1);
  743. end;
  744. function MatchesMaskList(What, MaskList: string): boolean;
  745. var P: integer;
  746. Match: boolean;
  747. begin
  748. Match:=false;
  749. if What<>'' then
  750. repeat
  751. P:=Pos(ListSeparator, MaskList);
  752. if P=0 then P:=length(MaskList)+1;
  753. Match:=MatchesMask(What,copy(MaskList,1,P-1));
  754. Delete(MaskList,1,P);
  755. until Match or (MaskList='');
  756. MatchesMaskList:=Match;
  757. end;
  758. constructor TFileList.Init(var Bounds: TRect; AScrollBar: PScrollBar);
  759. begin
  760. TSortedListBox.Init(Bounds, 2, AScrollBar);
  761. end;
  762. destructor TFileList.Done;
  763. begin
  764. if List <> nil then Dispose(List, Done);
  765. TListBox.Done;
  766. end;
  767. function TFileList.DataSize: Sw_Word;
  768. begin
  769. DataSize := 0;
  770. end;
  771. procedure TFileList.FocusItem(Item: Sw_Integer);
  772. begin
  773. TSortedListBox.FocusItem(Item);
  774. if (List^.Count > 0) then
  775. Message(Owner, evBroadcast, cmFileFocused, List^.At(Item));
  776. end;
  777. procedure TFileList.GetData(var Rec);
  778. begin
  779. end;
  780. function TFileList.GetKey(var S: String): Pointer;
  781. const
  782. SR: TSearchRec = ();
  783. procedure UpStr(var S: String);
  784. var
  785. I: Sw_Integer;
  786. begin
  787. for I := 1 to Length(S) do S[I] := UpCase(S[I]);
  788. end;
  789. begin
  790. if (HandleDir{ShiftState and $03 <> 0}) or ((S <> '') and (S[1]='.')) then
  791. SR.Attr := Directory
  792. else SR.Attr := 0;
  793. SR.Name := S;
  794. {$ifndef Unix}
  795. UpStr(SR.Name);
  796. {$endif Unix}
  797. GetKey := @SR;
  798. end;
  799. function TFileList.GetText(Item,MaxLen: Sw_Integer): String;
  800. var
  801. S: String;
  802. SR: PSearchRec;
  803. begin
  804. SR := PSearchRec(List^.At(Item));
  805. S := SR^.Name;
  806. if SR^.Attr and Directory <> 0 then
  807. begin
  808. S[Length(S)+1] := DirSeparator;
  809. Inc(S[0]);
  810. end;
  811. GetText := S;
  812. end;
  813. procedure TFileList.HandleEvent(var Event: TEvent);
  814. var
  815. S : String;
  816. K : pointer;
  817. Value : Sw_integer;
  818. begin
  819. if (Event.What = evMouseDown) and (Event.Double) then
  820. begin
  821. Event.What := evCommand;
  822. Event.Command := cmOK;
  823. PutEvent(Event);
  824. ClearEvent(Event);
  825. end
  826. else if (Event.What = evKeyDown) and (Event.CharCode='<') then
  827. begin
  828. { select '..' }
  829. S := '..';
  830. K := GetKey(S);
  831. If PSortedCollection(List)^.Search(K, Value) then
  832. FocusItem(Value);
  833. end
  834. else TSortedListBox.HandleEvent(Event);
  835. end;
  836. procedure TFileList.ReadDirectory(AWildCard: PathStr);
  837. const
  838. FindAttr = ReadOnly + Archive;
  839. PrevDir = '..';
  840. var
  841. S: SearchRec;
  842. P: PSearchRec;
  843. FileList: PFileCollection;
  844. NumFiles: Word;
  845. FindStr,
  846. WildName : string;
  847. Dir: DirStr;
  848. Ext: ExtStr;
  849. Name: NameStr;
  850. Event : TEvent;
  851. Tmp: PathStr;
  852. begin
  853. NumFiles := 0;
  854. FileList := New(PFileCollection, Init(5, 5));
  855. AWildCard := FExpand(AWildCard);
  856. FSplit(AWildCard, Dir, Name, Ext);
  857. if pos(ListSeparator,AWildCard)>0 then
  858. begin
  859. WildName:=Copy(AWildCard,length(Dir)+1,255);
  860. FindStr:=Dir+AllFiles;
  861. end
  862. else
  863. begin
  864. WildName:=Name+Ext;
  865. FindStr:=AWildCard;
  866. end;
  867. FindFirst(FindStr, FindAttr, S);
  868. P := PSearchRec(@P);
  869. while assigned(P) and (DosError = 0) do
  870. begin
  871. if (S.Attr and Directory = 0) and
  872. MatchesMaskList(S.Name,WildName) then
  873. begin
  874. { P := MemAlloc(SizeOf(P^));
  875. if assigned(P) then
  876. begin}
  877. new(P);
  878. P^.Attr:=S.Attr;
  879. P^.Time:=S.Time;
  880. P^.Size:=S.Size;
  881. P^.Name:=S.Name;
  882. FileList^.Insert(P);
  883. { end;}
  884. end;
  885. FindNext(S);
  886. end;
  887. {$ifdef fpc}
  888. FindClose(S);
  889. {$endif}
  890. Tmp := Dir + AllFiles;
  891. FindFirst(Tmp, Directory, S);
  892. while (P <> nil) and (DosError = 0) do
  893. begin
  894. if (S.Attr and Directory <> 0) and (S.Name <> '.') and (S.Name <> '..') then
  895. begin
  896. { P := MemAlloc(SizeOf(P^));
  897. if P <> nil then
  898. begin}
  899. new(p);
  900. P^.Attr:=S.Attr;
  901. P^.Time:=S.Time;
  902. P^.Size:=S.Size;
  903. P^.Name:=S.Name;
  904. FileList^.Insert(P);
  905. { end;}
  906. end;
  907. FindNext(S);
  908. end;
  909. {$ifdef fpc}
  910. FindClose(S);
  911. {$endif}
  912. {$ifndef Unix}
  913. if Length(Dir) > 4 then
  914. {$endif not Unix}
  915. begin
  916. {
  917. P := MemAlloc(SizeOf(P^));
  918. if P <> nil then
  919. begin}
  920. new(p);
  921. FindFirst(Tmp, Directory, S);
  922. FindNext(S);
  923. if (DosError = 0) and (S.Name = PrevDir) then
  924. begin
  925. P^.Attr:=S.Attr;
  926. P^.Time:=S.Time;
  927. P^.Size:=S.Size;
  928. P^.Name:=S.Name;
  929. end
  930. else
  931. begin
  932. P^.Name := PrevDir;
  933. P^.Size := 0;
  934. P^.Time := $210000;
  935. P^.Attr := Directory;
  936. end;
  937. FileList^.Insert(PSearchRec(P));
  938. {$ifdef fpc}
  939. FindClose(S);
  940. {$endif}
  941. { end;}
  942. end;
  943. if P = nil then
  944. MessageBox(strings^.get(sTooManyFiles), nil, mfOkButton + mfWarning);
  945. NewList(FileList);
  946. if List^.Count > 0 then
  947. begin
  948. Event.What := evBroadcast;
  949. Event.Command := cmFileFocused;
  950. Event.InfoPtr := List^.At(0);
  951. Owner^.HandleEvent(Event);
  952. end;
  953. end;
  954. procedure TFileList.SetData(var Rec);
  955. begin
  956. with PFileDialog(Owner)^ do
  957. Self.ReadDirectory(Directory^ + WildCard);
  958. end;
  959. {****************************************************************************}
  960. { TFileInfoPane Object }
  961. {****************************************************************************}
  962. {****************************************************************************}
  963. { TFileInfoPane.Init }
  964. {****************************************************************************}
  965. constructor TFileInfoPane.Init(var Bounds: TRect);
  966. begin
  967. TView.Init(Bounds);
  968. FillChar(S,SizeOf(S),#0);
  969. EventMask := EventMask or evBroadcast;
  970. end;
  971. {****************************************************************************}
  972. { TFileInfoPane.Draw }
  973. {****************************************************************************}
  974. procedure TFileInfoPane.Draw;
  975. var
  976. B: TDrawBuffer;
  977. D: String[9];
  978. M: String[3];
  979. PM: Boolean;
  980. Color: Word;
  981. Time: DateTime;
  982. Path: PathStr;
  983. FmtId: String;
  984. Params: array[0..7] of PtrInt;
  985. Str: String[80];
  986. const
  987. sDirectoryLine = ' %-12s %-9s %3s %2d, %4d %2d:%02d%cm';
  988. sFileLine = ' %-12s %-9d %3s %2d, %4d %2d:%02d%cm';
  989. InValidFiles : array[0..2] of string[12] = ('','.','..');
  990. var
  991. Month: array[1..12] of String[3];
  992. begin
  993. Month[1] := Strings^.Get(smJan);
  994. Month[2] := Strings^.Get(smFeb);
  995. Month[3] := Strings^.Get(smMar);
  996. Month[4] := Strings^.Get(smApr);
  997. Month[5] := Strings^.Get(smMay);
  998. Month[6] := Strings^.Get(smJun);
  999. Month[7] := Strings^.Get(smJul);
  1000. Month[8] := Strings^.Get(smAug);
  1001. Month[9] := Strings^.Get(smSep);
  1002. Month[10] := Strings^.Get(smOct);
  1003. Month[11] := Strings^.Get(smNov);
  1004. Month[12] := Strings^.Get(smDec);
  1005. { Display path }
  1006. if (PFileDialog(Owner)^.Directory <> nil) then
  1007. Path := PFileDialog(Owner)^.Directory^
  1008. else Path := '';
  1009. Path := FExpand(Path+PFileDialog(Owner)^.WildCard);
  1010. { avoid B Buffer overflow PM }
  1011. Path := ShrinkPath(Path, Size.X - 1);
  1012. Color := GetColor($01);
  1013. MoveChar(B, ' ', Color, Size.X); { fill with empty spaces }
  1014. WriteLine(0, 0, Size.X, Size.Y, B);
  1015. MoveStr(B[1], Path, Color);
  1016. WriteLine(0, 0, Size.X, 1, B);
  1017. if (S.Name = InValidFiles[0]) or (S.Name = InValidFiles[1]) or
  1018. (S.Name = InValidFiles[2]) then
  1019. Exit;
  1020. { Display file }
  1021. Params[0] := PtrInt(@S.Name);
  1022. if S.Attr and Directory <> 0 then
  1023. begin
  1024. FmtId := sDirectoryLine;
  1025. D := Strings^.Get(sDirectory);
  1026. Params[1] := PtrInt(@D);
  1027. end else
  1028. begin
  1029. FmtId := sFileLine;
  1030. Params[1] := S.Size;
  1031. end;
  1032. UnpackTime(S.Time, Time);
  1033. M := Month[Time.Month];
  1034. Params[2] := PtrInt(@M);
  1035. Params[3] := Time.Day;
  1036. Params[4] := Time.Year;
  1037. PM := Time.Hour >= 12;
  1038. Time.Hour := Time.Hour mod 12;
  1039. if Time.Hour = 0 then Time.Hour := 12;
  1040. Params[5] := Time.Hour;
  1041. Params[6] := Time.Min;
  1042. if PM then
  1043. Params[7] := Byte('p')
  1044. else Params[7] := Byte('a');
  1045. FormatStr(Str, FmtId, Params);
  1046. MoveStr(B, Str, Color);
  1047. WriteLine(0, 1, Size.X, 1, B);
  1048. { Fill in rest of rectangle }
  1049. MoveChar(B, ' ', Color, Size.X);
  1050. WriteLine(0, 2, Size.X, Size.Y-2, B);
  1051. end;
  1052. function TFileInfoPane.GetPalette: PPalette;
  1053. const
  1054. P: String[Length(CInfoPane)] = CInfoPane;
  1055. begin
  1056. GetPalette := PPalette(@P);
  1057. end;
  1058. procedure TFileInfoPane.HandleEvent(var Event: TEvent);
  1059. begin
  1060. TView.HandleEvent(Event);
  1061. if (Event.What = evBroadcast) and (Event.Command = cmFileFocused) then
  1062. begin
  1063. S := PSearchRec(Event.InfoPtr)^;
  1064. DrawView;
  1065. end;
  1066. end;
  1067. {****************************************************************************
  1068. TFileHistory
  1069. ****************************************************************************}
  1070. function LTrim(const S: String): String;
  1071. var
  1072. I: Sw_Integer;
  1073. begin
  1074. I := 1;
  1075. while (I < Length(S)) and (S[I] = ' ') do Inc(I);
  1076. LTrim := Copy(S, I, 255);
  1077. end;
  1078. function RTrim(const S: String): String;
  1079. var
  1080. I: Sw_Integer;
  1081. begin
  1082. I := Length(S);
  1083. while S[I] = ' ' do Dec(I);
  1084. RTrim := Copy(S, 1, I);
  1085. end;
  1086. function RelativePath(var S: PathStr): Boolean;
  1087. begin
  1088. S := LTrim(RTrim(S));
  1089. RelativePath := not ((S <> '') and ((S[1] = DirSeparator) or (S[2] = ':')));
  1090. end;
  1091. { try to reduce the length of S+dir as a file path+pattern }
  1092. function Simplify (var S,Dir : string) : string;
  1093. var i : sw_integer;
  1094. begin
  1095. if RelativePath(Dir) then
  1096. begin
  1097. if (S<>'') and (Copy(Dir,1,3)='..'+DirSeparator) then
  1098. begin
  1099. i:=Length(S);
  1100. for i:=Length(S)-1 downto 1 do
  1101. if S[i]=DirSeparator then
  1102. break;
  1103. if S[i]=DirSeparator then
  1104. Simplify:=Copy(S,1,i)+Copy(Dir,4,255)
  1105. else
  1106. Simplify:=S+Dir;
  1107. end
  1108. else
  1109. Simplify:=S+Dir;
  1110. end
  1111. else
  1112. Simplify:=Dir;
  1113. end;
  1114. {****************************************************************************}
  1115. { TFileHistory.HandleEvent }
  1116. {****************************************************************************}
  1117. procedure TFileHistory.HandleEvent(var Event: TEvent);
  1118. var
  1119. HistoryWindow: PHistoryWindow;
  1120. R,P: TRect;
  1121. C: Word;
  1122. Rslt: String;
  1123. begin
  1124. TView.HandleEvent(Event);
  1125. if (Event.What = evMouseDown) or
  1126. ((Event.What = evKeyDown) and (CtrlToArrow(Event.KeyCode) = kbDown) and
  1127. (Link^.State and sfFocused <> 0)) then
  1128. begin
  1129. if not Link^.Focus then
  1130. begin
  1131. ClearEvent(Event);
  1132. Exit;
  1133. end;
  1134. if assigned(CurDir) then
  1135. Rslt:=CurDir^
  1136. else
  1137. Rslt:='';
  1138. Rslt:=Simplify(Rslt,Link^.Data^);
  1139. RemoveDoubleDirSep(Rslt);
  1140. If IsWild(Rslt) then
  1141. RecordHistory(Rslt);
  1142. Link^.GetBounds(R);
  1143. Dec(R.A.X); Inc(R.B.X); Inc(R.B.Y,7); Dec(R.A.Y,1);
  1144. Owner^.GetExtent(P);
  1145. R.Intersect(P);
  1146. Dec(R.B.Y,1);
  1147. HistoryWindow := InitHistoryWindow(R);
  1148. if HistoryWindow <> nil then
  1149. begin
  1150. C := Owner^.ExecView(HistoryWindow);
  1151. if C = cmOk then
  1152. begin
  1153. Rslt := HistoryWindow^.GetSelection;
  1154. if Length(Rslt) > Link^.MaxLen then Rslt[0] := Char(Link^.MaxLen);
  1155. Link^.Data^ := Rslt;
  1156. Link^.SelectAll(True);
  1157. Link^.DrawView;
  1158. end;
  1159. Dispose(HistoryWindow, Done);
  1160. end;
  1161. ClearEvent(Event);
  1162. end
  1163. else if (Event.What = evBroadcast) then
  1164. if ((Event.Command = cmReleasedFocus) and (Event.InfoPtr = Link))
  1165. or (Event.Command = cmRecordHistory) then
  1166. begin
  1167. if assigned(CurDir) then
  1168. Rslt:=CurDir^
  1169. else
  1170. Rslt:='';
  1171. Rslt:=Simplify(Rslt,Link^.Data^);
  1172. RemoveDoubleDirSep(Rslt);
  1173. If IsWild(Rslt) then
  1174. RecordHistory(Rslt);
  1175. end;
  1176. end;
  1177. procedure TFileHistory.AdaptHistoryToDir(Dir : string);
  1178. var S,S2 : String;
  1179. i,Count : Sw_word;
  1180. begin
  1181. if assigned(CurDir) then
  1182. begin
  1183. S:=CurDir^;
  1184. if S=Dir then
  1185. exit;
  1186. DisposeStr(CurDir);
  1187. end
  1188. else
  1189. S:='';
  1190. CurDir:=NewStr(Simplify(S,Dir));
  1191. Count:=HistoryCount(HistoryId);
  1192. for i:=1 to count do
  1193. begin
  1194. S2:=HistoryStr(HistoryId,1);
  1195. HistoryRemove(HistoryId,1);
  1196. if RelativePath(S2) then
  1197. if S<>'' then
  1198. S2:=S+S2
  1199. else
  1200. S2:=FExpand(S2);
  1201. { simply full path
  1202. we should simplify relative to Dir ! }
  1203. HistoryAdd(HistoryId,S2);
  1204. end;
  1205. end;
  1206. destructor TFileHistory.Done;
  1207. begin
  1208. If assigned(CurDir) then
  1209. DisposeStr(CurDir);
  1210. Inherited Done;
  1211. end;
  1212. {****************************************************************************
  1213. TFileDialog
  1214. ****************************************************************************}
  1215. constructor TFileDialog.Init(AWildCard: TWildStr; const ATitle,
  1216. InputName: String; AOptions: Word; HistoryId: Byte);
  1217. var
  1218. Control: PView;
  1219. R: TRect;
  1220. Opt: Word;
  1221. begin
  1222. R.Assign(15,1,64,20);
  1223. TDialog.Init(R, ATitle);
  1224. Options := Options or ofCentered;
  1225. WildCard := AWildCard;
  1226. R.Assign(3,3,31,4);
  1227. FileName := New(PFileInputLine, Init(R, 79));
  1228. FileName^.Data^ := WildCard;
  1229. Insert(FileName);
  1230. R.Assign(2,2,3+CStrLen(InputName),3);
  1231. Control := New(PLabel, Init(R, InputName, FileName));
  1232. Insert(Control);
  1233. R.Assign(31,3,34,4);
  1234. FileHistory := New(PFileHistory, Init(R, FileName, HistoryId));
  1235. Insert(FileHistory);
  1236. R.Assign(3,14,34,15);
  1237. Control := New(PScrollBar, Init(R));
  1238. Insert(Control);
  1239. R.Assign(3,6,34,14);
  1240. FileList := New(PFileList, Init(R, PScrollBar(Control)));
  1241. Insert(FileList);
  1242. R.Assign(2,5,8,6);
  1243. Control := New(PLabel, Init(R, labels^.get(slFiles), FileList));
  1244. Insert(Control);
  1245. R.Assign(35,3,46,5);
  1246. Opt := bfDefault;
  1247. if AOptions and fdOpenButton <> 0 then
  1248. begin
  1249. Insert(New(PButton, Init(R,labels^.get(slOpen), cmFileOpen, Opt)));
  1250. Opt := bfNormal;
  1251. Inc(R.A.Y,3); Inc(R.B.Y,3);
  1252. end;
  1253. if AOptions and fdOkButton <> 0 then
  1254. begin
  1255. Insert(New(PButton, Init(R,labels^.get(slOk), cmFileOpen, Opt)));
  1256. Opt := bfNormal;
  1257. Inc(R.A.Y,3); Inc(R.B.Y,3);
  1258. end;
  1259. if AOptions and fdReplaceButton <> 0 then
  1260. begin
  1261. Insert(New(PButton, Init(R, labels^.get(slReplace),cmFileReplace, Opt)));
  1262. Opt := bfNormal;
  1263. Inc(R.A.Y,3); Inc(R.B.Y,3);
  1264. end;
  1265. if AOptions and fdClearButton <> 0 then
  1266. begin
  1267. Insert(New(PButton, Init(R, labels^.get(slClear),cmFileClear, Opt)));
  1268. Opt := bfNormal;
  1269. Inc(R.A.Y,3); Inc(R.B.Y,3);
  1270. end;
  1271. Insert(New(PButton, Init(R, labels^.get(slCancel), cmCancel, bfNormal)));
  1272. Inc(R.A.Y,3); Inc(R.B.Y,3);
  1273. if AOptions and fdHelpButton <> 0 then
  1274. begin
  1275. Insert(New(PButton, Init(R,labels^.get(slHelp),cmHelp, bfNormal)));
  1276. Inc(R.A.Y,3); Inc(R.B.Y,3);
  1277. end;
  1278. R.Assign(1,16,48,18);
  1279. Control := New(PFileInfoPane, Init(R));
  1280. Insert(Control);
  1281. SelectNext(False);
  1282. if AOptions and fdNoLoadDir = 0 then ReadDirectory;
  1283. end;
  1284. constructor TFileDialog.Load(var S: TStream);
  1285. begin
  1286. if not TDialog.Load(S) then
  1287. Fail;
  1288. S.Read(WildCard, SizeOf(WildCard));
  1289. if (S.Status <> stOk) then
  1290. begin
  1291. TDialog.Done;
  1292. Fail;
  1293. end;
  1294. GetSubViewPtr(S, FileName);
  1295. GetSubViewPtr(S, FileList);
  1296. GetSubViewPtr(S, FileHistory);
  1297. ReadDirectory;
  1298. if (DosError <> 0) then
  1299. begin
  1300. TDialog.Done;
  1301. Fail;
  1302. end;
  1303. end;
  1304. destructor TFileDialog.Done;
  1305. begin
  1306. DisposeStr(Directory);
  1307. TDialog.Done;
  1308. end;
  1309. procedure TFileDialog.GetData(var Rec);
  1310. begin
  1311. GetFilename(PathStr(Rec));
  1312. end;
  1313. procedure TFileDialog.GetFileName(var S: PathStr);
  1314. var
  1315. Path: PathStr;
  1316. Name: NameStr;
  1317. Ext: ExtStr;
  1318. TWild : string;
  1319. TPath: PathStr;
  1320. TName: NameStr;
  1321. TExt: NameStr;
  1322. i : Sw_integer;
  1323. begin
  1324. S := FileName^.Data^;
  1325. if RelativePath(S) then
  1326. begin
  1327. if (Directory <> nil) then
  1328. S := FExpand(Directory^ + S);
  1329. end
  1330. else
  1331. S := FExpand(S);
  1332. if Pos(ListSeparator,S)=0 then
  1333. begin
  1334. If FileExists(S) then
  1335. exit;
  1336. FSplit(S, Path, Name, Ext);
  1337. if ((Name = '') or (Ext = '')) and not IsDir(S) then
  1338. begin
  1339. TWild:=WildCard;
  1340. repeat
  1341. i:=Pos(ListSeparator,TWild);
  1342. if i=0 then
  1343. i:=length(TWild)+1;
  1344. FSplit(Copy(TWild,1,i-1), TPath, TName, TExt);
  1345. if ((Name = '') and (Ext = '')) then
  1346. S := Path + TName + TExt
  1347. else
  1348. if Name = '' then
  1349. S := Path + TName + Ext
  1350. else
  1351. if Ext = '' then
  1352. begin
  1353. if IsWild(Name) then
  1354. S := Path + Name + TExt
  1355. else
  1356. S := Path + Name + NoWildChars(TExt);
  1357. end;
  1358. if FileExists(S) then
  1359. break;
  1360. System.Delete(TWild,1,i);
  1361. until TWild='';
  1362. if TWild='' then
  1363. S := Path + Name + Ext;
  1364. end;
  1365. end;
  1366. end;
  1367. procedure TFileDialog.HandleEvent(var Event: TEvent);
  1368. begin
  1369. if (Event.What and evBroadcast <> 0) and
  1370. (Event.Command = cmListItemSelected) then
  1371. begin
  1372. EndModal(cmFileOpen);
  1373. ClearEvent(Event);
  1374. end;
  1375. TDialog.HandleEvent(Event);
  1376. if Event.What = evCommand then
  1377. case Event.Command of
  1378. cmFileOpen, cmFileReplace, cmFileClear:
  1379. begin
  1380. EndModal(Event.Command);
  1381. ClearEvent(Event);
  1382. end;
  1383. end;
  1384. end;
  1385. procedure TFileDialog.SetData(var Rec);
  1386. begin
  1387. TDialog.SetData(Rec);
  1388. if (PathStr(Rec) <> '') and (IsWild(TWildStr(Rec))) then
  1389. begin
  1390. Valid(cmFileInit);
  1391. FileName^.Select;
  1392. end;
  1393. end;
  1394. procedure TFileDialog.ReadDirectory;
  1395. begin
  1396. FileList^.ReadDirectory(WildCard);
  1397. FileHistory^.AdaptHistoryToDir(GetCurDir);
  1398. Directory := NewStr(GetCurDir);
  1399. end;
  1400. procedure TFileDialog.Store(var S: TStream);
  1401. begin
  1402. TDialog.Store(S);
  1403. S.Write(WildCard, SizeOf(WildCard));
  1404. PutSubViewPtr(S, FileName);
  1405. PutSubViewPtr(S, FileList);
  1406. PutSubViewPtr(S, FileHistory);
  1407. end;
  1408. function TFileDialog.Valid(Command: Word): Boolean;
  1409. var
  1410. FName: PathStr;
  1411. Dir: DirStr;
  1412. Name: NameStr;
  1413. Ext: ExtStr;
  1414. function CheckDirectory(var S: PathStr): Boolean;
  1415. begin
  1416. if not PathValid(S) then
  1417. begin
  1418. MessageBox(Strings^.Get(sInvalidDriveOrDir), nil, mfError + mfOkButton);
  1419. FileName^.Select;
  1420. CheckDirectory := False;
  1421. end else CheckDirectory := True;
  1422. end;
  1423. function CompleteDir(const Path: string): string;
  1424. begin
  1425. { keep c: untouched PM }
  1426. if (Path<>'') and (Path[Length(Path)]<>DirSeparator) and
  1427. (Path[Length(Path)]<>':') then
  1428. CompleteDir:=Path+DirSeparator
  1429. else
  1430. CompleteDir:=Path;
  1431. end;
  1432. function NormalizeDir(const Path: string): string;
  1433. var Root: boolean;
  1434. begin
  1435. Root:=false;
  1436. {$ifdef Unix}
  1437. if Path=DirSeparator then Root:=true;
  1438. {$else}
  1439. if (length(Path)=3) and (Upcase(Path[1]) in['A'..'Z']) and
  1440. (Path[2]=':') and (Path[3]=DirSeparator) then
  1441. Root:=true;
  1442. {$endif}
  1443. if (Root=false) and (copy(Path,length(Path),1)=DirSeparator) then
  1444. NormalizeDir:=copy(Path,1,length(Path)-1)
  1445. else
  1446. NormalizeDir:=Path;
  1447. end;
  1448. function NormalizeDirF(var S: openstring): boolean;
  1449. begin
  1450. S:=NormalizeDir(S);
  1451. NormalizeDirF:=true;
  1452. end;
  1453. begin
  1454. if Command = 0 then
  1455. begin
  1456. Valid := True;
  1457. Exit;
  1458. end
  1459. else Valid := False;
  1460. if TDialog.Valid(Command) then
  1461. begin
  1462. GetFileName(FName);
  1463. if (Command <> cmCancel) and (Command <> cmFileClear) then
  1464. begin
  1465. if IsWild(FName) or IsList(FName) then
  1466. begin
  1467. FSplit(FName, Dir, Name, Ext);
  1468. if CheckDirectory(Dir) then
  1469. begin
  1470. FileHistory^.AdaptHistoryToDir(Dir);
  1471. DisposeStr(Directory);
  1472. Directory := NewStr(Dir);
  1473. if Pos(ListSeparator,FName)>0 then
  1474. WildCard:=Copy(FName,length(Dir)+1,255)
  1475. else
  1476. WildCard := Name+Ext;
  1477. if Command <> cmFileInit then
  1478. FileList^.Select;
  1479. FileList^.ReadDirectory(Directory^+WildCard);
  1480. end;
  1481. end
  1482. else
  1483. if NormalizeDirF(FName) then
  1484. { ^^ this is just a dummy if construct (the func always returns true,
  1485. it's just there, 'coz I don't want to rearrange the following "if"s... }
  1486. if IsDir(FName) then
  1487. begin
  1488. if CheckDirectory(FName) then
  1489. begin
  1490. FileHistory^.AdaptHistoryToDir(CompleteDir(FName));
  1491. DisposeStr(Directory);
  1492. Directory := NewSTr(CompleteDir(FName));
  1493. if Command <> cmFileInit then FileList^.Select;
  1494. FileList^.ReadDirectory(Directory^+WildCard);
  1495. end
  1496. end
  1497. else
  1498. if ValidFileName(FName) then
  1499. Valid := True
  1500. else
  1501. begin
  1502. MessageBox(^C + Strings^.Get(sInvalidFileName), nil, mfError + mfOkButton);
  1503. Valid := False;
  1504. end;
  1505. end
  1506. else Valid := True;
  1507. end;
  1508. end;
  1509. { TDirCollection }
  1510. function TDirCollection.GetItem(var S: TStream): Pointer;
  1511. var
  1512. DirItem: PDirEntry;
  1513. begin
  1514. New(DirItem);
  1515. DirItem^.DisplayText := S.ReadStr;
  1516. DirItem^.Directory := S.ReadStr;
  1517. GetItem := DirItem;
  1518. end;
  1519. procedure TDirCollection.FreeItem(Item: Pointer);
  1520. var
  1521. DirItem: PDirEntry absolute Item;
  1522. begin
  1523. DisposeStr(DirItem^.DisplayText);
  1524. DisposeStr(DirItem^.Directory);
  1525. Dispose(DirItem);
  1526. end;
  1527. procedure TDirCollection.PutItem(var S: TStream; Item: Pointer);
  1528. var
  1529. DirItem: PDirEntry absolute Item;
  1530. begin
  1531. S.WriteStr(DirItem^.DisplayText);
  1532. S.WriteStr(DirItem^.Directory);
  1533. end;
  1534. { TDirListBox }
  1535. const
  1536. DrivesS: String = '';
  1537. Drives: PString = @DrivesS;
  1538. constructor TDirListBox.Init(var Bounds: TRect; AScrollBar:
  1539. PScrollBar);
  1540. begin
  1541. DrivesS := strings^.get(sDrives);
  1542. TListBox.Init(Bounds, 1, AScrollBar);
  1543. Dir := '';
  1544. end;
  1545. destructor TDirListBox.Done;
  1546. begin
  1547. if (List <> nil) then
  1548. Dispose(List,Done);
  1549. TListBox.Done;
  1550. end;
  1551. function TDirListBox.GetText(Item,MaxLen: Sw_Integer): String;
  1552. begin
  1553. GetText := PDirEntry(List^.At(Item))^.DisplayText^;
  1554. end;
  1555. procedure TDirListBox.HandleEvent(var Event: TEvent);
  1556. begin
  1557. case Event.What of
  1558. evMouseDown:
  1559. if Event.Double then
  1560. begin
  1561. Event.What := evCommand;
  1562. Event.Command := cmChangeDir;
  1563. PutEvent(Event);
  1564. ClearEvent(Event);
  1565. end;
  1566. evKeyboard:
  1567. if (Event.CharCode = ' ') and
  1568. (PSearchRec(List^.At(Focused))^.Name = '..') then
  1569. NewDirectory(PSearchRec(List^.At(Focused))^.Name);
  1570. end;
  1571. TListBox.HandleEvent(Event);
  1572. end;
  1573. function TDirListBox.IsSelected(Item: Sw_Integer): Boolean;
  1574. begin
  1575. { IsSelected := Item = Cur; }
  1576. IsSelected := Inherited IsSelected(Item);
  1577. end;
  1578. procedure TDirListBox.NewDirectory(var ADir: DirStr);
  1579. const
  1580. PathDir = 'ÀÄÂ';
  1581. FirstDir = 'ÀÂÄ';
  1582. MiddleDir = ' ÃÄ';
  1583. LastDir = ' ÀÄ';
  1584. IndentSize = ' ';
  1585. var
  1586. AList: PCollection;
  1587. NewDir, Dirct: DirStr;
  1588. C, OldC: Char;
  1589. S, Indent: String[80];
  1590. P: PString;
  1591. NewCur: Word;
  1592. isFirst: Boolean;
  1593. SR: SearchRec;
  1594. I: Sw_Integer;
  1595. function NewDirEntry(const DisplayText, Directory: String): PDirEntry;{$ifdef PPC_BP}near;{$endif}
  1596. var
  1597. DirEntry: PDirEntry;
  1598. begin
  1599. New(DirEntry);
  1600. DirEntry^.DisplayText := NewStr(DisplayText);
  1601. If Directory='' then
  1602. DirEntry^.Directory := NewStr(DirSeparator)
  1603. else
  1604. DirEntry^.Directory := NewStr(Directory);
  1605. NewDirEntry := DirEntry;
  1606. end;
  1607. begin
  1608. Dir := ADir;
  1609. AList := New(PDirCollection, Init(5,5));
  1610. {$ifdef HAS_DOS_DRIVES}
  1611. AList^.Insert(NewDirEntry(Drives^,Drives^));
  1612. if Dir = Drives^ then
  1613. begin
  1614. isFirst := True;
  1615. OldC := ' ';
  1616. for C := 'A' to 'Z' do
  1617. begin
  1618. if (C < 'C') or DriveValid(C) then
  1619. begin
  1620. if OldC <> ' ' then
  1621. begin
  1622. if isFirst then
  1623. begin
  1624. S := FirstDir + OldC;
  1625. isFirst := False;
  1626. end
  1627. else S := MiddleDir + OldC;
  1628. AList^.Insert(NewDirEntry(S, OldC + ':' + DirSeparator));
  1629. end;
  1630. if C = GetCurDrive then NewCur := AList^.Count;
  1631. OldC := C;
  1632. end;
  1633. end;
  1634. if OldC <> ' ' then
  1635. AList^.Insert(NewDirEntry(LastDir + OldC, OldC + ':' + DirSeparator));
  1636. end
  1637. else
  1638. {$endif HAS_DOS_DRIVES}
  1639. begin
  1640. Indent := IndentSize;
  1641. NewDir := Dir;
  1642. {$ifdef HAS_DOS_DRIVES}
  1643. Dirct := Copy(NewDir,1,3);
  1644. AList^.Insert(NewDirEntry(PathDir + Dirct, Dirct));
  1645. NewDir := Copy(NewDir,4,255);
  1646. {$else HAS_DOS_DRIVES}
  1647. Dirct := '';
  1648. {$endif HAS_DOS_DRIVES}
  1649. while NewDir <> '' do
  1650. begin
  1651. I := Pos(DirSeparator,NewDir);
  1652. if I <> 0 then
  1653. begin
  1654. S := Copy(NewDir,1,I-1);
  1655. Dirct := Dirct + S;
  1656. AList^.Insert(NewDirEntry(Indent + PathDir + S, Dirct));
  1657. NewDir := Copy(NewDir,I+1,255);
  1658. end
  1659. else
  1660. begin
  1661. Dirct := Dirct + NewDir;
  1662. AList^.Insert(NewDirEntry(Indent + PathDir + NewDir, Dirct));
  1663. NewDir := '';
  1664. end;
  1665. Indent := Indent + IndentSize;
  1666. Dirct := Dirct + DirSeparator;
  1667. end;
  1668. NewCur := AList^.Count-1;
  1669. isFirst := True;
  1670. NewDir := Dirct + AllFiles;
  1671. FindFirst(NewDir, Directory, SR);
  1672. while DosError = 0 do
  1673. begin
  1674. if (SR.Attr and Directory <> 0) and
  1675. (SR.Name <> '.') and (SR.Name <> '..') then
  1676. begin
  1677. if isFirst then
  1678. begin
  1679. S := FirstDir;
  1680. isFirst := False;
  1681. end else S := MiddleDir;
  1682. AList^.Insert(NewDirEntry(Indent + S + SR.Name, Dirct + SR.Name));
  1683. end;
  1684. FindNext(SR);
  1685. end;
  1686. FindClose(SR);
  1687. P := PDirEntry(AList^.At(AList^.Count-1))^.DisplayText;
  1688. I := Pos('À',P^);
  1689. if I = 0 then
  1690. begin
  1691. I := Pos('Ã',P^);
  1692. if I <> 0 then P^[I] := 'À';
  1693. end else
  1694. begin
  1695. P^[I+1] := 'Ä';
  1696. P^[I+2] := 'Ä';
  1697. end;
  1698. end;
  1699. NewList(AList);
  1700. FocusItem(NewCur);
  1701. Cur:=NewCur;
  1702. end;
  1703. procedure TDirListBox.SetState(AState: Word; Enable: Boolean);
  1704. begin
  1705. TListBox.SetState(AState, Enable);
  1706. if AState and sfFocused <> 0 then
  1707. PChDirDialog(Owner)^.ChDirButton^.MakeDefault(Enable);
  1708. end;
  1709. {****************************************************************************}
  1710. { TChDirDialog Object }
  1711. {****************************************************************************}
  1712. {****************************************************************************}
  1713. { TChDirDialog.Init }
  1714. {****************************************************************************}
  1715. constructor TChDirDialog.Init(AOptions: Word; HistoryId: Sw_Word);
  1716. var
  1717. R: TRect;
  1718. Control: PView;
  1719. begin
  1720. R.Assign(16, 2, 64, 20);
  1721. TDialog.Init(R,strings^.get(sChangeDirectory));
  1722. Options := Options or ofCentered;
  1723. R.Assign(3, 3, 30, 4);
  1724. DirInput := New(PInputLine, Init(R, FileNameLen+4));
  1725. Insert(DirInput);
  1726. R.Assign(2, 2, 17, 3);
  1727. Control := New(PLabel, Init(R,labels^.get(slDirectoryName), DirInput));
  1728. Insert(Control);
  1729. R.Assign(30, 3, 33, 4);
  1730. Control := New(PHistory, Init(R, DirInput, HistoryId));
  1731. Insert(Control);
  1732. R.Assign(32, 6, 33, 16);
  1733. Control := New(PScrollBar, Init(R));
  1734. Insert(Control);
  1735. R.Assign(3, 6, 32, 16);
  1736. DirList := New(PDirListBox, Init(R, PScrollBar(Control)));
  1737. Insert(DirList);
  1738. R.Assign(2, 5, 17, 6);
  1739. Control := New(PLabel, Init(R, labels^.get(slDirectoryTree), DirList));
  1740. Insert(Control);
  1741. R.Assign(35, 6, 45, 8);
  1742. OkButton := New(PButton, Init(R, labels^.get(slOk), cmOK, bfDefault));
  1743. Insert(OkButton);
  1744. Inc(R.A.Y,3); Inc(R.B.Y,3);
  1745. ChDirButton := New(PButton,Init(R,labels^.get(slChDir),cmChangeDir,
  1746. bfNormal));
  1747. Insert(ChDirButton);
  1748. Inc(R.A.Y,3); Inc(R.B.Y,3);
  1749. Insert(New(PButton, Init(R,labels^.get(slRevert), cmRevert, bfNormal)));
  1750. if AOptions and cdHelpButton <> 0 then
  1751. begin
  1752. Inc(R.A.Y,3); Inc(R.B.Y,3);
  1753. Insert(New(PButton, Init(R,labels^.get(slHelp), cmHelp, bfNormal)));
  1754. end;
  1755. if AOptions and cdNoLoadDir = 0 then SetUpDialog;
  1756. SelectNext(False);
  1757. end;
  1758. {****************************************************************************}
  1759. { TChDirDialog.Load }
  1760. {****************************************************************************}
  1761. constructor TChDirDialog.Load(var S: TStream);
  1762. begin
  1763. TDialog.Load(S);
  1764. GetSubViewPtr(S, DirList);
  1765. GetSubViewPtr(S, DirInput);
  1766. GetSubViewPtr(S, OkButton);
  1767. GetSubViewPtr(S, ChDirbutton);
  1768. SetUpDialog;
  1769. end;
  1770. {****************************************************************************}
  1771. { TChDirDialog.DataSize }
  1772. {****************************************************************************}
  1773. function TChDirDialog.DataSize: Sw_Word;
  1774. begin
  1775. DataSize := 0;
  1776. end;
  1777. {****************************************************************************}
  1778. { TChDirDialog.GetData }
  1779. {****************************************************************************}
  1780. procedure TChDirDialog.GetData(var Rec);
  1781. begin
  1782. end;
  1783. {****************************************************************************}
  1784. { TChDirDialog.HandleEvent }
  1785. {****************************************************************************}
  1786. procedure TChDirDialog.HandleEvent(var Event: TEvent);
  1787. var
  1788. CurDir: DirStr;
  1789. P: PDirEntry;
  1790. begin
  1791. TDialog.HandleEvent(Event);
  1792. case Event.What of
  1793. evCommand:
  1794. begin
  1795. case Event.Command of
  1796. cmRevert: GetDir(0,CurDir);
  1797. cmChangeDir:
  1798. begin
  1799. P := DirList^.List^.At(DirList^.Focused);
  1800. if (P^.Directory^ = Drives^)
  1801. or DriveValid(P^.Directory^[1]) then
  1802. CurDir := P^.Directory^
  1803. else Exit;
  1804. end;
  1805. else
  1806. Exit;
  1807. end;
  1808. if (Length(CurDir) > 3) and
  1809. (CurDir[Length(CurDir)] = DirSeparator) then
  1810. CurDir := Copy(CurDir,1,Length(CurDir)-1);
  1811. DirList^.NewDirectory(CurDir);
  1812. DirInput^.Data^ := CurDir;
  1813. DirInput^.DrawView;
  1814. DirList^.Select;
  1815. ClearEvent(Event);
  1816. end;
  1817. end;
  1818. end;
  1819. {****************************************************************************}
  1820. { TChDirDialog.SetData }
  1821. {****************************************************************************}
  1822. procedure TChDirDialog.SetData(var Rec);
  1823. begin
  1824. end;
  1825. {****************************************************************************}
  1826. { TChDirDialog.SetUpDialog }
  1827. {****************************************************************************}
  1828. procedure TChDirDialog.SetUpDialog;
  1829. var
  1830. CurDir: DirStr;
  1831. begin
  1832. if DirList <> nil then
  1833. begin
  1834. CurDir := GetCurDir;
  1835. DirList^.NewDirectory(CurDir);
  1836. if (Length(CurDir) > 3) and (CurDir[Length(CurDir)] = DirSeparator) then
  1837. CurDir := Copy(CurDir,1,Length(CurDir)-1);
  1838. if DirInput <> nil then
  1839. begin
  1840. DirInput^.Data^ := CurDir;
  1841. DirInput^.DrawView;
  1842. end;
  1843. end;
  1844. end;
  1845. {****************************************************************************}
  1846. { TChDirDialog.Store }
  1847. {****************************************************************************}
  1848. procedure TChDirDialog.Store(var S: TStream);
  1849. begin
  1850. TDialog.Store(S);
  1851. PutSubViewPtr(S, DirList);
  1852. PutSubViewPtr(S, DirInput);
  1853. PutSubViewPtr(S, OkButton);
  1854. PutSubViewPtr(S, ChDirButton);
  1855. end;
  1856. {****************************************************************************}
  1857. { TChDirDialog.Valid }
  1858. {****************************************************************************}
  1859. function TChDirDialog.Valid(Command: Word): Boolean;
  1860. var
  1861. P: PathStr;
  1862. begin
  1863. Valid := True;
  1864. if Command = cmOk then
  1865. begin
  1866. P := FExpand(DirInput^.Data^);
  1867. if (Length(P) > 3) and (P[Length(P)] = DirSeparator) then
  1868. Dec(P[0]);
  1869. {$I-}
  1870. ChDir(P);
  1871. if (IOResult <> 0) then
  1872. begin
  1873. MessageBox(Strings^.Get(sInvalidDirectory), nil, mfError + mfOkButton);
  1874. Valid := False;
  1875. end;
  1876. {$I+}
  1877. end;
  1878. end;
  1879. {****************************************************************************}
  1880. { TEditChDirDialog Object }
  1881. {****************************************************************************}
  1882. {****************************************************************************}
  1883. { TEditChDirDialog.DataSize }
  1884. {****************************************************************************}
  1885. function TEditChDirDialog.DataSize : Sw_Word;
  1886. begin
  1887. DataSize := SizeOf(DirStr);
  1888. end;
  1889. {****************************************************************************}
  1890. { TEditChDirDialog.GetData }
  1891. {****************************************************************************}
  1892. procedure TEditChDirDialog.GetData (var Rec);
  1893. var
  1894. CurDir : DirStr absolute Rec;
  1895. begin
  1896. if (DirInput = nil) then
  1897. CurDir := ''
  1898. else begin
  1899. CurDir := DirInput^.Data^;
  1900. if (CurDir[Length(CurDir)] <> DirSeparator) then
  1901. CurDir := CurDir + DirSeparator;
  1902. end;
  1903. end;
  1904. {****************************************************************************}
  1905. { TEditChDirDialog.SetData }
  1906. {****************************************************************************}
  1907. procedure TEditChDirDialog.SetData (var Rec);
  1908. var
  1909. CurDir : DirStr absolute Rec;
  1910. begin
  1911. if DirList <> nil then
  1912. begin
  1913. DirList^.NewDirectory(CurDir);
  1914. if DirInput <> nil then
  1915. begin
  1916. if (Length(CurDir) > 3) and (CurDir[Length(CurDir)] = DirSeparator) then
  1917. DirInput^.Data^ := Copy(CurDir,1,Length(CurDir)-1)
  1918. else DirInput^.Data^ := CurDir;
  1919. DirInput^.DrawView;
  1920. end;
  1921. end;
  1922. end;
  1923. {****************************************************************************}
  1924. { TSortedListBox Object }
  1925. {****************************************************************************}
  1926. {****************************************************************************}
  1927. { TSortedListBox.Init }
  1928. {****************************************************************************}
  1929. constructor TSortedListBox.Init(var Bounds: TRect; ANumCols: Sw_Word;
  1930. AScrollBar: PScrollBar);
  1931. begin
  1932. TListBox.Init(Bounds, ANumCols, AScrollBar);
  1933. SearchPos := 0;
  1934. ShowCursor;
  1935. SetCursor(1,0);
  1936. end;
  1937. {****************************************************************************}
  1938. { TSortedListBox.HandleEvent }
  1939. {****************************************************************************}
  1940. procedure TSortedListBox.HandleEvent(var Event: TEvent);
  1941. const
  1942. SpecialChars: set of Char = [#0,#9,#27];
  1943. var
  1944. CurString, NewString: String;
  1945. K: Pointer;
  1946. Value : Sw_integer;
  1947. OldPos, OldValue: Sw_Integer;
  1948. T: Boolean;
  1949. begin
  1950. OldValue := Focused;
  1951. TListBox.HandleEvent(Event);
  1952. if (OldValue <> Focused) or
  1953. ((Event.What = evBroadcast) and (Event.InfoPtr = @Self) and
  1954. (Event.Command = cmReleasedFocus)) then
  1955. SearchPos := 0;
  1956. if Event.What = evKeyDown then
  1957. begin
  1958. { patched to prevent error when no or empty list or Escape pressed }
  1959. if (not (Event.CharCode in SpecialChars)) and
  1960. (List <> nil) and (List^.Count > 0) then
  1961. begin
  1962. Value := Focused;
  1963. if Value < Range then
  1964. CurString := GetText(Value, 255)
  1965. else
  1966. CurString := '';
  1967. OldPos := SearchPos;
  1968. if Event.KeyCode = kbBack then
  1969. begin
  1970. if SearchPos = 0 then Exit;
  1971. Dec(SearchPos);
  1972. if SearchPos = 0 then
  1973. HandleDir:= ((GetShiftState and $3) <> 0) or (Event.CharCode in ['A'..'Z']);
  1974. CurString[0] := Char(SearchPos);
  1975. end
  1976. else if (Event.CharCode = '.') then
  1977. SearchPos := Pos('.',CurString)
  1978. else
  1979. begin
  1980. Inc(SearchPos);
  1981. if SearchPos = 1 then
  1982. HandleDir := ((GetShiftState and 3) <> 0) or (Event.CharCode in ['A'..'Z']);
  1983. CurString[0] := Char(SearchPos);
  1984. CurString[SearchPos] := Event.CharCode;
  1985. end;
  1986. K := GetKey(CurString);
  1987. T := PSortedCollection(List)^.Search(K, Value);
  1988. if Value < Range then
  1989. begin
  1990. if Value < Range then
  1991. NewString := GetText(Value, 255)
  1992. else
  1993. NewString := '';
  1994. if Equal(NewString, CurString, SearchPos) then
  1995. begin
  1996. if Value <> OldValue then
  1997. begin
  1998. FocusItem(Value);
  1999. { Assumes ListControl will set the cursor to the first character }
  2000. { of the sfFocused item }
  2001. SetCursor(Cursor.X+SearchPos, Cursor.Y);
  2002. end
  2003. else
  2004. SetCursor(Cursor.X+(SearchPos-OldPos), Cursor.Y);
  2005. end
  2006. else
  2007. SearchPos := OldPos;
  2008. end
  2009. else SearchPos := OldPos;
  2010. if (SearchPos <> OldPos) or (Event.CharCode in ['A'..'Z','a'..'z']) then
  2011. ClearEvent(Event);
  2012. end;
  2013. end;
  2014. end;
  2015. function TSortedListBox.GetKey(var S: String): Pointer;
  2016. begin
  2017. GetKey := @S;
  2018. end;
  2019. procedure TSortedListBox.NewList(AList: PCollection);
  2020. begin
  2021. TListBox.NewList(AList);
  2022. SearchPos := 0;
  2023. end;
  2024. {****************************************************************************}
  2025. { Global Procedures and Functions }
  2026. {****************************************************************************}
  2027. {****************************************************************************}
  2028. { Contains }
  2029. {****************************************************************************}
  2030. function Contains(S1, S2: String): Boolean;
  2031. { Contains returns true if S1 contains any characters in S2. }
  2032. var
  2033. i : Byte;
  2034. begin
  2035. Contains := True;
  2036. i := 1;
  2037. while ((i < Length(S2)) and (i < Length(S1))) do
  2038. if (Upcase(S1[i]) = Upcase(S2[i])) then
  2039. Exit
  2040. else Inc(i);
  2041. Contains := False;
  2042. end;
  2043. {****************************************************************************}
  2044. { StdDeleteFile }
  2045. {****************************************************************************}
  2046. function StdDeleteFile (AFile : FNameStr) : Boolean;
  2047. var
  2048. Rec : PStringRec;
  2049. begin
  2050. if CheckOnDelete then
  2051. begin
  2052. AFile := ShrinkPath(AFile,33);
  2053. Rec.AString := PString(@AFile);
  2054. StdDeleteFile := (MessageBox(^C + Strings^.Get(sDeleteFile),
  2055. @Rec,mfConfirmation or mfOkCancel) = cmOk);
  2056. end
  2057. else StdDeleteFile := False;
  2058. end;
  2059. {****************************************************************************}
  2060. { DriveValid }
  2061. {****************************************************************************}
  2062. function DriveValid(Drive: Char): Boolean;
  2063. {$ifdef HAS_DOS_DRIVES}
  2064. var
  2065. D: Char;
  2066. begin
  2067. D := GetCurDrive;
  2068. {$I-}
  2069. ChDir(Drive+':');
  2070. if (IOResult = 0) then
  2071. begin
  2072. DriveValid := True;
  2073. ChDir(D+':')
  2074. end
  2075. else DriveValid := False;
  2076. {$I+}
  2077. end;
  2078. {$else HAS_DOS_DRIVES}
  2079. begin
  2080. DriveValid:=true;
  2081. end;
  2082. {$endif HAS_DOS_DRIVES}
  2083. {****************************************************************************}
  2084. { Equal }
  2085. {****************************************************************************}
  2086. function Equal(const S1, S2: String; Count: Sw_word): Boolean;
  2087. var
  2088. i: Sw_Word;
  2089. begin
  2090. Equal := False;
  2091. if (Length(S1) < Count) or (Length(S2) < Count) then
  2092. Exit;
  2093. for i := 1 to Count do
  2094. if UpCase(S1[I]) <> UpCase(S2[I]) then
  2095. Exit;
  2096. Equal := True;
  2097. end;
  2098. {****************************************************************************}
  2099. { ExtractDir }
  2100. {****************************************************************************}
  2101. function ExtractDir(AFile: FNameStr): DirStr;
  2102. { ExtractDir returns the path of AFile terminated with a trailing '\'. If
  2103. AFile contains no directory information, an empty string is returned. }
  2104. var
  2105. D: DirStr;
  2106. N: NameStr;
  2107. E: ExtStr;
  2108. begin
  2109. FSplit(AFile,D,N,E);
  2110. if D = '' then
  2111. begin
  2112. ExtractDir := '';
  2113. Exit;
  2114. end;
  2115. if D[Byte(D[0])] <> DirSeparator then
  2116. D := D + DirSeparator;
  2117. ExtractDir := D;
  2118. end;
  2119. {****************************************************************************}
  2120. { ExtractFileName }
  2121. {****************************************************************************}
  2122. function ExtractFileName(AFile: FNameStr): NameStr;
  2123. var
  2124. D: DirStr;
  2125. N: NameStr;
  2126. E: ExtStr;
  2127. begin
  2128. FSplit(AFile,D,N,E);
  2129. ExtractFileName := N;
  2130. end;
  2131. {****************************************************************************}
  2132. { FileExists }
  2133. {****************************************************************************}
  2134. function FileExists (AFile : FNameStr) : Boolean;
  2135. begin
  2136. FileExists := (FSearch(AFile,'') <> '');
  2137. end;
  2138. {****************************************************************************}
  2139. { GetCurDir }
  2140. {****************************************************************************}
  2141. function GetCurDir: DirStr;
  2142. var
  2143. CurDir: DirStr;
  2144. begin
  2145. GetDir(0, CurDir);
  2146. if (Length(CurDir) > 3) then
  2147. begin
  2148. Inc(CurDir[0]);
  2149. CurDir[Length(CurDir)] := DirSeparator;
  2150. end;
  2151. GetCurDir := CurDir;
  2152. end;
  2153. {****************************************************************************}
  2154. { GetCurDrive }
  2155. {****************************************************************************}
  2156. function GetCurDrive: Char;
  2157. {$ifdef go32v2}
  2158. var
  2159. Regs : Registers;
  2160. begin
  2161. Regs.AH := $19;
  2162. Intr($21,Regs);
  2163. GetCurDrive := Char(Regs.AL + Byte('A'));
  2164. end;
  2165. {$else not go32v2}
  2166. var
  2167. D : DirStr;
  2168. begin
  2169. D:=GetCurDir;
  2170. if (Length(D)>1) and (D[2]=':') then
  2171. begin
  2172. if (D[1]>='a') and (D[1]<='z') then
  2173. GetCurDrive:=Char(Byte(D[1])+Byte('A')-Byte('a'))
  2174. else
  2175. GetCurDrive:=D[1];
  2176. end
  2177. else
  2178. GetCurDrive:='C';
  2179. end;
  2180. {$endif not go32v2}
  2181. {****************************************************************************}
  2182. { IsDir }
  2183. {****************************************************************************}
  2184. function IsDir(const S: String): Boolean;
  2185. var
  2186. SR: SearchRec;
  2187. Is: boolean;
  2188. begin
  2189. Is:=false;
  2190. {$ifdef Unix}
  2191. Is:=(S=DirSeparator); { handle root }
  2192. {$else}
  2193. Is:=(length(S)=3) and (Upcase(S[1]) in['A'..'Z']) and (S[2]=':') and (S[3]=DirSeparator);
  2194. { handle root dirs }
  2195. {$endif}
  2196. if Is=false then
  2197. begin
  2198. FindFirst(S, Directory, SR);
  2199. if DosError = 0 then
  2200. Is := (SR.Attr and Directory) <> 0
  2201. else
  2202. Is := False;
  2203. {$ifdef fpc}
  2204. FindClose(SR);
  2205. {$endif}
  2206. end;
  2207. IsDir:=Is;
  2208. end;
  2209. {****************************************************************************}
  2210. { IsWild }
  2211. {****************************************************************************}
  2212. function IsWild(const S: String): Boolean;
  2213. begin
  2214. IsWild := (Pos('?',S) > 0) or (Pos('*',S) > 0);
  2215. end;
  2216. {****************************************************************************}
  2217. { IsList }
  2218. {****************************************************************************}
  2219. function IsList(const S: String): Boolean;
  2220. begin
  2221. IsList := (Pos(ListSeparator,S) > 0);
  2222. end;
  2223. {****************************************************************************}
  2224. { MakeResources }
  2225. {****************************************************************************}
  2226. procedure MakeResources;
  2227. var
  2228. Dlg : PDialog;
  2229. Key : String;
  2230. i : Word;
  2231. begin
  2232. for i := 0 to 1 do
  2233. begin
  2234. case i of
  2235. 0 : begin
  2236. Key := reOpenDlg;
  2237. Dlg := New(PFileDialog,Init('*.*',strings^.get(sOpen),
  2238. labels^.get(slName),
  2239. fdOkButton or fdHelpButton or fdNoLoadDir,0));
  2240. end;
  2241. 1 : begin
  2242. Key := reSaveAsDlg;
  2243. Dlg := New(PFileDialog,Init('*.*',strings^.get(sSaveAs),
  2244. labels^.get(slName),
  2245. fdOkButton or fdHelpButton or fdNoLoadDir,0));
  2246. end;
  2247. 2 : begin
  2248. Key := reEditChDirDialog;
  2249. Dlg := New(PEditChDirDialog,Init(cdHelpButton,
  2250. hiCurrentDirectories));
  2251. end;
  2252. end;
  2253. if Dlg = nil then
  2254. begin
  2255. PrintStr('Error initializing dialog ' + Key);
  2256. Halt;
  2257. end
  2258. else begin
  2259. RezFile^.Put(Dlg,Key);
  2260. if (RezFile^.Stream^.Status <> stOk) then
  2261. begin
  2262. PrintStr('Error writing dialog ' + Key + ' to the resource file.');
  2263. Halt;
  2264. end;
  2265. end;
  2266. end;
  2267. end;
  2268. {****************************************************************************}
  2269. { NoWildChars }
  2270. {****************************************************************************}
  2271. function NoWildChars(S: String): String;
  2272. const
  2273. WildChars : array[0..1] of Char = ('?','*');
  2274. var
  2275. i : Sw_Word;
  2276. begin
  2277. repeat
  2278. i := Pos('?',S);
  2279. if (i > 0) then
  2280. System.Delete(S,i,1);
  2281. until (i = 0);
  2282. repeat
  2283. i := Pos('*',S);
  2284. if (i > 0) then
  2285. System.Delete(S,i,1);
  2286. until (i = 0);
  2287. NoWildChars:=S;
  2288. end;
  2289. {****************************************************************************}
  2290. { OpenFile }
  2291. {****************************************************************************}
  2292. function OpenFile (var AFile : FNameStr; HistoryID : Byte) : Boolean;
  2293. var
  2294. Dlg : PFileDialog;
  2295. begin
  2296. {$ifdef cdResource}
  2297. Dlg := PFileDialog(RezFile^.Get(reOpenDlg));
  2298. {$else}
  2299. Dlg := New(PFileDialog,Init('*.*',strings^.get(sOpen),labels^.get(slName),
  2300. fdOkButton or fdHelpButton,0));
  2301. {$endif cdResource}
  2302. { this might not work }
  2303. PHistory(Dlg^.FileName^.Next^.Next)^.HistoryID := HistoryID;
  2304. OpenFile := (Application^.ExecuteDialog(Dlg,@AFile) = cmFileOpen);
  2305. end;
  2306. {****************************************************************************}
  2307. { OpenNewFile }
  2308. {****************************************************************************}
  2309. function OpenNewFile (var AFile: FNameStr; HistoryID: Byte): Boolean;
  2310. { OpenNewFile allows the user to select a directory from disk and enter a
  2311. new file name. If the file name entered is an existing file the user is
  2312. optionally prompted for confirmation of replacing the file based on the
  2313. value in #CheckOnReplace#. If a file name is successfully entered,
  2314. OpenNewFile returns True. }
  2315. {#X OpenFile }
  2316. begin
  2317. OpenNewFile := False;
  2318. if OpenFile(AFile,HistoryID) then
  2319. begin
  2320. if not ValidFileName(AFile) then
  2321. Exit;
  2322. if FileExists(AFile) then
  2323. if (not CheckOnReplace) or (not ReplaceFile(AFile)) then
  2324. Exit;
  2325. OpenNewFile := True;
  2326. end;
  2327. end;
  2328. {****************************************************************************}
  2329. { RegisterStdDlg }
  2330. {****************************************************************************}
  2331. procedure RegisterStdDlg;
  2332. begin
  2333. RegisterType(RFileInputLine);
  2334. RegisterType(RFileCollection);
  2335. RegisterType(RFileList);
  2336. RegisterType(RFileInfoPane);
  2337. RegisterType(RFileDialog);
  2338. RegisterType(RDirCollection);
  2339. RegisterType(RDirListBox);
  2340. RegisterType(RSortedListBox);
  2341. RegisterType(RChDirDialog);
  2342. end;
  2343. {****************************************************************************}
  2344. { StdReplaceFile }
  2345. {****************************************************************************}
  2346. function StdReplaceFile (AFile : FNameStr) : Boolean;
  2347. var
  2348. Rec : PStringRec;
  2349. begin
  2350. if CheckOnReplace then
  2351. begin
  2352. AFile := ShrinkPath(AFile,33);
  2353. Rec.AString := PString(@AFile);
  2354. StdReplaceFile :=
  2355. (MessageBox(^C + Strings^.Get(sReplaceFile),
  2356. @Rec,mfConfirmation or mfOkCancel) = cmOk);
  2357. end
  2358. else StdReplaceFile := True;
  2359. end;
  2360. {****************************************************************************}
  2361. { SaveAs }
  2362. {****************************************************************************}
  2363. function SaveAs (var AFile : FNameStr; HistoryID : Word) : Boolean;
  2364. var
  2365. Dlg : PFileDialog;
  2366. begin
  2367. SaveAs := False;
  2368. Dlg := New(PFileDialog,Init('*.*',strings^.get(sSaveAs),
  2369. labels^.get(slSaveAs),
  2370. fdOkButton or fdHelpButton,0));
  2371. { this might not work }
  2372. PHistory(Dlg^.FileName^.Next^.Next)^.HistoryID := HistoryID;
  2373. Dlg^.HelpCtx := hcSaveAs;
  2374. if (Application^.ExecuteDialog(Dlg,@AFile) = cmFileOpen) and
  2375. ((not FileExists(AFile)) or ReplaceFile(AFile)) then
  2376. SaveAs := True;
  2377. end;
  2378. {****************************************************************************}
  2379. { SelectDir }
  2380. {****************************************************************************}
  2381. function SelectDir (var ADir : DirStr; HistoryID : Byte) : Boolean;
  2382. var
  2383. Dir: DirStr;
  2384. Dlg : PEditChDirDialog;
  2385. Rec : DirStr;
  2386. begin
  2387. {$I-}
  2388. GetDir(0,Dir);
  2389. {$I+}
  2390. Rec := FExpand(ADir);
  2391. Dlg := New(PEditChDirDialog,Init(cdHelpButton,HistoryID));
  2392. if (Application^.ExecuteDialog(Dlg,@Rec) = cmOk) then
  2393. begin
  2394. SelectDir := True;
  2395. ADir := Rec;
  2396. end
  2397. else SelectDir := False;
  2398. {$I-}
  2399. ChDir(Dir);
  2400. {$I+}
  2401. end;
  2402. {****************************************************************************}
  2403. { ShrinkPath }
  2404. {****************************************************************************}
  2405. function ShrinkPath (AFile : FNameStr; MaxLen : Byte) : FNameStr;
  2406. var
  2407. Filler: string;
  2408. D1 : DirStr;
  2409. N1 : NameStr;
  2410. E1 : ExtStr;
  2411. i : Sw_Word;
  2412. begin
  2413. if Length(AFile) > MaxLen then
  2414. begin
  2415. FSplit(FExpand(AFile),D1,N1,E1);
  2416. AFile := Copy(D1,1,3) + '..' + DirSeparator;
  2417. i := Pred(Length(D1));
  2418. while (i > 0) and (D1[i] <> DirSeparator) do
  2419. Dec(i);
  2420. if (i = 0) then
  2421. AFile := AFile + D1
  2422. else AFile := AFile + Copy(D1,Succ(i),Length(D1)-i);
  2423. if AFile[Length(AFile)] <> DirSeparator then
  2424. AFile := AFile + DirSeparator;
  2425. if Length(AFile)+Length(N1)+Length(E1) <= MaxLen then
  2426. AFile := AFile + N1 + E1
  2427. else
  2428. begin
  2429. Filler := '...' + DirSeparator;
  2430. AFile:=Copy(Afile,1,MaxLen-Length(Filler)-Length(N1)-Length(E1))
  2431. +Filler+N1+E1;
  2432. end;
  2433. end;
  2434. ShrinkPath := AFile;
  2435. end;
  2436. {****************************************************************************}
  2437. { ValidFileName }
  2438. {****************************************************************************}
  2439. function ValidFileName(var FileName: PathStr): Boolean;
  2440. var
  2441. IllegalChars: string[12];
  2442. Dir: DirStr;
  2443. Name: NameStr;
  2444. Ext: ExtStr;
  2445. begin
  2446. {$ifdef PPC_FPC}
  2447. {$ifdef go32v2}
  2448. { spaces are allowed if LFN is supported }
  2449. if LFNSupport then
  2450. IllegalChars := ';,=+<>|"[]'+DirSeparator
  2451. else
  2452. IllegalChars := ';,=+<>|"[] '+DirSeparator;
  2453. {$else not go32v2}
  2454. {$ifdef win32}
  2455. IllegalChars := ';,=+<>|"[]'+DirSeparator;
  2456. {$else not go32v2 and not win32 }
  2457. IllegalChars := ';,=+<>|"[] '+DirSeparator;
  2458. {$endif not win32}
  2459. {$endif not go32v2}
  2460. {$else not PPC_FPC}
  2461. IllegalChars := ';,=+<>|"[] '+DirSeparator;
  2462. {$endif PPC_FPC}
  2463. ValidFileName := True;
  2464. FSplit(FileName, Dir, Name, Ext);
  2465. if not ((Dir = '') or PathValid(Dir)) or
  2466. Contains(Name, IllegalChars) or
  2467. Contains(Dir, IllegalChars) then
  2468. ValidFileName := False;
  2469. end;
  2470. {****************************************************************************}
  2471. { Unit Initialization Section }
  2472. {****************************************************************************}
  2473. begin
  2474. {$ifdef PPC_BP}
  2475. ReplaceFile := StdReplaceFile;
  2476. DeleteFile := StdDeleteFile;
  2477. {$else}
  2478. ReplaceFile := @StdReplaceFile;
  2479. DeleteFile := @StdDeleteFile;
  2480. {$endif PPC_BP}
  2481. end.