Redo Operations - 0.1.0 (January 27, 2017)

Share script buttons and script add-ins to extend and modify Opus.
Enternal
Registered Opus Pro User
Posts: 84
Joined: 17 Feb 2016, 15:33
OS: Windows 7 64-bit
Opus: Latest Beta
Current Version
0.1.0 - January 27, 2017

Changes
0.1.0 - Changes since viewtopic.php?f=12&t=28677&p=156566#p156566
* Fixed bug where recent operations are added to the beginning of the list and then effectively deleted right after which simply rendered the script useless. This is because in the beginning I had recent operations appended to the programming variable but later changed it to have the recent operations inserted at the beginning of the variable but the code necessary to clean up duplicates and move items to the top did not reflect this change.

Description
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.

In Action
Redo Operations.gif
Redo Operations.gif (1.08 MiB) Viewed 626 times
Scenario explainations: I'm organizing the files in the folder and I move each of those items into folder Move 1, Move 2, and Move 3. For simplicity sake, I had all 3 folders in that single folder but imagine those 3 folders are in various places of the system. I then close pane 2. Pretend that I close down Opus and then went to lunch. Then I came back from lunch and then realized that I had a few more items I should clean up and sort. I simply selected the items that will go into folder Move 3, press the hotkey associated with displaying Recent Move Operations, select the destination I want them to go in, and voila! I'm done. no need to browse back to that folder to move those items in.

The Included Button:
Button.png
Button.png (6.66 KiB) Viewed 626 times

Recent Copy - will display the list of locations where a copy to operation was made will the script remember. Default hotkey is Ctrl + Shift + Z.
Recent Move - will display the list of locations where a move to operation was made will the script remember. Default hotkey is Ctrl + Shift + X.
Clear - Clear the history of both copy and move locations.

Options Available
CopyHistoryLength - Default is 15. Allows you to set how many locations where a copy to operation was made will the script remember.
MoveHistoryLength - Default is 15. Allows you to set how many locations where a move to operation was made will the script remember.
Debug - For debugging purposes, obviously haha.

Install Instructions
1. Copy button code below and paste into the toolbar in Toolbar Customization mode or download the DCF file and dragged it into the toolbar in Toolbar Customization mode.
2. Download the script and drag it into Settings > Toolbars > Script.
3. Modify settings as desired by clicking on the script.

Download
Button Code

Code: Select all

<?xml version="1.0"?>
<button backcol="none" display="both" label_pos="right" textcol="none" type="menu">
   <label>Redo Operations</label>
   <icon1>#undo2</icon1>
   <button backcol="none" display="both" hotkey="ctrl+shift+Z" label_pos="right" textcol="none">
      <label>Recent Copy\tCtrl + Shift + Z</label>
      <tip>Show recent copy operations</tip>
      <icon1>#copy</icon1>
      <function type="normal">
         <instruction>RedoOperation LISTCOPY 1</instruction>
      </function>
   </button>
   <button backcol="none" display="both" hotkey="ctrl+shift+X" label_pos="right" textcol="none">
      <label>Recent Move\tCtrl + Shift + X</label>
      <tip>Show recent move operations</tip>
      <icon1>#move</icon1>
      <function type="normal">
         <instruction>RedoOperation LISTMOVE 1</instruction>
      </function>
   </button>
   <button backcol="none" display="both" label_pos="right" textcol="none">
      <label>Clear</label>
      <tip>Clear history of all recent operations</tip>
      <icon1>#recentlistclear</icon1>
      <function type="normal">
         <instruction>RedoOperation CLEAR 1</instruction>
      </function>
   </button>
</button>

Or download DCF file for Button
Redo Operations.dcf
(1.09 KiB) Downloaded 22 times

Redo Operations Script
Redo_Operation.js.txt
(9.12 KiB) Downloaded 19 times

Code: Select all

// Redo Operation
// (c) 2017 Enternal

