GP SoftwareTwitter
Opus FAQsManualCommandsObjects

Dynamic SWITCHPATH v2.2

Overview

See the old post for v1.0 for an overview of what this does:

One new feature from v1.0 is the jump list which displays the entire config file in a menu, acting as a secondary favorite list and a gateway to getting to a switchpath group. The width of the jump menu can also be adjusted.

Usage

So far all possible commands in DOpus are:

  • DynSwitchPath or DynSwitchPath FORWARD will cycle forward
  • DynSwitchPath BACK will cycle backward
  • DynSwitchPath MENU=opt or DynSwitchPath MENU=options
  • DynSwitchPath MENU=jump or DynSwitchPath MENU=jumplist

Download

Installation (script)

After unzipping the archive, you should have these files:

  • dynamic_switchpath.js
  • dynamic_switchpath.txt

Type /dopusdata\Script AddIns into Opus to go to the scripts folder, and move both files there.

Installation (buttons)

NOTE: Right clicking the buttons is how to access the menus

For instructions on how to paste these code blocks on to a toolbar, see here:

Forward Button

<?xml version="1.0"?>
<button backcol="none" display="both" textcol="none" type="three_button">
	<label>DSP_forward</label>
	<icon1>#default:goforward</icon1>
	<button backcol="none" display="both" textcol="none">
		<label>DSP Forward</label>
		<icon1>#default:goforward</icon1>
		<function type="normal">
			<instruction>DynSwitchPath FORWARD</instruction>
		</function>
	</button>
	<button backcol="none" display="both" textcol="none">
		<label>DSP Jump Menu</label>
		<icon1>#default:goforward</icon1>
		<function type="normal">
			<instruction>DynSwitchPath MENU=jump</instruction>
		</function>
	</button>
</button>

Back Button

<?xml version="1.0"?>
<button backcol="none" display="both" textcol="none" type="three_button">
	<label>DSP_back</label>
	<icon1>#default:goback</icon1>
	<button backcol="none" display="both" textcol="none">
		<label>DSP Back</label>
		<icon1>#default:goback</icon1>
		<function type="normal">
			<instruction>DynSwitchPath BACK</instruction>
		</function>
	</button>
	<button backcol="none" display="both" textcol="none">
		<label>DSP Options</label>
		<icon1>#default:goback</icon1>
		<function type="normal">
			<instruction>DynSwitchPath MENU=opt</instruction>
		</function>
	</button>
</button>

Example configuration file

------dynamic_switchpath.txt-------
C:\
D:\<--------------------- Group 1
E:\
-
C:\Program Files
C:\Windows<----------- Group 2
C:\Windows\system32

Known Caveats

  • Requires DO11 beta6 or greater.
  • ConfFile: Paths must not end with a backslash (\) (with one exception, see below).
  • ConfFile: Cycling through drives root like C:\ and D:\ they must end with a backslash (\).
  • ConfFile: Try to avoid duplicate path entries throughout the whole file, because the first one found will always run, never the second.

Changelog:

v2.2 (03-04-2015)

  • Fixed case sensitive checking on folders (described below)
  • Fixed error when cancelling out of jump menu width dialog
  • Check for minimum dopus version

v2.1 (02-09-2014)

  • Added: Expand to Tabs (currently only works if path of focused tab is one that exists in config file)
  • Added: Where to expand Source/Destination/Ask
  • Added: Options Menu
  • Added: Jump Width Dialog
  • Creates two global vars, dspOptions and dspJumpWidth

v2.0 (02-02-2014)

  • Converted from batch script to jscript
  • Added: Jump List Menu

v1.0 (05-30-2012)

Script Code:

The script code from the v2.2 download above is reproduced here for reference.

Note that the download also includes a config file which you still need. The script is primarily reproduced here to help people looking for ways to do things.

// 2014 yonder

// Note if the comments aren't aligning try changing tabstop to 4 in external editor
// Turn line wrap off for ideal viewing

// file scope
var debug = false;
var cmd;
var objFSO = new ActiveXObject("Scripting.FileSystemObject");
var jumpRun = DOpus.NewVector();									// full length menu names
var jump1 = DOpus.NewVector();										// truncated menu names
var jump2 = DOpus.NewVector();										// menu item flags (bold, checked)
var startTime = new Date().getTime();								// calc runtime in ms
var fShowJump = false;												// jump or jumplist set ?
var dspOptions = 0;													// glob! var
var dspJumpWidth = 40;												// glob! var
//var soundFile = "C:\\WINDOWS\\Media\\Windows XP Ding.wav";

