org.molecularplayground.MPJmolApp Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmol Show documentation
Show all versions of jmol Show documentation
Jmol: an open-source Java viewer for chemical structures in 3D
/*
* Copyright 2011 University of Massachusetts
*
* File: MPJmolApp.java
* Description: Molecular Playground Jmol interface component/application
* Author: Adam Williams
*
* See http://molecularplayground.org/
*
* A Java application that listens over a port on the local host for
* instructions on what to display. Instructions come in over the port as JSON strings.
*
* This class uses the Naga asynchronous socket IO package, the JSON.org JSON package and Jmol.
*
* Adapted by Bob Hanson for Jmol 12.2
*
* see JsonNioService for details.
*
*/
package org.molecularplayground;
import java.awt.Dimension;
import java.awt.Graphics;
import javajs.util.PT;
import javax.swing.JPanel;
import org.jmol.adapter.smarter.SmarterJmolAdapter;
import org.jmol.api.JmolCallbackListener;
import org.jmol.api.JmolViewer;
import org.jmol.c.CBK;
import org.jmol.util.Logger;
import org.jmol.viewer.Viewer;
import org.openscience.jmol.app.jmolpanel.JmolPanel;
import org.openscience.jmol.app.jsonkiosk.BannerFrame;
import org.openscience.jmol.app.jsonkiosk.JsonNioClient;
import org.openscience.jmol.app.jsonkiosk.JsonNioServer;
import org.openscience.jmol.app.jsonkiosk.JsonNioService;
import org.openscience.jmol.app.jsonkiosk.KioskFrame;
/*
* Jmol 12 implementation of the Molecular Playground
*
* includes message "banner:xxxxx" intercept to
* display xxxxx on the banner, thus allowing that to
* be modified by a running script. (in JsonNioService.java)
version=12.3.3_dev
# new feature: MolecularPlayground now accepts messages to the banner:
# message banner: xxxxxxx
# new feature: MolecularPlayground fully functional.
# This application (MPJmolApp) is part of a three-part suite
# that runs on a Mac mini involving:
# "Hub" [name] for overall control (Mac app; not open source yet)
# MPKinectDriver for obtaining motion events (Mac app; not open source yet)
# MPJmolApp for displaying the results (source here)
# The Hub and MPJmolApp communicate over local port 31416, sending
# JSON messages back and forth. (See note in org.jmol.app.jsonkiosk.JsonNioService.java)
# For demonstrations of the installation at St. Olaf College,
# see the following YouTube videos:
# http://www.youtube.com/watch?v=iQRkuku8ry0
# http://www.youtube.com/watch?v=XCRrRZe1j6g
# http://www.youtube.com/watch?v=FTTIVWGtFD0
# For details relating to the original Molecular Playground
# installation at U. Mass.-Amherst, see
# http://molecularPlayground.org
# Note that all of the functionality of the original MP are
# present in MPJmolApp
# new feature: MolecularPLayground can now ignore all Hub requests for
# commands and content changes, thus allowing its own configuration
# script to drive the presentation instead of the Hub's. So the Hub
# can be used simply as an interface to the Kinect driver. This just
# allows a simpler development interface -- a simple three-column Excel file can
# be used to drive a presentation. (see org.jmol.molecularplayground.biophysics.xlsx)
# -- MPJmolApp looks for the file MpJmolAppConfig.spt
# -- This file can override MPJmolApp's default parameters:
# NIOContentPath
# -- default: System.getProperty("user.dir").replace('\\', '/')
# + "/Content-Cache/%ID%/%ID%.json"
# -- ignored if NIOcontentDisabled ends up true (see below)
# NIOterminatorMessage
# -- default: "MP_DONE"
# NIOresetMessage
# -- default: "MP_RESET"
# NIObannerEnabled
# -- default: true
# NIOcontentScript
# -- default: (not present, setting NIOcontentDisabled=false)
# NIOcontentDisabled
# -- default: true if NIOcontentScript is present; false if not
# NIOmotionDisabled
# -- default: false
# -- The script in MpJmolAppConfig.spt is run, along with whatever
# default settings are generated by the above checks.
# -- Parameters are set by querying the Viewer for those Jmol variables.
# -- If NIOcontentDisabled is true, then all JSON messages from the Hub
# of types "content", "command", and "banner" are ignored. It is still
# important that the running script send "MP_DONE" messages periodically
# (within every 6 minutes) so that the Hub knows that MPJmolApp is still
# alive and does not try to restart it.
# -- If NIOmotionDisabled is true, then all JSON messages from the Hub
# of types "move", "sync", and "touch" are ignored.
# -- These are checked every time a JSON command is received, so the
# running script can specifically turn off motion detection if that
# or content detection if that is desired.
# -- Note that MPJmolApp has a full console and menu that are available
# on the operator's screen, (which is just mirrored to the projector).
# This allows for parameter setting and adjustments on the fly.
#
*
*/
public class MPJmolApp implements JsonNioClient {
protected Viewer viewer;
private static int MP_VERSION = 1; // SET TO 2 if using Version 2 (AW 12/2011)
public static void main(String args[]) {
new MPJmolApp(args.length > 0 ? Integer.parseInt(args[0]) : 31416);
}
public MPJmolApp() {
this(31416);
}
public MPJmolApp(int port) {
startJsonNioKiosk(port);
}
protected JsonNioServer service;
private BannerFrame bannerFrame;
private KioskFrame kioskFrame;
private boolean contentDisabled;
private void startJsonNioKiosk(int port) {
KioskPanel kioskPanel = new KioskPanel();
bannerFrame = new BannerFrame(1024, 75);
kioskFrame = new KioskFrame(0, 75, 1024, 768 - 75, kioskPanel);
try {
setBannerLabel("click below and type exitJmol[enter] to quit");
String defaultScript = "set allowgestures;set allowKeyStrokes;set zoomLarge false;set frank off;set antialiasdisplay off;";
String script = "cd \"\"; " + viewer.getFileAsString3("MPJmolAppConfig.spt", false, null) + ";";
Logger.info("startJsonNioKiosk on port " + port);
Logger.info(script);
if (script.indexOf("java.io") >= 0)
script = "";
String s = PT.rep(script.toLowerCase(), " ", "");
if (s.indexOf("niocontentpath=") < 0) {
String path = System.getProperty("user.dir").replace('\\', '/')
+ "/Content-Cache/%ID%/%ID%.json";
script += "NIOcontentPath=\"" + path + "\";";
}
if (s.indexOf("nioterminatormessage=") < 0) {
script += "NIOterminatorMessage='MP_DONE';";
}
if (s.indexOf("nioresetmessage=") < 0) {
script += "NIOresetMessage='MP_RESET';";
}
if (s.indexOf("niobannerenabled=") < 0) {
script += "NIObannerEnabled=true;";
}
if (s.indexOf("niocontentscript=") >= 0) {
script += "NIOcontentDisabled=true;";
} else {
script += "NIOcontentScript='';NIOcontentDisabled=false;";
}
if (s.indexOf("niomotiondisabled=") < 0) {
script += "NIOmotionDisabled=false;";
}
Logger.info("startJsonNioKiosk: " + defaultScript + script);
viewer.scriptWait(defaultScript + script);
contentDisabled = JsonNioService.getJmolValueAsString(viewer, "NIOcontentDisabled").equals("true");
Logger.info("startJsonNioKiosk: contentDisabled=" + contentDisabled);
service = JmolPanel.getJsonNioServer();
if (service == null) {
Logger.info("Cannot start JsonNioServer");
System.exit(1);
}
service.startService(port, this, viewer, "-MP", MP_VERSION);
// Bob's demo model -- verifies that system is working and networked properly
viewer.script("load $caffeine");
} catch (Throwable e) {
e.printStackTrace();
if (service == null)
nioClosed(null);
else
service.close();
}
}
/// JsonNiosClient ///
private boolean haveStarted = false;
@Override
public synchronized void nioRunContent(JsonNioServer jns) {
if (contentDisabled && (jns == null || !haveStarted)) {
// needs to be run from the NIO thread, just once.
String script = (jns == null ? "; message testing nioRun2; cd \"\"; script \"" + JsonNioService.getJmolValueAsString(viewer, "NIOcontentScript") + "\"" : "");
haveStarted = true;
script += ";cd \"\";cd;script \"" + JsonNioService.getJmolValueAsString(viewer, "NIOcontentScript") + "\"";
System.out.println("nioRunContent " + Thread.currentThread() + " " + script);
viewer.script(script);
System.out.println("nioRunContent done");
}
}
@Override
public void setBannerLabel(String label) {
bannerFrame.setLabel(label);
}
@Override
public void nioClosed(JsonNioServer jns) {
try {
viewer.dispose();
bannerFrame.dispose();
kioskFrame.dispose();
} catch (Throwable e) {
//
}
System.exit(0);
}
////////////////////////
class KioskPanel extends JPanel implements JmolCallbackListener {
private final Dimension currentSize = new Dimension();
KioskPanel() {
viewer = (Viewer) JmolViewer.allocateViewer(this, new SmarterJmolAdapter(),
null, null, null, ""/*-multitouch-mp"*/, null);
viewer.setJmolCallbackListener(this);
// turn off all file-writing capabilities
viewer.setBooleanProperty("isKiosk", true);
}
@Override
public void paint(Graphics g) {
getSize(currentSize);
viewer.renderScreenImage(g, currentSize.width, currentSize.height);
}
// / JmolCallbackListener interface ///
@SuppressWarnings("incomplete-switch")
@Override
public boolean notifyEnabled(CBK type) {
switch (type) {
case SCRIPT:
case ECHO:
case MESSAGE:
return true;
}
return false;
}
@Override
public void notifyCallback(CBK type, Object[] data) {
if (service == null || viewer == null)
return;
String strInfo = (data == null || data[1] == null ? null : data[1]
.toString());
switch (type) {
case SCRIPT:
case MESSAGE:
case ECHO:
// could be terminator or message banner:...
service.scriptCallback(strInfo);
JmolCallbackListener appConsole = (JmolCallbackListener) viewer
.getProperty("DATA_API", "getAppConsole", null);
if (appConsole != null)
appConsole.notifyCallback(type, data);
break;
default:
break;
}
}
@Override
public void setCallbackFunction(String callbackType, String callbackFunction) {
// ignore
}
}
}