// filetags dbg 3 (for example) to set the level of debug information written to the "Other" log. // // 20201112 v1.0 // 20201123 v1.1 Fix problem with DOpus.Loadimage with invalid image files // 20201123 v1.1 Add support for the escape key as a means of exiting the dialog // 20201123 v1.1 Handle undefined focal length // 20201124 v1.2 Improve handling of invalid images // 20201124 v1.2 Allow tagging and rating and attribute setting on all existing non-archive files // 20201124 v1.2 Add support for Ctrl+0 through Ctrl+5 for setting star ratings // 20201124 v1.2 Add support for Ctrl+P to access script preferences // 20231030 v1.3 Add support for OSM zoom - See https://resource.dopus.com/t/filetags-file-tagger-and-metadata-viewer/37155/21 // 20231030 v1.3 Add support for trailing ; // 20231030 v1.3 Add support for move to next after Apply // 20231030 v1.3 Fix broken click to preview // 20231031 v1.3 Add support for OSM zoom with pinpoint //-- Defaults - added in v1.3 - Can all be changed in script preferences d_dbg = 0; d_dpi = 200; d_metric = true; d_msTabChange = 125; d_msThumbLoad = 1000; d_OSMzoom = 17; d_semiTrail = false; d_nextAfterApply = false; d_imgHandler1 = "/programfilesx86/Adobe/Photoshop Elements 5.0/PhotoshopElementsEditor.exe"; d_imgHandler1Label = "Photoshop"; d_imgHandler2 = "/programfiles/TechSmith/Snagit 2024/SnagitEditor.exe"; d_imgHandler2Label = "Snagit"; d_imgHandler3 = "/system/MSPaint.exe"; d_imgHandler3Label = "MSPaint"; d_editor1 = "/programfiles/Notepad++/Notepad++.exe"; d_editor1Label = "Notepad++"; d_editor2 = "/system/Notepad.exe"; d_editor2Label = "Notepad"; d_editor3 = "/portable/Frhed/Frhed.exe"; d_editor3Label = "Frhed"; d_esc = true; d_stars = true; //-- Global Variables var me = { name:"filetags", version:"v1.3 (October 31st, 2023)", copyright:"(c) @aussieboykie", inspiration:"https://resource.dopus.com/t/photo-exif/35015", minver:"12.21.5", // 12.21.5 includes several fixes to Dlg.WatchTab dlg:"dlgFileInfo" } var cmd = DOpus.create.command, strCommand; var dlg = DOpus.dlg, msg_obj; var watchedTabs = DOpus.Create.Map(); var currLister, currTab; var dbg, dpi, units, msTabChange, msThumbLoad, OSMzoom, semiTrail, nextAfterApply; // Values to be obtained via settings var firstShow = true; // Special handling for initial dialog populate var strName = "", flgNameChanged = false; var strCopyright = "", flgCopyrightChanged = false; var strDesc = "", flgDescriptionChanged = false; var strTags = "", flgTagsChanged = false; var intAltitude, intLatitude, intLongitude; var locateWith = DOpus.Create.Vector(0,"Google","OSM","Bing"); var locateWithURL = DOpus.Create.Vector("https://www.google.com/maps?q=","https://www.openstreetmap.org/?mlat=","https://www.bing.com/maps?v=2&q="); var imgHandler1, imgHandler2, imgHandler3; // Optional external handlers for images - e.g. Photoshop var editor1, editor2, editor3; // Optional external handlers for eligible files - e.g. Notetab var currFile, currFileIndex; var fileExists = false; var fileSize = false; var isImage = false; var isValidImage = false; // v1.2 var isMovie = false; var isMusic = false; var isProgram = false; var isArchive = false; var isDocument = false; var isPDF = false; var isInArchive = false; var isSpecial = false; var isColl = false; var isLib = false; var isOffline = false; var starRating = 0; //-- Initialise configuration variables, etc. function OnInit(initData) { initData.name = me.name; initData.version = me.version; initData.copyright = me.copyright; initData.default_enable = true; var cmd = initData.AddCommand(); cmd.name = me.name; cmd.method = "do_run"; cmd.label = me.name; cmd.template = "dbg/n"; initData.config_desc = DOpus.create.map(); initData.config.dbg = d_dbg; initData.config_desc("dbg") = 'How much debug info to write to "Other" log. Bigger number = more.'; initData.config.dpi = d_dpi; initData.config_desc("dpi") = 'Set Printer DPI.'; initData.config.metric = d_metric; initData.config_desc("metric") = 'Use metric paper size measurement units.'; initData.config.locatewith = locateWith; initData.config_desc("locatewith") = 'Choose a location mapping service.'; initData.config.msTabChange = d_msTabChange; initData.config_desc("msTabChange") = 'Retry delay for tab change to complete.'; initData.config.msThumbLoad = d_msThumbLoad; initData.config_desc("msThumbLoad") = 'Max wait for thumbnail load to complete.'; initData.config.OSMzoom = d_OSMzoom; // v1.3 initData.config_desc("OSMzoom") = "Zoom level for Open Street Map."; initData.config.semiTrail = d_semiTrail; // v1.3 initData.config_desc("semiTrail") = "Add trailing semicolon."; initData.config.nextAfterApply = d_nextAfterApply; // v1.3 initData.config_desc("nextAfterApply") = "Move to next item after Apply."; initData.config.imgHandler1 = d_imgHandler1; initData.config_desc("imgHandler1") = "Image Handler App #1"; initData.config.imgHandler1Label = d_imgHandler1Label; initData.config_desc("imgHandler1Label") = "e.g. imgHandler1"; initData.config.imgHandler2 = d_imgHandler2; initData.config_desc("imgHandler2") = "Image Handler App #2"; initData.config.imgHandler2Label = d_imgHandler2Label; initData.config_desc("imgHandler2Label") = "e.g. imgHandler2"; initData.config.imgHandler3 = d_imgHandler3; initData.config_desc("imgHandler3") = "Image Handler App #3"; initData.config.imgHandler3Label = d_imgHandler3Label; initData.config_desc("imgHandler3Label") = "e.g. imgHandler3"; initData.config.editor1 = d_editor1; initData.config_desc("editor1") = "Editor App #1"; initData.config.editor1Label = d_editor1Label; initData.config_desc("editor1Label") = "e.g. Editor #1"; initData.config.editor2 = d_editor2; initData.config_desc("editor2") = "Editor App #2"; initData.config.editor2Label = d_editor2Label; initData.config_desc("editor2Label") = "e.g. Editor #2"; initData.config.editor3 = d_editor3; initData.config_desc("editor3") = "Editor App #3"; initData.config.editor3Label = d_editor3Label; initData.config_desc("editor3Label") = "e.g. Editor #3"; initData.config.esc = d_esc; initData.config_desc("esc") = "Use the Esc (escape) key to exit the dialog."; initData.config.stars = d_stars; initData.config_desc("stars") = "Use Ctrl+0 through Ctrl+5 to set star rating."; initData.config.prefs = "Ctrl+P"; initData.config_desc("prefs") = "Key combination used to access script preferences."; } String.prototype.trim = function(s){s=s||"\\s";return this.replace(new RegExp("^("+s+"){1,}\|("+s+"){1,}$","g"),"");} //-- Main script code function do_run(ScriptCommandData) { dbg = (ScriptCommandData.func.args.got_arg.dbg) ? ScriptCommandData.func.args.dbg : Script.config.dbg; // Who am I? log(me.version+ " session starting. Debug level is "+dbg,1); // Check minimum version requirements if (!isVersionOK(me.minver)) return; // Process configuration variables and initialise key variables dpi = Script.config.dpi; metric = Script.config.metric; msTabChange = Script.config.msTabChange; msThumbLoad = Script.config.msThumbLoad; OSMzoom = Script.config.OSMzoom; // v1.3 semiTrail = Script.config.semiTrail; // v1.3 nextAfterApply = Script.config.nextAfterApply; // v1.3 imgHandler1 = Script.config.imgHandler1; imgHandler1Label = Script.config.imgHandler1Label; imgHandler2 = Script.config.imgHandler2; imgHandler2Label = Script.config.imgHandler2Label; imgHandler3 = Script.config.imgHandler3; imgHandler3Label = Script.config.imgHandler3Label; imgHandler1 = (imgHandler1==="") ? "" : DOpus.FSUtil.Resolve(imgHandler1); imgHandler1 = (DOpus.FSUtil.Exists(imgHandler1)) ? imgHandler1 : false; imgHandler2 = (imgHandler2==="") ? "" : DOpus.FSUtil.Resolve(imgHandler2); imgHandler2 = (DOpus.FSUtil.Exists(imgHandler2)) ? imgHandler2 : false; imgHandler3 = (imgHandler3==="") ? "" : DOpus.FSUtil.Resolve(imgHandler3); imgHandler3 = (DOpus.FSUtil.Exists(imgHandler3)) ? imgHandler3 : false; editor1 = Script.config.editor1; editor1Label = Script.config.editor1Label; editor2 = Script.config.editor2; editor2Label = Script.config.editor2Label; editor3 = Script.config.editor3; editor3Label = Script.config.editor3Label; editor1 = (editor1==="") ? "" : DOpus.FSUtil.Resolve(editor1); editor1 = (DOpus.FSUtil.Exists(editor1)) ? editor1 : false; editor2 = (editor2==="") ? "" : DOpus.FSUtil.Resolve(editor2); editor2 = (DOpus.FSUtil.Exists(editor2)) ? editor2 : false; editor3 = (editor3==="") ? "" : DOpus.FSUtil.Resolve(editor3); editor3 = (DOpus.FSUtil.Exists(editor3)) ? editor3 : false; // Log a few variables log("Printer DPI = "+dpi+" dots per inch",2); log("Metric = "+metric,2); log("Tab change delay = "+msTabChange+" milliseconds",2); log("Thumbnail load delay = "+msThumbLoad+" milliseconds",2); log("OSM Zoom = "+OSMzoom,2); log("semiTrail = "+semiTrail,2); log("nextAfterApply = "+nextAfterApply,2); log("imgHandler1 = "+imgHandler1,2); log("imgHandler1Label = "+imgHandler1Label,2); log("imgHandler2 = "+imgHandler2,2); log("imgHandler2Label = "+imgHandler2Label,2); log("imgHandler3 = "+imgHandler3,2); log("imgHandler3Label = "+imgHandler3Label,2); log("editor1 = "+editor1,2); log("editor1Label = "+editor1Label,2); log("editor2 = "+editor2,2); log("editor2Label = "+editor2Label,2); log("editor3 = "+editor3,2); log("editor3Label = "+editor3Label,2); // Establish a detached dialog cmd.deselect = false; currLister = DOpus.listers.lastactive; dlg.window = currLister; // Lock the dialog to the active lister dlg.template = me.dlg; // Set the correct dialog template dlg.detach = true; dlg.title = me.name+" - "+me.version; dlg.create; if (Script.config.esc) dlg.AddHotKey("escape","escape"); // v1.1 - Use Esc as an alternative means of exiting the dialog if (Script.config.stars) { // v1.2 - Use Ctrl+0 through Ctrl+5 for setting star ratings dlg.AddHotKey("star0","ctrl+0"); dlg.AddHotKey("star1","ctrl+1"); dlg.AddHotKey("star2","ctrl+2"); dlg.AddHotKey("star3","ctrl+3"); dlg.AddHotKey("star4","ctrl+4"); dlg.AddHotKey("star5","ctrl+5"); } if (Script.config.prefs!=="") dlg.AddHotKey("prefs",Script.config.prefs); // v1.2 - Key combination to access script preferences dlg.Control("lblPrintSize").label = "Maximum Print Size @ "+dpi+" dpi"; dlg.Control("editAddToColl").value = (Script.Vars.Exists("collTarget")) ? Script.vars("collTarget") : me.name; currTab = currLister.activetab; watchTab(); refreshDlg(); dlg.show; firstShow = false; do{ msg_obj = dlg.getmsg(); if (msg_obj==false) break; if (currFile!=false) currFile.Update(); // See https://resource.dopus.com/t/attribute-change-not-recognised-in-fileattr-object/37002/3 if (msg_obj.event=="click"){ log(msg_obj.control+" clicked",3); if (msg_obj.control=="btnQuit") break; /* Disabled in v1.3 - trigger is staticImage! else if (msg_obj.control=="btnShow") { strCommand = (isArchive) ? "Go \""+String(currFile)+"\" NEWTAB=findexisting" : "Show \""+String(currFile)+"\""; log(strCommand,4); cmd.runcommand(strCommand); } */ else if (msg_obj.control=="staticImage") { // v1.3 Replaces disabled btnShow code strCommand = (isArchive) ? "Go \""+String(currFile)+"\" NEWTAB=findexisting" : "Show \""+String(currFile)+"\""; log(strCommand,4); cmd.runcommand(strCommand); } else if (msg_obj.control=="btnRun") { strCommand = '"'+String(currFile)+'"'; log(strCommand,4); cmd.runcommand(strCommand); } else if (msg_obj.control=="btnNext") processApply(true,1); //v1.3 else if (msg_obj.control=="btnPrev") processApply(true,-1); else if ((msg_obj.control.slice(0,5)==="stars") && (msg_obj.control.slice(5)!=starRating)) { log("Rating change from "+starRating+" to "+msg_obj.control.slice(5),5); starRating = msg_obj.control.slice(5); strCommand = "SetAttr FILE \""+currFile.path+"\\"+currFile.name+"\" META \"rating:"+starRating+"\""; log(strCommand,4); cmd.runcommand(strCommand); } else if ((msg_obj.control=="btnAddToColl") && (dlg.Control("editAddToColl").value!="")) { var collTarget = "coll://"+(dlg.Control("editAddToColl").value); if (!DOpus.FSUtil.Exists(collTarget)) { strCommand = "\"/home/dopusrt.exe\" /col create /noclear \""+collTarget+"\""; log(strCommand,4); cmd.runcommand(strCommand); Script.Vars.Set("collTarget",dlg.Control("editAddToColl").value); } if (!DOpus.FSUtil.Exists(collTarget+"/"+String(currFile.name))) { strCommand = "Copy \""+String(currFile)+"\" TO \""+collTarget+"\" COPYTOCOLL=member WHENEXISTS=skip"; log(strCommand,4); cmd.runcommand(strCommand); } } else if (msg_obj.control=="btnCollToggle") { var currColl = "coll://"+dlg.Control("editAddToColl").value; if (DOpus.FSUtil.Exists(currColl)) { var currPath = String(currTab.path); if (currPath==currColl) var target = Script.Vars.Get("returnPath"); // Restore remembered target else { var target = currColl; Script.Vars.Set("returnPath",currPath); // Remember where to return to } if (DOpus.FSUtil.Exists(target)) { strCommand = "Go \""+target+"\" NEWTAB=findexisting"; log(strCommand,4); cmd.runcommand(strCommand); } } } else if (msg_obj.control.slice(0,10)==="btnImageH1") runHandler(imgHandler1); else if (msg_obj.control.slice(0,10)==="btnImageH2") runHandler(imgHandler2); else if (msg_obj.control.slice(0,10)==="btnImageH3") runHandler(imgHandler3); else if (msg_obj.control.slice(0,10)==="btnEditor1") runHandler(editor1); else if (msg_obj.control.slice(0,10)==="btnEditor2") runHandler(editor2); else if (msg_obj.control.slice(0,10)==="btnEditor3") runHandler(editor3); else if (msg_obj.control=="btnLocate") { strCommand = locateWithURL(Script.config.locateWith); if (strCommand.indexOf("mlat=")<0) strCommand = strCommand+intLatitude+","+intLongitude; else strCommand = strCommand+intLatitude+"&mlon="+intLongitude+"#map="+OSMzoom+"/"+intLatitude+"/"+intLongitude; log(strCommand,4); cmd.runcommand(strCommand); } else if (msg_obj.control=="btnApply") { var n = (nextAfterApply) ? 1 : 0; // v1.3 processApply(false,n); dlg.Control("btnApply").enabled = false; } else if (dlg.control("checkArchive").value!=currFile.fileattr.a) { var str = (dlg.control("checkArchive").value) ? "+a" : "-a"; log("Archive = "+str,4) var f = currFile.Open("m"); f.setattr(str); f.Close(); currFile = DOpus.FSUtil.GetItem(currFile); // See https://resource.dopus.com/t/attribute-change-not-recognised-in-fileattr-object/37002/3 } else if (dlg.control("checkReadOnly").value!=currFile.fileattr.r) { var str = (dlg.control("checkReadOnly").value) ? "+r" : "-r"; log("ReadOnly = "+str,4) var f = currFile.Open("m"); f.setattr(str); f.Close(); currFile = DOpus.FSUtil.GetItem(currFile); // See https://resource.dopus.com/t/attribute-change-not-recognised-in-fileattr-object/37002/3 } else if (dlg.control("checkHidden").value!=currFile.fileattr.h) { var str = (dlg.control("checkHidden").value) ? "+h" : "-h"; log("Hidden = "+str,4) var f = currFile.Open("m"); f.setattr(str); f.Close(); currFile = DOpus.FSUtil.GetItem(currFile); // See https://resource.dopus.com/t/attribute-change-not-recognised-in-fileattr-object/37002/3 } } else if (msg_obj.event=="hotkey") { log("msg_obj.control = "+msg_obj.control,4); if (msg_obj.control=="escape") break; // v1.1 - alternative means of exiting the dialog else if (msg_obj.control=="star0") dlg.control("stars0").value = true; // v1.2 else if (msg_obj.control=="star1") dlg.control("stars1").value = true; // v1.2 else if (msg_obj.control=="star2") dlg.control("stars2").value = true; // v1.2 else if (msg_obj.control=="star3") dlg.control("stars3").value = true; // v1.2 else if (msg_obj.control=="star4") dlg.control("stars4").value = true; // v1.2 else if (msg_obj.control=="star5") dlg.control("stars5").value = true; // v1.2 else if (msg_obj.control=="prefs") { // v1.2 strCommand = "Prefs PAGE=scripts:"+me.name; log(strCommand,4); cmd.runcommand(strCommand); } } else if (msg_obj.event=="editchange") { var fileExists = (currFile===false) ? false : DOpus.FSUtil.Exists(currFile); flgNameChanged = (fileExists) ? (dlg.Control("editName").value!=strName) : false; if (flgNameChanged) log("File name edited",4); flgCopyrightChanged = (fileExists) ? ((currFile.InGroup("Images")) && (dlg.Control("editProp2").value!=strCopyright)) : false; if (flgCopyrightChanged) log("Copyright edited",4); flgDescriptionChanged = (fileExists) ? ((!dlg.Control("editProp1").readonly) && (dlg.Control("editProp1").value!=strDesc)) : false; if (flgDescriptionChanged) log("Description edited",4); flgTagsChanged = (fileExists) ? (dlg.Control("editTags").value!=strTags) : false; if (flgTagsChanged) log("Tags edited",4); dlg.control("btnApply").enabled = (flgNameChanged || flgCopyrightChanged || flgDescriptionChanged || flgTagsChanged); } else if (msg_obj.event=="tab"){ if (msg_obj.value=="navigate") { currLister.update(); // Path has changed so force an update to the lister snapshot log("Navigated from "+currTab.displayed_label+" to "+currLister.activeTab.displayed_label,3); currTab = currLister.activeTab; watchTab(); // Path has changed so force the current file index to be rebuilt refreshDlg(); } else if (msg_obj.value=="select") { currTab.Update(); // Files may have been added or deleted log("Selection changed in "+currTab.displayed_label,3); var candidateFiles = (currTab.selected_files.count>0) ? currTab.selected_files : currTab.files; log("candidateFiles.count = "+candidateFiles.count,3); if (candidateFiles.count===0) { // No eligible files watchedTabs(String(currTab)) = -1; refreshDlg(); } else { // At least one eligible file var currFileIndex = -1; var focusFileIndex = -1; for (var i = 0; i < candidateFiles.count; i++) { if (candidateFiles(i).name===currFile.name) currFileIndex = i; if (candidateFiles(i).focus) focusFileIndex = i; if ((currFileIndex>-1) && (focusFileIndex>-1)) break; } watchedTabs(String(currTab)) = 0; if (focusFileIndex>-1) refreshDlg(focusFileIndex); // The file that has focus is selected else if (currFileIndex>-1) refreshDlg(currFileIndex); // The previous current file is still available else refreshDlg(currTab,0); // Focused file is not available, nor is the previous current file } } else if ((msg_obj.value==="activate") || (msg_obj.value=="srcdst")) { log("currTab.displayed_label = "+currTab.displayed_label,4); for (var i = 0; i < 10; i++) { // A delay may be needed for the new tab activation to complete currLister.Update(); // Tabs may have been added or removed log(i+": currLister.activeTab.displayed_label = "+currLister.activeTab.displayed_label,4); if (typeof currLister.activeTab.displayed_label==="string") break; DOpus.delay(msTabChange); } if (typeof currLister.activeTab.displayed_label==="string") { // Activation is complete currTab = currLister.activeTab; log("Tab ID = "+String(currTab),4); if (watchedTabs.exists(String(currTab))===false) watchTab(); refreshDlg(); } } } } while (msg_obj); log(me.version+ " session ended.",1); } function fmtAlt(intAltitude) { log("fmtAlt",6); return (typeof intAltitude==="number") ? intAltitude.toFixed(2) + " metres" : ""; } function fmtLatOrLong(LatOrLong) { log("fmtLatOrLong",6); if (typeof LatOrLong!=="number") return ""; var absolute = Math.abs(LatOrLong); var degrees = Math.floor(absolute); var minutesNotTruncated = (absolute - degrees) * 60; var minutes = Math.floor(minutesNotTruncated); var seconds = ((minutesNotTruncated - minutes) * 60).toFixed(6); var direction; if (intLatitude===LatOrLong) direction = (intLatitude>=0) ? "N" : "S"; else direction = (intLongitude>=0) ? "E" : "W"; return degrees + "° " + minutes + "' " + seconds + "\" " + direction; } function getAltitude(currFile) { log("getAltitude",6); try {var res = currFile.metadata.image.altitude} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="number") ? res : 0; } function getCopyright(currFile) { log("getCopyright",6); try {var res = currFile.metadata.image.copyright} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="string") ? res : ""; } function getDescription(currFile) { log("getDescription",6); try {var res = currFile.metadata.image.imagedesc} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="string") ? res : ""; } function getLatitude(currFile) { log("getLatitude",6); try {var res = currFile.metadata.image.latitude} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="number") ? res : 0; } function getLongitude(currFile) { log("getLongitude",6); try {var res = currFile.metadata.image.longitude} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="number") ? res : 0; } function getProdName(currFile) { log("getProdName",6); try {var res = currFile.metadata.exe.prodname} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="string") ? res : ""; } function getProdVersion(currFile) { log("getProdVersion",6); try {var res = currFile.metadata.exe.prodversion} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="string") ? res : ""; } function getRating(currFile) { log("getRating",6); try {var res = currFile.metadata.other.rating} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="number") ? res : 0; } function getUserComment(currFile) { log("getUserComment",6); try {var res = currFile.metadata.other.usercomment} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="string") ? res : ""; } function hasCoords() { log("hasCoords",6); try {var res = currFile.metadata.image.coords} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="string"); } function hasImageDescription() { log("hasImageDescription",6); try {var res = currFile.metadata.image.imagedesc} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="string"); } function hasImageDetails() { log("hasImageDetails",6); try {var res = currFile.metadata.image.isorating} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="string"); } function hasImageDimensions() { log("hasImageDimensions",6); try {var res = currFile.metadata.image.picwidth} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="number"); } function hasProdName() { log("hasProdName",6); try {var res = currFile.metadata.exe.prodname} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="string"); } function hasUserComment() { log("hasUserComment",6); try {var res = currFile.metadata.other.usercomment} catch(err) {log("err.message = " + err.message,5);} return (typeof res=="string"); } function isVersionOK(candidate){ log("isVersionOK",6); var isOK = DOpus.version.AtLeast(candidate); // Check minimum version requirements if (!isOK){ var str = "DOpus version "+candidate+" is required."; dlg.request(str,"OK","Version Check Failure"); log(str,0); } return isOK; } function log(str,i) { var lvl = (typeof i==="number") ? i : 0; if (dbg0) ? currFile.metadata.tags(0) : ""; for (var i = 1; i < n; i++) strTags = strTags+";"+currFile.metadata.tags(i); if ((strTags!="") && (semiTrail)) strTags+=";"; //v1.3 if (dlg.control("editTags").value!=strTags) dlg.control("editTags").value = strTags; return strTags; } function maybeRefresh(ctl,str) { log("maybeRefresh",6); if ((firstShow) || ((ctl.visible) && (ctl.value!==str))) ctl.value = str; return ctl.value; } function processApply(ask,next) { if ((!flgNameChanged) && (!flgCopyrightChanged) && (!flgDescriptionChanged) && (!flgTagsChanged)) { if (next!=undefined) refreshDlg(next); //v1.3 return; } if (ask==true) { cmd.runcommand("Play \"/windows/media/Windows Ding.wav\" QUIET"); var oneShot = DOpus.dlg; oneShot.request("Apply changes to editable field(s)?","Yes|No","Editable Field Changes"); if (oneShot.result==0) return; } if (flgNameChanged) { strCommand = "Rename FROM \""+currFile.path+"\\"+currFile.name+"\" "; strCommand = strCommand+"TO \""+dlg.Control("editName").value+"\""; log(strCommand,4); cmd.runcommand(strCommand); currTab.Update(); flgNameChanged = false; refreshDlg(); } if (flgCopyrightChanged) { var strCommand = "SetAttr FILE \""+currFile.path+"\\"+currFile.name+"\" "; strCommand = strCommand+"META \"copyright:"+dlg.Control("editProp2").value+"\""; log(strCommand,4); cmd.runcommand(strCommand); flgCopyrightChanged = false; } if (flgDescriptionChanged) { var strCommand = "SetAttr FILE \""+currFile.path+"\\"+currFile.name+"\" META \""; strCommand = currFile.InGroup("Images") ? strCommand+"imagedesc:" : strCommand+"usercomment:"; strCommand = strCommand+dlg.Control("editProp1").value+"\""; log(strCommand,4); cmd.runcommand(strCommand); flgDescriptionChanged = false; } if (flgTagsChanged) { var strCommand = "SetAttr FILE \""+currFile.path+"\\"+currFile.name+"\" "; strCommand = strCommand+"META \"tags:"+dlg.Control("editTags").value+"\""; log(strCommand,4); cmd.runcommand(strCommand); strTags = maybeRefreshTags(currFile); // In case the application of tags failed! See https://resource.dopus.com/t/untaggable-file/37052 flgTagsChanged = false; } if (next!=undefined) refreshDlg(next); //v1.3 } function processDialogButtons(fileItem) { log("processDialogButtons",6); var candidateFiles = (currTab.selected_files.count>0) ? currTab.selected_files : currTab.files; dlg.control("btnNext").visible = (candidateFiles.count>1); dlg.control("btnNext").enabled = (candidateFiles.count>1); dlg.control("btnPrev").visible = (candidateFiles.count>1); dlg.control("btnPrev").enabled = (candidateFiles.count>1); var showImageButtons = ((isValidImage) && (fileExists)); // v1.2 dlg.control("btnImageH1").visible = ((showImageButtons) && (imgHandler1!==false)); dlg.control("btnImageH2").visible = ((showImageButtons) && (imgHandler2!==false)); dlg.control("btnImageH3").visible = ((showImageButtons) && (imgHandler3!==false)); if (showImageButtons) { dlg.control("btnImageH1").label = (imgHandler1Label==="") ? "HandlerA" : imgHandler1Label; dlg.control("btnImageH2").label = (imgHandler2Label==="") ? "HandlerB" : imgHandler2Label; dlg.control("btnImageH3").label = (imgHandler3Label==="") ? "HandlerC" : imgHandler3Label; } var showEditorButtons = ((dlg.Control("btnShow").enabled) && (!isValidImage) && (!isMovie) && (!isMusic) && (!isProgram) && (!isArchive) && (!isDocument) && (!isPDF)); //v1.2 dlg.control("btnEditor1").visible = ((showEditorButtons) && (editor1!==false)); dlg.control("btnEditor2").visible = ((showEditorButtons) && (editor2!==false)); dlg.control("btnEditor3").visible = ((showEditorButtons) && (editor3!==false)); if (showEditorButtons) { dlg.control("btnEditor1").label = (editor1Label==="") ? "Editor1" : editor1Label; dlg.control("btnEditor2").label = (editor1Label==="") ? "Editor2" : editor2Label; dlg.control("btnEditor3").label = (editor1Label==="") ? "Editor3" : editor3Label; } dlg.control("btnRun").visible = (((isProgram) || (isDocument) || (isPDF))); dlg.control("btnApply").visible = true; dlg.control("btnApply").enabled = false; } function processFileAttr(fileItem) { log("processFileAttr",6); var isAttributable = ((fileExists) && (!isInArchive)); // v1.2 dlg.control("grpAttr").visible = (isAttributable); dlg.control("checkArchive").visible = (isAttributable); dlg.control("checkReadOnly").visible = (isAttributable); dlg.control("checkHidden").visible = (isAttributable); if (!isAttributable) return; if (dlg.control("checkArchive").value!=fileItem.fileattr.a) dlg.control("checkArchive").value = fileItem.fileattr.a; if (dlg.control("checkReadOnly").value!=fileItem.fileattr.r) dlg.control("checkReadOnly").value = fileItem.fileattr.r; if (dlg.control("checkHidden").value!=fileItem.fileattr.h) dlg.control("checkHidden").value = fileItem.fileattr.h; } function processFileInfo() { log("processFileInfo",6); var str = "Location"; var modDate = (fileExists) ? DOpus.FSUtil.GetItem(currFile).modify : ""; if ((currFileIndex>-1) && (currTab.files.count>0)) { var candidateFiles = (currTab.selected_files.count>0) ? currTab.selected_files : currTab.files; str ="File "+(currFileIndex+1)+" of "+(candidateFiles.count); if (isOffline) str = "Offline "+str; if ((isColl) || (isLib)) str = str+" in "+currTab.path; if (fileExists) str = str+" - last modified "+modDate.format(); } dlg.Control("grpFileInfo").label = str; dlg.control("lblName").visible = (!currFile===false); // May not exist if part of a collection dlg.control("editName").visible = (!currFile===false); // May not exist if part of a collection dlg.control("editName").readonly = (!fileExists); str = (currFile===false) ? "" : currFile.name; strName = maybeRefresh(dlg.control("editName"),str); str = (currFile===false) ? currTab.displayed_label : DOpus.FSUtil.Resolve(currFile.path); maybeRefresh(dlg.control("editPath"),str); } function processFilePreview() { log("processFilePreview",6); var str = (fileSize===false) ? "" : fileSize; if (currTab.files.count==0) {dlg.Control("btnShow").enabled = false; str = "No Files in Folder";} else if (!fileExists) {dlg.Control("btnShow").enabled = false; str = "Inaccessible File";} else if (isInArchive) {dlg.Control("btnShow").enabled = true; str = str+" File in Archive - Click to Preview";} else if (isArchive) {dlg.Control("btnShow").enabled = true; str = str+" Archive - Click to Open in Tab";} else if (isValidImage) {dlg.Control("btnShow").enabled = true; str = str+" Image - Click to Preview";} // v1.2 else if (isImage) {dlg.Control("btnShow").enabled = false; str = str+" Invalid Image - Unable to Preview";} // v1.2 else if (isMovie) {dlg.Control("btnShow").enabled = true; str = str+" Movie - Click to Preview";} else if (isDocument) {dlg.Control("btnShow").enabled = true; str = str+" Document - Click to Preview";} else if (isPDF) {dlg.Control("btnShow").enabled = true; str = str+" PDF - Click to Preview";} else if (isProgram) {dlg.Control("btnShow").enabled = true; str = str+" Program - Click for Hex Preview";} else {dlg.Control("btnShow").enabled = true; str = str+" File - Click to Preview";} dlg.Control("grpPreview").label = str; if (isValidImage) { // v1.2 dlg.Control("staticImage").visible = false; // Prevent flicker if image needs to be rotated dlg.Control("staticImage").label = DOpus.LoadImage(currFile,msThumbLoad); var rot = currFile.metadata.image.rotation; dlg.Control("staticImage").rotate = (rot==0) ? rot : 360 - rot; dlg.Control("staticImage").visible = true; } else if (isImage) dlg.Control("staticImage").label = ""; // v1.2 else { try {dlg.Control("staticImage").label = DOpus.LoadThumbnail(currFile,msThumbLoad);} catch(err) {log("err.message = " + err.message,5);} } } function processFileProperties() { log("processFileProperties",6); var showProp = (isImage) ? (isValidImage) : ((fileExists) && (!isInArchive)); // v1.2 dlg.control("grpProp").visible = (showProp); dlg.control("lblProp1").visible = (showProp); dlg.control("editProp1").visible = (showProp); var showProp2 = ((showProp) && ((isValidImage) || (isProgram))); // v1.2 dlg.control("lblProp2").visible = (showProp2); dlg.control("editProp2").visible = (showProp2); if (!showProp) return; dlg.Control("grpProp").label = (isProgram) ? "Program Properties" : "Editable Properties"; if (isValidImage) { // v1.2 dlg.control("lblProp1").label = "Description:"; strDesc = maybeRefresh(dlg.control("editProp1"),getDescription(currFile)); dlg.Control("editProp1").readonly = false; dlg.Control("lblProp2").label = "Copyright:"; strCopyright = maybeRefresh(dlg.control("editProp2"),getCopyright(currFile)); dlg.Control("editProp2").readonly = false; } else if (isProgram) { dlg.Control("lblProp1").label = "Program:"; maybeRefresh(dlg.control("editProp1"),getProdName(currFile)); dlg.Control("editProp1").readonly = true; dlg.Control("lblProp2").label = "Version:"; maybeRefresh(dlg.control("editProp2"),getProdVersion(currFile)); dlg.Control("editProp2").readonly = true; } else { dlg.control("lblProp1").label = "Comment:"; strDesc = maybeRefresh(dlg.control("editProp1"),getUserComment(currFile)); dlg.Control("editProp1").readonly = false; dlg.control("lblProp2").visible = false; dlg.control("editProp2").visible = false; } } function processFileRating(fileItem) { log("processFileRating",6); var isRateable = ((fileExists) && (!isInArchive)); // v1.2 dlg.control("grpStars").visible = (isRateable); dlg.control("stars0").visible = (isRateable); dlg.control("stars1").visible = (isRateable); dlg.control("stars2").visible = (isRateable); dlg.control("stars3").visible = (isRateable); dlg.control("stars4").visible = (isRateable); dlg.control("stars5").visible = (isRateable); if (!isRateable) return; starRating = getRating(fileItem); var str = "stars"+starRating; if (dlg.control(str).value==false) { dlg.control(str).value = true; log("dlg.control(\""+str+"\").value = "+dlg.control(str).value,5); } } function processFileTags(fileItem) { log("processFileTags",6); var isTaggable = ((fileExists) && (!isInArchive)); // v1.2 dlg.control("grpTags").visible = (isTaggable); dlg.control("editTags").visible = (isTaggable); dlg.control("editTags").enabled = (isTaggable); if (isTaggable) strTags = maybeRefreshTags(fileItem); } function processImageCameraInfo(fileItem,gotImageDetails) { log("processImageCameraInfo",6); dlg.Control("grpCamera").visible = (gotImageDetails); dlg.Control("lblCameraMake").visible = (gotImageDetails); dlg.Control("editCameraMake").visible = (gotImageDetails); dlg.Control("lblCameraModel").visible = (gotImageDetails); dlg.Control("editCameraModel").visible = (gotImageDetails); if (!gotImageDetails) return; maybeRefresh(dlg.control("editCameraMake"),fileItem.metadata.image.cameramake); maybeRefresh(dlg.control("editCameraModel"),fileItem.metadata.image.cameramodel); } function processImageDetails(fileItem,gotImageDetails) { log("processImageDetails",6); dlg.Control("grpImgDetails").visible = (gotImageDetails); dlg.Control("grpImgDetSep").visible = (gotImageDetails); dlg.Control("lblExposure").visible = (gotImageDetails); dlg.Control("editExposure").visible = (gotImageDetails); dlg.Control("lblISO").visible = (gotImageDetails); dlg.Control("editISO").visible = (gotImageDetails); dlg.Control("lblFocalLength").visible = (gotImageDetails); dlg.Control("editFocalLength").visible = (gotImageDetails); dlg.Control("lblFStop").visible = (gotImageDetails); dlg.Control("editFStop").visible = (gotImageDetails); dlg.Control("lblFlash").visible = (gotImageDetails); dlg.Control("editFlash").visible = (gotImageDetails); dlg.Control("lblDateTaken").visible = (gotImageDetails); dlg.Control("editDateTaken").visible = (gotImageDetails); if (!gotImageDetails) return; maybeRefresh(dlg.control("editExposure"),"1/"+(1 / fileItem.metadata.image.exposuretime).toFixed(0)+" secs"); maybeRefresh(dlg.control("editISO"),fileItem.metadata.image.isorating); var focalLength = (typeof fileItem.metadata.image.focallength=="number") ? fileItem.metadata.image.focallength+" mm" : ""; maybeRefresh(dlg.control("editFocalLength"),focalLength); // v1.1 - handle undefined focal length maybeRefresh(dlg.control("editFStop"),"f/"+fileItem.metadata.image.fnumber); maybeRefresh(dlg.control("editFlash"),fileItem.metadata.image.flash); maybeRefresh(dlg.control("editDateTaken"),fileItem.metadata.image.datetaken); } function processImageDimensions(fileItem,gotImageDimensions) { log("processImageDimensions",6); dlg.Control("grpImgDim").visible = (gotImageDimensions); dlg.Control("lblWidth").visible = (gotImageDimensions); dlg.Control("editWidth").visible = (gotImageDimensions); dlg.Control("lblHeight").visible = (gotImageDimensions); dlg.Control("editHeight").visible = (gotImageDimensions); dlg.Control("lblBitDepth").visible = (gotImageDimensions); dlg.Control("editBitDepth").visible = (gotImageDimensions); dlg.Control("lblPrintSize").visible = (gotImageDimensions); dlg.Control("editPrintSize").visible = (gotImageDimensions); if (!gotImageDimensions) return; maybeRefresh(dlg.control("editWidth"),fileItem.metadata.image.picwidth); maybeRefresh(dlg.control("editHeight"),fileItem.metadata.image.picheight); maybeRefresh(dlg.control("editBitDepth"),fileItem.metadata.image.picdepth); var prtMaxWidth = fileItem.metadata.image.picwidth / dpi; var prtMaxHeight = fileItem.metadata.image.picheight / dpi; if (metric) { prtMaxWidth = prtMaxWidth * 2.54; prtMaxHeight = prtMaxHeight * 2.54; } prtMaxWidth = prtMaxWidth.toFixed(2); prtMaxHeight = prtMaxHeight.toFixed(2); var units = (metric) ? "cm" : "inches"; maybeRefresh(dlg.control("editPrintSize"),prtMaxWidth+" "+units+" x "+prtMaxHeight+" "+units); } function processImageGPS(fileItem,gotImageDetails) { log("processImageGPS",6); var gotLocation = (isValidImage) ? hasCoords() : false; // v1.2 dlg.Control("grpGPS").visible = gotLocation; dlg.Control("lbAltitude").visible = (gotLocation); dlg.Control("lblLatitude").visible = (gotLocation); dlg.Control("lblLongitude").visible = (gotLocation); dlg.Control("editAltitude").visible = (gotLocation); dlg.Control("editLatitude").visible = (gotLocation); dlg.Control("editLongitude").visible = (gotLocation); dlg.Control("btnLocate").visible = (gotLocation); if (!gotImageDetails) return; intAltitude = getAltitude(fileItem); maybeRefresh(dlg.control("editAltitude"),fmtAlt(intAltitude)); intLatitude = getLatitude(fileItem); maybeRefresh(dlg.control("editLatitude"),fmtLatOrLong(intLatitude)); intLongitude = getLongitude(fileItem); maybeRefresh(dlg.control("editLongitude"),fmtLatOrLong(intLongitude)); dlg.Control("btnLocate").label = "Locate with "+locateWith(1+Script.config.locatewith); } function refreshDlg(ixOffSet) { log("refreshDlg",6); currTab.Update(); var offSet = (typeof ixOffSet==="number") ? ixOffSet : 0; if (!watchedTabs.exists(String(currTab))) watchTab(); // A tab has been added - e.g. by dragging currFileIndex = watchedTabs(String(currTab)); // If the associated index is -1 there are no files associated with this tab if (currFileIndex<0) currFile = false; else { var candidateFiles = (currTab.selected_files.count>0) ? currTab.selected_files : currTab.files; if (candidateFiles.count===1) currFileIndex = 0; else { currFileIndex = currFileIndex + offSet; if (currFileIndex>candidateFiles.count-1) currFileIndex = 0; else if (currFileIndex<0) currFileIndex = candidateFiles.count-1; } } watchedTabs(String(currTab)) = currFileIndex; // Update the saved index for this tab currFile = (currFileIndex<0) ? false : DOpus.FSUtil.Resolve(candidateFiles(currFileIndex)); // Resolve the likes of lib:// paths if (!currFile==false) currFile = DOpus.FSUtil.GetItem(currFile); // Create an item object for the current file log("currfile = "+currFile,3); fileExists = (currFile===false) ? false : DOpus.FSUtil.Exists(currFile); fileSize = (currFile===false) ? false : currFile.size.fmt; isImage = (currFile===false) ? false : currFile.InGroup("Images"); isValidImage = ((isImage) && (currFile.metadata=="image")); // v1.2 if (isImage) log("isValidImage = "+isValidImage,5); // v1.2 isMovie = (currFile===false) ? false : currFile.ingroup("Movies"); isMusic = (currFile===false) ? false : currFile.ingroup("Music"); isProgram = (currFile===false) ? false : currFile.ingroup("Programs"); isArchive = (currFile===false) ? false : currFile.ingroup("Archives"); isDocument = (currFile===false) ? false : currFile.ingroup("Documents"); isPDF = (currFile===false) ? false : (currFile.ext.toLowerCase()==".pdf"); isInArchive = (currFile===false) ? false : (!DOpus.FSUtil.GetItem(currFile.path).is_dir); strPath = String(currTab.path); isSpecial = ((strPath.indexOf(":{")>-1) || (strPath.indexOf("Lib:")===0) || (strPath.indexOf("Coll:")===0)); isColl = (strPath.indexOf("coll:")===0); isLib = (strPath.indexOf("lib:")===0); isOffline = (currFile===false) ? false : currFile.fileattr.offline; processFilePreview(); processFileInfo(); processFileProperties(); var gotImageDetails = (isValidImage) ? hasImageDetails() : false; //v1.2 processImageCameraInfo(currFile,gotImageDetails); var gotImageDimensions = (isValidImage) ? hasImageDimensions() : false; //v1.2 processImageDimensions(currFile,gotImageDimensions); processImageDetails(currFile,gotImageDetails); processImageGPS(currFile,gotImageDetails); processFileRating(currFile); processFileAttr(currFile); processFileTags(currFile); processDialogButtons(currFile); } function runHandler(handler) { log("runHandler",6); cmd.clearfiles(); // Only operate cmd.addfile(currFile); // on the current file strCommand = "\""+handler+"\" \"{f}\""; cmd.clear(); // Only execute cmd.addline(strCommand); // the specified handler log(strCommand,4); cmd.run(); // This technique allows the specified handler to operate with files in an archive } function watchTab() { log("watchTab",6); var strPath = String(currTab.path); var isSpecial, str; if (strPath==="") isSpecial = true; // Empty tab else { var resPath = DOpus.FSUtil.Resolve(currTab.path); str = (strPath===String(resPath)) ? strPath : strPath+" ("+resPath+")"; log("Watched path is "+str,3); isSpecial = ((strPath.indexOf(":{")>-1) || (strPath.indexOf("Lib:")===0) || (strPath.indexOf("Coll:")===0) || (strPath.indexOf("localhost")===2)); } var candidateFiles = (currTab.selected_files.count>0) ? currTab.selected_files : currTab.files; str = (isSpecial) ? "activate,navigate,srcdst" : "activate,navigate,select,srcdst"; log("Watching "+currTab.displayed_label+" ("+candidateFiles.count+" files) "+str,3); dlg.watchtab(currTab,str); watchedTabs(String(currTab)) = (candidateFiles.count===0) ? -1 : 0; } ==SCRIPT RESOURCES