Select folders which (sub)folder(s) contains certain file?

Here you go.. o)


Now featuring:

  • progress dialog
  • search dialog
    • search only in extension
    • search only in stem
    • search full filename (if extension/stem checkboxes enabled)
    • optionally exclude folder (must be entered in the button code, as there is no way to have 2 text fields right now)
    • input validation.. o)
  • previously used search parameters will be preserved per tab
<?xml version="1.0"?>
<button backcol="none" display="both" textcol="none">
	<label>Folder Selector</label>
	<tip>Folder Selector</tip>
	<icon1>#newcommand</icon1>
	<function type="script">
		<instruction>@script jscript</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>// Simple dialog based search to select folders.</instruction>
		<instruction>// Folders will be selected if they contain matching files and at the same</instruction>
		<instruction>// time do not contain a subfolder (optional).</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>var defaultSearch = new SearchParams(</instruction>
		<instruction>	/*search string*/	&apos;iso&apos;,</instruction>
		<instruction>	/*search extension*/	true,</instruction>
		<instruction>	/*search stem*/		false,</instruction>
		<instruction>	/*subfolder name*/	&apos;video_ts&apos;,</instruction>
		<instruction>	/*exclude subfolder*/	true</instruction>
		<instruction>);</instruction>
		<instruction />
		<instruction>var lastSearch = null;</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function OnClick(data){</instruction>
		<instruction>	DOpus.ClearOutput();</instruction>
		<instruction>	data.func.command.ClearFiles();</instruction>
		<instruction />
		<instruction>	//get enumerator and count of selected folders or complete list of folders</instruction>
		<instruction>	var folders = GetFolders(data);</instruction>
		<instruction />
		<instruction>	//get a combination of default, last used and current dialog search params</instruction>
		<instruction>	var params = GetSearchParams(data); if (!params) return; //dialog cancelled</instruction>
		<instruction />
		<instruction>	//save current search params</instruction>
		<instruction>	SaveSearchParams(data, params);</instruction>
		<instruction />
		<instruction>	//init, open and return progress dialog</instruction>
		<instruction>	var progress = OpenProgressDialog( data, &quot;Folder Selector..&quot;, folders.count);</instruction>
		<instruction />
		<instruction>	var searchMode = params.GetSearchMode();</instruction>
		<instruction>	while (!folders.enumerator.atEnd() ) {</instruction>
		<instruction>		var folder = folders.enumerator.item(); folders.enumerator.moveNext();</instruction>
		<instruction>		dout(&quot;Folder [&quot;+folder.name+&quot;]..&quot;);</instruction>
		<instruction>		progress.SetName(folder.name);</instruction>
		<instruction>		//if subfolder to exclude is given, search subfolders before looking for matching files</instruction>
		<instruction>		if (params.excludeFolder &amp;&amp; defaultSearch.excludeFolderName!=&quot;&quot; &amp;&amp; SubFolderExists( folder.path+&quot;\\&quot;+folder.name, defaultSearch.excludeFolderName)){</instruction>
		<instruction>			dout(&quot;    Contains subfolder [&quot;+defaultSearch.excludeFolderName+&quot;], skipping folder.&quot;);</instruction>
		<instruction>			progress.StepFiles(1);</instruction>
		<instruction>			continue;</instruction>
		<instruction>		}</instruction>
		<instruction>		if (exists = FileExists( folder.path+&quot;\\&quot;+folder.name, params.searchMe, searchMode)){</instruction>
		<instruction>			dout(&quot;    Contains at least one matching file.&quot;);</instruction>
		<instruction>			data.func.command.AddFile(folder);</instruction>
		<instruction>		}</instruction>
		<instruction>		progress.StepFiles(1);</instruction>
		<instruction>    }</instruction>
		<instruction />
		<instruction>	data.func.command.RunCommand(&quot;Select FROMSCRIPT DESELECTNOMATCH MAKEVISIBLE&quot;);</instruction>
		<instruction>	progress.Hide();</instruction>
		<instruction>	DOMsgBox(&quot;ISO-FolderSelector&quot;,&quot;Found &quot;+data.func.command.files.count+&quot; folder(s) matching your search.&quot;,&quot;Ok&quot;);</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function ReadFolder( path, recurse, exception){</instruction>
		<instruction>	if (recurse == undefined) recurse=false;</instruction>
		<instruction>	if (exception == undefined) exception=true;</instruction>
		<instruction>	var fEnum = DOpus.FSUtil.ReadDir( path, true);</instruction>
		<instruction>	if (fEnum.error!=0){</instruction>
		<instruction>		var error = &quot;ReadFolder(): Error reading folder [&quot;+name+&quot;], code [&quot;+fEnum.error+&quot;].&quot;;</instruction>
		<instruction>		if (exception) throw error;</instruction>
		<instruction>		dout(error);</instruction>
		<instruction>	}</instruction>
		<instruction>	return fEnum;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function SubFolderExists( folderPath, subFolderName){</instruction>
		<instruction>	subFolderName = subFolderName.toLowerCase();</instruction>
		<instruction>	var fEnum = ReadFolder( folderPath, true, true);</instruction>
		<instruction>	while (!fEnum.complete &amp;&amp; (fItem = fEnum.Next()))</instruction>
		<instruction>		if (fItem.is_dir &amp;&amp; (fItem.name.toLowerCase() == subFolderName))</instruction>
		<instruction>			return true;</instruction>
		<instruction>	return false;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function FileExists( folderPath, searchMe, searchMode){</instruction>
		<instruction>	if (searchMode == undefined) searchMode=&apos;full&apos;;</instruction>
		<instruction>	searchMe = searchMe.toLowerCase();</instruction>
		<instruction>	if (searchMode==&apos;ext&apos;) searchMe=searchMe.replace(&apos;\.&apos;,&apos;&apos;);</instruction>
		<instruction>	var fEnum = ReadFolder( folderPath, true, true);</instruction>
		<instruction>	while (!fEnum.complete &amp;&amp; (fItem = fEnum.Next())){</instruction>
		<instruction>		if (fItem.is_dir) continue;</instruction>
		<instruction>		switch (searchMode){</instruction>
		<instruction>			case &apos;ext&apos;:</instruction>
		<instruction>				if (fItem.ext.toLowerCase()==&quot;.&quot;+searchMe)</instruction>
		<instruction>					return true;</instruction>
		<instruction>			break;</instruction>
		<instruction>			case &apos;stem&apos;:</instruction>
		<instruction>				if (fItem.name_stem.toLowerCase().indexOf(searchMe)!=-1)</instruction>
		<instruction>					return true;</instruction>
		<instruction>			break;</instruction>
		<instruction>			case &apos;full&apos;:</instruction>
		<instruction>			default:</instruction>
		<instruction>				if (fItem.name.toLowerCase().indexOf(searchMe)!=-1)</instruction>
		<instruction>					return true;</instruction>
		<instruction>			break;</instruction>
		<instruction>		}</instruction>
		<instruction>	}</instruction>
		<instruction>	return false;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function GetFolders(data){</instruction>
		<instruction>	if (data.func.sourcetab.selected_dirs.count)</instruction>
		<instruction>		var dirs = data.func.sourcetab.selected_dirs;</instruction>
		<instruction>	else</instruction>
		<instruction>		var dirs = data.func.sourcetab.dirs;</instruction>
		<instruction>	return { enumerator:new Enumerator(dirs), count:dirs.count};</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function DoDialog( params){</instruction>
		<instruction>	var dlg = DOpus.Dlg</instruction>
		<instruction>	dlg.window = DOpus.Listers(0);</instruction>
		<instruction>	dlg.message = &quot;Please enter string/extension to search for:\n &quot;;</instruction>
		<instruction>	dlg.title = &quot;Folder Selector..&quot;;</instruction>
		<instruction>	dlg.buttons = &quot;OK|Cancel&quot;;</instruction>
		<instruction>	dlg.icon = &quot;question&quot;;</instruction>
		<instruction />
		<instruction>	dlg.max = 128; //enable text field</instruction>
		<instruction>	dlg[&apos;default&apos;] = params.searchMe;</instruction>
		<instruction />
		<instruction>	dlg.options(0).label = &quot;search extension&quot;;</instruction>
		<instruction>	dlg.options(0).state = params.searchExtension;</instruction>
		<instruction />
		<instruction>	dlg.options(1).label = &quot;search stem&quot;;</instruction>
		<instruction>	dlg.options(1).state = params.searchStem;</instruction>
		<instruction />
		<instruction>	if (defaultSearch.excludeFolderName!=&quot;&quot;){</instruction>
		<instruction>		dlg.options(2).label = &quot;may not contain folder (&quot;+defaultSearch.excludeFolderName+&quot;)&quot;;</instruction>
		<instruction>		dlg.options(2).state = params.excludeFolder;</instruction>
		<instruction>	}</instruction>
		<instruction>	return dlg;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function OpenProgressDialog( data, title, numFiles){</instruction>
		<instruction>	var progress = data.func.command.progress;</instruction>
		<instruction>	progress.delay = false;</instruction>
		<instruction>	progress.abort = true;</instruction>
		<instruction>	progress.Init(data.func.sourcetab, title);</instruction>
		<instruction>	progress.AddFiles(numFiles);</instruction>
		<instruction>	progress.Show();</instruction>
		<instruction>	return progress;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function SearchParams(searchMe, searchExtension, searchStem, excludeFolderName, excludeFolder){</instruction>
		<instruction>	if (searchMe == undefined) searchMe=&apos;iso&apos;;</instruction>
		<instruction>	if (searchExtension == undefined) searchExtension=true;</instruction>
		<instruction>	if (searchStem == undefined) searchStem=false;</instruction>
		<instruction>	if (excludeFolderName == undefined) excludeFolderName=&quot;&quot;;</instruction>
		<instruction>	if (excludeFolder == undefined) excludeFolder=false;</instruction>
		<instruction>	this.searchMe=searchMe;</instruction>
		<instruction>	this.searchExtension=searchExtension;</instruction>
		<instruction>	this.searchStem=searchStem;</instruction>
		<instruction>	this.excludeFolderName=excludeFolderName;</instruction>
		<instruction>	this.excludeFolder=excludeFolder;</instruction>
		<instruction>	this.GetSearchMode = function(){</instruction>
		<instruction>		var searchMode=&apos;full&apos;;</instruction>
		<instruction>		if (this.searchExtension &amp;&amp; !this.searchStem) searchMode=&apos;ext&apos;;</instruction>
		<instruction>		if (!this.searchExtension &amp;&amp; this.searchStem) searchMode=&apos;stem&apos;;</instruction>
		<instruction>		return searchMode;</instruction>
		<instruction>	}</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function GetSearchParamsFromDialog(dlg){</instruction>
		<instruction>	var dlgSearchParams = new SearchParams();</instruction>
		<instruction>	dlgSearchParams.searchMe = dlg.input;</instruction>
		<instruction>	dlgSearchParams.searchExtension = dlg.options(0).state;</instruction>
		<instruction>	dlgSearchParams.searchStem = dlg.options(1).state;</instruction>
		<instruction>	if (defaultSearch.excludeFolderName){ //exclude subfolder name given, so option is present to exclude it</instruction>
		<instruction>		dlgSearchParams.excludeFolder = dlg.options(2).state;</instruction>
		<instruction>	}</instruction>
		<instruction>	return dlgSearchParams;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function ValidateSearchParams(params){</instruction>
		<instruction>	if (!params)</instruction>
		<instruction>		return false;</instruction>
		<instruction>	if (!params.searchExtension &amp;&amp; !params.searchStem){</instruction>
		<instruction>			DOMsgBox(&quot;Folder Selector..&quot;, &quot;You need to select stem or extension or both!&quot;, &quot;Oops!&quot;);</instruction>
		<instruction>			return false;</instruction>
		<instruction>	}</instruction>
		<instruction>	if (params.searchMe==&quot;&quot;){</instruction>
		<instruction>			DOMsgBox(&quot;Folder Selector..&quot;, &quot;You forgot to enter a string to search for!&quot;, &quot;Oops!&quot;);</instruction>
		<instruction>			return false;</instruction>
		<instruction>	}</instruction>
		<instruction>	return true;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function GetDefaultOrLastSearchParams(data){</instruction>
		<instruction>	var search = defaultSearch;</instruction>
		<instruction>	if (data.func.sourcetab.vars.exists(&quot;lastSearch&quot;))</instruction>
		<instruction>		search = Vector2Search(data.func.sourcetab.vars.get(&quot;lastSearch&quot;));</instruction>
		<instruction>	return search;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function GetCombinedSearchParams(data){</instruction>
		<instruction>	var userSearchParams = GetDefaultOrLastSearchParams(data);</instruction>
		<instruction>	var dlg = DoDialog(userSearchParams);</instruction>
		<instruction>	var result=dlg.Show();</instruction>
		<instruction>	if (result==0){</instruction>
		<instruction>		dout(&quot;Folder Selector dialog cancelled.&quot;);</instruction>
		<instruction>		return null;</instruction>
		<instruction>	}</instruction>
		<instruction>	return GetSearchParamsFromDialog(dlg);</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function GetSearchParams(data){</instruction>
		<instruction>	var params = null;</instruction>
		<instruction>	while (!ValidateSearchParams(params)){</instruction>
		<instruction>		params = GetCombinedSearchParams(data);</instruction>
		<instruction>		if (!params)</instruction>
		<instruction>			return false; //dialog canceled</instruction>
		<instruction>	}</instruction>
		<instruction>	return params;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function SaveSearchParams(data, params){</instruction>
		<instruction>	data.func.sourcetab.vars.set(&quot;lastSearch&quot;, Search2Vector(params));</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function Search2Vector( search){</instruction>
		<instruction>	var vector = DOpus.NewVector();</instruction>
		<instruction>	vector.push_back(search.searchMe);</instruction>
		<instruction>	vector.push_back(search.searchExtension);</instruction>
		<instruction>	vector.push_back(search.searchStem);</instruction>
		<instruction>	vector.push_back(search.excludeFolderName);</instruction>
		<instruction>	vector.push_back(search.excludeFolder);</instruction>
		<instruction>	return vector;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function Vector2Search( vector){</instruction>
		<instruction>	return new SearchParams( vector(0), vector(1), vector(2), vector(3), vector(4));</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function DOMsgBox(title,message,buttons){</instruction>
		<instruction>	var dlg = DOpus.Dlg</instruction>
		<instruction>	dlg.window = DOpus.Listers(0);</instruction>
		<instruction>	dlg.message = message;</instruction>
		<instruction>	dlg.title = title;</instruction>
		<instruction>	dlg.buttons = buttons;</instruction>
		<instruction>	var result = dlg.Show();</instruction>
		<instruction>	dout(title+&quot; - &quot;+message+&quot; - &quot;+buttons+&quot; -&gt; &quot;+result);</instruction>
		<instruction>	return result;</instruction>
		<instruction>}</instruction>
		<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
		<instruction>function dout(text){</instruction>
		<instruction>	DOpus.Output(text);</instruction>
		<instruction>}</instruction>
	</function>
</button>