GP SoftwareTwitter
Opus FAQsManualCommandsObjects

Command: Go-Relative (go to next/prev sibling folder)


#1

PHPBB_IMPORT_WARNING CODE_NEAR_LI

[ul][li]Overview:

This script adds a GoRelative command.

[ul][li]GoRelative SIBLING=next will jump you directly to the next sibling of the current folder.

In other words, it is like going up one level, selecting the next (or previous) folder to where you were, then entering it. Or like pushing the up or down cursor key on the folder tree.

[/li]
[li]GoRelative SIBLING=prev jumps to the previous sibling folder.

[/li]
[li]Add the WRAP argument to loop back to the first folder when you reach the last one (or vice versa), instead of stopping at the ends.

[/li]
[li]Add the SKIPHIDDEN argument to skip over hidden folders.

[/li]
[li]Folders that you cannot access are skipped automatically. (e.g. So you don’t get error messages when cycling through folders below C:.)

[/li]
[li]More modes may be added in the future.[/li][/ul]

[/li]
[li]Installation:

[ul][li]Download Go_to_Relative.vbs.txt and drag it to Preferences / Toolbars / Scripts.

Go_to_Relative.vbs.txt (4.5 KB)
[/li]
[li]With the script installed, you can create toolbar buttons or hotkeys which use the GoRelative command, as described in the overview section above.

[/li]
[li]Here are two pre-made buttons you can drag to a toolbar:

Previous Sibling.dcf (278 Bytes)
Next Sibling.dcf (277 Bytes)[/li][/ul]

[/li]
[li]History:

[ul][li]1.1 (15/May/2015): No longer skips empty folders.[/li]
[li]1.0 (11/May/2015): Initial version.[/li][/ul]

[/li]
[li]Limitations:

[ul][li]It decides the next or previous folder by listing the parent’s folders in alphabetical order.

[/li]
[li]Only real paths are currently used, not virtual paths or localised names.

If you are in the Desktop virtual folder, the script will act as if you are below C:\Users<username>\Desktop instead, and cycle through the folders below C:\Users<username>.

Similarly, if you are in a library, the script will act as if you are below the library’s real path.

With localised names, the order you visit directories may not match the order you’re used to seeing; for example, the My Documents folder is really called Documents behind the scenes, so it will appear earlier in the cycle than you might expect, if you have Opus configured to use localised names.

[/li]
[li]Doesn’t currently do anything at the root of a drive. It might cycle through drive letters in the future.

[/li]
[li]May only currently consider the first ~65000 siblings. (This limitation may no longer apply, although the script will be very slow with that many folders to work through anyway.)[/li][/ul]

[/li]
[li]Script code:

The script code from the download above is reproduced below. This is for people browsing the forum for scripting techniques. You do not need to care about this code if you just want to use the script.

[code]option explicit

’ Go to Relative
’ © 2015 Leo Davidson

’ This is a script for Directory Opus.
’ See http://www.gpsoft.com.au/DScripts/redirect.asp?page=scripts for development information.

’ Called by Directory Opus to initialize the script
Function OnInit(initData)
initData.name = "Go to Relative"
initData.desc = "Adds command to navigate to sibling folders."
initData.copyright = "© 2015 Leo Davidson"
initData.version = "1.1"
initData.default_enable = true

Dim cmd

Set cmd = initData.AddCommand
cmd.name = "GoRelative"
cmd.method = "OnGoRelative"
cmd.desc = "Go to the next or previous sibling of the current folder."
cmd.label = "GoRelative"
cmd.template = "SIBLING/K[next,prev],WRAP/S,SKIPHIDDEN/S"

End Function

’ Implement the GoRelative command
Function OnGoRelative(scriptCmdData)

' Check arguments to see what we've been asked to do.

If (scriptCmdData.Func.args.got_arg.SIBLING) Then
	OnGoSibling(scriptCmdData)
End If

' Other modes may be added here in the future.

End Function

Function OnGoSibling(scriptCmdData)

' Check arguments to see if we're going to the next or previous sibling.

Dim modeString, fNext, fWrap, fSkipHidden

modeString = UCase(scriptCmdData.Func.args.SIBLING)
If (modeString = "NEXT") Then
	fNext = True
ElseIf (modeString = "PREV" Or modeString = "PREVIOUS") Then
	fNext = False
