/* * Copyright (C) 2013 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 whitebox.ui.plugin_dialog; import javax.swing.*; import javax.swing.event.*; import java.awt.*; import java.awt.event.*; import java.util.ArrayList; import java.io.*; import java.util.ResourceBundle; import java.util.logging.Level; import javax.swing.border.Border; import whitebox.interfaces.DialogComponent; import whitebox.interfaces.Communicator; import whitebox.interfaces.WhiteboxPluginHost; import javax.swing.event.HyperlinkListener; import whitebox.utilities.FileUtilities; /** * This class is used to provide a dialog box for a Whitebox GAT script tool. * * @author Dr. John Lindsay <jlindsay@uoguelph.ca> */ public class ScriptDialog implements Communicator, ActionListener, HyperlinkListener { private JButton ok = new JButton("OK"); private JButton close = new JButton("Close"); private JButton viewCode = new JButton("View Code"); private JButton back = new JButton(); private JButton forward = new JButton(); private JButton newHelp = new JButton(); private JButton modifyHelp = new JButton(); private JEditorPane helpPane = new JEditorPane(); private JScrollPane mainScrollPane = null; //new JScrollPane(); private JPanel mainPanel = new JPanel(); private String helpFile = ""; private String graphicsDirectory = ""; private String workingDirectory = ""; private String applicationDirectory = ""; private String resourcesDirectory = ""; private String logDirectory = ""; private String pathSep = ""; private String sourceFile = ""; private ArrayList<DialogComponent> components = new ArrayList<>(); private Communicator host = null; private boolean automaticallyClose = true; private ArrayList<String> helpHistory = new ArrayList<>(); private int helpHistoryIndex = 0; private ActionListener buttonActionListener = null; private ResourceBundle bundle; private ResourceBundle messages; private JDialog dialog; private String title; public ScriptDialog(WhiteboxPluginHost owner, String title, ActionListener buttonActionListener) { pathSep = File.separator; host = (Communicator) owner; workingDirectory = host.getWorkingDirectory(); applicationDirectory = host.getApplicationDirectory(); resourcesDirectory = host.getResourcesDirectory(); graphicsDirectory = resourcesDirectory + "Images" + pathSep; bundle = host.getGuiLabelsBundle(); messages = host.getMessageBundle(); this.title = title; //setTitle(title); this.buttonActionListener = buttonActionListener; createGui(); } // /** // * Constructor // * // * @param owner the name of the Whitebox GAT GUI class // * @param title A string that should be the same name as the script's // * descriptive name // * @param buttonActionListener A listener to attach to the OK button // */ // public ScriptDialog(Frame owner, String title, ActionListener buttonActionListener) { // super(owner, false); // pathSep = File.separator; // host = (Communicator) owner; // workingDirectory = host.getWorkingDirectory(); // applicationDirectory = host.getApplicationDirectory(); // resourcesDirectory = host.getResourcesDirectory(); // graphicsDirectory = resourcesDirectory + "Images" + pathSep; // bundle = host.getGuiLabelsBundle(); // messages = host.getMessageBundle(); // // setTitle(title); // // this.buttonActionListener = buttonActionListener; // // createGui(); // } private void createGui() { if (host != null && host instanceof Frame) { dialog = new JDialog((Frame)host, false); } else { dialog = new JDialog(); } dialog.setTitle(title); if (System.getProperty("os.name").contains("Mac")) { dialog.getRootPane().putClientProperty("apple.awt.brushMetalLook", Boolean.TRUE); } if (bundle != null) { ok = new JButton(bundle.getString("Run")); close = new JButton(bundle.getString("Close")); viewCode = new JButton(bundle.getString("ViewCode")); newHelp = new JButton(bundle.getString("NewHelp")); modifyHelp = new JButton(bundle.getString("ModifyHelp")); } else { ok = new JButton("Run"); close = new JButton("Close"); viewCode = new JButton("View Code"); newHelp = new JButton("Create New Help File"); modifyHelp = new JButton("Modify Help File"); } String imgLocation = null; ImageIcon image = null; helpPane.addHyperlinkListener(this); helpPane.setContentType("text/html"); mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS)); mainScrollPane = new JScrollPane(mainPanel); JScrollPane helpScroll = new JScrollPane(helpPane); Box box2 = Box.createHorizontalBox(); box2.add(Box.createHorizontalStrut(10)); box2.add(ok); ok.setActionCommand("ok"); ok.addActionListener(this); if (buttonActionListener != null) { ok.addActionListener(buttonActionListener); } box2.add(Box.createRigidArea(new Dimension(5, 30))); box2.add(close); close.setActionCommand("close"); close.addActionListener(this); if (buttonActionListener != null) { close.addActionListener(buttonActionListener); } box2.add(Box.createHorizontalStrut(5)); viewCode.setActionCommand("viewCode"); viewCode.addActionListener(this); viewCode.setVisible(false); box2.add(viewCode); box2.add(Box.createHorizontalGlue()); // create the newHelp button newHelp.setActionCommand("newHelp"); newHelp.setToolTipText("Create New HelpEntry"); newHelp.addActionListener(this); newHelp.setVisible(false); box2.add(newHelp); box2.add(Box.createHorizontalStrut(5)); // create the newHelp button modifyHelp.setActionCommand("modifyHelp"); modifyHelp.setToolTipText("Modify Help File"); modifyHelp.addActionListener(this); modifyHelp.setVisible(false); box2.add(modifyHelp); box2.add(Box.createHorizontalStrut(5)); // create the back button imgLocation = graphicsDirectory + "HelpBack.png"; image = new ImageIcon(imgLocation, ""); back.setActionCommand("back"); back.setToolTipText("back"); back.addActionListener(this); try { back.setIcon(image); } catch (Exception e) { back.setText("<"); } box2.add(back); box2.add(Box.createHorizontalStrut(5)); // create the forward button imgLocation = graphicsDirectory + "HelpForward.png"; image = new ImageIcon(imgLocation, ""); forward.setActionCommand("forward"); forward.setToolTipText("forward"); forward.addActionListener(this); try { forward.setIcon(image); } catch (Exception e) { forward.setText(">"); } box2.add(forward); box2.add(Box.createHorizontalStrut(10)); JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mainScrollPane, helpScroll); splitter.setDividerLocation(365); splitter.setResizeWeight(0.0); splitter.setDividerSize(4); dialog.getContentPane().add(splitter, BorderLayout.CENTER); dialog.getContentPane().add(box2, BorderLayout.SOUTH); dialog.pack(); dialog.setSize(800, 400); // Centre the dialog on the screen. // Get the size of the screen Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); int screenHeight = dim.height; int screenWidth = dim.width; //setSize(screenWidth / 2, screenHeight / 2); dialog.setLocation(screenWidth / 4, screenHeight / 4); } public void setVisible(boolean visible) { dialog.setVisible(visible); } public void setSize(int width, int height) { dialog.setSize(width, height); } /** * Adds a checkbox to the dialog * * @param description This string is entered into the pop-up description. * @param labelText This string is added to the checkbox label. * @param initialState Determines whether the checkbox is checked at * startup. * @return DialogCheckBox a reference to the created object. */ public DialogCheckBox addDialogCheckBox(String description, String labelText, boolean initialState) { String[] args = new String[4]; args[0] = "checkbox"; args[1] = description; args[2] = labelText; args[3] = Boolean.toString(initialState); DialogCheckBox dcb = new DialogCheckBox(); dcb.setArgs(args); components.add(dcb); mainPanel.add(dcb); return dcb; } public DialogDataInput addDialogDataInput(String description, String labelText, String initialText, boolean numericalInput, boolean makeOptional) { String[] args = new String[6]; args[0] = "data"; args[1] = description; args[2] = labelText; args[3] = initialText; args[4] = Boolean.toString(numericalInput); args[5] = Boolean.toString(makeOptional); DialogDataInput ddi = new DialogDataInput(); ddi.setArgs(args); components.add(ddi); mainPanel.add(ddi); return ddi; } public DialogFile addDialogFile(String description, String labelText, String dialogMode, String filter, boolean showButton, boolean makeOptional) { String[] args = new String[7]; args[0] = "file"; args[1] = description; args[2] = labelText; if (dialogMode.toLowerCase().contains("open")) { args[3] = Integer.toString(DialogFile.MODE_OPEN); } else { args[3] = Integer.toString(DialogFile.MODE_SAVEAS); } args[4] = Boolean.toString(showButton); args[5] = filter; args[6] = Boolean.toString(makeOptional); DialogFile df = new DialogFile(host); df.setArgs(args); components.add(df); mainPanel.add(df); return df; } // public DialogFile addDialogFile(String description, String labelText, // String dialogMode, String filter, boolean showButton, // boolean makeOptional, ActionListener actionListener) { // String[] args = new String[7]; // args[0] = "file"; // args[1] = description; // args[2] = labelText; // if (dialogMode.toLowerCase().contains("open")) { // args[3] = Integer.toString(DialogFile.MODE_OPEN); // } else { // args[3] = Integer.toString(DialogFile.MODE_SAVEAS); // } // args[4] = Boolean.toString(showButton); // args[5] = filter; // args[6] = Boolean.toString(makeOptional); // // DialogFile df = new DialogFile(host); // df.setArgs(args); // df.setTextFieldActionListener(actionListener); // components.add(df); // mainPanel.add(df); // return df; // } public DialogMultiFile addDialogMultiFile(String description, String labelText, String filter) { String[] args = new String[4]; args[0] = "multifile"; args[1] = description; args[2] = labelText; args[3] = filter; DialogMultiFile dmf = new DialogMultiFile(host); dmf.setArgs(args); components.add(dmf); mainPanel.add(dmf); return dmf; } public JButton addDialogButton(String text, String align) { Box box = Box.createHorizontalBox(); JButton btn = new JButton(text); //box.add(Box.createHorizontalStrut(5)); if (align.toLowerCase().contains("right")) { box.add(Box.createHorizontalGlue()); box.add(btn); } else if (align.toLowerCase().contains("left")) { box.add(btn); box.add(Box.createHorizontalGlue()); } else { // centre box.add(Box.createHorizontalGlue()); box.add(btn); box.add(Box.createHorizontalGlue()); } // JPanel panel = new JPanel(); // Border border = BorderFactory.createEmptyBorder(5, 5, 5, 5); // panel.setBorder(border); // panel.setBackground(Color.red); // panel.setMaximumSize(new Dimension(2500, btn.getPreferredSize().height + 8)); // panel.setPreferredSize(new Dimension(350, btn.getPreferredSize().height + 8)); // panel.add(box); mainPanel.add(box); return btn; } public JLabel addDialogLabel(String text) { // JPanel panel = new JPanel(); // panel.setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); //Border border = BorderFactory.createEmptyBorder(5, 5, 5, 5); //panel.setBorder(border); Box box = Box.createHorizontalBox(); JLabel lbl = new JLabel(text); box.add(Box.createHorizontalStrut(5)); box.add(lbl); box.add(Box.createHorizontalGlue()); //panel.setBackground(Color.blue); // panel.setMaximumSize(new Dimension(2500, lbl.getPreferredSize().height + 2)); // panel.setPreferredSize(new Dimension(350, lbl.getPreferredSize().height + 2)); // panel.add(box); mainPanel.add(box); return lbl; } public DialogFieldSelector addDialogFieldSelector(String description, String labelText, boolean allowMultipleSelection) { String[] args = new String[4]; args[0] = "fieldselector"; args[1] = description; args[2] = labelText; args[3] = Boolean.toString(allowMultipleSelection); DialogFieldSelector dfs = new DialogFieldSelector(); dfs.setHostDialog(host); dfs.setArgs(args); components.add(dfs); mainPanel.add(dfs); return dfs; } public DialogComboBox addDialogComboBox(String description, String labelText, ArrayList<String> listItems, int defaultItem) { String[] args = new String[5]; args[0] = "combobox"; args[1] = description; args[2] = labelText; StringBuilder items = new StringBuilder(); for (int a = 0; a < listItems.size(); a++) { if (a > 0) { items.append(",").append(listItems.get(a)); } else { items.append(listItems.get(a)); } } args[3] = items.toString(); args[4] = Integer.toString(defaultItem); DialogComboBox dcb = new DialogComboBox(); dcb.setArgs(args); components.add(dcb); mainPanel.add(dcb); return dcb; } public DialogComboBox addDialogComboBox(String description, String labelText, String[] listItems, int defaultItem) { String[] args = new String[5]; args[0] = "combobox"; args[1] = description; args[2] = labelText; StringBuilder items = new StringBuilder(); for (int a = 0; a < listItems.length; a++) { if (a > 0) { items.append(",").append(listItems[a]); } else { items.append(listItems[a]); } } args[3] = items.toString(); args[4] = Integer.toString(defaultItem); DialogComboBox dcb = new DialogComboBox(); dcb.setArgs(args); components.add(dcb); mainPanel.add(dcb); return dcb; } public DialogList addDialogList(String description, String labelText, String[] listItems, boolean allowMultipleSelection) { String[] args = new String[5]; args[0] = "list"; args[1] = description; args[2] = labelText; StringBuilder items = new StringBuilder(); for (int a = 0; a < listItems.length; a++) { if (a > 0) { items.append(",").append(listItems[a]); } else { items.append(listItems[a]); } } args[3] = items.toString(); args[4] = Boolean.toString(allowMultipleSelection); DialogList dl = new DialogList(); dl.setArgs(args); components.add(dl); mainPanel.add(dl); return dl; } public DialogOption addDialogOption(String description, String labelText, String button1String, String button2String) { String[] args = new String[5]; args[0] = "dialogoption"; args[1] = description; args[2] = labelText; args[3] = button1String; args[4] = button2String; DialogOption d = new DialogOption(); d.setArgs(args); components.add(d); mainPanel.add(d); return d; } private String[] collectValues() { int numComponents = components.size(); String[] ret = new String[numComponents]; for (int i = 0; i < numComponents; i++) { ret[i] = components.get(i).getValue(); } return ret; } @Override public String getWorkingDirectory() { // update the workingDirectory workingDirectory = host.getWorkingDirectory(); return workingDirectory; } @Override public void setWorkingDirectory(String workingDirectory) { this.workingDirectory = workingDirectory; // update the workingDirectory host.setWorkingDirectory(workingDirectory); } @Override public String getApplicationDirectory() { // update the applicationDirectory applicationDirectory = host.getApplicationDirectory(); return applicationDirectory; } @Override public void setApplicationDirectory(String applicationDirectory) { this.applicationDirectory = applicationDirectory; host.setApplicationDirectory(applicationDirectory); } @Override public String getResourcesDirectory() { // update the applicationDirectory resourcesDirectory = host.getResourcesDirectory(); return resourcesDirectory; } @Override public String getLogDirectory() { // update the applicationDirectory logDirectory = host.getLogDirectory(); return logDirectory; } /** * Used to communicate feedback pop-up messages between a plugin tool and * the main Whitebox user-interface. * * @param feedback String containing the text to display. */ @Override public int showFeedback(String message) { host.showFeedback(message); return -1; } @Override public int showFeedback(String message, int optionType, int messageType) { int n = host.showFeedback(message, optionType, messageType); return n; } /** * Used to find whether the dialog will automatically close after being * launched. * * @return boolean. */ public boolean getAutomaticallyClose() { return automaticallyClose; } /** * Used to set whether the dialog should automatically close after bing * launched. * * @param value Boolean value. True if dialog should close, otherwise false. */ public void setAutomaticallyClose(boolean value) { automaticallyClose = value; } public void setSourceFile(String file) { sourceFile = file; if (new File(sourceFile).exists()) { viewCode.setVisible(true); } } String scriptsHelpFile = null; public void setHelpFile(String newHelpFile) { this.helpFile = newHelpFile; if (!helpFile.contains(pathSep)) { helpFile = resourcesDirectory + "Help" + pathSep + helpFile; } if (!helpFile.endsWith(".html")) { helpFile = this.helpFile + ".html"; } File hlp = new File(helpFile); scriptsHelpFile = helpFile; if (!hlp.exists()) { // use the NoHelp.html file. helpFile = resourcesDirectory + "Help" + pathSep + "other" + pathSep + "NoHelp.html"; newHelp.setVisible(true); modifyHelp.setVisible(false); } else { modifyHelp.setVisible(true); newHelp.setVisible(false); } this.helpHistory.add(helpFile); helpPane.setEditable(false); try { //URL helpURL = getClass().getResource(helpFile); //helpPane.setPage(helpURL); helpPane.setPage("file:" + helpFile); } catch (IOException e) { System.err.println(e.getStackTrace()); } } /** * Used to run a plugin through the Host app. * * @param pluginName String containing the descriptive name of the plugin. * @param args String array containing the parameters to feed to the plugin. * @param runOnDedicatedThread boolean value; set to true if the tool should * be run on a dedicated thread and false if it should be run on the same * thread as the calling Communicator. */ @Override public void runPlugin(String pluginName, String[] args, boolean runOnDedicatedThread) { host.runPlugin(pluginName, args, runOnDedicatedThread); if (automaticallyClose) { this.dispose(); } } /** * Used to run a plugin through the Host app. * * @param pluginName String containing the descriptive name of the plugin. * @param args String array containing the parameters to feed to the plugin. */ @Override public void runPlugin(String pluginName, String[] args) { host.runPlugin(pluginName, args); if (automaticallyClose) { //this.setVisible(false); this.dispose(); } } @Override public void runPlugin(String pluginName, String[] args, boolean runOnDedicatedThread, boolean suppressReturnedData) { host.runPlugin(pluginName, args, runOnDedicatedThread, suppressReturnedData); if (automaticallyClose) { //this.setVisible(false); this.dispose(); } } private void back() { if (helpHistoryIndex == 0) { return; } helpHistoryIndex--; try { helpPane.setPage("file:" + helpHistory.get(helpHistoryIndex)); } catch (IOException e) { System.err.println(e.getStackTrace()); } } private void forward() { if (helpHistoryIndex == helpHistory.size() - 1) { return; } helpHistoryIndex++; try { helpPane.setPage("file:" + helpHistory.get(helpHistoryIndex)); } catch (IOException e) { System.err.println(e.getStackTrace()); } } public String[] collectParameters() { String[] args = collectValues(); if (userButtonSelection == 1) { //boolean containsNull = false; for (int i = 0; i < args.length; i++) { if (args[i] == null) { //containsNull = true; showFeedback("Parameter " + components.get(i).getComponentName() + " has not been specified. The tool will not execute."); break; } } } return args; } private int userButtonSelection = -1; public int getUserButtonSelection() { return userButtonSelection; } private void newHelp() { String helpDirectory = host.getResourcesDirectory() + "Help" + pathSep; // grab the text within the "NewHelp.txt" file in the helpDirectory; String defaultHelp = helpDirectory + "NewHelp.txt"; if (!(new File(defaultHelp)).exists()) { showFeedback(messages.getString("NoHelp")); return; } try { String defaultText = FileUtilities.readFileAsString(defaultHelp); // now place this text into the new file. FileUtilities.fillFileWithString(scriptsHelpFile, defaultText); ViewCodeDialog vcd = new ViewCodeDialog((Frame) host, false, new File(scriptsHelpFile), true); vcd.setSize(new Dimension(800, 600)); vcd.setVisible(true); } catch (IOException ioe) { showFeedback(messages.getString("HelpNotRead")); return; } } private void modifyHelp() { String helpDirectory = host.getResourcesDirectory() + "Help" + pathSep; // grab the text within the "NewHelp.txt" file in the helpDirectory; if (!(new File(scriptsHelpFile)).exists()) { showFeedback(messages.getString("NoHelpDirectory")); return; } ViewCodeDialog vcd = new ViewCodeDialog((Frame) host, false, new File(scriptsHelpFile), true); vcd.setSize(new Dimension(800, 600)); vcd.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { String actionCommand = e.getActionCommand(); if (actionCommand.equals("close")) { userButtonSelection = 2; this.setVisible(false); } else if (actionCommand.equals("ok")) { userButtonSelection = 1; this.setVisible(false); } else if (actionCommand.equals("viewCode") && sourceFile != null) { ViewCodeDialog vcd = new ViewCodeDialog((Frame) host, false, new File(sourceFile), false); vcd.setSize(new Dimension(800, 600)); vcd.setVisible(true); } else if (actionCommand.equals("back")) { back(); } else if (actionCommand.equals("forward")) { forward(); } else if (actionCommand.equals("newHelp")) { newHelp(); } else if (actionCommand.equals("modifyHelp")) { modifyHelp(); } } @Override public void hyperlinkUpdate(HyperlinkEvent event) { if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { try { if (helpHistoryIndex == helpHistory.size() - 1) { helpHistory.add(event.getURL().getFile()); helpHistoryIndex = helpHistory.size() - 1; } else { for (int i = helpHistory.size() - 1; i > helpHistoryIndex; i--) { helpHistory.remove(i); } helpHistory.add(event.getURL().getFile()); helpHistoryIndex = helpHistory.size() - 1; } helpPane.setPage(event.getURL()); } catch (IOException ioe) { // Some warning to user } } } //@Override public void dispose() { ok = null; close = null; viewCode = null; back = null; forward = null; helpPane = null; mainScrollPane = null; mainPanel = null; components = null; host = null; dialog.dispose(); } @Override public ResourceBundle getGuiLabelsBundle() { if (host != null) { return host.getGuiLabelsBundle(); } else { return null; } } @Override public ResourceBundle getMessageBundle() { if (host != null) { return host.getMessageBundle(); } else { return null; } } @Override public void logException(String message, Exception e) { if (host != null) { host.logException(message, e); } } @Override public void logThrowable(String message, Throwable t) { if (host != null) { host.logThrowable(message, t); } } @Override public void logMessage(Level level, String message) { if (host != null) { host.logMessage(level, message); } } @Override public String[] getCurrentlyDisplayedFiles() { return host.getCurrentlyDisplayedFiles(); } @Override public String getHelpDirectory() { return host.getHelpDirectory(); } }