Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jmol.script.ScriptManager Maven / Gradle / Ivy
Go to download
Jmol: an open-source Java viewer for chemical structures in 3D
/* $RCSfile$
* $Author: hansonr $
* $Date: 2006-05-01 16:40:46 -0500 (Mon, 01 May 2006) $
* $Revision: 5041 $
*
* Copyright (C) 2003-2005 The Jmol Development Team
*
* Contact: [email protected]
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jmol.script;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import javajs.api.ZInputStream;
import javajs.util.AU;
import javajs.util.Rdr;
import javajs.util.Lst;
import javajs.util.P3;
import javajs.util.PT;
import javajs.util.SB;
import org.jmol.api.Interface;
import org.jmol.api.JmolScriptEvaluator;
import org.jmol.api.JmolScriptManager;
import org.jmol.java.BS;
import org.jmol.modelset.Atom;
import org.jmol.thread.JmolThread;
import org.jmol.util.Elements;
import org.jmol.util.Logger;
import org.jmol.viewer.FileManager;
import org.jmol.viewer.JC;
import org.jmol.viewer.StatusManager;
import org.jmol.viewer.Viewer;
public class ScriptManager implements JmolScriptManager {
private Viewer vwr;
private ScriptEval eval;
private JmolScriptEvaluator evalTemp;
private Thread[] queueThreads = new Thread[2];
private boolean[] scriptQueueRunning = new boolean[2];
private JmolThread commandWatcherThread;
public Lst> scriptQueue = new Lst>();
@Override
public Lst> getScriptQueue() {
return scriptQueue;
}
@Override
public boolean isScriptQueued() {
return isScriptQueued;
}
public ScriptManager() {
// by reflection only
}
@Override
public JmolScriptEvaluator setViewer(Viewer vwr) {
this.vwr = vwr;
eval = newScriptEvaluator();
eval.setCompiler();
return eval;
}
private ScriptEval newScriptEvaluator() {
return ((ScriptEval) Interface
.getInterface("org.jmol.script.ScriptEval", vwr, "setOptions")).setViewer(vwr);
}
@Override
public void clear(boolean isAll) {
if (!isAll) {
evalTemp = null;
return;
}
startCommandWatcher(false);
interruptQueueThreads();
}
@Override
public String addScript(String strScript, boolean isQuiet) {
return (String) addScr("String", strScript, "", isQuiet);
}
private Object addScr(String returnType, String strScript, String statusList,
boolean isQuiet) {
/**
* @j2sNative this.useCommandWatcherThread = false;
*/
{
}
if (!vwr.g.useScriptQueue) {
clearQueue();
vwr.haltScriptExecution();
}
if (commandWatcherThread == null && useCommandWatcherThread)
startCommandWatcher(true);
if (commandWatcherThread != null && strScript.indexOf("/*SPLIT*/") >= 0) {
String[] scripts = PT.split(strScript, "/*SPLIT*/");
for (int i = 0; i < scripts.length; i++)
addScr(returnType, scripts[i], statusList, isQuiet);
return "split into " + scripts.length + " sections for processing";
}
boolean useCommandThread = (commandWatcherThread != null && (strScript
.indexOf("javascript") < 0 || strScript.indexOf("#javascript ") >= 0));
// scripts with #javascript will be processed at the browser end
Lst scriptItem = new Lst();
scriptItem.addLast(strScript);
scriptItem.addLast(statusList);
scriptItem.addLast(returnType);
// scriptItem.addLast(Boolean.FALSE);
scriptItem.addLast(isQuiet ? Boolean.TRUE : Boolean.FALSE);
scriptItem.addLast(Integer.valueOf(useCommandThread ? -1 : 1));
scriptQueue.addLast(scriptItem);
//if (Logger.debugging)
// Logger.info("ScriptManager queue size=" + scriptQueue.size() + " scripts; added: "
// + strScript + " " + Thread.currentThread().getName());
startScriptQueue(false);
return "pending";
}
//public int getScriptCount() {
// return scriptQueue.size();
//}
@Override
public void clearQueue() {
scriptQueue.clear();
}
@Override
public void waitForQueue() {
// just can't do this in JavaScript.
// if we are here and it is single-threaded, and there is
// a script running, then that's a problem.
if (vwr.isSingleThreaded)
return;
int n = 0;
while (isQueueProcessing()) {
try {
Thread.sleep(100);
if (((n++) % 10) == 0)
if (Logger.debugging) {
Logger.debug("...scriptManager waiting for queue: "
+ scriptQueue.size() + " thread="
+ Thread.currentThread().getName());
}
} catch (InterruptedException e) {
}
}
}
@Override
public boolean isQueueProcessing() {
return queueThreads[0] != null || queueThreads[1] != null;
}
synchronized private void flushQueue(String command) {
for (int i = scriptQueue.size(); --i >= 0;) {
String strScript = (String) (scriptQueue.get(i).get(0));
if (strScript.indexOf(command) == 0) {
scriptQueue.removeItemAt(i);
if (Logger.debugging)
Logger.debug(scriptQueue.size() + " scripts; removed: " + strScript);
}
}
}
private void startScriptQueue(boolean startedByCommandWatcher) {
int pt = (startedByCommandWatcher ? 1 : 0);
if (scriptQueueRunning[pt])
return;
scriptQueueRunning[pt] = true;
queueThreads[pt] = new ScriptQueueThread(this, vwr,
startedByCommandWatcher, pt);
//System.out.println("script manager starting " + pt + " " + queueThreads[pt]);
queueThreads[pt].start();
}
@Override
public Lst getScriptItem(boolean watching, boolean isByCommandWatcher) {
if (vwr.isSingleThreaded && vwr.queueOnHold)
return null;
Lst scriptItem = scriptQueue.get(0);
int flag = (((Integer) scriptItem.get(4)).intValue());
boolean isOK = (watching ? flag < 0
: isByCommandWatcher ? flag == 0
: flag == 1);
return (isOK ? scriptItem : null);
}
private boolean useCommandWatcherThread = false;
@Override
synchronized public void startCommandWatcher(boolean isStart) {
useCommandWatcherThread = isStart;
if (isStart) {
if (commandWatcherThread != null)
return;
commandWatcherThread = (JmolThread) Interface
.getInterface("org.jmol.script.CommandWatcherThread", vwr, "setOptions");
commandWatcherThread.setManager(this, vwr, null);
commandWatcherThread.start();
} else {
if (commandWatcherThread == null)
return;
clearCommandWatcherThread();
}
if (Logger.debugging) {
Logger.debug("command watcher " + (isStart ? "started" : "stopped")
+ commandWatcherThread);
}
}
/*
* CommandWatcher thread handles processing of
* command scripts independently of the user thread.
* This is important for the signed applet, where the
* thread opening remote files cannot be the browser's,
* and commands that utilize JavaScript must.
*
* We need two threads for the signed applet, because commands
* that involve JavaScript -- the "javascript" command or math javascript() --
* must run on a thread created by the thread generating the applet call.
*
* This CommandWatcher thread, on the other hand, is created by the applet at
* start up -- it can cross domains, but it can't run JavaScript.
*
* The 5th vector position is an Integer flag.
*
* -1 -- Owned by CommandWatcher; ready for thread assignment
* 0 -- Owned by CommandWatcher; running
* 1 -- Owned by the JavaScript-enabled/browser-limited thread
*
* If the command is to be ignored by the CommandWatcher, the flag is set
* to 1. For the watcher, the flag is first set to -1. This means the
* command watcher owns it, and the standard script thread should
* ignore it. The current script queue cycles.
*
* if the CommandWatcher sees a -1 in element 5 of the 0 (next) queue position
* vector, then it says, "That's mine -- I'll take it." It sets the
* flag to 0 and starts the script queue. When that script queue removes the
* 0-position item, the previous script queue takes off again and
* finishes the run.
*
*/
void interruptQueueThreads() {
for (int i = 0; i < queueThreads.length; i++) {
if (queueThreads[i] != null)
queueThreads[i].interrupt();
}
}
public void clearCommandWatcherThread() {
if (commandWatcherThread == null)
return;
commandWatcherThread.interrupt();
commandWatcherThread = null;
}
@Override
public void queueThreadFinished(int pt) {
//System.out.println("queuethread " + pt + " done");
queueThreads[pt].interrupt();
scriptQueueRunning[pt] = false;
queueThreads[pt] = null;
vwr.setSyncDriver(StatusManager.SYNC_ENABLE);
vwr.queueOnHold = false;
//System.out.println("queuethread " + pt + " done");
}
public void runScriptNow() {
// from ScriptQueueThread
if (scriptQueue.size() > 0) {
Lst scriptItem = getScriptItem(true, true);
if (scriptItem != null) {
scriptItem.set(4, Integer.valueOf(0));
startScriptQueue(true);
}
}
}
@Override
public String evalFile(String strFilename) {
// app -s flag
int ptWait = strFilename.indexOf(" -noqueue"); // for TestScripts.java
if (ptWait >= 0) {
return (String) evalStringWaitStatusQueued("String",
"script " + PT.esc(strFilename
.substring(0, ptWait)), "", false, false);
}
return addScript("script " + PT.esc(strFilename), false);
}
private int scriptIndex;
private boolean isScriptQueued = true;
@Override
public Object evalStringWaitStatusQueued(String returnType, String strScript,
String statusList,
boolean isQuiet, boolean isQueued) {
// from the scriptManager or scriptWait()
if (strScript == null)
return null;
String str = checkScriptExecution(strScript, false);
if (str != null)
return str;
SB outputBuffer = (statusList == null
|| statusList.equals("output") ? new SB() : null);
// typically request:
// "+scriptStarted,+scriptStatus,+scriptEcho,+scriptTerminated"
// set up first with applet.jmolGetProperty("jmolStatus",statusList)
// flush list
String oldStatusList = vwr.sm.statusList;
vwr.getStatusChanged(statusList);
if (vwr.isSyntaxCheck)
Logger.info("--checking script:\n" + eval.getScript() + "\n----\n");
boolean historyDisabled = (strScript.indexOf(")") == 0);
if (historyDisabled)
strScript = strScript.substring(1);
historyDisabled = historyDisabled || !isQueued; // no history for scriptWait
// 11.5.45
vwr.setErrorMessage(null, null);
// 14.11.0 need to use a new eval for each Jmol.scriptWait() or else we can
// run into the problem when that is used in a callback that eval.aatokens is overridden
ScriptEval eval = (isQueued ? this.eval : newScriptEvaluator());
boolean isOK = eval.compileScriptString(strScript, isQuiet);
String strErrorMessage = eval.getErrorMessage();
String strErrorMessageUntranslated = eval.getErrorMessageUntranslated();
vwr.setErrorMessage(strErrorMessage, strErrorMessageUntranslated);
vwr.refresh(7,"script complete");
if (isOK) {
isScriptQueued = isQueued;
if (!isQuiet)
vwr.setScriptStatus(null, strScript, -2 - (++scriptIndex), null);
eval.evaluateCompiledScript(vwr.isSyntaxCheck, vwr.isSyntaxAndFileCheck,
historyDisabled, vwr.listCommands, outputBuffer, isQueued || !vwr.isSingleThreaded);
} else {
vwr.scriptStatus(strErrorMessage);
vwr.setScriptStatus("Jmol script terminated", strErrorMessage, 1,
strErrorMessageUntranslated);
if (eval.isStateScript())
setStateScriptVersion(vwr, null); // set by compiler
}
if (strErrorMessage != null && vwr.autoExit)
vwr.exitJmol();
if (vwr.isSyntaxCheck) {
if (strErrorMessage == null)
Logger.info("--script check ok");
else
Logger.error("--script check error\n" + strErrorMessageUntranslated);
Logger.info("(use 'exit' to stop checking)");
}
isScriptQueued = true;
if (returnType.equalsIgnoreCase("String"))
return strErrorMessageUntranslated;
if (outputBuffer != null)
return (strErrorMessageUntranslated == null ? outputBuffer.toString()
: strErrorMessageUntranslated);
// get Vector of Vectors of Vectors info ("object") or, for the applet, JSON ("json")
Object info = vwr.getProperty(returnType, "jmolStatus", statusList);
vwr.getStatusChanged(oldStatusList);
return info;
}
private String checkScriptExecution(String strScript, boolean isInsert) {
String str = strScript;
if (str.indexOf("\1##") >= 0)
str = str.substring(0, str.indexOf("\1##"));
if (checkResume(str))
return "script processing resumed";
if (checkStepping(str))
return "script processing stepped";
if (checkHalt(str, isInsert))
return "script execution halted";
return null;
}
private boolean checkResume(String str) {
if (str.equalsIgnoreCase("resume")) {
vwr.setScriptStatus("", "execution resumed", 0, null);
eval.resumePausedExecution();
return true;
}
return false;
}
private boolean checkStepping(String str) {
if (str.equalsIgnoreCase("step")) {
eval.stepPausedExecution();
return true;
}
if (str.equalsIgnoreCase("?")) {
vwr.scriptStatus(eval.getNextStatement());
return true;
}
return false;
}
@Override
public String evalStringQuietSync(String strScript, boolean isQuiet,
boolean allowSyncScript) {
// central point for all incoming script processing
// all menu items, all mouse movement -- everything goes through this method
// by setting syncScriptTarget = ">" the user can direct that all scripts
// initiated WITHIN this applet (not sent to it)
// we append #NOSYNC; here so that the receiving applet does not attempt
// to pass it back to us or any other applet.
if (allowSyncScript && vwr.sm.syncingScripts
&& strScript.indexOf("#NOSYNC;") < 0)
vwr.syncScript(strScript + " #NOSYNC;", null, 0);
if (eval.isPaused() && strScript.charAt(0) != '!')
strScript = '!' + PT.trim(strScript, "\n\r\t ");
boolean isInsert = (strScript.length() > 0 && strScript.charAt(0) == '!');
if (isInsert)
strScript = strScript.substring(1);
String msg = checkScriptExecution(strScript, isInsert);
if (msg != null)
return msg;
if (vwr.isScriptExecuting() && (isInsert || eval.isPaused())) {
vwr.setInsertedCommand(strScript);
if (strScript.indexOf("moveto ") == 0)
flushQueue("moveto ");
return "!" + strScript;
}
vwr.setInsertedCommand("");
if (isQuiet)
strScript += JC.SCRIPT_EDITOR_IGNORE;
return addScript(strScript, isQuiet
&& !vwr.getBoolean(T.messagestylechime));
}
@Override
public boolean checkHalt(String str, boolean isInsert) {
if (str.equalsIgnoreCase("pause")) {
vwr.pauseScriptExecution();
if (vwr.scriptEditorVisible)
vwr.setScriptStatus("", "paused -- type RESUME to continue", 0, null);
return true;
}
if (str.equalsIgnoreCase("menu")) {
vwr.getProperty("DATA_API", "getPopupMenu", "\0");
return true;
}
str = str.toLowerCase();
boolean exitScript = false;
String haltType = null;
if (str.startsWith("exit")) {
vwr.haltScriptExecution();
vwr.clearScriptQueue();
vwr.clearTimeouts();
exitScript = str.equals(haltType = "exit");
} else if (str.startsWith("quit")) {
vwr.haltScriptExecution();
exitScript = str.equals(haltType = "quit");
}
if (haltType == null)
return false;
// !quit or !exit
if (isInsert) {
vwr.clearThreads();
vwr.queueOnHold = false;
}
if (isInsert || vwr.g.waitForMoveTo) {
vwr.tm.stopMotion();
}
Logger.info(vwr.isSyntaxCheck ? haltType
+ " -- stops script checking" : (isInsert ? "!" : "") + haltType
+ " received");
vwr.isSyntaxCheck = false;
return exitScript;
}
@Override
public BS getAtomBitSetEval(JmolScriptEvaluator eval,
Object atomExpression) {
if (eval == null) {
eval = evalTemp;
if (eval == null)
eval = evalTemp = newScriptEvaluator();
}
return vwr.slm.excludeAtoms(eval.getAtomBitSet(atomExpression), false);
}
@Override
public Object scriptCheckRet(String strScript, boolean returnContext) {
// from ConsoleTextPane.checkCommand() and applet Jmol.scriptProcessor()
if (strScript.indexOf(")") == 0 || strScript.indexOf("!") == 0) // history
// disabled
strScript = strScript.substring(1);
ScriptContext sc = newScriptEvaluator().checkScriptSilent(strScript);
return (returnContext || sc.errorMessage == null ? sc : sc.errorMessage);
}
//////////////////////// open file async ///////////////////////
/**
*
* From file dropping.
*
* @param fileName
* @param flags 1=pdbCartoons, 2=no scripting, 4=append
*
*/
@Override
public void openFileAsync(String fileName, int flags) {
boolean noScript = ((flags & 2) == 2);
boolean isAppend = ((flags & 4) == 4);
boolean pdbCartoons = ((flags & 1) == 1 && !isAppend);
String cmd = null;
fileName = fileName.trim();
if (fileName.startsWith("\t")) {
noScript = true;
fileName = fileName.substring(1);
}
fileName = fileName.replace('\\', '/');
boolean isCached = fileName.startsWith("cache://");
if (vwr.isApplet && fileName.indexOf("://") < 0)
fileName = "file://" + (fileName.startsWith("/") ? "" : "/") + fileName;
try {
// using finally... here on return
if (fileName.endsWith(".pse")) {
cmd = (isCached ? "" : "zap;") + "load SYNC " + PT.esc(fileName)
+ (vwr.isApplet ? "" : " filter 'DORESIZE'");
return;
}
if (fileName.endsWith("jvxl")) {
cmd = "isosurface ";
} else if (!fileName.toLowerCase().endsWith(".spt")) {
String type = getDragDropFileTypeName(fileName);
if (type == null) {
type = FileManager.determineSurfaceTypeIs(vwr
.getBufferedInputStream(fileName));
if (type != null)
cmd = "if (_filetype == 'Pdb') { isosurface sigma 1.0 within 2.0 {*} "
+ PT.esc(fileName)
+ " mesh nofill }; else; { isosurface "
+ PT.esc(fileName) + "}";
return;
}
// these next will end with the escaped file name
if (type.equals("dssr")) {
cmd = "model {visible} property dssr ";
} else if (type.equals("Jmol")) {
cmd = "script ";
} else if (type.equals("Cube")) {
cmd = "isosurface sign red blue ";
} else if (!type.equals("spt")) {
cmd = vwr.g.defaultDropScript;
cmd = PT.rep(cmd, "%FILE", fileName);
cmd = PT.rep(cmd, "%ALLOWCARTOONS", "" + pdbCartoons);
if (cmd.toLowerCase().startsWith("zap") && (isCached || isAppend))
cmd = cmd.substring(3);
if (isAppend) {
cmd = PT.rep(cmd, "load SYNC", "load append");
}
return;
}
}
if (cmd == null && !noScript && vwr.scriptEditorVisible)
vwr.showEditor(new String[] { fileName,
vwr.getFileAsString3(fileName, true, null) });
else
cmd = (cmd == null ? "script " : cmd) + PT.esc(fileName);
} finally {
if (cmd != null)
vwr.evalString(cmd);
}
}
private String getDragDropFileTypeName(String fileName) {
int pt = fileName.indexOf("::");
if (pt >= 0)
return fileName.substring(0, pt);
if (fileName.startsWith("="))
return "pdb";
if (fileName.endsWith(".dssr"))
return "dssr";
Object br = vwr.fm.getUnzippedReaderOrStreamFromName(fileName, null,
true, false, true, true, null);
if (br instanceof ZInputStream) {
String zipDirectory = getZipDirectoryAsString(fileName);
if (zipDirectory.indexOf("JmolManifest") >= 0)
return "Jmol";
return vwr.getModelAdapter().getFileTypeName(
Rdr.getBR(zipDirectory));
}
if (br instanceof BufferedReader || br instanceof BufferedInputStream)
return vwr.getModelAdapter().getFileTypeName(br);
if (AU.isAS(br)) {
return ((String[]) br)[0];
}
return null;
}
private String getZipDirectoryAsString(String fileName) {
Object t = vwr.fm.getBufferedInputStreamOrErrorMessageFromName(
fileName, fileName, false, false, null, false, true);
return vwr.getJzt().getZipDirectoryAsStringAndClose((BufferedInputStream) t);
}
private static int prevCovalentVersion = 1;
public static void setStateScriptVersion(Viewer vwr, String version) {
if (version != null) {
prevCovalentVersion = Elements.bondingVersion;
String[] tokens = PT.getTokens(version.replace('.', ' ')
.replace('_', ' '));
try {
int main = PT.parseInt(tokens[0]); //11
int sub = PT.parseInt(tokens[1]); //9
int minor = PT.parseInt(tokens[2]); //24
if (minor == Integer.MIN_VALUE) // RCxxx
minor = 0;
if (main != Integer.MIN_VALUE && sub != Integer.MIN_VALUE) {
int ver = vwr.stateScriptVersionInt = main * 10000 + sub * 100
+ minor;
vwr.setBooleanProperty("legacyautobonding", (ver < 110924));
vwr.g.legacyHAddition = (ver < 130117);
vwr.setBooleanProperty("legacyjavafloat", (ver < 140206 || ver >= 140300 && ver < 140306));
vwr.setIntProperty("bondingVersion", ver < 140111 ? 0 : 1);
return;
}
} catch (Exception e) {
// ignore
}
}
vwr.setIntProperty("bondingVersion", prevCovalentVersion);
vwr.setBooleanProperty("legacyautobonding", false);
vwr.g.legacyHAddition = false;
vwr.stateScriptVersionInt = Integer.MAX_VALUE;
}
@Override
public BS addHydrogensInline(BS bsAtoms, Lst vConnections, P3[] pts)
throws Exception {
int modelIndex = vwr.ms.at[bsAtoms.nextSetBit(0)].mi;
if (modelIndex != vwr.ms.mc - 1)
return new BS();
// must be added to the LAST data set only
BS bsA = vwr.getModelUndeletedAtomsBitSet(modelIndex);
vwr.g.appendNew = false;
// BitSet bsB = getAtomBits(Token.hydrogen, null);
// bsA.andNot(bsB);
int atomIndex = vwr.ms.ac;
int atomno = vwr.ms.getAtomCountInModel(modelIndex);
SB sbConnect = new SB();
for (int i = 0; i < vConnections.size(); i++) {
Atom a = vConnections.get(i);
sbConnect.append("; connect 0 100 ")
.append("({" + (atomIndex++) + "}) ")
.append("({" + a.i + "}) group;");
}
SB sb = new SB();
sb.appendI(pts.length).append("\n").append(JC.ADD_HYDROGEN_TITLE)
.append("#noautobond").append("\n");
for (int i = 0; i < pts.length; i++)
sb.append("H ").appendF(pts[i].x).append(" ").appendF(pts[i].y)
.append(" ").appendF(pts[i].z).append(" - - - - ").appendI(++atomno)
.appendC('\n');
vwr.openStringInlineParamsAppend(sb.toString(), null, true);
eval.runScriptBuffer(sbConnect.toString(), null, false);
BS bsB = vwr.getModelUndeletedAtomsBitSet(modelIndex);
bsB.andNot(bsA);
return bsB;
}
}