GP SoftwareTwitter
Opus FAQsManualCommandsObjects

Problems updating DOpus.viewers

While writing a script for the standalone viewer I ran into some problems. Here is a demo.

This script launches two images from the current tab:

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    cmd.deselect = false; // Prevent automatic deselection
    
    cmd.RunCommand('Close ALLVIEWERS');
    cmd.RunCommand('Show "' + tab.files(0) + '" POS=3120,0   SIZE=1200,960 NOUSEEXISTING');
    cmd.RunCommand('Show "' + tab.files(1) + '" POS=3120,960 SIZE=1200,960 NOUSEEXISTING');
}

Let's analyze the two viewers:

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    cmd.deselect = false; // Prevent automatic deselection

    // DOpus.viewers.Update();
    cmd.RunCommand('Set UTILITY=otherlog');
    DOpus.ClearOutput();
    DOpus.Output('DOpus.viewers.count: ' + DOpus.viewers.count);
    DOpus.Output('');

    for (var eViewer = new Enumerator(DOpus.viewers); !eViewer.atEnd(); eViewer.moveNext()) {
        var item = eViewer.item();
        DOpus.Output('item.parenttab.path' + ': "' + item.parenttab.path + '"');
        DOpus.Output('item.current' + ': "' + item.current + '"');
        DOpus.Output('item.index' + ': "' + item.index + '"');
        DOpus.Output('item.files.count' + ': "' + item.files.count + '"');
        DOpus.Output('item.title' + ': "' + item.title + '"');
        DOpus.Output('item.foreground' + ': "' + item.foreground + '"');
        DOpus.Output('item.lastactive' + ': "' + item.lastactive + '"');
        DOpus.Output('');
    }

    for (var i = 0; i < DOpus.viewers.count; i++) {
        DOpus.Output('DOpus.viewers(' + i + ').parenttab.path: "' + DOpus.viewers(i).parenttab.path + '"');
        DOpus.Output('DOpus.viewers(' + i + ').current: "' + DOpus.viewers(i).current + '"');
        DOpus.Output('DOpus.viewers(' + i + ').index: "' + DOpus.viewers(i).index + '"');
        DOpus.Output('DOpus.viewers(' + i + ').files.count: "' + DOpus.viewers(i).files.count + '"');
        DOpus.Output('DOpus.viewers(' + i + ').title: "' + DOpus.viewers(i).title + '"');
        DOpus.Output('DOpus.viewers(' + i + ').foreground: "' + DOpus.viewers(i).foreground + '"');
        DOpus.Output('DOpus.viewers(' + i + ').lastactive: "' + DOpus.viewers(i).lastactive + '"');
        DOpus.Output('');
    }
}

Everything's fine, the result might look like this:

DOpus.viewers.count: 2

item.parenttab.path: "D:\test\jpg"
item.current: "D:\test\jpg\0-file-2.jpg"
item.index: "0"
item.files.count: "1"
item.title: "undefined"
item.foreground: "false"
item.lastactive: "true"

item.parenttab.path: "D:\test\jpg"
item.current: "D:\test\jpg\0-file-1.jpg"
item.index: "0"
item.files.count: "1"
item.title: "undefined"
item.foreground: "false"
item.lastactive: "false"

DOpus.viewers(0).parenttab.path: "D:\test\jpg"
DOpus.viewers(0).current: "D:\test\jpg\0-file-2.jpg"
DOpus.viewers(0).index: "0"
DOpus.viewers(0).files.count: "1"
DOpus.viewers(0).title: "undefined"
DOpus.viewers(0).foreground: "false"
DOpus.viewers(0).lastactive: "true"

DOpus.viewers(1).parenttab.path: "D:\test\jpg"
DOpus.viewers(1).current: "D:\test\jpg\0-file-1.jpg"
DOpus.viewers(1).index: "0"
DOpus.viewers(1).files.count: "1"
DOpus.viewers(1).title: "undefined"
DOpus.viewers(1).foreground: "false"
DOpus.viewers(1).lastactive: "false"

