ExplorerTool – small enhancements of default shell

Post your working scripts, libraries and tools for AHK v1.1 and older
mcl
Posts: 355
Joined: 04 May 2018, 16:35

ExplorerTool – small enhancements of default shell

04 May 2018, 17:32

Hi all. I've wrote this little tool to extend default Windows file manager functionality and want to share it with you.
It works fine on my Win7 64-bit. If you can confirm that it works on WinXP/Win8/Win10, that'll be greatly appreciated.

This tool contains 3.5 useful functions that'll work when you have Explorer window active:

1. LiveQuery / SimpleQuery
Press hotkey and start typing — and files matching your input will be selected.
• You can use wildcards * (multiple chars), ? (single char) and # (single digit).
• You can use quotes if query "contains spaces", and pipe|bar to select multiple variants.
• You can also filter by size: for example, >100k <1m will select files between 100 kilobytes and 1 megabyte.
• By default, folders will not be selected, but you can use key /d to include them and /D to select only folders.
SimpleQuery function is based on InputBox, thus requires Enter to confirm selection.
LiveQuery function selects files on-the-fly. Its window hides automatically when loses focus, but Enter/Escape works as well.
Default hotkey: Ctrl-Q

2. SetViewMode
Switches between different view modes (list, details, thumbs) by hotkeys.
Meh, not so fancy.
Default hotkey: Ctrl-1/2/3

3. CreateNewFolder
Exactly.
Default hotkey: Ctrl-N, of course.

So, what do you think? I mean, besides 'why not use Far/TC/whatever'.

Code: Select all

