package com.drawbridge; import java.awt.BorderLayout; import java.awt.Desktop; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.event.EventHandler; import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.geometry.VPos; import javafx.scene.Scene; import javafx.scene.layout.HBox; import javafx.scene.layout.Region; import javafx.scene.web.WebEngine; import javafx.scene.web.WebEvent; import javafx.scene.web.WebView; import javax.swing.JButton; import javax.swing.JOptionPane; import com.drawbridge.dm.DMImageFactory.DMImage; import com.drawbridge.dm.DMPanel; import com.drawbridge.text.DBDocument.DBDocumentListener; import com.drawbridge.text.TextPanel; import com.drawbridge.utils.AnalyticUtils; import com.drawbridge.utils.GraphicUtils; import com.drawbridge.utils.JSUtils; import com.drawbridge.utils.SegmentPanel; import com.drawbridge.utils.TitlePanel; import com.drawbridge.utils.Utils; import com.drawbridge.vl.VLPanel; public class WebViewPanel extends SegmentPanel implements MouseListener, DBDocumentListener { private static final long serialVersionUID = 157476875799766795L; public static WebViewPanel instance = null; private MyBrowser myBrowser = null; private Scene scene = null; private boolean mPublishEnabled = false; private boolean mTestEnabled = true; private boolean mShowInBrowserEnabled = true; private final String mTestDir; public static WebViewPanel getInstance() { if (instance != null) { return instance; } else { instance = new WebViewPanel(); return instance; } } public WebViewPanel() { mTestDir = "/DrawBridge" + AnalyticUtils.username; final JFXPanel fxPanel = new JFXPanel(); this.setLayout(new BorderLayout()); TitlePanel mTitlePanel = new TitlePanel("Web View"); if(mTestEnabled){ JButton test = new JButton("Test"); test.setIcon(GraphicUtils.loadIconFromResource("/Assets/test.png")); test.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent me) { Platform.runLater(new Runnable() { @Override public void run() { myBrowser.requestCodeInjection(); AnalyticUtils.recordTestClick(); } }); } }); mTitlePanel.addButton(test); } if(mShowInBrowserEnabled){ JButton seeInBrowser = new JButton("Test In Browser"); seeInBrowser.setIcon(GraphicUtils.loadIconFromResource("/Assets/browser.png")); seeInBrowser.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent me) { if (Desktop.isDesktopSupported()) { try { File defaultHTML = new File(Utils.getTemporaryFolder() + mTestDir + "/default.html"); if (defaultHTML.exists()) { Desktop.getDesktop().browse(defaultHTML.toURI()); AnalyticUtils.recordShowInBrowserClick(); } else { JOptionPane.showMessageDialog(WebViewPanel.this, "Could not load webpage because file cannot be found in file system."); } } catch (IOException e) { JOptionPane.showMessageDialog(WebViewPanel.this, "Could not load webpage because file cannot be found."); } } else { JOptionPane.showMessageDialog(WebViewPanel.this, "Could not load webpage because system won't tell java what browser to use."); } } }); mTitlePanel.addButton(seeInBrowser); } if(mPublishEnabled){ JButton publish = new JButton("Publish"); publish.setIcon(GraphicUtils.loadIconFromResource("/Assets/publish.png")); publish.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent me) { // Popup publish window } }); mTitlePanel.addButton(publish); } this.add(mTitlePanel, BorderLayout.NORTH); this.add(fxPanel, BorderLayout.CENTER); this.setVisible(true); Platform.runLater(new Runnable() { @Override public void run() { initFX(fxPanel); } }); } public void initFX(JFXPanel fxPanel) { myBrowser = new MyBrowser(); scene = new Scene(myBrowser, fxPanel.getWidth(), fxPanel.getHeight()); fxPanel.setScene(scene); } @Override public void mouseClicked(MouseEvent me) { this.requestFocus(); } @Override public void mouseEntered(MouseEvent me) { } @Override public void mouseExited(MouseEvent arg0) { } @Override public void mousePressed(MouseEvent arg0) { } @Override public void mouseReleased(MouseEvent arg0) { } class MyBrowser extends Region { HBox toolbar; WebView webView = new WebView(); WebEngine webEngine = webView.getEngine(); URL urlDefaultHTML = null; Long lastTimeInjected = null; public MyBrowser() { // Load placeholder html here webView.getEngine().setOnAlert(new EventHandler<WebEvent<String>>() { @Override public void handle(WebEvent<String> event) { Utils.out.println(event.getData()); } }); toolbar = new HBox(); toolbar.setPadding(new Insets(10, 10, 10, 10)); toolbar.setSpacing(10); toolbar.setStyle("-fx-background-color: #336699"); getChildren().add(webView); } @Override protected void layoutChildren() { double w = getWidth(); double h = getHeight(); double toolbarHeight = toolbar.prefHeight(w); layoutInArea(webView, 0, 0, w, h - toolbarHeight, 0, HPos.CENTER, VPos.CENTER); layoutInArea(toolbar, 0, h - toolbarHeight, w, toolbarHeight, 0, HPos.CENTER, VPos.CENTER); } // Method requests code injection. It's only allowed to happen every so often (e.g. not every key stroke). public void requestCodeInjection() { long timeDelay = 100; if (lastTimeInjected == null) { lastTimeInjected = System.currentTimeMillis() - timeDelay - 1; } if (lastTimeInjected <= (System.currentTimeMillis() - timeDelay)) { injectCode(); lastTimeInjected = System.currentTimeMillis(); } else { // TODO add some sort of concurrent checker for this } } public void injectCode() { Utils.out.println(this.getClass(), "Injecting code!"); // User Code Loading StringBuilder userCode = new StringBuilder(); if(TextPanel.hasInstance()) userCode.append("function userCode(){\n" + TextPanel.getInstance().getDocument().getText() + "\n}\n\n"); else if(VLPanel.hasInstance()) userCode.append("function userCode(){\n" + VLPanel.getInstance().mCanvas.getModel().generateCodeFromBlocks(VLPanel.getInstance().mCanvas.mViewGrid) + "\n}\n\n"); else throw new RuntimeException("Can't find any code representation to execute!"); Utils.out.println(this.getClass(), "UserCode:" + userCode); boolean canSaveUserCode = Utils.saveTextToFile(userCode.toString(), new File(Utils.getTemporaryFolder() + mTestDir + "/user_code.js")); boolean canSaveScaffolding = false; // Scaffolding loading if (canSaveUserCode) { String loadCode = ""; if (DMPanel.hasInstance()) { List<DMImage> list = DMPanel.getInstance().mModel.getModelObjects(); loadCode = getLoadImagesScript(list); } String part1 = Utils.loadTextFromPackagedFile("/SimpleTweeningJS/scaffolding1.js"); String part2 = Utils.loadTextFromPackagedFile("/SimpleTweeningJS/scaffolding2.js"); String joinedScaffoldingCode = part1 + loadCode + part2; canSaveScaffolding = Utils.saveTextToFile(joinedScaffoldingCode, new File(Utils.getTemporaryFolder() + mTestDir + "/scaffolding.js")); } Utils.out.println(this.getClass(), "loading default html!"); // Default HTML loading if (canSaveUserCode && canSaveScaffolding) { String defaultHTML = Utils.loadTextFromPackagedFile("/SimpleTweeningJS/default.html"); File newHTMLLocation = new File(Utils.getTemporaryFolder() + mTestDir + "/default.html"); Utils.saveTextToFile(defaultHTML, newHTMLLocation); try { webEngine.load(newHTMLLocation.toURI().toURL().toExternalForm()); webEngine.reload(); } catch (MalformedURLException e) { e.printStackTrace(); } } Utils.out.println(this.getClass(), "after default html!"); } } @Override public void onDocumentUpdate(final String string) { Platform.runLater(new Runnable() { @Override public void run() { Utils.out.println("Updating canvas.."); myBrowser.webEngine.executeScript(JSUtils.JS_CANVAS_RESET); myBrowser.webEngine.executeScript(string); } }); } // Loads image from their external URLs rather than internal memory. private String getLoadImagesScript(List<DMImage> dmImages) { String args = ""; int addedCount = 0; for (int i = 0; i < dmImages.size(); i++) { URL url = null; if (dmImages.get(i).getURL() == null) { if (Utils.saveImageToFile(dmImages.get(i), mTestDir) == true) { if (dmImages.get(i).getURL() != null) { url = dmImages.get(i).getURL(); } } else { JOptionPane.showMessageDialog(this, "Failed to save image to file"); Utils.out.println("Failed to save to file:" + dmImages.get(i).getName()); } } else { url = dmImages.get(i).getURL(); } if (url != null) { if (addedCount > 0) args += ", "; args += "\"" + url.toExternalForm() + "\""; addedCount++; } } return "preloadImages_helper(" + args + ");"; } }