diff --git a/application/nrconsole/.classpath b/application/nrconsole/.classpath index 8031f7d..9248cbb 100644 --- a/application/nrconsole/.classpath +++ b/application/nrconsole/.classpath @@ -6,12 +6,10 @@ - - @@ -45,8 +43,6 @@ - - @@ -58,5 +54,15 @@ + + + + + + + + + + diff --git a/application/nrconsole/DigitalInputExampleSimple.java b/application/nrconsole/DigitalInputExampleSimple.java new file mode 100644 index 0000000..0ad9de2 --- /dev/null +++ b/application/nrconsole/DigitalInputExampleSimple.java @@ -0,0 +1,7 @@ +//Create a digital input object +DigitalInputChannel dig = new DigitalInputChannel(dyio.getChannel(0)); +//Loop forever printing out the state of the button +while(true){ + System.out.println(dig.isHigh()); + Thread.sleep(1000); +} \ No newline at end of file diff --git a/application/nrconsole/lib/.gitignore b/application/nrconsole/lib/.gitignore index bfa0625..7de07a2 100644 --- a/application/nrconsole/lib/.gitignore +++ b/application/nrconsole/lib/.gitignore @@ -1,3 +1 @@ -/nrsdk-3.9.1-jar-with-dependencies.jar -/nrsdk-3.10.0-jar-with-dependencies.jar -/nrsdk-3.11.0-jar-with-dependencies.jar +/nrsdk-*-jar-with-dependencies.jar diff --git a/application/nrconsole/lib/controlsfx-8.0.6.jar b/application/nrconsole/lib/controlsfx-8.0.6.jar new file mode 100644 index 0000000..2f2d1ba Binary files /dev/null and b/application/nrconsole/lib/controlsfx-8.0.6.jar differ diff --git a/application/nrconsole/lib/easybind-1.0.3.jar b/application/nrconsole/lib/easybind-1.0.3.jar new file mode 100644 index 0000000..ffb8a01 Binary files /dev/null and b/application/nrconsole/lib/easybind-1.0.3.jar differ diff --git a/application/nrconsole/lib/flowless-0.4.jar b/application/nrconsole/lib/flowless-0.4.jar new file mode 100644 index 0000000..ed71ec1 Binary files /dev/null and b/application/nrconsole/lib/flowless-0.4.jar differ diff --git a/application/nrconsole/lib/reactfx-2.0-M2u1.jar b/application/nrconsole/lib/reactfx-2.0-M2u1.jar new file mode 100644 index 0000000..36fd26a Binary files /dev/null and b/application/nrconsole/lib/reactfx-2.0-M2u1.jar differ diff --git a/application/nrconsole/lib/richtextfx-0.6.jar b/application/nrconsole/lib/richtextfx-0.6.jar new file mode 100644 index 0000000..79807d2 Binary files /dev/null and b/application/nrconsole/lib/richtextfx-0.6.jar differ diff --git a/application/nrconsole/lib/undofx-1.1.jar b/application/nrconsole/lib/undofx-1.1.jar new file mode 100644 index 0000000..2ab453f Binary files /dev/null and b/application/nrconsole/lib/undofx-1.1.jar differ diff --git a/application/nrconsole/lib/wellbehavedfx-0.1.jar b/application/nrconsole/lib/wellbehavedfx-0.1.jar new file mode 100644 index 0000000..baab1cd Binary files /dev/null and b/application/nrconsole/lib/wellbehavedfx-0.1.jar differ diff --git a/application/nrconsole/src/com/neuronrobotics/graphing/DataChannel.java b/application/nrconsole/src/com/neuronrobotics/graphing/DataChannel.java index bac1645..a267f1f 100644 --- a/application/nrconsole/src/com/neuronrobotics/graphing/DataChannel.java +++ b/application/nrconsole/src/com/neuronrobotics/graphing/DataChannel.java @@ -1,11 +1,14 @@ package com.neuronrobotics.graphing; +import javafx.application.Platform; + import org.jfree.data.xy.XYSeries; public class DataChannel { private String title; private XYSeries series; private static long startTime = System.currentTimeMillis(); + private long lastTime = System.currentTimeMillis(); public DataChannel(String title) { this.title = title; @@ -17,9 +20,23 @@ public String toString() { } public void graphValue(double value) { - long time = System.currentTimeMillis() - startTime ; - if(series != null) - series.add((double) time/1000, value); + if((lastTime+100)>System.currentTimeMillis()) + return; + lastTime= System.currentTimeMillis(); +// try{ +// Platform.runLater(()-> { +// long time = System.currentTimeMillis() - startTime ; +// if(series != null) +// series.add((double) time/1000, value); +// while(series.getItemCount()>3000){ +// Platform.runLater(()-> { +// series.remove(0); +// }); +// } +// }); +// }catch(IllegalStateException ex){ +// //application not yet loaded +// } } public XYSeries getSeries() { diff --git a/application/nrconsole/src/com/neuronrobotics/graphing/DyIOGraphPlugin.java b/application/nrconsole/src/com/neuronrobotics/graphing/DyIOGraphPlugin.java index 298321e..17e24e3 100644 --- a/application/nrconsole/src/com/neuronrobotics/graphing/DyIOGraphPlugin.java +++ b/application/nrconsole/src/com/neuronrobotics/graphing/DyIOGraphPlugin.java @@ -11,7 +11,7 @@ public class DyIOGraphPlugin extends AbstractNRConsoleTabedPanelPlugin { public static final String[] myNames ={"neuronrobotics.dyio.*"}; - private static final GraphingWindow gui = new GraphingWindow(); + private final GraphingWindow gui = new GraphingWindow(); public DyIOGraphPlugin(PluginManager pm) { this(myNames,pm); } diff --git a/application/nrconsole/src/com/neuronrobotics/graphing/GraphingWindow.java b/application/nrconsole/src/com/neuronrobotics/graphing/GraphingWindow.java index 9c10dea..3e5310b 100644 --- a/application/nrconsole/src/com/neuronrobotics/graphing/GraphingWindow.java +++ b/application/nrconsole/src/com/neuronrobotics/graphing/GraphingWindow.java @@ -161,7 +161,7 @@ private void setDefaultWindow() { axis.setAutoRange(true); axis.setFixedAutoRange(scale.getValue()); length.setText("" + scale.getValue()); - invalidate(); + //invalidate(); repaint(); } private void setMovedWindow(double percent) { @@ -177,8 +177,8 @@ private void setMovedWindow(double percent) { double sUpper =loc+(scale.getValue()/2); axis.setRange(sLower, sUpper); length.setText("" + scale.getValue()); - invalidate(); - repaint(); + //invalidate(); + //repaint(); } public void addDataset(DataChannel data) { diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/MenuBar.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/MenuBar.java index 26ef6cc..05e9ae6 100644 --- a/application/nrconsole/src/com/neuronrobotics/nrconsole/MenuBar.java +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/MenuBar.java @@ -209,6 +209,7 @@ void connect(){ }//clear any partial connection connectionMenu.setEnabled(true);//Re-enable connection menu to allow access to menu items + manager.firePluginUpdate(); } @@ -226,7 +227,7 @@ public void disconnect() { ex.printStackTrace(); } ThreadUtil.wait(75); - manager.firePluginUpdate(); + //manager.firePluginUpdate(); } /** diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/NRConsole.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/NRConsole.java index 61a7da8..c186351 100644 --- a/application/nrconsole/src/com/neuronrobotics/nrconsole/NRConsole.java +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/NRConsole.java @@ -132,7 +132,7 @@ public void onPluginListUpdate(PluginManager m) { //System.out.println("NRConsole is refreshing"); //new RuntimeException().printStackTrace(); if(nrcMenubar.isReady()){ - System.out.println("Connection ready"); + Log.debug("Connection ready"); SwingUtilities.invokeLater(() -> { nrcMenubar.setMenues(manager.getMenueItems()); nrcFrame.setDeviceManager(manager); diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/NRConsoleWindow.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/NRConsoleWindow.java index d4c554a..835649c 100644 --- a/application/nrconsole/src/com/neuronrobotics/nrconsole/NRConsoleWindow.java +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/NRConsoleWindow.java @@ -81,10 +81,12 @@ public void ancestorResized(HierarchyEvent arg0) { @Override public void stateChanged(ChangeEvent e) { try { - modePane.setMinimumSize(modePane.getSelectedComponent().getMinimumSize()); - updateUI(); + if(modePane != null){ + modePane.setMinimumSize(modePane.getSelectedComponent().getMinimumSize()); + updateUI(); + } } catch (Exception e2) { - e2.printStackTrace(); + //e2.printStackTrace(); } @@ -94,17 +96,17 @@ public void stateChanged(ChangeEvent e) { logoPanel.add(new JLabel(logo),"[0,2]"); setIconImage( ConnectionImageIconFactory.getIcon("images/hat.png").getImage()); updateUI(); - setSize(1050,1200); + setSize(1400, 1124); } - public void repaint(){ - logoPanel.repaint(); - for(JPanel p: panels){ - p.repaint(); - } - super.repaint(); - } +// public void repaint(){ +// logoPanel.repaint(); +// for(JPanel p: panels){ +// p.repaint(); +// } +// super.repaint(); +// } private void updateScroller(){ if(manager!=null) scroller.setPreferredSize(getCurrentPanelMinSize()); @@ -121,11 +123,12 @@ private void updateUI(){ // }else { //} - - updateScroller(); - invalidate(); - +// SwingUtilities.invokeLater(() -> { +// updateScroller(); +// getContentPane().validate(); +// getContentPane().repaint(); +// }); } public void setDeviceManager(PluginManager dm) { @@ -136,6 +139,7 @@ public void setDeviceManager(PluginManager dm) { manager.addIPluginUpdateListener(this); + manager.updateNamespaces(); Log.warning("Start Adding plugins "); for(JPanel p: manager.getPanels()){ diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/DyIOPanel.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/DyIOPanel.java index 05f013b..16b7311 100644 --- a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/DyIOPanel.java +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/DyIOPanel.java @@ -83,7 +83,7 @@ public void actionPerformed(ActionEvent e) { } }); int pr = Log.getMinimumPrintLevel(); - Log.enableInfoPrint(); + //Log.enableInfoPrint(); //brownOutDetect.setSelected(DyIORegestry.get().isServoPowerSafeMode()); Log.setMinimumPrintLevel(pr); brownOutDetect.addActionListener(new ActionListener() { diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/NRConsoleDyIOPlugin.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/NRConsoleDyIOPlugin.java index 2aa8571..f32cfd2 100644 --- a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/NRConsoleDyIOPlugin.java +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/NRConsoleDyIOPlugin.java @@ -45,7 +45,7 @@ public class NRConsoleDyIOPlugin implements INRConsoleTabedPanelPlugin,IChannelP private JMenuItem showSequencerConf = new JMenuItem("Show Sequencer Configuration"); private JMenuItem showPidConf = new JMenuItem("Show P.I.D. Configuration"); private JMenuItem showCloud = new JMenuItem("Show Cloud Computing Configuration"); - private JMenuItem showGettingStarted = new JMenuItem("Getting Started"); + //private JMenuItem showGettingStarted = new JMenuItem("Getting Started"); private JMenuItem graphOptionsMenuItem = new JMenuItem("Graphing Options"); private JMenuItem exportData = new JMenuItem("Export Data to File"); private boolean active=false; @@ -105,7 +105,6 @@ public boolean setConnection(BowlerAbstractConnection connection){ DyIORegestry.setConnection(connection); DyIORegestry.get().connect(); - try { DyIO.enableFWCheck(); DyIORegestry.get().checkFirmwareRev(); @@ -166,7 +165,7 @@ public boolean isAcvive() { public ArrayList getMenueItems() { JMenu collectionMenu = new JMenu("DyIO"); - collectionMenu.add(showGettingStarted); + //collectionMenu.add(showGettingStarted); //collectionMenu.add(showGraphMenuItem); collectionMenu.add(exportData); collectionMenu.add(showPidConf); @@ -228,17 +227,17 @@ public void run() { }.start(); } }); - showGettingStarted.addActionListener(new ActionListener() { - - public void actionPerformed(ActionEvent e) { - - INRConsoleTabedPanelPlugin p =new NRConsoleGettingStartedPlugin(manager); - p.setConnection(DyIORegestry.get().getConnection()); - manager.firePluginUpdate(); - showGettingStarted.setEnabled(false); - - } - }); +// showGettingStarted.addActionListener(new ActionListener() { +// +// public void actionPerformed(ActionEvent e) { +// +// INRConsoleTabedPanelPlugin p =new NRConsoleGettingStartedPlugin(manager); +// p.setConnection(DyIORegestry.get().getConnection()); +// manager.firePluginUpdate(); +// showGettingStarted.setEnabled(false); +// +// } +// }); showHexapodConf.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -401,6 +400,7 @@ public Dimension getMinimumWimdowDimentions() { @Override public void setActive(boolean b) { + if(active && DyIORegestry.get().isAvailable() && !b){ //DyIORegestry.get().killAllPidGroups(); for(int i =0;i<24;i++){ diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/NRConsoleGettingStartedPlugin.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/NRConsoleGettingStartedPlugin.java deleted file mode 100644 index ae4856f..0000000 --- a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/DyIO/NRConsoleGettingStartedPlugin.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.neuronrobotics.nrconsole.plugin.DyIO; - -import java.awt.Dimension; - -import javax.swing.JPanel; - -import com.neuronrobotics.nrconsole.plugin.AbstractNRConsoleTabedPanelPlugin; -import com.neuronrobotics.nrconsole.plugin.PluginManager; -import com.neuronrobotics.sdk.common.BowlerAbstractConnection; - -public class NRConsoleGettingStartedPlugin extends AbstractNRConsoleTabedPanelPlugin { - - public static final String[] myNames ={"neuronrobotics.dyio.*"}; - private GettingStartedPanel content; - public NRConsoleGettingStartedPlugin(PluginManager pm){ - super(myNames,pm); - } - - public JPanel getTabPane() { - if(content == null) - content = new GettingStartedPanel(); - content.setSize(getMinimumWimdowDimentions()); - return content; - } - - - public boolean setConnection(BowlerAbstractConnection connection) { - - return true; - } - - - - @Override - public Dimension getMinimumWimdowDimentions() { - // TODO Auto-generated method stub - return new Dimension(1400,1000); - } - -} diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/PluginManager.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/PluginManager.java index 1893c91..df1255a 100644 --- a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/PluginManager.java +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/PluginManager.java @@ -18,10 +18,13 @@ import com.neuronrobotics.nrconsole.plugin.cartesian.CartesianController; import com.neuronrobotics.nrconsole.plugin.scripting.NRConsoleScriptingPlugin; import com.neuronrobotics.sdk.common.BowlerAbstractConnection; +import com.neuronrobotics.sdk.common.BowlerDatagram; import com.neuronrobotics.sdk.common.IConnectionEventListener; import com.neuronrobotics.sdk.common.InvalidConnectionException; +import com.neuronrobotics.sdk.common.Log; import com.neuronrobotics.sdk.genericdevice.GenericDevice; import com.neuronrobotics.sdk.ui.ConnectionDialog; +import com.neuronrobotics.sdk.util.ThreadUtil; public class PluginManager { private ArrayList plugins = new ArrayList(); @@ -34,7 +37,8 @@ public class PluginManager { private JFrame frame; public PluginManager(JFrame frame){ this.setFrame(frame); - update(); + disconnect(); + } public void removeNRConsoleTabedPanelPlugin(INRConsoleTabedPanelPlugin p){ @@ -83,13 +87,14 @@ public boolean disconnect(){ for(INRConsoleTabedPanelPlugin pl:plugins){ pl.setActive(false); } - update(); + if(connection != null) { connection.disconnect(); } + return true; } - private void updateNamespaces(){ + public void updateNamespaces(){ for (int i=0;i(); + // HACK this should load using OSGI + // Once instantiated they add themselves to the static list of plugins + new NRConsoleJobExecPlugin(this); + new NRConsoleDeviceConfigPlugin(this); + new CartesianController(this); + + new NRConsoleDyIOPlugin(this); + new NRConsoleScriptingPlugin(this); + + new NRConsolePIDPlugin(this); + new NRConsoleBowlerCameraPlugin(this); + new NRConsoleBootloaderPlugin(this); + new NRConsoleBowlerRPCDisplayPlugin(this); + connection = ConnectionDialog.promptConnection(); + if(connection == null) { + return false; + } + + + Log.error("Switching to v4 parser"); + BowlerDatagram.setUseBowlerV4(true); + + gen = new GenericDevice(connection); + try{ + if(!gen.connect()) { + throw new InvalidConnectionException("Connection is invalid"); + } + if(!gen.ping(true)){ + throw new InvalidConnectionException("Communication failed"); } - connection.addConnectionEventListener(listener); - gen = new GenericDevice(connection); + } catch(Exception e) { + //connection.disconnect(); + ThreadUtil.wait(1000); + BowlerDatagram.setUseBowlerV4(false); if(!gen.connect()) { throw new InvalidConnectionException("Connection is invalid"); } @@ -113,9 +147,10 @@ public boolean connect(IConnectionEventListener listener) throws Exception{ connection = null; throw new InvalidConnectionException("Communication failed"); } - } catch(Exception e) { throw e; } + connection.addConnectionEventListener(listener); + setNameSpaces(gen.getNamespaces()); updateNamespaces(); for (int i=0;i(); - // HACK this should load using OSGI - // Once instantiated they add themselves to the static list of plugins - new NRConsoleJobExecPlugin(this); - new NRConsoleDeviceConfigPlugin(this); - new CartesianController(this); - new NRConsoleDyIOPlugin(this); - new NRConsolePIDPlugin(this); - new NRConsoleBowlerCameraPlugin(this); - new NRConsoleBootloaderPlugin(this); - new NRConsoleBowlerRPCDisplayPlugin(this); - new NRConsoleScriptingPlugin(this); - - //new NRConsoleBowlerConfigPlugin(this); - //System.out.println("Updating plugins:"+plugins); - - //END HACK - } + private ArrayList puListeners = new ArrayList(); public void addIPluginUpdateListener(IPluginUpdateListener l) { if(puListeners.contains(l)) @@ -221,9 +234,10 @@ public void removeIPluginUpdateListener(IPluginUpdateListener l) { puListeners.remove(l); } public void firePluginUpdate(){ + updateNamespaces(); //System.out.println(this.getClass()+"is refreshing"); - for(IPluginUpdateListener l:puListeners){ - l.onPluginListUpdate(this); + for(int i=0;i { + initFX(this); + pm.getFrame().addComponentListener(new java.awt.event.ComponentAdapter() { + public void componentResized(java.awt.event.ComponentEvent e) { + //Preferred Size of TabPane. + Platform.runLater(()-> { + tabPane.setPrefSize(pm.getFrame().getWidth()-50, pm.getFrame().getHeight()-100); + }); + } + }); + }); + } + + + private void initFX(JFXPanel fxPanel) { + // This method is invoked on JavaFX thread + Scene scene = createScene(); + fxPanel.setScene(scene); + } + + //Custom function for creation of New Tabs. + private void createFileTab(File file) { + + try { + addTab(new LocalFileScriptTabTab( dyio, pm, file),true); + + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + //Custom function for creation of New Tabs. + private void createAndSelectNewTab(final TabPane tabPane, final String title) { + + + try { + addTab(new ScriptingGistTab(title,dyio, pm , getHomeUrl(),tabPane), false); + } catch (IOException | InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + + private Tab createTab() throws IOException, InterruptedException{ + final ScriptingGistTab tab = new ScriptingGistTab(null,dyio, pm , null,null); + + return tab; + } + + public void addTab(Tab tab, boolean closable){ + Platform.runLater(()->{ + final ObservableList tabs = tabPane.getTabs(); + tab.setClosable(closable); + tabs.add(tabs.size() - 1, tab); + tabPane.getSelectionModel().select(tab); + }); + } + + + public Scene createScene() { + + final Group root = new Group(); + + BorderPane borderPane = new BorderPane(); + tabPane = new TabPane(); + + //Preferred Size of TabPane. + tabPane.setPrefSize(1365, 1024); + + //Placement of TabPane. + tabPane.setSide(Side.TOP); + + /* To disable closing of tabs. + * tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);*/ + + final Tab newtab = new Tab(); + newtab.setText("New Gist"); + newtab.setClosable(false); + + //Addition of New Tab to the tabpane. + tabPane.getTabs().addAll(newtab); + + createAndSelectNewTab(tabPane, "About NrConsole"); + + //Function to add and display new tabs with default URL display. + tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, + Tab oldSelectedTab, Tab newSelectedTab) { + if (newSelectedTab == newtab) { + + try { + addTab(createTab(),true); + + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + } + } + }); + + borderPane.setCenter(tabPane); + + + root.getChildren().add(borderPane); + + + return new Scene(root); + } + + + public static String getHomeUrl() { + return HOME_URL; + } + + + public void open() { + File last=FileSelectionFactory.GetFile(null, new GroovyFilter()); + if(last != null){ + createFileTab(last); + } + } + +} \ No newline at end of file diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/GithubGistBrowser.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/GithubGistBrowser.java deleted file mode 100644 index 72a83d5..0000000 --- a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/GithubGistBrowser.java +++ /dev/null @@ -1,327 +0,0 @@ -package com.neuronrobotics.nrconsole.plugin.scripting; - -import javafx.application.Platform; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.ObservableList; -import javafx.embed.swing.JFXPanel; -import javafx.event.EventHandler; -import javafx.scene.Scene; -import javafx.scene.web.WebEngine; -import javafx.scene.web.WebEvent; -import javafx.scene.web.WebHistory; -import javafx.scene.web.WebView; - -import javax.swing.*; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import net.miginfocom.swing.MigLayout; - -import java.awt.*; -import java.awt.event.*; -import java.io.StringWriter; -import java.net.MalformedURLException; -import java.net.URL; - -import static javafx.concurrent.Worker.State.FAILED; - - -public class GithubGistBrowser extends JPanel { - /** - * - */ - private static final long serialVersionUID = 5343656469640871773L; - private final JFXPanel jfxPanel = new JFXPanel(); - private WebEngine engine; - - private final JLabel lblStatus = new JLabel(); - - - private final JButton btnGo = new JButton("Go"); - private final JButton forward = new JButton("Fwd"); - private final JButton back = new JButton("Back"); - private final JButton btnHome = new JButton("Home"); - private final JButton btnNewGist = new JButton("New Gist"); - private final JTextField txtURL = new JTextField(100); - private final JProgressBar progressBar = new JProgressBar(); - private WebView view; - - public GithubGistBrowser() { - super(); - setLayout(new MigLayout()); - initComponents(); - } - - - private void initComponents() { - createScene(); - - ActionListener al = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - loadURL(txtURL.getText()); - } - }; - - btnGo.addActionListener(al); - txtURL.addActionListener(al); - btnHome.addActionListener(e -> { - loadURL("http://neuronrobotics.github.io/Java-Code-Library/Digital-Input-Example-Simple/"); - }); - btnNewGist.addActionListener(e -> { - loadURL("https://gist.github.com/"); - }); - back.addActionListener(e -> { - goBack(); - }); - forward.addActionListener(e -> { - goForward(); - }); - - progressBar.setPreferredSize(new Dimension(150, 18)); - progressBar.setStringPainted(true); - - JPanel topBar = new JPanel(new MigLayout()); - topBar.add(back); - topBar.add(forward); - topBar.add(btnHome); - topBar.add(btnNewGist); - topBar.add(txtURL ); - topBar.add(btnGo); - - JPanel statusBar = new JPanel(new MigLayout()); - statusBar.add(progressBar); - statusBar.add(lblStatus); - - - add(topBar, "wrap"); - add(jfxPanel, "wrap"); - add(statusBar, "wrap"); - - -// setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); -// pack(); - - } - - private void createScene() { - - Platform.runLater(new Runnable() { - - - @Override - public void run() { - - view = new WebView(); - engine = view.getEngine(); - engine.titleProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, String oldValue, final String newValue) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - GithubGistBrowser.this.setName(newValue); - } - }); - } - }); - - engine.setOnStatusChanged(new EventHandler>() { - @Override - public void handle(final WebEvent event) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - lblStatus.setText(event.getData()); - } - }); - } - }); - - engine.locationProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue ov, String oldValue, final String newValue) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - txtURL.setText(newValue); - } - }); - } - }); - - engine.getLoadWorker().workDoneProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observableValue, Number oldValue, final Number newValue) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - progressBar.setValue(newValue.intValue()); - } - }); - } - }); - - engine.getLoadWorker() - .exceptionProperty() - .addListener(new ChangeListener() { - - public void changed(ObservableValue o, Throwable old, final Throwable value) { - if (engine.getLoadWorker().getState() == FAILED) { - SwingUtilities.invokeLater(new Runnable() { - @Override public void run() { - JOptionPane.showMessageDialog( - null, - (value != null) ? - engine.getLocation() + "\n" + value.getMessage() : - engine.getLocation() + "\nUnexpected error.", - "Loading error...", - JOptionPane.ERROR_MESSAGE); - } - }); - } - } - }); - - - Platform.runLater(() -> { - view.setPrefWidth(1168); - view.setPrefHeight(768); - jfxPanel.setScene(new Scene(view)); -// view.setOnMouseClicked(new EventHandler() { -// -// @Override -// public void handle(MouseEvent mouse) { -// -// } -// }); - }); - - } - }); - } - public String goBack() - { - final WebHistory history=engine.getHistory(); - ObservableList entryList=history.getEntries(); - int currentIndex=history.getCurrentIndex(); -// Out("currentIndex = "+currentIndex); -// Out(entryList.toString().replace("],","]\n")); - - Platform.runLater(new Runnable() { public void run() { history.go(-1); } }); - return entryList.get(currentIndex>0?currentIndex-1:currentIndex).getUrl(); - } - - public String goForward() - { - final WebHistory history=engine.getHistory(); - ObservableList entryList=history.getEntries(); - int currentIndex=history.getCurrentIndex(); -// Out("currentIndex = "+currentIndex); -// Out(entryList.toString().replace("],","]\n")); - - Platform.runLater(new Runnable() { public void run() { history.go(1); } }); - return entryList.get(currentIndex=2){ - String id = tokens[2].split("#")[0]; - System.out.println("Gist URL Detected "+id); - return id; - } - - return null; - } - private String returnFirstGist(String html){ - //System.out.println(html); - String slug = html.split("//gist.github.com/")[1]; - String js= slug.split(".js")[0]; - String id = js.split("/")[1]; - - return id; - } - - public String getCurrentGist() { - String gist = urlToGist(txtURL.getText()); - if (gist==null){ - - try { - System.out.println("Non Gist URL Detected"); - String html; - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer t = tf.newTransformer(); - StringWriter sw = new StringWriter(); - t.transform(new DOMSource(engine.getDocument()), new StreamResult(sw)); - html = sw.getBuffer().toString(); - return returnFirstGist(html); - } catch (TransformerConfigurationException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (TransformerException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - return gist; - } - - -} diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/IScriptEventListener.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/IScriptEventListener.java new file mode 100644 index 0000000..3509d4b --- /dev/null +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/IScriptEventListener.java @@ -0,0 +1,14 @@ +package com.neuronrobotics.nrconsole.plugin.scripting; + +import groovy.lang.GroovyShell; +import groovy.lang.Script; + +public interface IScriptEventListener { + + void onGroovyScriptFinished(GroovyShell shell, Script script, Object result); + + void onGroovyScriptChanged(String previous, String current); + + void onGroovyScriptError(GroovyShell shell, Script script, Exception except); + +} diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/LocalFileScriptTabTab.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/LocalFileScriptTabTab.java new file mode 100644 index 0000000..ee664a2 --- /dev/null +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/LocalFileScriptTabTab.java @@ -0,0 +1,132 @@ +package com.neuronrobotics.nrconsole.plugin.scripting; + +import java.io.File; +import java.io.IOException; +import java.time.Duration; +import java.util.regex.Pattern; + +import org.fxmisc.richtext.CodeArea; +import org.reactfx.Change; +import org.reactfx.EventStream; +import org.reactfx.EventStreams; + +import groovy.lang.GroovyShell; +import groovy.lang.Script; + +import java.util.Collection; +import java.util.Collections; +import java.util.regex.Matcher; +import javafx.application.Platform; +import javafx.scene.Cursor; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import org.fxmisc.richtext.StyleSpansBuilder; +import com.neuronrobotics.sdk.dyio.DyIO; +import com.neuronrobotics.nrconsole.plugin.PluginManager; +import javafx.scene.control.Tab; + +public class LocalFileScriptTabTab extends Tab implements IScriptEventListener{ + + private ScriptingEngine scripting; + private PluginManager pm; + private DyIO dyio; + private File file; + + private static final String[] KEYWORDS = new String[]{ + "def", "in", "as", "abstract", "assert", "boolean", "break", "byte", + "case", "catch", "char", "class", "const", + "continue", "default", "do", "double", "else", + "enum", "extends", "final", "finally", "float", + "for", "goto", "if", "implements", "import", + "instanceof", "int", "interface", "long", "native", + "new", "package", "private", "protected", "public", + "return", "short", "static", "strictfp", "super", + "switch", "synchronized", "this", "throw", "throws", + "transient", "try", "void", "volatile", "while" + }; + + private static final Pattern KEYWORD_PATTERN + = Pattern.compile("\\b(" + String.join("|", KEYWORDS) + ")\\b"); + private final CodeArea codeArea = new CodeArea(); + private VBox vBox; + + + public LocalFileScriptTabTab(DyIO dyio, PluginManager pm,File file) throws IOException { + this.dyio = dyio; + this.pm = pm; + this.file = file; + scripting = new ScriptingEngine(dyio, pm,file ); + setText(file.getName()); + codeArea.textProperty().addListener( + (ov, oldText, newText) -> { + Matcher matcher = KEYWORD_PATTERN.matcher(newText); + int lastKwEnd = 0; + StyleSpansBuilder> spansBuilder + = new StyleSpansBuilder<>(); + while (matcher.find()) { + spansBuilder.add(Collections.emptyList(), + matcher.start() - lastKwEnd); + spansBuilder.add(Collections.singleton("keyword"), + matcher.end() - matcher.start()); + lastKwEnd = matcher.end(); + } + spansBuilder.add(Collections.emptyList(), + newText.length() - lastKwEnd); + codeArea.setStyleSpans(0, spansBuilder.create()); + }); + + EventStream> textEvents + = EventStreams.changesOf(codeArea.textProperty()); + + textEvents.reduceSuccessions((a, b) -> b, Duration.ofMillis(1000)). + subscribe(code -> { + //code in text box changed + scripting.setCode(codeArea.getText()); + //scripting.save(); + }); + Platform.runLater(()->{ + codeArea.replaceText(scripting.getCode()); + }); + + + scripting.addIScriptEventListener(this); + + + // Layout logic + HBox hBox = new HBox(5); + hBox.getChildren().setAll(codeArea); + HBox.setHgrow(codeArea, Priority.ALWAYS); + + vBox = new VBox(5); + vBox.getChildren().setAll(hBox, scripting); + VBox.setVgrow(codeArea, Priority.ALWAYS); + + codeArea.setPrefSize(1000, 1000); + setContent(vBox); + } + + + @Override + public void onGroovyScriptFinished(GroovyShell shell, Script script, + Object result) { + // TODO Auto-generated method stub + + } + + + @Override + public void onGroovyScriptChanged(String previous, String current) { + Cursor place = codeArea.getCursor(); + codeArea.replaceText(current); + codeArea.setCursor(place); + } + + + @Override + public void onGroovyScriptError(GroovyShell shell, Script script, + Exception except) { + // TODO Auto-generated method stub + + } +} diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/NRConsoleScriptingPlugin.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/NRConsoleScriptingPlugin.java index ec7beb6..5f1ec4e 100644 --- a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/NRConsoleScriptingPlugin.java +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/NRConsoleScriptingPlugin.java @@ -4,8 +4,14 @@ import java.io.PrintStream; import java.util.ArrayList; +import javafx.application.Platform; + import javax.swing.JMenu; +import javax.swing.JMenuItem; import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import net.miginfocom.swing.MigLayout; import com.neuronrobotics.nrconsole.plugin.AbstractNRConsoleTabedPanelPlugin; import com.neuronrobotics.nrconsole.plugin.PluginManager; @@ -18,10 +24,12 @@ public class NRConsoleScriptingPlugin extends AbstractNRConsoleTabedPanelPlugin private static final String[] myNamespaces = new String[]{"neuronrobotics.dyio.*"}; - ScriptingEngine se =null; + GistTabbedBrowser se =null; private PluginManager pm; + private JPanel ret; + public NRConsoleScriptingPlugin( PluginManager pm) { super(myNamespaces, pm); @@ -30,21 +38,92 @@ public NRConsoleScriptingPlugin( PluginManager pm) { } public ArrayList getMenueItems() { - if(se!=null) - return se.getMenueItems(); - return null; + + JMenu collectionMenu = new JMenu("Script"); + JMenuItem open = new JMenuItem("Open"); + open.addActionListener(e -> { + se.open(); + }); + collectionMenu.add(open); + +// nativeIdisplay = new JMenuItem("Switch to "+interfaceType.Native); +// webgist = new JMenuItem("Switch to "+interfaceType.WebGist); +// +// nativeIdisplay.addActionListener(e -> { +// nativeIdisplay.setEnabled(false); +// webgist.setEnabled(true); +// toDisplay=interfaceType.Native; +// removeAll(); +// SwingUtilities.invokeLater(() -> { +// try { +// loadCodeFromCurrentGist(); +// } catch (Exception e1) { +// e1.printStackTrace(); +// } +// }); +// +// add(codeScroll,"wrap"); +// add(controls,"wrap"); +// add(outputPane,"wrap"); +// invalidate(); +// pm.getFrame().invalidate(); +// }); +// webgist.addActionListener(e -> { +// nativeIdisplay.setEnabled(true); +// webgist.setEnabled(false); +// toDisplay=interfaceType.WebGist; + // +// SwingUtilities.invokeLater(() -> { +// removeAll(); +// add(browser,"wrap"); +// add(controls,"wrap"); +// add(outputPane,"wrap"); +// updateFile(); +// save(); +// SwingUtilities.invokeLater(() -> { +// invalidate(); +// pm.getFrame().invalidate(); +// }); +// +// }); + // +// }); +// +// collectionMenu.add(nativeIdisplay); +// collectionMenu.add(webgist); +// webgist.setEnabled(false); + ArrayList m = new ArrayList(); + m.add(collectionMenu); + return m; } @Override public JPanel getTabPane() { - // TODO Auto-generated method stub - return se; + if(ret == null){ + se=new GistTabbedBrowser(DyIORegestry.get(),pm); + ret = new JPanel(new MigLayout()); + ret.setName("Groovy Scripting"); + ret.add(se); + pm.getFrame().addComponentListener(new java.awt.event.ComponentAdapter() { + public void componentResized(java.awt.event.ComponentEvent e) { + //Preferred Size of TabPane. + SwingUtilities.invokeLater(()-> { + ret.setSize(pm.getFrame().getWidth(), pm.getFrame().getHeight()); + se.setSize(pm.getFrame().getWidth(), pm.getFrame().getHeight()); + }); + } + }); + } + return ret; } @Override public boolean setConnection(BowlerAbstractConnection connection) { - // TODO Auto-generated method stub - se = new ScriptingEngine(DyIORegestry.get(),pm); + if(!DyIORegestry.get().isAvailable()){ + DyIORegestry.setConnection(connection); + DyIORegestry.get().connect(); + return DyIORegestry.get().isAvailable(); + } return true; } @@ -55,3 +134,5 @@ public Dimension getMinimumWimdowDimentions() { } } + + diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/ScriptingEngine.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/ScriptingEngine.java index 2862f50..7412014 100644 --- a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/ScriptingEngine.java +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/ScriptingEngine.java @@ -5,15 +5,12 @@ import groovy.lang.Script; import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.io.InterruptedIOException; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; @@ -26,145 +23,204 @@ import java.util.Map.Entry; import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextArea; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.FlowPane; +import javafx.scene.paint.Color; +import javafx.scene.web.WebEngine; -import javax.swing.AbstractAction; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.KeyStroke; -import javax.swing.SwingUtilities; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.control.customizers.ImportCustomizer; import org.kohsuke.github.GHGist; import org.kohsuke.github.GHGistFile; -import org.kohsuke.github.GHUser; import org.kohsuke.github.GitHub; import com.neuronrobotics.nrconsole.plugin.PluginManager; import com.neuronrobotics.nrconsole.util.FileSelectionFactory; import com.neuronrobotics.nrconsole.util.GroovyFilter; -import com.neuronrobotics.nrconsole.util.Mp3Filter; +import com.neuronrobotics.sdk.common.Log; import com.neuronrobotics.sdk.dyio.DyIO; -import com.neuronrobotics.sdk.dyio.DyIORegestry; import com.neuronrobotics.sdk.util.FileChangeWatcher; import com.neuronrobotics.sdk.util.IFileChangeListener; import com.neuronrobotics.sdk.util.ThreadUtil; -import net.miginfocom.swing.MigLayout; +public class ScriptingEngine extends BorderPane implements IFileChangeListener{ + + + static ByteArrayOutputStream out = new ByteArrayOutputStream(); + + private static ArrayList engines = new ArrayList(); + static{ + System.setOut(new PrintStream(out)); + Platform.runLater(() -> { + handlePrintUpdate(); + }); + } + + static void handlePrintUpdate() { -public class ScriptingEngine extends JPanel implements IFileChangeListener{ + ThreadUtil.wait(200); + Platform.runLater(() -> { + if(out.size()>0){ + Platform.runLater(() -> { + String newString = out.toString(); + out.reset(); + for(int i=0;i2000) + current=new String(current.substring(current.getBytes().length-2000)); + final String toSet=current; + engines.get(myIndex).output.setText(toSet); + engines.get(myIndex).output.setScrollTop(Double.MAX_VALUE); + } + + }); + } + }); + Platform.runLater(() -> { + // TODO Auto-generated method stub + handlePrintUpdate(); + }); + } /** * */ private static final long serialVersionUID = 1L; - private JTextArea output; - private JTextArea code; - private JButton run; - - private JLabel fileLabel =new JLabel("No File Loaded"); + private File currentFile = null; private boolean running = false; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - private PrintStream orig= System.out; + private TextArea output = new TextArea() ; private Thread scriptRunner=null; private FileChangeWatcher watcher; - private String currentGist = "40fadfa5804eee848e62"; private DyIO dyio; private PluginManager pm; - private GithubGistBrowser browser; + private Dimension codeDimentions = new Dimension(1168, 768); + Label fileLabel = new Label(); + + private String codeText="println(dyio)\n" + + "while(true){\n" + + "\tThreadUtil.wait(100) // Spcae out the loop\n\n" + + "\tlong start = System.currentTimeMillis() //capture the starting value \n\n" + + "\tint value = dyio.getValue(15) //grab the value of pin 15\n" + + "\tint scaled = value/4 //scale the analog voltage to match the range of the servos\n" + + "\tdyio.setValue(0,scaled) // set the new value to the servo\n\n" + + "\t//Print out this loops values\n" + + "\tprint(\" Loop took = \"+(System.currentTimeMillis()-start))\n" + + "\tprint(\"ms Value= \"+value)\n" + + "\tprintln(\" Scaled= \"+scaled)\n" + + "}"; - private void reset(){ - System.setOut(orig); - running = false; - SwingUtilities.invokeLater(() -> { - run.setText("Run"); - }); + private ArrayList listeners = new ArrayList(); - } + private Button runfx= new Button("Run");; + private Button runsave= new Button("Save");; + private WebEngine engine; + + private String addr; + boolean loadGist=false; - private String getHTMLFromGist(String gist){ - return ""; + public ScriptingEngine(DyIO dyio, PluginManager pm, File currentFile,String currentGist, WebEngine engine ) throws IOException, InterruptedException{ + this(dyio,pm); + this.currentFile = currentFile; + loadCodeFromGist(currentGist,engine); } - - public ScriptingEngine(DyIO dyio, PluginManager pm){ + public ScriptingEngine(DyIO dyio, PluginManager pm,File currentFile) throws IOException{ + this(dyio,pm); + this.currentFile = currentFile; + loadCodeFromFile(currentFile); + } + + private ScriptingEngine(DyIO dyio, PluginManager pm){ this.dyio = dyio; this.pm = pm; - setName("Bowler Scripting"); - setLayout(new MigLayout()); - code = new JTextArea(20, 40); - output = new JTextArea(20, 100); - JScrollPane outputPane = new JScrollPane(output); - browser = new GithubGistBrowser(); - browser.setVisible(true); - browser.loadURL("http://neuronrobotics.github.io/Java-Code-Library/Digital-Input-Example-Simple/"); - //browser.loadURL("https://gist.github.com/madhephaestus/"+currentGist); - //browser.setPreferredSize(new Dimension(1400,600)); - //browser.loadHTML( getHTMLFromGist(currentGist)); - - run = new JButton("Run"); - JPanel controls = new JPanel(new MigLayout()); - controls.add(run); - controls.add(fileLabel); - -// JScrollPane codeScroll = new JScrollPane(code); -// codeScroll.setPreferredSize(new Dimension(1024, 400)); -// add(codeScroll,"wrap"); - - add(browser,"wrap"); - add(controls,"wrap"); - add(outputPane,"wrap"); - - - //getCode(); - setCode("println(dyio)\n" - + "while(true){\n" - + "\tThreadUtil.wait(100) // Spcae out the loop\n\n" - + "\tlong start = System.currentTimeMillis() //capture the starting value \n\n" - + "\tint value = dyio.getValue(15) //grab the value of pin 15\n" - + "\tint scaled = value/4 //scale the analog voltage to match the range of the servos\n" - + "\tdyio.setValue(0,scaled) // set the new value to the servo\n\n" - + "\t//Print out this loops values\n" - + "\tprint(\" Loop took = \"+(System.currentTimeMillis()-start))\n" - + "\tprint(\"ms Value= \"+value)\n" - + "\tprintln(\" Scaled= \"+scaled)\n" - + "}"); -// setCode(""); - - run.addActionListener(e -> { + runfx.setOnAction(e -> { if(running) stop(); else - start(); + start(); + }); + runsave.setOnAction(e -> { + save(); }); - String ctrlSave = "CTRL Save"; - code.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK), ctrlSave); - code.getActionMap().put(ctrlSave, new AbstractAction() { - /** - * - */ - private static final long serialVersionUID = 2405985221209391722L; - - @Override - public void actionPerformed(ActionEvent e) { - System.out.println("Saving Script"); - save(); - } + + + //String ctrlSave = "CTRL Save"; + engines.add(this); + fileLabel.setOnMouseEntered(e->{ + Platform.runLater(() -> { + ThreadUtil.wait(10); + fileLabel.setText(currentFile.getAbsolutePath()); + }); }); + + fileLabel.setOnMouseExited(e->{ + Platform.runLater(() -> { + ThreadUtil.wait(10); + fileLabel.setText(currentFile.getName()); + }); + }); + fileLabel.setTextFill(Color.GREEN); + + //Set up the run controls and the code area + // The BorderPane has the same areas laid out as the + // BorderLayout layout manager + setPadding(new Insets(20, 0, 20, 20)); + final FlowPane controlPane = new FlowPane(); + controlPane.setHgap(100); + controlPane.getChildren().add(runfx); + controlPane.getChildren().add(runsave); + controlPane.getChildren().add(fileLabel); + // put the flowpane in the top area of the BorderPane + setTop(controlPane); + setBottom(output); + output.textProperty().addListener((ChangeListener) (ov, oldValue, newValue) -> output.setScrollTop(Double.MAX_VALUE)); + } + + private void reset(){ + running = false; + Platform.runLater(() -> { + runfx.setText("Run"); + }); + + } + +// private String getHTMLFromGist(String gist){ +// return ""; +// } + + public void addIScriptEventListener(IScriptEventListener l){ + if(!listeners.contains(l)) + listeners.add(l); + } + + public void removeIScriptEventListener(IScriptEventListener l){ + if(listeners.contains(l)) + listeners.remove(l); } private void stop() { // TODO Auto-generated method stub reset(); while(scriptRunner.isAlive()){ - System.out.println("Interrupting"); + + Log.debug("Interrupting"); ThreadUtil.wait(10); try { scriptRunner.interrupt(); @@ -176,40 +232,96 @@ private void stop() { } } - - private void loadCodeFromCurrentGist() throws IOException, InterruptedException{ + public void loadCodeFromFile(File currentFile) throws IOException{ + setUpFile(currentFile); + setCode(new String(Files.readAllBytes(currentFile.toPath()))); + } + public void loadCodeFromGist(String addr,WebEngine engine) throws IOException, InterruptedException{ + this.addr = addr; + this.engine = engine; + loadGist=true; + String currentGist = getCurrentGist(addr,engine); GitHub github = GitHub.connectAnonymously(); - currentGist = browser.getCurrentGist(); - System.out.println("Loading Gist: "+currentGist); - GHGist gist = github.getGist(currentGist); - Map files = gist.getFiles(); - for (Entry entry : files.entrySet()) { - if(entry.getKey().endsWith(".java") || entry.getKey().endsWith(".groovy")){ - GHGistFile ghfile = entry.getValue(); - System.out.println("Key = " + entry.getKey()); - SwingUtilities.invokeLater(() -> { - setCode(ghfile.getContent()); - fileLabel.setText(entry.getKey().toString()); - if(currentFile==null) - currentFile = new File(fileLabel.getText()); - }); - Thread.sleep(200); - break; + Log.debug("Loading Gist: "+currentGist); + try{ + GHGist gist = github.getGist(currentGist); + Map files = gist.getFiles(); + for (Entry entry : files.entrySet()) { + if(entry.getKey().endsWith(".java") || entry.getKey().endsWith(".groovy")){ + GHGistFile ghfile = entry.getValue(); + Log.debug("Key = " + entry.getKey()); + //Platform.runLater(() -> { + setCode(ghfile.getContent()); + String fileName = entry.getKey().toString(); + fileLabel.setText(fileName); + currentFile = new File(fileName); + //}); + break; + } } + }catch (InterruptedIOException e){ + System.out.println("Gist Rate limited"); + }catch(Exception ex){ + ex.printStackTrace(); } } + + public String urlToGist(String in) { + String domain = in.split("//")[1]; + String [] tokens = domain.split("/"); + if (tokens[0].toLowerCase().contains("gist.github.com") && tokens.length>=2){ + String id = tokens[2].split("#")[0]; + + Log.debug("Gist URL Detected "+id); + return id; + } + + return null; + } + private String returnFirstGist(String html){ + //Log.debug(html); + String slug = html.split("//gist.github.com/")[1]; + String js= slug.split(".js")[0]; + String id = js.split("/")[1]; + + return id; + } + + public String getCurrentGist(String addr,WebEngine engine) { + String gist = urlToGist(addr); + if (gist==null){ + try { + Log.debug("Non Gist URL Detected"); + String html; + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer t = tf.newTransformer(); + StringWriter sw = new StringWriter(); + t.transform(new DOMSource(engine.getDocument()), new StreamResult(sw)); + html = sw.getBuffer().toString(); + return returnFirstGist(html); + } catch (TransformerConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (TransformerException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + return gist; + } + private void start() { running = true; - run.setText("Stop"); + runfx.setText("Stop"); scriptRunner = new Thread(){ public void run() { - setName("Bowler Script Runner"); - try{ - - loadCodeFromCurrentGist(); + setName("Bowler Script Runner "+currentFile.getName()); + + //try{ output.setText(""); CompilerConfiguration cc = new CompilerConfiguration(); @@ -225,115 +337,93 @@ public void run() { ); Binding binding = new Binding(); - System.setOut(new PrintStream(out)); + binding.setVariable("dyio", dyio); binding.setVariable("PluginManager", pm); + GroovyShell shell = new GroovyShell(getClass().getClassLoader(), + binding, cc); + System.out.println(getCode()+"\n\nStart\n\n"); + Script script = shell.parse(getCode()); try{ - GroovyShell shell = new GroovyShell(getClass().getClassLoader(), - binding, cc); - System.out.println(getCode()+"\n\nStart\n\n"); - Script script = shell.parse(getCode()); - Object obj = script.run(); - }catch(org.codehaus.groovy.control.MultipleCompilationErrorsException ex){ - throw ex; + for(IScriptEventListener l:listeners){ + l.onGroovyScriptFinished(shell, script, obj); + } + Platform.runLater(() -> { + append("\n"+currentFile+" Completed\n"); + }); + reset(); + + }catch(Exception ex){ + Platform.runLater(() -> { + if(!ex.getMessage().contains("sleep interrupted")){ + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + ex.printStackTrace(pw); + append("\n"+currentFile+" \n"+sw+"\n"); + + }else{ + append("\n"+currentFile+" Interupted\n"); + } + + reset(); + }); + for(IScriptEventListener l:listeners){ + l.onGroovyScriptError(shell, script, ex); + } + throw new RuntimeException(ex); } - SwingUtilities.invokeLater(() -> { - output.append("\nScript Completed\n"); - output.setCaretPosition(output.getDocument().getLength()); - }); - reset(); - }catch(Exception e){ - SwingUtilities.invokeLater(() -> { - if(!e.getMessage().contains("sleep interrupted")){ - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - output.append("\n"+sw+"\n"); - - }else{ - output.append("\nScript Interupted\n"); - } - output.setCaretPosition(output.getDocument().getLength()); - running = false; - run.setText("Run"); - System.setOut(orig); - }); - throw new RuntimeException(e); - } + } }; - SwingUtilities.invokeLater(() -> { - handlePrintUpdate(); - }); - scriptRunner.start(); - } - - private void handlePrintUpdate() { - // TODO Auto-generated method stub - ThreadUtil.wait(100); - SwingUtilities.invokeLater(() -> { - if(out.size()>0){ - output.append(out.toString()); - out.reset(); - output.setCaretPosition(output.getDocument().getLength()); + Platform.runLater(() -> { + try { + if(loadGist) + loadCodeFromGist( addr, engine); + else + save(); + scriptRunner.start(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); } }); - SwingUtilities.invokeLater(() -> { - // TODO Auto-generated method stub - handlePrintUpdate(); - }); + + } + + private void append(String s){ + System.out.println(s); } - public ArrayList getMenueItems() { - JMenu collectionMenu = new JMenu("Script"); - JMenuItem open = new JMenuItem("Open"); - open.addActionListener(e -> { - open(); - }); - collectionMenu.add(open); - - JMenuItem saveas = new JMenuItem("Save As"); - saveas.addActionListener(e -> { - updateFile(); - save(); + private void setUpFile(File f){ + currentFile = f; + Platform.runLater(() -> { + fileLabel.setText(f.getName()); }); - collectionMenu.add(saveas); - - JMenuItem save = new JMenuItem("Save"); - save.addActionListener(e -> { - save(); - }); - collectionMenu.add(save); - - ArrayList m = new ArrayList(); - m.add(collectionMenu); - return m; + if (watcher != null) { + watcher.close(); + } + try { + watcher = new FileChangeWatcher(currentFile); + watcher.addIFileChangeListener(this); + watcher.start(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } private void updateFile(){ - File last=FileSelectionFactory.GetFile(currentFile, new GroovyFilter()); if(last != null){ - currentFile = last; - if(watcher!=null){ - watcher.close(); - } - try { - watcher = new FileChangeWatcher(currentFile); - watcher.addIFileChangeListener(this); - watcher.start(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + setUpFile(last); } } - private void open() { + public void open() { updateFile(); try { @@ -344,7 +434,7 @@ private void open() { } } - private void save() { + public void save() { // TODO Auto-generated method stub try { @@ -367,6 +457,11 @@ public void onFileChange(File fileThatChanged, @SuppressWarnings("rawtypes") Wat public void run() { try { setCode(new String(Files.readAllBytes(Paths.get(fileThatChanged.getAbsolutePath())), "UTF-8")); + fileLabel.setTextFill(Color.RED); + Platform.runLater(() -> { + ThreadUtil.wait(750); + fileLabel.setTextFill(Color.GREEN); + }); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -382,15 +477,23 @@ public void run() { } } - protected String getCode(){ + public String getCode(){ + return codeText; + } - return code.getText(); + public void setCode(String string) { + String pervious = codeText; + codeText=string; + //System.out.println(codeText); + for(IScriptEventListener l:listeners){ + l.onGroovyScriptChanged(pervious, string); + } } - protected void setCode(String string) { - SwingUtilities.invokeLater(() -> { - code.setText(string); - }); + + public String getFileName() { + return currentFile.getName(); } + } diff --git a/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/ScriptingGistTab.java b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/ScriptingGistTab.java new file mode 100644 index 0000000..2ff338b --- /dev/null +++ b/application/nrconsole/src/com/neuronrobotics/nrconsole/plugin/scripting/ScriptingGistTab.java @@ -0,0 +1,267 @@ +package com.neuronrobotics.nrconsole.plugin.scripting; + +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import javax.imageio.ImageIO; +import javax.swing.SwingUtilities; + +import com.neuronrobotics.nrconsole.plugin.PluginManager; +import com.neuronrobotics.sdk.common.Log; +import com.neuronrobotics.sdk.dyio.DyIO; +import com.neuronrobotics.sdk.util.ThreadUtil; + +import javafx.application.Platform; +import javafx.beans.binding.Bindings; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.collections.ObservableList; +import javafx.concurrent.Worker.State; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.control.Button; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.control.TextField; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebHistory; +import javafx.scene.web.WebView; + +public class ScriptingGistTab extends Tab { + + private String Current_URL = "http://gist.github.com/"; + private PluginManager pm; + private DyIO dyio; + private ScriptingGistTab myTab; + private TabPane tabPane = null; + boolean loaded=false; + boolean initialized=false; + private WebView webView; + private WebEngine webEngine; + private VBox vBox; + private Button goButton = new Button("Go"); + private Button homeButton = new Button("Home"); + private Button backButton = new Button("<"); + private Button forwardButton = new Button(">"); + + private TextField urlField; + //private String currentAddress; + private ScriptingEngine scripting; + + + + public ScriptingGistTab(String title,DyIO dyio, PluginManager pm, String Url,TabPane tabPane) throws IOException, InterruptedException{ + this.dyio = dyio; + this.pm = pm; + this.tabPane = tabPane; + myTab = this; + if(pm== null) + return; + pm.getFrame().addComponentListener(new java.awt.event.ComponentAdapter() { + public void componentResized(java.awt.event.ComponentEvent e) { + //Preferred Size of TabPane. + Platform.runLater(()-> { + webView.setPrefSize(pm.getFrame().getWidth()-50, pm.getFrame().getHeight()-100); + }); + } + }); + if(title==null) + myTab.setText(" "); + else + myTab.setText(title); + Log.debug("Loading Gist Tab: "+Url); + webView = new WebView(); + webEngine = webView.getEngine(); + + if(Url!=null) + Current_URL=Url; + webEngine.load(Current_URL); + + loaded=false; + webEngine.getLoadWorker().workDoneProperty().addListener((ChangeListener) (observableValue, oldValue, newValue) -> Platform.runLater(() -> { + if(!(newValue.intValue()<100)){ + if(!initialized){ + initialized=true; + try { + finishLoadingComponents(); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (InterruptedException e2) { + // TODO Auto-generated catch block + e2.printStackTrace(); + } + } + loaded=true; + try { + scripting.loadCodeFromGist(Current_URL, webEngine); + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }else + loaded=false; + })); + urlField = new TextField(Current_URL); + webEngine.locationProperty().addListener((ChangeListener) (observable1, oldValue, newValue) ->{ + urlField.setText(newValue); + + }); + + goButton.setDefaultButton(true); + + webEngine.getLoadWorker().stateProperty().addListener( + new ChangeListener() { + public void changed(ObservableValue observable, + Object oldValue, Object newValue) { + State oldState = (State)oldValue; + State newState = (State)newValue; + if (State.SUCCEEDED == newValue) { + Current_URL = urlField.getText().startsWith("http://")|| urlField.getText().startsWith("https://") + ? urlField.getText() + : "http://" + urlField.getText(); + + Log.debug("Navagating "+Current_URL); + if( processNewTab(urlField.getText())){ + goBack(); + } + } + } + }); + backButton.setOnAction(arg0 -> { + goBack(); + }); + forwardButton.setOnAction(arg0 -> { + // TODO Auto-generated method stub + goForward(); + }); + homeButton.setOnAction(arg0 -> { + // TODO Auto-generated method stub + webEngine.load(GistTabbedBrowser.getHomeUrl()); + }); + + // Layout logic + HBox hBox = new HBox(5); + hBox.getChildren().setAll(backButton,forwardButton,homeButton,goButton,urlField); + HBox.setHgrow(urlField, Priority.ALWAYS); + + vBox = new VBox(5); + vBox.getChildren().setAll(hBox, webView); + VBox.setVgrow(webView, Priority.ALWAYS); + + myTab.setContent(vBox); + } + + private boolean processNewTab(String url){ + Current_URL = urlField.getText().startsWith("http://") || urlField.getText().startsWith("https://") + ? urlField.getText() + : "http://" + urlField.getText(); + if(tabPane!=null ){ + if(!Current_URL.contains("neuronrobotics.github.io")){ + try { + Log.debug("Non demo page found, opening new tab "+Current_URL); + final ScriptingGistTab tab = new ScriptingGistTab(null,dyio, pm , Current_URL,null); + final ObservableList tabs = tabPane.getTabs(); + tab.closableProperty().bind(Bindings.size(tabs).greaterThan(2)); + tabs.add(tabs.size() - 1, tab); + tabPane.getSelectionModel().select(tab); + return true; + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }else{ + if(scripting!=null){ + try{ + myTab.setText(scripting.getFileName()); + }catch(java.lang.NullPointerException ex){ + try { + scripting.loadCodeFromGist(Current_URL, webEngine); + myTab.setText(scripting.getFileName()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + return false; + } + + + + + + private void finishLoadingComponents() throws IOException, InterruptedException{ + scripting = new ScriptingEngine(dyio, pm, null ,Current_URL, webEngine); + + //Action definition for the Button Go. + EventHandler goAction = event -> { + if( !processNewTab(urlField.getText())){ + //Log.debug("Loading "+Current_URL); + //webEngine.load( Current_URL); + } + }; + + urlField.setOnAction(goAction); + goButton.setOnAction(goAction); + + vBox.getChildren().add(scripting); + if(tabPane==null){ + try{ + myTab.setText(scripting.getFileName()); + }catch(java.lang.NullPointerException ex){ + ex.printStackTrace(); + } + } + } + + public String goBack() + { + final WebHistory history=webEngine.getHistory(); + ObservableList entryList=history.getEntries(); + int currentIndex=history.getCurrentIndex(); +// Out("currentIndex = "+currentIndex); +// Out(entryList.toString().replace("],","]\n")); + + Platform.runLater(() ->{ + try{ + history.go(-1); + }catch(Exception e){} + }); + return entryList.get(currentIndex>0?currentIndex-1:currentIndex).getUrl(); + } + + public String goForward() + { + final WebHistory history=webEngine.getHistory(); + ObservableList entryList=history.getEntries(); + int currentIndex=history.getCurrentIndex(); +// Out("currentIndex = "+currentIndex); +// Out(entryList.toString().replace("],","]\n")); + + Platform.runLater(() -> history.go(1)); + return entryList.get(currentIndex