DriveView.pas 124 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141
  1. unit DriveView;
  2. {==================================================================
  3. Component TDriveView / Version 2.6, January 2000
  4. ==================================================================
  5. Description:
  6. ============
  7. Displays the the directory structure of all drives as treeview
  8. with shell icons. Complete drag&Drop support for files and
  9. directories.
  10. Author:
  11. =======
  12. (c) Ingo Eckel 1998, 1999
  13. Sodener Weg 38
  14. 65812 Bad Soden
  15. Germany
  16. V2.6:
  17. - Shows "shared"-symbol with directories
  18. - Delphi5 compatible
  19. For detailed documentation and history see TDriveView.htm.
  20. {==================================================================}
  21. interface
  22. {$IFDEF USE_DRIVEVIEW}
  23. { Define ENHVALIDATE to scan all existing directories on a detected filesystem change:}
  24. {.$DEFINE ENHVALIDATE}
  25. {Required compiler options for TDriveView:}
  26. {$A+,B-,X+,H+,P+}
  27. uses
  28. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, ComObj,
  29. Dialogs, ComCtrls, ShellApi, CommCtrl, ExtCtrls, ActiveX, ShlObj,
  30. DirView,
  31. ShellDialogs,
  32. DragDrop,
  33. DragDropFilesEx,
  34. FileChanges,
  35. FileOperator,
  36. DiscMon,
  37. IEDriveInfo,
  38. IEListView,
  39. PIDL,
  40. BaseUtils,
  41. ListExt,
  42. CustomDirView;
  43. {$I ResStrings.pas}
  44. const
  45. {$IFNDEF NO_THREADS}
  46. msThreadChangeDelay = 50;
  47. {$ENDIF}
  48. C_InvalidSize = $FFFFFFFF;
  49. DDMaxSlowCount = 3;
  50. DDVScrollDelay = 2000000;
  51. DDHScrollDelay = 2000000;
  52. DDDragStartDelay = 500000;
  53. DDExpandDelay = 25000000;
  54. ErrorNodeNA = '%s: Node not assigned';
  55. DirAttrMask = faDirectory or faSysFile or faHidden;
  56. {Flags used by TDriveView.RefreshRootNodes:}
  57. dvdsFloppy = 8; {Include floppy drives}
  58. dvdsRereadAllways = 16; {Refresh drivestatus in any case}
  59. {Types uses by the function IterateSubTree:}
  60. {TRecursiveScan: determines, wich nodes are scanned by the function IterateSubTree:
  61. rsNoRecursive: Scan startnode only.
  62. rsRecursive: Scan all subnodes of the startnode.
  63. rsRecursiveExisting: Scan all subnodes of the startnode but not new created subnodes.
  64. rsRecursiveExpanded: Scan all expanded subnodes of the startnode.}
  65. {TScanStartnode: determines, wether the startnode should also be scanned:}
  66. type
  67. TRecursiveScan = (rsNoRecursive, rsRecursive, rsRecursiveExisting, rsRecursiveExpanded);
  68. TScanStartNode = (coNoScanStartNode, coScanStartNode);
  69. TString12 = string[12];
  70. TCallBackFunc = function(var Node :TTreeNode; Data: Pointer): Boolean of object;
  71. ECreateShortCut = class(Exception);
  72. EInvalidDirName = class(Exception);
  73. EInvalidPath = class(Exception);
  74. ENodeNotAssigned = class(Exception);
  75. TDriveStatus = record
  76. Scanned: Boolean; {Drive allready scanned?}
  77. Verified: Boolean; {Drive completly scanned?}
  78. RootNode: TTreeNode; {Rootnode to drive}
  79. {$IFNDEF NO_THREADS}
  80. DiscMonitor: TDiscMonitor; {Monitor thread}
  81. {$ENDIF}
  82. ChangeTimer: TTimer; {Change timer for the monitor thread}
  83. DefaultDir: string; {Current directory}
  84. end;
  85. TScanDirInfo = record
  86. SearchNewDirs: Boolean;
  87. StartNode: TTreeNode;
  88. DriveType: Integer;
  89. end;
  90. PScanDirInfo = ^TScanDirInfo;
  91. TDriveViewScanDirEvent = Procedure(Sender: TObject; Node: TTreeNode; Var DoScanDir : Boolean) of object;
  92. TDriveViewDiskChangeEvent = Procedure(Sender: TObject; Drive : TDrive) of object;
  93. TDriveView = Class;
  94. TNodeData = Class
  95. Private
  96. FDirName : String;
  97. FShortName: TString12;
  98. FAttr : Integer;
  99. FScanned : Boolean;
  100. FData : Pointer;
  101. FExpanded : Boolean;
  102. FDrawBold : Boolean;
  103. FDirSize : Cardinal;
  104. FisRecycleBin : Boolean;
  105. FIconEmpty : Boolean;
  106. Public
  107. shAttr : ULONG;
  108. PIDL : PItemIDList;
  109. ShellFolder : iShellFolder;
  110. Property DirName : String Read FDirName Write FDirName;
  111. Property ShortName : TString12 Read FShortName Write FShortName;
  112. Property Attr : Integer Read Fattr Write Fattr;
  113. Property Scanned : Boolean Read FScanned Write FScanned;
  114. Property Data : Pointer Read FData Write FData;
  115. Property Expanded : Boolean Read FExpanded Write FExpanded;
  116. Property DrawBold : Boolean Read FDrawBold Write FDrawBold;
  117. Property DirSize : Cardinal Read FDirSize Write FDirSize;
  118. Property isRecycleBin : Boolean Read FIsRecycleBin;
  119. Property IconEmpty : Boolean Read FIconEmpty Write FIconEmpty;
  120. Constructor Create;
  121. Destructor Destroy; Override;
  122. End;
  123. {---------------------------------------------------------------}
  124. TDriveView = class(TCustomTreeView)
  125. {---------------------------------------------------------------}
  126. private
  127. {---------------------------------------------------------------}
  128. DriveStatus : Array[FirstDrive .. LastDrive] Of TDriveStatus;
  129. FConfirmDelete : Boolean;
  130. FConfirmOverwrite : Boolean;
  131. FWatchDirectory : Boolean;
  132. FDirectory : String;
  133. FFullDriveScan : Boolean;
  134. FDimmHiddenDirs : Boolean;
  135. FColorBold : TColor;
  136. FShowDirSize : Boolean;
  137. FShowVolLabel : Boolean;
  138. FVolDisplayStyle : TVolumeDisplayStyle;
  139. FUseSystemContextMenu : Boolean;
  140. FContinue : Boolean;
  141. FShowAnimation : Boolean;
  142. FChangeFlag : Boolean;
  143. FContextMenu : Boolean;
  144. FLastDir : String;
  145. FValidateFlag : Boolean;
  146. FCreating : Boolean;
  147. FParentForm : TCustomForm;
  148. FReadDrives : Boolean;
  149. FForceRename : Boolean;
  150. FRenameNode : TTreeNode;
  151. FLastRenameName : String;
  152. FDesktop : iShellFolder;
  153. FWorkPlace : iShellFolder;
  154. {Additional events:}
  155. FOnStartScan : TNotifyEvent;
  156. FOnEndScan : TNotifyEvent;
  157. FOnScanDir : TDriveViewScanDirEvent;
  158. FOnDiskChange : TDriveViewDiskChangeEvent;
  159. FOnInsertedDiskChange : TDriveViewDiskChangeEvent;
  160. FOnChangeDetected : TDriveViewDiskChangeEvent;
  161. FOnChangeInvalid : TDriveViewDiskChangeEvent;
  162. FOnDisplayContextMenu: TNotifyEvent;
  163. {used components:}
  164. FDirView : TDirView;
  165. FDriveBox : TObject;
  166. FFileOperator : TFileOperator;
  167. FChangeInterval : Cardinal;
  168. FCanChange : Boolean;
  169. FDragImageList : TDragImageList;
  170. FNoCheckDrives : String;
  171. FCompressedColor : TColor;
  172. FFileNameDisplay : TFileNameDisplay;
  173. {Drag&drop:}
  174. FDragDrive : TDrive;
  175. DragFileList : TStringList;
  176. DragNode : TTreeNode;
  177. FDD : TDragDropFilesEx;
  178. DragOverTime : FILETIME;
  179. DragStartTime : FILETIME;
  180. LastVScrollTime : FILETIME;
  181. LastHScrollTime : FILETIME;
  182. VScrollCount : Integer;
  183. FLastPathCut : String;
  184. FTargetPopUpMenu : Boolean;
  185. FUseDragImages : Boolean;
  186. FStartPos : TPoint;
  187. FDragPos : TPoint;
  188. FExeDrag : Boolean;
  189. FDDLinkOnExeDrag : Boolean;
  190. FOnDDDragEnter : TDDOnDragEnter;
  191. FOnDDDragLeave : TDDOnDragLeave;
  192. FOnDDDragOver : TDDOnDragOver;
  193. FOnDDDrop : TDDOnDrop;
  194. FOnDDQueryContinueDrag : TDDOnQueryContinueDrag;
  195. FOnDDGiveFeedback : TDDOnGiveFeedback;
  196. FOnDDDragDetect : TDDOnDragDetect;
  197. FOnDDProcessDropped : TOnProcessDropped;
  198. FOnDDError : TDDErrorEvent;
  199. FOnDDExecuted : TDDExecutedEvent;
  200. FOnDDFileOperation : TDDFileOperationEvent;
  201. FOnDDFileOperationExecuted : TDDFileOperationExecutedEvent;
  202. {Drag&Drop eventhandling:}
  203. Procedure DDDragEnter(DataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: longint; var Accept:boolean);
  204. Procedure DDDragLeave;
  205. Procedure DDDragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: longint);
  206. Procedure DDDrop(DataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: longint);
  207. Procedure DDQueryContinueDrag(fEscapePressed: BOOL; grfKeyState: Longint; var Result: HResult);
  208. Procedure DDGiveFeedback(dwEffect: Longint; var Result: HResult);
  209. Procedure DDDragDetect(grfKeyState: Longint; DetectStart, Pt: TPoint; DragStatus:TDragDetectStatus);
  210. Procedure DDProcessDropped(Sender: TObject; grfKeyState: Longint; pt: TPoint; dwEffect: Longint);
  211. Procedure DDSpecifyDropTarget(Sender: TObject; DragDropHandler : boolean; pt: TPoint; var pidlFQ : PItemIDList; var Filename : string);
  212. Procedure SetTargetPopUpMenu(PopMe : Boolean);
  213. {Drag&drop helper functions:}
  214. Procedure SignalDirDelete(Sender: TObject; Files : TStringList);
  215. Function CheckForSubDirs(Path: String) : Boolean;
  216. Function ReadSubDirs(Node : TTreeNode; DriveType: Integer) : Boolean;
  217. {Callback-functions used by iteratesubtree:}
  218. Function CallBackValidateDir (Var Node : TTreeNode; Data: Pointer) : Boolean;
  219. Function CallBackSaveNodeState (Var Node : TTreeNode; Data: Pointer) : Boolean;
  220. Function CallBackRestoreNodeState (Var Node : TTreeNode; Data: Pointer) : Boolean;
  221. Function CallBackDisplayName (Var Node : TTreeNode; Data: Pointer) : Boolean;
  222. Function CallBackSetDirSize (Var Node : TTreeNode; Data: Pointer) : Boolean;
  223. Function CallBackExpandLevel (Var Node : TTreeNode; Data: Pointer) : Boolean;
  224. {Notification procedures used by component TDiscMonitor:}
  225. Procedure ChangeDetected(Sender: TObject);
  226. Procedure ChangeInvalid(Sender: TObject);
  227. {Notification procedure used by component TTimer:}
  228. Procedure ChangeTimerOnTimer(Sender : TObject);
  229. {Special procedure for events OnEdited / OnDrawItem. Used to overwrite these events:}
  230. Procedure InternalOnDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
  231. {---------------------------------------------------------------}
  232. protected
  233. {---------------------------------------------------------------}
  234. Procedure SetSelected(Node : TTreeNode);
  235. Procedure SetFullDriveScan(DoFullDriveScan : Boolean);
  236. Procedure SetWatchDirectory(Watch : Boolean);
  237. Procedure SetShowDirSize(ShowIt : Boolean);
  238. Procedure SetShowVolLabel(ShowIt : Boolean);
  239. Procedure SetVolDisplayStyle(doStyle : TVolumeDisplayStyle);
  240. Procedure SetDirView(DV : TDirView);
  241. Procedure SetChangeInterval(Interval : Cardinal);
  242. Procedure SetDimmHiddenDirs(DimmIt : Boolean);
  243. Procedure SetNoCheckDrives(Value : String);
  244. Procedure SetCompressedColor(Value : TColor);
  245. Procedure SetFileNameDisplay(Value : TFileNameDisplay);
  246. Function GetDirectory : String;
  247. Procedure SetDirectory(Path : String);
  248. Procedure SetDrive(Drive : TDrive);
  249. Function GetDrive : TDrive;
  250. Function GetNodeFromHItem(Item: TTVItem): TTreeNode;
  251. Procedure GetNodeShellAttr(ParentFolder : iShellFolder; NodeData : TNodeData; Path : String; ContentMask : Boolean = True);
  252. Function DoScanDir(FromNode : TTreeNode) : Boolean; Virtual;
  253. Function AddChildNode(ParentNode : TTreeNode; SRec : TSearchRec) : TTreeNode; Virtual;
  254. {$IFNDEF NO_THREADS}
  255. Procedure CreateWatchThread(Drive : TDrive); Virtual;
  256. {$ENDIF}
  257. Procedure SetLastPathCut(Path : String);
  258. Function GetCanUndoCopyMove : Boolean; Virtual;
  259. Procedure DDError(ErrorNo : TDDError); Dynamic;
  260. Procedure CNNotify(Var Msg: TWMNotify); Message CN_NOTIFY;
  261. Procedure CreateWnd; Override;
  262. Procedure Edit(Const Item: TTVItem); Override;
  263. Procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
  264. Procedure WMLButtonDown(var Msg: TWMLButtonDown); Message WM_LBUTTONDOWN;
  265. Procedure WMLButtonUp (var Msg: TWMLButtonDown); Message WM_LBUTTONUP;
  266. Procedure WMRButtonDown(Var Msg: TWMRButtonDown); Message WM_RBUTTONDOWN;
  267. Procedure WMContextMenu(Var Msg: TWMContextMenu); Message WM_CONTEXTMENU;
  268. Procedure WMUserRename(Var Message : TMessage); Message WM_USER_RENAME;
  269. {---------------------------------------------------------------}
  270. public
  271. {---------------------------------------------------------------}
  272. {Runtime-only properties:}
  273. property Images;
  274. Property StateImages;
  275. Property Items Stored False;
  276. Property Selected Write SetSelected Stored False;
  277. Property WorkPlace : iShellFolder Read FWorkPlace;
  278. Property DragImageList : TDragImageList Read FDragImageList;
  279. Property Continue : Boolean Read FContinue
  280. Write FContinue;
  281. Property DriveBox : TObject Read FDriveBox
  282. Write FDriveBox;
  283. {Current drive:}
  284. Property Drive : TDrive Read GetDrive
  285. Write SetDrive
  286. Stored False;
  287. Property DragDropFilesEx : TDragDropFilesEx Read FDD;
  288. Property DragDrive : TDrive Read FDragDrive;
  289. Property CanUndoCopyMove : Boolean Read GetCanUndoCopyMove;
  290. Property DDFileOperator : TFileOperator Read FFileOperator;
  291. Property LastPathCut : String Read FLastPathCut
  292. Write SetLastPathCut;
  293. Function UndoCopyMove : Boolean; Dynamic;
  294. Procedure EmptyClipboard; Dynamic;
  295. Function CopyToClipBoard(Node : TTreeNode) : Boolean; Dynamic;
  296. Function CutToClipBoard(Node : TTreeNode) : Boolean; Dynamic;
  297. Function CanPasteFromClipBoard : Boolean; Dynamic;
  298. Function PasteFromClipBoard(TargetPath : String = '') : Boolean; Dynamic;
  299. Procedure PerformDragDropFileOperation(TargetPath : String; dwEffect: Integer; isRecycleBin : Boolean);
  300. {Drive handling:}
  301. Function GetDriveStatus(Drive : TDrive) : TDriveStatus;
  302. Function GetDriveTypetoNode(Node : TTreeNode) : Integer; {Returns DRIVE_CDROM etc..}
  303. Function GetDriveType(Drive : TDrive) : Integer; {Returns DRIVE_CDROM etc..}
  304. Function GetDriveToNode(Node : TTreeNode) : Char;
  305. Function GetDriveText(Drive : TDrive) : String;
  306. Procedure ScanDrive(Drive : TDrive);
  307. Procedure RefreshRootNodes(ScanDirectory : Boolean; dsFlags : Integer);
  308. Function GetValidDrivesStr : String;
  309. Procedure RefreshDirSize(Node : TTreeNode);
  310. Procedure RefreshDriveDirSize(Drive : TDrive);
  311. {Node handling:}
  312. Procedure SetImageIndex(Node : TTreeNode); Virtual;
  313. Function HasSubNodes(Node : TTreeNode) : Boolean;
  314. Function FindNodeToPath(Path : String) : TTreeNode;
  315. Procedure SetBoldDraw(Node : TTreeNode; BoldDraw : Boolean); Dynamic;
  316. Function NodeVerified(Node : TTreeNode) : Boolean;
  317. Function NodeAttr(Node : TTreeNode) : Integer;
  318. Function RootNode(Node : TTreeNode) : TTreeNode;
  319. Function GetDirPathName(Node: TTreeNode) : String;
  320. Function GetDirPath (Node : TTreeNode) : String;
  321. Function GetDirName(Node : TTreeNode) : String;
  322. Procedure CenterNode(Node : TTreeNode); Virtual;
  323. Function SortChildren(ParentNode : TTreeNode; Recurse : Boolean) : Boolean; Virtual;
  324. Function GetDirSize(Node : TTreeNode) : Cardinal; Virtual;
  325. Procedure SetDirSize(Node : TTreeNode); Virtual;
  326. Function GetDisplayName(Node : TTreeNode) : String;
  327. Function NodeUpdateAble(Node : TTreeNode) : Boolean; Virtual;
  328. Function FormatDirSize(Size : Cardinal) : String; Virtual;
  329. Procedure ExpandLevel(Node : TTreeNode; Level : Integer); Virtual;
  330. Function GetFQPIDL(Node : TTreeNode) : PItemIDList;
  331. Procedure ValidateDirectoryEx(Node : TTreeNode;
  332. Recurse : TRecursiveScan;
  333. NewDirs : Boolean); Virtual;
  334. Procedure ValidateDirectory(Node : TTreeNode); Virtual;
  335. Procedure ValidateDirectoryEasy(Node : TTreeNode); Virtual;
  336. Procedure ValidateVisibleDirectories(Node : TTreeNode); Virtual;
  337. Procedure ValidateAllDirectories(Node : TTreeNode); Dynamic;
  338. Function GetSubTreeSize(Node : TTreeNode) : Integer; Dynamic;
  339. {Directory update:}
  340. Function CreateDirectory(ParentNode : TTreeNode; NewName : String) : TTreeNode; Dynamic;
  341. Function DeleteDirectory(Node: TTreeNode; AllowUndo : Boolean) : Boolean; Dynamic;
  342. Procedure DeleteSubNodes(Node : TTreeNode); Dynamic;
  343. {Basic recursive function for scanning a subtree:}
  344. Function IterateSubTree(Var StartNode : TTreeNode;
  345. CallBackFunc : TCallBackFunc;
  346. Recurse : TRecursiveScan;
  347. ScanStartNode : TScanStartNode;
  348. Data : Pointer) : Boolean;
  349. constructor Create(AOwner: TComponent); Override;
  350. Destructor Destroy; Override;
  351. {Save and restore the subnodes expanded state:}
  352. Procedure SaveNodesState(Node : TTreeNode);
  353. Procedure RestoreNodesState(Node : TTreeNode);
  354. {Menu-handling:}
  355. Procedure DisplayContextMenu(Node : TTreeNode); Overload;
  356. Procedure DisplayContextMenu(Node : TTreeNode; ScreenPos : TPoint); Overload;
  357. Procedure DisplayPropertiesMenu(Node : TTreeNode); Dynamic;
  358. {$IFNDEF NO_THREADS}
  359. {Watchthread handling:}
  360. Procedure StartWatchThread; Virtual;
  361. Procedure StopWatchThread; Virtual;
  362. Procedure TerminateWatchThread(Drive : TDrive); Virtual;
  363. Procedure StartAllWatchThreads; Virtual;
  364. Procedure StopAllWatchThreads; Virtual;
  365. Function WatchThreadActive : Boolean; Overload;
  366. Function WatchThreadActive(Drive : TDrive) : Boolean; Overload;
  367. Function NodeWatched(Node : TTreeNode) : Boolean; Virtual;
  368. {$ENDIF}
  369. (* Modified Events: *)
  370. Procedure GetImageIndex(Node: TTreeNode); Override;
  371. Function CanEdit(Node: TTreeNode) : Boolean; Override;
  372. Function CanChange(Node: TTreeNode): Boolean; Override;
  373. Function CanExpand(Node: TTreeNode): Boolean; Override;
  374. Procedure Delete(Node: TTreeNode); Override;
  375. Procedure Loaded; Override;
  376. Procedure KeyDown(var Key: Word; Shift: TShiftState); Override;
  377. Procedure KeyPress(Var Key : Char); Override;
  378. Procedure KeyUp(var Key: Word; Shift: TShiftState); Override;
  379. Procedure Change(Node: TTreeNode); Override;
  380. {---------------------------------------------------------------}
  381. published
  382. {---------------------------------------------------------------}
  383. {Additional properties:}
  384. {Current selected directory:}
  385. Property Directory : String Read GetDirectory
  386. Write SetDirectory;
  387. {Confirm deleting directories:}
  388. Property ConfirmDelete : Boolean Read fConfirmDelete
  389. Write fConfirmDelete
  390. Default True;
  391. {Confirm overwriting directories:}
  392. Property ConfirmOverwrite : Boolean Read fConfirmOverwrite
  393. Write fConfirmOverwrite
  394. Default True;
  395. {Scan all directories in method ScanDrive:}
  396. Property FullDriveScan : Boolean Read fFullDriveScan
  397. Write SetFullDriveScan;
  398. Property DimmHiddenDirs : Boolean Read fDimmHiddenDirs
  399. Write SetDimmHiddenDirs;
  400. {Enable automatic update on filesystem changes:}
  401. Property WatchDirectory : Boolean Read fWatchDirectory
  402. Write SetWatchDirectory;
  403. {Peform automatic update after ChangeInterval milliseconds:}
  404. Property ChangeInterval : Cardinal Read fChangeInterval
  405. Write SetChangeInterval
  406. Default 1000;
  407. {Enables or disables the system context menu for a directory:}
  408. Property UseSystemContextMenu : Boolean Read FUseSystemContextMenu
  409. Write FUseSystemContextMenu
  410. Default True;
  411. {Linked component TDirView:}
  412. Property DirView : TDirView Read fDirView
  413. Write SetDirView;
  414. Property ColorBold : TColor Read fColorBold
  415. Write fColorBold
  416. Default clBlue;
  417. Property ShowDirSize : Boolean Read fShowDirSize
  418. Write SetShowDirSize;
  419. {Show the volume labels of drives:}
  420. Property ShowVolLabel : Boolean Read fShowVolLabel
  421. Write SetShowVolLabel;
  422. {How to display the drives volume labels:}
  423. Property VolDisplayStyle : TVolumeDisplayStyle Read fVolDisplayStyle
  424. Write SetVolDisplayStyle
  425. Default doPrettyName;
  426. {Show AVI-animation when performing a full drive scan:}
  427. Property ShowAnimation : Boolean Read FShowAnimation
  428. Write FShowAnimation;
  429. {Don't watch these drives for changes:}
  430. Property NoCheckDrives : String Read FNoCheckDrives
  431. Write SetNoCheckDrives;
  432. Property ReadDrives : Boolean Read FReadDrives
  433. Write FReadDrives
  434. Default True;
  435. Property CompressedColor : TColor Read FCompressedColor
  436. Write SetCompressedColor
  437. Default clBlue;
  438. Property FileNameDisplay : TFileNameDisplay Read FFileNameDisplay
  439. Write SetFileNameDisplay;
  440. {Additional events:}
  441. Property OnStartScan : TNotifyEvent Read fOnStartScan
  442. Write fOnStartScan;
  443. Property OnEndScan : TNotifyEvent Read fOnEndScan
  444. Write fOnEndScan;
  445. Property OnScanDir : TDriveViewScanDirEvent Read fOnScanDir
  446. Write fOnScanDir;
  447. Property OnDiskChange: TDriveViewDiskChangeEvent Read fOnDiskChange
  448. Write fOnDiskChange;
  449. Property OnInsertedDiskChange: TDriveViewDiskChangeEvent Read fOnInsertedDiskChange
  450. Write fOnInsertedDiskChange;
  451. Property OnChangeDetected : TDriveViewDiskChangeEvent Read fOnChangeDetected
  452. Write fOnChangeDetected;
  453. Property OnChangeInvalid : TDriveViewDiskChangeEvent Read fOnChangeInvalid
  454. Write fOnChangeInvalid;
  455. Property OnDisplayContextMenu: TNotifyEvent Read FOnDisplayContextMenu
  456. Write FOnDisplayContextMenu;
  457. {Drag&Drop properties:}
  458. Property DDLinkOnExeDrag : Boolean Read FDDLinkOnExeDrag
  459. Write FDDLinkOnExeDrag
  460. Default True;
  461. {Show drag images during a drag&drop operation:}
  462. Property UseDragImages : Boolean Read FUseDragImages
  463. Write FUseDragImages
  464. Default True;
  465. {Show popupmenu when dropping a file with the right mouse button:}
  466. Property TargetPopUpMenu : Boolean Read FTargetPopUpMenu
  467. Write SetTargetPopUpMenu
  468. Default True;
  469. {The mouse has entered the component window as a target of a drag&drop operation:}
  470. Property OnDDDragEnter : TDDOnDragEnter Read FOnDDDragEnter
  471. Write FOnDDDragEnter;
  472. {The mouse has leaved the component window as a target of a drag&drop operation:}
  473. Property OnDDDragLeave : TDDOnDragLeave Read FOnDDDragLeave
  474. Write FOnDDDragLeave;
  475. {The mouse is dragging in the component window as a target of a drag&drop operation:}
  476. Property OnDDDragOver : TDDOnDragOver Read FOnDDDragOver
  477. Write FOnDDDragOver;
  478. {The Drag&drop operation is about to be executed:}
  479. Property OnDDDrop : TDDOnDrop Read FOnDDDrop
  480. Write FOnDDDrop;
  481. Property OnDDQueryContinueDrag : TDDOnQueryContinueDrag Read FOnDDQueryContinueDrag
  482. Write FOnDDQueryContinueDrag;
  483. Property OnDDGiveFeedback : TDDOnGiveFeedback Read FOnDDGiveFeedback
  484. Write FOnDDGiveFeedback;
  485. {A drag&drop operation is about to be initiated whith the components window as the
  486. source:}
  487. Property OnDDDragDetect : TDDOnDragDetect Read FOnDDDragDetect
  488. Write FOnDDDragDetect;
  489. {The component window is the target of a drag&drop operation:}
  490. Property OnDDProcessDropped : TOnProcessDropped Read FOnDDProcessDropped
  491. Write FOnDDProcessDropped;
  492. {An error has occured during a drag&drop operation:}
  493. Property OnDDError : TDDErrorEvent Read FOnDDError
  494. Write FOnDDError;
  495. {The drag&drop operation has been executed:}
  496. Property OnDDExecuted : TDDExecutedEvent Read FOnDDExecuted
  497. Write FOnDDExecuted;
  498. {Event is fired just before executing the fileoperation. This event is also fired when
  499. files are pasted from the clipboard:}
  500. Property OnDDFileOperation : TDDFileOperationEvent Read FOnDDFileOperation
  501. Write FOnDDFileOperation;
  502. {Event is fired after executing the fileoperation. This event is also fired when
  503. files are pasted from the clipboard:}
  504. Property OnDDFileOperationExecuted : TDDFileOperationExecutedEvent Read FOnDDFileOperationExecuted
  505. Write FOnDDFileOperationExecuted;
  506. property Align;
  507. property Anchors;
  508. property AutoExpand;
  509. property BiDiMode;
  510. property BorderStyle;
  511. property BorderWidth;
  512. property ChangeDelay;
  513. property Color;
  514. property Ctl3D;
  515. property Constraints;
  516. {Delphi's drag&drop is not compatible with the OLE windows drag&drop:}
  517. property DragKind;
  518. property DragCursor;
  519. property DragMode;
  520. property OnDragDrop;
  521. property OnDragOver;
  522. property Enabled;
  523. property Font;
  524. property HideSelection;
  525. property HotTrack;
  526. property Indent;
  527. property ParentBiDiMode;
  528. property ParentColor;
  529. property ParentCtl3D;
  530. property ParentFont;
  531. property ParentShowHint;
  532. property PopupMenu;
  533. property ReadOnly;
  534. property RightClickSelect;
  535. property RowSelect;
  536. property ShowButtons;
  537. property ShowHint;
  538. property ShowLines;
  539. {property ShowRoot;}
  540. {property SortType;}
  541. property TabOrder;
  542. property TabStop;
  543. property ToolTips;
  544. property Visible;
  545. property OnChange;
  546. property OnChanging;
  547. property OnClick;
  548. property OnCollapsing;
  549. property OnCollapsed;
  550. property OnCompare;
  551. {Internal used events:
  552. property OnCustomDraw;
  553. property OnCustomDrawItem;}
  554. property OnDblClick;
  555. property OnDeletion;
  556. property OnEdited;
  557. property OnEditing;
  558. property OnEndDock;
  559. property OnEndDrag;
  560. property OnEnter;
  561. property OnExit;
  562. property OnExpanding;
  563. property OnExpanded;
  564. property OnGetImageIndex;
  565. property OnGetSelectedIndex;
  566. property OnKeyDown;
  567. property OnKeyPress;
  568. property OnKeyUp;
  569. property OnMouseDown;
  570. property OnMouseMove;
  571. property OnMouseUp;
  572. property OnStartDock;
  573. property OnStartDrag;
  574. end;
  575. {---------------------------------------------------------------}
  576. // ===========================================================
  577. // Other service procedures and functions:}
  578. // ===========================================================
  579. procedure Register;
  580. {$ENDIF}
  581. {==============================================================}
  582. implementation
  583. {$IFDEF USE_DRIVEVIEW}
  584. {==============================================================}
  585. uses IEComboBox;
  586. resourceString
  587. English_ErrorInvalidDirName = 'New name contains Invalid characters:';
  588. English_DragDropError = 'DragDrop Error: %d';
  589. {MP}{ German_ErrorInvalidDirName = 'Verzeichnisname enthält ungültige Zeichen:';
  590. French_ErrorInvalidDirName = 'Le nouveau nom contient des caractères invalides:';}
  591. Type
  592. PInt = ^Integer;
  593. TLogFileNode = Record
  594. Level : Integer;
  595. Attrs : Integer;
  596. ShortName : array[0..13] of AnsiChar;
  597. NameLen : Integer;
  598. End;
  599. TLogFileHeader = Record
  600. ID : String[10];
  601. Version : String[3];
  602. End;
  603. // ===========================================================
  604. // Global variables
  605. // ===========================================================
  606. Var ErrorInvalidDirName : String;
  607. procedure Register;
  608. begin
  609. {MP}RegisterComponents({'IE'}'DriveDir', [TDriveView]);
  610. end; {Register}
  611. Constructor TNodeData.Create;
  612. Begin
  613. Inherited Create;
  614. FAttr := 0;
  615. FDrawBold := False;
  616. FExpanded := False;
  617. FScanned := False;
  618. FDirName := '';
  619. FShortName := '';
  620. FDirSize := C_InvalidSize;
  621. FIsRecycleBin := False;
  622. FIconEmpty := True;
  623. shAttr := 0;
  624. PIDL := NIL;
  625. ShellFolder := NIL;
  626. End; {TNodeData.Create}
  627. Destructor TNodeData.Destroy;
  628. Begin
  629. SetLength(fDirName, 0);
  630. IF Assigned(PIDL) Then
  631. FreePIDL(PIDL);
  632. Inherited Destroy;
  633. End; {TNodeData.Destroy}
  634. Function TDriveView.GetFQPIDL(Node : TTreeNode) : PItemIDList;
  635. Var WStr : WideString;
  636. Eaten : ULONG;
  637. shAttr : ULONG;
  638. Begin
  639. Result := NIL;
  640. IF Assigned(Node) Then
  641. Begin
  642. WStr := GetDirPathName(Node);
  643. FDesktop.ParseDisplayName(FParentForm.Handle, NIL, PWideChar(WStr), Eaten, Result, shAttr);
  644. End;
  645. End; {GetFQPIDL}
  646. // ===========================================================
  647. // Class TDriveView:
  648. // ===========================================================
  649. (* -------------------------*)
  650. (* Events: *)
  651. (* -------------------------*)
  652. (* Overwrite Event OnCustomDraw: *)
  653. Procedure TDriveview.InternalOnDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
  654. Begin
  655. IF Assigned(Node) And Assigned(Node.Data) And (Node <> DropTarget) Then
  656. With TNodeData(Node.Data) Do
  657. IF Not Node.Selected Then
  658. Begin
  659. {Colored display of compressed directories:}
  660. IF Bool(Attr And FILE_ATTRIBUTE_COMPRESSED) Then
  661. Canvas.Font.Color := FCompressedColor
  662. Else
  663. {Dimmed display, if hidden-atrribut set:}
  664. IF fDimmHiddenDirs And Bool(Attr And FILE_ATTRIBUTE_HIDDEN) Then
  665. Canvas.Font.Color := clGrayText
  666. Else
  667. IF DrawBold Then
  668. Begin
  669. Canvas.Font.Color := fColorBold;
  670. Canvas.Font.Style := Canvas.Font.Style + [fsBold];
  671. End; End
  672. Else
  673. {HideSelection:}
  674. IF Not Self.Focused And HideSelection Then
  675. Begin
  676. Canvas.Brush.Color := clBtnFace;
  677. Canvas.Font.Color := clBtnText;
  678. End;
  679. End; {InternalOnDrawItem}
  680. (* Overwrite Event OnEditing: *)
  681. Function TDriveView.CanEdit(Node: TTreeNode) : Boolean;
  682. Begin
  683. Result := Inherited CanEdit(Node) Or FForceRename;
  684. IF Result Then
  685. Result := Assigned(Node.Parent) And
  686. Not TNodeData(Node.Data).isRecycleBin And
  687. Not ReadOnly And
  688. (FDD.DragDetectStatus <> ddsDrag) And
  689. (TNodeData(Node.Data).Attr and (faReadOnly or faSysFile) = 0) And
  690. (UpperCase(Node.Text) = UpperCase(GetDirName(Node)));
  691. FForceRename := False;
  692. End; {CanEdit}
  693. (* event OnEdited: *)
  694. procedure TDriveView.Edit(const Item: TTVItem);
  695. Var NewDirName : String;
  696. SRec : TSearchRec;
  697. Node : TTreeNode;
  698. Info : String;
  699. i : Integer;
  700. Begin
  701. Node := GetNodeFromHItem(Item);
  702. IF (Length(Item.pszText) > 0) And (Item.pszText <> Node.Text) Then
  703. Begin
  704. IF StrContains(coInvalidDosChars, Item.pszText) Then
  705. Begin
  706. Info := coInvalidDosChars;
  707. For i := Length(Info) DownTo 1 Do
  708. System.Insert(Space, Info, i);
  709. IF Assigned(OnEdited) Then
  710. Begin
  711. NewDirName := Node.Text;
  712. OnEdited(Self, Node, NewDirName);
  713. End;
  714. IF Length(Item.pszText) > 0 Then
  715. Raise EInvalidDirName.Create(ErrorInvalidDirName + Space + Info);
  716. Exit;
  717. End;
  718. {$IFNDEF NO_THREADS}
  719. StopWatchThread;
  720. IF Assigned(DirView) Then
  721. DirView.StopWatchThread;
  722. {$ENDIF}
  723. With FFileOperator Do
  724. Begin
  725. Flags := [foAllowUndo, foNoConfirmation];
  726. Operation := foRename;
  727. OperandFrom.Clear;
  728. OperandTo.Clear;
  729. OperandFrom.Add(GetDirPath(Node));
  730. OperandTo.Add(AddSlash(GetDirPath(Node.Parent)) + Item.pszText);
  731. End;
  732. Try
  733. IF FFileOperator.Execute Then
  734. {IF RenameFile(GetDirPath(Node), AddSlash(GetDirPath(Node.Parent)) + Item.pszText) Then}
  735. Begin
  736. Node.Text := Item.pszText;
  737. TNodeData(Node.Data).Dirname := Item.pszText;
  738. IF FindFirst(AddSlash(GetDirPath(Node.Parent)) + Item.pszText, faAnyFile, Srec) = 0 Then
  739. TNodeData(Node.Data).ShortName := Srec.FindData.cAlternateFileName;
  740. FindClose(Srec);
  741. SortChildren(Node.Parent, False);
  742. Inherited Edit(Item);
  743. End
  744. Else
  745. Begin
  746. {
  747. Raise ERenameFileFailed.Create(ErrorRenameFile + Item.pszText);
  748. }
  749. IF FileOrDirExists(AddSlash(GetDirPath(Node.Parent)) + Item.pszText) Then
  750. Info := SErrorRenameFileExists + Item.pszText
  751. Else
  752. Info := SErrorRenameFile + Item.pszText;
  753. MessageBeep(MB_ICONHAND);
  754. IF MessageDlg(Info, mtError, [mbOK, mbAbort], 0) = mrOK Then
  755. Begin
  756. FLastRenameName := Item.pszText;
  757. FRenameNode := Node;
  758. PostMessage(Self. Handle, WM_USER_RENAME, 0 , 0);
  759. End;
  760. End;
  761. Finally
  762. {$IFNDEF NO_THREADS}
  763. StartWatchThread;
  764. {$ENDIF}
  765. IF Assigned(DirView) Then
  766. Begin
  767. DirView.Reload2;
  768. {$IFNDEF NO_THREADS}
  769. DirView.StartWatchThread;
  770. {$ENDIF}
  771. End;
  772. End;
  773. End;
  774. End; {Edit}
  775. Procedure TDriveView.WMUserRename(Var Message : TMessage);
  776. Begin
  777. IF Assigned(FRenameNode) Then
  778. Begin
  779. FForceRename := True;
  780. TreeView_EditLabel(Handle, FRenameNode.ItemID);
  781. SetWindowText(TreeView_GetEditControl(Self.Handle), PChar(FLastRenameName));
  782. FRenameNode := NIL;
  783. End;
  784. End; {WMUserRename}
  785. (* Overwrite Event OnCanChange: *)
  786. Function TDriveView.CanChange(Node: TTreeNode): Boolean;
  787. Begin
  788. Result := Inherited CanChange(Node);
  789. IF Result And
  790. Not FCanChange And
  791. Assigned(Node) And
  792. Assigned(Node.Data) And
  793. Assigned(Selected) And
  794. Assigned(Selected.Data) Then
  795. Begin
  796. DropTarget := Node;
  797. Result := False;
  798. End
  799. Else
  800. DropTarget := NIL;
  801. End; {CanChange}
  802. (* Overwrite Event OnExpanding: *)
  803. Function TDriveView.CanExpand(Node: TTreeNode): Boolean;
  804. Var SubNode : TTreeNode;
  805. Drive : TDrive;
  806. SaveCursor : TCursor;
  807. Begin
  808. Result := Inherited CanExpand(Node);
  809. Drive := GetDriveToNode(Node);
  810. IF Node.HasChildren Then
  811. Begin
  812. IF (Node.Level = 0) And
  813. Not DriveStatus[Drive].Scanned And
  814. (Drive >= FirstFixedDrive) Then
  815. Begin
  816. SubNode := Node.GetFirstChild;
  817. IF Not Assigned(SubNode) Then
  818. Begin
  819. ScanDrive(Drive);
  820. SubNode := Node.GetFirstChild;
  821. Node.HasChildren := Assigned(SubNode);
  822. Result := Node.HasChildren;
  823. IF Not Assigned(DriveStatus[Drive].DiscMonitor) Then
  824. {$IFNDEF NO_THREADS}
  825. CreateWatchThread(Drive);
  826. {$ENDIF}
  827. End;
  828. End
  829. Else
  830. Begin
  831. SaveCursor := Screen.Cursor;
  832. Screen.Cursor := crHourGlass;
  833. Try
  834. IF Not TNodeData(Node.Data).Scanned And DoScanDir(Node) Then
  835. Begin
  836. ReadSubDirs(Node, DriveInfo[Drive].DriveType);
  837. End;
  838. Finally
  839. Screen.Cursor := SaveCursor;
  840. End;
  841. End;
  842. End;
  843. End; {CanExpand}
  844. (* Overwrite event OnGetImageIndex: *)
  845. procedure TDriveView.GetImageIndex(Node: TTreeNode);
  846. Begin
  847. IF TNodeData(Node.Data).IconEmpty Then
  848. SetImageIndex(Node);
  849. Inherited GetImageIndex(Node);
  850. End; {GetImageIndex}
  851. (* Overwrite event Loaded: *)
  852. Procedure TDriveView.Loaded;
  853. Begin
  854. Inherited Loaded;
  855. {Create the drive nodes:}
  856. RefreshRootNodes(False, dsDisplayName Or dvdsFloppy);
  857. {Set the initial directory:}
  858. IF (Length(FDirectory) > 0) And DirExists(FDirectory) Then
  859. Directory := FDirectory;
  860. fCreating := FALSE;
  861. End; {Loaded}
  862. (* Overwrite event OnDeletion: *)
  863. Procedure TDriveView.Delete(Node: TTreeNode);
  864. Var NodeData : TNodeData;
  865. Begin
  866. If Node = DragNode Then
  867. DragNode := NIL;
  868. IF Node = DropTarget Then
  869. Begin
  870. DropTarget := NIL;
  871. Update;
  872. End;
  873. NodeData := NIL;
  874. IF Assigned(Node) And Assigned(Node.Data) Then
  875. NodeData := TNodeData(Node.Data);
  876. Node.Data := NIL;
  877. Inherited Delete(Node);
  878. If Assigned(NodeData) Then
  879. NodeData.Destroy;
  880. End; {OnDelete}
  881. (* Overwrite event OnKeyDown: *)
  882. procedure TDriveView.KeyDown(var Key: Word; Shift: TShiftState);
  883. Begin
  884. IF (Key = VK_RETURN) And
  885. (ssAlt in Shift) And
  886. Not isEditing And
  887. Assigned(Selected) Then
  888. Begin
  889. DisplayPropertiesMenu(Selected);
  890. Key := 0;
  891. End;
  892. Inherited KeyDown(Key, Shift);
  893. End; {KeyDown}
  894. (* Overwrite event OnKeyPress: *)
  895. Procedure TDriveView.KeyPress(Var Key : Char);
  896. Begin
  897. IF Assigned(Selected) Then
  898. Begin
  899. IF Not isEditing Then
  900. Case Key of
  901. #13, ' ':
  902. Begin
  903. Selected.Expanded := Not Selected.Expanded;
  904. Key := #0;
  905. End;
  906. '/': Begin
  907. Selected.Collapse(True);
  908. Selected.MakeVisible;
  909. Key := #0;
  910. End;
  911. '*': Selected.MakeVisible;
  912. End {Case}
  913. Else
  914. IF (Pos(Key, coInvalidDosChars) <> 0) Then
  915. Begin
  916. Beep;
  917. Key := #0;
  918. End;
  919. End;
  920. Inherited KeyPress(Key);
  921. End; {KeyPress}
  922. Procedure TDriveView.KeyUp(var Key: Word; Shift: TShiftState);
  923. Var P : TPoint;
  924. Begin
  925. Inherited KeyUp(Key, Shift);
  926. IF (Key = VK_APPS) And Assigned(Selected) Then
  927. Begin
  928. P := ClientToScreen(Selected.DisplayRect(True).TopLeft);
  929. INC(P.Y, 20);
  930. DisplayContextMenu(Selected, P);
  931. End;
  932. End; {KeyUp}
  933. (* Overwrite event OnChange: *)
  934. Procedure TDriveView.Change(Node: TTreeNode);
  935. Var Drive : TDrive;
  936. OldSerial : DWORD;
  937. NewDir : String;
  938. LastDrive : TDrive;
  939. Begin
  940. IF Assigned(Node) Then
  941. Begin
  942. NewDir := GetDirPath(Node);
  943. IF NewDir <> FLastDir Then
  944. Begin
  945. Drive := NewDir[1];
  946. IF Length(FLastDir) > 0 Then
  947. LastDrive := FLastDir[1]
  948. Else
  949. LastDrive := #0;
  950. fChangeFlag := True;
  951. fLastDir := NewDir;
  952. OldSerial := DriveInfo[Drive].DriveSerial;
  953. DriveInfo.ReadDriveStatus(Drive, dsSize or dsImageIndex);
  954. With DriveInfo[Drive] Do
  955. Begin
  956. {MP}{IF Assigned(FDriveBox) Then
  957. TIEDriveComboBox(FDriveBox).Drive := NewDir[1];}
  958. IF Assigned(fDirView) And (fDirView.Path <> NewDir) Then
  959. fDirView.Path := NewDir;
  960. IF DriveReady Then
  961. Begin
  962. IF Not DirExists(NewDir) Then
  963. Begin
  964. ValidateDirectory(DriveStatus[Upcase(NewDir[1])].RootNode);
  965. Exit;
  966. End;
  967. DriveStatus[Drive].DefaultDir := AddSlash(NewDir);
  968. IF LastDrive <> Drive Then
  969. Begin
  970. {IF LastDrive < FirstFixedDrive Then
  971. TerminateWatchThread(LastDrive);}
  972. {$IFNDEF NO_THREADS}
  973. IF (LastDrive >= FirstDrive) And (DriveInfo[LastDrive].DriveType = DRIVE_REMOVABLE) Then
  974. TerminateWatchThread(LastDrive);
  975. {$ENDIF}
  976. {Drive serial has changed or is missing: allways reread the drive:}
  977. IF (DriveSerial <> OldSerial) Or (DriveSerial = 0) Then
  978. Begin
  979. IF TNodeData(DriveStatus[Drive].RootNode.Data).Scanned Then
  980. ScanDrive(Drive);
  981. IF Assigned(FOnInsertedDiskChange) Then
  982. FOnInsertedDiskChange(Self, Drive);
  983. End;
  984. If Assigned(fOnDiskChange) Then
  985. fOnDiskChange(Self, Drive);
  986. End;
  987. {$IFNDEF NO_THREADS}
  988. StartWatchThread;
  989. {$ENDIF}
  990. End
  991. Else {Drive not ready:}
  992. Begin
  993. DriveStatus[Drive].RootNode.DeleteChildren;
  994. DriveStatus[Drive].DefaultDir := EmptyStr;
  995. If (LastDrive <> Drive) Then
  996. Begin
  997. IF Assigned(fOnInsertedDiskChange) Then
  998. FOnInsertedDiskChange(Self, Drive);
  999. If Assigned(fOnDiskChange) Then
  1000. FOnDiskChange(Self, Drive);
  1001. End;
  1002. End;
  1003. End;
  1004. End;
  1005. End;
  1006. Inherited Change(Node);
  1007. End; {Change}
  1008. // ===========================================================
  1009. // Methods of object TDriveView:
  1010. // ===========================================================
  1011. constructor TDriveView.Create(AOwner: TComponent);
  1012. Var Drive : TDrive;
  1013. WinVer : TOSVersionInfo;
  1014. Begin
  1015. Inherited Create(AOwner);
  1016. fCreating := TRUE;
  1017. WinVer.dwOSVersionInfoSize := SizeOf(WinVer);
  1018. GetVersionEx(WinVer);
  1019. IF fChangeInterval = 0 Then
  1020. fChangeInterval := 1000;
  1021. For Drive := FirstDrive To LastDrive Do
  1022. With DriveStatus[Drive] Do
  1023. Begin
  1024. Scanned := False;
  1025. Verified := False;
  1026. RootNode := NIL;
  1027. DiscMonitor := NIL;
  1028. DefaultDir := EmptyStr;
  1029. {ChangeTimer: }
  1030. ChangeTimer := TTimer.Create(Self);
  1031. ChangeTimer.Interval := 0;
  1032. ChangeTimer.Enabled := False;
  1033. ChangeTimer.OnTimer := ChangeTimerOnTimer;
  1034. ChangeTimer.Tag := Ord(Drive);
  1035. End;
  1036. FFileOperator := TFileOperator.Create(Self);
  1037. FFileOperator.ProgressTitle := coFileOperatorTitle;
  1038. FFileOperator.Flags := [foAllowUndo, foNoConfirmMkDir];
  1039. FCompressedColor := clBlue;
  1040. FColorBold := clBlue;
  1041. FShowVolLabel := True;
  1042. FChangeFlag := False;
  1043. FContextMenu := False;
  1044. FLastDir := EmptyStr;
  1045. FValidateFlag := False;
  1046. FConfirmDelete := True;
  1047. FUseSystemContextMenu := True;
  1048. FCanChange := True;
  1049. FContinue := True;
  1050. FShowAnimation := False;
  1051. FDirectory := EmptyStr;
  1052. FFileNameDisplay := fndStored;
  1053. FReadDrives := True;
  1054. FForceRename := False;
  1055. FLastRenameName := '';
  1056. FRenameNode := NIL;
  1057. {Drag&drop:}
  1058. DragMode := dmAutomatic;
  1059. fConfirmOverwrite := True;
  1060. FDragDrive := #0;
  1061. DragFileList := TStringList.Create;
  1062. FLastPathCut := '';
  1063. FTargetPopupMenu := True;
  1064. FUseDragImages := (Win32PlatForm = VER_PLATFORM_WIN32_NT) Or (WinVer.dwMinorVersion > 0);
  1065. FStartPos.X := -1;
  1066. FStartPos.Y := -1;
  1067. FDragPos := FStartPos;
  1068. FExeDrag := False;
  1069. FDDLinkOnExeDrag := True;
  1070. FDD := TDragDropFilesEx.Create(Self);
  1071. With FDD Do
  1072. Begin
  1073. AcceptOwnDnd := True;
  1074. {MP}
  1075. {$IFDEF OLD_DND}
  1076. AutoDetectDnD := False;
  1077. {$ELSE}
  1078. DragDetect.Automatic := False;
  1079. {$ENDIF}
  1080. {/MP}
  1081. BringToFront := True;
  1082. CompleteFileList := True;
  1083. NeedValid := [nvFileName];
  1084. RenderDataOn := rdoEnterAndDropSync;
  1085. TargetPopUpMenu := FTargetPopupMenu;
  1086. {OnDragDetect := DDDragDetect;}
  1087. OnDragEnter := DDDragEnter;
  1088. OnDragLeave := DDDragLeave;
  1089. OnDragOver := DDDragOver;
  1090. OnProcessDropped := DDProcessDropped;
  1091. OnDrop := DDDrop;
  1092. OnQueryContinueDrag := DDQueryContinueDrag;
  1093. OnGiveFeedback := DDGiveFeedback;
  1094. ShellExtensions.DragDropHandler := True;
  1095. OnSpecifyDropTarget := DDSpecifyDropTarget;
  1096. End;
  1097. OnCustomDrawItem := InternalOnDrawItem;
  1098. End; {Create}
  1099. Procedure TDriveView.CreateWnd;
  1100. Var FileInfo : TShFileInfo;
  1101. PIDLWorkPlace : PItemIDList;
  1102. Begin
  1103. Inherited CreateWnd;
  1104. IF Not Assigned(Images) Then
  1105. Begin
  1106. Images := TImageList.Create(Self);
  1107. Images.Handle := SHGetFileInfo('', 0, FileInfo, SizeOf(FileInfo), SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
  1108. Images.ShareImages := True;
  1109. End;
  1110. IF Not Assigned(StateImages) Then
  1111. Begin
  1112. StateImages := TImageList.Create(Self);
  1113. StateImages.Handle := SHGetFileInfo('', 0, FileInfo, SizeOf(FileInfo), SHGFI_SYSICONINDEX or SHGFI_OPENICON);
  1114. StateImages.ShareImages := True;
  1115. End;
  1116. IF Not (csDesigning in ComponentState) Then
  1117. FDragImageList := TDragImageList.Create(Self);
  1118. IF Not Assigned(GlobalDragImageList) Then
  1119. GlobalDragImageList := FDragImageList;
  1120. IF Assigned(PopupMenu) Then
  1121. PopupMenu.Autopopup := False;
  1122. FParentForm := GetParentForm(Self);
  1123. OLECheck(shGetDesktopFolder(FDesktop));
  1124. OLECheck(shGetSpecialFolderLocation(Self.Handle, CSIDL_DRIVES, PIDLWorkPlace));
  1125. FDesktop.BindToObject(PIDLWorkPlace, NIL, IID_IShellFolder, Pointer(FWorkPlace));
  1126. FreePIDL(PIDLWorkPlace);
  1127. FDD.DragDropControl := Self;
  1128. FDD.SourceEffects := [deCopy, deMove, deLink];
  1129. FDD.TargetEffects := [deCopy, deMove, deLink];
  1130. End; {CreateWnd}
  1131. Destructor TDriveView.Destroy;
  1132. Var Drive : TDrive;
  1133. Begin
  1134. IF Assigned(Images) Then
  1135. Images.Free;
  1136. IF Assigned(StateImages) Then
  1137. StateImages.Free;
  1138. IF Assigned(FDragImageList) Then
  1139. Begin
  1140. IF GlobalDragImageList = FDragImageList Then
  1141. GlobalDragImageList := NIL;
  1142. FDragImageList.Free;
  1143. End;
  1144. For Drive := FirstDrive To LastDrive Do
  1145. With DriveStatus[Drive] Do
  1146. Begin
  1147. IF Assigned(DiscMonitor) Then
  1148. Discmonitor.Free;
  1149. IF Assigned(ChangeTimer) Then
  1150. ChangeTimer.Free;
  1151. End;
  1152. IF Assigned(FFileOperator) Then
  1153. FFileOperator.Free;
  1154. DragFileList.Destroy;
  1155. IF Assigned(FDD) Then
  1156. FDD.Free;
  1157. Inherited Destroy;
  1158. End; {Destroy}
  1159. Function TDriveView.GetNodeFromHItem(Item: TTVItem): TTreeNode;
  1160. begin
  1161. with Item do
  1162. if (state and TVIF_PARAM) <> 0 then
  1163. Result := Pointer(lParam)
  1164. else
  1165. Result := Items.GetNode(hItem);
  1166. end; {GetNodeFromItem}
  1167. Procedure TDriveView.CNNotify(Var Msg: TWMNotify);
  1168. Begin
  1169. Case Msg.NMHdr.code Of
  1170. TVN_BEGINDRAG: DDDragDetect(MK_LBUTTON, FStartPos, Mouse.CursorPos, ddsDrag);
  1171. TVN_BEGINRDRAG: DDDragDetect(MK_RBUTTON, FStartPos, Mouse.CursorPos, ddsDrag);
  1172. Else
  1173. Inherited;
  1174. End;
  1175. End; {CNNotify}
  1176. Procedure TDriveView.WMLButtonDown(var Msg: TWMLButtonDown);
  1177. Begin
  1178. FCanChange := False;
  1179. GetCursorPos(FStartPos);
  1180. Inherited;
  1181. End; {WMLButtonDown}
  1182. Procedure TDriveView.WMLButtonUp(var Msg: TWMLButtonDown);
  1183. Begin
  1184. FCanChange := True;
  1185. IF Assigned(DropTarget) And Assigned(DropTarget.Data) Then
  1186. Selected := DropTarget;
  1187. DropTarget := NIL;
  1188. Inherited;
  1189. End; {WMLButtonUp}
  1190. Procedure TDriveView.WMRButtonDown(var Msg: TWMRButtonDown);
  1191. Begin
  1192. GetCursorPos(FStartPos);
  1193. IF FDD.DragDetectStatus <> ddsDrag Then
  1194. fContextMenu := True;
  1195. Inherited;
  1196. End; {WMRButtonDown}
  1197. Procedure TDriveView.WMContextMenu(Var Msg: TWMContextMenu);
  1198. Var Node : TTreeNode;
  1199. DirWatched : Boolean;
  1200. P : TPoint;
  1201. Begin
  1202. IF Assigned(PopupMenu) Then
  1203. PopupMenu.Autopopup := False;
  1204. Inherited;
  1205. FStartPos.X := -1;
  1206. FStartPos.Y := -1;
  1207. Try
  1208. IF fContextMenu Then
  1209. Begin
  1210. P.X := Msg.XPos;
  1211. P.Y := Msg.YPos;
  1212. P := ScreenToClient(P);
  1213. Node := GetNodeAt(P.X, P.Y);
  1214. IF FUseSystemContextMenu And Assigned(Node) Then
  1215. Begin
  1216. IF Assigned(OnMouseDown) Then
  1217. OnMouseDown(Self, mbRight, [], Msg.XPos, Msg.YPos);
  1218. {$IFNDEF NO_THREADS}
  1219. DirWatched := NodeWatched(Node) And WatchThreadActive;
  1220. #else
  1221. DirWatched := False;
  1222. {$ENDIF}
  1223. DisplayContextMenu(Node);
  1224. IF Not DirWatched Then
  1225. ValidateDirectory(Node);
  1226. End
  1227. Else
  1228. Begin
  1229. {P.X := Msg.XPos;
  1230. P.Y := Msg.YPos;
  1231. P := ClientToScreen(P);}
  1232. IF Assigned(PopupMenu) And Not PopupMenu.AutoPopup Then
  1233. PopupMenu.Popup(Msg.XPos, Msg.YPos);
  1234. End;
  1235. End;
  1236. fContextMenu := False;
  1237. Finally
  1238. DropTarget := NIL;
  1239. End;
  1240. End; {WMContextMenu}
  1241. Procedure TDriveView.SetImageIndex(Node : TTreeNode);
  1242. Var FileInfo : TShFileInfo;
  1243. NodePath : String;
  1244. Begin
  1245. IF Assigned(Node) And TNodeData(Node.Data).IconEmpty Then
  1246. Begin
  1247. NodePath := GetDirPathName(Node);
  1248. IF Node.Level = 0 Then
  1249. Begin
  1250. With DriveInfo[NodePath[1]] Do
  1251. Begin
  1252. IF ImageIndex = 0 Then
  1253. Begin
  1254. DriveInfo.ReadDriveStatus(NodePath[1], dsImageIndex);
  1255. Node.ImageIndex := DriveInfo[NodePath[1]].ImageIndex;
  1256. End
  1257. Else
  1258. Node.ImageIndex := ImageIndex;
  1259. Node.SelectedIndex := Node.ImageIndex;
  1260. End;
  1261. End
  1262. Else
  1263. Begin
  1264. IF (DriveInfo[NodePath[1]].DriveType = DRIVE_REMOTE) Then
  1265. Begin
  1266. Node.ImageIndex := StdDirIcon;
  1267. Node.SelectedIndex := StdDirSelIcon;
  1268. End
  1269. Else
  1270. Begin
  1271. Try
  1272. SHGetFileInfo(PChar(NodePath), 0, FileInfo, SizeOf(FileInfo),
  1273. SHGFI_SYSICONINDEX Or SHGFI_SMALLICON);
  1274. IF (FileInfo.iIcon < Images.Count) And (FileInfo.iIcon > 0) Then
  1275. Begin
  1276. Node.ImageIndex := FileInfo.iIcon;
  1277. SHGetFileInfo(PChar(NodePath), 0, FileInfo, SizeOf(FileInfo),
  1278. SHGFI_SYSICONINDEX Or SHGFI_SMALLICON Or SHGFI_OPENICON);
  1279. Node.SelectedIndex := FileInfo.iIcon;
  1280. End
  1281. Else
  1282. Begin
  1283. Node.ImageIndex := StdDirIcon;
  1284. Node.SelectedIndex := StdDirSelIcon;
  1285. End;
  1286. Except
  1287. Begin
  1288. Node.ImageIndex := StdDirIcon;
  1289. Node.SelectedIndex := StdDirSelIcon;
  1290. End;
  1291. End;
  1292. End;
  1293. End;
  1294. End; {IconEmpty}
  1295. TNodeData(Node.Data).IconEmpty := False;
  1296. End; {SetImageIndex}
  1297. Function TDriveView.GetDriveText(Drive : TDrive) : String;
  1298. Begin
  1299. With DriveInfo[Drive] Do
  1300. Begin
  1301. IF fShowVolLabel And (Length(PrettyName) > 0) Then
  1302. Begin
  1303. Case fVolDisplayStyle Of
  1304. doPrettyName: Result := Prettyname;
  1305. doDisplayName: Result := DisplayName;
  1306. doLongPrettyName: Result := LongPrettyname;
  1307. End; {Case}
  1308. End Else
  1309. Result := Drive + ':';
  1310. End;
  1311. End; {GetDriveText}
  1312. Function TDriveView.GetValidDrivesStr : String;
  1313. Var Drive : TDrive;
  1314. Begin
  1315. Result := '';
  1316. For Drive := FirstDrive to LastDrive Do
  1317. IF DriveInfo[Drive].Valid Then
  1318. Result := Result + Drive;
  1319. End; {GetValidDriveStr}
  1320. Procedure TDriveView.GetNodeShellAttr(ParentFolder : iShellFolder; NodeData : TNodeData; Path : String; ContentMask : Boolean = True);
  1321. Begin
  1322. IF Not Assigned(ParentFolder) Or Not Assigned(NodeData) Then
  1323. Exit;
  1324. IF Not Assigned(NodeData.PIDL) Then
  1325. NodeData.PIDL := PIDL_GetFromParentFolder(ParentFolder, PChar(Path));
  1326. IF Assigned(NodeData.PIDL) Then
  1327. Begin
  1328. {NodeData.shAttr := SFGAO_CAPABILITYMASK or SFGAO_DISPLAYATTRMASK and
  1329. (not SFGAO_READONLY) or SFGAO_REMOVABLE or $F0000000 (* SFGAO_CONTENTSMASK *);}
  1330. IF ContentMask Then
  1331. NodeData.shAttr := SFGAO_DISPLAYATTRMASK Or SFGAO_CONTENTSMASK
  1332. Else
  1333. NodeData.shAttr := SFGAO_DISPLAYATTRMASK;
  1334. Try
  1335. IF Not Succeeded(ParentFolder.GetAttributesOf(1, NodeData.PIDL, NodeData.shAttr)) Then
  1336. NodeData.shAttr := 0;
  1337. Except
  1338. End;
  1339. IF Not Assigned(NodeData.ShellFolder) Then
  1340. ParentFolder.BindToObject(NodeData.PIDL, NIL, IID_IShellFolder, Pointer(NodeData.ShellFolder));
  1341. End;
  1342. End; {GetNodeAttr}
  1343. Procedure TDriveView.RefreshRootNodes(ScanDirectory : Boolean; dsFlags : Integer);
  1344. Var Drive : Char;
  1345. NewText : String;
  1346. NextDrive : TDrive;
  1347. D : TDrive;
  1348. SaveCursor : TCursor;
  1349. WasValid : Boolean;
  1350. OldSerial : DWORD;
  1351. wFirstDrive : TDrive;
  1352. NodeData : TNodeData;
  1353. Begin
  1354. {Fetch disabled drives from the registry:}
  1355. SaveCursor := Screen.Cursor;
  1356. Screen.Cursor := crHourGlass;
  1357. Try
  1358. IF dsFlags And dvdsFloppy <> 0 Then
  1359. wFirstDrive := FirstDrive
  1360. Else
  1361. wFirstDrive := FirstFixedDrive;
  1362. For Drive := wFirstDrive to LastDrive Do
  1363. Begin
  1364. With DriveInfo[Drive] Do
  1365. Begin
  1366. WasValid := {Valid And } Assigned(DriveStatus[Drive].RootNode);
  1367. OldSerial := DriveSerial;
  1368. End;
  1369. IF (dsFlags And dvdsReReadAllways = 0) And (Length(DriveInfo[Drive].DisplayName) > 0) Then
  1370. dsFlags := dsFlags And Not dsDisplayName;
  1371. IF FReadDrives Then
  1372. DriveInfo.ReadDriveStatus(Drive, dsFlags);
  1373. With DriveInfo[Drive], DriveStatus[Drive] Do
  1374. Begin
  1375. IF Valid Then
  1376. Begin
  1377. IF Not WasValid Then
  1378. {New drive has arrived: insert new rootnode:}
  1379. Begin
  1380. NextDrive := LastDrive;
  1381. IF Not fCreating Then
  1382. For D := Drive To LastDrive Do
  1383. Begin
  1384. IF Assigned(DriveStatus[D].RootNode) Then
  1385. Begin
  1386. NextDrive := D;
  1387. Break;
  1388. End;
  1389. End;
  1390. { Create root directory node }
  1391. NodeData := TNodeData.Create;
  1392. NodeData.DirName := Drive + ':\';
  1393. NodeData.ShortName := Drive + ':\';
  1394. {Get the shared attributes:}
  1395. IF Drive >= FirstFixedDrive Then
  1396. GetNodeShellAttr(FWorkPlace, NodeData, NodeData.DirName);
  1397. IF Assigned(DriveStatus[NextDrive].RootNode) Then
  1398. RootNode := Items.InsertObject(DriveStatus[NextDrive].RootNode, '', NodeData)
  1399. Else
  1400. RootNode := Items.AddObject(nil, '', NodeData);
  1401. If Bool(NodeData.shAttr And SFGAO_SHARE) Then
  1402. RootNode.OverlayIndex := 0;
  1403. RootNode.Text := GetDisplayName(RootNode);
  1404. RootNode.HasChildren := TRUE;
  1405. Scanned := False;
  1406. Verified := False;
  1407. End
  1408. Else
  1409. If RootNode.ImageIndex <> DriveInfo[Drive].ImageIndex Then
  1410. Begin {WasValid = True}
  1411. RootNode.ImageIndex := DriveInfo[Drive].ImageIndex;
  1412. RootNode.SelectedIndex := DriveInfo[Drive].ImageIndex;
  1413. End;
  1414. IF (Drive >= FirstFixedDrive) And Scanned Then
  1415. Begin
  1416. IF ScanDirectory And (DriveSerial <> OldSerial) Then
  1417. ScanDrive(Drive);
  1418. End;
  1419. IF Assigned(RootNode) Then
  1420. Begin
  1421. NewText := GetDisplayName(RootNode);
  1422. IF RootNode.Text <> NewText Then
  1423. RootNode.Text := NewText;
  1424. End;
  1425. End
  1426. Else
  1427. IF WasValid Then
  1428. {Drive has been removed => delete rootnode:}
  1429. Begin
  1430. IF Directory[1] = Drive Then
  1431. Begin
  1432. Directory := GetDirPathName(DriveStatus[Drive].RootNode.GetPrevSibling);
  1433. IF Not Assigned(Selected) Then
  1434. Directory := GetDirPathName(DriveStatus[FirstFixedDrive].RootNode);
  1435. End;
  1436. Scanned := False;
  1437. Verified := False;
  1438. RootNode.Delete;
  1439. RootNode := NIL;
  1440. End;
  1441. End;
  1442. End;
  1443. Finally
  1444. Screen.Cursor := SaveCursor;
  1445. End;
  1446. End; {RefreshRootNodes}
  1447. Function TDriveView.AddChildNode(ParentNode : TTreeNode; Srec : TSearchRec) : TTreeNode;
  1448. Var NewNode : TTreeNode;
  1449. NodeData : TNodeData;
  1450. Begin
  1451. NodeData := TNodeData.Create;
  1452. NodeData.Attr := Srec.Attr;
  1453. NodeData.DirName := Srec.Name;
  1454. NodeData.ShortName := Srec.FindData.cAlternateFileName;
  1455. NodeData.fisRecycleBin := (Srec.Attr And faSysFile <> 0) And
  1456. (ParentNode.Level = 0) And
  1457. (UpperCase(Srec.Name) = 'RECYCLED');
  1458. IF Not Assigned(TNodeData(ParentNode.Data).ShellFolder) Then
  1459. GetNodeShellAttr(FWorkPlace, TNodeData(ParentNode.Data), GetDirPathName(ParentNode));
  1460. GetNodeShellAttr(TNodeData(ParentNode.Data).ShellFolder, NodeData, SRec.Name );
  1461. NewNode := Self.Items.AddChildObject(ParentNode, '', NodeData);
  1462. NewNode.Text := GetDisplayName(NewNode);
  1463. If Bool(NodeData.shAttr And SFGAO_SHARE) Then
  1464. NewNode.OverlayIndex := 0;
  1465. Result := NewNode;
  1466. End; {AddChildNode}
  1467. Function TDriveView.GetDriveStatus(Drive : TDrive) : TDriveStatus;
  1468. Begin
  1469. Result := DriveStatus[Upcase(Drive)];
  1470. End; {GetDriveStatus}
  1471. Function TDriveView.DoScanDir(FromNode : TTreeNode) : Boolean;
  1472. Var ScanThisDir : Boolean;
  1473. Begin
  1474. With TNodeData(FromNode.Data) Do
  1475. ScanThisDir := Not isRecycleBin And (DirName <> 'RECYCLER');
  1476. IF Assigned(fOnScanDir) Then
  1477. fOnScanDir(Self, FromNode, ScanThisDir);
  1478. Result := ScanThisDir;
  1479. End; {DoScanDir}
  1480. Procedure TDriveView.ScanDrive(Drive : TDrive);
  1481. Var DosError : Integer;
  1482. RootNode : TTreeNode;
  1483. SaveCursor : TCursor;
  1484. FAnimate : TAnimate;
  1485. Procedure ScanPath(Const Path : String; ParentNode : TTreeNode);
  1486. Var Srec : TSearchRec;
  1487. SubNode : TTreeNode;
  1488. Begin
  1489. IF Not DoScanDir(ParentNode) Then
  1490. Exit;
  1491. DosError := FindFirst(Path, DirAttrMask, Srec);
  1492. While DosError = 0 Do
  1493. Begin
  1494. IF (Srec.Name <> '.') And
  1495. (Srec.Name <> '..') And
  1496. (Srec.Attr And faDirectory <> 0) Then
  1497. Begin
  1498. IF (Srec.Attr And faDirectory) <> 0 Then
  1499. Begin { Scan subdirectory }
  1500. SubNode := AddChildNode(ParentNode , Srec);
  1501. TNodeData(SubNode.Data).Scanned := True;
  1502. ScanPath(ExtractFilePath(Path) + Srec.Name + '\*.*', SubNode );
  1503. IF Not FContinue Then
  1504. Break;
  1505. End;
  1506. End;
  1507. DosError := FindNext(Srec);
  1508. End;
  1509. FindClose(Srec);
  1510. IF (Items.Count Mod 10) = 0 Then
  1511. Application.ProcessMessages;
  1512. IF Not FContinue Then
  1513. Exit;
  1514. End; {ScanPath}
  1515. Begin {ScanDrive}
  1516. with Self.Items do
  1517. begin
  1518. FContinue := True;
  1519. IF Not fFullDriveScan Then
  1520. Begin
  1521. ValidateDirectory(FindNodeToPath(Drive + ':\'));
  1522. DriveStatus[Drive].Scanned := TRUE;
  1523. DriveStatus[Drive].Verified := FALSE;
  1524. End
  1525. Else
  1526. Begin
  1527. FAnimate := NIL;
  1528. SaveCursor := Screen.Cursor;
  1529. Screen.Cursor := crHourglass;
  1530. Items.BeginUpdate;
  1531. IF FShowAnimation Then
  1532. Begin
  1533. FAnimate := TAnimate.Create(Self);
  1534. FAnimate.Top := (Height - FAnimate.Height) DIV 2;
  1535. FAnimate.Left := ((Width - FAnimate.Width) * 2) DIV 3;
  1536. FAnimate.Parent := Self;
  1537. FAnimate.CommonAVI := aviFindFolder;
  1538. FAnimate.Active := True;
  1539. End;
  1540. If Assigned(fOnStartScan) Then
  1541. fOnStartScan(Self);
  1542. Try
  1543. RootNode := DriveStatus[Drive].RootNode;
  1544. IF Not Assigned(RootNode) Then Exit;
  1545. IF RootNode.HasChildren Then
  1546. RootNode.DeleteChildren;
  1547. ScanPath(Drive + ':\*.*', RootNode); { scan subdirectories of rootdir}
  1548. TNodeData(RootNode.Data).Scanned := True;
  1549. DriveStatus[Drive].Scanned := TRUE;
  1550. DriveStatus[Drive].Verified := TRUE;
  1551. finally
  1552. SortChildren(DriveStatus[Drive].RootNode, True);
  1553. EndUpdate;
  1554. IF Assigned(FAnimate) Then
  1555. FAnimate.Free;
  1556. End;
  1557. RootNode.Expand(False);
  1558. Screen.Cursor := SaveCursor;
  1559. If Assigned(FOnEndScan) Then
  1560. FOnEndScan(Self);
  1561. End;
  1562. End;
  1563. End; {ScanDrive}
  1564. Function TDriveView.HasSubNodes(Node : TTreeNode) : Boolean;
  1565. Var NewNode : TTreeNode;
  1566. Begin
  1567. Result := Assigned(Node);
  1568. IF Result Then
  1569. Begin
  1570. NewNode := Node.GetFirstChild;
  1571. Result := Assigned(NewNode);
  1572. End;
  1573. End; {HasSubNodes}
  1574. Function TDriveView.FindNodeToPath(Path : String) : TTreeNode;
  1575. Var Drive: Char;
  1576. Function SearchSubDirs(ParentNode : TTreeNode; Path : String) : TTreeNode;
  1577. Var i : Integer;
  1578. Node : TTreeNode;
  1579. Dir : String;
  1580. Begin
  1581. Result := NIL;
  1582. IF Length(Path) = 0 Then
  1583. Exit;
  1584. {Extract first directory from path:}
  1585. i := Pos('\', Path);
  1586. IF (i = 0) Then
  1587. i := Length(Path);
  1588. Dir := System.Copy(Path, 1, i);
  1589. System.Delete(Path, 1, i);
  1590. IF Dir[Length(Dir)] = '\' Then
  1591. SetLength(Dir, Pred(Length(Dir)));
  1592. IF Not TNodeData(ParentNode.Data).Scanned Then
  1593. ReadSubDirs(ParentNode, GetDriveTypeToNode(ParentNode));
  1594. Result := NIL;
  1595. Node := ParentNode.GetFirstChild;
  1596. IF Not Assigned(Node) Then
  1597. Begin
  1598. ValidateDirectoryEx(ParentNode, rsRecursiveExisting, True);
  1599. Node := ParentNode.GetFirstChild;
  1600. End;
  1601. While Assigned(Node) Do
  1602. Begin
  1603. IF (UpperCase(GetDirName(Node)) = Dir) OR (TNodeData(Node.Data).ShortName = Dir) Then
  1604. Begin
  1605. IF Length(Path) > 0 Then
  1606. Result := SearchSubDirs(Node, Path)
  1607. Else
  1608. Result := Node;
  1609. Exit;
  1610. End;
  1611. Node := ParentNode.GetNextChild(Node);
  1612. End;
  1613. End; {SearchSubDirs}
  1614. Begin {FindNodeToPath}
  1615. Result := NIL;
  1616. IF Length(Path) < 3 Then
  1617. Exit;
  1618. Drive := UpCase(Path[1]);
  1619. IF (Drive < FirstDrive) Or (Drive > LastDrive) Then
  1620. EConvertError.Create(Format(ErrorInvalidDrive, [Drive]))
  1621. Else
  1622. IF Assigned(DriveStatus[Drive].RootNode) Then
  1623. Begin
  1624. System.Delete(Path, 1, 3);
  1625. IF Length(Path) > 0 Then
  1626. Begin
  1627. IF Not DriveStatus[Drive].Scanned Then
  1628. ScanDrive(Drive);
  1629. Result := SearchSubDirs(DriveStatus[Drive].RootNode, UpperCase(Path));
  1630. End
  1631. Else
  1632. Result := DriveStatus[Drive].RootNode;
  1633. End;
  1634. End; {FindNodetoPath}
  1635. Function TDriveView.IterateSubTree(Var StartNode : TTreeNode;
  1636. CallBackFunc : TCallBackFunc;
  1637. Recurse : TRecursiveScan;
  1638. ScanStartNode : TScanStartNode;
  1639. Data : Pointer) : Boolean;
  1640. (* Scans StartNode and level-1 Subdirectories plus open subdirectories*)
  1641. Function ScanSubDirs(Var StartNode : TTreeNode) : Boolean;
  1642. (* Scans all subdirectories of Startnode *)
  1643. Var Node : TTreeNode;
  1644. NextNode : TTreeNode;
  1645. NodeHasChilds : Boolean;
  1646. Begin
  1647. Result := False;
  1648. IF Not Assigned(StartNode) Then Exit;
  1649. Node := StartNode.GetFirstChild;
  1650. While Assigned(Node) And FContinue Do
  1651. Begin
  1652. NextNode := StartNode.GetNextChild(Node);
  1653. NodeHasChilds := HasSubNodes(Node);
  1654. IF Not FContinue Or Not CallBackFunc(Node, Data) Then
  1655. Exit;
  1656. IF Assigned(Node) And
  1657. ((Recurse = rsRecursive) Or
  1658. ((Recurse = rsRecursiveExpanded) And Node.Expanded) Or
  1659. ((Recurse = rsRecursiveExisting) And NodeHasChilds)) Then
  1660. IF Not ScanSubDirs(Node) Or Not FContinue Then
  1661. Exit;
  1662. Node := NextNode;
  1663. End;
  1664. Result := True;
  1665. End; {ScanSubDirs}
  1666. Begin {IterateSubTree}
  1667. Result := False;
  1668. FContinue := True;
  1669. IF Not Assigned(CallBackFunc) Then
  1670. Exit;
  1671. IF ScanStartNode = coScanStartNode Then
  1672. CallBackFunc(StartNode, Data);
  1673. IF Assigned(StartNode) Then
  1674. IF Not FContinue Or Not ScanSubDirs(StartNode) Then
  1675. Exit;
  1676. Result := True;
  1677. End; {IterateSubTree}
  1678. Function TDriveView.CheckForSubDirs(Path: String) : Boolean;
  1679. Var DosError : Integer;
  1680. SRec : TSearchRec;
  1681. Begin
  1682. Result := False;
  1683. DosError := FindFirst(AddSlash(Path) + '*.', DirAttrMask, SRec);
  1684. While DosError = 0 Do
  1685. Begin
  1686. IF (Srec.Name <> '.' ) And
  1687. (Srec.Name <> '..') And
  1688. (Srec.Attr And faDirectory <> 0) Then
  1689. Begin
  1690. Result := True;
  1691. Break;
  1692. End;
  1693. DosError := FindNext(Srec);
  1694. End;
  1695. FindClose(Srec);
  1696. End; {CheckForSubDirs}
  1697. Function TDriveView.ReadSubDirs(Node : TTreeNode; DriveType: Integer) : Boolean;
  1698. Var DosError : Integer;
  1699. SRec : TSearchRec;
  1700. NewNode : TTreeNode;
  1701. Begin
  1702. Result := False;
  1703. DosError := FindFirst(AddSlash(GetDirPath(Node)) + '*.*', DirAttrMask, SRec);
  1704. While DosError = 0 Do
  1705. Begin
  1706. IF (Srec.Name <> '.' ) And
  1707. (Srec.Name <> '..') And
  1708. (Srec.Attr And faDirectory <> 0) Then
  1709. Begin
  1710. NewNode := AddChildNode(Node, SRec);
  1711. IF DoScanDir(NewNode) Then
  1712. Begin
  1713. NewNode.HasChildren := Bool(TNodeData(NewNode.Data).shAttr And SFGAO_HASSUBFOLDER);
  1714. {IF (DriveType = DRIVE_REMOTE) Then
  1715. NewNode.HasChildren := CheckForSubDirs(GetDirPath(NewNode))
  1716. Else
  1717. NewNode.HasChildren := Bool(TNodeData(NewNode.Data).shAttr And SFGAO_HASSUBFOLDER);}
  1718. TNodeData(NewNode.Data).Scanned := Not NewNode.HasChildren;
  1719. End
  1720. Else
  1721. Begin
  1722. NewNode.HasChildren := False;
  1723. TNodeData(NewNode.Data).Scanned := True;
  1724. End;
  1725. Result := True;
  1726. End;
  1727. DosError := FindNext(Srec);
  1728. End; {While DosError = 0}
  1729. FindClose(Srec);
  1730. TNodeData(Node.Data).Scanned := True;
  1731. IF Result Then
  1732. {Sort subnodes:}
  1733. SortChildren(Node, False)
  1734. Else
  1735. Node.HasChildren := False;
  1736. Application.ProcessMessages;
  1737. End; {ReadSubDirs}
  1738. Function TDriveView.CallBackValidateDir(Var Node : TTreeNode; Data: Pointer) : Boolean;
  1739. Type PSearchRec = ^TSearchRec;
  1740. Var WorkNode : TTreeNode;
  1741. DelNode : TTreeNode;
  1742. NewNode : TTreeNode;
  1743. SRec : TSearchRec;
  1744. SrecList : TStringList;
  1745. SubDirList : TStringList;
  1746. DosError : Integer;
  1747. Index : Integer;
  1748. NewDirFound : Boolean;
  1749. ParentDir : String;
  1750. Begin {CallBackValidateDir}
  1751. Result := True;
  1752. IF Not Assigned(Node) Or Not Assigned(Node.Data) Then
  1753. Exit;
  1754. NewDirFound := False;
  1755. {Check, if directory still exists: (but not with root directory) }
  1756. IF Assigned(Node.Parent) And (PScanDirInfo(Data)^.StartNode = Node) Then
  1757. IF Not DirExists(GetDirPathName(Node)) Then
  1758. Begin
  1759. WorkNode := Node.Parent;
  1760. IF Selected = Node Then
  1761. Selected := WorkNode;
  1762. IF DropTarget = Node Then
  1763. DropTarget := NIL;
  1764. Node.Delete;
  1765. Node := NIL;
  1766. Exit;
  1767. End;
  1768. WorkNode := Node.GetFirstChild;
  1769. IF TNodeData(Node.Data).Scanned And Assigned(WorkNode) Then
  1770. {if node was already scanned: check wether the existing subnodes are still alive
  1771. and add all new subdirectories as subnodes:}
  1772. Begin
  1773. IF DoScanDir(Node) Then
  1774. Begin
  1775. ParentDir := AddSlash(GetDirPath(Node));
  1776. {Build list of existing subnodes:}
  1777. SubDirList := TStringList.Create;
  1778. While Assigned(Worknode) Do
  1779. Begin
  1780. SubDirList.Add(TNodeData(WorkNode.Data).DirName);
  1781. WorkNode := Node.GetNextChild(WorkNode);
  1782. End;
  1783. {Sorting not required, because the subnodes are already sorted!}
  1784. {SubDirList.Sort;}
  1785. SRecList := TStringList.Create;
  1786. DosError := FindFirst(ParentDir + '*.*', DirAttrMask, SRec);
  1787. While DosError = 0 Do
  1788. Begin
  1789. IF (Srec.Name <> '.' ) And
  1790. (Srec.Name <> '..') And
  1791. (Srec.Attr And faDirectory <> 0) Then
  1792. Begin
  1793. SrecList.Add(Srec.Name);
  1794. IF Not SubDirList.Find(Srec.Name, Index) Then
  1795. {Subnode does not exists: add it:}
  1796. Begin
  1797. NewNode := AddChildNode(Node, SRec);
  1798. NewNode.HasChildren := CheckForSubDirs(ParentDir + Srec.Name);
  1799. TNodeData(NewNode.Data).Scanned := Not NewNode.HasChildren;
  1800. NewDirFound := True;
  1801. End;
  1802. End;
  1803. DosError := FindNext(Srec);
  1804. End;
  1805. FindClose(Srec);
  1806. Sreclist.Sort;
  1807. {Remove not existing subnodes:}
  1808. WorkNode := Node.GetFirstChild;
  1809. While Assigned(WorkNode) Do
  1810. Begin
  1811. IF Not Assigned(WorkNode.Data) Or
  1812. NOT SrecList.Find(TNodeData(WorkNode.Data).DirName, Index) Then
  1813. Begin
  1814. DelNode := WorkNode;
  1815. WorkNode := Node.GetNextChild(WorkNode);
  1816. DelNode.Delete;
  1817. End
  1818. Else
  1819. Begin
  1820. IF (SrecList[Index] <> TNodeData(WorkNode.Data).DirName) Then
  1821. Begin
  1822. {Case of directory letters has changed:}
  1823. TNodeData(WorkNode.Data).DirName := SrecList[Index];
  1824. TNodeData(WorkNode.Data).ShortName := ExtractShortPathName(GetDirPathName(WorkNode));
  1825. WorkNode.Text := SrecList[Index];
  1826. End;
  1827. SrecList.Delete(Index);
  1828. WorkNode := Node.GetNextChild(WorkNode);
  1829. End;
  1830. End;
  1831. SrecList.Free;
  1832. SubDirList.Free;
  1833. {Sort subnodes:}
  1834. IF NewDirFound Then
  1835. SortChildren(Node, False);
  1836. End;
  1837. End
  1838. Else
  1839. {Node was not already scanned:}
  1840. IF (PScanDirInfo(Data)^.SearchNewDirs Or
  1841. TNodeData(Node.Data).Scanned Or
  1842. (Node = PScanDirInfo(Data)^.StartNode)) And
  1843. DoScanDir(Node) Then
  1844. ReadSubDirs(Node, PScanDirInfo(Data)^.DriveType);
  1845. {Application.ProcessMessages; <== causes the treeview flickering!}
  1846. End; {CallBackValidateDir}
  1847. Procedure TDriveView.ValidateDirectoryEx(Node : TTreeNode; Recurse : TRecursiveScan; NewDirs : Boolean);
  1848. Var Info : PScanDirInfo;
  1849. SelDir : String;
  1850. SaveCursor : TCursor;
  1851. {$IFNDEF NO_THREADS}
  1852. RestartWatchThread : Boolean;
  1853. {$ENDIF}
  1854. SaveCanChange : Boolean;
  1855. CurrentPath : String;
  1856. Begin
  1857. IF Not Assigned(Node) Or
  1858. Not Assigned(Node.Data) Or
  1859. fValidateFlag Or
  1860. Not DoScanDir(Node) Then
  1861. Exit;
  1862. SelDir := Directory;
  1863. SaveCursor := Screen.Cursor;
  1864. IF Self.Focused And (Screen.Cursor <> crHourGlass) Then
  1865. Screen.Cursor := crHourGlass;
  1866. CurrentPath := GetDirPath(Node);
  1867. IF Node.Level = 0 Then
  1868. DriveStatus[CurrentPath[1]].ChangeTimer.Enabled := False;
  1869. {$IFNDEF NO_THREADS}
  1870. RestartWatchThread := WatchThreadActive;
  1871. {$ENDIF}
  1872. Try
  1873. {$IFNDEF NO_THREADS}
  1874. IF WatchThreadActive Then
  1875. StopWatchThread;
  1876. {$ENDIF}
  1877. fValidateFlag := True;
  1878. New(Info);
  1879. Info^.StartNode := Node;
  1880. Info^.SearchNewDirs := NewDirs;
  1881. Info^.DriveType := DriveInfo[CurrentPath[1]].DriveType;
  1882. SaveCanChange := FCanChange;
  1883. FCanChange := True;
  1884. FChangeFlag := False;
  1885. IterateSubTree(Node, CallBackValidateDir, Recurse, coScanStartNode, Info);
  1886. fValidateFlag := False;
  1887. IF Not Assigned(Selected) And (Length(SelDir) > 0) Then
  1888. Directory := Copy(SelDir, 1, 3);
  1889. IF (SelDir <> Directory) And Not FChangeFlag Then
  1890. Change(Selected);
  1891. FCanChange := SaveCanChange;
  1892. Dispose(Info);
  1893. Finally
  1894. {$IFNDEF NO_THREADS}
  1895. IF RestartWatchThread And fWatchDirectory And Not WatchThreadActive Then
  1896. StartWatchThread;
  1897. {$ENDIF}
  1898. IF Screen.Cursor <> SaveCursor Then
  1899. Screen.Cursor := SaveCursor;
  1900. End;
  1901. End; {ValidateDirectoryEx}
  1902. Procedure TDriveView.ValidateDirectoryEasy(Node : TTreeNode);
  1903. Begin
  1904. IF Not Assigned(Node) Then
  1905. Exit;
  1906. IF Not Assigned(Node.Data) or Not TNodeData(Node.Data).Scanned Then
  1907. ValidateDirectoryEx(Node, rsRecursiveExpanded, False);
  1908. End; {ValidateDirectoryEasy}
  1909. Procedure TDriveView.ValidateDirectory(Node : TTreeNode);
  1910. Begin
  1911. ValidateDirectoryEx(Node, rsRecursiveExisting, False);
  1912. End; {ValidateDirectory}
  1913. Procedure TDriveView.ValidateVisibleDirectories(Node : TTreeNode);
  1914. Begin
  1915. ValidateDirectoryEx(Node, rsRecursiveExpanded, False);
  1916. End; {ValidateVisibleDirectories}
  1917. Procedure TDriveView.ValidateAllDirectories(Node : TTreeNode);
  1918. Begin
  1919. ValidateDirectoryEx(Node, rsRecursive, True);
  1920. End; {ValidateAllDirectories}
  1921. Function TDriveView.GetSubTreeSize(Node : TTreeNode) : Integer;
  1922. Var PSubSize : PInt;
  1923. SaveCursor : TCursor;
  1924. Begin
  1925. IF Not Assigned(Node) Then
  1926. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['GetSubTreeSize']));
  1927. SaveCursor := Screen.Cursor;
  1928. Screen.Cursor := crHourGlass;
  1929. ValidateAllDirectories(Node);
  1930. RefreshDirSize(Node);
  1931. New(PSubSize);
  1932. PSubSize^ := 0;
  1933. IterateSubTree(Node, CallBackSetDirSize, rsRecursive, coScanStartNode, PSubSize);
  1934. Result := PSubSize^;
  1935. Dispose(PSubSize);
  1936. Screen.Cursor := SaveCursor;
  1937. End; {GetSubTreeSize}
  1938. Function TDriveView.GetDriveTypeToNode(Node : TTreeNode) : Integer;
  1939. Begin
  1940. IF Not Assigned(Node) Then
  1941. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['GetDriveTypeToNode']));
  1942. Result := DriveInfo[GetDirPath(Node)[1]].DriveType
  1943. End; {GetDriveTypeToNode}
  1944. Function TDriveView.GetDriveType(Drive : TDrive) : Integer; {Returns DRIVE_CDROM etc..}
  1945. Begin
  1946. Result := DriveInfo[UpCase(Drive)].DriveType;
  1947. End; {GetDriveType}
  1948. Function TDriveView.NodeUpdateAble(Node : TTreeNode) : Boolean;
  1949. Begin
  1950. Result := Assigned(Node) And
  1951. Assigned(Node.Data) And
  1952. (Node.Level > 0);
  1953. End; {NodeUpdateAble}
  1954. Function TDriveView.CallBackSaveNodeState(Var Node : TTreeNode; Data: Pointer) : Boolean;
  1955. Begin
  1956. Result := True;
  1957. TNodeData(Node.Data).Expanded := Node.Expanded;
  1958. End; {CallBackSaveNodeState}
  1959. Function TDriveView.CallBackRestoreNodeState(Var Node : TTreeNode; Data: Pointer) : Boolean;
  1960. Begin
  1961. Result := True;
  1962. Node.Expanded := TNodeData(Node.Data).Expanded;
  1963. End; {CallBackRestoreNodeState}
  1964. Procedure TDriveView.SaveNodesState(Node : TTreeNode);
  1965. Begin
  1966. IterateSubTree(Node, CallbackSaveNodeState, rsRecursive, coScanStartNode, NIL);
  1967. End; {SaveNodesState}
  1968. Procedure TDriveView.RestoreNodesState(Node : TTreeNode);
  1969. Begin
  1970. Items.BeginUpdate;
  1971. IterateSubTree(Node, CallbackRestoreNodeState, rsRecursive, coScanStartNode, NIL);
  1972. Items.EndUpdate;
  1973. End; {RestoreNodesState}
  1974. Function TDriveView.CreateDirectory(ParentNode : TTreeNode; NewName : String) : TTreeNode;
  1975. Var Srec : TSearchRec;
  1976. Begin
  1977. IF Not Assigned(ParentNode) Then
  1978. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['CreateDirectory']));
  1979. Result := NIL;
  1980. IF Not TNodeData(ParentNode.Data).Scanned Then
  1981. ValidateDirectory(ParentNode);
  1982. {$IFNDEF NO_THREADS}
  1983. StopWatchThread;
  1984. {$ENDIF}
  1985. Try
  1986. {$IFNDEF NO_THREADS}
  1987. IF Assigned(FDirView) Then
  1988. FDirView.StopWatchThread;
  1989. {$ENDIF}
  1990. {create phyical directory:}
  1991. LastIOResult := 0;
  1992. IF Not Windows.CreateDirectory(PChar(GetDirPath(ParentNode) + '\' + NewName), NIL) Then
  1993. LastIOResult := GetLastError;
  1994. IF LastIOResult = 0 Then
  1995. Begin
  1996. {Create treenode:}
  1997. FindFirst(GetDirPath(ParentNode) + '\' + NewName, faAnyFile, SRec);
  1998. Result := AddChildNode(ParentNode, Srec);
  1999. FindClose(Srec);
  2000. TNodeData(Result.Data).Scanned := True;
  2001. SortChildren(ParentNode, False);
  2002. ParentNode.Expand(False);
  2003. End;
  2004. Finally
  2005. {$IFNDEF NO_THREADS}
  2006. StartWatchThread;
  2007. {$ENDIF}
  2008. IF Assigned(FDirView) Then
  2009. Begin
  2010. {$IFNDEF NO_THREADS}
  2011. FDirView.StartWatchThread;
  2012. {$ENDIF}
  2013. FDirView.Reload2;
  2014. End;
  2015. End;
  2016. End; {CreateDirectory}
  2017. Function TDriveView.DeleteDirectory(Node: TTreeNode; AllowUndo : Boolean) :Boolean;
  2018. Var DelDir : String;
  2019. OperatorResult : Boolean;
  2020. FileOperator : TFileOperator;
  2021. SaveCursor : TCursor;
  2022. Begin
  2023. IF Not Assigned(Node) Then
  2024. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['DeleteDirectory']));
  2025. Result := False;
  2026. IF Assigned(Node) And (Node.Level > 0) Then
  2027. Begin
  2028. SaveCursor := Screen.Cursor;
  2029. Screen.Cursor := crHourGlass;
  2030. FileOperator := TFileOperator.Create(Self);
  2031. DelDir := GetDirPathName(Node);
  2032. FileOperator.OperandFrom.Add(DelDir);
  2033. FileOperator.Operation := foDelete;
  2034. IF AllowUndo Then
  2035. FileOperator.Flags := FileOperator.Flags + [foAllowUndo]
  2036. Else
  2037. FileOperator.Flags := FileOperator.Flags - [foAllowUndo];
  2038. IF Not ConfirmDelete Then
  2039. FileOperator.Flags := FileOperator.Flags + [foNoConfirmation];
  2040. Try
  2041. IF DirExists(DelDir) Then
  2042. Begin
  2043. {$IFNDEF NO_THREADS}
  2044. StopWatchThread;
  2045. {$ENDIF}
  2046. OperatorResult := FileOperator.Execute;
  2047. IF OperatorResult And Not FileOperator.OperationAborted And Not DirExists(DelDir) Then
  2048. Node.Delete
  2049. Else
  2050. Begin
  2051. Result := False;
  2052. IF (Win32PlatForm = VER_PLATFORM_WIN32_NT) And Not AllowUndo Then
  2053. Begin
  2054. {WinNT4-Bug: FindFirst still returns the directories search record, even if the
  2055. directory was deleted:}
  2056. ChDir(DelDir);
  2057. IF IOResult <> 0 Then
  2058. Node.Delete;
  2059. End;
  2060. End;
  2061. End
  2062. Else
  2063. Begin
  2064. Node.Delete;
  2065. Result := True;
  2066. End;
  2067. Finally
  2068. {$IFNDEF NO_THREADS}
  2069. StartWatchThread;
  2070. createthread
  2071. {$ENDIF}
  2072. IF Assigned(DirView) And Assigned(Selected) Then
  2073. DirView.Path := GetDirPathName(Selected);
  2074. FileOperator.Free;
  2075. Screen.Cursor := SaveCursor;
  2076. End;
  2077. End;
  2078. End; {DeleteDirectory}
  2079. {$IFNDEF NO_THREADS}
  2080. Procedure TDriveView.CreateWatchThread(Drive : TDrive);
  2081. Begin
  2082. IF (csDesigning in ComponentState) Then
  2083. Exit;
  2084. IF Not Assigned(DriveStatus[Drive].DiscMonitor) And
  2085. FWatchDirectory And
  2086. (DriveInfo[Drive].DriveType <> DRIVE_REMOTE) And
  2087. (Pos(Drive, FNoCheckDrives) = 0) Then
  2088. With DriveStatus[Drive] Do
  2089. Begin
  2090. DiscMonitor := TDiscMonitor.Create(Self);
  2091. DiscMonitor.ChangeDelay := msThreadChangeDelay;
  2092. DiscMonitor.SubTree := True;
  2093. DiscMonitor.Filters := [moDirName];
  2094. DiscMonitor.OnChange := ChangeDetected;
  2095. DiscMonitor.OnInvalid := ChangeInvalid;
  2096. DiscMonitor.Directory := Drive + ':\';
  2097. DiscMonitor.Open;
  2098. End;
  2099. End; {CreateWatchThread}
  2100. {$ENDIF}
  2101. Procedure TDriveView.SetWatchDirectory(Watch : Boolean);
  2102. Begin
  2103. IF fWatchDirectory <> Watch Then
  2104. Begin
  2105. fWatchDirectory := Watch;
  2106. {$IFNDEF NO_THREADS}
  2107. IF Not (csDesigning in ComponentState) And Watch Then
  2108. StartAllWatchThreads
  2109. Else
  2110. StopAllWatchThreads;
  2111. {$ENDIF}
  2112. End;
  2113. End; {SetAutoScan}
  2114. Procedure TDriveView.SetDirView(DV : TDirView);
  2115. Begin
  2116. IF Assigned(fDirView) Then
  2117. fDirView.DriveView := NIL;
  2118. fDirView := DV;
  2119. IF Assigned(fDirView) Then
  2120. fDirView.DriveView := Self;
  2121. End; {SetDirView}
  2122. Procedure TDriveView.SetChangeInterval(Interval : Cardinal);
  2123. Var Drive : TDrive;
  2124. Begin
  2125. IF Interval > 0 Then
  2126. Begin
  2127. fChangeInterval := Interval;
  2128. For Drive := FirstDrive To LastDrive Do
  2129. With DriveStatus[Drive] Do
  2130. IF Assigned(ChangeTimer) Then
  2131. ChangeTimer.Interval := Interval;
  2132. End;
  2133. End; {SetChangeInterval}
  2134. Procedure TDriveView.SetDimmHiddenDirs(DimmIt : Boolean);
  2135. Begin
  2136. IF DimmIt <> fDimmHiddenDirs Then
  2137. Begin
  2138. fDimmHiddenDirs := DimmIt;
  2139. Self.Invalidate;
  2140. End;
  2141. End; {SetDimmHiddenDirs}
  2142. Procedure TDriveView.SetNoCheckDrives(Value : String);
  2143. Begin
  2144. FNoCheckDrives := UpperCase(Value);
  2145. End; {SetNoCheckDrives}
  2146. Procedure TDriveView.DeleteSubNodes(Node : TTreeNode);
  2147. Begin
  2148. IF Assigned(Node) Then
  2149. Begin
  2150. Node.DeleteChildren;
  2151. IF Node.Level = 0 Then
  2152. DriveStatus[GetDriveToNode(Node)].Scanned := False;
  2153. Node.HasChildren := False;
  2154. End;
  2155. End; {DeleteSubNodes}
  2156. Function TDriveView.NodeWatched(Node : TTreeNode) : Boolean;
  2157. Var Drive : TDrive;
  2158. Begin
  2159. Drive := GetDriveToNode(Node);
  2160. Result := Assigned(DriveStatus[Drive].DiscMonitor) And
  2161. DriveStatus[Drive].DiscMonitor.Active;
  2162. End; {NodeWatched}
  2163. procedure TDriveView.ChangeInvalid(Sender: TObject);
  2164. Var Dir : String;
  2165. Begin
  2166. Dir := (Sender as TDiscMonitor).Directory;
  2167. With DriveStatus[Dir[1]] Do
  2168. Begin
  2169. DiscMonitor.Close;
  2170. IF Assigned(fOnChangeInvalid) Then
  2171. fOnChangeInvalid(Self, Dir[1]);
  2172. End;
  2173. End; {DirWatchChangeInvalid}
  2174. procedure TDriveView.ChangeDetected(Sender: TObject);
  2175. Var DirChanged : String;
  2176. Begin
  2177. IF (Sender is TDiscMonitor) Then
  2178. Begin
  2179. DirChanged := (Sender as TDiscMonitor).Directory;
  2180. IF Length(DirChanged) > 0 Then
  2181. With DriveStatus[DirChanged[1]] Do
  2182. Begin
  2183. ChangeTimer.Interval := 0;
  2184. ChangeTimer.Interval := fChangeInterval;
  2185. ChangeTimer.Enabled := True;
  2186. End;
  2187. End;
  2188. End; {DirWatchChangeDetected}
  2189. Procedure TDriveView.ChangeTimerOnTimer(Sender : TObject);
  2190. Var Node : TTreeNode;
  2191. Drive : TDrive;
  2192. Begin
  2193. IF Sender is TTimer Then
  2194. With TTimer(Sender) Do
  2195. Begin
  2196. Drive := Chr(Tag);
  2197. Node := FindNodeToPath(Drive + ':\');
  2198. Interval := 0;
  2199. Enabled := False;
  2200. IF Assigned(Node) Then
  2201. Begin
  2202. {Check also collapsed (invisible) subdirectories:}
  2203. ValidateDirectory(Node);
  2204. IF Assigned(fOnChangeDetected) Then
  2205. fOnChangeDetected(Self, Drive);
  2206. End;
  2207. End;
  2208. End; {ChangeTimerOnTimer}
  2209. {$IFNDEF NO_THREADS}
  2210. Procedure TDriveView.StartWatchThread;
  2211. Var NewWatchedDir : String;
  2212. Drive : TDrive;
  2213. Begin
  2214. IF (csDesigning in ComponentState) Or
  2215. Not Assigned(Selected) Or
  2216. Not fWatchDirectory Then
  2217. Exit;
  2218. NewWatchedDir := GetDirPathName(RootNode(Selected));
  2219. Drive := Upcase(NewWatchedDir[1]);
  2220. With DriveStatus[Drive] Do
  2221. Begin
  2222. IF Not Assigned(DiscMonitor) Then
  2223. CreateWatchThread(Drive);
  2224. IF Assigned(DiscMonitor) And Not DiscMonitor.Active Then
  2225. DiscMonitor.Open;
  2226. End;
  2227. End; {StartWatchThread}
  2228. Procedure TDriveView.StopWatchThread;
  2229. Begin
  2230. IF Assigned(Selected) Then
  2231. With DriveStatus[GetDriveToNode(Selected)] Do
  2232. IF Assigned(DiscMonitor) Then
  2233. DiscMonitor.Close;
  2234. End; {StopWatchThread}
  2235. Procedure TDriveView.TerminateWatchThread(Drive : TDrive);
  2236. Begin
  2237. IF Drive >= FirstDrive Then
  2238. With DriveStatus[Drive] Do
  2239. IF Assigned(DiscMonitor) Then
  2240. Begin
  2241. DiscMonitor.Free;
  2242. DiscMonitor := NIL;
  2243. End;
  2244. End; {StopWatchThread}
  2245. Procedure TDriveView.StartAllWatchThreads;
  2246. Var Drive : TDrive;
  2247. Begin
  2248. IF (csDesigning in ComponentState) Or
  2249. Not FWatchDirectory Then
  2250. Exit;
  2251. For Drive := FirstFixedDrive To LastDrive Do
  2252. With DriveStatus[Drive] Do
  2253. IF Scanned Then
  2254. Begin
  2255. IF Not Assigned(DiscMonitor) Then
  2256. CreateWatchThread(Drive);
  2257. IF Assigned(DiscMonitor) And Not DiscMonitor.Active Then
  2258. DiscMonitor.Open;
  2259. End;
  2260. IF Assigned(Selected) And (GetDriveToNode(Selected) < FirstFixedDrive) Then
  2261. StartWatchThread;
  2262. End; {StartAllWatchThreads}
  2263. Procedure TDriveView.StopAllWatchThreads;
  2264. Var Drive : TDrive;
  2265. Begin
  2266. For Drive := FirstDrive To LastDrive Do
  2267. With DriveStatus[Drive] Do
  2268. Begin
  2269. IF Assigned(DiscMonitor) Then
  2270. DiscMonitor.Close;
  2271. End;
  2272. End; {StopAllWatchThreads}
  2273. Function TDriveView.WatchThreadActive(Drive : TDrive) : Boolean;
  2274. Begin
  2275. Result := FWatchDirectory And
  2276. Assigned(DriveStatus[Drive].DiscMonitor) And
  2277. DriveStatus[Drive].DiscMonitor.Active;
  2278. End; {WatchThreadActive}
  2279. Function TDriveView.WatchThreadActive : Boolean;
  2280. Var Drive : TDrive;
  2281. Begin
  2282. IF Not Assigned(Selected) Then
  2283. Begin
  2284. Result := False;
  2285. Exit;
  2286. End;
  2287. Drive := GetDriveToNode(Selected);
  2288. Result := FWatchDirectory And
  2289. Assigned(DriveStatus[Drive].DiscMonitor) And
  2290. DriveStatus[Drive].DiscMonitor.Active;
  2291. End; {WatchThreadActive}
  2292. {$ENDIF}
  2293. Procedure TDriveView.SetFullDriveScan(DoFullDriveScan : Boolean);
  2294. Begin
  2295. IF fFullDriveScan <> DoFullDriveScan Then
  2296. Begin
  2297. fFullDriveScan := DoFullDriveScan;
  2298. {IF FullDriveScan And Assigned(Selected) And Not (csDesigning in ComponentState) Then
  2299. ValidateAllDirectories(RootNode(Selected));}
  2300. End;
  2301. End; {SetAutoScan}
  2302. Function TDriveView.GetDirectory : String;
  2303. Begin
  2304. IF Assigned(Selected) Then
  2305. Result := GetDirPathName(Selected)
  2306. Else
  2307. Result := '';
  2308. End; {GetDirectory}
  2309. Procedure TDriveView.SetDirectory(Path : String);
  2310. Var NewSel : TTreeNode;
  2311. Rect : TRect;
  2312. Begin
  2313. FDirectory := Path;
  2314. {Find existing path or parent path of not existing path:}
  2315. Repeat
  2316. NewSel := FindNodeToPath(Path);
  2317. IF Not Assigned(NewSel) Then
  2318. Path := ExtractFilePath(RemoveSlash(Path));
  2319. Until Assigned(NewSel) Or (Length(Path) < 3);
  2320. IF Assigned(NewSel) Then
  2321. Begin
  2322. FCanChange := True;
  2323. NewSel.MakeVisible;
  2324. Rect := NewSel.DisplayRect(False);
  2325. Selected := NewSel;
  2326. IF (Selected.Level = 0) Then
  2327. Begin
  2328. IF Not DriveStatus[GetDriveToNode(Selected)].Scanned Then
  2329. ScanDrive(GetDriveToNode(Selected));
  2330. End;
  2331. End
  2332. Else
  2333. IF csDesigning in ComponentState Then
  2334. Selected := NIL;
  2335. {Application.ProcessMessages;}
  2336. End; {SetDirectory}
  2337. Procedure TDriveView.SetDrive(Drive : TDrive);
  2338. Begin
  2339. IF GetDrive <> Drive Then
  2340. With DriveStatus[Drive] Do
  2341. IF Assigned(RootNode) Then
  2342. Begin
  2343. IF DefaultDir = EmptyStr Then
  2344. DefaultDir := Drive + ':\';
  2345. IF Not Scanned Then
  2346. RootNode.Expand(False);
  2347. TopItem := RootNode;
  2348. Directory := AddSlash(DefaultDir);
  2349. End;
  2350. End; {SetDrive}
  2351. Function TDriveView.GetDrive : TDrive;
  2352. Begin
  2353. IF Assigned(Selected) Then
  2354. Result := GetDriveToNode(Selected)
  2355. Else
  2356. Result := #0;
  2357. End; {GetDrive}
  2358. {Centers the Node vertically in the treeview window:}
  2359. Procedure TDriveView.CenterNode(Node : TTreeNode);
  2360. Var NodePos : TRect;
  2361. ScrollInfo : TScrollInfo;
  2362. Begin
  2363. IF Not Assigned(Node) Or (Items.Count = 0) Then
  2364. Exit;
  2365. Node.MakeVisible;
  2366. NodePos := Node.DisplayRect(False);
  2367. With ScrollInfo Do
  2368. Begin
  2369. cbSize := SizeOf(ScrollInfo);
  2370. fMask := SIF_ALL;
  2371. nMin := 0;
  2372. nMax := 0;
  2373. nPage := 0;
  2374. End;
  2375. GetScrollInfo(Handle, SB_VERT, ScrollInfo);
  2376. IF ScrollInfo.nMin <> ScrollInfo.nMax Then
  2377. Begin
  2378. {Scroll tree up:}
  2379. IF (NodePos.Top < Height Div 4) And (ScrollInfo.nPos > 0) Then
  2380. Begin
  2381. ScrollInfo.fMask := SIF_POS;
  2382. While (ScrollInfo.nPos > 0) And (NodePos.Top < (Height Div 4)) Do
  2383. Begin
  2384. Perform(WM_VSCROLL, SB_LINEUP, 0);
  2385. GetScrollInfo(Handle, SB_VERT, ScrollInfo);
  2386. NodePos := Node.DisplayRect(False);
  2387. End;
  2388. End
  2389. Else
  2390. IF (NodePos.Top > ((Height * 3) Div 4)) Then
  2391. Begin
  2392. {Scroll tree down:}
  2393. ScrollInfo.fMask := SIF_POS;
  2394. While (ScrollInfo.nPos + ABS(ScrollInfo.nPage) < ScrollInfo.nMax) And
  2395. (NodePos.Top > ((Height * 3) Div 4)) And
  2396. (ScrollInfo.nPage > 0) Do
  2397. Begin
  2398. Perform(WM_VSCROLL, SB_LINEDOWN, 0);
  2399. GetScrollInfo(Handle, SB_VERT, ScrollInfo);
  2400. NodePos := Node.DisplayRect(False);
  2401. End;
  2402. End;
  2403. NodePos := Node.DisplayRect(True);
  2404. End;
  2405. IF (NodePos.Left < 50) Then
  2406. Perform(WM_HSCROLL, SB_PAGELEFT, 0);
  2407. End; {CenterNode}
  2408. Function TDriveView.GetDirName(Node : TTreeNode) : String;
  2409. Begin
  2410. IF Assigned(Node) And Assigned(Node.Data) Then
  2411. Result := TNodeData(Node.Data).Dirname
  2412. Else
  2413. Result := '';
  2414. End; {GetDirName}
  2415. {GetDirPath: Allways returns the complete path to Node without the trailing backslash:
  2416. C:, C:\WINDOWS, C:\WINDOWS\SYSTEM }
  2417. Function TDriveView.GetDirPath (Node : TTreeNode) : String;
  2418. Var T : TTreeNode;
  2419. PStr : String;
  2420. Begin
  2421. IF Not Assigned(Node) Then
  2422. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['GetDirPath']));
  2423. PStr := GetDirName(Node);
  2424. T := Node.Parent;
  2425. While (T <> NIL) AND (T.Level >= 0) Do
  2426. Begin
  2427. IF T.Level > 0 Then
  2428. PStr := GetDirName(T) + '\' + PStr
  2429. Else
  2430. PStr := GetDirName(T) + PStr;
  2431. T := T.Parent;
  2432. End;
  2433. IF Length(PStr) = 3 Then
  2434. Result := Copy(PStr,1, 2)
  2435. Else
  2436. Result := PStr;
  2437. End; {GetDirPath}
  2438. {GetDirPathName: Returns the complete path to Node with trailing backslash on rootnodes:
  2439. C:\ ,C:\WINDOWS, C:\WINDOWS\SYSTEM }
  2440. Function TDriveView.GetDirPathName(Node: TTreeNode) : String;
  2441. Begin
  2442. Result := GetDirPath(Node);
  2443. IF Length(Result) = 2 Then
  2444. Result := Result + '\';
  2445. End; {GetDirPathName}
  2446. {GetDrive: returns the driveletter of the Node.}
  2447. Function TDriveView.GetDriveToNode(Node : TTreeNode) : Char;
  2448. Var Path : String;
  2449. Begin
  2450. IF Not Assigned (Node) Or Not Assigned(Node.Data) Then
  2451. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['GetDrive']));
  2452. Path := GetDirPath(Node);
  2453. IF Length(Path) > 0 Then
  2454. Result := Upcase(Path[1])
  2455. Else
  2456. Result := #0;
  2457. End; {GetDrive}
  2458. {RootNode: returns the rootnode to the Node:}
  2459. Function TDriveView.RootNode(Node : TTreeNode) : TTreeNode;
  2460. Begin
  2461. Result := Node;
  2462. IF Not Assigned(Node) Then
  2463. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['RootNode']));
  2464. While Assigned(Result.Parent) Do
  2465. Result := Result.Parent;
  2466. End; {RootNode}
  2467. {NodeAttr: Returns the directory attributes to the node:}
  2468. Function TDriveView.NodeAttr(Node : TTreeNode) : Integer;
  2469. Begin
  2470. IF Not Assigned(Node) Then
  2471. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['NodeAttr']));
  2472. Result := TNodeData(Node.Data).Attr;
  2473. End; {NodeAttr}
  2474. Function TDriveView.NodeVerified(Node : TTreeNode) : Boolean;
  2475. Begin
  2476. IF Not Assigned(Node) Or Not Assigned(Node.Data) Then
  2477. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['NodeVerified']));
  2478. Result := TNodeData(Node.Data).Scanned;
  2479. End; {NodeVerified}
  2480. Procedure TDriveView.SetBoldDraw(Node : TTreeNode; BoldDraw : Boolean);
  2481. Begin
  2482. IF Not Assigned(Node) Or Not Assigned(Node.Data) Then
  2483. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['SetBoldDraw']));
  2484. IF TNodeData(Node.Data).DrawBold <> BoldDraw Then
  2485. Begin
  2486. TNodeData(Node.Data).DrawBold := BoldDraw;
  2487. Node.Text := Node.Text; {Force redraw}
  2488. End;
  2489. End; {SetBoldDraw}
  2490. Function TDriveView.CallBackExpandLevel(Var Node : TTreeNode; Data: Pointer) : Boolean;
  2491. Begin
  2492. Result := True;
  2493. IF Not Assigned(Node) Then
  2494. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['CallBackExpandLevel']));
  2495. IF (Node.Level <= Integer(Data)) And Not Node.Expanded Then
  2496. Node.Expand(False)
  2497. Else IF (Node.Level > Integer(Data)) And Node.Expanded Then
  2498. Node.Collapse(True);
  2499. End; {CallBackExpandLevel}
  2500. Procedure TDriveView.ExpandLevel(Node : TTreeNode; Level : Integer);
  2501. {Purpose: Expands all subnodes of node up to the given level}
  2502. Begin
  2503. IF Not Assigned(Node) Or Not Assigned(Node.Data) Then
  2504. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['ExpandLevel']));
  2505. Items.BeginUpdate;
  2506. IterateSubTree(Node, CallBackExpandLevel, rsRecursive, coScanStartNode, Pointer(Level));
  2507. Items.EndUpdate;
  2508. End; {ExpandLevel}
  2509. Function TDriveView.CallBackDisplayName(Var Node : TTreeNode; Data: Pointer) : Boolean;
  2510. Begin
  2511. Result := True;
  2512. IF Not Assigned(Node) Then
  2513. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['CallBackDisplayName']));
  2514. Node.Text := GetDisplayName(Node);
  2515. End; {CallBackDisplayName}
  2516. Function TDriveView.CallBackSetDirSize(Var Node : TTreeNode; Data: Pointer) : Boolean;
  2517. Begin
  2518. Result := True;
  2519. IF Assigned(Node) Then
  2520. Begin
  2521. SetDirSize(Node);
  2522. IF fShowDirSize Then
  2523. Node.Text := GetDisplayName(Node);
  2524. IF Assigned(Data) Then
  2525. INC(PInt(Data)^, TNodeData(Node.Data).DirSize);
  2526. End;
  2527. Application.ProcessMessages;
  2528. IF Not FContinue Then
  2529. Exit;
  2530. End; {CallBackSetDirSize}
  2531. Function TDriveView.FormatDirSize(Size : Cardinal) : String;
  2532. Var FSize : Cardinal;
  2533. Begin
  2534. FSize := Size;
  2535. IF (Size > 0) And (Size < 1024) Then
  2536. fSize := 1
  2537. Else
  2538. fSize := fSize DIV 1024;
  2539. IF fSize <= 99999 Then
  2540. Result := FormatSize(FSize) + 'K'
  2541. Else
  2542. Result := FormatSize(FSize DIV 1024) + 'M';
  2543. End; {FormatDirSize}
  2544. Procedure TDriveView.SetShowDirSize(ShowIt : Boolean);
  2545. Var Drive : Char;
  2546. RootNode : TTreeNode;
  2547. SaveCursor: TCursor;
  2548. Begin
  2549. IF ShowIt = fShowDirSize Then
  2550. Exit;
  2551. fShowDirSize := ShowIt;
  2552. SaveCursor := Screen.Cursor;
  2553. Screen.Cursor := crHourglass;
  2554. Items.BeginUpdate;
  2555. For Drive := FirstFixedDrive To LastDrive Do
  2556. Begin
  2557. IF DriveInfo[Drive].Valid Then
  2558. Begin
  2559. RootNode := DriveStatus[Drive].RootNode;
  2560. IF Assigned(RootNode) Then
  2561. IterateSubTree(RootNode, CallBackDisplayName, rsRecursive, coScanStartNode, NIL);
  2562. End;
  2563. End;
  2564. Items.EndUpdate;
  2565. Screen.Cursor := SaveCursor;
  2566. End; {SetShowDirSize}
  2567. Procedure TDriveView.RefreshDirSize(Node : TTreeNode);
  2568. Begin
  2569. IF Not Assigned(Node) Then
  2570. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['RefreshDirSize']));
  2571. CallBackSetDirSize(Node, NIL);
  2572. End; {RefreshDirSize}
  2573. Procedure TDriveView.RefreshDriveDirSize(Drive : TDrive);
  2574. Var SaveCursor : TCursor;
  2575. Begin
  2576. SaveCursor := Screen.Cursor;
  2577. Screen.Cursor := crHourglass;
  2578. Items.BeginUpdate;
  2579. With DriveStatus[Drive] Do
  2580. Begin
  2581. IF Assigned(RootNode) Then
  2582. IterateSubTree(RootNode, CallBackSetDirSize, rsRecursive, coScanStartNode, NIL);
  2583. End;
  2584. Items.EndUpdate;
  2585. Screen.Cursor := SaveCursor;
  2586. End; {RefreshDriveDirSize}
  2587. Function TDriveView.GetDirSize(Node : TTreeNode) : Cardinal;
  2588. Begin
  2589. IF Not Assigned(Node) Or Not Assigned(Node.Data) Then
  2590. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['GetDirSize']));
  2591. IF TNodeData(Node.Data).DirSize = C_InvalidSize Then
  2592. SetDirSize(Node);
  2593. Result := TNodeData(Node.Data).DirSize;
  2594. End; {GetDirSize}
  2595. Procedure TDriveView.SetDirSize(Node : TTreeNode);
  2596. Var SRec : TSearchRec;
  2597. Size : Cardinal;
  2598. Begin
  2599. IF Not Assigned(Node) Or Not Assigned(Node.Data) Then
  2600. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['SetDirSize']));
  2601. Size := 0;
  2602. IF FindFirst(AddSlash(GetDirPath(Node)) + '*.*', faAnyFile, SRec) = 0 Then
  2603. Begin
  2604. Repeat
  2605. IF (Srec.Attr And faDirectory) = 0 Then
  2606. INC(Size, Srec.Size);
  2607. Until FindNext(Srec) <> 0;
  2608. End;
  2609. FindClose(Srec);
  2610. TNodeData(Node.Data).DirSize := Size;
  2611. End; {SetDirSize}
  2612. Function TDriveView.GetDisplayName(Node : TTreeNode) : String;
  2613. Var DirName : String;
  2614. Begin
  2615. Result := '';
  2616. IF Not Assigned(Node) OR Not Assigned(Node.Data) Then
  2617. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['GetDisplayName']));
  2618. IF Node.Level = 0 Then
  2619. Result := GetDriveText(GetDriveToNode(Node))
  2620. Else
  2621. Begin
  2622. DirName := GetDirName(Node);
  2623. Case FFileNameDisplay Of
  2624. fndCap : Result := UpperCase(DirName);
  2625. fndNoCap : Result := LowerCase(DirName);
  2626. fndNice : If Length(DirName) <= 8 Then
  2627. Begin
  2628. Result := LowerCase(DirName);
  2629. Result[1] := Upcase(Result[1]);
  2630. End
  2631. Else
  2632. Result := DirName;
  2633. Else
  2634. Result := DirName;
  2635. End; {Case}
  2636. End;
  2637. IF FShowDirSize Then
  2638. Result := Result + ' = ' + FormatDirSize(GetDirSize(Node));
  2639. End; {GetDisplayName}
  2640. Procedure TDriveView.SetShowVolLabel(ShowIt : Boolean);
  2641. Begin
  2642. IF ShowIt = fShowVolLabel Then
  2643. Exit;
  2644. fShowVolLabel := ShowIt;
  2645. RefreshRootNodes(False, dvdsFloppy);
  2646. End; {SetShowVolLabel}
  2647. Procedure TDriveView.SetVolDisplayStyle(doStyle : TVolumeDisplayStyle);
  2648. Var Drive : TDrive;
  2649. Begin
  2650. IF doStyle <> fVolDisplayStyle Then
  2651. Begin
  2652. fVolDisplayStyle := doStyle;
  2653. IF Not fCreating Then
  2654. For Drive := FirstDrive To LastDrive Do
  2655. Begin
  2656. IF DriveInfo[Drive].Valid Then
  2657. DriveStatus[Drive].RootNode.Text := GetDisplayName(DriveStatus[Drive].RootNode);
  2658. End;
  2659. {RefreshRootNodes(False, dvdsFloppy);}
  2660. End;
  2661. End; {SetVolDisplayStyle}
  2662. Procedure TDriveView.SetCompressedColor(Value : TColor);
  2663. Begin
  2664. IF Value <> FCompressedColor Then
  2665. Begin
  2666. FCompressedColor := Value;
  2667. Invalidate;
  2668. End;
  2669. End; {SetCompressedColor}
  2670. Procedure TDriveView.SetFileNameDisplay(Value : TFileNameDisplay);
  2671. Var Drive : TDrive;
  2672. Begin
  2673. IF Value <> FFileNameDisplay Then
  2674. Begin
  2675. FFileNameDisplay := Value;
  2676. For Drive := FirstDrive To LastDrive Do
  2677. With DriveStatus[Drive] Do
  2678. IF Assigned(RootNode) And DriveStatus[Drive].Scanned Then
  2679. IterateSubTree(RootNode, CallBackDisplayName, rsRecursive, coNoScanStartNode, NIL);
  2680. End;
  2681. End; {SetFileNameDisplay}
  2682. Procedure TDriveView.DisplayContextMenu(Node : TTreeNode; ScreenPos : TPoint);
  2683. Var Verb : String;
  2684. Begin
  2685. IF Not Assigned(Node) Then
  2686. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['DisplayContextMenu']));
  2687. IF Node <> Selected Then
  2688. DropTarget := Node;
  2689. Verb := EmptyStr;
  2690. IF Assigned(FOnDisplayContextMenu) Then
  2691. FOnDisplayContextMenu(Self);
  2692. ShellDisplayContextMenu(FParentForm.Handle, ScreenPos, GetDirPathName(Node), CanEdit(Node), Verb, False);
  2693. If Verb = shcRename Then
  2694. Node.EditText
  2695. Else If Verb = shcCut Then
  2696. Begin
  2697. LastClipBoardOperation := cboCut;
  2698. LastPathCut := GetDirPathName(Node);
  2699. End
  2700. Else If Verb = shcCopy Then
  2701. LastClipBoardOperation := cboCopy
  2702. Else If Verb = shcPaste Then
  2703. PasteFromClipBoard(GetDirPathName(Node));
  2704. DropTarget := NIL;
  2705. End; {DisplayContextMenu (2)}
  2706. Procedure TDriveView.DisplayContextMenu(Node : TTreeNode);
  2707. Begin
  2708. DisplayContextMenu(Node, Mouse.CursorPos);
  2709. End; {DisplayContextMenu (1)}
  2710. Procedure TDriveView.DisplayPropertiesMenu(Node : TTreeNode);
  2711. Begin
  2712. IF Not Assigned(Node) Then
  2713. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['DisplayPropertiesMenu']));
  2714. ShellExecuteContextCommand(FParentForm.Handle, shcProperties, GetDirPathName(Node));
  2715. End; {ContextMenu}
  2716. Function TDriveView.SortChildren(ParentNode : TTreeNode; Recurse : Boolean) : Boolean;
  2717. Var Node : TTreeNode;
  2718. Begin
  2719. Result := False;
  2720. IF Not Assigned(ParentNode) Then
  2721. Raise ENodeNotAssigned.Create(Format(ErrorNodeNA, ['SortChildren']));
  2722. IF TreeView_SortChildren(Self.Handle, ParentNode.ItemID, 0) Then
  2723. Begin
  2724. Result := True;
  2725. IF Recurse Then
  2726. Begin
  2727. Node := ParentNode.GetFirstChild;
  2728. While Assigned(Node) Do
  2729. Begin
  2730. IF Node.HasChildren Then
  2731. SortChildren(Node, Recurse);
  2732. Node := ParentNode.GetNextChild(Node);
  2733. End;
  2734. End;
  2735. End;
  2736. End; {SortChildren}
  2737. Procedure TDriveView.Notification(AComponent: TComponent; Operation: TOperation);
  2738. begin
  2739. Inherited Notification(AComponent, Operation);
  2740. If (Operation = opRemove) Then
  2741. Begin
  2742. IF AComponent = fDirView then
  2743. fDirView := NIL
  2744. Else
  2745. IF AComponent = FDriveBox then
  2746. FDriveBox := NIL
  2747. End;
  2748. end; {Notification}
  2749. Procedure TDriveView.SetSelected(Node : TTreeNode);
  2750. Begin
  2751. IF Node <> Selected Then
  2752. Begin
  2753. FChangeFlag := False;
  2754. FCanChange := True;
  2755. Inherited Selected := Node;
  2756. IF Not fChangeFlag Then
  2757. Change(Selected);
  2758. End;
  2759. End; {SetSelected}
  2760. {=================================================================}
  2761. { Drag&Drop handling: }
  2762. {=================================================================}
  2763. {Called by TFileDeleteThread, when a file deletion was detected by the D&D receiving application:}
  2764. Procedure TDriveView.SignalDirDelete(Sender: TObject; Files : TStringList);
  2765. Begin
  2766. IF Files.Count > 0 Then
  2767. ValidateDirectory(FindNodeToPath(Files[0]));
  2768. End; {SignalDirDelete}
  2769. Procedure TDriveView.DDDragEnter(DataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: longint; var Accept:boolean);
  2770. Var KeyBoardState : TKeyBoardState;
  2771. i : Integer;
  2772. Begin
  2773. IF (FDD.FileList.Count > 0) And (Length(TFDDListItem(FDD.FileList[0]^).Name) > 0) Then
  2774. Begin
  2775. FDragDrive := TFDDListItem(FDD.FileList[0]^).Name[1];
  2776. FExeDrag := FDDLinkOnExeDrag And ((FDD.AvailableDropEffects And DropEffect_Link) <> 0);
  2777. IF FExeDrag Then
  2778. For i := 0 To FDD.FileList.Count - 1 Do
  2779. If Not isExecutable(TFDDListItem(FDD.FileList[i]^).Name) Then
  2780. Begin
  2781. FExeDrag := False;
  2782. Break;
  2783. End;
  2784. End
  2785. Else
  2786. FDragDrive := #0;
  2787. GetSystemTimeAsFileTime(DragOverTime);
  2788. GetSystemTimeAsFileTime(LastHScrollTime);
  2789. GetSystemTimeAsFileTime(LastVScrollTime);
  2790. VScrollCount := 0;
  2791. IF (GetKeyState(VK_SPACE) <> 0) And GetKeyboardState(KeyBoardState) Then
  2792. Begin
  2793. KeyBoardState[VK_SPACE] := 0;
  2794. SetKeyBoardState(KeyBoardState);
  2795. End;
  2796. IF Assigned(FOnDDDragEnter) Then
  2797. FOnDDDragEnter(Self, DataObj, grfKeyState, Pt, dwEffect, Accept);
  2798. End; {DDDragEnter}
  2799. Procedure TDriveView.DDDragLeave;
  2800. Begin
  2801. IF Assigned(DropTarget) Then
  2802. Begin
  2803. IF GlobalDragImageList.Dragging Then
  2804. GlobalDragImageList.HideDragImage;
  2805. DropTarget := NIL;
  2806. Update;
  2807. End;
  2808. IF Assigned(FOnDDDragLeave) Then
  2809. FOnDDDragLeave(Self);
  2810. End; {DragLeave}
  2811. Procedure TDriveView.DDDragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: longint);
  2812. Var Node : TTreeNode;
  2813. KnowTime : FILETIME;
  2814. TempTopItem : TTreeNode;
  2815. NbPixels : Integer;
  2816. ScrollInfo : TScrollInfo;
  2817. KeyBoardState: TKeyBoardState;
  2818. Rect1 : Trect;
  2819. UpdateImage : Boolean;
  2820. LastDragNode : TTreeNode;
  2821. TargetDrive : Char;
  2822. begin
  2823. IF dwEffect <> DropEffect_None Then
  2824. Begin
  2825. Node := GetNodeAt(Pt.X, Pt.Y);
  2826. IF Assigned(Node) Then
  2827. Begin
  2828. LastDragNode := DropTarget;
  2829. UpdateImage := False;
  2830. IF GlobalDragImageList.Dragging And (LastDragNode <> Node) Then
  2831. Begin
  2832. IF Assigned(LastDragNode) Then
  2833. Begin
  2834. Rect1 := LastDragNode.DisplayRect(True);
  2835. IF Rect1.Right >= Pt.x - GlobalDragImageList.GetHotSpot.X Then
  2836. Begin
  2837. GlobalDragImageList.HideDragImage;
  2838. UpdateImage := True;
  2839. End
  2840. Else
  2841. Begin
  2842. Rect1 := Node.DisplayRect(True);
  2843. IF Rect1.Right >= Pt.x - GlobalDragImageList.GetHotSpot.X Then
  2844. Begin
  2845. GlobalDragImageList.HideDragImage;
  2846. UpdateImage := True;
  2847. End
  2848. End;
  2849. End
  2850. Else
  2851. {LastDragNode not assigned:}
  2852. Begin
  2853. GlobalDragImageList.HideDragImage;
  2854. UpdateImage := True;
  2855. End;
  2856. End;
  2857. DropTarget := Node;
  2858. IF UpdateImage Then
  2859. GlobalDragImageList.ShowDragImage;
  2860. TargetDrive := GetDirPath(Node)[1];
  2861. {Drop-operation allowed at this location?}
  2862. IF Assigned(DragNode) And
  2863. (dwEffect <> DropEffect_Link) And
  2864. ((Node = DragNode) Or Node.HasAsParent(DragNode) Or (DragNode.Parent = Node)) Then
  2865. dwEffect := DropEffect_None;
  2866. GetSystemTimeAsFileTime(KnowTime);
  2867. IF GetKeyState(VK_SPACE) = 0 Then
  2868. Begin
  2869. {Expand node after 2.5 seconds: }
  2870. IF Not Assigned(LastDragNode) Or (LastDragNode <> Node) Then
  2871. GetSystemTimeAsFileTime(DragOverTime) {not previous droptarget: start timer}
  2872. Else
  2873. Begin
  2874. IF ((INT64(KnowTime) - INT64(DragOverTime)) > DDExpandDelay) Then
  2875. Begin
  2876. TempTopItem := TopItem;
  2877. GlobalDragImageList.HideDragImage;
  2878. Node.Expand(False);
  2879. TopItem := TempTopItem;
  2880. Update;
  2881. GlobalDragImageList.ShowDragImage;
  2882. DragOverTime := KnowTime;
  2883. End;
  2884. End;
  2885. End
  2886. Else
  2887. Begin
  2888. {restart timer}
  2889. GetSystemTimeAsFileTime(DragOverTime);
  2890. IF GetKeyboardState(KeyBoardState) Then
  2891. Begin
  2892. KeyBoardState[VK_Space] := 0;
  2893. SetKeyBoardState(KeyBoardState);
  2894. End;
  2895. TempTopItem := TopItem;
  2896. GlobalDragImageList.HideDragImage;
  2897. IF Not Node.HasChildren Then
  2898. ValidateDirectory(Node);
  2899. IF Node.Expanded Then
  2900. Begin
  2901. IF Not Selected.HasAsParent(Node) Then
  2902. Node.Collapse(False);
  2903. End
  2904. Else
  2905. Node.Expand(False);
  2906. TopItem := TempTopItem;
  2907. Update;
  2908. GlobalDragImageList.ShowDragImage;
  2909. End;
  2910. NbPixels := Abs((Font.Height));
  2911. {Vertical treescrolling:}
  2912. IF ((INT64(KnowTime) - INT64(LastVScrollTime)) > DDVScrollDelay) OR
  2913. ((VScrollCount > 3) And ((INT64(KnowTime) - INT64(LastVScrollTime)) > (DDVScrollDelay Div 4))) Then
  2914. Begin
  2915. {Scroll tree up, if droptarget is topitem:}
  2916. IF Node = TopItem Then
  2917. Begin
  2918. GlobalDragImageList.HideDragImage;
  2919. Perform(WM_VSCROLL, SB_LINEUP, 0);
  2920. GlobalDragImageList.ShowDragImage;
  2921. GetSystemTimeAsFileTime(LastVScrollTime);
  2922. INC(VScrollCount);
  2923. End
  2924. Else
  2925. {Scroll tree down, if next visible item of droptarget is not visible:}
  2926. Begin
  2927. IF PT.Y + 3 * nbPixels > Height Then
  2928. Begin
  2929. GlobalDragImageList.HideDragImage;
  2930. Perform(WM_VSCROLL, SB_LINEDOWN, 0);
  2931. GlobalDragImageList.ShowDragImage;
  2932. GetSystemTimeAsFileTime(LastVScrollTime);
  2933. INC(VScrollCount);
  2934. End
  2935. Else
  2936. Begin
  2937. VScrollCount := 0;
  2938. End;
  2939. End;
  2940. End; {VScrollDelay}
  2941. {Horizontal treescrolling:}
  2942. {Scroll tree Left}
  2943. IF ((INT64(KnowTime) - INT64(LastHScrollTime)) > DDHScrollDelay) Then
  2944. Begin
  2945. GetSystemTimeAsFileTime(LastHScrollTime);
  2946. ScrollInfo.cbSize := SizeOf(ScrollInfo);
  2947. ScrollInfo.FMask := SIF_ALL;
  2948. GetScrollInfo(Handle, SB_HORZ, ScrollInfo);
  2949. if ScrollInfo.nMin <> ScrollInfo.nMax then
  2950. Begin
  2951. if (PT.X < 50 ) then
  2952. Begin
  2953. IF Node.DisplayRect(True).Right + 50 < Width Then
  2954. Begin
  2955. GlobalDragImageList.HideDragImage;
  2956. Perform(WM_HSCROLL, SB_LINELEFT, 0);
  2957. GlobalDragImageList.ShowDragImage;
  2958. End;
  2959. End
  2960. Else
  2961. IF (PT.X > (Width - 50)) Then
  2962. Begin
  2963. IF Node.DisplayRect(True).Left > 50 Then
  2964. Begin
  2965. GlobalDragImageList.HideDragImage;
  2966. Perform(WM_HSCROLL, SB_LINERIGHT, 0);
  2967. GlobalDragImageList.ShowDragImage;
  2968. End;
  2969. End;
  2970. End;
  2971. End;
  2972. {Set Drop effect:}
  2973. IF (TNodeData(DropTarget.Data).isRecycleBin And FDD.FileNamesAreMapped) Then
  2974. dwEffect := DropEffect_None
  2975. Else
  2976. Begin
  2977. IF TNodeData(DropTarget.Data).isRecycleBin Then
  2978. dwEffect := DropEffect_Move
  2979. Else
  2980. IF (grfKeyState And (MK_CONTROL Or MK_SHIFT) = 0) Then
  2981. Begin
  2982. If FExeDrag And (TargetDrive >= FirstFixedDrive) And (FDragDrive >= FirstFixedDrive) Then
  2983. dwEffect := DropEffect_Link
  2984. Else
  2985. IF (dwEffect = DropEffect_Copy) And
  2986. ((DragDrive = GetDriveToNode(DropTarget)) And
  2987. (FDD.AvailableDropEffects and DropEffect_Move <> 0)) Then
  2988. dwEffect := DropEffect_Move;
  2989. End;
  2990. End;
  2991. End {Assigned(Node)}
  2992. Else
  2993. dwEffect := DropEffect_None;
  2994. End;
  2995. IF Assigned(FOnDDDragOver) Then
  2996. FOnDDDragOver(Self, grfKeyState, Pt, dwEffect);
  2997. End; {DDDragOver}
  2998. Procedure TDriveView.DDDrop(DataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: longint);
  2999. Begin
  3000. IF GlobalDragImageList.Dragging Then
  3001. GlobalDragImageList.HideDragImage;
  3002. IF dwEffect = DropEffect_None Then
  3003. DropTarget := NIL;
  3004. IF Assigned(FOnDDDrop) Then
  3005. FOnDDDrop(Self, DataObj, grfKeyState, Pt, dwEffect);
  3006. End; {DDDrop}
  3007. Procedure TDriveView.DDQueryContinueDrag(fEscapePressed: BOOL; grfKeyState: Longint; var Result: HResult);
  3008. Var P : TPoint;
  3009. ClientP : TPoint;
  3010. KnowTime : FILETIME;
  3011. Begin
  3012. IF Assigned(FOnDDQueryContinueDrag) Then
  3013. FOnDDQueryContinueDrag(Self, fEscapePressed, grfKeyState, Result);
  3014. IF fEscapePressed Then
  3015. Begin
  3016. IF GlobalDragImageList.Dragging Then
  3017. GlobalDragImageList.HideDragImage;
  3018. DropTarget := NIL;
  3019. Exit;
  3020. End;
  3021. IF (Result = DRAGDROP_S_DROP) Then
  3022. Begin
  3023. GetSystemTimeAsFileTime(KnowTime);
  3024. IF ((INT64(KnowTime) - INT64(DragStartTime)) <= DDDragStartDelay) Then
  3025. Result := DRAGDROP_S_CANCEL;
  3026. End;
  3027. IF GlobalDragImageList.Dragging Then
  3028. Begin
  3029. GetCursorPos(P);
  3030. {Convert screen coordinates to the parentforms coordinates:}
  3031. ClientP := FParentForm.ScreenToClient(P);
  3032. {Move the drag image to the new position and show it:}
  3033. IF Not CompareMem(@ClientP, @FDragPos, SizeOf(TPoint)) Then
  3034. Begin
  3035. FDragPos := ClientP;
  3036. IF PtInRect(FParentForm.BoundsRect, P) Then
  3037. Begin
  3038. GlobalDragImageList.DragMove(ClientP.X, ClientP.Y);
  3039. GlobalDragImageList.ShowDragImage;
  3040. End
  3041. Else
  3042. GlobalDragImageList.HideDragImage;
  3043. End;
  3044. End;
  3045. End; {DDQueryContinueDrag}
  3046. Procedure TDriveView.DDGiveFeedback(dwEffect: Longint; var Result: HResult);
  3047. Begin
  3048. IF Assigned(FOnDDGiveFeedback) Then
  3049. FOnDDGiveFeedback(Self, dwEffect, Result);
  3050. End; {DDGiveFeedback}
  3051. Procedure TDriveView.DDSpecifyDropTarget(Sender: TObject; DragDropHandler : boolean; pt: TPoint; var pidlFQ : PItemIDList; var Filename : string);
  3052. Begin
  3053. pidlFQ := NIL;
  3054. IF DragDropHandler And Assigned(DropTarget) Then
  3055. FileName := GetDirPathName(DropTarget)
  3056. Else
  3057. FileName := EmptyStr;
  3058. End; {DDSpecifyDropTarget}
  3059. Procedure TDriveView.DDDragDetect(grfKeyState: Longint; DetectStart, Pt: TPoint; DragStatus:TDragDetectStatus);
  3060. Var DDResult : TDragResult;
  3061. DragPath : String;
  3062. DragParentPath : String;
  3063. DragNodeLevel : Integer;
  3064. {$IFNDEF NO_THREADS}
  3065. WatchThreadOK : Boolean;
  3066. {$ENDIF}
  3067. P : TPoint;
  3068. Himl : HImageList;
  3069. NodeRect : TRect;
  3070. Begin
  3071. IF (DragStatus = ddsDrag) And Not Assigned(DragNode) Then
  3072. Begin
  3073. P := ScreenToClient(FStartPos);
  3074. DragNode := GetNodeAt(P.X, P.Y);
  3075. End;
  3076. IF Assigned(FOnDDDragDetect) Then
  3077. FOnDDDragDetect(Self, grfKeyState, DetectStart, Pt, DragStatus);
  3078. IF (DragStatus = ddsDrag) And Assigned(DragNode) Then
  3079. Begin
  3080. NodeRect := DragNode.DisplayRect(True);
  3081. Dec(NodeRect.Left, 16);
  3082. {Check, wether the mouse cursor was within the nodes display rectangle:}
  3083. IF (NodeRect.Left > P.X) Or (NodeRect.Right < P.X) Then
  3084. Begin
  3085. DragNode := NIL;
  3086. Exit;
  3087. End;
  3088. FDragDrive := #0;
  3089. {Create the dragimage:}
  3090. GlobalDragImageList := FDragImageList;
  3091. IF UseDragImages Then
  3092. Begin
  3093. {Hide the selection mark to get a proper dragimage:}
  3094. IF Selected = DragNode Then
  3095. Selected := NIL;
  3096. HIml := TreeView_CreateDragImage(Handle, DragNode.ItemID);
  3097. {Show the selection mark if it was hidden:}
  3098. IF Not Assigned(Selected) Then
  3099. Selected := DragNode;
  3100. IF Himl <> Invalid_Handle_Value Then
  3101. Begin
  3102. GlobalDragImageList.Handle := Himl;
  3103. GlobalDragImageList.SetDragImage(0, P.X - NodeRect.TopLeft.X, P.Y - NodeRect.TopLeft.Y);
  3104. P := FParentForm.ScreenToClient(Pt);
  3105. GlobalDragImageList.BeginDrag(FParentForm.Handle, P.X, P.Y);
  3106. GlobalDragImageList.HideDragImage;
  3107. ShowCursor(True);
  3108. End;
  3109. End;
  3110. Dragpath := GetDirPathName(DragNode);
  3111. IF Assigned(DragNode.Parent) Then
  3112. DragParentPath := GetDirPathName(DragNode.Parent)
  3113. Else
  3114. DragParentPath := DragPath;
  3115. DragNodeLevel := DragNode.Level;
  3116. FDD.FileList.Clear;
  3117. FDD.CompleteFileList := GetDriveType(DragPath[1]) <> DRIVE_REMOVABLE;
  3118. FDD.FileList.AddItem(nil,DragPath);
  3119. IF DragNodeLevel = 0 Then
  3120. FDD.SourceEffects := FDD.SourceEffects - [deCopy, deMove]
  3121. Else
  3122. FDD.SourceEffects := FDD.SourceEffects + [deCopy, deMove];
  3123. {$IFNDEF NO_THREADS}
  3124. WatchThreadOK := WatchThreadActive;
  3125. {$ENDIF}
  3126. DropSourceControl := Self;
  3127. GetSystemTimeAsFileTime(DragStartTime);
  3128. {Supress the context menu:}
  3129. fContextMenu := False;
  3130. {Execute the drag&drop-Operation:}
  3131. DDResult := FDD.Execute;
  3132. {the drag&drop operation is finished, so clean up the used drag image:}
  3133. GlobalDragImageList.EndDrag;
  3134. GlobalDragImageList.Clear;
  3135. Application.ProcessMessages;
  3136. FDD.FileList.Clear;
  3137. FDragDrive := #0;
  3138. IF DDResult = drCancelled Then
  3139. DropTarget := NIL;
  3140. IF (DDResult = drMove)
  3141. {$IFNDEF NO_THREADS}
  3142. And Not WatchThreadOK
  3143. {$ENDIF}
  3144. Then
  3145. Begin
  3146. IF (DragNodeLevel > 0) OR
  3147. (DragParentPath <> GetDirPathName(Selected.Parent)) Then
  3148. Begin
  3149. DragNode := FindNodeToPath(DragPath);
  3150. IF Assigned(DragNode) Then
  3151. Begin
  3152. DragFileList.Clear;
  3153. DragFileList.Add(DragPath);
  3154. {$IFNDEF NO_THREADS}
  3155. TFileDeleteThread.Create(DragFileList, MaxWaitTimeOut, SignalDirDelete);
  3156. {$ENDIF}
  3157. End;
  3158. End;
  3159. End;
  3160. DragNode := NIL;
  3161. DropSourceControl := NIL;
  3162. End;
  3163. End; {(DDDragDetect}
  3164. Procedure TDriveView.DDProcessDropped(Sender: TObject; grfKeyState: Longint; pt: TPoint; dwEffect: Longint);
  3165. Var TargetPath : String;
  3166. Begin
  3167. IF Assigned(DropTarget) Then
  3168. Begin
  3169. TargetPath := GetDirPathName(DropTarget);
  3170. IF DirExists(TargetPath) Then
  3171. Begin
  3172. IF Assigned(FOnDDProcessDropped) Then
  3173. FOnDDProcessDropped(Self, grfKeyState, pt, dwEffect);
  3174. PerformDragDropFileOperation(TargetPath, dwEffect, TNodeData(DropTarget.Data).isRecycleBin);
  3175. IF Assigned(FOnDDExecuted) Then
  3176. FOnDDExecuted(Self, dwEffect);
  3177. End
  3178. Else
  3179. Begin
  3180. ValidateDirectory(DropTarget);
  3181. DDError(DDPathNotFoundError);
  3182. End;
  3183. DropTarget := NIL;
  3184. FDD.FileList.Clear;
  3185. End;
  3186. End; {ProcessDropped}
  3187. Procedure TDriveView.PerformDragDropFileOperation(TargetPath : String; dwEffect: Integer; isRecycleBin : Boolean);
  3188. Var i : Integer;
  3189. SourcePath : String;
  3190. SourceParentPath : String;
  3191. SourceFile : String;
  3192. SaveCursor : TCursor;
  3193. DoFileOperation : Boolean;
  3194. TargetNode : TTreeNode;
  3195. FileNamesAreMapped: Boolean;
  3196. Begin
  3197. {DragDropExec}
  3198. IF FDD.FileList.Count = 0 Then
  3199. Exit;
  3200. SaveCursor := Screen.Cursor;
  3201. Screen.Cursor := crHourGlass;
  3202. SourcePath := EmptyStr;
  3203. Try
  3204. IF (dwEffect = DropEffect_Copy) Or
  3205. (dwEffect = DropEffect_Move) Then
  3206. Begin
  3207. {$IFNDEF NO_THREADS}
  3208. StopAllWatchThreads;
  3209. If Assigned(FDirView) Then
  3210. FDirView.StopWatchThread;
  3211. IF Assigned(DropSourceControl) And
  3212. (DropSourceControl is TDirView) And
  3213. (DropSourceControl <> FDirView) Then
  3214. TDirView(DropSourceControl).StopWatchThread;
  3215. {$ENDIF}
  3216. FileNamesAreMapped := TFDDListItem(FDD.FileList[0]^).MappedName <> '';
  3217. {Set the source directory:}
  3218. For i := 0 to FDD.FileList.Count - 1 Do
  3219. Begin
  3220. FFileOperator.OperandFrom.Add(TFDDListItem(FDD.FileList[i]^).Name);
  3221. IF FileNamesAreMapped Then
  3222. FFileOperator.OperandTo.Add(AddSlash(TargetPath) + TFDDListItem(FDD.FileList[i]^).MappedName);
  3223. End;
  3224. SourcePath := TFDDListItem(FDD.FileList[0]^).Name;
  3225. SourceParentPath := ExtractFilePath(RemoveSlash(SourcePath));
  3226. FDD.FileList.Clear;
  3227. FFileOperator.Flags := [foAllowUndo, foNoConfirmMkDir];
  3228. {Set the target directory or target files:}
  3229. IF FileNamesAreMapped And Not isRecycleBin Then
  3230. FFileOperator.Flags := FFileOperator.Flags + [foMultiDestFiles]
  3231. Else
  3232. Begin
  3233. FFileOperator.Flags := FFileOperator.Flags - [foMultiDestFiles];
  3234. FFileOperator.OperandTo.Clear;
  3235. FFileOperator.OperandTo.Add(TargetPath);
  3236. End;
  3237. IF isRecycleBin Then
  3238. FFileOperator.Operation := foDelete
  3239. Else
  3240. Case dwEffect Of
  3241. DropEffect_Copy : FFileOperator.Operation := foCopy;
  3242. DropEffect_Move : FFileOperator.Operation := foMove;
  3243. End; {Case}
  3244. IF isRecycleBin Then
  3245. Begin
  3246. IF Not ConfirmDelete Then
  3247. FFileOperator.Flags := FFileOperator.Flags + [foNoConfirmation];
  3248. End
  3249. Else
  3250. IF Not ConfirmOverwrite Then
  3251. FFileOperator.Flags := FFileOperator.Flags + [foNoConfirmation];
  3252. DoFileOperation := True;
  3253. IF Assigned(FOnDDFileOperation) Then
  3254. FOnDDFileOperation(Self, dwEffect, SourcePath, TargetPath, DoFileOperation);
  3255. IF DoFileOperation And (FFileOperator.OperandFrom.Count > 0) Then
  3256. Begin
  3257. FFileOperator.Execute;
  3258. IF Assigned(FOnDDFileOperationExecuted) Then
  3259. FOnDDFileOperationExecuted(Self, dwEffect, SourcePath, TargetPath);
  3260. IF FileNamesAreMapped Then
  3261. FFileOperator.ClearUndo;
  3262. End;
  3263. End
  3264. Else
  3265. IF (dwEffect = DropEffect_Link) Then
  3266. { Create Link requested: }
  3267. Begin
  3268. For i := 0 to FDD.FileList.Count - 1 Do
  3269. Begin
  3270. SourceFile := TFDDListItem(FDD.FileList[i]^).Name;
  3271. IF Length(SourceFile) = 3 Then
  3272. SourcePath := Copy(DriveInfo[SourceFile[1]].PrettyName, 4, 255) + '(' + SourceFile[1] + ')'
  3273. Else
  3274. SourcePath := ExtractFileName(SourceFile);
  3275. IF Not CreateFileShortCut(SourceFile, AddSlash(TargetPath) + ChangeFileExt(SourcePath, '.lnk'),
  3276. ExtractFileNameOnly(SourceFile)) Then
  3277. DDError(DDCreateShortCutError);
  3278. End;
  3279. End;
  3280. IF dwEffect = DropEffect_Move Then
  3281. Items.BeginUpdate;
  3282. {Update source directory, if move-operation was performed:}
  3283. IF ((dwEffect = DropEffect_Move) OR isRecycleBin) Then
  3284. ValidateDirectory(FindNodeToPath(SourceParentPath));
  3285. {Update subdirectories of target directory:}
  3286. TargetNode := FindNodeToPath(TargetPath);
  3287. IF Assigned(TargetNode) Then
  3288. ValidateDirectory(TargetNode)
  3289. Else
  3290. ValidateDirectory(DriveStatus[TargetPath[1]].RootNode);
  3291. IF dwEffect = DropEffect_Move Then
  3292. Items.EndUpdate;
  3293. {Update linked component TDirView:}
  3294. IF Assigned(FDirView)
  3295. {$IFNDEF NO_THREADS}
  3296. And Not FDirView.WatchThreadActive
  3297. {$ENDIF}
  3298. Then
  3299. Case dwEffect of
  3300. DropEffect_Copy,
  3301. DropEffect_Link: If (AddSlash(TargetPath) = AddSlash(DirView.Path)) Then
  3302. FDirView.Reload2;
  3303. DropEffect_Move: If (AddSlash(TargetPath) = AddSlash(DirView.Path)) Or
  3304. (AddSlash(SourceParentPath) = AddSlash(DirView.Path)) Then
  3305. Begin
  3306. IF FDirView <> DropSourceControl Then
  3307. FDirView.Reload2;
  3308. End;
  3309. End; {Case}
  3310. {Update the DropSource control, if files are moved and it is a TDirView:}
  3311. IF (dwEffect = DropEffect_Move) And (DropSourceControl is TDirView) Then
  3312. TDirView(DropSourceControl).ValidateSelectedFiles;
  3313. Finally
  3314. FFileOperator.OperandFrom.Clear;
  3315. FFileOperator.OperandTo.Clear;
  3316. {$IFNDEF NO_THREADS}
  3317. StartAllWatchThreads;
  3318. IF Assigned(FDirView) And Not FDirView.WatchThreadActive Then
  3319. FDirView.StartWatchThread;
  3320. IF Assigned(DropSourceControl) And (DropSourceControl is TDirView) And Not TDirView(DropSourceControl).WatchThreadActive Then
  3321. TDirView(DropSourceControl).StartWatchThread;
  3322. {$ENDIF}
  3323. Screen.Cursor := SaveCursor;
  3324. End;
  3325. End; {PerformDragDropFileOperation}
  3326. Procedure TDriveView.DDError(ErrorNo : TDDError);
  3327. Begin
  3328. IF Assigned(FOnDDError) Then
  3329. FOnDDError(Self, ErrorNo)
  3330. Else
  3331. Raise EDragDrop.CreateFmt(ENGLISH_DragDropError, [Ord(ErrorNo)]);
  3332. End; {DDError}
  3333. Function TDriveView.GetCanUndoCopyMove : Boolean;
  3334. Begin
  3335. Result := Assigned(FFileOperator) And FFileOperator.CanUndo;
  3336. End; {CanUndoCopyMove}
  3337. Function TDriveView.UndoCopyMove : Boolean;
  3338. Var LastTarget : String;
  3339. LastSource : String;
  3340. Begin
  3341. Result := False;
  3342. IF FFileOperator.CanUndo Then
  3343. Begin
  3344. Lasttarget := FFileOperator.LastOperandTo[0];
  3345. LastSource := FFileOperator.LastOperandFrom[0];
  3346. {$IFNDEF NO_THREADS}
  3347. StopAllWatchThreads;
  3348. {$ENDIF}
  3349. Result := FFileOperator.UndoExecute;
  3350. ValidateDirectory(FindNodeToPath(ExtractFilePath(LastTarget)));
  3351. ValidateDirectory(FindNodeToPath(ExtractFilePath(LastSource)));
  3352. {$IFNDEF NO_THREADS}
  3353. StartAllWatchThreads;
  3354. {$ENDIF}
  3355. IF Assigned(FDirView) Then
  3356. With FDirView Do
  3357. {$IFNDEF NO_THREADS}
  3358. IF Not WatchThreadActive Then
  3359. {$ENDIF}
  3360. Begin
  3361. IF (AddSlash(ExtractFilePath(LastTarget)) = AddSlash(Path)) Or
  3362. (AddSlash(ExtractFilePath(LastSource)) = AddSlash(Path)) Then
  3363. Reload2;
  3364. End;
  3365. End;
  3366. End; {UndoCopyMove}
  3367. {Clipboard operations:}
  3368. Procedure TDriveView.SetLastPathCut(Path : String);
  3369. Var Node : TTreeNode;
  3370. Begin
  3371. If FLastPathCut <> Path Then
  3372. Begin
  3373. Node := FindNodeToPath(FLastPathCut);
  3374. IF Assigned(Node) Then
  3375. Begin
  3376. FLastPathCut := Path;
  3377. Node.Cut := False;
  3378. End;
  3379. Node := FindNodeToPath(Path);
  3380. IF Assigned(Node) Then
  3381. Begin
  3382. FLastPathCut := Path;
  3383. Node.Cut := True;
  3384. End;
  3385. End;
  3386. End; {SetLastNodeCut}
  3387. Procedure TDriveView.EmptyClipboard;
  3388. Begin
  3389. IF Windows.OpenClipBoard(0) Then
  3390. Begin
  3391. Windows.EmptyClipBoard;
  3392. Windows.CloseClipBoard;
  3393. LastPathCut := '';
  3394. LastClipBoardOperation := cboNone;
  3395. IF Assigned(FDirView) Then
  3396. FDirView.EmptyClipboard;
  3397. End;
  3398. End; {EmptyClipBoard}
  3399. Function TDriveView.CopyToClipBoard(Node : TTreeNode) : Boolean;
  3400. Begin
  3401. Result := Assigned(Selected);
  3402. IF Result Then
  3403. Begin
  3404. EmptyClipBoard;
  3405. FDD.FileList.Clear;
  3406. FDD.FileList.AddItem(NIL, GetDirPathName(Selected));
  3407. Result := FDD.CopyToClipBoard;
  3408. LastClipBoardOperation := cboCopy;
  3409. End;
  3410. End; {CopyToClipBoard}
  3411. Function TDriveView.CutToClipBoard(Node : TTreeNode) : Boolean;
  3412. Begin
  3413. Result := Assigned(Node) And (Node.Level > 0) And CopyToClipBoard(Node);
  3414. IF Result Then
  3415. Begin
  3416. LastPathCut := GetDirPathName(Node);
  3417. LastClipBoardOperation := cboCut;
  3418. End;
  3419. End; {CutToClipBoard}
  3420. Function TDriveView.CanPasteFromClipBoard : Boolean;
  3421. Begin
  3422. Result := False;
  3423. IF Assigned(Selected) And Windows.OpenClipboard(0) Then
  3424. Begin
  3425. Result := IsClipboardFormatAvailable(CF_HDROP);
  3426. Windows.CloseClipBoard;
  3427. End;
  3428. End; {CanPasteFromClipBoard}
  3429. Function TDriveView.PasteFromClipBoard(TargetPath : String = '') : Boolean;
  3430. Begin
  3431. FDD.FileList.Clear;
  3432. Result := False;
  3433. IF CanPasteFromClipBoard And
  3434. {MP}{$IFDEF OLD_DND} FDD.GetFromClipBoard {$ELSE} FDD.PasteFromClipboard {$ENDIF}{/MP}
  3435. Then
  3436. Begin
  3437. IF TargetPath = '' Then
  3438. TargetPath := GetDirPathName(Selected);
  3439. Case LastClipBoardOperation Of
  3440. cboCopy,
  3441. cboNone: Begin
  3442. PerformDragDropFileOperation(TargetPath, DropEffect_Copy, TNodeData(Selected.Data).isRecycleBin);
  3443. IF Assigned(FOnDDExecuted) Then
  3444. FOnDDExecuted(Self, DropEffect_Copy);
  3445. End;
  3446. cboCut : Begin
  3447. PerformDragDropFileOperation(TargetPath, DropEffect_Move, TNodeData(Selected.Data).isRecycleBin);
  3448. IF Assigned(FOnDDExecuted) Then
  3449. FOnDDExecuted(Self, DropEffect_Move);
  3450. EmptyClipBoard;
  3451. End;
  3452. End;
  3453. Result := True;
  3454. End;
  3455. End; {PasteFromClipBoard}
  3456. Procedure TDriveView.SetTargetPopUpMenu(PopMe : Boolean);
  3457. Begin
  3458. IF PopMe <> FTargetPopUpMenu Then
  3459. Begin
  3460. FTargetPopUpMenu := PopMe;
  3461. IF Assigned(FDD) Then
  3462. FDD.TargetPopupMenu := PopMe;
  3463. End;
  3464. end; {SetTargetPopUpMenu}
  3465. {$ENDIF}
  3466. initialization
  3467. {$IFDEF USE_DRIVEVIEW}
  3468. ErrorInvalidDirName := English_ErrorInvalidDirName;
  3469. {$ENDIF}
  3470. end.