stddlg.pas 77 KB

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