Tagger3 for DOpus12

Many thanks to abr for participating in the development of Tagger. Many features are based on his testing, feedback and suggestions.

This new version requires at least DOpus v.12.2.3 to work. There's an older Version for DOpus 11 here.

Short description:
Tagger is a Script Add-In for Directory Opus that provides a resizable dialog. DOpus will remember size and position of the dialog.
The purpose of Tagger is to comfortably show, find, edit, replace, add or delete Tags or Comment and Rating for files and folders. When you start Tagger the tags, comments and ratings of all files in the current folder are read and stored in a dictionary for performance reasons. So if you are in a folder with a lot of files it may take a few seconds until the dialog appears.
The dialog shows all tags or the comment of a single file in a list where you can directly edit each entry.
You can also select a range of files. Tagger will then show tags or comment and rating if they exist in all selected files.
You can search for a certain tag, a rating value (0-5) or for comments containing a certain string by entering the search string in the main input field and pressing the hotkey alt+f. Tagger will select all files containing the specified tag, comment or rating and show the shared string in the list or in the rating input field. For comment Tagger will show all comments containing the search string in the list and the index of the file that contains the comment in a second column.
You can sort all tags in all files in the current folder alphabetically by pressing the hotkey alt+s.
You can always edit tags or comment in the list, change rating or add/replace/delete tags or comment for each selected file or folder using the "Apply" or "Remove" button.


  • Download the file Command.File_Tagger.vbs.txt and copy it to /dopusdata/Script AddIns or drag it into the settings window Settings => Preferences => Toolbar => Scripts
Script Configuration:
  • Go to Settings => Preferences => Toolbar => Scripts. Click the entry Command.File: Tagger.
  • Language: Select the language in which you want to show the dialog. Currently available are english, deutsch and français. "default" shows the dialog in the current language of DOpus if available, otherwise in english.
  • ShowIndexColumn: By default Tagger always shows the column "Index". If you don't want this change this option to "False".
  • Hot_[x]: You can change the default hotkeys here. See the discription of each hotkey at the bottom of the script configuration window.
  • vHot_[x]: These hotkeys are only available when working with the standalone viewer (Argument VIEWER). Nearly all default hotkeys of the viewer are also available from the Tagger GUI. Several of the original hotkeys needed to be modified by an additional modifier key. Download the file TaggerHotkeys.txt for a complete list of supported hotkeys.
  • MyHotkey: You can specify a user defined hotkey like "alt+v" here.
  • MyCommand: Specify the command the hotkey "MyHotkey" will execute.

Create and configure a button or hotkey:

  • Create a button or hotkey with the command Tagger. If you want to start Tagger in Comment mode press the modifier key Strg on the keyboard when you click the button (not working if Tagger is called by an embedded command).
  • You can add several arguments:
  • APP: provide path and command line options of an application to open the selected file. Example for Foobar2000: APP="/programfilesx86\foobar2000\foobar2000.exe /immediate"
  • CLOSEAPP: together with the Argument VIEWER this will close the standalone viewer together with Tagger. For other applications you can provide a command to close the application. Example for Foobar2000: CLOSEAPP="/programfilesx86\foobar2000\foobar2000.exe /exit"
  • CONFIRMDELETE: show a confirmation dialog when deleting Tags or comments.
  • FILTER: apply a filter if you want to work work with certain file types only. Other files will be hidden. Examples : FILTER=*.(jpg|png) or FILTER=grp:images
  • NOFOLDERS: hide folders. If you use the argument VIEWER you don't need to provide this argument because folders are always hidden (the standalone viewer doesn't like folders). If this argument was provided and a single folder is selected at start, Tagger will open this folder and select the first file.
  • OPACITY: make the dialog transparent (0= fully transparent, 255 = opaque). This is especially useful when you're working with the standalone viewer.
  • READONLY: apply this argument if you only want to watch the metadata of the files and prevent to make any changes to the files. Several dialog controls will be disabled in this mode.
  • VIEWER: if you want to use the standalone viewer use this argument for a button in the toolbar of the viewer. If you want to start Tagger from a lister toolbar you'll have to start the viewer first and start Tagger with an embedded command like this:

