/FastFolders.ahk

http://7plus.googlecode.com/ · AutoHotKey · 335 lines · 276 code · 17 blank · 42 comment · 48 complexity · 42e96ac62a307e0cc6594e04fbf8d1b8 MD5 · raw file

  1. #include *i %A_ScriptDir%\Navigate.ahk
  2. #include *i %A_ScriptDir%\MiscFunctions.ahk
  3. Class CFastFolders extends CArray
  4. {
  5. MinIndex()
  6. {
  7. return 0
  8. }
  9. MaxIndex()
  10. {
  11. return 9
  12. }
  13. }
  14. ClearStoredFolder(Slot)
  15. {
  16. global FastFolders
  17. ;Slot+=1
  18. FastFolders[Slot].Path := ""
  19. FastFolders[Slot].Name := ""
  20. RefreshFastFolders()
  21. }
  22. ;Assigns a new folder to a FastFolder slot and updates registry
  23. UpdateStoredFolder(Slot, Path = "")
  24. {
  25. global FastFolders
  26. ;Fast folder slots are 0-based externally but 1 based in the FastFolders array
  27. ;Slot += 1
  28. if(Path)
  29. FastFolders[Slot].Path := Path
  30. else
  31. {
  32. FastFolders[Slot].Path := Navigation.GetPath()
  33. FastFolders[Slot].Name := Navigation.GetDisplayName()
  34. }
  35. if(!FastFolders[Slot].Name)
  36. {
  37. SplitPath, Path , split
  38. FastFolders[Slot].Name := split
  39. }
  40. RefreshFastFolders()
  41. }
  42. ;Removes and re-adds all FastFolder Buttons
  43. RefreshFastFolders()
  44. {
  45. if(Settings.Explorer.FastFolders.ShowInFolderBand)
  46. RemoveAllExplorerButtons("IsFastFolderButton")
  47. AddAllButtons(Settings.Explorer.FastFolders.ShowInFolderBand, Settings.Explorer.FastFolders.ShowInPlacesBar)
  48. }
  49. ;Adds all FastFolder Buttons
  50. AddAllButtons(ToFolderBand, ToPlacesBar)
  51. {
  52. global FastFolders
  53. Loop 10
  54. {
  55. ;Fast folder slots are 0-based externally
  56. pos := A_Index - 1
  57. if(FastFolders[pos].Path)
  58. {
  59. if(pos <= 4 && ToPlacesBar) ;update placesbar
  60. {
  61. value := FastFolders[pos].Path
  62. RegWrite, REG_SZ,HKCU,Software\Microsoft\Windows\CurrentVersion\Policies\comdlg32\Placesbar, Place%pos%,%value%
  63. }
  64. }
  65. }
  66. if(ToFolderBand)
  67. {
  68. ;Explorer folder band bar buttons are added in a separate process since this takes a few seconds
  69. if(FastFolders.WorkerThread)
  70. FastFolders.WorkerThread.Repeat := true ;Mark for repetition with new data
  71. else
  72. {
  73. outputdebug starting new worker thread to refresh FastFolder buttons
  74. FastFolders.WorkerThread := new CWorkerThread("AddButtonsToFolderBandBar", 0, 0, 1)
  75. FastFolders.WorkerThread.OnFinish.Handler := "FastFolders_WorkerThread_OnFinish"
  76. FastFolders.WorkerThread.Start(FastFolders)
  77. FastFolders.WorkerThread.WaitForStart(5)
  78. }
  79. }
  80. }
  81. ;Called on main thread when the Fast Folders worker thread has finished
  82. FastFolders_WorkerThread_OnFinish(WorkerThread, Result)
  83. {
  84. global FastFolders
  85. outputdebug Fast Folder buttons refresh finished
  86. if(WorkerThread.Repeat)
  87. {
  88. RemoveAllExplorerButtons("IsFastFolderButton")
  89. outputdebug starting new worker thread to refresh FastFolder buttons
  90. FastFolders.WorkerThread := new CWorkerThread("AddButtonsToFolderBandBar", 0, 0, 1)
  91. FastFolders.WorkerThread.OnFinish.Handler := "FastFolders_WorkerThread_OnFinish"
  92. FastFolders.WorkerThread.Start(FastFolders)
  93. FastFolders.WorkerThread.WaitForStart(5)
  94. }
  95. else
  96. ;Remove the worker thread to indicate that a new one is needed next time
  97. FastFolders.Remove("WorkerThread")
  98. }
  99. ;Worker function executed in seperate thread
  100. AddButtonsToFolderBandBar(WorkerThread, FastFolders)
  101. {
  102. Loop 10
  103. if(FastFolders[A_Index - 1].Path)
  104. AddButton("", FastFolders[A_Index - 1].Path, "", (A_Index - 1) ":" FastFolders[A_Index - 1].Name, "", "Both", 2) ;7plus now uses AHK=2 key in registry to indicate FastFolder buttons
  105. }
  106. ;Callback function for determining if a specific registry key was created by 7plus
  107. IsFastFolderButton(Command, Name, Tooltip, ahk)
  108. {
  109. return ahk = 2 || RegExMatch(Name, "^\d+:") ;RegexMatch is legacy code for buttons which don't have ahk=2 set
  110. }
  111. ;Removes all buttons created with this script. Function can be the name of a function with these arguments: func(command, Title, tooltip, ahk) and it can be used to tell the script if an entry may be deleted
  112. RemoveAllExplorerButtons(function = "")
  113. {
  114. BaseKey := "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderTypes"
  115. ;go into view folders (clsid)
  116. Loop, HKLM, %BaseKey%, 2, 0
  117. {
  118. clsid := A_LoopRegName
  119. ;code below needs to be executed for two folders each, [selected item / no selected item]
  120. Keys := {TasksItemsSelected : "", TasksNoItemsSelected : ""}
  121. for Key, v in Keys
  122. {
  123. ;go into numbered folders of single buttons
  124. Loop, HKLM, %BaseKey%\%clsid%\%Key%, 2, 0
  125. {
  126. ButtonNumber := A_LoopRegName
  127. ;This function will only remove buttons created by 7plus which have an additional AHK key
  128. RegRead, ahk, HKLM, %BaseKey%\%clsid%\%Key%\%ButtonNumber%, AHK
  129. ;go into clsid folder
  130. Loop, HKLM, %BaseKey%\%clsid%\%Key%\%ButtonNumber%, 2, 0
  131. {
  132. skip := false
  133. RegRead, value, HKLM, %BaseKey%\%clsid%\%Key%\%ButtonNumber%\%A_LoopRegName%, InfoTip
  134. RegRead, Title, HKLM, %BaseKey%\%clsid%\%Key%\%ButtonNumber%\%A_LoopRegName%, Title
  135. RegRead, cmd, HKLM, %BaseKey%\%clsid%\%Key%\%ButtonNumber%\%A_LoopRegName%\shell\InvokeTask\command
  136. ;Custom skip function code
  137. if(IsFunc(function))
  138. if(!%function%(cmd, Title, value, ahk))
  139. {
  140. skip := true
  141. break
  142. }
  143. }
  144. if(skip)
  145. continue
  146. if(ahk)
  147. RegDelete, HKLM, %BaseKey%\%clsid%\%Key%\%ButtonNumber%
  148. }
  149. }
  150. }
  151. }
  152. ;Removes a button. Command can either be a real command (with arguments), a path or a function with three arguments (command, key, param) which identifies the proper key
  153. RemoveButton(Command, param="")
  154. {
  155. if(!IsFunc(Command) && InStr(Command,"\",0,strlen(Command)))
  156. StringTrimRight, Command, Command, 1
  157. BaseKey := "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderTypes"
  158. ButtonFound := false
  159. ;go into view folders (clsid)
  160. Loop, HKLM, %BaseKey%, 2, 0
  161. {
  162. clsid := A_LoopRegName
  163. ;code below needs to be executed for two folders each, [selected item / no selected item]
  164. Keys := {TasksItemsSelected : "", TasksNoItemsSelected : ""}
  165. for Key, v in Keys
  166. {
  167. ;Local variable inside this loop for telling found state of the selected/no selected folders
  168. maxnumber := -1
  169. ;Loop through all buttons of this view (reg loop goes backwards apparently)
  170. Loop, HKLM, %BaseKey%\%clsid%\%Key%, 2, 0
  171. {
  172. ButtonNumber := A_LoopRegName
  173. maxnumber := max(ButtonNumber, maxnumber)
  174. ;Keys created by 7plus have an "AHK" key added to them to make sure that only Keys related to 7plus are modified
  175. RegRead, ahk, HKLM, %BaseKey%\%clsid%\%Key%\%ButtonNumber%, AHK
  176. if(ahk)
  177. {
  178. ;go into 2nd clsid folder
  179. Loop, HKLM, %BaseKey%\%clsid%\%Key%\%ButtonNumber%, 2, 0
  180. {
  181. RegRead, value, HKLM, %BaseKey%\%clsid%\%Key%\%ButtonNumber%\%A_LoopRegName%, InfoTip
  182. ;Check if the current key is the correct one (possibly with a caller-defined function)
  183. if((!IsFunc(Command) && value = Command) || (IsFunc(Command) && %Command%(value, BaseKey "\" clsid "\" Key "\" ButtonNumber "\" A_LoopRegName "\shell\InvokeTask\command", param)))
  184. {
  185. ;If the key is correct, it may be deleted
  186. RegDelete, HKLM, %BaseKey%\%clsid%\%Key%\%ButtonNumber%
  187. ButtonFound := true
  188. ;after item has been deleted, we need to move the higher ones down by one
  189. if(maxnumber > ButtonNumber)
  190. {
  191. i := ButtonNumber + 1
  192. while i <= maxnumber
  193. {
  194. j := i - 1
  195. Runwait, reg copy HKLM\%BaseKey%\%clsid%\%Key%\%i% HKLM\%BaseKey%\%clsid%\%Key%\%j% /s /f, , Hide
  196. regdelete, HKLM, %BaseKey%\%clsid%\%Key%\%i%
  197. i++
  198. }
  199. }
  200. break 2
  201. }
  202. }
  203. }
  204. }
  205. }
  206. }
  207. if(!ButtonFound)
  208. outputdebug % "Explorer button not found: " (param.Extends("CEvent") ? param.Name : Command)
  209. return ButtonFound
  210. }
  211. ;Adds a button. You may specify a command (and possibly an argument) or a path, and a name which should be used.
  212. ;Other parameters are a ToolTip
  213. AddButton(Command, path, Args = "", Name = "", Tooltip = "", AddTo = "Both", ahk = 1, IterationsSelected = "", IterationsNoSelected = "")
  214. {
  215. outputdebug addbutton command %command% path %path% args %args% name %name%
  216. if(A_IsCompiled)
  217. ahk_path := """" A_ScriptDir "\7plus.exe"""
  218. else
  219. ahk_path := """" A_AhkPath """ """ A_ScriptFullPath """"
  220. icon := "%SystemRoot%\System32\shell32.dll,3" ;Icon is not working, probably not supported by explorer, some ms entries have icons defined but they don't show up either
  221. if(Command)
  222. {
  223. if(!Name)
  224. {
  225. SplitPath, Command , Name
  226. if(Name = "")
  227. Name := Command
  228. }
  229. icon := Command ",1"
  230. description := command
  231. command .= " " args
  232. }
  233. if(path)
  234. {
  235. ;Remove trailing backslash
  236. if(InStr(path,"\", 0, strlen(path)))
  237. StringTrimRight, path, path, 1
  238. if(!name)
  239. {
  240. SplitPath, path , Name
  241. if(Name = "")
  242. Name := path
  243. }
  244. Command := ahk_path " """ path """"
  245. description := path
  246. }
  247. if(!command && !path && args) ;args only, use start 7plus with -id param
  248. {
  249. Command := """" (A_IsCompiled ? A_ScriptPath : A_AhkPath """ """ A_ScriptFullPath) """ -id:" args
  250. description := Tooltip
  251. }
  252. SomeCLSID := "{" . uuid(false) . "}"
  253. ;These arrays store the next free index of the buttons in the FolderTypes subfolders for speed improvements
  254. if(!IsObject(IterationsSelected))
  255. IterationsSelected := []
  256. if(!IsObject(IterationsNoSelected))
  257. IterationsNoSelected := []
  258. BasePath := "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderTypes"
  259. ;go into view folders (clsid)
  260. Loop, HKLM, %BasePath%, 2, 0
  261. {
  262. if(AddTo = "Both" || AddTo = "Selected")
  263. AddButton_Write(BasePath "\" A_LoopRegName "\TasksItemsSelected", SomeCLSID, command, Name, Description, Icon, ahk, A_LoopRegName, IterationsSelected)
  264. if(AddTo = "Both" || AddTo = "NoSelected")
  265. AddButton_Write(BasePath "\" A_LoopRegName "\TasksNoItemsSelected", SomeCLSID, command, Name, Description, Icon, ahk, A_LoopRegName, IterationsNoSelected)
  266. }
  267. }
  268. ;Writes the data for a single button (for selected or no-selected state)
  269. AddButton_Write(Path, SomeCLSID, command, Title, InfoTip, Icon, AHK, Name, Iterations)
  270. {
  271. ;figure out first free key number
  272. if(!Iterations.HasKey(Name))
  273. {
  274. Iterations[Name] := 0
  275. Loop, HKLM, %Path%, 2, 0
  276. Iterations[Name]++
  277. }
  278. Path .= "\" Iterations[Name]
  279. ;Marker for easier recognition of ahk-added entries
  280. RegWrite, REG_SZ, HKLM, %Path%, AHK, %AHK%
  281. Path .= "\" SomeCLSID
  282. ;Write reg keys
  283. RegWrite, REG_EXPAND_SZ, HKLM, %Path%, Icon, %icon%
  284. RegWrite, REG_SZ, HKLM, %Path%, InfoTip, %InfoTip%
  285. RegWrite, REG_SZ, HKLM, %Path%, Title, %Title%
  286. RegWrite, REG_SZ, HKLM, %Path%\shell\InvokeTask\command, , %command%
  287. Iterations[Name]++
  288. }
  289. ;Checks if a particular button exists
  290. FindButton(function, param)
  291. {
  292. if(!IsFunc(function))
  293. return false
  294. BasePath := "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderTypes"
  295. ;go into view folders (clsid)
  296. Loop, HKLM, %BasePath%, 2, 0
  297. {
  298. regkey := A_LoopRegName
  299. maxnumber := -1
  300. ;loop through selected item number folders (loop goes backwards)
  301. Loop, HKLM, %Basepath%\%regkey%\TasksItemsSelected, 2, 0
  302. {
  303. numberfolder := A_LoopRegName
  304. RegRead, ahk, HKLM, %Basepath%\%regkey%\TasksItemsSelected\%numberfolder%, AHK
  305. if(ahk)
  306. {
  307. ;go into clsid folder
  308. Loop, HKLM, %Basepath%\%regkey%\TasksItemsSelected\%numberfolder%, 2, 0
  309. {
  310. RegRead, value, HKLM, %Basepath%\%regkey%\TasksItemsSelected\%numberfolder%\%A_LoopRegName%\shell\InvokeTask\command
  311. if(%function%(value, Basepath "\" regkey "\TasksItemsSelected\" numberfolder "\" A_LoopRegName "\shell\InvokeTask\command", param))
  312. return true
  313. }
  314. }
  315. }
  316. }
  317. return false
  318. }