Else
	DOpus.Output "GoRelative: SIBLING argument used with invalid parameter """ & modeString & """.", True
	Exit Function
End If

fWrap = scriptCmdData.Func.args.got_arg.WRAP
fSkipHidden = scriptCmdData.Func.args.got_arg.SKIPHIDDEN

' Get the parent folder, resolving aliases like /desktop while we're at it.

Dim pathParent, stringCurrentPath
Set pathParent = DOpus.FSUtil.Resolve(scriptCmdData.Func.sourcetab.path)
stringCurrentPath = pathParent

If (Not pathParent.test_parent) Then
	' If we're on a drive letter, find the next/prev drive.

	Dim driveNum
	driveNum = CInt(pathParent.drive)

	If (driveNum = 0) Then
		' No parent, and not a drive letter, so we give up.
		Exit Function
	End If
	
	' TODO: Hopping between drives not implemented yet.
Else
	pathParent.Parent

	' List the sibling folders, then sort the list.

	Dim vecSiblings, folderEnum, folderItem, folderError
	Set vecSiblings = DOpus.Create.Vector
	Set folderEnum = DOpus.FSUtil.ReadDir(pathParent, False)

	If (CLng(folderEnum.error) <> 0) Then
		DOpus.Output "GoRelative: Error " & CLng(folderEnum.error) & " reading folder """ & pathParent & """.", True
		Exit Function
	End If

	Do While (Not folderEnum.complete)
		Set folderItem = folderEnum.Next
		
		If (folderItem.is_dir) Then
			vecSiblings.push_back(folderItem)
		End If
	Loop

	vecSiblings.sort

	' Find the current folder in the list.
	
	Dim curIdx, origIdx, total, fFound
	curIdx = CLng(0)
	total = CLng(vecSiblings.count)
	fFound = False

	Do While (curIdx < total)
		If (vecSiblings(curIdx) = stringCurrentPath) Then
			fFound = True
			Exit Do
		End If
		curIdx = curIdx + CLng(1)
	Loop
	
	If (Not fFound) Then
		Exit Function
	End If

	origIdx = curIdx

	Do While (True)
		If (fNext) Then
			curIdx = curIdx + CLng(1)
			If (curIdx = total) Then
				If (Not fWrap) Then
					Exit Function
				End If
				curIdx = CLng(0)
			End If
		Else
			If (curIdx = CLng(0)) Then
				If (Not fWrap) Then
					Exit Function
				End If
				curIdx = total - CLng(1)
			Else
				curIdx = curIdx - CLng(1)
			End If
		End If

		If (origIdx = curIdx) Then
			Exit Function ' We could not find another folder to go to.
		End If

		' Test we can access the folder, and skip it if not.
		Set folderEnum = DOpus.FSUtil.ReadDir(vecSiblings(curIdx), False)
		' If error is non-zero but complete is not set, it means we can read the dir
		' but may be unable to get information about some of its children, which is fine.
		
		folderError = CLng(folderEnum.error)
		
		' Error 18 is ERROR_NO_MORE_FILES which just means the folder is empty.
		If (folderError = CLng(0) Or folderError = CLng(18) Or Not folderEnum.complete) Then

			If (Not fSkipHidden) Then
				Exit Do ' This is the folder we want.
			End If

			' Check if the folder is hidden and skip it if it is.

			If ((vecSiblings(curIdx).attr And 2) = 0) Then
				Exit Do
			End If
		End If
	Loop
	
	scriptCmdData.func.command.RunCommand "Go PATH=""" & vecSiblings(curIdx) & """"
End If

End Function[/code][/li][/ul]


Select Next or Previous folder
Multi-line file display toolbar with address on a dedicated line
#2

Wtf? It’s unusable with that limitation! o)

It does not enter empty folders though, as the readdirs() returncode is 18 or something for them iirc. Maybe another option “SKIPEMPTY” makes sense, to make this behaviour more determined?

Anyway, this one is perfect for ctrl-doubleclicking the listers background (+shift = previous e.g.), to have it “nearby” the regular Go BACK/UP by mouse (I think). Thanks for doing this, I tried… and it works real’ good. o)


#3

Thank you very much, Leo. I had never thought about such a button, but once I had added it and started working, I immediately realised how much fiddling about it eliminated for me. I now have two beaut new hotkeys, one for “Next Sibling” and one for “Previous Sibling”.

As tbone also asks, could you possibly not skip empty directories — or else provide a “NoSkipEmpty” switch (or make this the default and provide a “SkipEmpty” switch). For example, at the start of each year, I automatically generate various empty directories, which I then populate during the year as things come in. I am finding the buttons’ behaviours confusing in this situation, because I don’t know which directories are still empty, and so I don’t know how many times to press the hotkey. I also can’t get to some still-empty directory that I am actually aiming for.


#4

@julianon
I have a GoEx command in the making, that combines some other GO-related things and adds SKIPEMPTY and WRAPASK to this beauty.
I started to create rather multifunctional commands recently, as I lose oversight of what’s in my script addins folder and because some of the contributions just don’t evolve once published. They sometimes serve more as an example than something that is under maintanance, don’t know what this one will end up though. If Leo is willing to improve it, you’re just spoilt for choice I guess. o)


#5

I installed the script and created a button using the GORELATIVE command. Since I am not as sharp as you guys, all I found when I used the button was script errors. Please add a button with the script download. Thanks!


#6

What were the errors?


#7

Root post updated to v1.1. No longer skips empty folders.

Added two sample buttons, too.


#8

Thanks Leo. No problems using the updated script and the two buttons. Very nice. :thumbsup:


#9

Thanks again, Leo, for the changed behaviour with empty directories — it’s perfect now as far as I am concerned. My brother has 65537 siblings, but I don’t, so that limitation doesn’t worry me.


#10

Leo’s GoRelative, with no more scripting, allows two further very simple buttons that navigate parallel directory structures. They are also proving very useful to me, and I thought it may be worth posting them.

I have some systems of parallel directories based on years. For example, in my records, the directory 2015 has subdirectories
Banking, BankingStatements, Super, Tax, . . . and so do the directories 2014, 2013, 2012, . . . When I am in 2015\Tax, I often want to go directly to the previous parallel directory 2014\Tax, or further back to 2013\Tax, and then return to 2015\Tax.

The following button use GoRelative to go to the next parallel directory:
@Set TheDirectory={SourcePath|NoPath}
Go Up
GoRelative Sibling=Next Wrap SkipHidden
Go {$TheDirectory}
and changing “Next” to “Prev” gives a button that goes to the previous parallel directory. The last line throws an error if there is no parallel directory. The buttons are easily adapted to any deeper parallel nesting.


#11

A very useful script, good work.


#12

Dopus and @leo strikes again!

I just came to the forums to look/ask for exactly this type of button.
You are making my life a living hell! Because with the direction windows is going it’s time to seriously think about moving on to linux, imho.

But how can I do that, when there is no DOPus on linux? Huh!!!???


#13

Very useful script Leo !

just found it, I will use it a lot.

@Julianon, I don’t have that kind of directory structure, but i have to say the idea is great and should prove very useful to many :wink:


#14

Nice. I was looking for something like that for some time, decided to search for it and found it.


#15

I’ve taken the dangerous liberty of adding some bells and whistles to leo’s script. Apologies, leo, in advance for my inevitable mistakes and misunderstandings. In particular, I’m not confident that I’ve understood the significance of all the checks in the code.

  1. I rewrote it in JScript because I don’t know VBScript, and renamed it from Go_to_Relative.vbs to GoRelative.js to avoid confusion with leo’s script.

  2. Drive-hopping is added. That is, if the script climbs to the root of a drive rather than a directory, then it will hop to the next or previous drive in alphabetical order.
    — This drivehopping ignores drives that are not ready, but otherwise does not distinguish between types of drives (one could easily add such code).
    — A new switch argument ChooseDrive of type /S triggers a dialogue for the user to choose the target drive, rather than have it chosen automatically.
    — Another new argument OmitDrives of type /K can avoid annoying things such as HP’s naming of their backup drive as D: drive. For example,
    OmitDrives=D:,M:,Z: (OmitDrives=D,M,Z and OmitDrives=D:,M:,Z:\ will also work).

  3. More significantly, a new argument Depth, of type /O, allows automatic navigation through parallel directory structures. By itself or with an invalid value, it triggers a dialogue, otherwise it should have a positive whole number as its value.
    — Depth=1 is the default if the Depth argument is not mentioned. This makes the script behave as before.
    — Depth=2 climbs two steps instead of one up and then down the directory tree. For example, suppose that there are two directories:
    …\Lessons\2016\Class09 AND …\Lessons\2017\Class09
    Suppose that one is working in the \Lessons\2017\Class09 directory, and wants to go to \Lessons\2016\Class09 to pick up something from last year’s directory. The following two buttons swap between them:
    GoRelative Depth=2 Sibling=Previous (or Sibling=-1)
    GoRelative Depth=2 Sibling=Next (or Sibling=1)
    — Depth=3 extends this climb one more step. Suppose that there are two directories:
    …\Lessons\2016\Class09\Quadratics AND
    …\Lessons\2017\Class09\Quadratics
    The following two buttons swap between them:
    GoRelative Sibling=Previous Depth=3
    GoRelative Sibling=Next Depth=3
    — And so on. Depth=4 would be for …Lessons\2016\Class09\Quadratics\Tests.

  4. For depths greater than 1, the tree-climbing may comes to a drive prematurely. In this situation, the climbing stops, and drive-hopping begins.

  5. Once the depth is greater than 1, the parallel target directory may not exist. When this happens, the script goes as far back down the target tree as far as it can, then issues a warning message.

  6. The Sibling argument is now of type /O. The chosen sibling may be 1, 2, 3, … away, which may be useful when the depth is greater than 1.
    — When the argument is absent (not recommended), it defaults to the Next sibling directory (or drive).
    — The argument Sibling can take any non-zero integer, where positive integers move forward that many items through the siblings, and negative numbers move backwards through the siblings.
    — The argument Sibling can also take, as it did before, the values Next (=1), Previous (=-1) or Prev, which move to the next or previous sibling.
    — By itself or with an invalid value, the argument Sibling triggers a dialogue.
    — The switch argument Wrap of type /S now uses modulo arithmetic in the obvious way.

In particular, the command GoRelative with no Sibling argument is the same as GoRelative Sibling=Next or GoRelative Sibling=1.

  1. The default is now to include hidden files, but exclude system files. These defaults can be changed with two switches of type /S:
    SkipHidden (unchanged) and IncludeSystem (new).

  2. In a DOpus thread a year or so ago, I posted a system using the keys F12, F11, F10 and F9, for opening directories in another tab, the other dual panel, or another single- or dual-panel lister. These methods now work consistently with the GoRelative commands.

I had already implemented, and posted above, a less elaborate version of ‘depth’ using leo’s unaltered script combined with ordinary DOpus commands. But the F12-F9 methods did not work consistently with these earlier ‘depth’ buttons, perhaps because of timing issues, and this was my original motivation for fiddling with leo’s script.

— A new switch UserDefinedGo, of type /S, now changes the final command from DOpus’ normal Go command to the user-defined command A@Go used in the F12–F9 system. Obviously, ignore this switch entirely unless the F12–F9 system is already installed and running.

[To recapitulate this system, before running the script:
Press F12 to open the new folder in a new tab.
Press F11 to open it in the dual panel.
Press F12 and F11 to open it in a new tab of the dual panel.
Press F10 to open it in a single-panel lister.
Press F9 to open it in a dual-panel lister.
See the earlier thread for the code to attach to F12-F9 and the corresponding menubar icons, where the hotkeys are arbitrary, or could be omitted.]


SOME EXAMPLE CODES FOR BUTTONS (WITHOUT THE SWITCH UserDefinedGo):
GoRelative Sibling=Next Wrap Depth=1 — Totally standard
GoRelative Sibling=Previous Depth ChooseDrive SkipHidden — Dialogues for the depth and the drive.
GoRelative Sibling Wrap Depth=2 OmitDrives=M:,Z: — Dialogue for the sibling, and Drives M: and Z: are omitted if drive-hopping is necessary.

INSTALLATION:
The file below is the adapted GoRelative.js script. I was not sure how to handle the copyright protocols, which may well need adjusting.

First, disable the old addon Go_to_Relative.vbs if it is installed, otherwise DOpus will have two conflicting commands GoRelative. The easiest way is to navigate to the addons directory and rename its extension to .vbsx — this is easily reversed in the event of blunders by me.

Download the new file GoRelative.js.txt below, open the scripts window by Preferences --> Toolbars --> Scripts, and drag the downloaded file to its right-hand panel.
GoRelative.js.txt (14.8 KB)