// Threads Created by Enternal to Ask for Help to Develop Script:
//http://resource.dopus.com/viewtopic.php?f=12&t=28677
//http://resource.dopus.com/viewtopic.php?f=12&t=28694
//http://resource.dopus.com/viewtopic.php?f=12&t=28699
//http://resource.dopus.com/viewtopic.php?f=12&t=28704
//http://resource.dopus.com/viewtopic.php?f=12&t=28706

// Misc Notes
//https://resource.dopus.com/viewtopic.php?t=24251
//http://resource.dopus.com/viewtopic.php?t=24063

function OnInit(initData)
{
   initData.name = "Redo Operation";
   initData.version = "0.1.0";
   initData.copyright = "(c) 2017 Enternal";
   initData.url = "http://resource.dopus.com/viewtopic.php?f=35&t=28756";
   initData.desc = "Track copy/move operations and allow redo for other selected items";
   initData.default_enable = true;
   //initData.min_version = "12.0";

   //http://resource.dopus.com/viewtopic.php?t=22979  Helper: ConfigHelper (easier config item handling) by tbone
   function ConfigHelper(data){ //v1.2
      var t=this; t.d=data; t.c=data.config; t.cd=DOpus.Create.Map();
      t.add=function(name, val, des){ t.l={n:name,ln:name.
         toLowerCase()}; return t.val(val).des(des);}
      t.des=function(des){ if (!des) return t; if (t.cd.empty)
         t.d.config_desc=t.cd; t.cd(t.l.n)=des; return t;}
      t.val=function(val){ var l=t.l; if (l.v!==l.x&&typeof l.v=="object")
         l.v.push_back(val);else l.v=t.c[l.n]=val;return t;}
      t.trn=function(){return t.des(t("script.config."+t.l.ln));}
   }
   var cfg = new ConfigHelper(initData);
   cfg.add("MoveHistoryLength", "15", "Set the history length for recent MOVE operations.");
   cfg.add("CopyHistoryLength", "15", "Set the history length for recent COPY operations.");
   cfg.add("Debug", false, "Set debug to on.");

   var cmd = initData.AddCommand();
   cmd.name = "RedoOperation"
   cmd.method = "OnRedoOperation";
   cmd.desc = initData.desc;
   cmd.label = "Redo Operation"
   cmd.template = "CLEAR/N,LISTMOVE/N,LISTCOPY/N"
}


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

   if (ReOps_move == true) {
      ReOpsInitialize()
      var ReOps_data_move = DOpus.Vars.Get("ReOpsMove");
      var index = searchVector(ReOps_data_move, ReOps_dest);
      if (index != null) {for (var i=index.length-1; i>-1; i=i-1) {ReOps_data_move.erase(index(i));}}
      ReOps_data_move.insert(0, ReOps_dest);
      DOpus.Vars("ReOpsMove") = ReOps_data_move;
      var MoveHistoryLength = Script.config["MoveHistoryLength"];
      while (ReOps_data_move.length>MoveHistoryLength) {
         ReOps_data_move.erase(ReOps_data_move.length-1);
         DOpus.Vars("ReOpsMove") = ReOps_data_move;
      }
   }
   else {
      ReOpsInitialize()
      var ReOps_data_copy = DOpus.Vars.Get("ReOpsCopy");
      var index = searchVector(ReOps_data_copy, ReOps_dest);
      if (index != null) {for (var i=0; i<index.length; i++) {ReOps_data_copy.erase(i);}}
      ReOps_data_copy.insert(0, ReOps_dest);
      DOpus.Vars("ReOpsCopy") = ReOps_data_copy;
         var CopyHistoryLength = Script.config["CopyHistoryLength"];
      while (ReOps_data_copy.length>CopyHistoryLength) {
         ReOps_data_copy.erase(ReOps_data_copy.length-1);
         DOpus.Vars("ReOpsCopy") = ReOps_data_copy;
      }
   }

   if (Script.config["Debug"] == true) {
      //DOpus.ClearOutput
      ReOpsInitialize()
      var ReOps_data_move = DOpus.Vars.Get("ReOpsMove");
      var ReOps_data_copy = DOpus.Vars.Get("ReOpsCopy");
      Log("Redo Operation (Debug)")
      Log("  Redo Operation ReOpsMove Exist: " +DOpus.Vars.Exists("ReOpsMove"))
      Log("  Redo Operation ReOpsCopy Exist: " +DOpus.Vars.Exists("ReOpsCopy"))
      Log("  Redo Operation MOVE History: " +Script.config["MoveHistoryLength"]);
      Log("  Redo Operation COPY History: " +Script.config["CopyHistoryLength"]);
      Log("  Redo Operation MOVE Events");
      if (ReOps_data_move && ReOps_data_move.length) {
         Log("      Vector Length: " +ReOps_data_move.length);
         for (var i=0; i<ReOps_data_move.length; i++) {
            Log("      Event("+i+"): " +ReOps_data_move(i));}
      }
      else {Log("      None")}
      if (ReOps_data_copy && ReOps_data_copy.length) {
         Log("  Redo Operation COPY Events");
         Log("      Vector Length: " +ReOps_data_copy.length);
         for (var i=0; i<ReOps_data_copy.length; i++) {
            Log("      Event("+i+"): " +ReOps_data_copy(i));}
      }
      else {Log("      None")}
      Log("");
   }
}