The dialog and it's controls:

  • List: in the listview control you'll see the tags or the comment of the currently selected file. Above the listview control you'll see the count of existing tags. If you select more than one file the list will only show tags or comment if they exist in all selected files. You can inline rename each entry and the changes will be written to the files. If you delete all characters from an entry the tag or comment will be deleted. Doubleclick a listview item to copy it to the main input.
  • Name field: if only one file is currently selected this field will show the index and the name of the file. Otherwise it will only show how many files are currently selected. In some situations you may see a notification here.
  • Main input: write tags or comment you want to apply to all selected files using the "Apply" button here. For tags you can enter any semicolon-separated string according to the rules documented in Keywords for SetAttr META. You can also use the main input for the Find feature of Tagger: Enter a string representing a tag and press the hotkey alt+f to find and select all files containing this tag ("+" or "-" at the beginning and ";" at the end of the string will be ignored). In comment mode Tagger will find all files with a comment containing the searchstring and show all these comments in the list. In a second column of the listview control the index of the file containing the comment will be shown. If you enter a number between 0 and 5 Tagger will find all files rated with this value. If you want to find all files rated 3,4 or 5 enter "3,4,5".
  • Lock checkbox: by default, the main input will be cleared when the Apply or Remove button was clicked. Enable the checkbox to preserve the content of the main input. This can be useful to collect tags from several files using the "doubleclick listview item" feature and afterwards write them to others. The hotkey alt+l toggles the state of the checkbox.
  • Combobox1: select Tags or Comment mode. The hotkey alt+m toggles this control.
  • Combobox2: choose the behaviour of Tagger when the Apply or Remove button was clicked: arrow down: select next file arrow up: select previous file square: stay here
  • Button "C" (Copy): click this button to copy all tags or the comment shown in the list to the main input. Hotkey: alt+c
  • Rating input: provides a scrollable list of rating values 0-5. If more than one file is selected this control will only show a value if all files have the same rating value. Otherwise it will be empty. If you change the value of this control, the rating value will always be written to the selected files when you click the Apply or Remove button. Hotkeys: alt+[0-5] or alt+[NUM0-NUM5].
  • Range input: this control will always show the index or range of the selected files. You can enter a index or range to select files. If you delete the content of the input field Tagger will select the last single selected file. Tagger will also select the last single file if several files are selected and you click the Next or Previous button or the Apply or Remove button according to the setting of Combobox2.
  • Next Button (arrow down): select the next single file without writing anything to selected files. Hotkeys: alt++ and alt+NUM+
  • Previous Button (arrow up): select the previous single file without writing anything to selected files. Hotkey: alt+- and alt+NUM-
  • Apply button: apply tags or comment written to the main input and rating written to the rating input to all selected files. If the main input is empty or just "+" or "-" nothing new will be written to the files but if you are in Tags mode and a single file is selected the tags of the file will be alphabetically sorted and rewritten to the file. Hotkey: alt+a
  • Remove button: the Remove button will delete all tags or the comment of all selected files if no items are selected in the list. Otherwise the button will only delete the selected items from all selected files. Hotkey: alt+d

Other features:
Some features are only available by pressing a hotkey on the keyboard:

  • Find (alt+f):. see short description and description of the main input dialog control.
  • Sort (alt+s): this will rewrite the tags of all files in the source folder alphabetically sorted. Since this needs some time for many files you'll see a notification in the name field until all files are written.
  • Refresh (alt+F5): Tagger will notice if the sourcepath from which it was started or the number of files in the folder has changed and automatically refresh the dictionary in which the informations about all files are stored. You will be notified about this event in the name field. However, not all possible changes are detected by Tagger. If you made changes to the files outside of Tagger (replace files, manually write tags to files) you should use this hotkey to refresh Tagger. Otherwise Tagger may show false information about existing tags.
  • TaggerFocus: Tagger will move the focus from the viewer window to the Tagger GUI when the global Variable TaggerFocus exists. To use this feature create a viewer hotkey with this command:
    @set glob!:TaggerFocus = True
    Currently DOpus can't move the focus from the Tagger GUI to the viewer but you can use the command line tool nircmd.exe and MyHotkey/MyCommand described above to do this. To toggle the focus from Tagger to the viewer window MyCommand would be:
    [path to]nircmd.exe win activate stitle "Tagger - "
    Apply the same hotkey like "alt+v" to the viewer hotkey and MyHotkey to get a hotkey that toggles the focus between Tagger GUI and viewer window.

