stddlg.pas 75 KB

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