/************************************************************************** * * @@@BUILDINFO@@@ 35omvData-2.jsx 2.0.1.63 27-Mar-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. **************************************************************************/ // Object Model Viewer Data. // For dynamic targets, the ESTK stores the mined XML into app.prefsFolder. // The file name is omv$btid$dictname.xml, e.g. omv$indesign-5.0-en_us$main.xml. // Create an OMV data provider. Takes the BridgeTalk ID of the target. // Properties: // btID the full BridgeTalk ID if installed, the bare name if not // xml the original XML // map a copy of the XML map, single-level // dict the dictionary name for dynamic mining, null otherwise // file a File instance pointing to the OMV file to load // title the title of the TOC // dynamic true if the target is dynamic and can be mined // loaded true if the xml is complete // menu the menu command item (if we need to disable) // ui null if no UI yet, the OMV instance otherwise // asked true if the user has been asked if he wants to load the OMV data // loadOK true if loading is OK because user agreed // dlg a progress dialog if present; if aborted, this becomes null // showProgress true if the OMV UI should show a progress dialog function OMVData (btID, dictOrFile) { this.btID = btID; this.dict = (typeof dictOrFile == "string") ? dictOrFile : null; this.file = (dictOrFile instanceof File) ? dictOrFile : null; this.menu = null; this.ui = this.xml = this.map = null; this.loaded = false; this.dynamic = (this.dict != null); this.asked = this.loadOK = (btID == "estoolkit-2.0"); this.dlg = null; this.showProgress = !this.loadOK; OMVData.setData (this); } // The OMVData.instances object contains all loaded OMV data stored under // their BT name, either with the simple BT name, or with a '$' and a // dictionary name attached. Each entry is an array, filled with all main // OMVs (OMVs containing a title attribute in their map element). OMVData.instances = {} // The OMVData.files object contains all OMV instances stored under the // files that the OMV has loaded. Each entry is the OMV instance. OMVData.files = {} // This is the location of where to create the next menu item. OMVData.menuItemLocation = "at the beginning of help"; // This is a running count for the creation of menu IDs. OMVData.menuItemCount = 0; // An object containing the last target, engine, text, and result for getCodeHints(). OMVData.lastFindInfo = { target:"", engine:"", text:"", found:null }; // Set up all OMV entries in the Help menu. When a menu item is selected, // the OMV data is loaded, and the UI is created or made visible. OMVData.setup = function() { // Collect all XML info into two groups. // Each element contains an object: // { dict:dictName, title:theTitle, btid:BridgeTalkID } var groups = [ // Group 0 is for CommonFiles [], // Group 1 is for the other files. [] ]; var apps = BridgeTalk.getTargets(); for (var i = 0; i < apps.length; i++) { var app = BridgeTalk.getSpecifier (apps [i]); if (!app) continue; switch (BridgeTalk.getOMVDictionaryType (app)) { case "dynamic": var obj = { btid:app, dict:"" }; var name = this.getDisplayName (app); obj.title = localize ("$$$/ESToolkit/OMV/Title=%1 Object Model", name); groups[1].push (obj); break; } } // Add all directories inside the Dictionaries folder var dictFolder = Folder (Folder.commonFiles + "/Adobe/Scripting Dictionaries CS3"); var folders = dictFolder.getFiles(); for (var i = 0; i < folders.length; i++) { var f = folders [i]; if (!(f instanceof Folder)) continue; var files = f.getFiles ("*.xml"); for (var j = 0; j < files.length; j++) { // the title of the map, and the (optional) dictionary name var title = null, dictName = null; // Attempt to load the beginning of the XML file, // to find the official reference name plus any dynamic dict info var xmlfile = files [j]; var resolved = xmlfile.resolve(); if (resolved) xmlfile = resolved; // Open this file, and read the first 1024 bytes to find the element if (!xmlfile.open()) // IO error - ignore continue; var s = xmlfile.read (1024); xmlfile.close(); var re = / b.title) return 1; else return 0; } for (grp = 0; grp < 2; grp++) groups [grp].sort (sortfn); // We got all groups lined up; now, set up the menu for (grp = 0; grp < 2; grp++) { for (var i = 0; i < groups [grp].length; i++) { var obj = groups [grp][i]; // At the beginning of each group, insert a separator (except for group #0) if (0 != grp && 0 == i) OMVData.menuItemLocation = "---" + OMVData.menuItemLocation; var data = new OMVData (obj.btid, obj.dict); this.createMenuItem (data, obj.title); } } } // Create a menu item. Returns the ID OMVData.createMenuItem = function (data, title) { OMVData.menuItemCount++; var menuID = "help/omv" + OMVData.menuItemCount; var item = new MenuElement ("command", title, OMVData.menuItemLocation, menuID); OMVData.menuItemLocation = "after " + menuID; // connect the data data.menu = item; item.data = data; item.onSelect = function() { if (!this.data.show()) this.enabled = false; } } // Display the OMV instance for viewing. OMVData.prototype.show = function() { // If the user wants to see, we assume that loading is OK. this.asked = this.loadOK = true; if (!this.load()) return false; else if (this.ui) this.ui.w.show(); else this.ui = new OMV (this); return true; } // Load the data. If the data is dynamic, mine the target. OMVData.prototype.load = function() { if (!this.asked) { this.asked = true; var name = this.getDisplayName(); this.loadOK = (PrefUtils.getValue( 'prefs.omv.confirmLoad', 'Boolean' )) ? queryBox ("$$$/ESToolkit/OMV/NotLoaded=The Object Model for %1 has not yet been loaded.^nLoad it now?", name) : true; } if (this.loadOK && !this.loaded) { // Do progress messages for all OMV files except for the CommonFiles if (this.showProgress) { var msg = localize ("$$$/ESToolkit/OMV/LoadingObjectModel=Loading Object Model for %1...", this.getDisplayName()); this.dlg = new ProgressBox (msg); this.dlg.setProgress (0, 100); this.loadXML(); this.dlg.stop(); this.dlg = null; } else this.loadXML(); } return this.loaded && (this.xml != null); } // Create a File instance pointing to an XML file in the Prefs area. // The name is "omv$btid.xml", or "omv$btid$dict.xml", where "btid" // is the full BT ID, and "dict" is the dictionary name if given. OMVData.prototype.getTempXMLFile = function() { var s = app.prefsFolder + "/omv$" + this.btID; if (this.dict) s += "$" + this.dict; return File (s + ".xml"); } // Save the XML to the prefs area. OMVData.prototype.saveTempXML = function() { // save the mined XML var f = this.getTempXMLFile(); if (f.open ("w")) { if (this.dlg) this.dlg.setText ('$$$/ESToolkit/OMV/Saving=Saving Object Model...'); // stamp the time if not given if (this.xml.map.@time.toString() == "") this.xml.map.@time = new Date().toString(); f.encoding = "UTF-8"; f.write (this.xml.toXMLString()); f.close(); if (f.error != "") f.remove(); else this.file = f; } } // Get the display name for this OMV data instance OMVData.prototype.getDisplayName = function() { return OMVData.getDisplayName (this.btID); } // Get the display name for a BT specifier OMVData.getDisplayName = function (btID) { var name = BridgeTalk.getDisplayName (btID); if (!name) { name = btID.split ('-')[0]; if (name == "aftereffects") name = "After Effects"; else // just make 1st character upper case name = name[0].toUpperCase() + name.substr (1); } return name; } // Get the OMVData instance(s) for a specific target and engine. // In this context, it is assumed that the engine matches the // name of the dictionary to get. OMVData.getData = function (target, engine) { target = target.split('-')[0]; // Pass 1: the full BT target var targetID = target + "-" + engine; var omv = OMVData.instances [targetID]; if (!omv) omv = OMVData.instances [target]; return omv; } // Get the OMVData instance(s) for a specific XML. OMVData.getDataForXML = function (xml) { // find the root while (xml.parent() != null) xml = xml.parent(); for (var prop in OMVData.instances) { var arr = OMVData.instances [prop]; for (var i = 0; i < arr.length; i++) { var data = arr [i]; if (data.xml == xml) return data; } } return null; } // Set the OMVData instance for a specific target and dictionary. // In this context, it is assumed that the engine matches the // name of the dictionary to get. Since the OMV is only running // in one locale and for one version (we loaded from "Scripting // Dictionaries CS3"), we use the BT base name to store the data OMVData.setData = function (data) { var btID = data.btID.split ('-')[0]; var targetID = btID; if (data.dict) targetID += "-" + data.dict; if (!OMVData.instances [targetID]) OMVData.instances [targetID] = []; OMVData.instances [targetID].push (data); if (data.dict) { // for the first (or main) dictionary, set the global entry, too // because the debugger does not know yet which engines it will have if (data.dict == "main") { if (!OMVData.instances [btID]) OMVData.instances [btID] = []; OMVData.instances [btID].push (data); } } } // Checks if the OMV for a specific target/engine has been loaded. OMVData.checkForTarget = function (target, engine) { return (OMVData.getData (target, engine) != null); } // Check the time stamp for a target if that target is dynamic and running. // On errors, the Bad XML dialog pops up, and this.xml is set to null. OMVData.checkTimeStampForTarget = function (target, engine) { var omv = OMVData.getData (target, engine); if (omv) { for (var i = 0; i < omv.length; i++) { var xml = omv [i].xml; if (xml) { if (omv [i].checkTimeStamp()) { if (omv [i].xml != xml) { // Stuff was updated if (omv [i].omv) omv [i].omv.detach(); } } } } } } // Find code completion text for a specific target/engine combo. This // works only if the name of a dictionary matches the name of an engine. OMVData.findTextForTarget = function (target, engine, text) { var text = null; var omv = OMVData.getData (target, engine); if (omv) { for (var i = 0; i < omv.length; i++) { text = omv[i].findText (text); if (text) break; } } return text; } // Load the XML. If there is no installed file, // attempt to connect to the target and ask the target for its TOC. // In that case, the XML is incomplete, and the app is asked for // each class. OMVData.prototype.loadXML = function () { var result = false; this.xml = new XML(''); // Load all XML files from disk, and merge their contents. // The returned value is true for OK, false for errors. // For dynamic targets, the ESTK loads the mined XML into app.prefsFolder. // The file name is omv$btid$dictname, e.g. omv$indesign-5.0-en_us$main.xml. // Look after a temp file first var tempFile = this.getTempXMLFile(); if (!tempFile.exists) tempFile = null; var f = tempFile ? tempFile : this.file; if (f) { // The progress is set up as follows: // 20% = loading and parsing all files // 80% = preparing XML // To have a good resolution, we set the max value to (#files*100), and increment by 2 * 10 if (this.dlg) this.dlg.setProgress (0, 100); var text = Document.safeRead (f, true); var ok = false; if (text) { ok = true; if (this.dlg) this.dlg.setProgress (10); try { text = text.replace (//, ""); this.xml = new XML (text); } catch (e) { ok = false; } } if (!ok) { // XML error: ignore the temp file if (tempFile) { tempFile.remove(); tempFile = null; } else { this.badXML ("XML file format error"); return false; } } if (this.dlg) this.dlg.setProgress (20); if (!this.checkTimeStamp()) return false; // Load sub-XMLs if (!tempFile && !this.loadSubXMLFiles (f)) { this.badXML ("Bad sub XML files"); return "error"; } this.loaded = true; if (this.prepareXML()) { this.file = f; // Register this OMV under the file name OMVData.files [this.file.absoluteURI] = this; return true; } else return false; } else { if( this.dynamic && !this.file ) { if (!BridgeTalk.isRunning (this.btID)) { var launchMsg = "$$$/ESToolkit/OMV/Launch=%1 must be running to retrieve Object Model data.^nDo you want to launch %1?"; if (!app.launchTarget (this.btID, launchMsg)) return false; } } // no temp file yet if (this.dynamic && this.checkTimeStamp()) { if (this.prepareXML()) { // Register this OMV under the file name OMVData.files [this.file.absoluteURI] = this; return true; } } this.badXML ("Cannot open " + f); return false; } } // Load all sub-XML files. These files contain additional information. They are // found in a subdirectory carrying the same name as the main XML file. The names // of these files are irrelevant. Their XML is merged into the main XML. OMVData.prototype.loadSubXMLFiles = function (f) { // strip the .xml part var dir = Folder (f.fsName.substr (0, f.fsName.length - 4)); var files = dir.getFiles ("*.xml"); if (0 == files.length) return true; // The progress is set up as follows: // 20% = loading and parsing main files // 60% = loading and parsing sub files // 20% = preparing XML if (this.dlg) this.dlg.setProgress (20); var progressValue = 20; var increment = 60 / (files.length * 2); for (var i = 0; i < files.length; i++) { f = files [i]; var resolved = f.resolve(); if (resolved) f = resolved; if (f.exists) { if (this.dlg) this.dlg.setProgress (progressValue); progressValue += increment; var text = Document.safeRead (f, true); if (text == null) return false; var xml; try { // Remove all namespaces text = text.replace (//, ""); xml = new XML (text); } catch (e) { return false; } if (this.dlg) this.dlg.setProgress (progressValue); progressValue += increment; var globals = xml.map.topicref.xpath ('topicref[@href="#/global"]'); if (globals.length() == 1) { // Update my own element with the globals if not present delete globals.parent()[globals.childIndex()]; var myGlobals = this.xml.map.topicref.xpath ('topicref[@href="#/global"]') if (myGlobals.length() == 0) this.xmp.map.appendChild (globals); // Add the globals instance stuff to my globals globals = xml['package'].xpath ('classdef[@name="global"]'); myGlobals = this.xml['package'].xpath ('classdef[@name="global"]'); if (globals.length() > 0) { if (myGlobals.length() == 0) this.xml['package'].appendChild (globals); else { var inst = globals.xpath ('elements[@type="instance"]'); var myInst = myGlobals.xpath ('elements[@type="instance"]'); if (myInst.length() == 0) myGlobals.appendChild (inst); else myInst.appendChild (inst.children()); } // remove from the original tree delete globals.parent() [globals.childIndex()]; } } // Add the other classes this.xml.map.appendChild (xml.map.children()); this.xml['package'].appendChild (xml['package'].children()); // Register this OMV under the file name OMVData.files [f.absoluteURI] = this; } else return false; } return true; } // Create a single-level TOC, ignoring the top level structure for now, and sort the TOC. // Store this TOC under this.map. Returns false on abort. OMVData.prototype.prepareXML = function() { if (!this.xml) return false; var pkg = this.xml['package']; // Get rid of the level 1 entries for now var list = this.xml.map.children().children(); // Remove duplicates this.map = XML (''); // Set up the classes at the OMV object this.classNames = {}; var increment = this.dlg ? this.dlg.getRemainingProgress() / list.length() : 0; for (var i = 0; i < list.length(); i++) { if (this.dlg && !this.dlg.increment (increment)) { this.badXML ("Load Aborted"); return false; } var name = list [i].@navtitle.toString(); if (this.classNames [name]) continue; this.classNames [name] = list [i].@href.toString(); this.map.appendChild (list [i]); } return true; } // Get XML from a target with a sync call. Returns null on errors, // the XML otherwise. OMVData.prototype.getXMLFromTarget = function (commandXML, noErrorMsg) { if (!BridgeTalk.isRunning (this.btID)) { var launchMsg = "$$$/ESToolkit/OMV/Launch=%1 must be running to retrieve Object Model data.^nDo you want to launch %1?"; if (!app.launchTarget (this.btID, launchMsg)) return false; } var bt = new BridgeTalk; bt.type = "Debug"; bt.target = this.btID + "#estk"; bt.body = commandXML; bt.data = this; bt.xml = null; // Keep a reference here for async IO garbage collection inhibit this.bt = bt; bt.onResult = function (bt) { this.data.bt = null; try { this.xml = new XML (bt.body); } catch (e) { this.xml = null; } } bt.onError = function (bt) { this.data.bt = null; this.xml = null; } bt.send(); var then = new Date; while (this.bt) { var now = new Date; if (now - then > 15000) break; BridgeTalk.pump(); $.sleep (20); } if (!bt.xml && !noErrorMsg) this.badXML ("App did not return valid XML"); return bt.xml; } // Error message for bad XML. OMVData.prototype.badXML = function (reason) { if (this.dlg) this.dlg.stop(); errorBox ('$$$/ESToolkit/Alerts/BadXML=Cannot load XML!\nHelp is not available.'); this.xml = null; this.loaded = true; if (this.menu) this.menu.enabled = false; if (this.ui) this.ui.disable(); if ($.version.indexOf ("(debug)") > 0) { print ("Cannot load XML! Reason: " + reason); print ($.stack); } } // Check the time stamp in a loaded TOC from temp XML and a running dynamic target. // The XML is assumed to have been loaded from a temp file already. // If the XML needs to be re-mined, do so immediately without asking. // The progress bar is set to 20%. OMVData.prototype.checkTimeStamp = function() { if (this.dlg) this.dlg.setProgress (20, 100); if (this.dynamic && BridgeTalk.isRunning (this.btID)) { var map = this.getXMLFromTarget (''); if (map) { var oldStamp = this.xml ? this.xml.map.@time.toString() : ""; var newStamp = map.@time.toString(); if (newStamp.length) { // Always re-mine if the dynamic TOC had a stamp, but the loaded XML had not var remove = true; if (oldStamp.length) { var oldDate = new Date (oldStamp); var newDate = new Date (newStamp); remove = (newDate > oldDate); } if (remove) { this.getTempXMLFile().remove(); // Mine the target. this.xml = null; // Try to load the entire dictionary in one chunk var xml = this.getXMLFromTarget ('', true); if (xml) { // good load this.xml = xml; if (this.dlg) this.dlg.setProgress (40); } else { // old code: mine one by one. May be removed once clients pick up ES 3.7.63 this.xml = new XML (''); this.xml.map = map; this.xml.appendChild (XML ('')); var topics = map.topicref.children(); var count = topics.length(); // We use 60% (we had 20%, and leave 20% for prepareXML()) var progressValue = 20; for (var i = 0; i < count; i++) { if (this.dlg && !this.dlg.setProgress (progressValue)) { this.badXML ("Load aborted"); return false; } progressValue += (60 / count); var topic = topics [i]; var href = this.splitHref (topic.@href.toString()); // ignore the package for now var xml = this.getXMLFromTarget ('' + '' + href.cls + ''); if (xml) { // pull out of a "package" container if (xml.localName() == "package") xml = xml.children(); this.xml ['package'].appendChild (xml); } else { this.badXML ("Target did not return class info for " + href.cls); return false; } } } // end old code if (this.xml) { var title = this.xml.map.@title.toString(); if (title == "") { title = localize ("$$$/ESToolkit/OMV/Title=%1 Object Model", this.getDisplayName()); this.xml.map.@title = title; } this.dynamic = false; this.loaded = true; this.saveTempXML(); } } } } } return true; } // Find XML. The search string could be a simple string (which could be a // class name or an element name), or a dot-separated string for class and // element name. Additional patterns are *.element, .element, class. or // class.*. If the class XML is not found, a getClassInfo request is sent // to any dynamic target. // Returns the found XML (class or element XML) or null. OMVData.prototype.findXML = function (what, wholeWord) { if (!this.xml) return null; var className = null; var elementName = null; var classWholeWord = wholeWord; var elementWholeWord = wholeWord; var findText = what.split ('.'); if (findText.length == 2) { // Looks like it is both class and element // but the class name could be empty or a star if (findText[0] == "" || findText[0] == "*") elementName = findText [1]; else { classWholeWord = true; className = findText[0]; // any element given? elementName = (findText[1] != "" && findText[1] != "*") ? findText [1] : ""; } } else { className = findText [0]; // do not search for "" or "*" (too many results) if (className == "" || className == "*") return null; // if the first character if lower case, it must be an element if (className.toLowerCase() == className && className [0] != "$" && className [0] != '_') elementName = className, className = null; } // The data has been set up, but remember that an upper-case // class name could as well be an upper-case element name var xml = null; if (className != null && elementName == null) { xml = this.xml['package'].xpath (classWholeWord ? "* [@name = '" + className + "']" : "* [starts-with (@name, '" + className + "')]"); // Also assume an element name! elementName = className; className = null; } if (elementName != null) { var xml2; if (className) xml2 = this.xml['package'].xpath ("* [@name = '" + className + "']"); else xml2 = this.xml['package'].children(); xml2 = xml2.elements.children(); if (elementName != "") { var xpathExpr = elementWholeWord ? "self::node() [@name = '" + elementName + "']" : "self::node() [starts-with (@name, '" + elementName + "')]"; xml2 = xml2.xpath (xpathExpr); } if (xml2) { if (xml) xml += xml2; else xml = xml2; } } if (xml.length() == 0) return null; else return xml; } // Create a HREF string for the given XML. // This link has the form [file]#/Classname[/Containertype/Elementname]. OMVData.prototype.getHrefForXML = function (xml) { var href = ""; switch (xml.localName()) { case "method": case "property": href = "#/" + xml.parent().parent().@name + "/" + xml.parent().@type + "/" + xml.@name; break; default: href = "#/" + xml.@name; break; } return href; } // Get the XML for a given HREF link. OMVData.prototype.getXMLForHref = function (href) { if (!this.xml) return null; href = this.splitHref (href); // ignore package for now // Get the class var xml = this.xml['package'].classdef.xpath ('self::node()[@name="' + href.cls + '"]'); if (href.type && href.name) xml = xml.xpath ('self::node()[@type="' + href.type + '"]/*[@name="' + href.name + '"]'); if (xml.length() == 0) xml = null; return xml; } // Split up a HREF. Returns an object with these properties: // file - the file portion, "" if no file portion // pkg - the package name, "" for no package name // cls - the class name // type - the element container type (e.g. class, instance, "" if not present) // name - the element name ("" if not present) OMVData.prototype.splitHref = function (href) { var obj = { file:"", cls:"", type:"", name:"" }; var file = href.split ('#'); if (file.length == 1) file [1] = ""; if (file.length > 1) { if (file [0].length) { // Change the file part to a file that we hope will exist var f = file[0].split ('/'); var folder = Folder.commonFiles + "/Adobe/Scripting Dictionaries CS3/"; if (f [0] == "$COMMON") { f.shift(); obj.file = folder + "CommonFiles/" + f.join ('/'); } else if (file [0].length) { // This is the root directory var f = this.file.parent; if (!f) f = File ("/"); f.changePath (file [0]); if (!f.exists) { // OK, it is not in the same folder as the main file. Try // the subfolder containing the same name f = this.file.fsName; // just assume that the extension is .xml (= 4 chars) f = new Folder (f.substr (0, f.length - 4)); f.changePath (file [0]); } obj.file = f.fsName; } } href = file [1]; } else href = file [0]; // just in case someone forgot to add the leading slash if (href.length == 0) // assume all classes href = "/"; else if (href[0] != '/') href = '/' + href; href = href.split ('/'); obj.pkg = href [0]; if (href.length > 1) obj.cls = href [1]; if (href.length > 2) { // if the container type is missing, assume "instance" if (href.length == 3) obj.type = "instance", obj.name = href [2]; else obj.type = href [2], obj.name = href [3]; } return obj; } // Piece a HREF together from the object returned by splitHref() OMVData.prototype.joinHref = function (href) { var file = href.file; if (file) { var folder = Folder.commonFiles + "/Adobe/Scripting Dictionaries CS3/"; if (file.indexOf ("CommonFiles") == folder.length) file = "$COMMON" + file.substr (folder.length + "CommonFiles".length); else { var f = File (file); file = f.getRelativeURI (folder); } } // Rebuild the HREF var newHref = file + "#" + href.pkg + "/" + href.cls; if (href.name) newHref += "/" + href.type + "/" + href.name; return newHref; } // Code Completion interface. OMVData.getCodeHints = function (target, engine, text) { if (OMVData.lastFindInfo.target == target && OMVData.lastFindInfo.engine == engine && OMVData.lastFindInfo.target == text) return OMVData.lastFindInfo.found; if (!OMVData.load (target, true)) return null; if (!OMVData.load ("estoolkit-2.0", true)) return null; // Create a complete array of all OMVs var data = []; var appData = OMVData.getData (target, engine); var coreData = OMVData.getData ("estoolkit"); if (appData) { for (var i = 0; i < appData.length; i++) data.push (appData [i]); } if (coreData && coreData != appData) { for (i = 0; i < coreData.length; i++) data.push (coreData [i]); } var xml = XML('<>'); var count = 0; outer: for (i = 0; i < data.length; i++) { var partXML = data [i].findXML (text); if (partXML) { // turn off tracking as per Alan's request // if (data[i].ui) // data[i].ui.displayXML (partXML); for (var j = 0; j < partXML.length(); j++) { xml += partXML[j]; if (++count > 20) break outer; } } } // return an array of strings for Code Completion var returnArray = []; // Add an xml{} object to the found info, where each XML is stored // as a property under the generated array element's text, plus this.lastFindInfo = { target:target, engine:engine, text:text, found:returnArray, xml: {} }; if (xml) { for (var i = 0; i < xml.length(); i++) { var elem = xml [i]; var name; if (elem.localName() == "classdef") name = elem.@name.toString(); else { name = elem.parent().parent().@name; // Avoid global.name if (name == "global") name = elem.@name.toString(); // Avoid Array.Array else if (name != elem.@name) name += "." + elem.@name; if (elem.localName() == "method") { var args = "("; var params = elem.parameters.children(); for (var j = 0; j < params.length(); j++) { if (j) args += ", "; args += params [j].@name; } args += ")"; if (args.length > 2) name += " "; name += args; } } var help = this.flatten (elem.shortdesc); if (help.length) name += ": " + help; returnArray.push (name); this.lastFindInfo.xml [name] = elem; } returnArray.sort(); if (count > 20) returnArray.push ("..."); } return returnArray; } // Update any UI with the code hint selected. The given text // is the original text of the array element that was returned. OMVData.displaySelectedCodeHint = function (target, engine, text) { if (OMVData.lastFindInfo.target != target || OMVData.lastFindInfo.engine != engine) return; // get the XML var xml = OMVData.lastFindInfo.xml [text]; if (!xml) return; // get the OMVData that own this XML var data = OMVData.getDataForXML (xml); if (data && data.ui) data.ui.displayXML (xml); } // Flatten an XML text to a string. OMVData.flatten = function (xml) { var s = ""; xml = xml.children(); for (var i = 0; i < xml.length(); i++) { if (s.length) s += " "; if (xml[i].nodeKind() == "text") s += xml[i]; else s += this.flatten (xml [i]); } return s; } // Load the OMV for the given target. Called when the debugger connects. // Check if the OMVData is loaded, and, if not, attempt to load this data. // The debugger calls this method to load data for dynamic targets (if the // target is dynamic at all). OMVData.load = function (target, loadAll) { // We skip the own debugger here to save load time // That OMV is loaded later on during Code Completion if (!loadAll && target == "estoolkit-2.0") return true; // TODO: implement multiple dictionaries var data = OMVData.getData (target, ""); if (!data) return false; for (var i = 0; i < data.length; i++) { if (!data [i].load()) return false; } return true; } // Get the OMV for a specific file. If not present, attempt to load it. OMVData.getByFile = function (f) { if (!(f instanceof File)) f = File (f); if (!f.exists) return null; // Make sure that we have preloaded the default stuff if (!OMVData.load ("estoolkit-2.0", true)) return null; var omv = OMVData.files [f.absoluteURI]; if (!omv) { // The file's parent should be the basic BT name var btid = f.parent ? BridgeTalk.getSpecifier (f.parent.name) : NULL; if (btid) omv = new OMVData (btid, f); } return omv; }