Current Version
0.2.0 - March 03, 2017
Changes
0.2.0 - March 03, 2017
- Added the Universal option. Instead of having a separate list for recent COPY and MOVE operations, they all share the same list. Therefore you can COPY a file/folder to a location where you recently had moved files/folder to. Off by default (turn it on in Options).
0.1.0 - January 27, 2017
Changes since Redo Operation Scripting Help - 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
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:
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 to will the script remember.
MoveHistoryLength - Default is 15. Allows you to set how many locations where a move to operation was made to will the script remember.
Universal - Default is Off. Instead of having a separate list for recent COPY and MOVE operations, they all share the same list.
UniversalHistoryLength - Default is 15. Allows you to set how many locations where an operation was made will the script remember.
Debug - For debugging purposes, obviously haha.
Requirements
Preferences > File Operations/Copy Options > Automatically manage file copy queues option must be turned on
Install Instructions
- 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.
- Download the script and drag it into Settings > Toolbars > Script.
- Modify settings as desired by clicking on the script.
NOTE!
Due to a bug in Directory Opus as discussed here, the minimum version requirements for the script to work correctly is version 12.3.4 beta.
Download
Button Code
<?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 KB)
Redo Operations Script
Redo_Operation.js.txt (Current - Version 0.2; 12.6 KB)
Old Versions
Redo_Operation.js.txt (Version 0.1; 9.12 KB)
// Redo Operation
// (c) 2017 Enternal
// Threads Created by Enternal to Ask for Help to Develop Script:
//https://resource.dopus.com/t/redo-operation-scripting-help/24602
//https://resource.dopus.com/t/how-to-get-the-gui-popuout-list-like-the-undo-list-item-in-the-toolbar/24617
//https://resource.dopus.com/t/quick-easy-way-to-search-an-array-vector-and-return-index/24622
//https://resource.dopus.com/t/enumerate-selected-items-into-a-simple-line-list/24627
//https://resource.dopus.com/t/how-to-insert-data-into-a-vector-not-through-push-back/24629
//https://resource.dopus.com/t/getcopyqueuenamedata-vs-dopus-listers-0-activetab-path/24740
// Misc Notes
//https://resource.dopus.com/t/js-reusing-regular-global-variables-through-multiple-executions/20358
function OnInit(initData)
{
initData.name = "Redo Operation";
initData.version = "0.2.0";
initData.copyright = "(c) 2017 Enternal";
initData.url = "https://resource.dopus.com/t/redo-operations/24675";
initData.desc = "Quickly and easily redo copy/move operations to recent copied/moved to locations.";
initData.default_enable = true;
//initData.min_version = "12.3.4";
//https://resource.dopus.com/t/helper-confighelper-easier-config-item-handling/19129
// 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("Universal", false, "Recent operations are UNIVERSAL instead of recent COPY destinations are only available for copy operations and vice versa.");
cfg.add("UniversalHistoryLength", "15", "Set the history length for UNIVERSAL recent 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;
// https://resource.dopus.com/t/getcopyqueuenamedata-vs-dopus-listers-0-activetab-path/24740
// Directory Opus below version 12.3.4 beta had a bug where network locations that were mounted
// onto a drive letter had their true path stripped down to the drive letters only.
// Code below still kept since it may be useful for other debugging purposes.
if (Script.config["Debug"] == true) {
DOpus.ClearOutput
ReOpsInitialize()
Log("Redo Operation (Debug) - Path Checks")
Log(" Redo Operation GetCopyQueueNameData.dest: " +GetCopyQueueNameData.dest)
Log(" Redo Operation DOpus.listers(0).activetab.path: " +DOpus.listers(0).activetab.path)
if (String(DOpus.listers(0).activetab.path) == String(GetCopyQueueNameData.dest)) {
Log(" Redo Operation: GetCopyQueueNameData.dest and DOpus.listers(0).activetab.path Matches")
}
else {
Log(" Redo Operation: GetCopyQueueNameData.dest and DOpus.listers(0).activetab.path Does Not Match")
}
}
if (Script.config["Universal"] == true) {
ReOpsInitialize()
var ReOps_data_universal = DOpus.Vars.Get("ReOpsUniversal");
var index = searchVector(ReOps_data_universal, ReOps_dest);
if (index != null) {for (var i=index.length-1; i>-1; i=i-1) {ReOps_data_universal.erase(index(i));}}
ReOps_data_universal.insert(0, ReOps_dest);
DOpus.Vars("ReOpsUniversal") = ReOps_data_universal;
var UniversalHistoryLength = Script.config["UniversalHistoryLength"];
while (ReOps_data_universal.length>UniversalHistoryLength) {
ReOps_data_universal.erase(ReOps_data_universal.length-1);
DOpus.Vars("ReOpsUniversal") = ReOps_data_universal;
}
}
else 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");
var ReOps_data_universal = DOpus.Vars.Get("ReOpsUniversal");
Log("Redo Operation (Debug) - General")
Log(" Redo Operation ReOpsMove Exist: " +DOpus.Vars.Exists("ReOpsMove"))
Log(" Redo Operation ReOpsCopy Exist: " +DOpus.Vars.Exists("ReOpsCopy"))
Log(" Redo Operation ReOpsUniversal Exist: " +DOpus.Vars.Exists("ReOpsUniversal"))
Log(" Redo Operation MOVE History: " +Script.config["MoveHistoryLength"]);
Log(" Redo Operation COPY History: " +Script.config["CopyHistoryLength"]);
Log(" Redo Operation UNIVERSAL History: " +Script.config["UniversalHistoryLength"]);
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")}
if (ReOps_data_universal && ReOps_data_universal.length) {
Log(" Redo Operation UNIVERSAL Events");
Log(" Vector Length: " +ReOps_data_universal.length);
for (var i=0; i<ReOps_data_universal.length; i++) {
Log(" Event("+i+"): " +ReOps_data_universal(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.
if (Script.config["Universal"] == true) {var ReOps_data_move = DOpus.Vars.Get("ReOpsUniversal");} // If config Universal is on, load the global history for shared operations into a local variable to work on
else {var ReOps_data_move = DOpus.Vars.Get("ReOpsMove");} // Else, load the global history for MOVE operations 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));
}
//https://resource.dopus.com/t/enumerate-selected-items-into-a-simple-line-list/24627
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()
if (Script.config["Universal"] == true) {var ReOps_data_copy = DOpus.Vars.Get("ReOpsUniversal");}
else {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");
DOpus.Vars.Delete("ReOpsUniversal");
Log("Redo Operation: History Cleared");
}
if (Script.config["Debug"] == true) {
Log("Redo Operation (Debug) - Permanent Variables Check");
Log(" ReOpsMove Exist: " +DOpus.Vars.Exists("ReOpsMove"));
Log(" ReOpsCopy Exist: " +DOpus.Vars.Exists("ReOpsCopy"));
Log(" ReOpsUniversal Exist: " +DOpus.Vars.Exists("ReOpsUniversal"));
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");
}
if (DOpus.Vars.Exists("ReOpsUniversal") == false) {
DOpus.Vars("ReOpsUniversal") = DOpus.Create.Vector();
DOpus.Vars("ReOpsUniversal").persist = true;
var ReOps_data_copy = DOpus.Vars.Get("ReOpsUniversal");
}
}
// 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
}
To Add To Context Menu
-
Settings > File Types...
-
-
-
RedoOperation LISTCOPY 1
RedoOperation LISTMOVE 1