We should be able to merge the two scripts and still get the same result, right?

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    cmd.deselect = false; // Prevent automatic deselection

    cmd.RunCommand('Close ALLVIEWERS');
    cmd.RunCommand('Show "' + tab.files(0) + '" POS=3120,0   SIZE=1200,960 NOUSEEXISTING');
    cmd.RunCommand('Show "' + tab.files(1) + '" POS=3120,960 SIZE=1200,960 NOUSEEXISTING');
    // DOpus.viewers.Update();

    cmd.RunCommand('Set UTILITY=otherlog');
    DOpus.ClearOutput();
    DOpus.Output('DOpus.viewers.count: ' + DOpus.viewers.count);
    DOpus.Output('');

    for (var eViewer = new Enumerator(DOpus.viewers); !eViewer.atEnd(); eViewer.moveNext()) {
        var item = eViewer.item();
        DOpus.Output('item.parenttab.path' + ': "' + item.parenttab.path + '"');
        DOpus.Output('item.current' + ': "' + item.current + '"');
        DOpus.Output('item.index' + ': "' + item.index + '"');
        DOpus.Output('item.files.count' + ': "' + item.files.count + '"');
        DOpus.Output('item.title' + ': "' + item.title + '"');
        DOpus.Output('item.foreground' + ': "' + item.foreground + '"');
        DOpus.Output('item.lastactive' + ': "' + item.lastactive + '"');
        DOpus.Output('');
    }

    for (var i = 0; i < DOpus.viewers.count; i++) {
        DOpus.Output('DOpus.viewers(' + i + ').parenttab.path: "' + DOpus.viewers(i).parenttab.path + '"');
        DOpus.Output('DOpus.viewers(' + i + ').current: "' + DOpus.viewers(i).current + '"');
        DOpus.Output('DOpus.viewers(' + i + ').index: "' + DOpus.viewers(i).index + '"');
        DOpus.Output('DOpus.viewers(' + i + ').files.count: "' + DOpus.viewers(i).files.count + '"');
        DOpus.Output('DOpus.viewers(' + i + ').title: "' + DOpus.viewers(i).title + '"');
        DOpus.Output('DOpus.viewers(' + i + ').foreground: "' + DOpus.viewers(i).foreground + '"');
        DOpus.Output('DOpus.viewers(' + i + ').lastactive: "' + DOpus.viewers(i).lastactive + '"');
        DOpus.Output('');
    }
}

Well, we don't. It looks like this:

DOpus.viewers.count: 2

item.parenttab.path: "undefined"
item.current: "undefined"
item.index: "0"
item.files.count: "0"
item.title: "undefined"
item.foreground: "false"
item.lastactive: "false"

item.parenttab.path: "undefined"
item.current: "D:\test\jpg\0-file-1.jpg"
item.index: "0"
item.files.count: "1"
item.title: "undefined"
item.foreground: "true"
item.lastactive: "true"

DOpus.viewers(0).parenttab.path: "undefined"
DOpus.viewers(0).current: "D:\test\jpg\0-file-2.jpg"
DOpus.viewers(0).index: "0"
DOpus.viewers(0).files.count: "0"
DOpus.viewers(0).title: "undefined"
DOpus.viewers(0).foreground: "true"
DOpus.viewers(0).lastactive: "true"

DOpus.viewers(1).parenttab.path: "undefined"
DOpus.viewers(1).current: "D:\test\jpg\0-file-1.jpg"
DOpus.viewers(1).index: "0"
DOpus.viewers(1).files.count: "1"
DOpus.viewers(1).title: "undefined"
DOpus.viewers(1).foreground: "false"
DOpus.viewers(1).lastactive: "false"

Ok... we can update lister objects with DOpus.listers.Update() (docs), so maybe DOpus.viewers.Update() works as well, although it's not mentioned in the docs.

Let's give it a try:

DOpus.viewers.count: 2

item.parenttab.path: "undefined"
item.current: "undefined"
item.index: "0"
item.files.count: "0"
item.title: "undefined"
item.foreground: "false"
item.lastactive: "false"

item.parenttab.path: "undefined"
item.current: "D:\test\jpg\0-file-1.jpg"
item.index: "0"
item.files.count: "1"
item.title: "undefined"
item.foreground: "true"
item.lastactive: "true"

DOpus.viewers(0).parenttab.path: "undefined"
DOpus.viewers(0).current: "D:\test\jpg\0-file-2.jpg"
DOpus.viewers(0).index: "0"
DOpus.viewers(0).files.count: "0"
DOpus.viewers(0).title: "undefined"
DOpus.viewers(0).foreground: "true"
DOpus.viewers(0).lastactive: "true"

