/************************************************************************** * * @@@BUILDINFO@@@ 00globals-2.jsx 2.0.1.66 04-May-2007 * Copyright 2006-2007 Adobe Systems Incorporated * All Rights Reserved. * * NOTICE: All information contained herein is, and remains the property of * Adobe Systems Incorporated and its suppliers, if any. The intellectual * and technical concepts contained herein are proprietary to Adobe Systems * Incorporated and its suppliers and may be covered by U.S. and Foreign * Patents,patents in process,and are protected by trade secret or copyright * law. Dissemination of this information or reproduction of this material * is strictly forbidden unless prior written permission is obtained from * Adobe Systems Incorporated. **************************************************************************/ // // set app.resourceFolder and app.requiredFolder // if( $.os.indexOf( 'Windows' ) > -1 ) { app.resourceFolder = Folder (Folder.appPackage + "/required"); var f = app.resourceFolder.resolve(); if (f) app.resourceFolder = f; app.requiredFolder = app.resourceFolder; app.resourceFolder += '/icons/'; } else { app.requiredFolder = Folder.appPackage.absoluteURI + '/Contents/SharedSupport/Required/'; app.resourceFolder = Folder.appPackage.absoluteURI + '/Contents/Resources/'; } /////////////////////////////////////////////////////////////////////////////// const _win = (File.fs == "Windows"); // the list of all non-document panes var panes = []; // The list of all document var documents = []; // The current document var document = null; // All menus, grouped by name (like e.g. menus.file) const menus = {}; // target manager var targetMgr = null; // global broadcaster var globalBroadcaster = null; // favorites var favorites = null; // workspace visibility var menuToggleWS = null; var workspaceVisible = true; var wsHideOnNextStartup = false; // in shutdown var appInShutDown = false; /////////////////////////////////////////////////////////////////////////////// // A list of predefined HTML colors. const colors = { AliceBlue : 0xF0F8FF, AntiqueWhite : 0xFAEBD7, Aqua : 0x00FFFF, Aquamarine : 0x7FFFD4, Azure : 0xF0FFFF, Beige : 0xF5F5DC, Bisque : 0xFFE4C4, Black : 0x000000, BlanchedAlmond : 0xFFEBCD, Blue : 0x0000FF, BlueViolet : 0x8A2BE2, Brown : 0xA52A2A, BurlyWood : 0xDEB887, CadetBlue : 0x5F9EA0, Chartreuse : 0x7FFF00, Chocolate : 0xD2691E, Coral : 0xFF7F50, CornflowerBlue : 0x6495ED, Cornsilk : 0xFFF8DC, Crimson : 0xDC143C, Cyan : 0x00FFFF, DarkBlue : 0x00008B, DarkCyan : 0x008B8B, DarkGoldenRod : 0xB8860B, DarkGray : 0xA9A9A9, DarkGreen : 0x006400, DarkKhaki : 0xBDB76B, DarkMagenta : 0x8B008B, DarkOliveGreen : 0x556B2F, Darkorange : 0xFF8C00, DarkOrchid : 0x9932CC, DarkRed : 0x8B0000, DarkSalmon : 0xE9967A, DarkSeaGreen : 0x8FBC8F, DarkSlateBlue : 0x483D8B, DarkSlateGray : 0x2F4F4F, DarkTurquoise : 0x00CED1, DarkViolet : 0x9400D3, DeepPink : 0xFF1493, DeepSkyBlue : 0x00BFFF, DimGray : 0x696969, DodgerBlue : 0x1E90FF, Feldspar : 0xD19275, FireBrick : 0xB22222, FloralWhite : 0xFFFAF0, ForestGreen : 0x228B22, Fuchsia : 0xFF00FF, Gainsboro : 0xDCDCDC, GhostWhite : 0xF8F8FF, Gold : 0xFFD700, GoldenRod : 0xDAA520, Gray : 0x808080, Green : 0x008000, GreenYellow : 0xADFF2F, HoneyDew : 0xF0FFF0, HotPink : 0xFF69B4, IndianRed : 0xCD5C5C, Indigo : 0x4B0082, Ivory : 0xFFFFF0, Khaki : 0xF0E68C, Lavender : 0xE6E6FA, LavenderBlush : 0xFFF0F5, LawnGreen : 0x7CFC00, LemonChiffon : 0xFFFACD, LightBlue : 0xADD8E6, LightCoral : 0xF08080, LightCyan : 0xE0FFFF, LightGoldenRodYellow: 0xFAFAD2, LightGray : 0xD3D3D3, LightGreen : 0x90EE90, LightPink : 0xFFB6C1, LightSalmon : 0xFFA07A, LightSeaGreen : 0x20B2AA, LightSkyBlue : 0x87CEFA, LightSlateBlue : 0x8470FF, LightSlateGray : 0x778899, LightSteelBlue : 0xB0C4DE, LightYellow : 0xFFFFE0, Lime : 0x00FF00, LimeGreen : 0x32CD32, Linen : 0xFAF0E6, Magenta : 0xFF00FF, Maroon : 0x800000, MediumAquaMarine : 0x66CDAA, MediumBlue : 0x0000CD, MediumOrchid : 0xBA55D3, MediumPurple : 0x9370D8, MediumSeaGreen : 0x3CB371, MediumSlateBlue : 0x7B68EE, MediumSpringGreen : 0x00FA9A, MediumTurquoise : 0x48D1CC, MediumVioletRed : 0xC71585, MidnightBlue : 0x191970, MintCream : 0xF5FFFA, MistyRose : 0xFFE4E1, Moccasin : 0xFFE4B5, NavajoWhite : 0xFFDEAD, Navy : 0x000080, OldLace : 0xFDF5E6, Olive : 0x808000, OliveDrab : 0x6B8E23, Orange : 0xFFA500, OrangeRed : 0xFF4500, Orchid : 0xDA70D6, PaleGoldenRod : 0xEEE8AA, PaleGreen : 0x98FB98, PaleTurquoise : 0xAFEEEE, PaleVioletRed : 0xD87093, PapayaWhip : 0xFFEFD5, PeachPuff : 0xFFDAB9, Peru : 0xCD853F, Pink : 0xFFC0CB, Plum : 0xDDA0DD, PowderBlue : 0xB0E0E6, Purple : 0x800080, Red : 0xFF0000, RosyBrown : 0xBC8F8F, RoyalBlue : 0x4169E1, SaddleBrown : 0x8B4513, Salmon : 0xFA8072, SandyBrown : 0xF4A460, SeaGreen : 0x2E8B57, SeaShell : 0xFFF5EE, Sienna : 0xA0522D, Silver : 0xC0C0C0, SkyBlue : 0x87CEEB, SlateBlue : 0x6A5ACD, SlateGray : 0x708090, Snow : 0xFFFAFA, SpringGreen : 0x00FF7F, SteelBlue : 0x4682B4, Tan : 0xD2B48C, Teal : 0x008080, Thistle : 0xD8BFD8, Tomato : 0xFF6347, Turquoise : 0x40E0D0, Violet : 0xEE82EE, VioletRed : 0xD02090, Wheat : 0xF5DEB3, White : 0xFFFFFF, WhiteSmoke : 0xF5F5F5, Yellow : 0xFFFF00, YellowGreen : 0x9ACD32 }; // Global Alert box that is localizable and displays an error title function messageBox (msg) { var title = app.title + ' ' + app.version; if (msg [0] == "$") msg = localize.apply (this, arguments); alert (msg, title); } // Global Error box that is localizable and displays an error title function errorBox (msg) { var target = app.title + ' ' + app.version; var title = localize ("$$$/ESToolkit/Alerts/ErrorTitle=%1 Error", target); if (msg [0] == "$") msg = localize.apply (this, arguments); alert (msg, title, true); } // Global Confirm box that is localizable and displays the right title function queryBox (msg) { var title = app.title + ' ' + app.version; if (msg [0] == "$") msg = localize.apply (this, arguments); return confirm (msg, false, title); } // A little modeless dialog floating in the middle of the window // This dialog displays short, one-line messages. Use an empty message // or no arguments to hide the dialog. The message may take additional // arguments, and it is passed to localize(). // If cancelCB is supplied, the floatingMessage has a Cancel button, // and if that button is clicked, cancelCB (userData) is called. var floatDlg = null; var floatDlgCB = null; function floatingMessage (msg) { // Hide any callback floater if (floatDlgCB && floatDlgCB.visible) { floatDlgCB.maxWidth = 0; floatDlgCB.hide(); } if (!floatDlg && msg) { floatDlg = new Window ("palette { msg: StaticText { } }"); floatDlg.text = app.title + ' ' + app.version; floatDlg.maxWidth = 0; } if (msg) { if (msg [0] == "$") msg = localize.apply (this, arguments); var uiMsg = floatDlg.msg; uiMsg.text = msg; var size = uiMsg.graphics.measureString (msg); if (size.width > floatDlg.maxWidth) { floatDlg.maxWidth = size.width; uiMsg.size = size; floatDlg.layout.layout (true); } floatDlg.center (Window.children[0]); floatDlg.show(); } else if (floatDlg) { floatDlg.maxWidth = 0; floatDlg.hide(); } } // Same as above; additional arguments to the message follow the userData argument. // The floatingMessage has a Cancel button, and if that button is clicked, // cancelCB (userData) is called. // IMPORTANT: while processing, call app.pumpEventLoop() to enable the Cancel button! function floatingMessageCB (msg, cancelCB, userData) { // Hide any non-callback floater if (floatDlg && floatDlg.visible) { floatDlg.maxWidth = 0; floatDlg.hide(); } if (!floatDlgCB && msg) { floatDlgCB = new Window ( "palette { msg: StaticText { },\ btn: Button { text:'$$$/CT/ExtendScript/UI/Cancel=&Cancel', properties:{name:'cancel'} } }"); floatDlgCB.text = app.title + ' ' + app.version; floatDlgCB.btn.onClick = function() { this.cancelCB (this.userData); } } if (msg) { floatDlgCB.btn.cancelCB = cancelCB; floatDlgCB.btn.userData = userData; if (msg [0] == "$") { var args = [msg]; for (var i = 3; i < arguments.length; i++) args.push (arguments [i]); msg = localize.apply (this, args); } var uiMsg = floatDlgCB.msg; uiMsg.text = msg; var size = uiMsg.graphics.measureString (msg); if (size.width > floatDlgCB.maxWidth) { floatDlgCB.maxWidth = size.width; uiMsg.size = size; floatDlgCB.layout.layout (true); } floatDlgCB.center (Window.children[0]); floatDlgCB.show(); // Disable the app app.enabled = false; } else if (floatDlgCB) { floatDlgCB.maxWidth = 0; floatDlgCB.hide(); // re-enable the app app.enabled = true; } } /////////////////////////////////////////////////////////////////// // // ProgressBox // // The ProgressBox displays a progress dialog. The ctor takes a // text which is localized. The ctor may take additional arguments. // We have these functions: // setText (msg) - set text (additional args permitted) // setProgress (val[, max]) - set progress. Returns false on abort. // stop() - hide the dialog. // /////////////////////////////////////////////////////////////////// function ProgressBox (msg) { this.dlg = new Window ( "palette { \ msg: StaticText { \ alignment : 'left', \ }, \ bar: Progressbar { \ preferredSize: [200, 20], \ }, \ btn: Button { \ text: '$$$/CT/ExtendScript/UI/Cancel=&Cancel', \ properties: { \ name :'cancel' \ } \ } \ }"); if (msg [0] == "$") msg = localize.apply (this, arguments); this.dlg.text = app.title + ' ' + app.version; this.dlg.btn.self = this; this.dlg.btn.onClick = function() { this.self.aborted = true; this.self.stop(); } this.dlg.bar.maxvalue = 100; this.maxWidth = 0; this.aborted = false; this.setText (msg); this.dlg.center (Window.children [0]); this.dlg.show(); app.enabled = false; } ProgressBox.prototype.setText = function (msg) { if (this.dlg) { if (msg [0] == "$") msg = localize.apply (this, arguments); var uiMsg = this.dlg.msg; uiMsg.text = msg; var size = uiMsg.graphics.measureString (msg); if (size.width > this.maxWidth) { this.maxWidth = size.width; uiMsg.size = size; this.dlg.layout.layout (true); } } } ProgressBox.prototype.increment = function (n) { if (!this.dlg || this.aborted) return false; if (!n) n = 1; return this.setProgress (this.dlg.bar.value + n); } ProgressBox.prototype.setProgress = function (n, end) { var ok = app.pumpEventLoop (true); ok &= (!this.aborted && (this.dlg != null)); if (ok) { if (end != undefined) this.dlg.bar.maxvalue = end; this.dlg.bar.value = n; } return ok; } ProgressBox.prototype.getRemainingProgress = function () { var n = 0; if (this.dlg) n = this.dlg.bar.maxvalue - this.dlg.bar.value; return n; } Progressbar.prototype.disableCancel = function() { this.dlg.btn.enabled = false; } ProgressBox.prototype.stop = function() { if (this.dlg) this.dlg.hide(); this.dlg = null; app.enabled = true; } /////////////////////////////////////////////////////////////////// // // print() // /////////////////////////////////////////////////////////////////// function print() { if (console) { var s = ""; for (var i = 0; i < arguments.length; i++) s += arguments [i]; console.print (s); } } // // wait for BridgeTalk // function wait( abortFct, timeout ) { var ret = false; if( abortFct ) { if( !timeout ) timeout = 50000; var then = new Date; while( abortFct() ) { BridgeTalk.pump(); var now = new Date; if( (now - then) > timeout ) return ret; } ret = true; } return ret; } // // enable/disable icon buttons // IconButton.prototype.setEnabled = function( state ) { if( !this.stateCount ) this.stateCount = 0; if( state ) { this.stateCount--; if( this.stateCount < 0 ) this.stateCount = 0; } else { this.stateCount++; } this.enabled = state;//(this.stateCount == 0 ); // this.icon = this.enabled ? this.enabledIcon : this.disabledIcon; } /////////////////////////////////////////////////////////////////// // // Delayed Tasks // call addDelayedTask (foo) to add a function that is executed // about 20 msecs after this function has been called. If there // are multiple delayed functions, the latest function is added // to the stack of functions to be executed. The function should // not take long to execute, and it should not alter any visible. // Only one instance of a funtcion is added. // /////////////////////////////////////////////////////////////////// function addDelayedTask (foo, param1, param2, param3) { $.bp (typeof foo != "function"); for (var i = 0; i < delayedTasks.length; i++) { if( delayedTasks[i].funct == foo && delayedTasks[i].arg1 == param1 && delayedTasks[i].arg2 == param2 && delayedTasks[i].arg03 == param3 ) { // foo is there already - remove delayedTasks.splice (i, 1); break; } } delayedTasks.push( { funct:foo, arg1:param1, arg2:param2, arg3:param3 } ); // app.onStartup sets delayedTaskID to 0 to signal that running // these tasks is OK now. if (delayedTasks.length && delayedTaskID == 0) delayedTaskID = app.scheduleTask ("delayedTaskExec()", 20, true); } // app.onStartup() calls this function at the end to get things going // that vae accumulated during startup. function startDelayedTasks() { delayedTaskID = 0; if (delayedTasks.length) delayedTaskID = app.scheduleTask ("delayedTaskExec()", 20, true); } var delayedTasks = []; var delayedTaskID = -1; function delayedTaskExec() { var foo = delayedTasks[0].funct; var arg1 = delayedTasks[0].arg1; var arg2 = delayedTasks[0].arg2; var arg3 = delayedTasks[0].arg3; delayedTasks.shift(); foo( arg1, arg2, arg3 ); if (!delayedTasks.length) { app.cancelTask (delayedTaskID); delayedTaskID = 0; } } /////////////////////////////////////////////////////////////////////////////// // // string utils // function stripWS( str ) { var tmp = stripLeadingWS( str ); tmp = stripTrailingWS( tmp ); return tmp; } function stripLeadingWS( str ) { for( var i=0; i= str.length ) return ''; else return str.substring( i+1 ); } } return str; } function stripTrailingWS( str ) { for( var i=str.length-1; i>=0; i-- ) { var ch = str.charAt(i); if( ch != ' ' && ch != '\t' && ch != '\n' ) { if( i+1 >= str.length ) return str; else return str.substr( 0, i+1 ); } } return str; }