diff options
Diffstat (limited to 'JLanguageTool/src/java/de/danielnaber/languagetool/gui')
8 files changed, 2110 insertions, 0 deletions
diff --git a/JLanguageTool/src/java/de/danielnaber/languagetool/gui/AboutDialog.java b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/AboutDialog.java new file mode 100644 index 0000000..26df4a1 --- /dev/null +++ b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/AboutDialog.java @@ -0,0 +1,58 @@ +/* LanguageTool, a natural language style checker + * Copyright (C) 2007 Daniel Naber (http://www.danielnaber.de) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +package de.danielnaber.languagetool.gui; + +import java.util.ResourceBundle; + +import javax.swing.JOptionPane; + +import de.danielnaber.languagetool.JLanguageTool; +import de.danielnaber.languagetool.Language; +import de.danielnaber.languagetool.tools.StringTools; + +/** + * A dialog with version and copyright information. + * + * @author Daniel Naber + */ +public class AboutDialog { + + protected final ResourceBundle messages; + + public AboutDialog(final ResourceBundle messages) { + this.messages = messages; + } + + public void show() { + final String aboutText = + StringTools.getLabel(messages.getString("guiMenuAbout")); + JOptionPane.showMessageDialog(null, getAboutText(), + aboutText, JOptionPane.INFORMATION_MESSAGE); + } + + protected String getAboutText() { + return "LanguageTool " + JLanguageTool.VERSION + "\n" + + "Copyright (C) 2005-2010 Daniel Naber\n" + + "This software is licensed under the GNU Lesser General Public License.\n" + + "LanguageTool Homepage: http://www.languagetool.org\n\n" + + "Maintainers of the language modules:\n\n" + + Language.getAllMaintainers(messages); + } + +} diff --git a/JLanguageTool/src/java/de/danielnaber/languagetool/gui/Configuration.java b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/Configuration.java new file mode 100644 index 0000000..932e1fe --- /dev/null +++ b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/Configuration.java @@ -0,0 +1,233 @@ +/* LanguageTool, a natural language style checker + * Copyright (C) 2005 Daniel Naber (http://www.danielnaber.de) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +package de.danielnaber.languagetool.gui; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.*; + +import de.danielnaber.languagetool.Language; +import de.danielnaber.languagetool.server.HTTPServer; + +/** + * Configuration -- currently this is just a list of disabled rule IDs. + * Configuration is loaded from and stored to a properties file. + * + * @author Daniel Naber + */ +public class Configuration { + + private static final String CONFIG_FILE = "languagetool.properties"; + private static final String DISABLED_RULES_CONFIG_KEY = "disabledRules"; + private static final String ENABLED_RULES_CONFIG_KEY = "enabledRules"; + private static final String DISABLED_CATEGORIES_CONFIG_KEY = "disabledCategories"; + private static final String MOTHER_TONGUE_CONFIG_KEY = "motherTongue"; + private static final String SERVER_RUN_CONFIG_KEY = "serverMode"; + private static final String SERVER_PORT_CONFIG_KEY = "serverPort"; + + private File configFile; + + private Set<String> disabledRuleIds = new HashSet<String>(); + private Set<String> enabledRuleIds = new HashSet<String>(); + private Set<String> disabledCategoryNames = new HashSet<String>(); + private Language motherTongue; + private boolean runServer; + private int serverPort = HTTPServer.DEFAULT_PORT; + + public Configuration(final File baseDir, final String filename) + throws IOException { + if (!baseDir.isDirectory()) { + throw new IllegalArgumentException("Not a directory: " + baseDir); + } + configFile = new File(baseDir, filename); + loadConfiguration(); + } + + public Configuration(final File baseDir) throws IOException { + this(baseDir, CONFIG_FILE); + } + + public Set<String> getDisabledRuleIds() { + return disabledRuleIds; + } + + public Set<String> getEnabledRuleIds() { + return enabledRuleIds; + } + + public Set<String> getDisabledCategoryNames() { + return disabledCategoryNames; + } + + public void setDisabledRuleIds(final Set<String> ruleIDs) { + disabledRuleIds = ruleIDs; + } + + public void setEnabledRuleIds(final Set<String> ruleIDs) { + enabledRuleIds = ruleIDs; + } + + public void setDisabledCategoryNames(final Set<String> categoryNames) { + disabledCategoryNames = categoryNames; + } + + public Language getMotherTongue() { + return motherTongue; + } + + public void setMotherTongue(final Language motherTongue) { + this.motherTongue = motherTongue; + } + + public boolean getRunServer() { + return runServer; + } + + public void setRunServer(final boolean runServer) { + this.runServer = runServer; + } + + public int getServerPort() { + return serverPort; + } + + public void setServerPort(final int serverPort) { + this.serverPort = serverPort; + } + + private void loadConfiguration() throws IOException { + + // FIXME: disabling a rule X in language Y should not disable it in all + // languages - need to add a language parameter + + FileInputStream fis = null; + try { + fis = new FileInputStream(configFile); + final Properties props = new Properties(); + props.load(fis); + final String val = (String) props.get(DISABLED_RULES_CONFIG_KEY); + if (val != null) { + final String[] ids = val.split(","); + disabledRuleIds.addAll(Arrays.asList(ids)); + } + + final String enRul = (String) props.get(ENABLED_RULES_CONFIG_KEY); + if (enRul != null) { + final String[] ids = enRul.split(","); + enabledRuleIds.addAll(Arrays.asList(ids)); + } + + final String cat = (String) props.get(DISABLED_CATEGORIES_CONFIG_KEY); + if (cat != null) { + final String[] names = cat.split(","); + disabledCategoryNames.addAll(Arrays.asList(names)); + } + + final String motherTongueStr = (String) props + .get(MOTHER_TONGUE_CONFIG_KEY); + if (motherTongueStr != null) { + motherTongue = Language.getLanguageForShortName(motherTongueStr); + } + final String runServerString = (String) props.get(SERVER_RUN_CONFIG_KEY); + if (runServerString != null) { + runServer = runServerString.equals("true"); + } + final String serverPortString = (String) props + .get(SERVER_PORT_CONFIG_KEY); + if (serverPortString != null) { + serverPort = Integer.parseInt(serverPortString); + } + } catch (final FileNotFoundException e) { + // file not found: okay, leave disabledRuleIds empty + } finally { + if (fis != null) { + fis.close(); + } + } + } + + public void saveConfiguration() throws IOException { + final Properties props = new Properties(); + + if (disabledRuleIds == null) { + props.setProperty(DISABLED_RULES_CONFIG_KEY, ""); + } else { + final StringBuilder sb = new StringBuilder(); + for (final Iterator<String> iter = disabledRuleIds.iterator(); iter + .hasNext();) { + final String id = iter.next(); + sb.append(id); + if (iter.hasNext()) { + sb.append(','); + } + } + props.setProperty(DISABLED_RULES_CONFIG_KEY, sb.toString()); + } + + if (enabledRuleIds == null) { + props.setProperty(ENABLED_RULES_CONFIG_KEY, ""); + } else { + final StringBuilder sb = new StringBuilder(); + for (final Iterator<String> iter = enabledRuleIds.iterator(); iter.hasNext();) { + final String id = iter.next(); + sb.append(id); + if (iter.hasNext()) { + sb.append(','); + } + } + props.setProperty(ENABLED_RULES_CONFIG_KEY, sb.toString()); + } + + if (disabledCategoryNames == null) { + props.setProperty(DISABLED_CATEGORIES_CONFIG_KEY, ""); + } else { + final StringBuilder sb = new StringBuilder(); + for (final Iterator<String> iter = disabledCategoryNames.iterator(); iter + .hasNext();) { + final String name = iter.next(); + sb.append(name); + if (iter.hasNext()) { + sb.append(','); + } + } + props.setProperty(DISABLED_CATEGORIES_CONFIG_KEY, sb.toString()); + } + + if (motherTongue != null) { + props.setProperty(MOTHER_TONGUE_CONFIG_KEY, motherTongue.getShortName()); + } + props.setProperty(SERVER_RUN_CONFIG_KEY, Boolean.valueOf(runServer) + .toString()); + props.setProperty(SERVER_PORT_CONFIG_KEY, Integer.valueOf(serverPort) + .toString()); + FileOutputStream fos = null; + try { + fos = new FileOutputStream(configFile); + props.store(fos, "LanguageTool configuration"); + } finally { + if (fos != null) { + fos.close(); + } + } + } + +} diff --git a/JLanguageTool/src/java/de/danielnaber/languagetool/gui/ConfigurationDialog.java b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/ConfigurationDialog.java new file mode 100644 index 0000000..d78ea08 --- /dev/null +++ b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/ConfigurationDialog.java @@ -0,0 +1,497 @@ +/* LanguageTool, a natural language style checker + * Copyright (C) 2005 Daniel Naber (http://www.danielnaber.de) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +package de.danielnaber.languagetool.gui; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.ResourceBundle; +import java.util.Set; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRootPane; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.KeyStroke; + +import de.danielnaber.languagetool.JLanguageTool; +import de.danielnaber.languagetool.Language; +import de.danielnaber.languagetool.rules.Rule; +import de.danielnaber.languagetool.server.HTTPServer; +import de.danielnaber.languagetool.tools.StringTools; + +/** + * Dialog that offers the available rules so they can be turned on/off + * individually. + * + * @author Daniel Naber + */ +public class ConfigurationDialog implements ActionListener { + + private static final String NO_MOTHER_TONGUE = "---"; + + private JButton okButton; + private JButton cancelButton; + + private final ResourceBundle messages; + private JDialog dialog; + + private JComboBox motherTongueBox; + + private JCheckBox serverCheckbox; + private JTextField serverPortField; + + private final List<JCheckBox> checkBoxes = new ArrayList<JCheckBox>(); + private final List<String> checkBoxesRuleIds = new ArrayList<String>(); + private final List<String> checkBoxesCategories = new ArrayList<String>(); + + private final List<String> defaultOffRules = new ArrayList<String>(); + + private Set<String> inactiveRuleIds = new HashSet<String>(); + private Set<String> enabledRuleIds = new HashSet<String>(); + private Set<String> inactiveCategoryNames = new HashSet<String>(); + private final List<JCheckBox> categoryCheckBoxes = new ArrayList<JCheckBox>(); + private final List<String> checkBoxesCategoryNames = new ArrayList<String>(); + private Language motherTongue; + private boolean serverMode; + private int serverPort; + + private final Frame owner; + private final boolean insideOOo; + + public ConfigurationDialog(Frame owner, boolean insideOOo) { + this.owner = owner; + this.insideOOo = insideOOo; + messages = JLanguageTool.getMessageBundle(); + } + + public void show(List<Rule> rules) { + dialog = new JDialog(owner, true); + dialog.setTitle(messages.getString("guiConfigWindowTitle")); + checkBoxes.clear(); + checkBoxesRuleIds.clear(); + categoryCheckBoxes.clear(); + checkBoxesCategoryNames.clear(); + + Collections.sort(rules, new CategoryComparator()); + + // close dialog when user presses Escape key: + final KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); + final ActionListener actionListener = new ActionListener() { + public void actionPerformed(@SuppressWarnings("unused") ActionEvent actionEvent) { + dialog.setVisible(false); + } + }; + final JRootPane rootPane = dialog.getRootPane(); + rootPane.registerKeyboardAction(actionListener, stroke, + JComponent.WHEN_IN_FOCUSED_WINDOW); + + // JPanel + final JPanel checkBoxPanel = new JPanel(); + checkBoxPanel.setLayout(new GridBagLayout()); + GridBagConstraints cons = new GridBagConstraints(); + cons.anchor = GridBagConstraints.NORTHWEST; + cons.gridx = 0; + int row = 0; + String prevID = null; + String prevCategory = null; + for (final Rule rule : rules) { + // avoid displaying rules from rule groups more than once: + if (prevID == null || !rule.getId().equals(prevID)) { + cons.gridy = row; + final JCheckBox checkBox = new JCheckBox(rule.getDescription()); + if (inactiveRuleIds != null + && (inactiveRuleIds.contains(rule.getId()) || inactiveCategoryNames + .contains(rule.getCategory().getName()))) { + checkBox.setSelected(false); + } else { + checkBox.setSelected(true); + } + + if (rule.isDefaultOff() && !enabledRuleIds.contains(rule.getId())) { + checkBox.setSelected(false); + } + + if (rule.isDefaultOff()) { + defaultOffRules.add(rule.getId()); + if (rule.getCategory().isDefaultOff()) { + inactiveCategoryNames.add(rule.getCategory().getName()); + } + } else { + if (rule.getCategory().isDefaultOff()) { + inactiveCategoryNames.remove(rule.getCategory().getName()); + } + } + + final ActionListener ruleCheckBoxListener = new ActionListener() { + public void actionPerformed(final ActionEvent actionEvent) { + final JCheckBox cBox = (JCheckBox) actionEvent.getSource(); + final boolean selected = cBox.getModel().isSelected(); + int i = 0; + for (final JCheckBox chBox : checkBoxes) { + if (chBox.equals(cBox)) { + final int catNo = checkBoxesCategoryNames + .indexOf(checkBoxesCategories.get(i)); + if (selected && !categoryCheckBoxes.get(catNo).isSelected()) { + categoryCheckBoxes.get(catNo).setSelected(true); + } + } + i++; + } + } + }; + checkBox.addActionListener(ruleCheckBoxListener); + checkBoxes.add(checkBox); + checkBoxesRuleIds.add(rule.getId()); + checkBoxesCategories.add(rule.getCategory().getName()); + final boolean showHeadline = rule.getCategory() != null + && !rule.getCategory().getName().equals(prevCategory); + if ((showHeadline || prevCategory == null) + && rule.getCategory() != null) { + + // TODO: maybe use a Tree of Checkboxes here, like in: + // http://www.javaworld.com/javaworld/jw-09-2007/jw-09-checkboxtree.html + final JCheckBox categoryCheckBox = new JCheckBox(rule.getCategory() + .getName()); + if (inactiveCategoryNames != null + && inactiveCategoryNames.contains(rule.getCategory().getName())) { + categoryCheckBox.setSelected(false); + } else { + categoryCheckBox.setSelected(true); + } + + final ActionListener categoryCheckBoxListener = new ActionListener() { + public void actionPerformed(final ActionEvent actionEvent) { + final JCheckBox cBox = (JCheckBox) actionEvent.getSource(); + final boolean selected = cBox.getModel().isSelected(); + int i = 0; + for (final JCheckBox ruleBox : checkBoxes) { + if (ruleBox.isSelected() != selected) { + if (checkBoxesCategories.get(i).equals(cBox.getText())) { + ruleBox.setSelected(selected); + } + } + i++; + } + } + }; + + categoryCheckBox.addActionListener(categoryCheckBoxListener); + categoryCheckBoxes.add(categoryCheckBox); + checkBoxesCategoryNames.add(rule.getCategory().getName()); + checkBoxPanel.add(categoryCheckBox, cons); + prevCategory = rule.getCategory().getName(); + cons.gridy++; + row++; + } + checkBox.setMargin(new Insets(0, 20, 0, 0)); // indent + checkBoxPanel.add(checkBox, cons); + row++; + } + prevID = rule.getId(); + } + + final JPanel motherTonguePanel = new JPanel(); + motherTonguePanel.add(new JLabel(messages.getString("guiMotherTongue")), + cons); + motherTongueBox = new JComboBox(getPossibleMotherTongues()); + if (motherTongue != null) { + if (motherTongue == Language.DEMO) { + motherTongueBox.setSelectedItem(NO_MOTHER_TONGUE); + } else { + motherTongueBox.setSelectedItem(messages.getString(motherTongue + .getShortName())); + } + } + motherTonguePanel.add(motherTongueBox, cons); + + final JPanel portPanel = new JPanel(); + portPanel.setLayout(new GridBagLayout()); + // TODO: why is this now left-aligned?!?! + cons = new GridBagConstraints(); + cons.insets = new Insets(0, 4, 0, 0); + cons.gridx = 0; + cons.gridy = 0; + cons.anchor = GridBagConstraints.WEST; + cons.fill = GridBagConstraints.NONE; + cons.weightx = 0.0f; + if (!insideOOo) { + serverCheckbox = new JCheckBox(StringTools.getLabel(messages + .getString("guiRunOnPort"))); + serverCheckbox.setMnemonic(StringTools.getMnemonic(messages + .getString("guiRunOnPort"))); + serverCheckbox.setSelected(serverMode); + portPanel.add(serverCheckbox, cons); + serverPortField = new JTextField(Integer.toString(serverPort)); + serverPortField.setEnabled(serverCheckbox.isSelected()); + // TODO: without this the box is just a few pixels small, but why??: + serverPortField.setMinimumSize(new Dimension(100, 25)); + cons.gridx = 1; + serverCheckbox.addActionListener(new ActionListener() { + public void actionPerformed(@SuppressWarnings("unused") ActionEvent e) { + serverPortField.setEnabled(serverCheckbox.isSelected()); + } + }); + portPanel.add(serverPortField, cons); + } + + final JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new GridBagLayout()); + okButton = new JButton(StringTools.getLabel(messages + .getString("guiOKButton"))); + okButton.setMnemonic(StringTools.getMnemonic(messages + .getString("guiOKButton"))); + okButton.addActionListener(this); + cancelButton = new JButton(StringTools.getLabel(messages + .getString("guiCancelButton"))); + cancelButton.setMnemonic(StringTools.getMnemonic(messages + .getString("guiCancelButton"))); + cancelButton.addActionListener(this); + cons = new GridBagConstraints(); + cons.insets = new Insets(0, 4, 0, 0); + buttonPanel.add(okButton, cons); + buttonPanel.add(cancelButton, cons); + + final Container contentPane = dialog.getContentPane(); + contentPane.setLayout(new GridBagLayout()); + cons = new GridBagConstraints(); + cons.insets = new Insets(4, 4, 4, 4); + cons.gridx = 0; + cons.gridy = 0; + cons.weightx = 10.0f; + cons.weighty = 10.0f; + cons.fill = GridBagConstraints.BOTH; + contentPane.add(new JScrollPane(checkBoxPanel), cons); + + cons.gridx = 0; + cons.gridy = 1; + cons.weightx = 0.0f; + cons.weighty = 0.0f; + cons.fill = GridBagConstraints.NONE; + cons.anchor = GridBagConstraints.WEST; + contentPane.add(motherTonguePanel, cons); + + cons.gridx = 0; + cons.gridy = 2; + cons.weightx = 0.0f; + cons.weighty = 0.0f; + cons.fill = GridBagConstraints.NONE; + cons.anchor = GridBagConstraints.WEST; + contentPane.add(portPanel, cons); + + cons.gridx = 0; + cons.gridy = 3; + cons.weightx = 0.0f; + cons.weighty = 0.0f; + cons.fill = GridBagConstraints.NONE; + cons.anchor = GridBagConstraints.EAST; + contentPane.add(buttonPanel, cons); + + dialog.pack(); + dialog.setSize(500, 500); + // center on screen: + final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + final Dimension frameSize = dialog.getSize(); + dialog.setLocation(screenSize.width / 2 - frameSize.width / 2, + screenSize.height / 2 - frameSize.height / 2); + dialog.setVisible(true); + } + + private Object[] getPossibleMotherTongues() { + final List<Object> motherTongues = new ArrayList<Object>(); + motherTongues.add(NO_MOTHER_TONGUE); + for (final Language lang : Language.LANGUAGES) { + if (lang != Language.DEMO) { + motherTongues.add(messages.getString(lang.getShortName())); + } + } + return motherTongues.toArray(); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == okButton) { + int i = 0; + inactiveCategoryNames.clear(); + for (final JCheckBox checkBox : categoryCheckBoxes) { + if (!checkBox.isSelected()) { + final String categoryName = checkBoxesCategoryNames.get(i); + inactiveCategoryNames.add(categoryName); + } + i++; + } + i = 0; + inactiveRuleIds.clear(); + enabledRuleIds.clear(); + for (final JCheckBox checkBox : checkBoxes) { + if (!checkBox.isSelected()) { + final String ruleId = checkBoxesRuleIds.get(i); + if (!defaultOffRules.contains(ruleId)) { + inactiveRuleIds.add(ruleId); + } + } + + if (checkBox.isSelected()) { + final String ruleId = checkBoxesRuleIds.get(i); + if (defaultOffRules.contains(ruleId)) { + enabledRuleIds.add(ruleId); + } + } + + i++; + } + + if (motherTongueBox.getSelectedItem() instanceof String) { + motherTongue = getLanguageForLocalizedName(motherTongueBox + .getSelectedItem().toString()); + } else { + motherTongue = (Language) motherTongueBox.getSelectedItem(); + } + if (serverCheckbox != null) { + serverMode = serverCheckbox.isSelected(); + serverPort = Integer.parseInt(serverPortField.getText()); + } + dialog.setVisible(false); + } else if (e.getSource() == cancelButton) { + dialog.setVisible(false); + } + } + + public void setDisabledRules(Set<String> ruleIDs) { + inactiveRuleIds = ruleIDs; + } + + public Set<String> getDisabledRuleIds() { + return inactiveRuleIds; + } + + public void setEnabledRules(Set<String> ruleIDs) { + enabledRuleIds = ruleIDs; + } + + public Set<String> getEnabledRuleIds() { + return enabledRuleIds; + } + + public void setDisabledCategories(Set<String> categoryNames) { + inactiveCategoryNames = categoryNames; + } + + public Set<String> getDisabledCategoryNames() { + return inactiveCategoryNames; + } + + public void setMotherTongue(Language motherTongue) { + this.motherTongue = motherTongue; + } + + public Language getMotherTongue() { + return motherTongue; + } + + /** + * Get the Language object for the given localized language name. + * + * @param languageName + * e.g. <code>English</code> or <code>German</code> (case is + * significant) + * @return a Language object or <code>null</code> + */ + private Language getLanguageForLocalizedName(final String languageName) { + for (final Language element : Language.LANGUAGES) { + if (NO_MOTHER_TONGUE.equals(languageName)) { + return Language.DEMO; + } + if (languageName.equals(messages.getString(element.getShortName()))) { + return element; + } + } + return null; + } + + public void setRunServer(boolean serverMode) { + this.serverMode = serverMode; + } + + public boolean getRunServer() { + if (serverCheckbox == null) { + return false; + } + return serverCheckbox.isSelected(); + } + + public void setServerPort(int serverPort) { + this.serverPort = serverPort; + } + + public int getServerPort() { + if (serverPortField == null) { + return HTTPServer.DEFAULT_PORT; + } + return Integer.parseInt(serverPortField.getText()); + } + + /** + * Opens the dialog - for internal testing only. + */ + public static void main(String[] args) throws IOException { + final ConfigurationDialog dlg = new ConfigurationDialog(null, false); + final List<Rule> rules = new ArrayList<Rule>(); + final JLanguageTool lt = new JLanguageTool(Language.ENGLISH); + lt.activateDefaultPatternRules(); + rules.addAll(lt.getAllRules()); + dlg.show(rules); + } + +} + +class CategoryComparator implements Comparator<Rule> { + + public int compare(final Rule r1, final Rule r2) { + final boolean hasCat = r1.getCategory() != null && r2.getCategory() != null; + if (hasCat) { + final int res = r1.getCategory().getName().compareTo( + r2.getCategory().getName()); + if (res == 0) { + return r1.getDescription().compareToIgnoreCase(r2.getDescription()); + } + return res; + } + return r1.getDescription().compareToIgnoreCase(r2.getDescription()); + } + +} diff --git a/JLanguageTool/src/java/de/danielnaber/languagetool/gui/LanguageManagerDialog.java b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/LanguageManagerDialog.java new file mode 100644 index 0000000..18c5b26 --- /dev/null +++ b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/LanguageManagerDialog.java @@ -0,0 +1,184 @@ +/* LanguageTool, a natural language style checker + * Copyright (C) 2007 Daniel Naber (http://www.danielnaber.de) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +package de.danielnaber.languagetool.gui; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JRootPane; +import javax.swing.JScrollPane; +import javax.swing.KeyStroke; +import javax.swing.filechooser.FileFilter; + +import de.danielnaber.languagetool.Language; +import de.danielnaber.languagetool.language.LanguageBuilder; + +/** + * Dialog for managing externally loaded rules. + * + * @author Daniel Naber + */ +public class LanguageManagerDialog implements ActionListener { + + private JDialog dialog; + + private JList list; + private JButton addButton; + private JButton removeButton; + private JButton closeButton; + private final List<File> ruleFiles = new ArrayList<File>(); + + private final Frame owner; + //private ResourceBundle messages = null; + + public LanguageManagerDialog(Frame owner, List<Language> languages) { + this.owner = owner; + for (Language lang : languages) { + ruleFiles.add(new File(lang.getRuleFileName())); + } + //messages = JLanguageTool.getMessageBundle(); + } + + public void show() { + dialog = new JDialog(owner, true); + dialog.setTitle("Language Module Manager"); // FIXME: i18n + + // close dialog when user presses Escape key: + // TODO: taken from ConfigurationDialog, avoid duplication: + final KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); + final ActionListener actionListener = new ActionListener() { + @SuppressWarnings("unused") + public void actionPerformed(ActionEvent actionEvent) { + dialog.setVisible(false); + } + }; + final JRootPane rootPane = dialog.getRootPane(); + rootPane.registerKeyboardAction(actionListener, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW); + + final Container contentPane = dialog.getContentPane(); + contentPane.setLayout(new GridBagLayout()); + + list = new JList(ruleFiles.toArray(new File[]{})); + GridBagConstraints cons = new GridBagConstraints(); + cons.insets = new Insets(4, 4, 4, 4); + cons.gridx = 0; + cons.gridy = 0; + cons.fill = GridBagConstraints.BOTH; + cons.weightx = 2.0f; + cons.weighty = 2.0f; + contentPane.add(new JScrollPane(list), cons); + + cons = new GridBagConstraints(); + cons.insets = new Insets(4, 4, 4, 4); + cons.fill = GridBagConstraints.HORIZONTAL; + + final JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new GridBagLayout()); + addButton = new JButton("Add..."); // FIXME: i18n + addButton.addActionListener(this); + cons.gridx = 1; + cons.gridy = 0; + buttonPanel.add(addButton, cons); + + removeButton = new JButton("Remove"); // FIXME: i18n + removeButton.addActionListener(this); + cons.gridx = 1; + cons.gridy = 1; + buttonPanel.add(removeButton, cons); + + closeButton = new JButton("Close"); // FIXME: i18n + closeButton.addActionListener(this); + cons.gridx = 1; + cons.gridy = 2; + buttonPanel.add(closeButton, cons); + + cons.gridx = 1; + cons.gridy = 0; + cons = new GridBagConstraints(); + cons.anchor = GridBagConstraints.NORTH; + contentPane.add(buttonPanel, cons); + + dialog.pack(); + dialog.setSize(300, 200); + // center on screen: + final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + final Dimension frameSize = dialog.getSize(); + dialog.setLocation(screenSize.width/2 - (frameSize.width/2), screenSize.height/2 - (frameSize.height/2)); + dialog.setVisible(true); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == addButton) { + final File ruleFile = Tools.openFileDialog(null, new XMLFileFilter()); + // TODO: avoid duplicate files! + ruleFiles.add(ruleFile); + list.setListData(ruleFiles.toArray(new File[]{})); + } else if (e.getSource() == removeButton) { + if (list.getSelectedIndex() != -1) { + ruleFiles.remove(list.getSelectedIndex()); + list.setListData(ruleFiles.toArray(new File[]{})); + } + } else if (e.getSource() == closeButton) { + dialog.setVisible(false); + } else { + throw new IllegalArgumentException("Don't know how to handle " + e); + } + } + + /** + * Return all external Languages. + */ + List<Language> getLanguages() { + final List<Language> languages = new ArrayList<Language>(); + for (File ruleFile : ruleFiles) { + final Language newLanguage = LanguageBuilder.makeLanguage(ruleFile); + languages.add(newLanguage); + } + return languages; + } + + static class XMLFileFilter extends FileFilter { + public boolean accept(final File f) { + if (f.getName().toLowerCase().endsWith(".xml") || f.isDirectory()) { + return true; + } + return false; + } + public String getDescription() { + return "*.xml"; + } + } + +} diff --git a/JLanguageTool/src/java/de/danielnaber/languagetool/gui/Main.java b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/Main.java new file mode 100644 index 0000000..eb73813 --- /dev/null +++ b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/Main.java @@ -0,0 +1,738 @@ +/* LanguageTool, a natural language style checker + * Copyright (C) 2005 Daniel Naber (http://www.danielnaber.de) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +package de.danielnaber.languagetool.gui; + +import java.awt.AWTException; +import java.awt.Container; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Image; +import java.awt.Insets; +import java.awt.MenuItem; +import java.awt.PopupMenu; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.Set; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTextArea; +import javax.swing.JTextPane; +import javax.swing.UIManager; +import javax.swing.WindowConstants; +import javax.swing.filechooser.FileFilter; +import javax.xml.parsers.ParserConfigurationException; + +import org.jdesktop.jdic.tray.SystemTray; +import org.jdesktop.jdic.tray.TrayIcon; +import org.xml.sax.SAXException; + +import de.danielnaber.languagetool.JLanguageTool; +import de.danielnaber.languagetool.Language; +import de.danielnaber.languagetool.language.RuleFilenameException; +import de.danielnaber.languagetool.rules.Rule; +import de.danielnaber.languagetool.rules.RuleMatch; +import de.danielnaber.languagetool.server.HTTPServer; +import de.danielnaber.languagetool.server.PortBindingException; +import de.danielnaber.languagetool.tools.StringTools; + +/** + * A simple GUI to check texts with. + * + * @author Daniel Naber + */ +public final class Main implements ActionListener { + + private final ResourceBundle messages; + + private static final String HTML_FONT_START = "<font face='Arial,Helvetica'>"; + private static final String HTML_FONT_END = "</font>"; + + private final static String SYSTEM_TRAY_ICON_NAME = "/TrayIcon.png"; + private static final String SYSTEM_TRAY_TOOLTIP = "LanguageTool"; + private static final String CONFIG_FILE = ".languagetool.cfg"; + + private final Configuration config; + + private JFrame frame; + private JTextArea textArea; + private JTextPane resultArea; + private JComboBox langBox; + + private HTTPServer httpServer; + + private final Map<Language, ConfigurationDialog> configDialogs = new HashMap<Language, ConfigurationDialog>(); + + // whether clicking on the window close button hides to system tray: + private boolean trayMode; + + private boolean isInTray; + + private Main() throws IOException { + config = new Configuration(new File(System.getProperty("user.home")), + CONFIG_FILE); + messages = JLanguageTool.getMessageBundle(); + maybeStartServer(); + } + + private void createGUI() { + frame = new JFrame("LanguageTool " + JLanguageTool.VERSION); + + try { + for (UIManager.LookAndFeelInfo info : UIManager + .getInstalledLookAndFeels()) { + if ("Nimbus".equals(info.getName())) { + UIManager.setLookAndFeel(info.getClassName()); + break; + } + } + } catch (Exception ex) { + // Well, what can we do... + } + + frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frame.addWindowListener(new CloseListener()); + frame.setIconImage(new ImageIcon(JLanguageTool.getDataBroker().getFromResourceDirAsUrl( + Main.SYSTEM_TRAY_ICON_NAME)).getImage()); + frame.setJMenuBar(new MainMenuBar(this, messages)); + + textArea = new JTextArea(messages.getString("guiDemoText")); + // TODO: wrong line number is displayed for lines that are wrapped + // automatically: + textArea.setLineWrap(true); + textArea.setWrapStyleWord(true); + resultArea = new JTextPane(); + resultArea.setContentType("text/html"); + resultArea.setText(HTML_FONT_START + messages.getString("resultAreaText") + + HTML_FONT_END); + resultArea.setEditable(false); + final JLabel label = new JLabel(messages.getString("enterText")); + final JButton button = new JButton(StringTools.getLabel(messages + .getString("checkText"))); + button + .setMnemonic(StringTools.getMnemonic(messages.getString("checkText"))); + button.addActionListener(this); + + final JPanel panel = new JPanel(); + panel.setLayout(new GridBagLayout()); + final GridBagConstraints buttonCons = new GridBagConstraints(); + buttonCons.gridx = 0; + buttonCons.gridy = 0; + panel.add(button, buttonCons); + buttonCons.gridx = 1; + buttonCons.gridy = 0; + panel.add(new JLabel(" " + messages.getString("textLanguage") + " "), + buttonCons); + buttonCons.gridx = 2; + buttonCons.gridy = 0; + langBox = new JComboBox(); + populateLanguageBox(); + // use the system default language to preselect the language from the combo + // box: + try { + final Locale defaultLocale = Locale.getDefault(); + langBox.setSelectedItem(messages.getString(defaultLocale.getLanguage())); + } catch (final MissingResourceException e) { + // language not supported, so don't select a default + } + panel.add(langBox, buttonCons); + + final Container contentPane = frame.getContentPane(); + final GridBagLayout gridLayout = new GridBagLayout(); + contentPane.setLayout(gridLayout); + final GridBagConstraints cons = new GridBagConstraints(); + cons.insets = new Insets(5, 5, 5, 5); + cons.fill = GridBagConstraints.BOTH; + cons.weightx = 10.0f; + cons.weighty = 10.0f; + cons.gridx = 0; + cons.gridy = 1; + cons.weighty = 5.0f; + final JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, + new JScrollPane(textArea), new JScrollPane(resultArea)); + splitPane.setDividerLocation(200); + contentPane.add(splitPane, cons); + + cons.fill = GridBagConstraints.NONE; + cons.gridx = 0; + cons.gridy = 2; + cons.weighty = 0.0f; + cons.insets = new Insets(3, 3, 3, 3); + // cons.fill = GridBagConstraints.NONE; + contentPane.add(label, cons); + cons.gridy = 3; + contentPane.add(panel, cons); + + frame.pack(); + frame.setSize(600, 550); + } + + private void populateLanguageBox() { + final List<String> toSort = new ArrayList<String>(); + langBox.removeAllItems(); + for (final Language lang : Language.LANGUAGES) { + if (lang != Language.DEMO) { + try { + toSort.add(messages.getString(lang.getShortName())); + } catch (final MissingResourceException e) { + // can happen with external rules: + toSort.add(lang.getName()); + } + } + } + Collections.sort(toSort); + for (final String lng : toSort) { + langBox.addItem(lng); + } + } + + private void showGUI() { + frame.setVisible(true); + } + + public void actionPerformed(final ActionEvent e) { + try { + if (e.getActionCommand().equals( + StringTools.getLabel(messages.getString("checkText")))) { + final JLanguageTool langTool = getCurrentLanguageTool(); + checkTextAndDisplayResults(langTool, getCurrentLanguage()); + } else { + throw new IllegalArgumentException("Unknown action " + e); + } + } catch (final Exception exc) { + Tools.showError(exc); + } + } + + void loadFile() { + final File file = Tools.openFileDialog(frame, new PlainTextFilter()); + if (file == null) { + return; + } + try { + final String fileContents = StringTools.readFile(new FileInputStream(file + .getAbsolutePath())); + textArea.setText(fileContents); + final JLanguageTool langTool = getCurrentLanguageTool(); + checkTextAndDisplayResults(langTool, getCurrentLanguage()); + } catch (final IOException e) { + Tools.showError(e); + } + } + + void hideToTray() { + final String version = System.getProperty("java.version"); + if (!isInTray && version.startsWith("1.5")) { // we don't run under <= 1.4, + // so we don't check for that + TrayIcon trayIcon = null; + try { + final Icon sysTrayIcon = new ImageIcon(JLanguageTool.getDataBroker().getFromResourceDirAsUrl(Main.SYSTEM_TRAY_ICON_NAME)); + trayIcon = new TrayIcon(sysTrayIcon); + } catch (final NoClassDefFoundError e) { + throw new MissingJdicException(e); + } + final SystemTray tray = SystemTray.getDefaultSystemTray(); + trayIcon.addActionListener(new TrayActionListener()); + trayIcon.setToolTip(SYSTEM_TRAY_TOOLTIP); + tray.addTrayIcon(trayIcon); + } else if (!isInTray) { + // Java 1.6 or later + final java.awt.SystemTray tray = java.awt.SystemTray.getSystemTray(); + final Image img = Toolkit.getDefaultToolkit().getImage( + JLanguageTool.getDataBroker().getFromResourceDirAsUrl(Main.SYSTEM_TRAY_ICON_NAME)); + final PopupMenu popup = makePopupMenu(); + try { + final java.awt.TrayIcon trayIcon = new java.awt.TrayIcon(img, + "tooltip", popup); + trayIcon.addMouseListener(new TrayActionListener()); + trayIcon.setToolTip(SYSTEM_TRAY_TOOLTIP); + tray.add(trayIcon); + } catch (final AWTException e1) { + // thrown if there's no system tray + Tools.showError(e1); + } + } + isInTray = true; + frame.setVisible(false); + } + + private PopupMenu makePopupMenu() { + final PopupMenu popup = new PopupMenu(); + final ActionListener rmbListener = new TrayActionRMBListener(); + // Check clipboard text: + final MenuItem checkClipboardItem = new MenuItem(StringTools + .getLabel(messages.getString("guiMenuCheckClipboard"))); + checkClipboardItem.addActionListener(rmbListener); + popup.add(checkClipboardItem); + // Open main window: + final MenuItem restoreItem = new MenuItem(StringTools.getLabel(messages + .getString("guiMenuShowMainWindow"))); + restoreItem.addActionListener(rmbListener); + popup.add(restoreItem); + // Exit: + final MenuItem exitItem = new MenuItem(StringTools.getLabel(messages + .getString("guiMenuQuit"))); + exitItem.addActionListener(rmbListener); + popup.add(exitItem); + return popup; + } + + void addLanguage() { + final LanguageManagerDialog lmd = new LanguageManagerDialog(frame, Language + .getExternalLanguages()); + lmd.show(); + try { + Language.reInit(lmd.getLanguages()); + } catch (final RuleFilenameException e) { + Tools.showErrorMessage(e); + } + populateLanguageBox(); + } + + void showOptions() { + final JLanguageTool langTool = getCurrentLanguageTool(); + final List<Rule> rules = langTool.getAllRules(); + final ConfigurationDialog configDialog = getCurrentConfigDialog(); + configDialog.show(rules); // this blocks until OK/Cancel is clicked in the + // dialog + config.setDisabledRuleIds(configDialog.getDisabledRuleIds()); + config.setEnabledRuleIds(configDialog.getEnabledRuleIds()); + config.setDisabledCategoryNames(configDialog.getDisabledCategoryNames()); + config.setMotherTongue(configDialog.getMotherTongue()); + config.setRunServer(configDialog.getRunServer()); + config.setServerPort(configDialog.getServerPort()); + // Stop server, start new server if requested: + stopServer(); + maybeStartServer(); + } + + private void restoreFromTray() { + frame.setVisible(true); + } + + // show GUI and check the text from clipboard/selection: + private void restoreFromTrayAndCheck() { + final String s = getClipboardText(); + restoreFromTray(); + textArea.setText(s); + final JLanguageTool langTool = getCurrentLanguageTool(); + checkTextAndDisplayResults(langTool, getCurrentLanguage()); + } + + void checkClipboardText() { + final String s = getClipboardText(); + textArea.setText(s); + final JLanguageTool langTool = getCurrentLanguageTool(); + checkTextAndDisplayResults(langTool, getCurrentLanguage()); + } + + private String getClipboardText() { + // get text from clipboard or selection: + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemSelection(); + if (clipboard == null) { // on Windows + clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + } + String s = null; + final Transferable data = clipboard.getContents(this); + try { + if (data != null + && data.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor())) { + final DataFlavor df = DataFlavor.getTextPlainUnicodeFlavor(); + final Reader sr = df.getReaderForText(data); + s = StringTools.readerToString(sr); + } else { + s = ""; + } + } catch (final Exception ex) { + ex.printStackTrace(); + if (data != null) { + s = data.toString(); + } else { + s = ""; + } + } + return s; + } + + void quitOrHide() { + if (trayMode) { + hideToTray(); + } else { + quit(); + } + } + + void quit() { + stopServer(); + try { + config.saveConfiguration(); + } catch (final IOException e) { + Tools.showError(e); + } + frame.setVisible(false); + System.exit(0); + } + + private void maybeStartServer() { + if (config.getRunServer()) { + httpServer = new HTTPServer(config.getServerPort()); + try { + httpServer.run(); + } catch (final PortBindingException e) { + JOptionPane.showMessageDialog(null, e.getMessage(), "Error", + JOptionPane.ERROR_MESSAGE); + } + } + } + + private void stopServer() { + if (httpServer != null) { + httpServer.stop(); + httpServer = null; + } + } + + private Language getCurrentLanguage() { + final String langName = langBox.getSelectedItem().toString(); + String lang = langName; + for (final Enumeration<String> e = messages.getKeys(); e.hasMoreElements();) { + final String elem = e.nextElement(); + if (messages.getString(elem).equals(langName)) { + lang = elem; + break; + } + } + // external rules: + if (lang.length() > 2) { + return Language.getLanguageForName(lang); + } + return Language.getLanguageForShortName(lang); + } + + private ConfigurationDialog getCurrentConfigDialog() { + final Language language = getCurrentLanguage(); + ConfigurationDialog configDialog = null; + if (configDialogs.containsKey(language)) { + configDialog = configDialogs.get(language); + } else { + configDialog = new ConfigurationDialog(frame, false); + configDialog.setMotherTongue(config.getMotherTongue()); + configDialog.setDisabledRules(config.getDisabledRuleIds()); + configDialog.setEnabledRules(config.getEnabledRuleIds()); + configDialog.setDisabledCategories(config.getDisabledCategoryNames()); + configDialog.setRunServer(config.getRunServer()); + configDialog.setServerPort(config.getServerPort()); + configDialogs.put(language, configDialog); + } + return configDialog; + } + + private JLanguageTool getCurrentLanguageTool() { + final JLanguageTool langTool; + try { + final ConfigurationDialog configDialog = getCurrentConfigDialog(); + langTool = new JLanguageTool(getCurrentLanguage(), configDialog + .getMotherTongue()); + langTool.activateDefaultPatternRules(); + langTool.activateDefaultFalseFriendRules(); + final Set<String> disabledRules = configDialog.getDisabledRuleIds(); + if (disabledRules != null) { + for (final String ruleId : disabledRules) { + langTool.disableRule(ruleId); + } + } + final Set<String> disabledCategories = configDialog + .getDisabledCategoryNames(); + if (disabledCategories != null) { + for (final String categoryName : disabledCategories) { + langTool.disableCategory(categoryName); + } + } + final Set<String> enabledRules = configDialog.getEnabledRuleIds(); + if (enabledRules != null) { + for (String ruleName : enabledRules) { + langTool.enableDefaultOffRule(ruleName); + langTool.enableRule(ruleName); + } + } + } catch (final IOException ioe) { + throw new RuntimeException(ioe); + } catch (final ParserConfigurationException ex) { + throw new RuntimeException(ex); + } catch (final SAXException ex) { + throw new RuntimeException(ex); + } + return langTool; + } + + private void checkTextAndDisplayResults(final JLanguageTool langTool, + final Language lang) { + if (StringTools.isEmpty(textArea.getText().trim())) { + textArea.setText(messages.getString("enterText2")); + } else { + final StringBuilder sb = new StringBuilder(); + final String startCheckText = Tools.makeTexti18n(messages, + "startChecking", new Object[] { lang.getTranslatedName(messages) }); + resultArea.setText(HTML_FONT_START + startCheckText + "<br>\n" + + HTML_FONT_END); + resultArea.repaint(); // FIXME: why doesn't this work? + // TODO: resultArea.setCursor(new Cursor(Cursor.WAIT_CURSOR)); + sb.append(startCheckText); + sb.append("...<br>\n"); + int matches = 0; + try { + matches = checkText(langTool, textArea.getText(), sb); + } catch (final Exception ex) { + sb.append("<br><br><b><font color=\"red\">" + ex.toString() + "<br>"); + final StackTraceElement[] elements = ex.getStackTrace(); + for (final StackTraceElement element : elements) { + sb.append(element); + sb.append("<br>"); + } + sb.append("</font></b><br>"); + ex.printStackTrace(); + } + final String checkDone = Tools.makeTexti18n(messages, "checkDone", + new Object[] {matches}); + sb.append(checkDone); + sb.append("<br>\n"); + resultArea.setText(HTML_FONT_START + sb.toString() + HTML_FONT_END); + resultArea.setCaretPosition(0); + } + } + + private int checkText(final JLanguageTool langTool, final String text, + final StringBuilder sb) throws IOException { + final long startTime = System.currentTimeMillis(); + final List<RuleMatch> ruleMatches = langTool.check(text); + final long startTimeMatching = System.currentTimeMillis(); + int i = 0; + for (final RuleMatch match : ruleMatches) { + final String output = Tools.makeTexti18n(messages, "result1", + new Object[] {i + 1, + match.getLine() + 1, + match.getColumn()}); + sb.append(output); + String msg = match.getMessage(); + msg = msg.replaceAll("<suggestion>", "<b>"); + msg = msg.replaceAll("</suggestion>", "</b>"); + msg = msg.replaceAll("<old>", "<b>"); + msg = msg.replaceAll("</old>", "</b>"); + sb.append("<b>" + messages.getString("errorMessage") + "</b> " + msg + "<br>\n"); + if (match.getSuggestedReplacements().size() > 0) { + final String repl = StringTools.listToString(match + .getSuggestedReplacements(), "; "); + sb.append("<b>" + messages.getString("correctionMessage") + "</b> " + + repl + "<br>\n"); + } + final String context = Tools.getContext(match.getFromPos(), match + .getToPos(), text); + sb.append("<b>" + messages.getString("errorContext") + "</b> " + context); + sb.append("<br>\n"); + i++; + } + final long endTime = System.currentTimeMillis(); + sb.append(Tools.makeTexti18n(messages, "resultTime", new Object[] { + endTime - startTime, + endTime - startTimeMatching})); + return ruleMatches.size(); + } + + private void setTrayMode(boolean trayMode) { + this.trayMode = trayMode; + } + + public static void main(final String[] args) { + try { + final Main prg = new Main(); + if (args.length == 1 + && (args[0].equals("-t") || args[0].equals("--tray"))) { + // dock to systray on startup + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + prg.createGUI(); + prg.setTrayMode(true); + prg.hideToTray(); + } catch (final MissingJdicException e) { + JOptionPane.showMessageDialog(null, e.getMessage(), "Error", + JOptionPane.ERROR_MESSAGE); + System.exit(1); + } catch (final Exception e) { + Tools.showError(e); + System.exit(1); + } + } + }); + } else if (args.length >= 1) { + System.out + .println("Usage: java de.danielnaber.languagetool.gui.Main [-t|--tray]"); + System.out + .println(" -t, --tray: dock LanguageTool to system tray on startup"); + } else { + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + prg.createGUI(); + prg.showGUI(); + } catch (final Exception e) { + Tools.showError(e); + } + } + }); + } + } catch (final Exception e) { + Tools.showError(e); + } + } + + // + // The System Tray stuff + // + + class TrayActionRMBListener implements ActionListener { + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equalsIgnoreCase( + StringTools.getLabel(messages.getString("guiMenuCheckClipboard")))) { + restoreFromTrayAndCheck(); + } else if (e.getActionCommand().equalsIgnoreCase( + StringTools.getLabel(messages.getString("guiMenuShowMainWindow")))) { + restoreFromTray(); + } else if (e.getActionCommand().equalsIgnoreCase( + StringTools.getLabel(messages.getString("guiMenuQuit")))) { + quit(); + } else { + JOptionPane.showMessageDialog(null, "Unknown action: " + + e.getActionCommand(), "Error", JOptionPane.ERROR_MESSAGE); + } + } + + } + + class TrayActionListener implements ActionListener, MouseListener { + + // for Java 1.5 / Jdic: + public void actionPerformed(@SuppressWarnings("unused")ActionEvent e) { + handleClick(); + } + + // Java 1.6: + public void mouseClicked(@SuppressWarnings("unused")MouseEvent e) { + handleClick(); + } + + private void handleClick() { + if (frame.isVisible() && frame.isActive()) { + frame.setVisible(false); + } else if (frame.isVisible() && !frame.isActive()) { + frame.toFront(); + restoreFromTrayAndCheck(); + } else { + restoreFromTrayAndCheck(); + } + } + + public void mouseEntered(@SuppressWarnings("unused") MouseEvent e) { + } + + public void mouseExited(@SuppressWarnings("unused")MouseEvent e) { + } + + public void mousePressed(@SuppressWarnings("unused")MouseEvent e) { + } + + public void mouseReleased(@SuppressWarnings("unused")MouseEvent e) { + } + + } + + class CloseListener implements WindowListener { + + public void windowClosing(@SuppressWarnings("unused")WindowEvent e) { + quitOrHide(); + } + + public void windowActivated(@SuppressWarnings("unused")WindowEvent e) { + } + + public void windowClosed(@SuppressWarnings("unused")WindowEvent e) { + } + + public void windowDeactivated(@SuppressWarnings("unused")WindowEvent e) { + } + + public void windowDeiconified(@SuppressWarnings("unused")WindowEvent e) { + } + + public void windowIconified(@SuppressWarnings("unused")WindowEvent e) { + } + + public void windowOpened(@SuppressWarnings("unused")WindowEvent e) { + } + + } + + static class PlainTextFilter extends FileFilter { + + @Override + public boolean accept(final File f) { + if (f.getName().toLowerCase().endsWith(".txt")) { + return true; + } + return false; + } + + @Override + public String getDescription() { + return "*.txt"; + } + + } + +} diff --git a/JLanguageTool/src/java/de/danielnaber/languagetool/gui/MainMenuBar.java b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/MainMenuBar.java new file mode 100644 index 0000000..72e3191 --- /dev/null +++ b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/MainMenuBar.java @@ -0,0 +1,170 @@ +/* LanguageTool, a natural language style checker + * Copyright (C) 2005 Daniel Naber (http://www.danielnaber.de) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +package de.danielnaber.languagetool.gui; + +import java.awt.Event; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.util.ResourceBundle; + +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.KeyStroke; + +import de.danielnaber.languagetool.tools.StringTools; + +/** + * The menu bar of the main dialog. + * + * @author Daniel Naber + */ +class MainMenuBar extends JMenuBar implements ActionListener { + + private static final long serialVersionUID = -7160998682243081767L; + + private final ResourceBundle messages; + + // File: + private String openText; + private String checkClipboardText; + private String dockToTrayText; + private String addLanguageText; + private String optionsText; + private String quitText; + // Help: + private String aboutText; + + private final Main prg; + private JMenu fileMenu; + private JMenu helpMenu; + + MainMenuBar(Main prg, ResourceBundle messages) { + this.prg = prg; + this.messages = messages; + initStrings(); + fileMenu.setMnemonic(StringTools.getMnemonic( + messages.getString("guiMenuFile"))); + helpMenu.setMnemonic(StringTools.getMnemonic( + messages.getString("guiMenuHelp"))); + // "Open": + final JMenuItem openItem = new JMenuItem(openText); + openItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, Event.CTRL_MASK)); + openItem.setMnemonic(StringTools.getMnemonic( + messages.getString("guiMenuOpen"))); + openItem.addActionListener(this); + fileMenu.add(openItem); + // "Check Text in Clipboard": + final JMenuItem checkClipboardItem = new JMenuItem(checkClipboardText); + checkClipboardItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, Event.CTRL_MASK)); + checkClipboardItem.setMnemonic(StringTools.getMnemonic( + messages.getString("guiMenuCheckClipboard"))); + checkClipboardItem.addActionListener(this); + fileMenu.add(checkClipboardItem); + // "Hide to System Tray": + final JMenuItem dockToTrayItem = new JMenuItem(dockToTrayText); + dockToTrayItem.setMnemonic(StringTools.getMnemonic( + messages.getString("guiMenuHide"))); + dockToTrayItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, Event.CTRL_MASK)); + dockToTrayItem.addActionListener(this); + fileMenu.add(dockToTrayItem); + // "Add Language": + final JMenuItem addLanguageItem = new JMenuItem(addLanguageText); + addLanguageItem.setMnemonic(StringTools.getMnemonic( + messages.getString("guiMenuAddRules"))); + addLanguageItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK)); + addLanguageItem.addActionListener(this); + fileMenu.add(addLanguageItem); + // "Options": + final JMenuItem optionsItem = new JMenuItem(optionsText); + optionsItem.setMnemonic(StringTools.getMnemonic( + messages.getString("guiMenuOptions"))); + optionsItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, Event.CTRL_MASK)); + optionsItem.addActionListener(this); + fileMenu.add(optionsItem); + // "Quit": + final JMenuItem quitItem = new JMenuItem(quitText); + quitItem.setMnemonic(StringTools.getMnemonic( + messages.getString("guiMenuQuit"))); + quitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, Event.CTRL_MASK)); + quitItem.addActionListener(this); + fileMenu.add(quitItem); + // "About": + final JMenuItem helpItem = new JMenuItem(aboutText); + helpItem.addActionListener(this); + helpItem.setMnemonic(StringTools.getMnemonic( + messages.getString("guiMenuAbout"))); + helpMenu.add(helpItem); + // add menus: + add(fileMenu); + add(helpMenu); + } + + private void initStrings() { + fileMenu = new JMenu(StringTools.getLabel( + messages.getString("guiMenuFile"))); + helpMenu = new JMenu(StringTools.getLabel( + messages.getString("guiMenuHelp"))); + // File: + openText = StringTools.getLabel( + messages.getString("guiMenuOpen")); + checkClipboardText = StringTools.getLabel( + messages.getString("guiMenuCheckClipboard")); + dockToTrayText = StringTools.getLabel( + messages.getString("guiMenuHide")); + addLanguageText = StringTools.getLabel( + messages.getString("guiMenuAddRules")); + optionsText = StringTools.getLabel( + messages.getString("guiMenuOptions")); + quitText = StringTools.getLabel( + messages.getString("guiMenuQuit")); + // Help: + aboutText = StringTools.getLabel( + messages.getString("guiMenuAbout")); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals(openText)) { + prg.loadFile(); + } else if (e.getActionCommand().equals(checkClipboardText)) { + prg.checkClipboardText(); + } else if (e.getActionCommand().equals(dockToTrayText)) { + try { + prg.hideToTray(); + } catch (MissingJdicException ex) { + JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", + JOptionPane.ERROR_MESSAGE); + } + } else if (e.getActionCommand().equals(addLanguageText)) { + prg.addLanguage(); + } else if (e.getActionCommand().equals(optionsText)) { + prg.showOptions(); + } else if (e.getActionCommand().equals(quitText)) { + prg.quit(); + } else if (e.getActionCommand().equals(aboutText)) { + final AboutDialog about = new AboutDialog(messages); + about.show(); + } else { + throw new IllegalArgumentException("Unknown action " + e); + } + } + +} diff --git a/JLanguageTool/src/java/de/danielnaber/languagetool/gui/MissingJdicException.java b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/MissingJdicException.java new file mode 100644 index 0000000..6dcf5de --- /dev/null +++ b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/MissingJdicException.java @@ -0,0 +1,38 @@ +/* LanguageTool, a natural language style checker + * Copyright (C) 2007 Daniel Naber (http://www.danielnaber.de) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +package de.danielnaber.languagetool.gui; + +/** + * Exception thrown with Java 1.5 if the jdic library cannot be found. + * + * @author Daniel Naber + */ +public class MissingJdicException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = 8822404582351420654L; + + public MissingJdicException(Throwable throwable) { + super("TrayIcon class not found. Please unzip " + + "'standalone-libs.zip' in your LanguageTool installation directory.", throwable); + } + +} diff --git a/JLanguageTool/src/java/de/danielnaber/languagetool/gui/Tools.java b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/Tools.java new file mode 100644 index 0000000..5abe803 --- /dev/null +++ b/JLanguageTool/src/java/de/danielnaber/languagetool/gui/Tools.java @@ -0,0 +1,192 @@ +/* LanguageTool, a natural language style checker + * Copyright (C) 2005 Daniel Naber (http://www.danielnaber.de) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +package de.danielnaber.languagetool.gui; + +import java.awt.Frame; +import java.io.File; +import java.text.MessageFormat; +import java.util.ResourceBundle; + +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.filechooser.FileFilter; + +import de.danielnaber.languagetool.tools.StringTools; + +/** + * GUI-related tools. + * + * @author Daniel Naber + */ +public class Tools { + + private static final int DEFAULT_CONTEXT_SIZE = 40; // characters + private static final String MARKER_START = "<b><font color=\"red\">"; + private static final String MARKER_END = "</font></b>"; + + private Tools() { + // no constructor + } + + public static String makeTexti18n(final ResourceBundle messages, final String key, + final Object[] messageArguments) { + final MessageFormat formatter = new MessageFormat(""); + formatter.applyPattern(messages.getString(key)); + return formatter.format(messageArguments); + } + + /** + * Get the default context (40 characters) of the given text range, + * highlighting the range with HTML. + */ + public static String getContext(final int fromPos, final int toPos, final String text) { + return getContext(fromPos, toPos, text, DEFAULT_CONTEXT_SIZE); + } + + /** + * Get the context (<code>contextSize</code> characters) of the given text + * range, highlighting the range with HTML code. + */ + public static String getContext(final int fromPos, final int toPos, final String fileContents, + int contextSize) { + return getContext(fromPos, toPos, fileContents, contextSize, MARKER_START, + MARKER_END, true); + } + + /** + * Get the context (<code>contextSize</code> characters) of the given text + * range, highlighting the range with the given marker strings, not escaping + * HTML. + */ + public static String getContext(final int fromPos, final int toPos, + final String fileContents, final int contextSize, + final String markerStart, final String markerEnd) { + return getContext(fromPos, toPos, fileContents, contextSize, markerStart, + markerEnd, false); + } + /** + * Get the context (<code>contextSize</code> characters) of the given text + * range, highlighting the range with the given marker strings. + * + * @param fromPos + * the start position of the error in characters + * @param toPos + * the end position of the error in characters + * @param text + * the text from which the context should be taken + * @param contextSize + * the size of the context in characters + * @param markerStart + * the string used to mark the beginning of the error + * @param markerEnd + * the string used to mark the end of the error + * @param escapeHTML + * whether HTML/XML characters should be escaped + */ + public static String getContext(final int fromPos, final int toPos, + String text, final int contextSize, final String markerStart, + final String markerEnd, final boolean escapeHTML) { + text = text.replace('\n', ' '); + // calculate context region: + int startContent = fromPos - contextSize; + String prefix = "..."; + String postfix = "..."; + String markerPrefix = " "; + if (startContent < 0) { + prefix = ""; + markerPrefix = ""; + startContent = 0; + } + int endContent = toPos + contextSize; + final int fileLen = text.length(); + if (endContent > fileLen) { + postfix = ""; + endContent = fileLen; + } + // make "^" marker. inefficient but robust implementation: + final StringBuilder marker = new StringBuilder(); + final int totalLen = fileLen + prefix.length(); + for (int i = 0; i < totalLen; i++) { + if (i >= fromPos && i < toPos) { + marker.append('^'); + } else { + marker.append(' '); + } + } + // now build context string plus marker: + final StringBuilder sb = new StringBuilder(); + sb.append(prefix); + sb.append(text.substring(startContent, endContent)); + final String markerStr = markerPrefix + + marker.substring(startContent, endContent); + sb.append(postfix); + final int startMark = markerStr.indexOf('^'); + final int endMark = markerStr.lastIndexOf('^'); + String result = sb.toString(); + if (escapeHTML) { + result = StringTools.escapeHTML(result.substring(0, startMark)) + + markerStart + + StringTools.escapeHTML(result.substring(startMark, endMark + 1)) + + markerEnd + StringTools.escapeHTML(result.substring(endMark + 1)); + } else { + result = result.substring(0, startMark) + markerStart + + result.substring(startMark, endMark + 1) + markerEnd + + result.substring(endMark + 1); + } + return result; + } + + /** + * Show a file chooser dialog and return the file selected by the user or + * <code>null</code>. + */ + static File openFileDialog(final Frame frame, final FileFilter fileFilter) { + final JFileChooser jfc = new JFileChooser(); + jfc.setFileFilter(fileFilter); + jfc.showOpenDialog(frame); + final File file = jfc.getSelectedFile(); + if (file == null) { + return null; + } + return file; + } + + /** + * Show the exception (with stacktrace) in a dialog and print it to STDERR. + */ + static void showError(final Exception e) { + final String msg = de.danielnaber.languagetool.tools.Tools + .getFullStackTrace(e); + JOptionPane + .showMessageDialog(null, msg, "Error", JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + + /** + * Show the exception (message without stacktrace) in a dialog and print it to + * STDERR. + */ + static void showErrorMessage(final Exception e) { + final String msg = e.getMessage(); + JOptionPane + .showMessageDialog(null, msg, "Error", JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + +} |