// Implement the OnRedoOperation command to clear Redo Operation's history
function OnRedoOperation(scriptCmd)
{
   ReOps_clear = 0; // Default value = 0, command not passed
   if (scriptCmd.func.args.got_arg.clear)
      ReOps_clear = scriptCmd.func.args.got_arg.clear;
   ReOps_listmove = 0;
   if (scriptCmd.func.args.got_arg.listmove)
      ReOps_listmove = scriptCmd.func.args.got_arg.listmove;
   ReOps_listcopy = 0;
   if (scriptCmd.func.args.got_arg.listcopy)
      ReOps_listcopy = scriptCmd.func.args.got_arg.listcopy;


   if (ReOps_listmove == 1) {
      ReOpsInitialize() // Ensure all required global varaibles containing history of recent operations exists. If not, initialize them.
      var ReOps_data_move = DOpus.Vars.Get("ReOpsMOVE"); // Load the global history into a local variable to work on
      if (ReOps_data_move.empty == true) {Log("Redo Operation: MOVE History Empty");return;} // If history empty, quit.

      // Create a Dialog object.
      dlg = DOpus.Dlg;
      // Initialise the object to display a popup menu the user can select from
      dlg.window = DOpus.Listers(0);
      dlg.choices = ReOps_data_move; // The list of recent operations stored are the choices to be shown in the menu
      dlg.menu = DOpus.Create.Vector(0);
      // Show the menu
      ret = dlg.Show;
      if (ret == 0) {return;} // Nothing was selected so quit the script
      if (Script.config["Debug"] == true) {
         DOpus.Output("Redo Operation (Debug): MOVE Dialog.Show: " +ret);
         DOpus.Output("Redo Operation (Debug): MOVE Dialog.Selected: " +ReOps_data_move(ret-1));
      }

      //http://resource.dopus.com/viewtopic.php?f=12&t=28704
      if (scriptCmd.func.sourcetab.selected.count == 0) {Log("Redo Operation: No Items Are Selected. Aborting..."); return;} // Quick check to make sure there are something selected
      var cmd = DOpus.Create.Command(); // Create new command to apply to the selected files and folders
      cmd.SetFiles(scriptCmd.func.sourcetab.selected); // Set the selected files and folders as the main items to be acted upon
      cmd.RunCommand('COPY MOVE TO ' + '"' + ReOps_data_move(ret-1) + '"'); // (ret-1) because vectors start from 0 while the dlg.Show starts at 1
   }
   if (ReOps_listcopy == 1) {
      ReOpsInitialize()
      var ReOps_data_copy = DOpus.Vars.Get("ReOpsCopy");
      if (ReOps_data_copy.empty == true) {Log("Redo Operation: Copy History Empty");return;}

      dlg = DOpus.Dlg;
      dlg.window = DOpus.Listers(0);
      dlg.choices = ReOps_data_copy;
      dlg.menu = DOpus.Create.Vector(0);
      ret = dlg.Show;
      if (ret == 0) {return;}
      if (Script.config["Debug"] == true) {
         DOpus.Output("Redo Operation (Debug): COPY Dialog.Show: " +ret);
         DOpus.Output("Redo Operation (Debug): COPY Dialog.Selected: " +ReOps_data_copy(ret-1));
      }

      if (scriptCmd.func.sourcetab.selected.count == 0) {Log("Redo Operation: No Items Are Selected. Aborting..."); return;}
      var cmd = DOpus.Create.Command();
      cmd.SetFiles(scriptCmd.func.sourcetab.selected);
      cmd.RunCommand('COPY TO ' + '"' + ReOps_data_copy(ret-1) + '"');
   }


   if (ReOps_clear == 1) {
      DOpus.Vars.Delete("ReOpsMove"); // Delete global variable that contains the history of recent operations
      DOpus.Vars.Delete("ReOpsCopy");
      Log("Redo Operation: History Cleared");
   }
   if (Script.config["Debug"] == true) {
      Log("Redo Operation (Debug)");
      Log("  ReOpsMove Exist: " +DOpus.Vars.Exists("ReOpsMove"));
      Log("  ReOpsCopy Exist: " +DOpus.Vars.Exists("ReOpsCopy"));
      Log("");
   }
}


