stddlg.pas 77 KB

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