Redo Operation Scripting Help

There are a many times where I have a folder with many various files and folders in them. I then want to organize it and going through each individual items, I would then either copy or move them to their organized folders such as:

E:\Desktop\Pictures\Japan
E:\Dekstop\Pictures\Switzerland
O:\Some\Other\Folder\Path

As such, there is a feature in another software that allows me to redo certain operations. It does it by tracking what operation I did (copy/move) and the destination. Therefore if I had previously moved files into the three example folders above, the feature would give me a popout list that allows me to select what recent operation to do and apply them to my currently selected files or folders regardless if they're not the same files or folders I had operated on previously into those folders.

I'm now trying to implement this by scripting it here in DOpus so that I can have this wonderful feature in both software. However I'm new to scripting here and I'm really confuse and stuck how to proceed with this. This is my current work so far:

// Redo Operation
// (c) 2017 Enternal

// Called by Directory Opus to initialize the script
function OnInit(initData)
{
	initData.name = "Redo Operation";
	initData.version = "0.0.1";
	initData.copyright = "(c) 2017 Enternal";
	//initData.url = "https://resource.dopus.com/";
	initData.desc = "Track copy/move operations and allow redo for other selected items";
	initData.default_enable = true;
	initData.min_version = "12.0";
}

// Called when a copy or move operation take place
function OnGetCopyQueueName(GetCopyQueueNameData)
{
	var reops_dest = GetCopyQueueNameData.dest;
	var reops_move = GetCopyQueueNameData.move;
	var reops_redo;
	DOpus.vars.Set("reops_redo", [[reops_move, reops_dest], [reops_redo]]);
	//DOpus.vars.Set("reops_redo").persist = false; //persist across session only instead of reboot?

	//https://resource.dopus.com/t/question-about-jscript-based-rename-script-syntax/10562/1
	//var Shell = new ActiveXObject("WScript.Shell");
	//Shell.Popup(reops_dest, 0, "Destination Path", 0x30);
	//DOpus.Output(reops_redo);
	//DOpus.Output(reops_redo[0]);
	//DOpus.Output(reops_redo[1]);

}

What I'm trying to do is have it automatically track (whenever there is a copy or move operation) and store whether it's a copy or a move operation and the destination into a DOpus global multidimensional array. Basically it will be a nx2 array. I will then use an additional button script that will then use that data to make a list of the recent operations while listing the most recent operation at the top by divided into groups whether it's a copy or a move operation. How should I proceed with this?

