You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

KOLDirDlgEx.pas 43KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354
  1. {$ifndef read_implementation}
  2. {$ifdef FPC} {$mode delphi} {$endif FPC}
  3. unit KOLDirDlgEx;
  4. interface
  5. uses Windows, Messages, KOL {$IFDEF USE_GRUSH}, ToGrush, KOLGRushControls {$ENDIF}
  6. {$ifdef FPC}{$if not defined(VER2_2_0) and defined(wince)},commctrl{$endif}{$endif};
  7. {$endif read_implementation}
  8. {$IFDEF EXTERNAL_DEFINES}
  9. {$INCLUDE EXTERNAL_DEFINES.INC}
  10. {$ENDIF EXTERNAL_DEFINES}
  11. //{$DEFINE NO_DEFAULT_FASTSCAN}
  12. { if you add such option, all icons for removable and remote drives
  13. are obtained by default accessing these drives, slow. }
  14. //{$DEFINE DIRDLGEX_NO_DBLCLK_ON_NODE_OK}
  15. { if this option is on, double clicks in the directories tree
  16. is used only to expand/collapse children nodes. By default,
  17. double click on a node w/o children selects it and
  18. finishes the dialog as in case when OK is clicked. }
  19. //{$DEFINE DIRDLGEX_LINKSPANEL}
  20. { if this option is on, links panel is available (on the left side).
  21. Also USE_MENU_CURCTL symbol must be added! }
  22. //{$DEFINE DIRDLGEX_STDFONT}
  23. { add this option to use standard font size in a links panel
  24. (otherwise Arial, 14 is used) }
  25. {$DEFINE DIRDLGEX_BIGGERPANEL}
  26. { a bit bigger links panel with bigger buttons on it }
  27. { ----------------------------------------------------------------------
  28. TOpenDirDialogEx
  29. ----------------------------------------------------------------------- }
  30. { TOpenDirDialogEx - àëüòåðíàòèâà ñòàíäàðòíîìó äèàëîãó âûáîðà ïàïêè.
  31. (c) by Vladimir Kladov, 2005, 14 Dec.
  32. Íåîáõîäèìîñòü: ñòàíäàðòíûé äèàëîã ðàáîòàåò ìåäëåííî, äëÿ êàæäîé îïåðàöèè
  33. âûáîðà ïàïêè ïîëüçîâàòåëåì îòêðûâàåòñÿ çàíîâî, ñòðîÿ çàíîâî
  34. äåðåâî ïàïîê, ïðè ýòîì ãëþ÷èò: ðåãóëÿðíî âîçíèêàåò ñèòóàöèÿ,
  35. êîãäà ðîäèòåëüñêèé óçåë äëÿ ïåðâîíà÷àëüíîé ïàïêè ìîæåò ïîêàçàòü
  36. òîëüêî òåêóùóþ âëîæåííóþ ïàïêó, õîòÿ òàì åñòü åùå ïàïêè.
  37. Íå ãîâîðÿ óæå î ìåëêèõ ãëóïîñòÿõ, âðîäå òîé, ÷òî òåêóùèé óçåë
  38. â ìîìåíò îòêðûòèÿ ìîæåò ïðîñòî îêàçàòüñÿ âíå ïîëÿ çðåíèÿ, èëè
  39. òîé, ÷òî â ñòàíäàðòíîì äèàëîãå àêòèâíûì îêàçûâàåòñÿ íå äåðåâî
  40. âûáîðà ïàïîê, à êíîïêà ÎÊ (èëè êòî-òî äóìàåò, ÷òî ïîëüçîâàòåëü
  41. îòêðûë äèàëîã äëÿ òîãî, ÷òîáû íàæàòü ÎÊ, íå âûáèðàÿ ïàïêó?).
  42. Îñîáåííîñòè TOpenDirDialogEx: ðàáîòàåò áûñòðî. Ïðè ïîâòîðíîì âûïîëíåíèè
  43. Execute ïåðåñêàíèðóåòñÿ òîëüêî òà ÷àñòü äåðåâà, êîòîðàÿ âûøå òåêóùåé ïàïêè
  44. (ò.å. ïîâòîðíîå îòêðûòèå âûïîëíÿåòñÿ ïðàêòè÷åñêè ìãíîâåííî). Ïåðâîíà÷àëüíî
  45. îòêðûâàåòñÿ òîëüêî ÷àñòü äåðåâà ïàïîê, êîòîðàÿ íåîáõîäèìà, ÷òîáû ïîëíîñòü
  46. îòêðûòü âñå ïàïêè íà ïóòè îò êîðíÿ äèñêà äî òåêóùåé ïàïêè. Ïðî÷èå ïàïêè
  47. îòêðûâàþòñÿ è ïåðåñêàíèðóþòñÿ ïðè èõ îòêðûòèè (ðàñïàõèâàíèè). Ïîâòîðíîå
  48. ðàñïàõèâàíèå ïàïêè ïåðåñêàíèðóåò åå (êàê àëüòåðíàòèâà àâòîìàòè÷åñêîìó
  49. îáíîâëåíèþ, êîòîðîå íå ðåàëèçîâàíî - õîòÿ è îñîáîé íåîáõîäèìîñòè â àâòîìàòèêå
  50. íà ïðàêòèêå íåò, è êðîìå äîïîëíèòåëüíîé íàãðóçêè íà ñèñòåìó òîëêó îò òàêîãî
  51. àâòîìàòà òîæå íå âèäíî).
  52. Äîïîëíèòåëüíûå âêóñíîñòè:
  53. Åñòü âîçìîæíîñòü ïîìåíÿòü íàäïèñè íà êíîïêàõ, çàãîëîâîê äèàëîãà.
  54. Åñòü âîçìîæíîñòü îòôèëüòðîâàòü äèðåêòîðèè ïî àòðèáóòàì (FilterAttrs), íàïðèìåð,
  55. åñëè ïðèñâîèòü FILE_ATTRIBUTE_HIDDEN, òî ñêðûòûå ïàïêè â äåðåâå ïîêàçàíû íå áóäóò.
  56. }
  57. const
  58. WM_USER_RESCANTREE = WM_USER;
  59. {$ifdef FPC}
  60. {$if not defined(UNICODE_CTRLS) and not defined(wince)}
  61. {$I fpc_unicode_add.inc}
  62. {$endif}
  63. {$endif FPC}
  64. {$ifdef wince}
  65. type
  66. TFindexInfoLevels = FINDEX_INFO_LEVELS;
  67. TFindexSearchOps = FINDEX_SEARCH_OPS;
  68. {$endif wince}
  69. type
  70. TFindFirstFileEx = function(lpFileName: PKOLChar; fInfoLevelId: TFindexInfoLevels;
  71. lpFindFileData: Pointer; fSearchOp: TFindexSearchOps; lpSearchFilter: Pointer;
  72. dwAdditionalFlags: DWORD): THandle; stdcall;
  73. POpenDirDialogEx = ^TOpenDirDialogEx;
  74. TOpenDirDialogEx = object( TObj )
  75. protected
  76. FFastScan: Boolean;
  77. DlgClient: PControl;
  78. DirTree: PControl;
  79. BtnPanel: PControl;
  80. RescanningNode, RescanningTree: Boolean;
  81. FPath, FRecycledName: KOLString;
  82. FRemoteIconSysIdx: Integer;
  83. FFindFirstFileEx: TFindFirstFileEx;
  84. k32: THandle;
  85. DialogForm: PControl;
  86. function GetFindFirstFileEx: TFindFirstFileEx;
  87. procedure SetPath(const Value: KOLString);
  88. function GetDialogForm: PControl;
  89. procedure DoOK( Sender: PObj );
  90. procedure DoCancel( Sender: PObj );
  91. procedure DoNotClose( Sender: PObj; var Accept: Boolean );
  92. procedure DoShow( Sender: PObj );
  93. function DoMsg( var Msg: TMsg; var Rslt: Integer ): Boolean;
  94. function DoExpanding( Sender: PControl; Item: THandle; Expand: Boolean )
  95. : Boolean;
  96. function DoFilterAttrs( Attrs: DWORD; const APath: KOLString ): Boolean;
  97. procedure Rescantree;
  98. procedure RescanNode( node: Integer );
  99. procedure RescanDisks;
  100. function RemoteIconSysIdx: Integer;
  101. procedure CheckNodeHasChildren( node: Integer );
  102. procedure CreateDialogForm;
  103. property _FindFirstFileEx: TFindFirstFileEx read GetFindFirstFileEx;
  104. procedure DeleteNode( node: Integer );
  105. procedure DestroyingForm( Sender: PObj );
  106. function GetNodePath(N: THandle): KOLString;
  107. public
  108. OKCaption, CancelCaption: KOLString;
  109. FilterAttrs: DWORD;
  110. FilterRecycled: Boolean;
  111. Title: KOLString;
  112. property Form: PControl read GetDialogForm;
  113. {* DialogForm object. Though it is possible to do anything since it is
  114. in public section, do this only if you understand possible consequences.
  115. E.g., use it to change DialogForm bounding rectangle on screen or to
  116. add your own controls, event handlers and so on. }
  117. destructor Destroy; virtual;
  118. function Execute: Boolean;
  119. property InitialPath: KOLString read FPath write SetPath;
  120. property Path: KOLString read FPath write SetPath;
  121. property FastScan: Boolean read FFastScan write FFastScan;
  122. procedure DoubleClick( Sender: PControl; var M: TMouseEventData );
  123. {$IFDEF DIRDLGEX_LINKSPANEL}
  124. protected
  125. LinksPanel, LinksBox, LinksTape: PControl;
  126. LinksUp, LinksDn, LinksAdd: PControl;
  127. LinksList: PStrListEx;
  128. LinksImgList: PImageList;
  129. LinksRollTimer: PTimer;
  130. LinksPopupMenu: PMenu;
  131. procedure CreateLinksPanel;
  132. function GetLinksPanelOn: Boolean;
  133. procedure SetLinksPanelOn( const Value: Boolean );
  134. function GetLinksCount: Integer;
  135. function GetLinks(idx: Integer): KOLString;
  136. procedure SetLinks(idx: Integer; const Value: KOLString);
  137. procedure SetupLinksTapeHeight;
  138. procedure SetUpTaborders;
  139. procedure LinksUpClick( Sender: PControl; var Mouse: TMouseEventData );
  140. procedure LinksDnClick( Sender: PControl; var Mouse: TMouseEventData );
  141. procedure LinksUpDnStop( Sender: PControl; var Mouse: TMouseEventData );
  142. procedure LinksAddClick( Sender: PObj );
  143. procedure LinkClick( Sender: PObj );
  144. procedure LinksRollTimerTimer( Sender: PObj );
  145. //procedure LinksPanelShowEvent( Sender: PObj );
  146. procedure RemoveLinkClick( Sender: PMenu; Item: Integer );
  147. public
  148. property LinksPanelOn: Boolean read GetLinksPanelOn write SetLinksPanelOn;
  149. property LinksCount: Integer read GetLinksCount;
  150. property Links[ idx: Integer ]: KOLString read GetLinks write SetLinks;
  151. procedure AddLinks( SL: PStrList );
  152. function CollectLinks: PStrList;
  153. function LinkPresent( const s: KOLString ): Boolean;
  154. procedure RemoveLink( const s: KOLString );
  155. procedure ClearLinks;
  156. {$ENDIF DIRDLGEX_LINKSPANEL}
  157. end;
  158. {$ifndef read_implementation}
  159. function NewOpenDirDialogEx: POpenDirDialogEx;
  160. {$IFDEF KOL_MCK}
  161. {$IFNDEF DIRDLGEX_OPTIONAL} { add this symbol if you want use
  162. both types of the open directory dialog in your application
  163. (and in such case, call a constructor of the TOpenDirDialogEx
  164. object manually). }
  165. type TKOLOpenDirDialog = POpenDirDialogEx;
  166. {$ENDIF}
  167. {$ENDIF}
  168. implementation
  169. {$endif read_implementation}
  170. function NewOpenDirDialogEx: POpenDirDialogEx;
  171. begin
  172. new( Result, Create );
  173. {$IFNDEF NO_DEFAULT_FASTSCAN}
  174. Result.FastScan := TRUE;
  175. {$ENDIF}
  176. end;
  177. procedure NewPanelWithSingleButtonToolbar( AParent: PControl; W, H: Integer;
  178. A: TControlAlign; Bmp: PBitmap; const C, T: KOLString; var Pn, Bar: PControl;
  179. const ClickEvent: TOnEvent; DownEvent, ReleaseEvent: TOnMouse;
  180. P: PMenu );
  181. var i: Integer;
  182. Buffer: PKOLChar;
  183. begin
  184. Pn := NewPanel( AParent, esNone ).SetSize( 0, H ).SetAlign( A );
  185. Pn.Border := 0;
  186. {$ifdef wince}
  187. pn.Color:=clBtnFace;
  188. pn.HasBorder:=True;
  189. {$endif wince}
  190. Bar := NewToolbar( Pn, caClient, [
  191. tboNoDivider, tboTextBottom {, tboFlat} ],
  192. Bmp.ReleaseHandle,
  193. [ PKOLChar( {$IFDEF TOOLBAR_DOT_NOAUTOSIZE_BUTTON} '.' + {$ENDIF} C ) ], [ 0 ] );
  194. Buffer := AllocMem( (Length( T ) + 1)*SizeOf(KOLChar) );
  195. if T <> '' then
  196. Move(T[1], Buffer^, Length( T )*SizeOf(KOLChar));
  197. {$IFDEF USE_GRUSH}
  198. i := 0;
  199. {$IFDEF TOGRUSH_OPTIONAL}
  200. if NoGrush then
  201. begin
  202. i := Bar.TBIndex2Item(0);
  203. Bar.Perform( TB_SETBITMAPSIZE, 0, MakeLong( Bmp.Width, Bmp.Height ) );
  204. end;
  205. if not NoGrush then
  206. {$ENDIF}
  207. begin
  208. PGRushControl( Bar.Children[0] ).All_GlyphVAlign := vaTop;
  209. if C = '' then
  210. begin
  211. PGRushControl( Bar.Children[0] ).All_GlyphVAlign := vaCenter;
  212. PGRushControl( Bar.Children[0] ).All_ContentOffsets := MakeRect( -4, -4, 4, 4 );
  213. end;
  214. PGRushControl( Bar.Children[0] ).All_GlyphHAlign := haCenter;
  215. PGRushControl( Bar.Children[0] ).All_GlyphWidth := Bmp.Width;
  216. PGRushControl( Bar.Children[0] ).All_Spacing := 2;
  217. PGRushControl( Bar.Children[0] ).Width := W;
  218. if not Assigned( DownEvent ) then
  219. PGRushControl( Bar.Children[0] ).OnClick := ClickEvent
  220. else
  221. begin
  222. PGRushControl( Bar.Children[0] ).OnMouseDown := DownEvent;
  223. PGRushControl( Bar.Children[0] ).OnMouseUp := ReleaseEvent;
  224. end;
  225. PGRushControl( Bar.Children[0] ).CustomData := Buffer;
  226. PGRushControl( Bar.Children[0] ).All_ColorOuter := AParent.Color;
  227. //PGRushControl( Bar ).All_ColorFrom := AParent.Color;
  228. //PGRushControl( Bar ).All_ColorTo := AParent.Color;
  229. end
  230. {$IFDEF TOGRUSH_OPTIONAL}
  231. else
  232. begin
  233. i := Bar.TBIndex2Item(0);
  234. Bar.TBButtonWidth[ i ] := W;
  235. Bar.Perform( TB_SETBITMAPSIZE, 0, MakeLong( Bmp.Width, Bmp.Height ) );
  236. if not Assigned( ReleaseEvent ) then
  237. Bar.OnClick := ClickEvent
  238. else
  239. begin
  240. Bar.OnMouseDown := DownEvent;
  241. Bar.OnMouseUp := ReleaseEvent;
  242. end;
  243. Bar.CustomData := Buffer;
  244. end
  245. {$ENDIF TOGRUSH_OPTIONAL}
  246. ;
  247. {$ELSE}
  248. i := Bar.TBIndex2Item(0);
  249. Bar.TBButtonWidth[ i ] := W;
  250. Bar.Perform( TB_SETBITMAPSIZE, 0, MakeLong( Bmp.Width, Bmp.Height ) );
  251. if not Assigned( ReleaseEvent ) then
  252. Bar.OnClick := ClickEvent
  253. else
  254. begin
  255. Bar.OnMouseDown := DownEvent;
  256. Bar.OnMouseUp := ReleaseEvent;
  257. end;
  258. Bar.CustomData := Buffer;
  259. {$ENDIF USE_GRUSH}
  260. ToolbarSetTooltips( Bar, i, [ PKOLChar( T ) ] );
  261. if P <> nil then
  262. begin
  263. Pn.SetAutoPopupMenu( P );
  264. end;
  265. Bmp.Free;
  266. end;
  267. { TOpenDirDialogEx }
  268. {$IFDEF DIRDLGEX_LINKSPANEL}
  269. procedure TOpenDirDialogEx.AddLinks(SL: PStrList);
  270. var i: Integer;
  271. begin
  272. for i := 0 to SL.Count-1 do
  273. if not LinkPresent( SL.Items[ i ] ) then
  274. Links[ LinksCount ] := SL.Items[ i ];
  275. end;
  276. {$ENDIF DIRDLGEX_LINKSPANEL}
  277. procedure TOpenDirDialogEx.CheckNodeHasChildren(node: Integer);
  278. var HasSubDirs: Boolean;
  279. {$ifndef wince}
  280. txt: KOLString;
  281. {$endif wince}
  282. F: THandle;
  283. Find32: TWin32FindData;
  284. ii, n: Integer;
  285. begin
  286. HasSubDirs := FALSE;
  287. {$ifndef wince}
  288. txt := DirTree.TVItemText[ node ];
  289. if (Length( txt ) = 2) then
  290. if (txt[ 2 ] = ':') then
  291. begin
  292. ii := GetDriveType( PKOLChar( txt + '\' ) );
  293. if IntIn( ii, [ DRIVE_REMOVABLE, DRIVE_REMOTE, DRIVE_CDROM ] ) then
  294. HasSubDirs := TRUE;
  295. end;
  296. if not HasSubDirs then
  297. begin
  298. if WinVer >= wvNT then
  299. begin
  300. {$endif wince}
  301. _FindFirstFileEx;
  302. F := FFindFirstFileEx( PKOLChar( GetNodePath( node ) + '\*.*' ),
  303. FindExInfoStandard, @ Find32, FindExSearchLimitToDirectories, nil, 0 );
  304. if F <> INVALID_HANDLE_VALUE then
  305. begin
  306. while TRUE do
  307. begin
  308. if Find32.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
  309. if (Find32.cFileName <> KOLString( '.' )) and (Find32.cFileName <> '..') then
  310. if DoFilterAttrs( Find32.dwFileAttributes, Find32.{$ifdef wince}cFileName{$else}cAlternateFileName{$endif} ) then
  311. begin
  312. HasSubDirs := TRUE;
  313. break;
  314. end;
  315. if not FindNextFile( F, Find32 ) then break;
  316. end;
  317. if not FindClose( F ) then
  318. {begin
  319. asm
  320. nop
  321. end;
  322. end};
  323. end;
  324. {$ifndef wince}
  325. end
  326. else
  327. begin
  328. F := FindFirstFile( PKOLChar( GetNodePath( node ) + '\*.*' ), Find32 );
  329. if F <> INVALID_HANDLE_VALUE then
  330. begin
  331. while TRUE do
  332. begin
  333. if Find32.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
  334. if (Find32.cFileName <> KOLString( '.' )) and (Find32.cFileName <> '..') then
  335. begin
  336. HasSubDirs := TRUE;
  337. break;
  338. end;
  339. if not FindNextFile( F, Find32 ) then break;
  340. end;
  341. FindClose( F );
  342. end;
  343. end;
  344. end;
  345. {$endif wince}
  346. if not HasSubDirs then
  347. begin
  348. DirTree.TVExpand( node, TVE_COLLAPSE );
  349. n := DirTree.TVItemChild[ node ];
  350. while n <> 0 do
  351. begin
  352. ii := n;
  353. n := DirTree.TVItemNext[ n ];
  354. //DirTree.TVDelete( ii );
  355. DeleteNode( ii );
  356. end;
  357. end;
  358. if DirTree.TVItemParent[ node ] = 0 then HasSubDirs := TRUE;
  359. DirTree.TVItemHasChildren[ node ] := HasSubDirs;
  360. end;
  361. {$IFDEF DIRDLGEX_LINKSPANEL}
  362. procedure TOpenDirDialogEx.ClearLinks;
  363. var i: Integer;
  364. begin
  365. if LinksList = nil then Exit;
  366. LinksList.Clear;
  367. for i := LinksTape.ChildCount-1 downto 0 do
  368. LinksTape.Children[ i ].Free;
  369. LinksTape.Height := 8;
  370. LinksTape.Top := 0;
  371. end;
  372. function TOpenDirDialogEx.CollectLinks: PStrList;
  373. var i: Integer;
  374. begin
  375. Result := NewStrList;
  376. for i := 0 to LinksCount-1 do
  377. Result.Add( Links[ i ] );
  378. end;
  379. {$ENDIF DIRDLGEX_LINKSPANEL}
  380. procedure TOpenDirDialogEx.CreateDialogForm;
  381. var Sysimages: PImageList;
  382. BtOk, BtCancel, DTSubPanel: PControl;
  383. s: KOLString;
  384. begin
  385. if not Assigned( DialogForm ) then
  386. begin
  387. if Title = '' then Title := 'Select folder' {$ifdef wince} + ':' {$endif};
  388. {$ifndef wince}
  389. OleInit;
  390. {$endif wince}
  391. DialogForm := NewForm( Applet, '' ){$ifndef wince}.SetSize( 324, 330 ).CenterOnParent{$endif};
  392. DialogForm.OnDestroy := DestroyingForm;
  393. DialogForm.OnClose := DoNotClose;
  394. DialogForm.Tabulate;
  395. {$ifdef wince}
  396. DialogForm.Border := 4;
  397. DialogForm.Font.FontName:='Tahoma';
  398. DialogForm.Font.FontHeight:=-11;
  399. {$else}
  400. DialogForm.Border := 6;
  401. DialogForm.MinWidth := 324;
  402. DialogForm.MinHeight := 330;
  403. DialogForm.ExStyle := DialogForm.ExStyle or
  404. WS_EX_DLGMODALFRAME or WS_EX_WINDOWEDGE;
  405. DialogForm.Style := DialogForm.Style and
  406. not (WS_MINIMIZEBOX or WS_MAXIMIZEBOX);
  407. {$endif wince}
  408. Sysimages := NewImageList( DialogForm );
  409. Sysimages.LoadSystemIcons( TRUE );
  410. //DlgClient := NewPanel( DialogForm, esNone ).SetAlign(caClient);
  411. {$IFDEF USE_GRUSH}
  412. {$IFDEF TOGRUSH_OPTIONAL}
  413. if not NoGrush then
  414. {$ENDIF TOGRUSH_OPTIONAL}
  415. begin
  416. DialogForm.Color := clGRushLight;
  417. DlgClient := NewPanel( DialogForm, esNone ).SetAlign(caClient);
  418. //DlgClient.Border := 2;
  419. end
  420. {$IFDEF TOGRUSH_OPTIONAL}
  421. else DlgClient := DialogForm;
  422. {$ENDIF TOGRUSH_OPTIONAL}
  423. ;
  424. {$ELSE}
  425. DlgClient := DialogForm;
  426. {$ENDIF}
  427. {$IFDEF USE_GRUSH}
  428. {$IFDEF TOGRUSH_OPTIONAL}
  429. if not NoGrush then
  430. {$ENDIF TOGRUSH_OPTIONAL}
  431. begin
  432. DTSubPanel := KOL.NewPanel( DlgClient, esNone );
  433. DTSubPanel.Color := clWindow;
  434. DTSubPanel.Border := 2;
  435. BtnPanel := NewPanel( DlgClient, esTransparent )
  436. .SetSize( 0, 26 ).SetAlign(caBottom );
  437. //BtnPanel.Color := clGRushMedium;
  438. BtnPanel.Border := 2;
  439. DTSubPanel.SetAlign( caClient );
  440. DirTree := NewTreeView( DTSubPanel, [ tvoLinesRoot ], Sysimages, nil );
  441. {$IFNDEF DIRDLGEX_NO_DBLCLK_ON_NODE_OK}
  442. DirTree.OnMouseDblClk := DoubleClick;
  443. {$ENDIF}
  444. DirTree.Color := clWindow;
  445. DirTree.OnTVExpanding := DoExpanding;
  446. DirTree.SetAlign( caClient );
  447. end
  448. {$IFDEF TOGRUSH_OPTIONAL}
  449. else
  450. begin
  451. DTSubPanel := DlgClient;
  452. DirTree := NewTreeView( DTSubPanel, [ tvoLinesRoot ], Sysimages, nil );
  453. DirTree.Color := clWindow;
  454. DirTree.OnTVExpanding := DoExpanding;
  455. BtnPanel := NewPanel( DlgClient, esTransparent )
  456. .SetSize( 0, 26 ).SetAlign(caBottom );
  457. BtnPanel.Border := 2;
  458. DirTree.SetAlign( caClient );
  459. end
  460. {$ENDIF TOGRUSH_OPTIONAL}
  461. ;
  462. {$ELSE}
  463. {$ifdef wince}
  464. NewLabel(DlgClient, Title).AutoSize(True).SetAlign(caTop);
  465. {$endif wince}
  466. DTSubPanel := DlgClient;
  467. DirTree := NewTreeView( DTSubPanel, [ {$ifndef wince} tvoLinesRoot {$endif} ], Sysimages, nil );
  468. DirTree.Color := clWindow;
  469. DirTree.OnTVExpanding := DoExpanding;
  470. BtnPanel := NewPanel( DlgClient, esTransparent )
  471. .SetSize( 0, 26 ).SetAlign(caBottom );
  472. BtnPanel.Border := 2;
  473. DirTree.SetAlign( caClient );
  474. {$ENDIF}
  475. DTSubPanel.OnMessage := DoMsg;
  476. DlgClient := DTSubPanel; // !!!
  477. s := CancelCaption; if s = '' then s := 'Cancel';
  478. BtCancel := NewButton( BtnPanel, s );
  479. BtCancel.MinWidth := 75; BtCancel.OnClick := DoCancel;
  480. BtCancel.AutoSize( TRUE ).SetAlign( caRight );
  481. s := OKCaption; if s = '' then s := 'OK';
  482. BtOK := NewButton( BtnPanel, s );
  483. BtOK.MinWidth := 75; BtOK.OnClick := DoOK;
  484. BtOK.AutoSize( TRUE ).SetAlign( caRight );
  485. BtCancel.TabOrder := 1;
  486. BtOK.DefaultBtn := TRUE;
  487. BtCancel.CancelBtn := TRUE;
  488. DialogForm.OnShow := DoShow;
  489. {$IFDEF USE_GRUSH}
  490. {$IFDEF TOGRUSH_OPTIONAL}
  491. if not NoGrush then
  492. {$ENDIF TOGRUSH_OPTIONAL}
  493. begin
  494. BtOK.Transparent := TRUE;
  495. BtCancel.Transparent := TRUE;
  496. end;
  497. {$ENDIF USE_GRUSH}
  498. end;
  499. end;
  500. {$IFDEF DIRDLGEX_LINKSPANEL}
  501. procedure TOpenDirDialogEx.CreateLinksPanel;
  502. var BUp, BDn, BLt: PBitmap;
  503. {$IFDEF USE_GRUSH}
  504. cFrom: TColor;
  505. {$ENDIF USE_GRUSH}
  506. function NewArrowBitmap( const Pts: array of Integer ): PBitmap;
  507. begin
  508. Result := NewDibBitmap( 16, 8, pf32bit );
  509. Result.Canvas.Brush.Color := clBtnFace;
  510. Result.Canvas.FillRect( Result.BoundsRect );
  511. Result.Canvas.Brush.Color := clBlack;
  512. Result.Canvas.Polygon( [ MakePoint( Pts[ 0 ], Pts[ 1 ] ),
  513. MakePoint( Pts[ 2 ], Pts[ 3 ] ),
  514. MakePoint( Pts[ 4 ], Pts[ 5 ] ),
  515. MakePoint( Pts[ 6 ], Pts[ 7 ] ) ] );
  516. end;
  517. var PnUp, LUp, PnDn, LDn, PnLt, LLt: PControl;
  518. d: Integer;
  519. begin
  520. if LinksPanel <> nil then Exit;
  521. GetDialogForm;
  522. BUp := NewArrowBitmap( [ 2, 6, 7, 1, 8, 1, 13, 6 ] );
  523. BDn := NewArrowBitmap( [ 2, 1, 7, 6, 8, 6, 13, 1 ] );
  524. BLt := NewArrowBitmap( [ 11, 0, 4, 3, 4, 4, 11, 7 ] );
  525. LinksPanel := NewPanel( DlgClient, esLowered )
  526. .SetSize( {$IFDEF DIRDLGEX_BIGGERPANEL} 14 + {$ENDIF} 64, 0 )
  527. .SetAlign( caLeft );
  528. //LinksPanel.OnShow := LinksPanelShowEvent;
  529. LinksPanel.Border := 2;
  530. {$IFNDEF DIRDLGEX_STDFONT}
  531. {$ifndef wince}
  532. LinksPanel.Font.FontName := 'Arial';
  533. LinksPanel.Font.FontHeight := 14;
  534. {$endif wince}
  535. {$ENDIF DIRDLGEX_STDFONT}
  536. d := 0;
  537. {$IFDEF USE_GRUSH}
  538. {$IFDEF TOGRUSH_OPTIONAL}
  539. if not NoGrush then
  540. {$ENDIF TOGRUSH_OPTIONAL}
  541. d := 2;
  542. {$ENDIF USE_GRUSH}
  543. NewPanelWithSingleButtonToolbar( LinksPanel, LinksPanel.Width-6+d, 15, caTop,
  544. BUp, '', '', PnUp, LUp, nil, LinksUpClick, LinksUpDnStop, nil );
  545. NewPanelWithSingleButtonToolbar( LinksPanel, LinksPanel.Width-6+d, 15, caBottom,
  546. BDn, '', '', PnDn, LDn, nil, LinksDnClick, LinksUpDnStop, nil );
  547. NewPanelWithSingleButtonToolbar( BtnPanel, 20, 16, caNone,
  548. BLt, '', '', PnLt, LLt, LinksAddClick, nil, nil, nil ); PnLt.Width := 20;
  549. {$ifdef wince}
  550. PnLt.Align:=caLeft;
  551. {$else}
  552. PnLt.SetPosition( 68, 0 );
  553. PnLt.Transparent := TRUE;
  554. LLt.Transparent := TRUE;
  555. {$endif wince}
  556. LinksBox := NewPaintBox( LinksPanel ).SetAlign(caClient);
  557. LinksBox.Border := 0;
  558. LinksTape := NewPaintBox( LinksBox ).SetSize( LinksBox.Width, 0 );
  559. //LinksTape.DoubleBuffered := TRUE;
  560. {$IFDEF USE_GRUSH}
  561. {$IFDEF TOGRUSH_OPTIONAL}
  562. if not NoGrush then
  563. {$ENDIF TOGRUSH_OPTIONAL}
  564. begin
  565. LinksTape.Border := 2;
  566. LinksTape.MarginLeft := -2;
  567. LinksTape.MarginRight := -2;
  568. LinksTape.MarginTop := 2;
  569. LinksTape.MarginBottom := 2;
  570. //LinksPanel.Transparent := TRUE;
  571. PGRushControl( LinksPanel ).All_GradientStyle := gsHorizontal;
  572. cFrom := PGRushControl( LinksPanel ).Def_ColorFrom;
  573. PGRushControl( LinksPanel ).All_ColorTo := {
  574. PGRushControl( LinksPanel ).Def_ColorFrom;
  575. PGRushControl( LinksPanel ).All_ColorFrom :=} cFrom;
  576. LinksBox.Color := cFrom;
  577. //LinksAdd.Left := LinksAdd.Left + 6;
  578. end
  579. {$IFDEF TOGRUSH_OPTIONAL}
  580. else
  581. begin
  582. //LinksTape.Border := 0;
  583. end
  584. {$ENDIF TOGRUSH_OPTIONAL}
  585. ;
  586. {$ELSE not USE_GRUSH}
  587. //LinksTape.Border := 0;
  588. {$ENDIF USE_GRUSH}
  589. LinksPanel.Visible := FALSE;
  590. LinksRollTimer := NewTimer( 50 );
  591. //LinksRollTimer.Enabled := FALSE;
  592. LinksRollTimer.OnTimer := LinksRollTimerTimer;
  593. LinksPanel.Add2AutoFree( LinksRollTimer );
  594. end;
  595. {$ENDIF DIRDLGEX_LINKSPANEL}
  596. procedure TOpenDirDialogEx.DeleteNode(node: Integer);
  597. function NodeIsParentOf( node, parent: Integer ): Boolean;
  598. begin
  599. Result := TRUE;
  600. while node <> 0 do
  601. begin
  602. if node = parent then Exit;
  603. node := DirTree.TVItemParent[ node ];
  604. end;
  605. Result := FALSE;
  606. end;
  607. var sel, n: Integer;
  608. begin
  609. sel := DirTree.TVSelected;
  610. if (sel <> 0) and NodeIsParentOf( sel, node ) then
  611. begin
  612. n := DirTree.TVItemPrevious[ node ];
  613. if n = 0 then
  614. n := DirTree.TVItemNext[ node ];
  615. DirTree.TVSelected := n;
  616. end;
  617. DirTree.TVDelete( node );
  618. end;
  619. destructor TOpenDirDialogEx.Destroy;
  620. begin
  621. Free_And_Nil( DialogForm );
  622. FPath := '';
  623. FRecycledName := '';
  624. OKCaption := '';
  625. CancelCaption := '';
  626. Title := '';
  627. {$IFDEF DIRDLGEX_LINKSPANEL}
  628. LinksList.Free;
  629. {$ENDIF DIRDLGEX_LINKSPANEL}
  630. inherited;
  631. {$ifndef wince}
  632. OleUnInit;
  633. {$endif wince}
  634. end;
  635. procedure TOpenDirDialogEx.DestroyingForm(Sender: PObj);
  636. begin
  637. DialogForm := nil;
  638. end;
  639. procedure TOpenDirDialogEx.DoCancel(Sender: PObj);
  640. begin
  641. DialogForm.ModalResult := -1;
  642. end;
  643. function TOpenDirDialogEx.DoExpanding(Sender: PControl; Item: THandle;
  644. Expand: Boolean): Boolean;
  645. begin
  646. Result := FALSE;
  647. if RescanningNode or RescanningTree then Exit;
  648. if Expand then
  649. RescanNode( Item );
  650. end;
  651. function TOpenDirDialogEx.DoFilterAttrs(Attrs: DWORD; const APath: KOLString): Boolean;
  652. begin
  653. Result := (Attrs and FilterAttrs = 0);
  654. if not Result then Exit;
  655. if FilterRecycled then
  656. begin
  657. if (Attrs and (FILE_ATTRIBUTE_SYSTEM or FILE_ATTRIBUTE_HIDDEN) =
  658. (FILE_ATTRIBUTE_SYSTEM or FILE_ATTRIBUTE_HIDDEN))
  659. then
  660. //if StrEq( APath, 'RECYCLED' ) then
  661. Result := FALSE;
  662. end;
  663. end;
  664. function TOpenDirDialogEx.DoMsg(var Msg: TMsg; var Rslt: Integer): Boolean;
  665. var NMHdr: PNMHdr;
  666. NMCustomDraw: PNMCustomDraw;
  667. i: Integer;
  668. begin
  669. Result := FALSE;
  670. if DialogForm = nil then Exit;
  671. if Msg.message = WM_USER_RESCANTREE then
  672. begin
  673. Rescantree;
  674. DirTree.Focused := TRUE;
  675. Result := TRUE;
  676. end
  677. else
  678. if Msg.message = WM_NOTIFY then
  679. begin // îòëàâëèâàåòñÿ ìîìåíò îòðèñîâêè êàæäîãî óçëà, ÷òîáû ïðîâåðèòü íàëè÷èå
  680. // â íåì äî÷åðíèõ ïàïîê, è "ïîêàçàòü" êíîïêó [+], åñëè åñòü
  681. NMHdr := Pointer( Msg.lParam );
  682. if DirTree = nil then Exit;
  683. if NMHdr.hwndFrom = DirTree.Handle then
  684. CASE LongInt(NMHdr.code) OF
  685. NM_CUSTOMDRAW:
  686. begin
  687. NMCustomDraw := Pointer( NMHdr );
  688. if NMCustomDraw.dwDrawStage = CDDS_ITEMPOSTPAINT then
  689. begin
  690. i := NMCustomDraw.dwItemSpec;
  691. if DirTree.TVItemData[ i ] = nil then // óçåë åùå íå ïðîâåðÿëñÿ
  692. begin
  693. CheckNodeHasChildren( i ); // ïðîâåðèòü óçåë
  694. DirTree.TVItemData[ i ] := Pointer( 1 ); // ôëàã = "ïðîâåðåí"
  695. end;
  696. Rslt := CDRF_DODEFAULT; // ïóñòü ðèñóåò ñåáÿ ñàì êàê îáû÷íî
  697. end
  698. else
  699. if NMCustomDraw.dwDrawStage = CDDS_PREPAINT then
  700. Rslt := CDRF_NOTIFYITEMDRAW // ñîîáùèòü äëÿ êàæäîãî óçëà íà ñòàäèè CDDS_ITEMPREPAINT
  701. else
  702. Rslt := CDRF_NOTIFYPOSTPAINT; // ïðè CDDS_ITEMPREPAINT: ñîîáùèòü î CDDS_ITEMPOSTPAINT
  703. Result := TRUE;
  704. end;
  705. END;
  706. end;
  707. end;
  708. procedure TOpenDirDialogEx.DoNotClose(Sender: PObj;
  709. var Accept: Boolean);
  710. begin
  711. Accept := FALSE;
  712. DialogForm.Hide;
  713. end;
  714. procedure TOpenDirDialogEx.DoOK(Sender: PObj);
  715. begin
  716. DialogForm.ModalResult := 1;
  717. end;
  718. procedure TOpenDirDialogEx.DoShow(Sender: PObj);
  719. begin
  720. DlgClient.PostMsg( WM_USER_RESCANTREE, 0, 0 );
  721. {$IFDEF DIRDLGEX_LINKSPANEL}
  722. if LinksPanelOn and Assigned( LinksTape ) then
  723. begin
  724. Global_Align( LinksTape );
  725. SetupLinksTapeHeight;
  726. end;
  727. {$ENDIF DIRDLGEX_LINKSPANEL}
  728. end;
  729. type
  730. PControl_ = ^TControl_;
  731. TControl_ = object( TControl )
  732. end;
  733. procedure TOpenDirDialogEx.DoubleClick(Sender: PControl;
  734. var M: TMouseEventData);
  735. var N: DWORD;
  736. Where: DWORD;
  737. begin
  738. N := DirTree.TVItemAtPos( M.X, M.Y, Where );
  739. if (N = DirTree.TVSelected) and
  740. not DirTree.TVItemHasChildren[ N ] then
  741. Form.ModalResult := 1;
  742. end;
  743. function TOpenDirDialogEx.Execute: Boolean;
  744. var ParentForm: PControl_;
  745. begin
  746. CreateDialogForm;
  747. DlgClient.ActiveControl := DirTree;
  748. {$ifndef wince}
  749. DialogForm.Caption := Title;
  750. {$endif wince}
  751. ParentForm := PControl_( Applet.ActiveControl );
  752. if ParentForm <> nil then
  753. begin
  754. if not ParentForm.fIsForm then
  755. ParentForm := PControl_( Applet );
  756. end;
  757. if ParentForm <> nil then
  758. DialogForm.StayOnTop := ParentForm.StayOnTop;
  759. DialogForm.ShowModal;
  760. DialogForm.Hide;
  761. if ParentForm <> nil then
  762. SetForegroundWindow( ParentForm.Handle );
  763. Result := DialogForm.ModalResult >= 0;
  764. if Result then
  765. begin
  766. Path := IncludeTrailingPathDelimiter(
  767. GetNodePath( DirTree.TVSelected ) );
  768. end;
  769. end;
  770. function TOpenDirDialogEx.GetDialogForm: PControl;
  771. begin
  772. CreateDialogForm;
  773. Result := DialogForm;
  774. end;
  775. function TOpenDirDialogEx.GetFindFirstFileEx: TFindFirstFileEx;
  776. begin
  777. {$ifdef wince}
  778. FFindFirstFileEx:=@FindFirstFileEx;
  779. {$else}
  780. if not Assigned( FFindFirstFileEx ) then
  781. begin
  782. k32 := GetModuleHandle( 'kernel32.dll' );
  783. FFindFirstFileEx := GetProcAddress( k32, 'FindFirstFileEx' + {$ifdef UNICODE_CTRLS}'W'{$else}'A'{$endif} );
  784. end;
  785. {$endif wince}
  786. Result := FFindFirstFileEx;
  787. end;
  788. function TOpenDirDialogEx.GetNodePath(N: THandle): KOLString;
  789. begin
  790. Result:=DirTree.TVItemPath(N, '\');
  791. {$ifdef wince}
  792. System.Delete(Result, 1, 9);
  793. {$endif wince}
  794. end;
  795. {$IFDEF DIRDLGEX_LINKSPANEL}
  796. function TOpenDirDialogEx.GetLinks(idx: Integer): KOLString;
  797. begin
  798. Result := '';
  799. if (LinksList <> nil) and (LinksList.Count > idx) then
  800. Result := LinksList.Items[ idx ];
  801. end;
  802. function TOpenDirDialogEx.GetLinksCount: Integer;
  803. begin
  804. Result := 0;
  805. if LinksList <> nil then Result := LinksList.Count;
  806. end;
  807. function TOpenDirDialogEx.GetLinksPanelOn: Boolean;
  808. begin
  809. Result := (LinksPanel <> nil) and (LinksPanel.Visible);
  810. end;
  811. procedure TOpenDirDialogEx.LinkClick(Sender: PObj);
  812. var s, CurPath: KOLString;
  813. begin
  814. s := IncludeTrailingPathDelimiter(
  815. PKOLChar( PControl( Sender ).CustomData ) );
  816. if DirectoryExists( s ) then
  817. begin
  818. CurPath := IncludeTrailingPathDelimiter(
  819. GetNodePath( DirTree.TVSelected ) );
  820. if StrEq( CurPath, s ) then
  821. Form.ModalResult := 1
  822. else Path := s;
  823. end;
  824. end;
  825. function TOpenDirDialogEx.LinkPresent(const s: KOLString): Boolean;
  826. begin
  827. Result := (LinksList <> nil) and
  828. (LinksList.IndexOf_NoCase(
  829. IncludeTrailingPathDelimiter( s ) ) >= 0);
  830. end;
  831. procedure TOpenDirDialogEx.LinksAddClick(Sender: PObj);
  832. var SL: PStrList;
  833. CurPath: KOLString;
  834. begin
  835. CurPath := IncludeTrailingPathDelimiter(
  836. GetNodePath( DirTree.TVSelected ) );
  837. SL := NewStrList;
  838. if DirectoryExists( CurPath ) then
  839. begin
  840. SL.Add( CurPath );
  841. AddLinks( SL );
  842. end;
  843. SL.Free;
  844. end;
  845. procedure TOpenDirDialogEx.LinksDnClick(Sender: PControl; var Mouse: TMouseEventData);
  846. begin
  847. LinksRollTimer.Tag := 1;
  848. LinksRollTimer.Enabled := TRUE;
  849. end;
  850. {procedure TOpenDirDialogEx.LinksPanelShowEvent(Sender: PObj);
  851. begin
  852. end;}
  853. procedure TOpenDirDialogEx.LinksRollTimerTimer(Sender: PObj);
  854. var NewTop, d: Integer;
  855. begin
  856. d := Integer( LinksRollTimer.Tag );
  857. LinksRollTimer.Tag := Integer( LinksRollTimer.Tag ) + Sgn( d );
  858. NewTop := LinksTape.Top - (Sgn( d ) + d div 4) * 2;
  859. if (d > 0) and
  860. (NewTop + LinksTape.Height < LinksBox.Height) and
  861. (LinksTape.Top <= 0) then
  862. begin
  863. NewTop := LinksBox.Height - LinksTape.Height;
  864. if NewTop > 0 then
  865. NewTop := 0;
  866. end;
  867. if (d < 0) and (NewTop > 0) then NewTop := 0;
  868. if (NewTop = LinksTape.Top) or not Form.Visible then
  869. LinksRollTimer.Enabled := FALSE;
  870. LinksTape.Top := NewTop;
  871. LinksTape.Update;
  872. end;
  873. procedure TOpenDirDialogEx.LinksUpClick(Sender: PControl; var Mouse: TMouseEventData);
  874. begin
  875. LinksRollTimer.Tag := DWORD( -1 );
  876. LinksRollTimer.Enabled := TRUE;
  877. end;
  878. procedure TOpenDirDialogEx.LinksUpDnStop(Sender: PControl; var Mouse: TMouseEventData);
  879. begin
  880. LinksRollTimer.Enabled := FALSE;
  881. end;
  882. {$ENDIF DIRDLGEX_LINKSPANEL}
  883. function TOpenDirDialogEx.RemoteIconSysIdx: Integer;
  884. begin
  885. if FRemoteIconSysIdx = 0 then
  886. begin
  887. if DirectoryExists( '\\localhost\' ) then
  888. FRemoteIconSysIdx := DirIconSysIdxOffline( '\\localhost\' )
  889. else
  890. FRemoteIconSysIdx := DirIconSysIdxOffline( 'C:\' );
  891. end;
  892. Result := FRemoteIconSysIdx;
  893. end;
  894. {$IFDEF DIRDLGEX_LINKSPANEL}
  895. procedure TOpenDirDialogEx.RemoveLink(const s: KOLString);
  896. var i: Integer;
  897. Pn: PControl;
  898. begin
  899. i := LinksList.IndexOf( IncludeTrailingPathDelimiter( s ) );
  900. if i >= 0 then
  901. begin
  902. Pn := Pointer( LinksList.Objects[ i ] );
  903. Pn.Free;
  904. LinksList.Delete( i );
  905. end;
  906. Global_Align( LinksTape );
  907. SetupLinksTapeHeight;
  908. end;
  909. procedure TOpenDirDialogEx.RemoveLinkClick(Sender: PMenu; Item: Integer);
  910. var Pn: PControl;
  911. i: Integer;
  912. begin
  913. Form.ModalResult := 0; //????
  914. Pn := Sender.CurCtl;
  915. if Pn <> nil then
  916. begin
  917. i := LinksList.IndexOfObj( Pn );
  918. if i >= 0 then
  919. begin
  920. RemoveLink( LinksList.Items[ i ] );
  921. end;
  922. end;
  923. end;
  924. {$ENDIF DIRDLGEX_LINKSPANEL}
  925. procedure TOpenDirDialogEx.RescanDisks;
  926. begin
  927. RescanNode( 0 );
  928. end;
  929. procedure TOpenDirDialogEx.RescanNode(node: Integer);
  930. { (Ïåðå)ñêàíèðîâàíèå ïîääèðåêòîðèé â çàäàííîé óçëîì node ðîäèòåëüñêîé ïàïêå.
  931. Åñëè node = 0, òî ñêàíèðóåòñÿ ñïèñîê äèñêîâ íà óðîâíå êîðíÿ äåðåâà.
  932. }
  933. var p, s: KOLString;
  934. i, j, n, d, m, ii: Integer;
  935. Find32: TWin32FindData;
  936. F: THandle;
  937. SL: PStrListEx;
  938. {$ifndef wince}
  939. DL: PDirList;
  940. disk: Char;
  941. {$endif wince}
  942. //test: KOLString;
  943. begin
  944. if AppletTerminated or not AppletRunning then Exit;
  945. RescanningNode := TRUE;
  946. //Applet.ProcessMessages;
  947. TRY
  948. // âû÷èñëÿåòñÿ ïóòü ê ðîäèòåëüñêîé ïàïêå èëè äèñêó (ïóñòî, åñëè âåðõíèé óðîâåíü)
  949. p := '';
  950. if node <> 0 then
  951. p := IncludeTrailingPathDelimiter( GetNodePath( node ) );
  952. // â SL íàêàïëèâàåòñÿ ñïèñîê äî÷åðíèõ äèðåêòîðèé (èëè äèñêîâ)
  953. SL := NewStrListEx;
  954. TRY
  955. if node = 0 then
  956. begin
  957. {$ifdef wince}
  958. SL.AddObject( 'My Device', 0 );
  959. {$else}
  960. for disk := 'A' to 'Z' do
  961. begin
  962. case GetDriveType( PKOLChar( KOLString(disk) + ':\' ) ) of
  963. DRIVE_FIXED, DRIVE_RAMDISK: ii := 0;
  964. DRIVE_REMOVABLE, DRIVE_CDROM: ii := 1;
  965. DRIVE_REMOTE: ii := 2;
  966. else ii := -1;
  967. end;
  968. if ii >= 0 then SL.AddObject( disk + ':', ii );
  969. end;
  970. {$endif wince}
  971. end
  972. else
  973. {$ifndef wince}
  974. if WinVer >= wvNT then // èñïîëüçóåòñÿ áîëåå áûñòðûé âàðèàíò - äëÿ NT/2K/XP
  975. {$endif wince}
  976. begin
  977. _FindFirstFileEx;
  978. F := FFindFirstFileEx( PKOLChar( p + '*.*' ), FindExInfoStandard, @ Find32,
  979. FindExSearchLimitToDirectories, nil, 0 );
  980. if F <> INVALID_HANDLE_VALUE then
  981. begin
  982. TRY
  983. while TRUE do
  984. begin
  985. if Find32.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
  986. if (Find32.cFileName <> KOLString( '.' )) and (Find32.cFileName <> '..') then
  987. if DoFilterAttrs( Find32.dwFileAttributes, Find32.{$ifdef wince}cFileName{$else}cAlternateFileName{$endif} ) then
  988. SL.Add( Find32.cFileName );
  989. if not FindNextFile( F, Find32 ) then break;
  990. end;
  991. SL.Sort( FALSE );
  992. FINALLY
  993. FindClose( F );
  994. END;
  995. end;
  996. {$ifndef wince}
  997. end
  998. else
  999. begin
  1000. DL := NewDirListEx( p, '*.*;*', FILE_ATTRIBUTE_DIRECTORY );
  1001. TRY
  1002. DL.Sort( [ ] );
  1003. for i := 0 to DL.Count-1 do
  1004. if DoFilterAttrs( DL.Items[ i ].dwFileAttributes,
  1005. DL.Items[ i ].cAlternateFileName ) then
  1006. SL.Add( DL.Names[ i ] );
  1007. FINALLY
  1008. DL.Free;
  1009. END;
  1010. {$endif wince}
  1011. end;
  1012. // òåïåðü ïðîñìàòðèâàþòñÿ âñå äî÷åðíèå óçëû ðîäèòåëÿ node (èëè äèñêè
  1013. // íà êîðíåâîì óðîâíå)
  1014. if node = 0 then
  1015. n := DirTree.TVRoot
  1016. else
  1017. n := DirTree.TVItemChild[ node ];
  1018. for i := 0 to SL.Count do
  1019. begin
  1020. //test := DirTree.TVItemText[ n ];
  1021. //test := SL.Items[ i ];
  1022. // ïîêà î÷åðåäíîå èìÿ â ñïèñêå áîëüøå ÷åì òî ÷òî â î÷åðåäíîì óçëå
  1023. while (n <> 0) and
  1024. ( (i >= SL.Count) or
  1025. (AnsiCompareStrNoCase( SL.Items[ i ], DirTree.TVItemText[ n ] ) > 0)
  1026. ) do
  1027. begin
  1028. //test := DirTree.TVItemText[ n ];
  1029. //test := SL.Items[ i ];
  1030. // åñëè äèðåêòîðèÿ â òåêóùåì óçëå îòñóòñòâóåò â ñïèñêå, òî îíà óäàëåíà
  1031. // è åå ñëåäóåò óäàëèòü èç äåðåâà ïîñëå ïåðåõîäà ê ñëåäóþùåìó óçëó
  1032. d := n;
  1033. s := DirTree.TVItemText[ n ];
  1034. for j := 0 to SL.Count-1 do
  1035. if AnsiCompareStrNoCase( SL.Items[ j ], s ) = 0 then
  1036. begin
  1037. d := 0; break; // åñòü òàêàÿ â ñïèñêå, íå óäàëÿòü
  1038. end;
  1039. if d = 0 then
  1040. DirTree.TVItemData[ n ] := nil; // ñáðîñ ôëàæêà "äî÷åðíèå ïðîâåðåíû"
  1041. n := DirTree.TVItemNext[ n ]; // ïåðåõîä ê ñëåäóþùåìó óçëó äåðåâà
  1042. if d <> 0 then // óäàëÿåòñÿ óçåë íåñóùåñòâóþøåé äèðåêòîðèè
  1043. //DirTree.TVDelete( d );
  1044. DeleteNode( d );
  1045. end;
  1046. if i >= SL.Count then break;
  1047. if (n <> 0) and
  1048. (AnsiCompareStrNoCase( SL.Items[ i ], DirTree.TVItemText[ n ] ) = 0) then
  1049. begin
  1050. DirTree.TVItemData[ n ] := nil; // ñáðîñ ôëàæêà "äî÷åðíèå ïðîâåðåíû"
  1051. n := DirTree.TVItemNext[ n ]; // ïåðåõîä ê ñëåäóþùåìó óçëó äåðåâà
  1052. continue;
  1053. end;
  1054. // îñòàåòñÿ ñëó÷àé, êîãäà (íîâîå) èìÿ äèðåêòîðèè ìåíüøå ÷åì èìÿ â
  1055. // î÷åðåäíîì óçëå (èëè óçëû èñ÷åðïàíû): íàäî äîáàâèòü åãî ïåðåä ýòèì óçëîì
  1056. // (â êîíåö ñïèñêà óçëîâ):
  1057. if n = 0 then
  1058. m := DirTree.TVInsert( node, TVI_LAST, SL.Items[ i ] )
  1059. else
  1060. begin
  1061. m := DirTree.TVItemPrevious[ n ];
  1062. if m = 0 then
  1063. m := DirTree.TVInsert( node, TVI_FIRST, SL.Items[ i ] )
  1064. else
  1065. m := DirTree.TVInsert( node, m, SL.Items[ i ] );
  1066. end;
  1067. if (SL.Objects[ i ] = 1) and FastScan then
  1068. SL.Objects[ i ] := 2;
  1069. CASE SL.Objects[ i ] OF
  1070. 0{,1}: ii := FileIconSystemIdx( p + SL.Items[ i ]{$ifndef wince} + '\' {$endif} );
  1071. {$ifndef wince}
  1072. 1: ii := DirIconSysIdxOffline( p + SL.Items[ i ] + '\' );
  1073. {2:}else ii := RemoteIconSysIdx;
  1074. {$endif wince}
  1075. END;
  1076. DirTree.TVItemImage[ m ] := ii;
  1077. DirTree.TVItemSelImg[ m ] := ii;
  1078. end;
  1079. if SL.Count = 0 then
  1080. if node <> 0 then
  1081. DirTree.TVItemHasChildren[ node ] := FALSE;
  1082. FINALLY
  1083. SL.Free;
  1084. END;
  1085. FINALLY
  1086. RescanningNode := FALSE;
  1087. END;
  1088. end;
  1089. procedure TOpenDirDialogEx.Rescantree;
  1090. var s, n, {$ifndef wince}d,{$endif} e: KOLString;
  1091. node, parent, ii: Integer;
  1092. begin
  1093. RescanningTree := TRUE;
  1094. //DirTree.BeginUpdate;
  1095. TRY
  1096. RescanDisks;
  1097. if (Path = '') or not DirectoryExists( Path ) then Path := GetWorkDir;
  1098. node := DirTree.TVSelected;
  1099. if (node = 0)
  1100. // äåðåâî ïóñòî: ïåðâîíà÷àëüíîå çàïîëíåíèå - îò òåêóùåãî óçëà ê êîðíþ (äèñêó)
  1101. // è äîáàâëåíèå ñïèñêà âñåõ äèñêîâ íà âåðõíåì óðîâíå
  1102. OR
  1103. (AnsiCompareStrNoCase( IncludeTrailingPathDelimiter(
  1104. GetNodePath( node ) ),
  1105. IncludeTrailingPathDelimiter( Path ) ) <> 0 )
  1106. // èëè òåêóùèé óçåë â äåðåâå îòëè÷àòñÿ îò òîãî, ÷òî óêàçàíî â Path
  1107. then
  1108. begin
  1109. s := Path;
  1110. {$ifdef wince}
  1111. node:=DirTree.TVRoot;
  1112. if s = '\' then
  1113. RescanNode( node );
  1114. DirTree.TVExpand( node, TVE_EXPAND );
  1115. {$else}
  1116. node := 0;
  1117. {$endif wince}
  1118. e := '';
  1119. // ïàðñèðóåì ïóòü, ïî î÷åðåäè îïóñàÿñü âñå íèæå ê óêàçàííîé ïàïêå
  1120. while s <> '' do
  1121. begin
  1122. if AppletTerminated or not AppletRunning then Exit;
  1123. n := Parse( s, '\/' );
  1124. if n = '' then continue;
  1125. {$ifndef wince}
  1126. if (n[ Length( n ) ] <> ':') and (pos( ':', n ) > 0) then
  1127. begin
  1128. d := Parse( n, ':' ) + ':';
  1129. s := n + '\' + s;
  1130. n := d;
  1131. end;
  1132. {$endif wince}
  1133. // n = î÷åðåäíîé óçåë, êîòîðûé íàäî ëèáî íàéòè ñðåäè äåòîê node,
  1134. // ëèáî ïîñòðîèòü â ýòîì ñïèñêå, åñëè åãî òàì íåò
  1135. parent := node;
  1136. if parent = 0 then
  1137. node := DirTree.TVRoot
  1138. else begin
  1139. {$ifndef wince}
  1140. if (Length( n ) = 2) and (n[ 2 ] = ':') then
  1141. begin
  1142. if not IntIn( GetDriveType( PKOLChar( n + '\' ) ),
  1143. [ DRIVE_REMOVABLE, DRIVE_REMOTE, DRIVE_CDROM ] ) then
  1144. RescanNode( parent );
  1145. end
  1146. else
  1147. {$endif wince}
  1148. RescanNode( parent );
  1149. node := DirTree.TVItemChild[ parent ];
  1150. end;
  1151. while node <> 0 do
  1152. begin
  1153. if AnsiCompareStrNoCase( DirTree.TVItemText[ node ], n ) = 0 then
  1154. break;
  1155. node := DirTree.TVItemNext[ node ];
  1156. end;
  1157. if node = 0 then
  1158. node := DirTree.TVInsert( parent, TVI_LAST, n );
  1159. if parent <> 0 then
  1160. DirTree.TVExpand( parent, TVE_EXPAND );
  1161. e := e + n + '\'; // ïî äîðîãå â e ñòðîèì ïîëíûé ïóòü
  1162. ii := FileIconSystemIdx( e );
  1163. DirTree.TVItemImage[ node ] := ii;
  1164. DirTree.TVItemSelImg[ node ] := ii;
  1165. end;
  1166. DirTree.TVSelected := node;
  1167. end;
  1168. if node <> 0 then
  1169. DirTree.Perform( TVM_ENSUREVISIBLE, 0, node );
  1170. FINALLY
  1171. RescanningTree := FALSE;
  1172. //DirTree.EndUpdate;
  1173. END;
  1174. end;
  1175. {$IFDEF DIRDLGEX_LINKSPANEL}
  1176. procedure TOpenDirDialogEx.SetLinks(idx: Integer; const Value: KOLString);
  1177. var Bar, Pn: PControl;
  1178. Bmp: PBitmap;
  1179. Ico: PIcon;
  1180. s: KOLString;
  1181. H: Integer;
  1182. begin
  1183. CreateLinksPanel;
  1184. s := ExcludeTrailingPathDelimiter( Value );
  1185. if LinksList = nil then
  1186. LinksList := NewStrListEx;
  1187. while LinksList.Count <= idx do
  1188. LinksList.AddObject( '', 0 );
  1189. if LinksList.Objects[ idx ] <> 0 then
  1190. begin
  1191. PObj( Pointer( LinksList.Objects[ idx ] ) ).Free;
  1192. end;
  1193. Bmp := NewDibBitmap( 32, 32, pf32bit );
  1194. Bmp.Canvas.Brush.Color := clBtnFace;
  1195. Bmp.Canvas.FillRect( Bmp.BoundsRect );
  1196. if LinksImgList = nil then
  1197. begin
  1198. LinksImgList := NewImageList( LinksPanel );
  1199. LinksImgList.LoadSystemIcons( FALSE );
  1200. end;
  1201. Ico := NewIcon;
  1202. Ico.Handle := LinksImgList.ExtractIcon( FileIconSystemIdx( s ) );
  1203. Ico.Draw( Bmp.Canvas.Handle, 0, 0 );
  1204. Ico.Free;
  1205. if LinksPopupMenu = nil then
  1206. begin
  1207. NewMenu( Form, 0, [ '' ], nil );
  1208. LinksPopupMenu := NewMenu( Form, 0, [ '&Remove link' ], nil );
  1209. LinksPopupMenu.AssignEvents( 0, [ RemoveLinkClick ] );
  1210. end;
  1211. H := 60;
  1212. {$IFDEF DIRDLGEX_BIGGERPANEL}
  1213. {$IFDEF USE_GRUSH}
  1214. {$IFDEF TOGRUSH_OPTIONAL}
  1215. if not NoGrush then
  1216. {$ENDIF TOGRUSH_OPTIONAL}
  1217. inc( H, 14 );
  1218. {$ENDIF USE_GRUSH}
  1219. {$ENDIF DIRDLGEX_BIGGERPANEL}
  1220. NewPanelWithSingleButtonToolbar( LinksTape, LinksBox.Width,
  1221. H, caTop, Bmp,
  1222. ExtractFileName( s ), s, Pn, Bar, LinkClick, nil, nil, LinksPopupMenu );
  1223. Pn.CreateWindow;
  1224. LinksList.Items[ idx ] := IncludeTrailingPathDelimiter( Value );
  1225. LinksList.Objects[ idx ] := DWORD( Pn );
  1226. SetUpTaborders;
  1227. SetupLinksTapeHeight;
  1228. end;
  1229. procedure TOpenDirDialogEx.SetLinksPanelOn(const Value: Boolean);
  1230. begin
  1231. if LinksPanelOn = Value then Exit;
  1232. GetDialogForm;
  1233. if Assigned( LinksPanel ) then
  1234. LinksPanel.Visible := Value;
  1235. if not Value then LinksAdd.Visible := FALSE
  1236. else
  1237. begin
  1238. CreateLinksPanel;
  1239. LinksPanel.Visible := TRUE;
  1240. end;
  1241. end;
  1242. {$ENDIF DIRDLGEX_LINKSPANEL}
  1243. procedure TOpenDirDialogEx.SetPath(const Value: KOLString);
  1244. begin
  1245. FPath := Value;
  1246. if FPath <> '' then
  1247. FPath := IncludeTrailingPathDelimiter( FPath );
  1248. if Assigned( DialogForm ) and (DialogForm.Visible) then
  1249. Rescantree;
  1250. end;
  1251. {$IFDEF DIRDLGEX_LINKSPANEL}
  1252. procedure TOpenDirDialogEx.SetupLinksTapeHeight;
  1253. var H: Integer;
  1254. Pn: PControl;
  1255. begin
  1256. H := 0;
  1257. if LinksList.Count > 0 then
  1258. begin
  1259. Pn := Pointer( LinksList.Objects[ LinksList.Count-1 ] );
  1260. H := Pn.Top + Pn.Height;
  1261. end;
  1262. LinksTape.Height := H + 4;
  1263. end;
  1264. procedure TOpenDirDialogEx.SetUpTaborders;
  1265. var i: Integer;
  1266. Pn: PControl;
  1267. begin
  1268. for i := 0 to LinksCount-1 do
  1269. begin
  1270. Pn := Pointer( LinksList.Objects[ i ] );
  1271. Pn.TabOrder := i;
  1272. end;
  1273. end;
  1274. {$ENDIF DIRDLGEX_LINKSPANEL}
  1275. {$ifndef read_implementation}
  1276. end.
  1277. {$endif read_implementation}