stddlg.pas 77 KB

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