function OnInit(initData) { initData.name = "touch"; var version = "5.0"; var version_date = "3rd April, 2017"; initData.version = version; initData.copyright = "(c) 2016 Aussie"; initData.url = "http://resource.dopus.com/viewtopic.php?f=35&t=27733"; initData.desc = "Adjust MODIFIED date/time stamps"; initData.default_enable = true; initData.min_version = "12.3"; var cmd = initData.AddCommand(); cmd.name = initData.name; cmd.method = "do_main"; cmd.desc = initData.desc; cmd.label = initData.name; cmd.template = "clip/s,file/o"; // Define defaults for things the user can configure via Preferences --> Scripts var def_debug = true; // Used to write progress/trace message to the "other" log var def_clearoutput = true; // Only applies if debug is true var def_ymd = false; // Used to force YMD dates. Default is locale var def_daynames = true; // Control display of day names in locale mode var def_align = true; // Used to force dates to be aligned by padding with zeros var cfg = new CfgHelper(initData); cfg.add("URL",initData.url,"URL of related Opus Resource forum post"); cfg.add("version",version,"Version "); cfg.add("version_date",version_date,"Updated " + version_date); cfg.add("debug",def_debug,"Set to TRUE to write debug messages to OTHER log."); cfg.add("clearoutput",def_clearoutput,"Set to TRUE to pre-clear debug message log."); cfg.add("ymd",def_ymd,"Set to TRUE to force dates to be displayed as YMD."); cfg.add("daynames",def_daynames,'Control display of day names if "Show day names in date columns" option is set in Prefs.'); cfg.add("align",def_align,"Set to TRUE to force displayed dates to be aligned."); // Based on original code by @tbone at http://resource.dopus.com/viewtopic.php?f=35&t=22979 function CfgHelper(d){ this.d = d; this.name = null; if (d.config_desc==undefined) d.config_desc=DOpus.Create.Map(); this.add = function(name, val, description){ if (name==undefined) return this; // if name not supplied, exit immediately this.name=name; // needed later to add corresponding value(s) and/or description return this.addval(val).setdesc(description); } this.addvec = function(name){ if (name==undefined) return this; // if name not supplied, exit immediately this.name=name; // needed later to add corresponding value(s) and/or description return this.addval(DOpus.Create.Vector); // create an empty vector } this.addval = function(val){ if (this.name==undefined) return this; // need to add value to something if (typeof this.d.config[this.name]=="object") { if (val!=undefined) this.d.config[this.name].push_back(val); } else this.d.config[this.name]=(val==undefined)?false:val; // default value = FALSE return this; } this.setdesc = function(description){ if (this.name==undefined) return this; // need to add description to something d.config_desc(this.name)=(description==undefined)?null:description; return this } } } // Global variables var dbg; // Config option to enable debug message output to "Other" log. var ymd; // Config option to display dates in YMD format. var align; // Config option to align display of dates. var cmd, d, dlg, msgbox, msg_obj, result, src, str; var ix_sel, ix_newest, ix_oldest; var inc_amt = 1, inc_type; var items = DOpus.create.vector; var original_items = DOpus.create.vector; var current_items_date = DOpus.create.vector; var pending_items_date = DOpus.create.vector; var user_supplied_items = DOpus.create.vector; var help_desc = DOpus.create.map; function do_main(ClickData) { // Process configuration settings dbg = Script.config.debug; ymd = Script.config.ymd; align = Script.config.align; // Initialise some variables d = ClickData; src = d.func.sourcetab; dlg = d.func.dlg, msgbox = d.func.dlg; // dlg = main dialog, msgbox used for warning messages cmd = d.func.command; if (dbg){ if (Script.config.clearoutput) DOpus.clearoutput(); DOpus.output("version " + Script.config.version + " (" + Script.config.version_date + ") starting.."); DOpus.output("Local date format = " + dateformat()); } // Populate Help descriptions with mapped message strings build_help_desc(); // Prepare the main Opus 12 detached dialog for use dlg.window = src; // See dialog layout details below under SCRIPT RESOURCES dlg.template = "touch"; dlg.detach = true; dlg.title = '"Touch" version ' + Script.config.version + " (" + Script.config.version_date + ")"; dlg.create; // Apply highlighting to the "changes" static text control dlg.control("changes").fg = "#FF0000"; dlg.control("changes").style = "i"; // Determine the initial date display format if (ymd) dlg.control("date_ymd").value = true; // The user may want YMD format date display else if (align==false) dlg.control("date_locale").value = true; // Or possibly locale default date display // Build the initial list of items // The source can be the clipboard (clip option) or a single filespec (file option) or selected items if (d.func.args.got_arg.clip){ // If the clip option was specified create a vector of valid items pulled from the clipboard items.assign(find_items(DOpus.getclip("text"))); if (items.count==0) return false; result = refresh_items(items); } else if (d.func.args.got_arg.file){ // If the file option was specified validate the supplied item spec items.assign(find_items(d.func.args.file)); if (items.count==0) return false; result = refresh_items(items); } // Default if neither clip nor file was specified is to use selected items else result = refresh_items(); // Will return false if nothing is selected.. if (result==false) return false; // ..in which case just exit draw_lb(dlg.control("lb1")); // ..otherwise populate the listbox with validated or selected items // Display the initialised dialog dlg.show; var iteration = 0; // Initialise an action counter (for debugging purposes) // ------------------------------------------- // Loop until the dialog is closed by the user // ------------------------------------------- do{ msg_obj = dlg.getmsg(); if (msg_obj==false) break; // User has terminated the dialog str = iteration++; // Increment action counter if (dbg){ str+= " : msg_obj.event = " + msg_obj.event; str+= " : msg_obj.control = " + msg_obj.control; DOpus.output(str); } // No action required if focus changes if (msg_obj.event=="focus") continue; // A control may have been switched off if (dlg.control(msg_obj.control).value==false){ if (dbg) DOpus.output(dlg.control(msg_obj.control) + " has been switched off"); continue; } // ------------------------------------------------------------ // Fix for erroneous "click" event being sent to script dialogs // when a radio button gains the focus - e.g. after selecting another window // and then returning to the dialog window. Addressed in Opus v12.3.8 Beta. // See https://resource.dopus.com/t/dialog-reselection-triggers-first-control/25116/2 if (msg_obj.control=="adj_seconds"){ if (dlg.control(msg_obj.control).value==false){ if (dbg) DOpus.output("Spurious radio button click event trapped!"); continue; } } // ------------------------------------------------------------ // Process an adjustment type change (e.g. Seconds, Minutes, Hours) if (msg_obj.control.indexOf("adj_")==0){ if (dbg) DOpus.output("Change type of adjustment (hours, days, etc.)"); inc_type = (msg_obj.control=="adj_months") ? "M" : msg_obj.control.substr(4,1); if (dbg){ DOpus.output("inc_amt = " + inc_amt); DOpus.output("inc_type = " + inc_type); // Will be s, m, h, d, w, M, y } // If there are multiple items, increment and decrement must be enabled if (original_items.count>1){ dlg.control("all_increment").enabled = true; dlg.control("all_decrement").enabled = true; if (dlg.control("all_increment").value==true) dlg.control("all_increment").value = false; else if (dlg.control("all_decrement").value==true) dlg.control("all_decrement").value = false; } if (dbg) DOpus.output("msg_obj.control = " + msg_obj.control); dlg.control("help_text").label = help_desc(msg_obj.control); } // Process an adjustment amount change else if (msg_obj.control=="adjustment"){ if (dbg) DOpus.output("Change adjustment amount (1, 2, 3, etc.)"); inc_amt = dlg.control("adjustment").value; if (dbg){ DOpus.output("inc_amt = " + inc_amt); DOpus.output("inc_type = " + inc_type); } // If there are multiple items and the current action is either increment or decrement // apply the updated increment or decrement to the listed items if (original_items.count>1){ if ((dlg.control("all_increment").value==true) || (dlg.control("all_decrement").value==true)){ var dt = current_items_date(0).clone; for (var i = 1; i < original_items.count; i++){ dt.add(inc_amt,inc_type); pending_items_date(i) = dt.clone; } } } } // Process a date display request else if (msg_obj.control.indexOf("date_")==0){ if (dbg) DOpus.output("Date display request"); ymd = (msg_obj.control=="date_ymd"); align = (msg_obj.control=="date_aligned"); } // Process a selection change else if (msg_obj.event=="selchange"){ if (dbg) DOpus.output("Selection change"); ix_sel = dlg.control("lb1").value.index; if (dlg.control("all_selected").value==true){ if (dbg) DOpus.output("ix_sel = " + ix_sel); var dt = current_items_date(ix_sel); for (var i = 0; i < original_items.count; i++) pending_items_date(i) = dt; } } // Process an adjustment request (+ or -) else if (msg_obj.control.indexOf("amt_")==0){ if (dbg) DOpus.output("Add or Subtract selected amount and type"); ix_sel = 0; inc_amt = dlg.control("adjustment").value; if (dbg){ DOpus.output("inc_amt = " + inc_amt); DOpus.output("inc_type = " + inc_type); } for (var i = 0; i < original_items.count; i++){ var dt = pending_items_date(i).clone; if (msg_obj.control.indexOf("down")>0) dt.sub(inc_amt,inc_type); else dt.add(inc_amt,inc_type); pending_items_date(i) = dt.clone; } // Switch the current action button off after processing an adjustment if (dlg.control("all_original").value==true) dlg.control("all_original").value=false; else if (dlg.control("all_now").value==true) dlg.control("all_now").value=false; else if (original_items.count>1){ if (dlg.control("all_oldest").value==true) dlg.control("all_oldest").value=false; if (dlg.control("all_newest").value==true) dlg.control("all_newest").value=false; if (dlg.control("all_selected").value==true) dlg.control("all_selected").value=false; if (dlg.control("all_increment").value==true) dlg.control("all_increment").value=false; } } else if (msg_obj.control=="all_original"){ if (dbg) DOpus.output("Reset all to original"); ix_sel = 0; for (var i = 0; i < original_items.count; i++) pending_items_date(i) = original_items(i).modify; dlg.control("help_text").label = help_desc("all_original"); } else if (msg_obj.control=="all_now"){ if (dbg) DOpus.output("Set all = NOW"); var dt = DOpus.create.date(); for (var i = 0; i < original_items.count; i++) pending_items_date(i) = dt; dlg.control("help_text").label = help_desc("all_now"); } else if (msg_obj.control=="all_oldest"){ if (dbg) DOpus.output("Set all = OLDEST"); ix_sel = ix_oldest; var dt = current_items_date(ix_sel); for (var i = 0; i < original_items.count; i++) pending_items_date(i) = dt; dlg.control("help_text").label = help_desc("all_oldest"); } else if (msg_obj.control=="all_newest"){ if (dbg) DOpus.output("Set all = NEWEST"); ix_sel = ix_newest; var dt = current_items_date(ix_sel); for (var i = 0; i < original_items.count; i++) pending_items_date(i) = dt; dlg.control("help_text").label = help_desc("all_newest"); } else if (msg_obj.control=="all_selected"){ if (dbg) DOpus.output("Set all = SELECTED"); for (var i = 0; i < original_items.count; i++) pending_items_date(i) = original_items(ix_sel).modify; dlg.control("help_text").label = help_desc("all_selected"); } else if ((msg_obj.control=="all_increment") || (msg_obj.control=="all_decrement")){ if (dbg) DOpus.output("Increment or decrement off current base"); ix_sel = 0; var dt = pending_items_date(0).clone; inc_amt = dlg.control("adjustment").value; if (dbg){ DOpus.output("inc_amt = " + inc_amt); DOpus.output("inc_type = " + inc_type); } for (var i = 0; i < original_items.count; i++){ pending_items_date(i) = dt.clone; if (msg_obj.control=="all_increment") dt.add(inc_amt,inc_type); else dt.sub(inc_amt,inc_type); } var temp = help_desc("all_increment"); if (msg_obj.control=="all_decrement"){ temp = temp.replace(" add ", " subtract "); temp = temp.replace(" to the ", " from the "); } dlg.control("help_text").label = temp; } // Refresh with current selected items (user has selected a new set of items) else if (msg_obj.control=="btn_selected"){ if (dbg) DOpus.output("Refresh with selected items"); result = refresh_items(); if (result==false) return false; } // Refresh with clipboard items else if (msg_obj.control=="btn_clip"){ if (dbg) DOpus.output("Refresh with clipboard items"); items.clear(); items.assign(find_items(DOpus.getclip("text"))); if (items.count!=0) refresh_items(items); } // Use SetAttr to adjust the last modified time stamps of items else if (msg_obj.control=="btn_process"){ if (dbg) DOpus.output("Process a change"); for (var i = 0; i < original_items.count; i++) { // Process items whose new and current timestamps are different if (pending_items_date(i).compare(current_items_date(i))!=0){ str = 'SetAttr "' + original_items(i).path + "\\" + original_items(i).name + '"'; str = str + ' MODIFIED "' + pending_items_date(i).format("D#yyyy-MM-dd T#HH:mm:ss") + '"'; if (dbg) DOpus.output("str = " + str); current_items_date(i) = pending_items_date(i).clone; cmd.runcommand(str); } } } draw_lb(dlg.control("lb1")); } while (msg_obj); } function build_help_desc(){ help_desc("general") = "Select an action to apply to all listed items or specify an amount and click + or - to adjust timestamps up or down."; help_desc("all_original") = "All item timestamps will be restored to their original value."; help_desc("all_oldest") = "The timestamp of the oldest listed item will be applied to all listed items."; help_desc("all_newest") = "The timestamp of the newest listed item will be applied to all listed items."; help_desc("all_now") = "All listed items will have their timestamps updated to the current date and time."; help_desc("all_selected") = "All listed items will have their timestamps updated to the selected item's date and time."; help_desc("all_increment") = "Listed items will have their timestamps incrementally updated to add the currently specified adjustment to the base (first) item's date and time."; str = "Adjustments, increments and decrements will be applied in units of "; help_desc("adj_seconds") = str + "seconds."; help_desc("adj_minutes") = str + "minutes."; help_desc("adj_hours") = str + "hours."; help_desc("adj_days") = str + "days."; help_desc("adj_weeks") = str + "weeks."; help_desc("adj_months") = str + "months."; help_desc("adj_years") = str + "years."; } function draw_lb(lb){ if (dbg) DOpus.output("draw_lb: ix_sel = " + ix_sel); var str, changes_pending = false; lb.RemoveItem(-1); // Clear the listbox // Add items to the listbox for (var i = 0; i < original_items.count; i++){ str = " | " + original_items(i).name; if (pending_items_date(i).compare(current_items_date(i))!=0){ changes_pending = true; str = " ===> " + format_date(pending_items_date(i)) + str; } str = format_date(current_items_date(i)) + str; lb.AddItem(str); } lb.SelectItem(ix_sel); dlg.control("filespec").label = "Path: " + original_items(ix_sel).path; if (changes_pending){ dlg.control("changes").label = "Timestamp adjustments are pending!"; dlg.control("filedate").label = dlg.control("lb1").GetItemAt(ix_sel).name; dlg.control("g5").label = "Changes are ready to be processed"; dlg.control("btn_process").enabled = true; } else{ dlg.control("changes").label = ""; dlg.control("filedate").label = ""; dlg.control("g5").label = "No pending changes"; dlg.control("btn_process").enabled = false; } } function format_date(d){ var dt = d.clone(); var daynames = Script.config.daynames; if ((align==false) && (ymd==false)){ var str = " " + dt.format("t"); str = (daynames) ? dt.format("d") + str : dt.format("d","n") + str; return str; } var time = dt.format("t"); var sep = ":"; var a = time.split(sep); time = "0" + a[0]; time = time.slice(-2); for (var i = 1; i < a.length; i++) time = time + sep + a[i]; dt.sub(1,"w"); // Make sure date is not shown as (e.g.) Today var day = dt.day; var month = dt.month; var year = dt.year; if (day==month) dt.sub(1,"d") // Eliminate possible day = month confusion, e.g. 7/7/2016 dt = dt.format("d","n"); // Could be D-M-Y, M-D-Y, Y-M-D or D/M/Y, M/D/Y, Y/M/D var i = dt.indexOf("-"); if (i<0) i = dt.indexOf("/"); sep = dt.substr(i,1); a = dt.split(sep); day = "0" + d.day; day = day.slice(-2); month = "0" + d.month; month = month.slice(-2); year = d.year; if (ymd || a[0]==year) return year + sep + month + sep + day + " " + time; else if (a[0]==month) return month + sep + day + sep + year + " " + time; else return day + sep + month + sep + year + " " + time; } function dateformat(){ // Return a string representing the local date format - YMD, DMY or MDY var dbg = Script.config.debug; var now = DOpus.create.date; var m1 = now.month; var d1 = now.day; if (d1==m1) now.add(1,"d"); // Deal with day = month var ts = now.format("d","n"); var a = ts.split(" "); // a[0] = date a = a[0].split(/\D/); // Split by whatever the separator is - e.g. / or - if (a[0].length==4) return "YMD"; else if (a[1]==m1) return "DMY" else return "MDY"; } function find_items(str){ // If items were supplied via FILE or CLIP, check for existence and build and return a list var valid_items = DOpus.create.vector; var strings = str.split(/(?:\n|\r\n?)/); for (var i = 0; i < strings.length; i++){ str = strings[i]; if (DOpus.FSUtil.Exists(str)) valid_items.push_back(str); else{ str = src.path + "\\" + str; if (DOpus.FSUtil.Exists(str)) valid_items.push_back(str); } } if (valid_items.count==0) warn("Requested item(s) not found"); return valid_items; } function refresh_items(items){ // Establish in-scope items. Default is selected items if no list is supplied. ix_sel = ix_newest = ix_oldest = 0; original_items.clear(); current_items_date.clear(); pending_items_date.clear(); user_supplied_items.clear(); if (items!=undefined){ // If items were supplied via FILE or CLIP, check for existence and build a list if (dbg) DOpus.output("items.count = " + items.count); user_supplied_items.assign(items); for (var i = 0; i < user_supplied_items.count; i++){ str = user_supplied_items(i); var next_item = DOpus.FSUtil.Getitem(str); var item = {path:next_item.path, name:next_item.name, modify:next_item.modify.clone}; original_items.push_back(item); } } else{ // Default is to build a list of selected items src.update(); if (src.selected.count==0){ warn("Need at least one selected file or folder"); return false; } for (var i = 0; i < src.selected.count; i++){ var next_item = src.selected(i); var item = {path:next_item.path, name:next_item.name, modify:next_item.modify.clone}; original_items.push_back(item); } } dlg.control("help_text").label = help_desc("general"); if (dbg) DOpus.output("original_items.count = " + original_items.count); // Populate current and pending dates and establish oldest and newest indices var dt_oldest = dt_newest = original_items(0).modify; // Modified date of first item for (var i = 0; i < original_items.count; i++){ current_items_date.push_back(original_items(i).modify); pending_items_date.push_back(original_items(i).modify); if (original_items(i).modify.compare(dt_oldest)<0){ dt_oldest = original_items(i).modify; ix_oldest = i; } else if (original_items(i).modify.compare(dt_newest)>0){ dt_newest = original_items(i).modify; ix_newest = i; } } if (dbg){ DOpus.output("ix_oldest = " + ix_oldest); DOpus.output("ix_newest = " + ix_newest); } var more_than_one_item = (original_items.count>1); dlg.control("all_oldest").enabled = more_than_one_item; dlg.control("all_newest").enabled = more_than_one_item; dlg.control("all_selected").enabled = more_than_one_item; if (inc_type!=undefined){ dlg.control("all_increment").enabled = more_than_one_item; dlg.control("all_decrement").enabled = more_than_one_item; } if (!more_than_one_item){ if (dlg.control("all_oldest").value==true) dlg.control("all_oldest").value=false; else if (dlg.control("all_newest").value==true) dlg.control("all_newest").value=false; else if (dlg.control("all_selected").value==true) dlg.control("all_selected").value=false; else if (dlg.control("all_increment").value==true) dlg.control("all_increment").value=false; else if (dlg.control("all_decrement").value==true) dlg.control("all_decrement").value=false; } } function warn(msg){ msgbox.message = msg; msgbox.buttons = "OK"; msgbox.icon = "warn"; msgbox.title = "Warning"; msgbox.show(); } ==SCRIPT RESOURCES