DOpus.viewers(1).parenttab.path: "undefined"
DOpus.viewers(1).current: "D:\test\jpg\0-file-1.jpg"
DOpus.viewers(1).index: "0"
DOpus.viewers(1).files.count: "1"
DOpus.viewers(1).title: "undefined"
DOpus.viewers(1).foreground: "false"
DOpus.viewers(1).lastactive: "false"

A bit better, but still not completely correct.

Things I noticed while debugging:

  • The results would vary after a while.
  • The two enumerating methods sometimes delivered very different results.
  • Opus soft crashed a few times (I am sending the mini dumps via mail)
  • Occasionally the viewer stopped launching at all and Opus needed to be restarted.
  • Using the script from the viewer instead of lister toolbar seemed to produce better results.

LaunchViewers.dcf (1.1 KB)
ProbeViewers.dcf (3.7 KB)

MultiShow.dcf (4.1 KB)

I think what you're seeing is because opening and closing the viewers is asynchronous, and hasn't (completely) happened at the time the script queries the state of all open viewers.

Adding a DOpus.Delay(500); after running the commands, and before anything accesses DOpus.viewers, seems to fix things. That's not a full fix, of course, since you have no way of knowing how long you really need to wait.

Is the overall aim to get handles to the two viewers which are being opened? We could provide something like Results.newlisters for that, if it's what you need.

Adding a DOpus.Delay(500); seems to fix things.

Yes, it does :+1:

Is the overall aim to get handles to the two viewers which are being opened?

Yes, that is exactly what I wanted to do :slight_smile:

Makes sense!

We've made things more synchronized in the next update, so your original code will work. (At least for opening viewers. Haven't checked closing them yet.)

We've also added Command.Results.NewViewers so you can do things more easily (and not have to worry about the old, closed/closing viewers at all):

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    cmd.deselect = false; // Prevent automatic deselection

    cmd.AddLine('Close ALLVIEWERS');
    cmd.AddLine('Show "' + tab.files(0) + '" POS=3120,0   SIZE=1200,960 NOUSEEXISTING');
    cmd.AddLine('Show "' + tab.files(1) + '" POS=3120,960 SIZE=1200,960 NOUSEEXISTING');
	cmd.Run();
	var results = cmd.Results;

    cmd.RunCommand('Set UTILITY=otherlog');
    DOpus.ClearOutput();

	DOpus.Output('Viewer count = ' + results.newviewers.count);

    DOpus.Output('');

    for (var eViewer = new Enumerator(results.newviewers); !eViewer.atEnd(); eViewer.moveNext()) {
        var item = eViewer.item();
        DOpus.Output('item.parenttab.path' + ': "' + item.parenttab.path + '"');
        DOpus.Output('item.current' + ': "' + item.current + '"');
        DOpus.Output('item.index' + ': "' + item.index + '"');
        DOpus.Output('item.files.count' + ': "' + item.files.count + '"');
        DOpus.Output('item.title' + ': "' + item.title + '"');
        DOpus.Output('item.foreground' + ': "' + item.foreground + '"');
        DOpus.Output('item.lastactive' + ': "' + item.lastactive + '"');
        DOpus.Output('');
    }
}
1 Like

Additionally, DOpus.Viewers will no longer include viewers which have started closing.

Thanks! Very cool. I am impressed!

DOpus.Viewers will no longer include viewers which have started closing.

Ah yes... that explains why sometimes the viewer count was three. Got me really confused :crazy_face:

Some more notes:

When opening multiple viewers, you'll (probably) want to use AddLine/Run (like in my last example) instead of RunCommand (like in the originals) even if you aren't using the Results.NewViewers object. This is because we will let a command open multiple viewers in parallel, and then sync with them at the end of the command. So if you use RunCommand instead, you'll open one viewer, then wait for it to load, before moving on and opening the next viewer. (In the current version, it doesn't matter which you use, as we never sync with the viewers.)

We're also going to return the list of viewers in the same order they were opened, and make the same change for the NewListers and NewTabs lists. (At the moment, they returned things in an arbitrary order, which means you might need to go hunting for things more than you'd want to. Although your script should still be prepared for failures/timeouts causing there to be fewer results than expected.)

1 Like

The Results.NewViewers property and related fixes are now available in Directory Opus 12.17.6 (Beta)