/* * Copyright (C) 2011-2012 Dr. John Lindsay <jlindsay@uoguelph.ca> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package whiteboxgis.user_interfaces; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.*; import java.lang.reflect.*; import java.util.Map; import java.util.HashMap; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ResourceBundle; import javax.script.Bindings; import javax.script.Compilable; import javax.script.CompiledScript; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.swing.*; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import org.fife.ui.autocomplete.*; import org.fife.ui.rtextarea.*; import org.fife.ui.rsyntaxtextarea.*; //import whitebox.interfaces.Communicator; import whitebox.interfaces.WhiteboxPluginHost; import whitebox.utilities.ClassEnumerator; import static whiteboxgis.user_interfaces.Scripter.PROP_SCRIPTING_LANGUAGE; import static whiteboxgis.user_interfaces.Scripter.ScriptingLanguage.GROOVY; import static whiteboxgis.user_interfaces.Scripter.ScriptingLanguage.JAVASCRIPT; import static whiteboxgis.user_interfaces.Scripter.ScriptingLanguage.PYTHON; import whiteboxgis.ScripterCompletionProvider; /** * * @author Dr. John Lindsay email: jlindsay@uoguelph.ca */ public class Scripter extends JDialog implements ActionListener, KeyListener { private String pathSep; private String graphicsDirectory; private String scriptsDirectory; private String sourceFile = null; private WhiteboxPluginHost host = null; private RSyntaxTextArea editor = new RSyntaxTextArea(); private RTextScrollPane scroll; private ScriptEngineManager mgr = new ScriptEngineManager(); // private List<ScriptEngineFactory> factories = mgr.getEngineFactories(); private ScriptEngine engine; private JTextArea textArea = new JTextArea(); private JSplitPane splitPane; private PrintWriter errOut = new PrintWriter(new Scripter.TextAreaWriter(textArea)); private Scripter.ScriptingLanguage language = Scripter.ScriptingLanguage.PYTHON; private JPanel status = null; private JLabel statusLabel = new JLabel(); private JCheckBoxMenuItem python = new JCheckBoxMenuItem("Python"); private JCheckBoxMenuItem groovy = new JCheckBoxMenuItem("Groovy"); private JCheckBoxMenuItem javascript = new JCheckBoxMenuItem("Javascript"); private ResourceBundle bundle; // private JButton generateDataButton; public static final String PROP_SCRIPTING_LANGUAGE = "languageChanged"; // public static final String PROP_GENERATE_DATA = "generateData"; private int numLinesInDoc = 1; private boolean editorDirty = false; private JTextField searchField; private JTextField replaceField; private JCheckBox regexCB; private JCheckBox matchCaseCB; private JCheckBox wholeWordCB; private JToolBar findAndReplaceToolbar; private JButton nextButton; private JButton prevButton; private JLabel findLabel; private JLabel replaceLabel; private JButton replaceButton; private boolean saveOnExecution = true; public enum ScriptingLanguage { PYTHON("Python", "#"), GROOVY("Groovy", "//"), JAVASCRIPT("Javascript", "//"), RUBY("Ruby", "#"); private String displayName; private String commentMarker; private ScriptingLanguage(String displayName, String commentMarker) { this.displayName = displayName; this.commentMarker = commentMarker; } public String getCommentMarker() { return this.commentMarker; } @Override public String toString() { return this.displayName; } } public Scripter(Frame owner, boolean modal) { super(owner, modal); try { if (owner != null && owner instanceof WhiteboxPluginHost) { host = (WhiteboxPluginHost) owner; bundle = host.getGuiLabelsBundle(); } this.pathSep = File.separator; findGraphicsDirectory(new File(host.getResourcesDirectory())); findScriptDirectory(new File(host.getResourcesDirectory())); // String applicationDirectory = java.net.URLDecoder.decode(getClass().getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF-8"); // if (applicationDirectory.endsWith(".exe") || applicationDirectory.endsWith(".jar")) { // applicationDirectory = new File(applicationDirectory).getParent(); // } else { // // Add the path to the class files // applicationDirectory += getClass().getName().replace('.', File.separatorChar); // // // Step one level up as we are only interested in the // // directory containing the class files // applicationDirectory = new File(applicationDirectory).getParent(); // } // applicationDirectory = new File(applicationDirectory).getParent(); // findGraphicsDirectory(new File(applicationDirectory)); // findScriptDirectory(new File(applicationDirectory)); initUI(); } catch (Exception e) { host.logException("Error in Scripter.", e); } } public Scripter(Frame owner, boolean modal, String fileName) { super(owner, modal); try { this.pathSep = File.separator; // String applicationDirectory = java.net.URLDecoder.decode(getClass().getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF-8"); // if (applicationDirectory.endsWith(".exe") || applicationDirectory.endsWith(".jar")) { // applicationDirectory = new File(applicationDirectory).getParent(); // } else { // // Add the path to the class files // applicationDirectory += getClass().getName().replace('.', File.separatorChar); // // // Step one level up as we are only interested in the // // directory containing the class files // applicationDirectory = new File(applicationDirectory).getParent(); // } // applicationDirectory = new File(applicationDirectory).getParent(); // findGraphicsDirectory(new File(applicationDirectory)); // findScriptDirectory(new File(applicationDirectory)); if (owner != null && owner instanceof WhiteboxPluginHost) { host = (WhiteboxPluginHost) owner; bundle = host.getGuiLabelsBundle(); } findGraphicsDirectory(new File(host.getResourcesDirectory())); findScriptDirectory(new File(host.getResourcesDirectory())); initUI(); openFile(fileName); } catch (Exception e) { host.logException("Error in Scripter.", e); } } private void findScriptDirectory(File dir) { File[] files = dir.listFiles(); for (int x = 0; x < files.length; x++) { if (files[x].isDirectory()) { if (files[x].toString().endsWith(pathSep + "Scripts")) { scriptsDirectory = files[x].toString() + pathSep; break; } else { findScriptDirectory(files[x]); } } } } private void findGraphicsDirectory(File dir) { File[] files = dir.listFiles(); for (int x = 0; x < files.length; x++) { if (files[x].isDirectory()) { if (files[x].toString().endsWith(pathSep + "Images")) { graphicsDirectory = files[x].toString() + pathSep; break; } else { findGraphicsDirectory(files[x]); } } } } private void initUI() { try { if (System.getProperty("os.name").contains("Mac")) { this.getRootPane().putClientProperty("apple.awt.brushMetalLook", Boolean.TRUE); System.setProperty("apple.laf.useScreenMenuBar", "true"); //System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Whitebox GAT"); System.setProperty("com.apple.mrj.application.growbox.intrudes", "true"); //System.setProperty("Xdock:name", "Whitebox"); System.setProperty("apple.awt.fileDialogForDirectories", "true"); System.setProperty("apple.awt.textantialiasing", "true"); System.setProperty("apple.awt.graphics.EnableQ2DX", "true"); } if (System.getProperty("mrj.version") != null) { System.setProperty("com.apple.macos.useScreenMenuBar", "true"); System.setProperty("apple.laf.useScreenMenuBar", "true"); } errOut = new PrintWriter(new Scripter.TextAreaWriter(textArea)); initScriptEngine(); this.setTitle("Whitebox Scripter"); this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); this.setPreferredSize(new Dimension(550, 650)); Container c = this.getContentPane(); createMenu(); JToolBar toolbar = createToolbar(); //c.add(toolbar, BorderLayout.PAGE_START); findAndReplaceToolbar = createFindToolbar(); findAndReplaceToolbar.setVisible(false); JPanel toolbarPanel = new JPanel(); toolbarPanel.setLayout(new BoxLayout(toolbarPanel, BoxLayout.Y_AXIS)); toolbarPanel.add(toolbar); toolbarPanel.add(findAndReplaceToolbar); c.add(toolbarPanel, BorderLayout.PAGE_START); editor = new RSyntaxTextArea(20, 60); editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_PYTHON); editor.setCodeFoldingEnabled(true); editor.setAntiAliasingEnabled(true); editor.setCloseCurlyBraces(true); editor.addKeyListener(this); editor.setTabSize(4); editor.setBracketMatchingEnabled(true); editor.setAutoIndentEnabled(true); editor.setCloseCurlyBraces(true); editor.setMarkOccurrences(true); resetAutocompletion(); // setupAutocomplete(); scroll = new RTextScrollPane(editor); scroll.setFoldIndicatorEnabled(true); Box outputBox = Box.createHorizontalBox(); Box outputToolbarBox = Box.createVerticalBox(); JToolBar outputToolbar = createOutputToolbar(); outputToolbar.setOrientation(SwingConstants.VERTICAL); outputToolbar.setFloatable(false); outputToolbarBox.add(outputToolbar); outputToolbarBox.add(Box.createVerticalGlue()); JScrollPane scroll2 = new JScrollPane(textArea); outputBox.add(outputToolbarBox); outputBox.add(scroll2); // text popup menu JPopupMenu textPopup = new JPopupMenu(); JMenuItem mi; mi = new JMenuItem(bundle.getString("Clear")); mi.addActionListener(this); mi.setActionCommand("clearText"); textPopup.add(mi); mi = new JMenuItem(bundle.getString("Cut")); mi.addActionListener(this); mi.setActionCommand("cutText"); textPopup.add(mi); mi = new JMenuItem(bundle.getString("Copy")); mi.addActionListener(this); mi.setActionCommand("copyText"); textPopup.add(mi); mi = new JMenuItem(bundle.getString("Paste")); mi.addActionListener(this); mi.setActionCommand("pasteText"); textPopup.add(mi); mi = new JMenuItem(bundle.getString("SelectAll")); mi.addActionListener(this); mi.setActionCommand("selectAllText"); textPopup.add(mi); textPopup.setOpaque(true); textPopup.setLightWeightPopupEnabled(true); textArea.setComponentPopupMenu(textPopup); splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scroll, outputBox); splitPane.setDividerLocation(400); c.add(splitPane); status = new JPanel(); status.setLayout(new BoxLayout(status, BoxLayout.LINE_AXIS)); status.setPreferredSize(new Dimension(10, 24)); status.add(Box.createHorizontalStrut(5)); status.add(statusLabel); status.add(Box.createHorizontalGlue()); c.add(status, BorderLayout.PAGE_END); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { checkIfEditorIsDirty(); } }); this.pack(); } catch (Exception e) { host.logException("Error in Scripter.", e); } } private JToolBar createToolbar() { JToolBar toolbar = new JToolBar(); JButton openBtn = makeToolBarButton("open.png", "open", bundle.getString("OpenFile"), "Open"); toolbar.add(openBtn); JButton closeBtn = makeToolBarButton("close.png", "close", bundle.getString("CloseFile"), "Close"); toolbar.add(closeBtn); JButton saveBtn = makeToolBarButton("SaveMap.png", "save", bundle.getString("SaveFile"), "Save"); toolbar.add(saveBtn); JButton printBtn = makeToolBarButton("print.png", "print", bundle.getString("Print"), "Print"); toolbar.add(printBtn); toolbar.addSeparator(); JButton toggleComment = makeToolBarButton("Comment.png", "Comment", bundle.getString("ToggleComments"), "Comment"); toolbar.add(toggleComment); JButton indent = makeToolBarButton("Indent.png", "Indent", "Indent", "Indent"); toolbar.add(indent); JButton outdent = makeToolBarButton("Outdent.png", "Outdent", "Outdent", "Outdent"); toolbar.add(outdent); toolbar.addSeparator(); JButton executeBtn = makeToolBarButton("Execute.png", "execute", bundle.getString("ExecuteCode"), "Execute"); toolbar.add(executeBtn); // generateDataButton = makeToolBarButton("GenerateData.png", "generateData", // bundle.getString("GenerateColumnData"), "Generate Data"); // toolbar.add(generateDataButton); // // showGenerateDataButton(false); toolbar.add(Box.createHorizontalGlue()); return toolbar; } private JToolBar createFindToolbar() { // Create a toolbar with searching options. JToolBar toolbar = new JToolBar(); toolbar.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); findLabel = new JLabel("Find:"); //c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 0.15; c.gridx = 0; c.gridy = 0; toolbar.add(findLabel, c); searchField = new JTextField(7); searchField.setMinimumSize(searchField.getPreferredSize()); c.weightx = 0.25; c.gridx = 1; c.gridy = 0; toolbar.add(searchField, c); JPanel findButtonBox = new JPanel(); //Box.createHorizontalBox(); findButtonBox.setLayout(new BoxLayout(findButtonBox, BoxLayout.X_AXIS)); prevButton = new JButton("\u25C0"); //"\u2190"); // previous prevButton.setActionCommand("FindPrev"); prevButton.addActionListener(this); findButtonBox.add(prevButton); nextButton = new JButton("\u25B6"); //"\u2192"); // next nextButton.setActionCommand("FindNext"); nextButton.addActionListener(this); findButtonBox.add(nextButton); findButtonBox.add(Box.createHorizontalGlue()); searchField.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { nextButton.doClick(0); } }); matchCaseCB = new JCheckBox("Match Case"); findButtonBox.add(matchCaseCB); wholeWordCB = new JCheckBox("Whole Words"); findButtonBox.add(wholeWordCB); regexCB = new JCheckBox("Regex"); findButtonBox.add(regexCB); findButtonBox.add(Box.createHorizontalGlue()); JButton closeBtn = new JButton("x"); closeBtn.setBorderPainted(false); closeBtn.setFocusPainted(false); closeBtn.setContentAreaFilled(false); closeBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { findAndReplaceToolbar.setVisible(false); } }); //toolBar.add(closeBtn); findButtonBox.add(closeBtn); c.weightx = 1.0; c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 2; c.gridy = 0; toolbar.add(findButtonBox, c); replaceLabel = new JLabel("Replace:"); c.weightx = 0.15; c.gridx = 0; c.gridy = 1; toolbar.add(replaceLabel, c); replaceField = new JTextField(7); replaceField.setMinimumSize(replaceField.getPreferredSize()); replaceField.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { SearchContext context = new SearchContext(); String text = searchField.getText(); if (text.length() == 0) { return; } context.setSearchFor(text); context.setReplaceWith(replaceField.getText()); context.setMatchCase(matchCaseCB.isSelected()); context.setRegularExpression(regexCB.isSelected()); context.setWholeWord(wholeWordCB.isSelected()); SearchEngine.replaceAll(editor, context); } }); c.weightx = 0.25; c.gridx = 1; c.gridy = 1; toolbar.add(replaceField, c); replaceButton = new JButton("replace"); replaceButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { SearchContext context = new SearchContext(); String text = searchField.getText(); if (text.length() == 0) { return; } context.setSearchFor(text); context.setReplaceWith(replaceField.getText()); context.setMatchCase(matchCaseCB.isSelected()); context.setRegularExpression(regexCB.isSelected()); context.setWholeWord(wholeWordCB.isSelected()); SearchEngine.replaceAll(editor, context); } }); JPanel replaceButtonPanel = new JPanel(); replaceButtonPanel.setLayout(new BoxLayout(replaceButtonPanel, BoxLayout.X_AXIS)); replaceButtonPanel.add(replaceButton); replaceButtonPanel.add(Box.createHorizontalGlue()); c.weightx = 1.0; c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 2; c.gridy = 1; toolbar.add(replaceButtonPanel, c); // Box textFields = Box.createVerticalBox(); // // Box findBox = Box.createHorizontalBox(); // findLabel = new JLabel("Find:"); // findBox.add(findLabel); // searchField = new JTextField(10); // //toolBar.add(searchField); // findBox.add(searchField); // textFields.add(findBox); // // Box replaceBox = Box.createHorizontalBox(); // replaceLabel = new JLabel("Replace:"); // replaceBox.add(replaceLabel); // replaceField = new JTextField(10); // replaceField.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // SearchContext context = new SearchContext(); // String text = searchField.getText(); // if (text.length() == 0) { // return; // } // context.setSearchFor(text); // context.setReplaceWith(replaceField.getText()); // context.setMatchCase(matchCaseCB.isSelected()); // context.setRegularExpression(regexCB.isSelected()); //// context.setWholeWord(false); // // SearchEngine.replaceAll(editor, context); // } // }); // // replaceBox.add(replaceField); // textFields.add(replaceBox); // // toolbar.add(textFields); // // Box findButtonBox = Box.createHorizontalBox(); // nextButton = new JButton("Next"); // nextButton.setActionCommand("FindNext"); // nextButton.addActionListener(this); // findButtonBox.add(nextButton); // //toolBar.add(nextButton); // // searchField.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // nextButton.doClick(0); // } // }); // // // prevButton = new JButton("Previous"); // prevButton.setActionCommand("FindPrev"); // prevButton.addActionListener(this); // //toolBar.add(prevButton); // findButtonBox.add(prevButton); // // regexCB = new JCheckBox("Regex"); // //toolBar.add(regexCB); // findButtonBox.add(regexCB); // matchCaseCB = new JCheckBox("Match Case"); // //toolBar.add(matchCaseCB); // findButtonBox.add(matchCaseCB); // // findButtonBox.add(Box.createHorizontalGlue()); // //toolBar.add(Box.createHorizontalGlue()); // // JButton closeBtn = new JButton("x"); // closeBtn.setBorderPainted(false); // closeBtn.setFocusPainted(false); // closeBtn.setContentAreaFilled(false); // closeBtn.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // findAndReplaceToolbar.setVisible(false); // } // }); // //toolBar.add(closeBtn); // findButtonBox.add(closeBtn); // // Box box2 = Box.createVerticalBox(); // // box2.add(findButtonBox); // box2.add(Box.createVerticalGlue()); // // toolbar.add(box2); return toolbar; } private JToolBar createOutputToolbar() { JToolBar toolbar = new JToolBar(); JButton clearConsole = makeToolBarButton("ClearConsole.png", "clearConsole", bundle.getString("ClearConsole"), "CLR"); //bundle.getString("ClearConsole")); toolbar.add(clearConsole); return toolbar; } private void createMenu() { try { JMenuBar menubar = new JMenuBar(); JMenu fileMenu = new JMenu(bundle.getString("File")); JMenuItem open = new JMenuItem(bundle.getString("OpenFile")); open.setActionCommand("open"); open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); open.addActionListener(this); fileMenu.add(open); JMenuItem save = new JMenuItem(bundle.getString("Save")); save.setActionCommand("save"); save.addActionListener(this); save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); fileMenu.add(save); JMenuItem saveAs = new JMenuItem(bundle.getString("SaveAs") + "..."); saveAs.setActionCommand("saveAs"); saveAs.addActionListener(this); fileMenu.add(saveAs); JMenuItem print = new JMenuItem(bundle.getString("Print")); print.setActionCommand("print"); print.addActionListener(this); print.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); fileMenu.add(print); JMenuItem close = new JMenuItem(bundle.getString("CloseFile")); close.setActionCommand("close"); //close.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); close.addActionListener(this); fileMenu.add(close); fileMenu.addSeparator(); JMenuItem exit = new JMenuItem(bundle.getString("Exit")); exit.setActionCommand("exit"); exit.addActionListener(this); exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); fileMenu.add(exit); menubar.add(fileMenu); JMenu editMenu = new JMenu(bundle.getString("Edit")); JMenuItem undo = new JMenuItem(bundle.getString("Undo")); undo.setActionCommand("undo"); undo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); undo.addActionListener(this); editMenu.add(undo); JMenuItem redo = new JMenuItem(bundle.getString("Redo")); redo.setActionCommand("redo"); redo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); redo.addActionListener(this); editMenu.add(redo); JMenuItem cut = new JMenuItem(bundle.getString("Cut")); cut.setActionCommand("cut"); cut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); cut.addActionListener(this); editMenu.add(cut); JMenuItem copy = new JMenuItem(bundle.getString("Copy")); copy.setActionCommand("copy"); copy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); copy.addActionListener(this); editMenu.add(copy); JMenuItem paste = new JMenuItem(bundle.getString("Paste")); paste.setActionCommand("paste"); paste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); paste.addActionListener(this); editMenu.add(paste); JMenuItem selectAll = new JMenuItem("Select All"); selectAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); selectAll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { editor.selectAll(); } }); editMenu.add(selectAll); editMenu.addSeparator(); JMenuItem find = new JMenuItem("Find"); find.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); find.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { findAndReplaceToolbar.setVisible(true); searchField.requestFocus(); replaceField.setVisible(false); replaceLabel.setVisible(false); replaceButton.setVisible(false); // searchField.setVisible(true); // findLabel.setVisible(true); prevButton.setVisible(true); nextButton.setVisible(true); } }); editMenu.add(find); JMenuItem replace = new JMenuItem("Replace"); replace.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); replace.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { findAndReplaceToolbar.setVisible(true); searchField.requestFocus(); replaceField.setVisible(true); replaceLabel.setVisible(true); replaceButton.setVisible(true); // searchField.setVisible(false); // findLabel.setVisible(false); prevButton.setVisible(false); nextButton.setVisible(false); } }); editMenu.add(replace); menubar.add(editMenu); // JMenu viewMenu = new JMenu("View"); // // JMenuItem groovyConsole = new JMenuItem("View Groovy Console"); // groovyConsole.setActionCommand("viewGroovyConsole"); // groovyConsole.addActionListener(this); // viewMenu.add(groovyConsole); // // menubar.add(viewMenu); JMenu languageMenu = new JMenu(bundle.getString("Language")); python.setActionCommand("python"); python.addActionListener(this); python.setState(true); languageMenu.add(python); groovy.setActionCommand("groovy"); groovy.addActionListener(this); groovy.setState(false); languageMenu.add(groovy); javascript.setActionCommand("javascript"); javascript.addActionListener(this); javascript.setState(false); languageMenu.add(javascript); menubar.add(languageMenu); JMenu sourceMenu = new JMenu(bundle.getString("Source")); JMenuItem execute = new JMenuItem(bundle.getString("ExecuteCode")); execute.setActionCommand("execute"); execute.addActionListener(this); execute.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); sourceMenu.add(execute); JCheckBoxMenuItem saveOnExecute = new JCheckBoxMenuItem("Automatically Save On Execute", saveOnExecution); saveOnExecute.setActionCommand("saveOnExecute"); saveOnExecute.addActionListener(this); sourceMenu.add(saveOnExecute); sourceMenu.addSeparator(); JMenuItem toggleComments = new JMenuItem(bundle.getString("ToggleComments")); toggleComments.setActionCommand("Comment"); toggleComments.addActionListener(this); toggleComments.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); sourceMenu.add(toggleComments); JMenuItem indent = new JMenuItem("Indent"); // indent.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); indent.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { indentSelection(); } }); sourceMenu.add(indent); JMenuItem outdent = new JMenuItem("Outdent"); // outdent.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); outdent.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { outdentSelection(); } }); sourceMenu.add(outdent); menubar.add(sourceMenu); this.setJMenuBar(menubar); } catch (Exception e) { host.logException("Error in Scripter.", e); } } private JButton makeToolBarButton(String imageName, String actionCommand, String toolTipText, String altText) { //Look for the image. String imgLocation = graphicsDirectory + imageName; ImageIcon image = new ImageIcon(imgLocation, ""); //Create and initialize the button. JButton button = new JButton(); button.setActionCommand(actionCommand); button.setToolTipText(toolTipText); button.addActionListener(this); if (!(new File(imgLocation).exists())) { button.setText(altText); return button; } button.setOpaque(false); button.setBorderPainted(false); try { button.setIcon(image); } catch (Exception e) { button.setText(altText); host.logException("Error in Scripter.", e); } return button; } @Override public void keyTyped(KeyEvent e) { //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override public void keyReleased(KeyEvent e) { try { if (e.getKeyCode() != KeyEvent.VK_UP && e.getKeyCode() != KeyEvent.VK_DOWN && e.getKeyCode() != KeyEvent.VK_LEFT && e.getKeyCode() != KeyEvent.VK_RIGHT) { editorDirty = true; } if (e.getKeyCode() == KeyEvent.VK_ENTER) { if (editor.getLineCount() != numLinesInDoc) { scanDoc(); numLinesInDoc = editor.getLineCount(); } } else if (e.getKeyCode() == KeyEvent.VK_DELETE || e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { if (editor.getLineCount() != numLinesInDoc) { resetAutocompletion(); scanDoc(); numLinesInDoc = editor.getLineCount(); } } else if (e.getKeyCode() == KeyEvent.VK_PERIOD) { // pressed dot int start = editor.getLineStartOffsetOfCurrentLine(); int end = editor.getLineEndOffsetOfCurrentLine(); String line = editor.getText(start, end - start + 1); line = line.split("\n")[0]; if (line.startsWith("import") || line.startsWith("from")) { String pck = line.replace("import", "").replace("from", "").trim(); if (pck.endsWith(".")) { pck = pck.substring(0, pck.length() - 1); } importPackage(pck); } } } catch (Exception ex) { System.out.println(ex.toString()); } } private void checkIfEditorIsDirty() { if (editorDirty) { Object[] options = {"Yes", "No"}; int n = JOptionPane.showOptionDialog(this, "The source code has changed. Would you like to save it?", "Whitebox GAT Message", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, //do not use a custom Icon options, //the titles of buttons options[0]); //default button title if (n == JOptionPane.YES_OPTION) { save(); } } } @Override public void keyPressed(KeyEvent e) { } private ScripterCompletionProvider provider; private AutoCompletion ac; private void setupAutocomplete() { provider = new ScripterCompletionProvider(); provider.setAutoActivationRules(false, "."); addLanguageKeywords(); importVariableAs("pluginHost", WhiteboxPluginHost.class.getCanonicalName()); // An AutoCompletion acts as a "middle-man" between a text component // and a CompletionProvider. It manages any options associated with // the auto-completion (the popup trigger key, whether to display a // documentation window along with completion choices, etc.). Unlike // CompletionProviders, instances of AutoCompletion cannot be shared // among multiple text components. ac = new AutoCompletion(provider); ac.setAutoCompleteEnabled(true); ac.setAutoActivationEnabled(true); ac.setShowDescWindow(true); ac.setParameterAssistanceEnabled(true); ac.install(editor); } private void resetAutocompletion() { listOfImportedClasses.clear(); listOfImportedItems.clear(); listOfImportedVariables.clear(); listOfImportedMethods.clear(); listOfMethodReturns.clear(); variableClassMap.clear(); setupAutocomplete(); // ArrayList<String> jars = FileUtilities.findAllFilesWithExtension(new File(host.getApplicationDirectory()), ".jar", true); // for (String str : jars) { // System.out.println(str); // } // if (language == PYTHON) { // importClass("org.python.core.__builtin__"); // } // if (language == GROOVY) { // importPackage("java.lang"); // importPackage("java.io"); // importPackage("java.net"); // importPackage("java.util"); // importPackage("groovy.lang"); // importPackage("groovy.util"); // // importClass("java.lang.*"); // importClass("java.io.*"); // importClass("java.math.BigDecimal"); // importClass("java.math.BigInteger"); // importClass("java.net.*"); // importClass("java.util.*"); // importClass("groovy.lang.*"); // importClass("groovy.util.*"); // } } Map<String, String> variableClassMap = new HashMap<>(); private boolean scanDoc() { try { // read each line in the doc String[] lines = editor.getText().split("\r\n"); //System.lineSeparator()); if (lines.length <= 1) { lines = editor.getText().split("\n"); } for (String line : lines) { line = line.replace("\t", ""); if (!line.isEmpty() && !line.startsWith(language.getCommentMarker())) { if (line.startsWith("import")) { // import a class String className = line.replace("import", "").trim(); if (!listOfImportedClasses.contains(className)) { importClass(className); } } else if (line.contains("import") && line.contains("from")) { // python class import String className = line.replace("import", ".").replace("from", "").trim().replace(" ", ""); if (!listOfImportedClasses.contains(className)) { importClass(className); } } else if (line.contains("=") && !line.contains("==") && !line.contains("!=")) { // variable definition // first find the name of the variable String[] s1 = line.split("="); if (s1.length == 2) { String[] s2 = s1[0].split(" "); String variableName = s2[s2.length - 1].trim(); if (!listOfImportedVariables.contains(variableName)) { // now figure out the class String className = null; String variableType = ""; if (language == GROOVY) { variableType = s1[1].replace(";", "").trim(); if ((variableType.startsWith("\"") && variableType.endsWith("\"")) || (variableType.startsWith("\'") && variableType.endsWith("\'"))) { // it is a string className = "groovy.lang.GString"; } else if (whitebox.utilities.StringUtilities.isInteger(variableType)) { className = "java.lang.Integer"; } else if (whitebox.utilities.StringUtilities.isNumeric(variableType)) { className = "java.lang.Double"; } else if (whitebox.utilities.StringUtilities.isBoolean(variableType)) { className = "java.lang.Boolean"; } else if (variableType.startsWith("[") && variableType.endsWith("]") && !variableType.contains(":")) { className = "java.util.List"; } else if (variableType.startsWith("[") && variableType.endsWith("]") && !variableType.contains(":")) { className = "java.util.MapWithDefault"; } else if (listOfImportedVariables.contains(variableType)) { // it is being assigned another variable. Use the other variable's class className = variableClassMap.get(variableType); } else if (variableType.contains("(")) { variableType = s1[1].substring(0, s1[1].indexOf("(")).replace(" new ", "").trim(); // is the type known?String className = null; for (String str : listOfImportedClasses) { if (str.endsWith("." + variableType)) { className = str; break; } } } else if (className == null) { className = "java.lang.Object"; } } else if (language == PYTHON) { variableType = s1[1].trim(); if ((variableType.startsWith("\"") && variableType.endsWith("\"")) || (variableType.startsWith("\'") && variableType.endsWith("\'"))) { // it is a string className = "org.python.core.PyString"; } else if (variableType.startsWith("float(") && variableType.endsWith(")")) { className = "org.python.core.PyFloat"; } else if (variableType.startsWith("int(") && variableType.endsWith(")")) { className = "org.python.core.PyInteger"; } else if (variableType.startsWith("long(") && variableType.endsWith(")")) { className = "org.python.core.PyLong"; } else if (variableType.startsWith("complex(") && variableType.endsWith(")")) { className = "org.python.core.PyComplex"; } else if (whitebox.utilities.StringUtilities.isInteger(variableType)) { className = "org.python.core.PyLong"; } else if (whitebox.utilities.StringUtilities.isNumeric(variableType)) { className = "org.python.core.PyFloat"; } else if (whitebox.utilities.StringUtilities.isBoolean(variableType)) { className = "org.python.core.PyBoolean"; } else if (variableType.startsWith("[") && variableType.endsWith("]")) { className = "org.python.core.PyList"; } else if (variableType.startsWith("(") && variableType.endsWith(")")) { className = "org.python.core.PyTuple"; } else if (variableType.contains("(")) { variableType = s1[1].substring(0, s1[1].indexOf("(")).replace(" new ", "").trim(); // is the type known?String className = null; for (String str : listOfImportedClasses) { if (str.endsWith("." + variableType)) { className = str; break; } } } else if (listOfImportedVariables.contains(variableType)) { // it is being assigned another variable. Use the other variable's class className = variableClassMap.get(variableType); } else if (className == null) { className = "org.python.core.PyObject"; } } else if (language == JAVASCRIPT) { variableType = s1[1].replace(";", "").trim(); } importVariableAs(variableName, className); variableClassMap.put(variableName, className); } } } else if (line.contains("class")) { String[] s1 = line.split(" "); // the class name is the one after the class keyword String className = ""; for (int i = 0; i < s1.length; i++) { if (s1[i].trim().toLowerCase().equals("class")) { String[] s2 = s1[i + 1].split("\\("); className = s2[0]; break; } } if (!className.isEmpty()) { if (!listOfImportedClasses.contains(className)) { listOfImportedClasses.add(className); provider.addCompletion(new BasicCompletion(provider, className)); } } } } } return true; } catch (Exception e) { return false; } } ArrayList<String> listOfImportedItems = new ArrayList<>(); ArrayList<String> listOfImportedClasses = new ArrayList<>(); ArrayList<String> listOfImportedVariables = new ArrayList<>(); ArrayList<String> listOfImportedMethods = new ArrayList<>(); HashMap<String, String> listOfMethodReturns = new HashMap<>(); private void importPackage(String pck) { ArrayList<String> myClasses = ClassEnumerator.getClassNamesForPackage(pck); if (myClasses == null) { return; } Collections.sort(myClasses); for (String str : myClasses) { if (!listOfImportedItems.contains(str)) { provider.addCompletion(new BasicCompletion(provider, str)); listOfImportedItems.add(str); } } } private void importPackage(Package pck) { ArrayList<String> myClasses = ClassEnumerator.getClassNamesForPackage(pck); if (myClasses == null) { return; } Collections.sort(myClasses); for (String str : myClasses) { if (!listOfImportedItems.contains(str)) { provider.addCompletion(new BasicCompletion(provider, str)); listOfImportedItems.add(str); } } } private void importVariableAs(String variableName, String className) { if (!listOfImportedVariables.contains(variableName)) { try { if (className != null) { Class c = Class.forName(className); if (addVariableToProvider(variableName, c)) { listOfImportedVariables.add(variableName); } } else { if (addVariableToProvider(variableName, null)) { listOfImportedVariables.add(variableName); } } } catch (ClassNotFoundException | SecurityException e) { // class not found. } } } private void importClass(String className) { if (!listOfImportedClasses.contains(className)) { try { if (!className.endsWith("*")) { if (addClassToProvider(className)) { listOfImportedClasses.add(className); } } else { // import all of the classes in this package String packageName = className.replace("*", ""); for (String str : listOfImportedItems) { if (str.startsWith(packageName) && !listOfImportedClasses.contains(str)) { if (addClassToProvider(str)) { listOfImportedClasses.add(str); } } } } } catch (Exception e) { // class not found. } } } private void addLanguageKeywords() { provider.setParameterizedCompletionParams("(".charAt(0), ", ", ")".charAt(0)); //LanguageAwareCompletionProvider lacProvider = new LanguageAwareCompletionProvider(provider); switch (language) { case PYTHON: provider.addCompletion(new BasicCompletion(provider, "and")); provider.addCompletion(new BasicCompletion(provider, "as")); provider.addCompletion(new BasicCompletion(provider, "assert")); provider.addCompletion(new BasicCompletion(provider, "break")); provider.addCompletion(new BasicCompletion(provider, "class")); provider.addCompletion(new BasicCompletion(provider, "continue")); provider.addCompletion(new BasicCompletion(provider, "def")); provider.addCompletion(new BasicCompletion(provider, "del")); provider.addCompletion(new BasicCompletion(provider, "elif")); provider.addCompletion(new BasicCompletion(provider, "else")); provider.addCompletion(new BasicCompletion(provider, "except")); provider.addCompletion(new BasicCompletion(provider, "exec")); provider.addCompletion(new BasicCompletion(provider, "finally")); provider.addCompletion(new BasicCompletion(provider, "for")); provider.addCompletion(new BasicCompletion(provider, "from")); provider.addCompletion(new BasicCompletion(provider, "global")); provider.addCompletion(new BasicCompletion(provider, "if")); provider.addCompletion(new BasicCompletion(provider, "import")); provider.addCompletion(new BasicCompletion(provider, "in")); provider.addCompletion(new BasicCompletion(provider, "is")); provider.addCompletion(new BasicCompletion(provider, "lambda")); provider.addCompletion(new BasicCompletion(provider, "not")); provider.addCompletion(new BasicCompletion(provider, "or")); provider.addCompletion(new BasicCompletion(provider, "pass")); provider.addCompletion(new BasicCompletion(provider, "print")); provider.addCompletion(new BasicCompletion(provider, "raise")); provider.addCompletion(new BasicCompletion(provider, "return")); provider.addCompletion(new BasicCompletion(provider, "try")); provider.addCompletion(new BasicCompletion(provider, "while")); provider.addCompletion(new BasicCompletion(provider, "with")); provider.addCompletion(new BasicCompletion(provider, "yield")); break; case GROOVY: // Add completions for all groovy keywords. A BasicCompletion is just // a straightforward word completion. provider.addCompletion(new BasicCompletion(provider, "abstract")); provider.addCompletion(new BasicCompletion(provider, "as")); provider.addCompletion(new BasicCompletion(provider, "assert")); provider.addCompletion(new BasicCompletion(provider, "break")); provider.addCompletion(new BasicCompletion(provider, "case")); provider.addCompletion(new BasicCompletion(provider, "catch")); provider.addCompletion(new BasicCompletion(provider, "class")); provider.addCompletion(new BasicCompletion(provider, "const")); provider.addCompletion(new BasicCompletion(provider, "continue")); provider.addCompletion(new BasicCompletion(provider, "def")); provider.addCompletion(new BasicCompletion(provider, "default")); provider.addCompletion(new BasicCompletion(provider, "do")); provider.addCompletion(new BasicCompletion(provider, "else")); provider.addCompletion(new BasicCompletion(provider, "enum")); provider.addCompletion(new BasicCompletion(provider, "extends")); provider.addCompletion(new BasicCompletion(provider, "final")); provider.addCompletion(new BasicCompletion(provider, "finally")); provider.addCompletion(new BasicCompletion(provider, "for")); provider.addCompletion(new BasicCompletion(provider, "goto")); provider.addCompletion(new BasicCompletion(provider, "if")); provider.addCompletion(new BasicCompletion(provider, "implements")); provider.addCompletion(new BasicCompletion(provider, "import")); provider.addCompletion(new BasicCompletion(provider, "in")); provider.addCompletion(new BasicCompletion(provider, "instanceof")); provider.addCompletion(new BasicCompletion(provider, "interface")); provider.addCompletion(new BasicCompletion(provider, "native")); provider.addCompletion(new BasicCompletion(provider, "new")); provider.addCompletion(new BasicCompletion(provider, "package")); provider.addCompletion(new BasicCompletion(provider, "private")); provider.addCompletion(new BasicCompletion(provider, "property")); provider.addCompletion(new BasicCompletion(provider, "protected")); provider.addCompletion(new BasicCompletion(provider, "public")); provider.addCompletion(new BasicCompletion(provider, "return")); provider.addCompletion(new BasicCompletion(provider, "static")); provider.addCompletion(new BasicCompletion(provider, "strictfp")); provider.addCompletion(new BasicCompletion(provider, "super")); provider.addCompletion(new BasicCompletion(provider, "switch")); provider.addCompletion(new BasicCompletion(provider, "synchronized")); provider.addCompletion(new BasicCompletion(provider, "this")); provider.addCompletion(new BasicCompletion(provider, "throw")); provider.addCompletion(new BasicCompletion(provider, "throws")); provider.addCompletion(new BasicCompletion(provider, "transient")); provider.addCompletion(new BasicCompletion(provider, "try")); provider.addCompletion(new BasicCompletion(provider, "void")); provider.addCompletion(new BasicCompletion(provider, "volatile")); provider.addCompletion(new BasicCompletion(provider, "while")); break; case JAVASCRIPT: provider.addCompletion(new BasicCompletion(provider, "break")); provider.addCompletion(new BasicCompletion(provider, "case")); provider.addCompletion(new BasicCompletion(provider, "catch")); provider.addCompletion(new BasicCompletion(provider, "continue")); provider.addCompletion(new BasicCompletion(provider, "debugger")); provider.addCompletion(new BasicCompletion(provider, "default")); provider.addCompletion(new BasicCompletion(provider, "delete")); provider.addCompletion(new BasicCompletion(provider, "do")); provider.addCompletion(new BasicCompletion(provider, "else")); provider.addCompletion(new BasicCompletion(provider, "finally")); provider.addCompletion(new BasicCompletion(provider, "for")); provider.addCompletion(new BasicCompletion(provider, "function")); provider.addCompletion(new BasicCompletion(provider, "if")); provider.addCompletion(new BasicCompletion(provider, "in")); provider.addCompletion(new BasicCompletion(provider, "instanceof")); provider.addCompletion(new BasicCompletion(provider, "new")); provider.addCompletion(new BasicCompletion(provider, "return")); provider.addCompletion(new BasicCompletion(provider, "switch")); provider.addCompletion(new BasicCompletion(provider, "this")); provider.addCompletion(new BasicCompletion(provider, "throw")); provider.addCompletion(new BasicCompletion(provider, "try")); provider.addCompletion(new BasicCompletion(provider, "typeof")); provider.addCompletion(new BasicCompletion(provider, "var")); provider.addCompletion(new BasicCompletion(provider, "void")); provider.addCompletion(new BasicCompletion(provider, "while")); provider.addCompletion(new BasicCompletion(provider, "with")); break; } } private boolean addClassToProvider(String className) { try { Class c = Class.forName(className); Constructor[] con = c.getConstructors(); for (int i = 0; i < con.length; i++) { FunctionCompletion fc = new FunctionCompletion(provider, c.getSimpleName(), "none"); Class<?>[] p = con[i].getParameterTypes(); List<ParameterizedCompletion.Parameter> params = new ArrayList<>(); ParameterizedCompletion.Parameter param; for (int j = 0; j < p.length; j++) { param = new ParameterizedCompletion.Parameter(p[j].getSimpleName(), "arg" + (j + 1)); //param.setDescription("This is the string to print."); params.add(param); } fc.setParams(params); fc.setShortDescription("Constructor"); fc.setDefinedIn(con[i].getDeclaringClass().getName()); provider.addCompletion(fc); } //Class c = Class.forName("whitebox"); Method m[] = c.getMethods(); for (int i = 0; i < m.length; i++) { FunctionCompletion fc = new FunctionCompletion(provider, c.getSimpleName() + "." + m[i].getName(), m[i].getReturnType().getSimpleName()); Class<?>[] p = m[i].getParameterTypes(); List<ParameterizedCompletion.Parameter> params = new ArrayList<>(); ParameterizedCompletion.Parameter param; for (int j = 0; j < p.length; j++) { param = new ParameterizedCompletion.Parameter(p[j].getSimpleName(), "arg" + (j + 1)); params.add(param); } fc.setParams(params); fc.setDefinedIn(m[i].getDeclaringClass().getName()); provider.addCompletion(fc); listOfImportedMethods.add(c.getSimpleName() + "." + m[i].getName()); listOfMethodReturns.put(c.getSimpleName() + "." + m[i].getName(), m[i].getReturnType().getCanonicalName()); } Field f[] = c.getFields(); for (int i = 0; i < f.length; i++) { VariableCompletion vc = new VariableCompletion(provider, c.getSimpleName() + "." + f[i].getName(), f[i].getType().toString()); vc.setDefinedIn(f[i].getDeclaringClass().getName()); provider.addCompletion(vc); } return true; } catch (ClassNotFoundException | SecurityException e) { return false; } } private boolean addVariableToProvider(String variableName, Class c) { try { if (c != null) { String className = c.getCanonicalName(); if (!listOfImportedClasses.contains(className)) { if (addClassToProvider(className)) { listOfImportedClasses.add(className); // Package p = c.getPackage(); // importPackage(p); } } VariableCompletion vc = new VariableCompletion(provider, variableName, c.getCanonicalName()); provider.addCompletion(vc); //provider.addCompletion(new BasicCompletion(provider, variableName)); Method m[] = c.getMethods(); for (int i = 0; i < m.length; i++) { StringBuilder name = new StringBuilder(variableName); name.append(".").append(m[i].getName()); FunctionCompletion fc = new FunctionCompletion(provider, name.toString(), m[i].getReturnType().getSimpleName()); Class<?>[] p = m[i].getParameterTypes(); List<ParameterizedCompletion.Parameter> params = new ArrayList<>(); ParameterizedCompletion.Parameter param; for (int j = 0; j < p.length; j++) { param = new ParameterizedCompletion.Parameter(p[j].getSimpleName(), "arg" + (j + 1)); params.add(param); } fc.setParams(params); fc.setDefinedIn(m[i].getDeclaringClass().getName()); provider.addCompletion(fc); listOfImportedMethods.add(name.toString()); listOfMethodReturns.put(name.toString(), m[i].getReturnType().getCanonicalName()); } Field f[] = c.getFields(); for (int i = 0; i < f.length; i++) { StringBuilder name = new StringBuilder(variableName); name.append(".").append(f[i].getName()); vc = new VariableCompletion(provider, name.toString(), f[i].getType().toString()); vc.setDefinedIn(f[i].getDeclaringClass().getName()); provider.addCompletion(vc); } } else { VariableCompletion vc = new VariableCompletion(provider, variableName, "Object"); provider.addCompletion(vc); } return true; } catch (SecurityException e) { return false; } } private void handleError(String msg) { errOut.append(msg + "\n"); } private void initScriptEngine() { try { if (language == PYTHON) { if (System.getProperty("python.home") == null) { System.setProperty("python.home", ""); } } engine = mgr.getEngineByName(language.toString().toLowerCase()); PrintWriter out = new PrintWriter(new Scripter.TextAreaWriter(textArea)); engine.getContext().setWriter(out); engine.getContext().setErrorWriter(out); if (language == PYTHON && sourceFile != null) { engine.put("__file__", sourceFile); } engine.put("pluginHost", (WhiteboxPluginHost) host); engine.put("args", new String[0]); // update the statusbar ScriptEngineFactory scriptFactory = engine.getFactory(); statusLabel.setText(bundle.getString("ScriptingLanguage") + ": " + scriptFactory.getLanguageName()); } catch (Exception e) { handleError(e.getMessage()); } } public void openFile(String fileName) { sourceFile = fileName; if (sourceFile == null || sourceFile.isEmpty()) { openFile(); } if (sourceFile.toLowerCase().contains(".py")) { //language = Scripter.ScriptingLanguage.PYTHON; setLanguage(Scripter.ScriptingLanguage.PYTHON); editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_PYTHON); } else if (sourceFile.toLowerCase().contains(".groovy")) { //language = Scripter.ScriptingLanguage.GROOVY; setLanguage(Scripter.ScriptingLanguage.GROOVY); editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_GROOVY); } else { //language = Scripter.ScriptingLanguage.JAVASCRIPT; setLanguage(Scripter.ScriptingLanguage.JAVASCRIPT); editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); } //editor.setContentType("text/" + language); editor.setEditable(true); DataInputStream in = null; BufferedReader br = null; try { // Open the file that is the first command line parameter FileInputStream fstream = new FileInputStream(this.sourceFile); // Get the object of DataInputStream in = new DataInputStream(fstream); br = new BufferedReader(new InputStreamReader(in)); String line; String str = ""; if (this.sourceFile != null) { //Read File Line By Line while ((line = br.readLine()) != null) { str += line + "\n"; } } editor.setText(str); } catch (Exception e) { } editor.setEditable(true); editor.setCaretPosition(0); this.setTitle("Whitebox Scripter: " + new File(sourceFile).getName()); } private void openFile() { JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setMultiSelectionEnabled(false); fc.setAcceptAllFileFilterUsed(true); fc.setCurrentDirectory(new File(scriptsDirectory)); FileFilter ft = new FileNameExtensionFilter("Javascript " + bundle.getString("Files"), "js"); fc.addChoosableFileFilter(ft); ft = new FileNameExtensionFilter("Groovy " + bundle.getString("Files"), "groovy"); fc.addChoosableFileFilter(ft); ft = new FileNameExtensionFilter("Python " + bundle.getString("Files"), "py"); fc.addChoosableFileFilter(ft); int result = fc.showOpenDialog(this); if (result == JFileChooser.APPROVE_OPTION) { File file = fc.getSelectedFile(); sourceFile = file.toString(); //String fileDirectory = file.getParentFile() + pathSep; if (sourceFile.toLowerCase().contains(".py")) { //language = Scripter.ScriptingLanguage.PYTHON; setLanguage(Scripter.ScriptingLanguage.PYTHON); editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_PYTHON); } else if (sourceFile.toLowerCase().contains(".groovy")) { //language = Scripter.ScriptingLanguage.GROOVY; setLanguage(Scripter.ScriptingLanguage.GROOVY); editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_GROOVY); } else { //language = Scripter.ScriptingLanguage.JAVASCRIPT; setLanguage(Scripter.ScriptingLanguage.JAVASCRIPT); editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); } //editor.setContentType("text/" + language); editor.setEditable(true); DataInputStream in = null; BufferedReader br = null; try { // Open the file that is the first command line parameter FileInputStream fstream = new FileInputStream(this.sourceFile); // Get the object of DataInputStream in = new DataInputStream(fstream); br = new BufferedReader(new InputStreamReader(in)); String line; String str = ""; if (this.sourceFile != null) { //Read File Line By Line while ((line = br.readLine()) != null) { str += line + "\n"; } } editor.setText(str); } catch (Exception e) { } editor.setEditable(true); editor.setCaretPosition(0); this.setTitle("Whitebox Scripter: " + new File(sourceFile).getName()); } } private void save() { if (sourceFile == null) { String extension = ""; switch (language) { case PYTHON: extension = ".py"; break; case GROOVY: extension = ".groovy"; break; case JAVASCRIPT: extension = ".js"; break; } JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setMultiSelectionEnabled(false); fc.setAcceptAllFileFilterUsed(true); fc.setFileHidingEnabled(true); FileFilter ft = new FileNameExtensionFilter("Javascript " + bundle.getString("Files"), "js"); fc.addChoosableFileFilter(ft); ft = new FileNameExtensionFilter("Groovy " + bundle.getString("Files"), "groovy"); fc.addChoosableFileFilter(ft); ft = new FileNameExtensionFilter("Python " + bundle.getString("Files"), "py"); fc.addChoosableFileFilter(ft); //fc.setFileFilter(ft); fc.setCurrentDirectory(new File(scriptsDirectory)); int result = fc.showSaveDialog(this); File file = null; if (result == JFileChooser.APPROVE_OPTION) { file = fc.getSelectedFile(); // does the file contain an extension? if (!file.toString().endsWith(extension)) { file = new File(file.toString() + extension); } if (file.exists()) { Object[] options = {"Yes", "No"}; int n = JOptionPane.showOptionDialog(this, host.getMessageBundle().getString("FileExists") + "\n" + host.getMessageBundle().getString("Overwrite"), "Whitebox GAT Message", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, //do not use a custom Icon options, //the titles of buttons options[0]); //default button title if (n == JOptionPane.YES_OPTION) { file.delete(); new File(file.toString().replace(".dep", ".tas")).delete(); } else if (n == JOptionPane.NO_OPTION) { return; } } sourceFile = file.toString(); if (sourceFile.toLowerCase().contains(".py")) { setLanguage(Scripter.ScriptingLanguage.PYTHON); //language = Scripter.ScriptingLanguage.PYTHON; } else if (sourceFile.toLowerCase().contains(".groovy")) { setLanguage(Scripter.ScriptingLanguage.GROOVY); //language = Scripter.ScriptingLanguage.GROOVY; } else if (sourceFile.toLowerCase().contains(".js")) { setLanguage(Scripter.ScriptingLanguage.JAVASCRIPT); //language = Scripter.ScriptingLanguage.JAVASCRIPT; } this.setTitle("Whitebox Scripter: " + new File(sourceFile).getName()); } else { return; } } File file = new File(sourceFile); FileWriter fw = null; BufferedWriter bw = null; PrintWriter out = null; try { fw = new FileWriter(file, false); bw = new BufferedWriter(fw); out = new PrintWriter(bw, true); out.print(editor.getText()); bw.close(); fw.close(); editorDirty = false; } catch (java.io.IOException e) { System.err.println("Error: " + e.getMessage()); } catch (Exception e) { //Catch exception if any System.err.println("Error: " + e.getMessage()); } finally { if (out != null || bw != null) { out.flush(); out.close(); } } } private void saveAs() { sourceFile = null; save(); } private void print() { try { editor.print(); } catch (Exception e) { host.logException("Error in Scripter.", e); } } private void execute() { try { host.resetRequestForOperationCancel(); String expression = editor.getText(); execWithThread(expression); } catch (Exception e) { errOut.append(e.getMessage() + "\n"); } } private void execWithThread(final String scriptString) { final Runnable r = new Runnable() { @Override public void run() { try { engine.eval(scriptString); } catch (ScriptException e) { errOut.append(e.getMessage() + "\n"); } } }; final Thread t = new Thread(r); t.start(); } private void comment() { try { String selectedText = editor.getSelectedText(); int start = editor.getSelectionStart(); int end = editor.getSelectionEnd(); if (selectedText == null || selectedText.isEmpty()) { toggleComment(editor.getCaretLineNumber()); } else { int startLine = editor.getLineOfOffset(start); int endLine = editor.getLineOfOffset(end); for (int i = startLine; i <= endLine; i++) { toggleComment(i); } } } catch (Exception e) { // do nothing } } private void indentSelection() { try { int start = editor.getSelectionStart(); int end = editor.getSelectionEnd(); int startLine = editor.getLineOfOffset(start); int endLine = editor.getLineOfOffset(end); for (int i = startLine; i <= endLine; i++) { int j = editor.getLineStartOffset(i); // add a line comment tag. editor.insert("\t", j); } } catch (Exception e) { // do nothing } } private void outdentSelection() { try { int start = editor.getSelectionStart(); int end = editor.getSelectionEnd(); int startLine = editor.getLineOfOffset(start); int endLine = editor.getLineOfOffset(end); for (int i = startLine; i <= endLine; i++) { int j = editor.getLineStartOffset(i); if (editor.getText(j, "\t".length()).startsWith("\t")) { // remove the indent editor.replaceRange("", j, j + "\t".length()); } else if (editor.getText(j, " ".length()).startsWith(" ")) { // remove the indent editor.replaceRange("", j, j + " ".length()); } } } catch (Exception e) { // do nothing } } private void toggleComment(int lineNum) { try { int start = editor.getLineStartOffset(lineNum); String openingCharacters = editor.getText(start, language.getCommentMarker().length()); if (openingCharacters.startsWith(language.getCommentMarker())) { // remove the line comment tag. editor.replaceRange("", start, start + language.getCommentMarker().length()); } else { // add a line comment tag. editor.insert(language.getCommentMarker(), start); } } catch (Exception e) { // do nothing } } @Override public void actionPerformed(ActionEvent e) { // Object source = e.getSource(); String actionCommand = e.getActionCommand(); switch (actionCommand.toLowerCase()) { case "indent": indentSelection(); break; case "outdent": outdentSelection(); break; case "close": if (editorDirty) { Object[] options = {"Yes", "No", "Cancel"}; int n = JOptionPane.showOptionDialog(this, "The source code has changed. Would you like to save it?", "Whitebox GAT Message", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, //do not use a custom Icon options, //the titles of buttons options[0]); //default button title if (n == JOptionPane.YES_OPTION) { save(); } else if (n == JOptionPane.NO_OPTION) { // do nothing } else if (n == JOptionPane.CANCEL_OPTION) { return; } } editor.setText(""); sourceFile = null; editorDirty = false; this.setTitle("Whitebox Scripter"); break; case "exit": if (editorDirty) { Object[] options = {"Yes", "No", "Cancel"}; int n = JOptionPane.showOptionDialog(this, "The source code has changed. Would you like to save it?", "Whitebox GAT Message", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, //do not use a custom Icon options, //the titles of buttons options[0]); //default button title if (n == JOptionPane.YES_OPTION) { save(); } else if (n == JOptionPane.NO_OPTION) { // do nothing } else if (n == JOptionPane.CANCEL_OPTION) { return; } } this.dispose(); break; case "execute": if (sourceFile != null && editorDirty && saveOnExecution) { save(); } execute(); break; case "saveOnExecute": saveOnExecution = !saveOnExecution; case "open": openFile(); resetAutocompletion(); scanDoc(); break; case "print": print(); break; case "python": setLanguage(Scripter.ScriptingLanguage.PYTHON); break; case "groovy": setLanguage(Scripter.ScriptingLanguage.GROOVY); break; case "javascript": setLanguage(Scripter.ScriptingLanguage.JAVASCRIPT); break; case "comment": comment(); break; case "save": save(); break; case "saveas": saveAs(); break; case "clearconsole": textArea.setText(""); break; case "generatedata": this.firePropertyChange("generateData", false, true); break; case "undo": editor.undoLastAction(); break; case "redo": editor.redoLastAction(); break; case "cut": editor.cut(); break; case "copy": editor.copy(); break; case "paste": editor.paste(); resetAutocompletion(); scanDoc(); break; case ("findnext"): case ("findprev"): boolean forward = "findnext".equals(actionCommand.toLowerCase()); // Create an object defining our search parameters. SearchContext context = new SearchContext(); String text = searchField.getText(); if (text.length() == 0) { return; } context.setSearchFor(text); context.setMatchCase(matchCaseCB.isSelected()); context.setRegularExpression(regexCB.isSelected()); context.setSearchForward(forward); context.setWholeWord(wholeWordCB.isSelected()); // boolean found = SearchEngine.find(editor, context); SearchResult result = SearchEngine.find(editor, context); if (!result.wasFound()) { JOptionPane.showMessageDialog(this, "Text not found"); } break; case "selectalltext": textArea.selectAll(); break; case "copytext": textArea.copy(); break; case "pastetext": textArea.paste(); break; case "cuttext": textArea.cut(); break; case "cleartext": textArea.setText(""); break; } } // @Override // public void dispose() { // if (editorDirty) { // Object[] options = {"Yes", "No", "Cancel"}; // int n = JOptionPane.showOptionDialog(this, // "The source code has changed. Would you like to save it?", // "Whitebox GAT Message", // JOptionPane.YES_NO_OPTION, // JOptionPane.QUESTION_MESSAGE, // null, //do not use a custom Icon // options, //the titles of buttons // options[0]); //default button title // // if (n == JOptionPane.YES_OPTION) { // save(); // } else if (n == JOptionPane.NO_OPTION) { // // do nothing // } else if (n == JOptionPane.CANCEL_OPTION) { // return; // } // } // super.dispose(); // } public void setLanguage(Scripter.ScriptingLanguage lang) { Scripter.ScriptingLanguage oldLang = this.language; if (lang == null) { return; } switch (lang) { case PYTHON: python.setState(true); groovy.setState(false); javascript.setState(false); editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_PYTHON); break; case GROOVY: python.setState(false); groovy.setState(true); javascript.setState(false); editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_GROOVY); break; case JAVASCRIPT: groovy.setState(false); python.setState(false); javascript.setState(true); editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); break; // case RUBY: // python.setState(false); // groovy.setState(false); // javascript.setState(false); // editor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_RUBY); // break; } this.language = lang; // setupAutoComplete(); // this.editor.setContentType("text/" + this.language); initScriptEngine(); resetAutocompletion(); scanDoc(); this.firePropertyChange(PROP_SCRIPTING_LANGUAGE, oldLang, lang); } // public void showGenerateDataButton(boolean show) { // generateDataButton.setVisible(show); // } /** * Creates a CompiledScript object using the provided text and the currently * selected ScriptEngine. * * @return */ public CompiledScript compileScript() { try { CompiledScript compiled = ((Compilable) engine).compile(this.editor.getText()); return compiled; } catch (ScriptException e) { System.out.println(e); } return null; } public Bindings createBindingsObject() { return engine.createBindings(); } public void setEditorText(String text) { this.editor.setText(text); } public Scripter.ScriptingLanguage getLanguage() { return this.language; } public static void main(String args[]) throws ScriptException { Scripter scripter = new Scripter(null, false); scripter.setVisible(true); } public final class TextAreaWriter extends Writer { private final JTextArea textArea; public TextAreaWriter(final JTextArea textArea) { this.textArea = textArea; } @Override public void flush() { } @Override public void close() { } @Override public void write(char[] cbuf, int off, int len) throws IOException { textArea.append(new String(cbuf, off, len)); } } // class JTextAreaInputStream extends InputStream { // // byte[] contents; // int pointer = 0; // // public JTextAreaInputStream(final JTextArea text) { // // text.addKeyListener(new KeyAdapter() { // @Override // public void keyReleased(KeyEvent e) { // if (e.getKeyChar() == '\n') { // contents = text.getText().getBytes(); // pointer = 0; // text.setText(""); // } // super.keyReleased(e); // } // }); // } // // @Override // public int read() throws IOException { // if (pointer >= contents.length) { // return -1; // } // return this.contents[pointer++]; // } // } // final class TextAreaStreamer extends InputStream implements ActionListener { // // private JTextArea textArea; // private String str = null; // private int pos = 0; // // public TextAreaStreamer(JTextArea jta) { // textArea = jta; // textArea.addKeyListener(new KeyAdapter() { // @Override // public void keyReleased(KeyEvent e) { // if (e.getKeyChar() == '\n') { // str = textArea.getText(); //.getBytes(); // pos = 0; // read(); // } // super.keyReleased(e); // } // }); // } // // //gets triggered everytime that "Enter" is pressed on the textfield // @Override // public void actionPerformed(ActionEvent e) { // str = textArea.getText() + "\n"; // pos = 0; // textArea.setText(""); // synchronized (this) { // //maybe this should only notify() as multiple threads may // //be waiting for input and they would now race for input // this.notify(); // } // } // // @Override // public int read() { // //test if the available input has reached its end // //and the EOS should be returned // if (str != null && pos == str.length()) { // str = null; // //this is supposed to return -1 on "end of stream" // //but I'm having a hard time locating the constant // return java.io.StreamTokenizer.TT_EOF; // } // //no input available, block until more is available because that's // //the behavior specified in the Javadocs // while (str == null || pos >= str.length()) { // try { // //according to the docs read() should block until new input is available // synchronized (this) { // this.wait(); // } // } catch (InterruptedException ex) { // ex.printStackTrace(); // } // } // //read an additional character, return it and increment the index // return str.charAt(pos++); // } // } }