Class ExplorerTool {
	
	SetViewMode( pMode := 0 ) {
		Static viewModes := {"Icon": 1, "SmallIcon":2, "List":3, "Details":4, "Thumbs":5, "Tile":6, "ThumbStrip":7}
		
		activeSFV := this.GetActiveShellFolderView()
		
		If (activeSFV == "")
			Return
		
		If (viewModes[pMode] != "")
			pMode := viewModes[pMode]
		
		If ((pMode < 1) || (pMode > 7))
			Return
		
		activeSFV.CurrentViewMode := pMode
	}
	
	
	CreateNewFolder( pName := "New Folder" ) {
		activeSFV := this.GetActiveShellFolderView()
		
		If (activeSFV == "")
			Return
		
		newFolderNameX := pName
		
		Loop {
			isAlreadyExists := activeSFV.Folder.ParseName(newFolderNameX)
			
			If (isAlreadyExists == "") {
				activeSFV.Folder.NewFolder(newFolderNameX)
				Break
			}
			
			newFolderNameX := Format("{1} ({2})", newFolderName, A_Index)
		}
		
		newFolderAsItem := activeSFV.Folder.ParseName(newFolderNameX)
		activeSFV.SelectItem(newFolderAsItem, 3|4|8|16)
	}
	
	
	Class LiveQuery {
		Static __Parent     := ""
		Static guiControls  := ""
		Static activeSFV    := ""
		Static focusHandler := ""
		
		
		Init() {
			If (this.__Parent == "") {
				parentClassName := RegexReplace(this.__Class, "\.[^\.]+$", "")
				this.__Parent := %parentClassName%
			}
			
			If (this.focusHandler == "") {
				this.focusHandler := ObjBindMethod(this, "GuiCheckFocus", this)
			}
			
			If (this.guiControls != "")
				Return
			
			
			ETGuiWindowTitle := "ExplorerTool Filter Query"
			ETGuiTextHint    := "Enter query. You can use wildcards * ? #, ""quotes"", pipe|bar,"
					   . "`n" . "size filters >10k <10m and folder keys keys /d /D"
			
			
			Gui, ETGui: New       ,      HWNDhETGuiWindow , % ETGuiWindowTitle
			Gui, ETGui: Add, Text , w500 HWNDhETGuiText   , % ETGuiTextHint
			Gui, ETGui: Add, Edit , w500 HWNDhETGuiEdit   , % ""
			
			Gui, ETGui: +ToolWindow
			
			
			this.guiControls := {}
			this.guiControls["Window"] := hETGuiWindow
			this.guiControls["Edit"  ] := hETGuiEdit
			
			
			Gui, % ("ETGui:+Label" . this.__Class . ".GuiOn")
			
			editHandler := ObjBindMethod(this, "GuiOnEdit", this)
			GuiControl, ETGui: +g, % hETGuiEdit, % editHandler
			
			enterHandler := ObjBindMethod(this, "GuiOnClose", this)
			HotKey, IfWinActive, % ("ahk_id " . this.guiControls["Window"])
			HotKey, Enter, % enterHandler
			HotKey, If
		}
		
		
		GuiOnClose() {
			Gui, ETGui: Hide
		}
		
		GuiOnEscape() {
			Gui, ETGui: Hide
		}
		
		GuiCheckFocus() {
			If (WinActive("A") != this.guiControls["Window"]) {
				this.GuiOnClose()
				Return
			}
			
			focusHandler := this.focusHandler
			SetTimer, % focusHandler, -250
		}
		
		
		GuiOnEdit() {
			GuiControlGet, queryText,, % this.guiControls["Edit"]
			this.__Parent.SelectFiltered(this.activeSFV, queryText)
		}
		
		
		Show() {
			this.Init()
			this.activeSFV := this.__Parent.GetActiveShellFolderView()
			
			If (this.activeSFV == "")
				Return
			
			Gui, ETGui: Show, Y0
			GuiControl,, % this.guiControls["Edit"]
			GuiControl, Focus, % this.guiControls["Edit"]
			
			WinWaitActive % "ahk_id " this.guiControls["Window"]
			this.GuiCheckFocus()
		}
	}
	
	
	SimpleQuery() {
		activeSFV := this.GetActiveShellFolderView()
		
		If (activeSFV == "")
			Return
		
		InputBox, query, % "Enter filter query"
		, % "You can use wildcards *, ? and # for digits"
		. "`nInclude folders with /d or select only folders with /D"
		. "`nFilter size with >100k and <100m"
		. "`nUse quotes if query ""contains spaces"""
		. "`nSelect multiple|several variants with pipe"
		,,,, , 0
		
		If (ErrorLevel == 1)
			Return
		
		this.SelectFiltered(activeSFV, query)
	}
	
	
	GetActiveShellFolderView() {
		activeWindowHWND := WinActive("A")
		
		comShell := ComObjCreate("Shell.Application")
		comShellWindows := comShell.Windows()
		
		comActiveShellView := ""
		
		Loop % comShellWindows.Count {
			comShellWindow := comShellWindows.Item(A_Index-1)
			
			If (comShellWindow.HWND == activeWindowHWND) {
				comActiveShellView := comShellWindow.Document
				Break
			}
		}
		
		Return comActiveShellView
	}
	
	
	SelectFiltered(pSFView, pQuery) {
		Critical
		
		If (pSFView == "")
			Return
		
		filter := this.Filter.Prepare(pQuery)
		comFolderItems := pSFView.Folder.Items
		
		Loop % comFolderItems.Count {
			item := comFolderItems.Item(A_Index-1)
			itemMatch := this.Filter.Match(item, filter)
			
			pSFView.SelectItem(item, itemMatch)
		}
	}
	
	
	Class Filter {
		Static escapeChars := Format("([{1}])", RegexReplace("^$.+\()[]{}", "(.)", "\$1"))
		Static sizeFactors := {B:1,  K:1024,  M:1024**2,  G:1024**3}
		Static sizeRegexp  := "Oi)^(<|>)(\d+)([bkmg]?)$"
		
		Prepare( pQueryText ) {
			filter := {tokens: []}
			
			queryDequote := StrSplit(pQueryText, """")
			
			Loop % queryDequote.Length() {
				newToken := queryDequote[A_Index]
				newToken := RegexReplace(newToken, this.escapeChars, "\$1")
				
				If (A_Index & 1 == 0) {
					filter.tokens.Push(newToken)
					Continue
				}
				
				
				tokens := StrSplit(newToken, " ")
				
				For i, token In tokens {
					If (token == "")
						Continue
					
					token := StrReplace(token, "?", ".")
					token := StrReplace(token, "*", ".*?")
					token := StrReplace(token, "#", "\d")
					
					filter.tokens.Push(token)
				}
			}
			
			
			filter.folders := 0
			filter.sizeMin := -1
			filter.sizeMax := -1
			
			tokensCount := filter.tokens.Length()
			
			Loop % tokensCount {
				tokenIndex := tokensCount + 1 - A_Index
				token := filter.tokens[tokenIndex]
				
				If (token ~= "i)^/d$") {
					filter.folders := (token == "/d") ? 1 : 2
					filter.tokens.RemoveAt(tokenIndex)
					Continue
				}
				
				RegexMatch(token, this.sizeRegexp, tokenSize)
				
				If (tokenSize) {
					sizeFactor := tokenSize[3] ? this.sizeFactors[tokenSize[3]] : 1
					totalSize := Floor(tokenSize[2]) * sizeFactor
					
					If (tokenSize[1] == ">") {
						filter.sizeMin := totalSize
					} Else {
						filter.sizeMax := totalSize
					}
					
					filter.tokens.RemoveAt(tokenIndex)
				}
			}
			
			Return filter
		}
		
		
		Match( pItem, pFilter ) {
			itemIsFolder := (pItem.IsFolder && (pItem.Size == 0))
			
			If (((pFilter.folders == 0) && (itemIsFolder == True))
			||  ((pFilter.folders == 2) && (itemIsFolder == False))
			||  ((pFilter.sizeMin != -1) && (pItem.Size < pFilter.sizeMin))
			||  ((pFilter.sizeMax != -1) && (pItem.Size > pFilter.sizeMax)))
				Return False
			
			If ((pFilter.tokens.Length() == 0)
			&&  (pFilter.sizeMin == -1)
			&&  (pFilter.sizeMax == -1))
				Return False
			
			itemName   := pItem.Name
			
			For i, token In pFilter.tokens {
				If ((itemName ~= ("i)" . token)) == 0) {
					Return False
				}
			}
			
			Return True
		}
	}
}


#If WinActive("ahk_class ExploreWClass") || WinActive("ahk_class CabinetWClass")
^q::
	; ExplorerTool.SimpleQuery()
	ExplorerTool.LiveQuery.Show()
	Return

^n::
	ExplorerTool.CreateNewFolder()
	Return

^1::
	ExplorerTool.SetViewMode("List")
	Return

^2::
	ExplorerTool.SetViewMode("Details")
	Return

^3::
	ExplorerTool.SetViewMode("Thumbs")
	Return
Spoiler
github://oGDIp - GDI+ wrapper for AHK v1.1
drozdman
Posts: 78
Joined: 05 Dec 2015, 01:07

Re: ExplorerTool – small enhancements of default shell

04 May 2018, 19:50

This works on Win Vista, Win 8. I didn't check it on Win 10, because I avoid using it (it messes up my multi-boot sequence).
This may be useful especially on newer Windows versions.
zhotkey
Posts: 14
Joined: 21 Jun 2017, 08:22

Re: ExplorerTool – small enhancements of default shell

05 May 2018, 07:13

Works on Windows 10. Very useful! I would change you description to specify the /d or /D must start the string.
mcl
Posts: 355
Joined: 04 May 2018, 16:35

Re: ExplorerTool – small enhancements of default shell

05 May 2018, 08:45

drozdman wrote:This works on Win Vista, Win 8.
zhotkey wrote:Works on Windows 10.
Thanks, it's good to know.
zhotkey wrote:I would change you description to specify the /d or /D must start the string.
These keys should work anywhere as long as they separated by spaces. /d name and name /d should be equivalent.
github://oGDIp - GDI+ wrapper for AHK v1.1
Ldub

Re: ExplorerTool – small enhancements of default shell

06 May 2018, 05:10

Small but very nice enhancement !
Thank's for sharing.
User avatar
DataLife
Posts: 447
Joined: 29 Sep 2013, 19:52

Re: ExplorerTool – small enhancements of default shell

06 May 2018, 21:43

Very nice, thanks
Check out my scripts. (MyIpChanger) (ClipBoard Manager) (SavePictureAs)
All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.
User avatar
Cerberus
Posts: 172
Joined: 12 Jan 2016, 15:46

Re: ExplorerTool – small enhancements of default shell

28 May 2018, 21:42

Wow, this is perfect! Each of these functions is highly useful. It works well on Windows XP.

One little thing that could make it even more useful is if the new folder could be selected and "rename" activated, because 99% of the time, you would want to give that new folder a name.

P.S. What's far? I presume TC is Total Command, and it already has these functions?
Asmodeus
Posts: 57
Joined: 19 Oct 2015, 15:53

Re: ExplorerTool – small enhancements of default shell

30 May 2018, 07:26

drozdman wrote:This works on Win Vista, Win 8. I didn't check it on Win 10, because I avoid using it (it messes up my multi-boot sequence).
I agree to avoid win10 but for other (privacy) reasons. you could easily setup multiboot by using vhd (no need to partition the hard drive). search the internet if you want to learn how (but don't use dr. google for the same reasons). ah yeah, in case you use whatsapp please uninstall it und delete your facebook account (same reasons).
OK, I stop now :facepalm: , I think you got my point :wave:
Cerberus wrote:P.S. What's far? I presume TC is Total Command, and it already has these functions?
FAR is a file manager, and TC is Total Commander also a Norton clone are superior substitutes for windows explorer.

btw, nice script, well done! :bravo:
User avatar
Cerberus
Posts: 172
Joined: 12 Jan 2016, 15:46

Re: ExplorerTool – small enhancements of default shell

25 Jun 2018, 22:23

Asmodeus wrote:
drozdman wrote:This works on Win Vista, Win 8. I didn't check it on Win 10, because I avoid using it (it messes up my multi-boot sequence).
I agree to avoid win10 but for other (privacy) reasons. you could easily setup multiboot by using vhd (no need to partition the hard drive). search the internet if you want to learn how (but don't use dr. google for the same reasons). ah yeah, in case you use whatsapp please uninstall it und delete your facebook account (same reasons).
OK, I stop now :facepalm: , I think you got my point :wave:
Cerberus wrote:P.S. What's far? I presume TC is Total Command, and it already has these functions?
FAR is a file manager, and TC is Total Commander also a Norton clone are superior substitutes for windows explorer.

btw, nice script, well done! :bravo:
Ah, I see. The lack of capitals mist have confused me.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: gwarble, spidell and 65 guests