diff --git a/src/org/aavso/tools/vstar/ui/dialog/TextAreaTabs.java b/src/org/aavso/tools/vstar/ui/dialog/TextAreaTabs.java index abfe0ca8..d7cf2f3d 100644 --- a/src/org/aavso/tools/vstar/ui/dialog/TextAreaTabs.java +++ b/src/org/aavso/tools/vstar/ui/dialog/TextAreaTabs.java @@ -33,130 +33,125 @@ */ public class TextAreaTabs implements ITextComponent { - private boolean canBeEmpty; - private boolean readOnly; - - private List textAreas; - - private JTabbedPane tabs; - - /** - * Constructor. - * - * @param names - * The list of tab names. - * @param initialValues - * The list of initial text area values. - * @param rows - * The number of rows in these text areas; 0 means don't set; - * applied to all text areas. - * @param cols - * The number of rows in these text areas; 0 means don't set; - * applied to all text areas. - * @param readOnly - * Are all these areas read-only? - * @param canBeEmpty - * Can any of these areas be empty? (all or none) - */ - public TextAreaTabs(List names, List initialValues, - int rows, int cols, boolean readOnly, boolean canBeEmpty) { - assert names.size() == initialValues.size(); - - this.readOnly = readOnly; - this.canBeEmpty = canBeEmpty; - this.textAreas = new ArrayList(); - - List namedComponents = new ArrayList(); - - for (int i = 0; i < names.size(); i++) { - JTextArea textArea = new JTextArea( - initialValues.get(i) == null ? "" : initialValues.get(i)); - - textAreas.add(textArea); - - // textArea.setBorder(BorderFactory.createTitledBorder(names.get(i))); - if (!isReadOnly()) { - textArea.setToolTipText("Enter " + names.get(i)); - } - - namedComponents.add(new NamedComponent(names.get(i), - new JScrollPane(textArea))); - } - - for (JTextArea textArea : textAreas) { - if (rows != 0) { - textArea.setRows(rows); - } - - if (cols != 0) { - textArea.setColumns(cols); - } - } - - tabs = PluginComponentFactory.createTabs(namedComponents); - } - - @Override - public String getName() { - return null; - } - - @Override - public boolean canBeEmpty() { - return canBeEmpty; - } - - @Override - public boolean isReadOnly() { - return readOnly; - } - - @Override - public String getValue() { - StringBuffer value = new StringBuffer(); - - for (JTextArea textArea : textAreas) { - value.append(textArea.getText()); - value.append("\n"); - } - - return value.toString(); - } - - @Override - public String getStringValue() { - StringBuffer buf = new StringBuffer(); - - for (JTextArea textArea : textAreas) { - buf.append(textArea.getText()); - buf.append("\n"); - } - - return buf.toString(); - } - - @Override - public void setEditable(boolean state) { - readOnly = !state; - - } - - @Override - public void setValue(String value) { - if ("".equals(value)) { - for (JTextArea textArea : textAreas) { - textArea.setText(""); - } - } else { - String[] values = value.split("\\"); - for (int i = 0; i < values.length; i++) { - textAreas.get(i).setText(values[i]); - } - } - } - - @Override - public JComponent getUIComponent() { - return tabs; - } + private boolean canBeEmpty; + private boolean readOnly; + private String tabTextseparator; + + private List textAreas; + + private JTabbedPane tabs; + + /** + * Constructor. + * + * @param names The list of tab names. + * @param initialValues The list of initial text area values. + * @param rows The number of rows in these text areas; 0 means don't + * set; applied to all text areas. + * @param cols The number of rows in these text areas; 0 means don't + * set; applied to all text areas. + * @param readOnly Are all these areas read-only? + * @param canBeEmpty Can any of these areas be empty? (all or none) + * @param tabTextseparator The text value separator for each tabbed text pane. + */ + public TextAreaTabs(List names, List initialValues, int rows, int cols, boolean readOnly, + boolean canBeEmpty, String tabTextseparator) { + assert names.size() == initialValues.size(); + + this.readOnly = readOnly; + this.canBeEmpty = canBeEmpty; + this.tabTextseparator = tabTextseparator; + this.textAreas = new ArrayList(); + + List namedComponents = new ArrayList(); + + for (int i = 0; i < names.size(); i++) { + JTextArea textArea = new JTextArea(initialValues.get(i) == null ? "" : initialValues.get(i)); + + textAreas.add(textArea); + + // textArea.setBorder(BorderFactory.createTitledBorder(names.get(i))); + if (!isReadOnly()) { + textArea.setToolTipText("Enter " + names.get(i)); + } + + namedComponents.add(new NamedComponent(names.get(i), new JScrollPane(textArea))); + } + + for (JTextArea textArea : textAreas) { + if (rows != 0) { + textArea.setRows(rows); + } + + if (cols != 0) { + textArea.setColumns(cols); + } + } + + tabs = PluginComponentFactory.createTabs(namedComponents); + } + + @Override + public String getName() { + return null; + } + + @Override + public boolean canBeEmpty() { + return canBeEmpty; + } + + @Override + public boolean isReadOnly() { + return readOnly; + } + + @Override + public String getValue() { + StringBuffer value = new StringBuffer(); + + for (JTextArea textArea : textAreas) { + value.append(textArea.getText()); + value.append("\n"); + } + + return value.toString(); + } + + @Override + public String getStringValue() { + StringBuffer buf = new StringBuffer(); + + for (JTextArea textArea : textAreas) { + buf.append(textArea.getText()); + buf.append("\n"); + } + + return buf.toString(); + } + + @Override + public void setEditable(boolean state) { + readOnly = !state; + + } + + @Override + public void setValue(String value) { + if ("".equals(value)) { + for (JTextArea textArea : textAreas) { + textArea.setText(""); + } + } else { + String[] values = value.split(tabTextseparator); + for (int i = 0; i < values.length; i++) { + textAreas.get(i).setText(values[i]); + } + } + } + + @Override + public JComponent getUIComponent() { + return tabs; + } } diff --git a/src/org/aavso/tools/vstar/ui/dialog/prefs/PreferencesDialog.java b/src/org/aavso/tools/vstar/ui/dialog/prefs/PreferencesDialog.java index 09d56b6e..1a26bf88 100644 --- a/src/org/aavso/tools/vstar/ui/dialog/prefs/PreferencesDialog.java +++ b/src/org/aavso/tools/vstar/ui/dialog/prefs/PreferencesDialog.java @@ -40,6 +40,7 @@ public class PreferencesDialog extends AbstractOkCancelDialog { private StarGroupManagementPane starGroupManagementPane; private PluginSettingsPane pluginSettingsPane; private LocaleSelectionPane localeSelectionPane; + private VeLaSettingsPane veLaSettingsPane; /** * Constructor. @@ -86,6 +87,9 @@ private JTabbedPane createTabs() { localeSelectionPane = new LocaleSelectionPane(); tabs.addTab("Locale", localeSelectionPane); + veLaSettingsPane = new VeLaSettingsPane(); + tabs.addTab("VeLa", veLaSettingsPane); + return tabs; } @@ -107,6 +111,7 @@ protected void okAction() { starGroupManagementPane.update(); pluginSettingsPane.update(); localeSelectionPane.update(); + veLaSettingsPane.update(); this.setVisible(false); } @@ -122,6 +127,7 @@ protected void reset() { starGroupManagementPane.reset(); pluginSettingsPane.reset(); localeSelectionPane.reset(); + veLaSettingsPane.reset(); } /** diff --git a/src/org/aavso/tools/vstar/ui/dialog/prefs/VeLaSettingsPane.java b/src/org/aavso/tools/vstar/ui/dialog/prefs/VeLaSettingsPane.java new file mode 100644 index 00000000..7841b362 --- /dev/null +++ b/src/org/aavso/tools/vstar/ui/dialog/prefs/VeLaSettingsPane.java @@ -0,0 +1,168 @@ +/** + * VStar: a statistical analysis tool for variable star data. + * Copyright (C) 2009 AAVSO (http://www.aavso.org/) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.aavso.tools.vstar.ui.dialog.prefs; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFileChooser; +import javax.swing.JPanel; +import javax.swing.JTextArea; + +import org.aavso.tools.vstar.ui.mediator.DocumentManager; +import org.aavso.tools.vstar.util.locale.LocaleProps; +import org.aavso.tools.vstar.vela.VeLaPrefs; + +/** + * VeLa Preferences pane + */ +@SuppressWarnings("serial") +public class VeLaSettingsPane extends JPanel implements IPreferenceComponent { + + private JFileChooser veLaCodeDirectoryChooser; + private JTextArea veLaCodeDirectoriesField; + + private JCheckBox veLaDiagnosticCheckbox; + + public VeLaSettingsPane() { + JPanel veLaSettingsPanel = new JPanel(); + veLaSettingsPanel.setLayout(new BoxLayout(veLaSettingsPanel, BoxLayout.PAGE_AXIS)); + veLaSettingsPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + // VeLa code directories + JPanel veLaCodeDirPanel = new JPanel(); + veLaCodeDirPanel.setLayout(new BoxLayout(veLaCodeDirPanel, BoxLayout.LINE_AXIS)); + veLaCodeDirPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + veLaCodeDirectoriesField = new JTextArea(VeLaPrefs.getCodeDirs()); + veLaCodeDirectoriesField.setEditable(false); + veLaCodeDirectoriesField.setToolTipText("VeLa code directories"); + veLaCodeDirectoriesField.setBorder(BorderFactory.createTitledBorder("Directories")); + + veLaCodeDirPanel.add(veLaCodeDirectoriesField); + + veLaCodeDirectoryChooser = new JFileChooser(); + veLaCodeDirectoryChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + JButton addVeLaCodeDirButton = new JButton("Add VeLa Code Directory"); + addVeLaCodeDirButton.addActionListener(e -> requestDirToAdd()); + + veLaCodeDirPanel.add(addVeLaCodeDirButton); + + veLaSettingsPanel.add(veLaCodeDirPanel); + + veLaSettingsPanel.add(Box.createRigidArea(new Dimension(10, 10))); + + // VeLa dialog diagnostic mode + JPanel veLaCheckboxPanel = new JPanel(); + veLaCheckboxPanel.setLayout(new BoxLayout(veLaCheckboxPanel, BoxLayout.LINE_AXIS)); + veLaCheckboxPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + veLaDiagnosticCheckbox = new JCheckBox("Additional diagnostic tabs in VeLa dialog?"); + veLaDiagnosticCheckbox.setSelected(VeLaPrefs.getDiagnosticMode()); + veLaDiagnosticCheckbox.setToolTipText("Tabs for Abstract Syntax Trees in DOT and LISP form"); + + veLaCheckboxPanel.add(veLaDiagnosticCheckbox); + veLaSettingsPanel.add(veLaCheckboxPanel); + + veLaSettingsPanel.add(Box.createRigidArea(new Dimension(10, 10))); + + // Add a local context button pane. + veLaSettingsPanel.add(createButtonPane()); + + add(veLaSettingsPanel); + } + + protected JPanel createButtonPane() { + JPanel panel = new JPanel(new BorderLayout()); + + JButton setDefaultsButton = new JButton("Set Defaults"); + setDefaultsButton.addActionListener(createSetDefaultsButtonActionListener()); + panel.add(setDefaultsButton, BorderLayout.LINE_START); + + JButton applyButton = new JButton(LocaleProps.get("APPLY_BUTTON")); + applyButton.addActionListener(createApplyButtonActionListener()); + panel.add(applyButton, BorderLayout.LINE_END); + + return panel; + } + + @Override + public void update() { + VeLaPrefs.setCodeDirs(veLaCodeDirectoriesField.getText()); + VeLaPrefs.setDiagnosticMode(veLaDiagnosticCheckbox.isSelected()); + } + + /** + * Prepare this pane for use by resetting whatever needs to be, in particular, + * updating widgets with current preferences. + */ + @Override + public void reset() { + veLaCodeDirectoriesField.setText(VeLaPrefs.getCodeDirs()); + veLaDiagnosticCheckbox.setSelected(VeLaPrefs.getDiagnosticMode()); + } + + // Set defaults action button listener creator. + private ActionListener createSetDefaultsButtonActionListener() { + return new ActionListener() { + public void actionPerformed(ActionEvent e) { + veLaDiagnosticCheckbox.setSelected(Boolean.parseBoolean(VeLaPrefs.DEFAULT_DIAGNOSTIC_MODE_STR)); + veLaCodeDirectoriesField.setText(VeLaPrefs.DEFAULT_CODE_DIR_STR); + } + }; + } + + // Set apply button listener creator. + private ActionListener createApplyButtonActionListener() { + return new ActionListener() { + public void actionPerformed(ActionEvent e) { + update(); + } + }; + } + + /** + * Open file chooser to ask for a code directory to add. + * + * @return An optional directory + */ + private void requestDirToAdd() { + int retVal = veLaCodeDirectoryChooser.showOpenDialog(DocumentManager.findActiveWindow()); + + if (retVal == JFileChooser.APPROVE_OPTION) { + File dir = veLaCodeDirectoryChooser.getSelectedFile(); + + String dirStr = veLaCodeDirectoriesField.getText(); + if (!dirStr.isEmpty()) { + // TODO: perhaps we really want a JList instead with dirList as model + dirStr += "\n"; + } + dirStr += dir.getAbsolutePath(); + veLaCodeDirectoriesField.setText(dirStr); + } + } +} diff --git a/src/org/aavso/tools/vstar/ui/vela/VeLaDialog.java b/src/org/aavso/tools/vstar/ui/vela/VeLaDialog.java index 4395f558..7472a65f 100644 --- a/src/org/aavso/tools/vstar/ui/vela/VeLaDialog.java +++ b/src/org/aavso/tools/vstar/ui/vela/VeLaDialog.java @@ -25,18 +25,18 @@ import java.io.FileOutputStream; import java.io.PrintStream; import java.util.Arrays; -import java.util.Collections; +import java.util.List; import java.util.Optional; import javax.swing.BoxLayout; import javax.swing.JButton; -import javax.swing.JCheckBox; import javax.swing.JPanel; import javax.swing.JTextArea; import org.aavso.tools.vstar.ui.dialog.ITextComponent; import org.aavso.tools.vstar.ui.dialog.MessageBox; import org.aavso.tools.vstar.ui.dialog.TextArea; +import org.aavso.tools.vstar.ui.dialog.TextAreaTabs; import org.aavso.tools.vstar.ui.dialog.TextDialog; import org.aavso.tools.vstar.ui.mediator.Mediator; import org.aavso.tools.vstar.util.Pair; @@ -44,6 +44,7 @@ import org.aavso.tools.vstar.vela.AST; import org.aavso.tools.vstar.vela.Operand; import org.aavso.tools.vstar.vela.VeLaInterpreter; +import org.aavso.tools.vstar.vela.VeLaPrefs; /** * A dialog in which to run VeLa code. @@ -51,41 +52,45 @@ @SuppressWarnings("serial") public class VeLaDialog extends TextDialog { + private static final String tabTextSeparator = "===---==="; + private static ITextComponent codeTextArea; - private static TextArea resultTextArea; - private static JCheckBox verbosityCheckBox; + private static ITextComponent resultTextArea; private static VeLaInterpreter vela; + private static String code = ""; + private String path; - static { - codeTextArea = new TextArea("VeLa Code", "", 12, 42, false, true); + private static List> createTextAreas() { + codeTextArea = new TextArea("VeLa Code", code, 12, 42, false, true); addKeyListener(); - // resultTextArea = new TextAreaTabs(Arrays.asList("Output", "Error", - // "AST", "DOT"), Arrays.asList("", "", "", ""), 15, 70, - // true, true); - // resultTextArea = new TextAreaTabs(Arrays.asList("Output", "Error"), - // Arrays.asList("", ""), 10, 40, true, true); - resultTextArea = new TextArea("Output", "", 12, 42, true, true); + boolean diagnosticMode = VeLaPrefs.getDiagnosticMode(); + + if (diagnosticMode) { + resultTextArea = new TextAreaTabs(Arrays.asList("Output", "LISP AST", "DOT AST"), Arrays.asList("", "", ""), 15, 70, + true, true, tabTextSeparator); + } else { + resultTextArea = new TextArea("Output", "", 12, 42, true, true); + } Font font = codeTextArea.getUIComponent().getFont(); codeTextArea.getUIComponent().setFont(new Font(Font.MONOSPACED, Font.PLAIN, font.getSize())); resultTextArea.getUIComponent().setFont(new Font(Font.MONOSPACED, Font.PLAIN, font.getSize())); - verbosityCheckBox = new JCheckBox("Verbose?"); - verbosityCheckBox.setSelected(false); - verbosityCheckBox.setVisible(false); + return Arrays.asList(codeTextArea, resultTextArea); } public VeLaDialog(String title) { - super(title, Arrays.asList(codeTextArea, resultTextArea), true, true); + super(title, createTextAreas(), true, true); path = "Untitled"; } public VeLaDialog(String title, String code) { this(title); + VeLaDialog.code = code; codeTextArea.setValue(code); } @@ -162,13 +167,17 @@ protected JPanel createButtonPane() { }); panel.add(dismissButton); - panel.add(verbosityCheckBox); - return panel; } // Helpers + @Override + protected void okAction() { + VeLaDialog.code = VeLaDialog.codeTextArea.getValue(); + super.okAction(); + } + private static void addKeyListener() { JTextArea area = (JTextArea) (codeTextArea.getUIComponent()); area.addKeyListener(new KeyAdapter() { @@ -227,7 +236,7 @@ public void keyTyped(KeyEvent e) { } private void execute() { - boolean verbose = verbosityCheckBox.isSelected(); + boolean diagnostic = VeLaPrefs.getDiagnosticMode(); String text = codeTextArea.getValue(); @@ -247,8 +256,7 @@ private void execute() { Mediator.getUI().setScriptingStatus(true); // Compile and execute the code. - vela = new VeLaInterpreter(false, true, Collections.emptyList()); - vela.setVerbose(verbose); + vela = new VeLaInterpreter(VeLaPrefs.getVerboseMode(), true, VeLaPrefs.getCodeDirsList()); Pair, AST> pair = vela.veLaToResultASTPair(text); @@ -256,7 +264,7 @@ private void execute() { if (result.isPresent()) { AST ast = pair.second; - if (verbose && ast != null) { + if (diagnostic && ast != null) { lispAST = ast.toString(); dotAST = ast.toFullDOT(); } @@ -295,15 +303,25 @@ private void execute() { Mediator.getUI().setScriptingStatus(false); } - resultTextArea.setValue(areaTabsPayload(output, error)); + String result = output; + if (!error.isEmpty()) { + result += "\n"; + result += error; + } + + resultTextArea.setValue(areaTabsPayload(VeLaPrefs.getDiagnosticMode(), result, lispAST, dotAST)); } - private String areaTabsPayload(String... strings) { + private String areaTabsPayload(boolean verbose, String... strings) { StringBuffer buf = new StringBuffer(); for (String str : strings) { buf.append(str); - buf.append("\n"); + if (verbose) { + buf.append(tabTextSeparator); + } else { + buf.append("\n"); + } } return buf.toString().trim(); diff --git a/src/org/aavso/tools/vstar/vela/VeLaPrefs.java b/src/org/aavso/tools/vstar/vela/VeLaPrefs.java new file mode 100644 index 00000000..bff90f0d --- /dev/null +++ b/src/org/aavso/tools/vstar/vela/VeLaPrefs.java @@ -0,0 +1,131 @@ +/** + * VStar: a statistical analysis tool for variable star data. + * Copyright (C) 2009 AAVSO (http://www.aavso.org/) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.aavso.tools.vstar.vela; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.prefs.Preferences; + +/** + * VeLa preferences class. + */ +public class VeLaPrefs { + + public final static String DEFAULT_CODE_DIR_STR = ""; + public final static String DEFAULT_DIAGNOSTIC_MODE_STR = "false"; + public final static String DEFAULT_VERBOSE_MODE_STR = "false"; + + private final static String PREFS_PREFIX = "VELA_"; + + private final static String CODE_DIRS = "CODE_DIRS"; + private final static String DIAGNOSTIC_MODE = "DIAGNOSTIC_MODE"; + + private static Preferences prefs; + + private static String codeDirs = DEFAULT_CODE_DIR_STR; + private static Boolean diagnosticMode = Boolean.parseBoolean(DEFAULT_DIAGNOSTIC_MODE_STR); + private static Boolean verboseMode = Boolean.parseBoolean(DEFAULT_VERBOSE_MODE_STR); + static { + // Create preferences node. + try { + prefs = Preferences.userNodeForPackage(VeLaPrefs.class); + } catch (Throwable t) { + // We need VStar to function in the absence of prefs. + } + } + + // Preference value getters + + public static String getCodeDirs() { + loadCodeDirs(); + return codeDirs; + } + + public static void setCodeDirs(String codeDirs) { + VeLaPrefs.codeDirs = codeDirs; + saveCodeDirs(codeDirs); + } + + public static List getCodeDirsList() { + getCodeDirs(); + + String[] dirs = codeDirs.split("\n"); + + List dirList = new ArrayList(); + + for (String dir : dirs) { + dirList.add(new File(dir)); + } + + return dirList; + } + + public static boolean getDiagnosticMode() { + loadDiagnosticMode(); + return diagnosticMode; + } + + public static void setDiagnosticMode(Boolean diagnosticMode) { + VeLaPrefs.diagnosticMode = diagnosticMode; + saveDiagnosticMode(diagnosticMode); + } + + // Note: uncertain that verbose mode is needed, so just stop at getter for now + public static boolean getVerboseMode() { + return verboseMode; + } + + // Preference save/load methods + + public static void saveCodeDirs(String codeDirs) { + try { + prefs.put(PREFS_PREFIX + CODE_DIRS, codeDirs); + } catch (Throwable t) { + // We need VStar to function in the absence of prefs. + } + } + + public static void loadCodeDirs() { + try { + codeDirs = prefs.get(PREFS_PREFIX + CODE_DIRS, DEFAULT_CODE_DIR_STR); + } catch (Throwable t) { + // We need VStar to function in the absence of prefs. + } + } + + public static void saveDiagnosticMode(Boolean diagnosticMode) { + try { + prefs.put(PREFS_PREFIX + DIAGNOSTIC_MODE, diagnosticMode.toString()); + } catch (Throwable t) { + // We need VStar to function in the absence of prefs. + } + } + + public static void loadDiagnosticMode() { + String modeStr = DEFAULT_DIAGNOSTIC_MODE_STR; + + try { + modeStr = prefs.get(PREFS_PREFIX + DIAGNOSTIC_MODE, DEFAULT_DIAGNOSTIC_MODE_STR); + } catch (Throwable t) { + // We need VStar to function in the absence of prefs. + } + + diagnosticMode = Boolean.parseBoolean(modeStr); + } +}