function OnInit(initData)
{
	initData.name = "Dynamic SWITCHPATH";
	initData.desc = "Multiple switchpath definitions to cycle through, from one command. " +
					"Based off current viewing folder in focus. " +
					"(DOpus 11.0 Beta 6 or higher required)";
	initData.copyright = "Feb-2014 yonder";
	initData.version = "2.2";
	initData.default_enable = true;
	initData.min_version = "11.4";

	// define and initialise command
	var cmd = initData.AddCommand();
	cmd.name = "DynSwitchPath";
	cmd.method = "dspMain";
	cmd.desc = initData.desc;
	cmd.label = "DynSwitchPath";
	cmd.template = "FORWARD/S/O,BACK/S/O,MENU/K[opt,jump]/O";

	return false;
}

//////////
// Main
//////////
function dspMain(funcData)
{
	var cntAll = 0;													// counter will only count everything when jump menu is issued
	var cntGrpPaths = 0;											// counter; how many paths per group
	var cntGrps = 0;												// counter; how many groups
	var source = 0;													// choice from "ask" sub menu
	var primary = "", allOther = "";								// Go "primary" SWITCHPATH "all" "other" "paths"
	var group = new Array();
	
	var back = false;
	var match = false;
	
	cmd = funcData.func.Command;
	cmd.Clear();
	cmd.ClearFiles();

	// dspOptions glob!
	if (DOpus.Vars("dspOptions").Exists())
		dspOptions = DOpus.Vars("dspOptions").value;
	else
	{
		// set defaults
		dspOptions |= 8;
		
		DOpus.Vars("dspOptions") = dspOptions;
		DOpus.Vars("dspOptions").persist = true;
	}

	// dspJumpWidth glob!
	if (DOpus.Vars("dspJumpWidth").Exists())
		dspJumpWidth = DOpus.Vars("dspJumpWidth").value;
	else
	{
		DOpus.Vars("dspJumpWidth") = dspJumpWidth;
		DOpus.Vars("dspJumpWidth").persist = true;
	}

	if (dspOptions & 1)
	{
		debug = true;
		if (dspOptions & 2)
			DOpus.ClearOutput();
	}
	
	// parse parameters
	if (funcData.func.args.got_arg.back) back = true;
	if (funcData.func.args.got_arg.menu)
	{
		switch (funcData.func.args.menu)
		{
		case "opt":
		case "options":
			var r = showOptMenu(funcData.func.Dlg);
			if (r == 0)
				return false;
			else
				source = r;
			break;
		case "jump":
		case "jumplist":
			fShowJump = true;
		}
	}

	// pwd (.\\) was returning /home, so using alias to get current working dir
	var dopusData = DOpus.Aliases("dopusdata").path;
	var cfgFile = dopusData + "\\Script AddIns\\dynamic_switchpath.txt";
	if (!objFSO.FileExists(cfgFile))
	{
		d("Config file not found: \"/dopusdata\\Script AddIns\\dynamic_switchpath.txt\"", true);
		cmd.RunCommand("Set UTILITY=otherlog");
		//soundOnError();
		return false;												// fail
	}
	
	// process config file and execute command or show jump menu
	var srcPath = funcData.func.sourcetab.path;
	var objFile = objFSO.OpenTextFile(cfgFile, 1, false);

	while (!objFile.AtEndOfStream)
	{
		var line = trim(objFile.ReadLine());

		if (line.substr(0, 2) == "//") continue;					// ignore comments
		if (line == "-")
		{
			cntGrps++;
			if (match && !fShowJump) break;
			cntGrpPaths = -1;
			primary = "";
			allOther = "";
			group = [];
		}

		if (cntGrpPaths == 0)
			group[cntGrpPaths] = primary = "\"" + line + "\"";
		else if (cntGrpPaths > 0)
		{
			if (back)
				allOther = "\"" + line + "\" " + allOther;
			else
				allOther = allOther + " \"" + line + "\"";
			group[cntGrpPaths] = "\"" + line + "\"";
		}

		if (line.toLowerCase() == lcase(srcPath)) match = 1;
		if (fShowJump)
		{	// prep jump menu
			jump1.push_back(truncatePath(line, dspJumpWidth));
			jumpRun.push_back(line);

			if (line.toLowerCase() == lcase(srcPath))
				jump2.push_back(1);
			else
				jump2.push_back(0);
		}

		cntGrpPaths++; cntAll++;
	}

	objFile.Close();
	
	primary = trim(primary);
	allOther = trim(allOther);
	
	if (match && source)
	{	// expand to tabs
		var openInDest = "";
		for (var i=0; i < group.length; i++)
		{
			if(group[i] == ("\"" + srcPath + "\"")) continue;
			if(source == 2) openInDest = "OPENINDEST";
			cmd.AddLine("Go " + group[i] + " NEWTAB " + openInDest);
		}
		cmd.Run();
	}
	else if (match && !fShowJump)
	{	// switchpath
		cmd.RunCommand("Go " + primary + " SWITCHPATH " + allOther);
		d(cntGrps + " " + cntGrpPaths + " " + primary + " " + allOther);
		
		var elapsedTime = new Date().getTime() - startTime;
		d(elapsedTime + " milliseconds");
		delete elapsedTime;
	}
	else if (fShowJump)
	{	// jump list
		var dlg = funcData.func.Dlg;
		dlg.choices = jump1;
		dlg.menu = jump2;
		var r = dlg.Show();

		if (r > 0)
		{
			cmd.RunCommand("Go " + "\"" + jumpRun(r - 1) + "\"");
			d(jumpRun(r - 1));
		}
	}
	delete group, startTime, objFSO;
	return true;
}