I'm not sure if my french translation is good because I'm not good in french. Please shout if something should be changed.
If you want to have Tagger in your own language feel free to download the provided text file LanguageStrings.txt, translate the strings and upload your translation here. I'll be glad to add new languages.
Tagger_Hotkeys.txt (2.07 KB)
Command.File_Tagger.vbs.txt (155 KB)
LanguageStrings.txt (1.06 KB)



  • Tagger v3.0 published.

26.11.2016: Update to v3.1:

  • Bugfix: if the arguments VIEWER and CLOSEAPP where applied and another instance of the viewer got the focus Tagger was closed although the parent viewer window still existed.
  • New feature: Tagger will now get notified if the currently shown image in the standalone viewer has changed and select the new image when the dialog gets the focus again.

29.11.2016: Update to v3.2:

  • Tagger now follows the selection in the viewer in realtime with a 300ms delay.
  • Tagger and it's parent viewer window are now working correctly with FlatView.
  • Some changes to avoid script errors when a bad button code with the argument VIEWER was used. For example if you use Tagger VIEWER from a button in a lister toolbar without starting Tagger "embedded" (enclosed in square brackets) or without starting a viewer instance first you'll no longer get a script error. If a viewer window exists Tagger will close that window and behave as if the argument VIEWER wasn't given.

09.12.2016: Update to v3.3:

  • Bugfix: Tagger is no longer steeling the focus when you change the currently displayed image from the viewer window.
  • Nearly all default hotkeys of the standalone viewer are also available from the Tagger GUI now. Several hotkeys needed to be modified with an additional modifier key. Download the file "TaggerHotkeys.txt" from the first post for a complete list of supported hotkeys.
  • Added "Myhotkey" and "MyCommand" to the script configuration. You can specify your own hotkey that executes a user defined command with these options.
  • To toggle the focus from the viewer to the Tagger GUI you can now create a new viewer hotkey that creates a global variable named "TaggerFocus". Tagger will detect this variable and move the focus to it's main input field. The command for the viewer hotkey is: @set glob!:TaggerFocus = True
  • Updated the first post to describe the new features. Below "Other features" there's also a description how to create a hotkey that toggles the focus between Viewer window and Tagger GUI using "TaggerFocus", "MyHotkey/MyCommand" and the command line tool "nircmd.exe".
1 Like

An interesting piece of work! o)

I just tested this in fullscreen viewer mode (with the button code you provided) and it stays in place nicely and the navigation works quite good from the Tagger GUI itself too. Is there still some kind of Autohotkey magic involved here or is this all plain DO scripting? Unfortunately I did not find the time to play with the new scripting and dialog toolbox in DO12, so I cannot tell things apart correctly yet. o)

I wonder if the Tagger GUI could sync with the image currently displayed? So control of next/previous image is on the viewer. I'm still not much into tagging things, but you seem to prove that if you throw all the DO12 scripting goodness together, amazing addons can be done. Very nice! o)

Thanks for your feedback.

It's pure DO magic. :smiley:

Interesting question. There is an OnViewerEvent that could probably be involved to make this possible.
The downside of navigating with the viewer is that Tagger would loose focus and there's currently no way to toggle the focus between dialog and viewer by script or hotkey. However, it would be nice if Tagger would follow when the currently displayed image in the viewer was changed.

Concerning Autohotkey, i'm glad that it works without it now. No problem anymore, for example, to start somewhere in the middle of the folders images. In the old version, i had to start from the file number 1, skipping through, if i wanten to edit image no. 30, & it's also much more responsive.

