stddlg.pas 78 KB

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