/////////////////
// prepOptMenu
/////////////////
function showOptMenu(dlg)
{
	var tmpJumpWidth = dspJumpWidth;
	if ((parseInt(tmpJumpWidth)) == 255)
		tmpJumpWidth = "MAX";

	var opt1 = DOpus.NewVector(/*"Tabs to SwitchPath, Save",*/
							   /*"Tabs to SwitchPath, Temp",*/
							   "Expand to Tabs", "-",
							    "Ask", "Open in Source", "Open in Destination", "-",
							   /*"Update Toolbar Icon(s)",*/
							   "Jump Menu Width: " + tmpJumpWidth, "-",
							   "Debug", "Clear Output on Run");
	var opt2 = DOpus.NewVector(opt1.length);

	// load options from glob! var
	for (var i = 0; i < opt1.length; i++)
	{
		switch (opt1(i))
		{
		case "Ask":
			if (dspOptions & 8)
			{
				opt2(i) = 6;
				opt2(i+1) = 0;
				opt2(i+2) = 0;
			}
			break;
		case "Open in Source":
			if (!(dspOptions & 4) && !(dspOptions & 8))
				opt2(i) = 6;
			break;
		case "Open in Destination":
			if ((dspOptions & 4) && !(dspOptions & 8))
				opt2(i) = 6;
			break;
		case "Debug":
			if (dspOptions & 1)
			{
				opt2(i) = 2;
				opt2(i+1) &= ~8;
			}
			else
				opt2(i+1) |= 8;
			break;
		case "Clear Output on Run":
			if (dspOptions & 2)
				opt2(i) |= 2;
			break;
		}
	}

	// show menu
	dlg.choices = opt1;
	dlg.menu = opt2;
	var r = dlg.Show();

	// clicked item
	if (r > 0)
	{
		switch (opt1(r - 1))
		{
		case "Expand to Tabs":
			if (dspOptions & 8)
				return showSubMenu("ask_src_dest");
			else if (!(dspOptions & 4) && !(dspOptions & 8))
				return 1; // src
			else if ((dspOptions & 4) && !(dspOptions & 8))
				return 2; // dest
			break;
		case "Ask": dspOptions |= 8; break;
		case "Open in Source": dspOptions &= ~4 & ~8; break;
		case "Open in Destination": dspOptions |= 4; dspOptions &= ~8; break;
		case "Jump Menu Width: "+tmpJumpWidth: showJumpWidthDlg(); break;
		case "Debug": dspOptions ^= 1; if (dspOptions & 1) debug = true; break;
		case "Clear Output on Run": dspOptions ^= 2; break;
		}
		DOpus.Vars("dspOptions") = dspOptions;
		d("dspOptions: " + pad(dspOptions, 3) + " (" + pad(d2b(dspOptions), 8) + ")");
		//return -1;
	}
	return false;
}