The transparency is great, because otherwise details would be obscured. Thx, kundal :thumbsup: ! I have some wish list, to make the Tagger even more independent, but you have already requested parts of it, like being also able to switch between the image & the script's input field (for the standard meta editor it was recently added, thanks for that, too, GP!. After i had requested that, Kundal took up the work again on the Tagger, which wasn't functional for me some time ago, with DO12, but i still use the meta editor for small edits). In the meantime i keep using my two macros, to achieve the switching between the image (including setting it to original size, because usually there are lots of small details), & going back to the input field.

I also like the copy function, which is included, as well as the possibility to click-select parts of the list for further processing.

Update to v3.1: see second post of this thread for changes.

@tbone: Tagger will now be notified when the current image in the viewer was changed and select the new image. That doesn't mean that control of next/previous image is on the viewer and Tagger will immediately show the change because the dialog can't update until it gets back the focus.

Thanks Kundal, I tried but.. o)

27.11.2016 12:18 Tagger:  Error at line 216, position 9
 27.11.2016 12:18 Tagger:  A method was called unexpectedly (0x8000ffff)

That line looks strange to me?!

data.Func.viewer.Command(cmd.RunCommand("Show LISTSIBLINGS USEEXISTING " & """" & lastFile & """"))

If run twice, the second time it takes some time for the viewer to appear, but there is no Tagger window at all.

I can't reproduce that error here. Probably something in your button code?
This kind of error will appear if the viewer window doesn't exist. If you're using the button code with the embedded command it may be some timing problem because the viewer doesn't seem to be ready when Tagger calls this line. Does the error also appear when you start Tagger from a button in the toolbar of the viewer?
Please describe the exact steps to reproduce it.

Line 216 is only used at the start of Tagger. I need this to generate the next/prev list of the viewer.
The data.Func.viewer.Command part is needed to make sure the Show command comes from the parent viewer of Tagger. There is no VIEWERCMD=listsiblings argument I could use so I have to use Show LISTSIBLINGS to generate the next/prev list.

I did not change the code in the button since my first encounter with T3.
I used the code you provided above (with the embedded command). I simply select some images and run the button.

Line 216 still looks suspicous to me. According to the docs, data.func.viewer.command accepts a string to run or an DO.Command object, what you pass looks like just the return code of cmd.RunCommand(), so unless I overlooked something, this probably does not work as expected/intended?!
Extract from the docs for "Viewer.Command":

Runs a command in the context of this viewer window. You can either pass a command string (e.g. Command(“Show VIEWERCMD=next”) or a Command object.

The example you gave is not correct and wouldn't work. To open the next image in the viewer it has to be Command("next") because if the argument is a string it's always an argument of VIEWERCMD. To run anything else you'll have to provide a Command object which is in my case data.Func.Command.RunCommand():[quote]If the argument you pass is a string then it can only be a viewer command argument as documented for the Show VIEWERCMD command. For example, Command(“next”) would run the Show VIEWERCMD=next command in the context of this viewer.
If you pass a Command object then all commands (internal or external) can be used.
[/quote]I'm also using the same button code (except the Filter grp:images is grp:Bilder in german) and everything is working as expected here so I don't think there's something wrong with that line.

It seems Tagger is not started "embedded" (which means from the viewer as parent window) for you because I'll get a similar error with line 216 when I delete the squared brackets from the button code. Please check your button code again.

Hu,what example did I give? o)
Button still looks like this:


Regarding line 216:

data.Func.Command.RunCommand() is not and will not return a command object, it will return an integer as input to viewer.Command().

data.Func.viewer.Command(cmd.RunCommand("Show LISTSIBLINGS USEEXISTING " & """" & lastFile & """"))

From my perspective it should like this to pass the command object to viewer.Command():
data.Func.viewer.Command(cmd) No? I really don't want to argue and maybe there is some magic involved I don't know yet. o)

I think the command you run "Show LISTSIBLINGS.. " will be run in the context of "cmd", not "viewer.command". The latter only receives the result of cmd.RunCommand("Show LISTSIBSLING.."), which is 1 or 0 and might not be what you expect to happen.

Try changing the line to cmd.RunCommand("Show LISTSIBLINGS USEEXISTING " & """" & lastFile & """"). Does this prevent the error? It doesn't seem to change anything here.

I tried some other ways and the one you suggested, but still no worky worky. o)
If I run the "Tagger" command separately, it also takes several seconds for the dialog to come up, this wasn't the case in the first version.

Maybe Leo/Jon can shed some light onto the viewer.command object? Does it run commands the moment you pass a string/cmd-object to it or does it need an additional viewer.command.Run() call to execute the command string/object passed? It's not very clear to me how this should work, the naming does not suggest it executes things right away at least.

It may take some seconds until the dialog appears because tags, comment and rating of all files in the current folder are read to a dictionary so it depends on the number of files in the folder and the speed of your machine.

Please create a button in the toolbar of the viewer with only the line Tagger VIEWER FILTER=grp:images CLOSEAPP CONFIRMDELETE OPACITY=180 and try if it's working when you start Tagger from within the viewer window. Starting Tagger with the VIEWER argument from a lister toolbar is a special case that depends on the embedded command thing working correctly.

It'll run the inner cmd.RunCommand(...) part first, then pass the result of that (a number) to viewer.Command(...) which will do nothing with it at all, since it's not a valid viewer command. So it won't hurt, but cmd.RunCommand(...) is all you need.

Thanks for explaining this. However, I'll have to change the line anyway because the generated next/prev list doesn't work in Flatview.

@tbone: please change line 216 to this: data.Func.viewer.Command("open," & lastFile)
and change line 641 (or 637, I made a silent update where I deleted 4 lines. It's the line after "If arg.got_arg.viewer = True Then") to this: data.Func.viewer.Command("open," & file)
With these changes Tagger works correctly in flatview. Does it also work with your embedded command?

Thanks for confirming what I thought about that line. Can you also please tell us if the viewer.command() method runs things immediately or is there some additional step required (when passing a command object e.g.)? As mentioned, I think neither the naming nor the docs really suggest what happens here.

I did! Now it works, thank you. o)
I tried skipping through the images with the viewer to see how the GUI behaves, it updates now once you give it focus again. I think that's how you described the new behaviour. We are getting closer with this I think. I had a look into the viewer events and since you already make use of them, you could add a timer to the GUI to update every half a second or so and let it sync with the image currently in the viewer. To prevent some kind of loop if you trigger "next" from the GUI, stop the timer, make the viewer change the image, restart the timer and only update the Tagger GUI whenever the item in the viewer is different from the one the Tagger GUI shows. What do you think? o)

It actually runs the command asynchronously (in the context of the viewer) - the Command() method itself will return immediately.

Interesting and important "async" detail, thanks! Should really be added to the documentation! o) Still unsure about the case where a Command object will be passed. Is it comparable to invoking Run() on the command object directly and just source/target tabs and modifiers will be overriden?

The timer thing really works and would be easy to implement. The problem with this is that navigating with the viewer GUI currently doesn't work in FlatView. Another problem that occurs with the fix I provided for you is that images will not be automatically EXIF-rotated when opened with data.Func.viewer.Command("open," & file) and rotating them manually afterwards is a pain. I already reported both issues.
At the moment I'd like to stay with the Show command hoping that the Flatview issue will be fixed soon because I don't have a satisfying workaround for the rotate issue.

I still not understand why cmd.RunCommand("Show LISTSIBLINGS USEEXISTING " & """" & lastFile & """") throws an error for you because it's a simple Show command that should work even if the embedded Tagger command doesn't work correctly. abr also never reported a problem with this. What's the error message you get with this? I'm sure the "A method was called unexpectedly" came from the "data.Func.viewer.Command" part of the line and shouldn't appear with this version.
Would be nice if we could find out what's different for you. Sometimes it makes a difference when you change the order of arguments: cmd.RunCommand("Show " & """" & lastFile & """" & " USEEXISTING LISTSIBLINGS").
I also looked into the preferences settings for the viewer but can't think of a setting that could cause this.