stddlg.pas 77 KB

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