PageRenderTime 24ms CodeModel.GetById 18ms app.highlight 3ms RepoModel.GetById 1ms app.codeStats 0ms

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