/////////////////////
// showJumpWidthDlg
/////////////////////
function showJumpWidthDlg()
{
	var dlg = DOpus.Dlg;
	var input, r;

	dlg.window = DOpus.Listers(0);			// 0 seems to be the lister in focus (z-order?)
	dlg.title = "Jump menu width";
	dlg.message = "Specify desired jump menu width.\n\nAvailable range: 0-255";
	dlg.buttons = "OK|Cancel";
	dlg.Default = dspJumpWidth.toString();
	dlg.max = 3;

	while (true) // only accept numeric input
	{
		r = dlg.Show();
		if (!r) break;
		
		input = trim(dlg.input);
		if (input.match(/^\d+$/) != null)
		{
			if ((parseInt(input)) > 255)
				input = "255";
			DOpus.Vars("dspJumpWidth") = dspJumpWidth = input;
			break;
		}

		dlg.message = "Specify desired jump menu width.      >> NUMBERS ONLY <<\n\nAvailable range: 0-255";
		dlg.Default = input;
	}
	d("dlgJumpWidth: (" + r + ") " + input);
}

////////////////
// showSubMenu
////////////////
function showSubMenu(menu)
{
	var sub1 = DOpus.NewVector();
	var sub2 = DOpus.NewVector();
	var r;

	var dlg = DOpus.Dlg;
	dlg.window = DOpus.Listers(0);
	dlg.choices = sub1;
	dlg.menu = sub2;

	switch (menu)
	{
	case "ask_src_dest": 					// return 1 for src, 2 for dest, 0 fail
		var src = "Source";
		var dest = "Destination";
		
		var dual = DOpus.Listers(0).dual;
		if (cmd.sourcetab.right)
		{
			switch (dual)
			{	
			case 1:
				src = "(Right)  " + src;
				dest = "(Left)  " + dest; break;
			case 2:
				src = "(Bottom)  " + src;
				dest = "(Top)  " + dest; break;
			}
		}
		else
		{
			switch (dual)
			{		
			case 1:
				src = "(Left)  " + src;
				dest = "(Right)  " + dest; break;
			case 2:
				src = "(Top)  " + src;
				dest = "(Bottom)  " + dest; break;
			}
		}
		
		sub1.push_back(src);
		sub2.push_back(0);
		sub1.push_back(dest);
		sub2.push_back(0);
		return dlg.Show();
	}
	return 0;
}

//////////////////
// truncatePath
//////////////////
function truncatePath(path, width)
{	// truncate to length of width
	if (path == "-") return path;
	if (path.length < width) return path;

	var slash_pos = path.lastIndexOf("\\");
	var last_folder = path.substr(slash_pos, path.length - slash_pos);
	var remainder = width - last_folder.length - 3;  // -3 for ...
	return path.substr(0, remainder) + "..." + last_folder;
}

//function soundOnError() {cmd.RunCommand("Play \"" + soundFile + "\" QUIET");}
function d2b(d) {return d.toString(2);} 	// decimal to binary
function pad(n, z) {return Array(Math.max(z - String(n).length + 1, 0)).join(0) + n;}
function lcase(s) {return String.prototype.toLowerCase.apply(s);}
function trim(s) {return s.replace(/^\s+|\s+$/g,"");}
function d(o) {d(o, false);}
function d(o, override) {if(debug || override) DOpus.Output(o);}

/* dspOptions bit flags

0x01 (01)	debug
0x02 (02)	clearOutput
0x04 (04)	0=Src, 1=Dest
0x08 (08)	Ask
0x10 (16)	jumpListIndicator

*/

I will be replying on every script update. Since editing the original post does not reflect changes at the forum home page (timestamp, etc), replying does. :slight_smile:

Updated to 2.1

I just found out the script (v2.1) has trouble runnin' on windows 7 (at least for me).
The fix until the next script update is to delete all 4 occurances of...

.toLowerCase()

example:
if (line.toLowerCase() == srcPath.toLowerCase())
to
if (line == srcPath)

Then the upper/lowercase would all have to be correct in the config file to match your actual folders.

Hi,

Not sure if i'm being thick, but i can't see a explanation of what exactly this script does. As a layman looking at this I have no idea really what it does.

Can you add a description or similar please.

thanks

The link in the overview section of the first post leads to a description.

Updated to 2.2

Sorry for delay...

@yonder Do you still have the latest v2.2 zip file? For some reason it is not on the forum server, nor in any backups.

I've reuploaded, thanks.

Many thanks!