stddlg.pas 77 KB

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