// Function to check whether the required global variables for this script to work exist or not. If not, make them and initialize them.
function ReOpsInitialize()
{
   if (DOpus.Vars.Exists("ReOpsMove") == false) {
      DOpus.Vars("ReOpsMove") = DOpus.Create.Vector(); // Initialize global variable as a vector
      DOpus.Vars("ReOpsMove").persist = true; // Set global variable property "persist" to true to last across reboots
      var ReOps_data_move = DOpus.Vars.Get("ReOpsMove");
   }
   if (DOpus.Vars.Exists("ReOpsCopy") == false) {
      DOpus.Vars("ReOpsCopy") = DOpus.Create.Vector();
      DOpus.Vars("ReOpsCopy").persist = true;
      var ReOps_data_copy = DOpus.Vars.Get("ReOpsCopy");
   }
}


// External Helpful Functions
function Log(scriptCmd){DOpus.Output(scriptCmd);} // Saves time from writing the whole "DOpus.Output("Text") to simply "Log("Text")
function searchVector(vector, searchterm) { // Search vector for matched terms and return indexes
   var index = DOpus.Create.Vector(); // Initialize the index vector
   for (var n=0; n<vector.length; n++) { // Go through each element and compare value with search term
      if (String(vector(n)) === String(searchterm)) {index.push_back = n;} // If match search term, store the index into the index vector
                                                   // Had to use String function. Otherwise it won't work... will need to figure out why...
   }
   return index; // Return the index vector
}

User avatar
leo
GPSoftware
Posts: 36498
Joined: 07 Nov 2004, 01:30
OS: Windows 10 64-bit
Opus: Directory Opus 12
Location: London, UK
Contact:
Very neat script! I love the example gif.

ktbcrash
Registered Opus Pro User
Posts: 640
Joined: 19 Jan 2009, 16:55
OS: Windows 7 64-bit
Opus: Directory Opus 12
This was a great idea! Thank you for sharing :thumbsup:

Enternal
Registered Opus Pro User
Posts: 84
Joined: 17 Feb 2016, 15:33
OS: Windows 7 64-bit
Opus: Latest Beta
And I'm glad that people liked it!