Secondly, how can I display the array into the Script Log window for testing purposes? I tried DOpus.Output (don't know how I can use it to display the values of DOpus.vars) and DOpus.vars.Get and some other random stuff. The manual is also confusing me haha.

Also, I'm using the OnGetCopyQueueName event and therefore the limitation of that is the Automatically manage file copy queues must be on otherwise it won't work right?

The last question I have is I remember reading somewhere that global variables are written to a file. This is what allows them to survive reboots. I tried looking around the only file I found was uservars.oxc. But that's not the file it seems. Where do DOpus store these reboot-proof variables?

Can you give me guidance on this? Thanks! Or... you could implement this feature into DOpus one day?

I'm sorry! I don't know how it happened but I wrote this in Help & Support but somehow a copy ended up in Script & Plugin Development as well! :open_mouth:

That was me. I moved the thread, but left a pointer in the old place as well.

I would really like some help here if possible...

Anyways my code is now:

// Redo Operation
// (c) 2017 Enternal

// Called by Directory Opus to initialize the script
function OnInit(initData)
{
    initData.name = "Redo Operation";
    initData.version = "0.0.1";
    initData.copyright = "(c) 2017 Enternal";
    //initData.url = "https://resource.dopus.com/";
    initData.desc = "Track copy/move operations and allow redo for other selected items";
    initData.default_enable = true;
    initData.min_version = "12.0";
}

// Called when a copy or move operation take place
function OnGetCopyQueueName(GetCopyQueueNameData)
{
    var reops_dest = GetCopyQueueNameData.dest;
    var reops_move = GetCopyQueueNameData.move;

    if (DOpus.Vars.Exists("reops_redo") == false) {
       DOpus.Output("reops_redo Does Not Exist. Creating reops_redo...");
       var reops_data = DOpus.Create.Vector();
    }
    else {
       var reops_data = DOpus.Vars.Get("reops_redo");
       DOpus.Output("reops_redo Existed, The Elements Are:");
       for (var i=0; i<reops_data.length; i++) {
          DOpus.Output("    Vector("+i+"): " +reops_data(i));
       }
    }

    reops_data.push_back = [reops_move, reops_dest];
    DOpus.Vars("reops_redo") = reops_data;
    DOpus.Vars("reops_redo").persist = true;

    //DOpus.Output("    Vector Persistency: " +DOpus.Vars("reops_redo").persist);
    //DOpus.Output("    Vector Length: " +reops_data.length);
    DOpus.Output("Results After Adding New Elements");
    for (var i=0; i<reops_data.length; i++) {
       DOpus.Output("    Vector("+i+"): " +reops_data(i));
    }
    var reops_data = DOpus.Vars.Get("reops_redo");
    DOpus.Output("reops_redo Right After DOpus.Vars... = reops_data:");
    for (var i=0; i<reops_data.length; i++) {
       DOpus.Output("    Vector("+i+"): " +reops_data(i));
    }

    DOpus.Output("");
    //DOpus.Vars.Delete("reops_redo");
}

But I'm running into an issue that I don't get. Run the code once above and you will get:

 1/18/2017 10:12 PM Redo Operation:  reops_redo Does Not Exist. Creating reops_redo...
 1/18/2017 10:12 PM Redo Operation:  Results After Adding New Elements
 1/18/2017 10:12 PM Redo Operation:      Vector(0): false,E:\New Folder
 1/18/2017 10:12 PM Redo Operation:  reops_redo Right After DOpus.Vars... = reops:
 1/18/2017 10:12 PM Redo Operation:      Vector(0): false,E:\New Folder
 1/18/2017 10:12 PM Redo Operation:  

That makes sense. the global DOpus variable reops_redo does not exist and thus it's created. After adding a new element into it, the results are displayed. The new vector is now saved into the DOpus global reops_redo. I then recheck to see if reops_redo have the correct data and it does.

Ran it the second time gave me:

 1/18/2017 10:12 PM Redo Operation:  reops_redo Existed, The Elements Are:
 1/18/2017 10:12 PM Redo Operation:      Vector(0): 
 1/18/2017 10:12 PM Redo Operation:  Results After Adding New Elements
 1/18/2017 10:12 PM Redo Operation:      Vector(0): 
 1/18/2017 10:12 PM Redo Operation:      Vector(1): false,E:\New Folder
 1/18/2017 10:12 PM Redo Operation:  reops_redo Right After DOpus.Vars... = reops:
 1/18/2017 10:12 PM Redo Operation:      Vector(0): 
 1/18/2017 10:12 PM Redo Operation:      Vector(1): false,E:\New Folder
 1/18/2017 10:12 PM Redo Operation:  

So reops_redo exist now that it was created during the 1st run which is what I expected. The content of it however is empty?! The length of it is correct though. Adding new element into it and the results are as expected except Vector(0) is empty which is not what I expected as I have said before.

Ran it the 3rd time gave me:

 1/18/2017 10:12 PM Redo Operation:  reops_redo Existed, The Elements Are:
 1/18/2017 10:12 PM Redo Operation:      Vector(0): 
 1/18/2017 10:12 PM Redo Operation:      Vector(1): 
 1/18/2017 10:12 PM Redo Operation:  Results After Adding New Elements
 1/18/2017 10:12 PM Redo Operation:      Vector(0): 
 1/18/2017 10:12 PM Redo Operation:      Vector(1): 
 1/18/2017 10:12 PM Redo Operation:      Vector(2): false,E:\New Folder
 1/18/2017 10:12 PM Redo Operation:  reops_redo Right After DOpus.Vars... = reops:
 1/18/2017 10:12 PM Redo Operation:      Vector(0): 
 1/18/2017 10:12 PM Redo Operation:      Vector(1): 
 1/18/2017 10:12 PM Redo Operation:      Vector(2): false,E:\New Folder
 1/18/2017 10:12 PM Redo Operation:  

So like before, for some reason the content of reops_redo is completely empty even though the length is correct. What's going on here? I found tbone's thread here Vector persistency issue and ran that code. That code ran perfectly fine. I actually simply copied and paste it directly into my code and it ran perfectly with the second time giving the correct results. Yet mine is not...

The popout list that you get from the command Undo LIST, are there other ways to make this type of dialog? Basically parse the destinations that I retrieve from the above code and then list them in just like that Undo LIST.

Ah I see the problem. The problem is it does not support nested vectors. So something like:

reops_data.push_back = [reops_move, reops_dest];is no good at all.

Are there any methods of making multi-dimensional arrays/vectors than? Guess no matrix support then?

Anyways, FINALLY. Some progress after so much time. I'm still new to scripting DOpus and would still love it if someone answers the few questions I had up there.

You can have vectors of vectors, I think.

This would not be the syntax, though:

reops_data.push_back = [reops_move, reops_dest];

If would be something like:

var vec1 = DOpus.Create.Vector();
vec1.push_back(reops_move);
vec1.push_back(reops_dest);

var vec2 = DOpus.Create.Vector();
vec2.push_back(vec1);

To output a vector to the script log window, you have to loop through it and output each element. (If the element itself is a nested vector, you would have to loop through that as well.)

It's best to ask one question per thread than put lots together, as it gets quite complicated to answer everything at once, and too difficult to keep track of what has and hasn't been answered as the thread goes on. That's one reason I had not replied yet. If I can answer a thread in 5 minutes while waiting for something, I'll answer it quickly as there are lots of 5 minute gaps through the day. If it takes 30 minutes to answer everything, it'll take longer for a reply as there are fewer 30 minute gaps, and I'd rather post a full answer later than give half an answer and then have to re-read a complex thread again later on to work out what was missed the first time. So 6 small threads will be answered faster, and easier for everyone to follow, than 1 thread with 6 questions interwoven into a single discussion, even thought the total time is still similar if all 6 replies are written at once.

Ah yes I tried that method before a while after my last post. It got a bit too complex than I wanted thought it gave me what I was looking for so I ended up going with something slightly different. Thank you though!

Ah I'm sorry. I keep falling for the trap since the questions are related to one main topic, I put them all in the same thread. I will spread them out then.

So the script is functionally done at the moment. I am going to clean it up further. So it would be nice if somebody here can try it out and see how it works. Also are there anything else I can do to make it better coding wise and optimizing it? I'm sure there are tons of bad coding practices so point them out but don't be too mean to a newbie... Anyways... wow that was a lot of painful moments coding this since I had no idea where to start. Anyways, at least it's finally functionally done after several days haha.

So to explain again what this script does... This script basically keep tracks of you all your copy and move destinations. You can then apply that same copy/move operations to other selected files. This is helpful a lot if you try to organize folders that have many many files that goes into various folders throughout the system. You could of course keep all those tabs for each of those folders open but it can get pretty messy if there are many many destinations and it could change all the time. The script will then give you a popout list with the most recent destination for an operation at the top. All duplicates are automatically taken care of. The script also comes with two configuration options that allows you to change the length of the history. By default it's set to remember 15 copy and move operations.
Redo_Operation.js.txt (9.06 KB)Redo Operations.dcf (895 Bytes)

If it all works well, I will do the final touches on it and then post the final version to the Script Buttons & Add-Ins sub-forum.

Got it now, Enternal, thanks! You were right on both things. With the queue options fully ticked, & the latter version, it looks much better now. I'm just starting testing. Cool!