I initially had at least seven screenshots to explain what this script really does but then realized that a single "video" will take care of all that haha.

martyprod
Registered Opus Pro User
Posts: 35
Joined: 27 Feb 2012, 09:54
OS: Windows 10 64-bit
Opus: Directory Opus 12
Hi, I love your script ! Thank you !

1) One request please ! your script work perfectly on Hardisc etc... but when i try to use it on a network drive (Smb drive (for my Synology server), it's only remember the root of the drive, and not the full path to the folder used.
so for example i move a file to S:/Pictures , and the path remembered is S:/ , not S:/Pictures.
is it possible to add this feature ? Thanks :).

2) got an error from Directory opus :
- - - - - - - ->
Chrome "https://encrypted.google.com/search?as_q="
<- - - - - - - -
28/01/2017 15:00 Redo Operation: Erreur à la ligne 73, position 59 (Error line 73, position 59)
28/01/2017 15:00 Redo Operation: Indice en dehors de la plage (0x800a0009) (Out of range)

Enternal
Registered Opus Pro User
Posts: 84
Joined: 17 Feb 2016, 15:33
OS: Windows 7 64-bit
Opus: Latest Beta
#1 Ok! Just to confirm though, it's UNC path isn't it? So it should be \\ServerName\Path\to\Folder? Or you meant that you mounted the network drive to a drive letter like S:\? Because in both cases, it should work.

#2 Ooh that's weird. I don't know why there's a google search term in there and also not sure why there's an out of range error since that should have been taken care of in the script. Please do the following:
1. Turn on the Debug setting in Settings > Toolbars > Script > Click on Redo Operation > Change Debug from False to True.
2. Display the Script Logs by Help > Logs > Script Log.
3. Do a copy and a move operation
4. Save the log and send it to me.

After that, clear your Redo Operations History and try to reproduce the error you had with #2 and send the log to me again. And finally, clear your Redo Operation History again and do a copy and move operations to your network drive and then send me that log for that too. So there should be three log files total.

By the way, it may take me a few days since I'm busy so try to use it on Harddisk for now until I fix the error and check why #1 did not work.

martyprod
Registered Opus Pro User
Posts: 35
Joined: 27 Feb 2012, 09:54
OS: Windows 10 64-bit
Opus: Directory Opus 12
Enternal wrote:#1 Ok! Just to confirm though, it's UNC path isn't it? So it should be \\ServerName\Path\to\Folder? Or you meant that you mounted the network drive to a drive letter like S:\? Because in both cases, it should work.


Hi ! yes, it's a network drive mounted, but the adress path is as well \\**\**
i can give you some example, but i confirm this.

#2 Ooh that's weird. I don't know why there's a google search term in there and also not sure why there's an out of range error since that should have been taken care of in the script. Please do the following:
1. Turn on the Debug setting in Settings > Toolbars > Script > Click on Redo Operation > Change Debug from False to True.
2. Display the Script Logs by Help > Logs > Script Log.
3. Do a copy and a move operation
4. Save the log and send it to me.
After that, clear your Redo Operations History and try to reproduce the error you had with #2 and send the log to me again. And finally, clear your Redo Operation History again and do a copy and move operations to your network drive and then send me that log for that too. So there should be three log files total.


ok i will do the #2 and will come back here as soon as it's done (French time, 10p.m, Rzzzzzzzzz ;) )

By the way, it may take me a few days since I'm busy so try to use it on Harddisk for now until I fix the error and check why #1 did not work.


no problem i'll try my best ! :).

martyprod
Registered Opus Pro User
Posts: 35
Joined: 27 Feb 2012, 09:54
OS: Windows 10 64-bit
Opus: Directory Opus 12
Enternal wrote:So there should be three log files total.


i sent the link to Logs / screen captures by PM !

:).


Return to “Script Buttons & Add-Ins”