All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.stanford.nlp.trees.tregex.gui.PreferencesPanel Maven / Gradle / Ivy

Go to download

Stanford CoreNLP provides a set of natural language analysis tools which can take raw English language text input and give the base forms of words, their parts of speech, whether they are names of companies, people, etc., normalize dates, times, and numeric quantities, mark up the structure of sentences in terms of phrases and word dependencies, and indicate which noun phrases refer to the same entities. It provides the foundational building blocks for higher level text understanding applications.

There is a newer version: 4.5.7
Show newest version
// Tregex/Tsurgeon, PreferencesPanel - a GUI for tree search and modification
// Copyright (c) 2007-2008 The Board of Trustees of
// The Leland Stanford Junior University. All Rights Reserved.
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// This code is a GUI interface to Tregex and Tsurgeon (which were
// written by Rogey Levy and Galen Andrew).
//
// For more information, bug reports, fixes, contact:
//    Christopher Manning
//    Dept of Computer Science, Gates 1A
//    Stanford CA 94305-9010
//    USA
//    Support/Questions: [email protected]
//    Licensing: [email protected]
//    http://www-nlp.stanford.edu/software/tregex.shtml

package edu.stanford.nlp.trees.tregex.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

import edu.stanford.nlp.trees.*;

/**
 * Class for creating the preferences panel which holds user definable preferences (e.g., tree display size,
 * highlight color) and syncs these preferences with the appropriate data structures. This class only needs to be
 * instantiated once for a given instance of the gui.
 *
 * @author Anna Rafferty
 */
@SuppressWarnings("serial")
public class PreferencesPanel extends JDialog {

  private static final String FONT_ERROR = "font";//error code if font size given is not an int > 0
  private static final String HISTORY_ERROR = "history";//error code if history size is not an int >0
  private static final String MAX_MATCH_ERROR = "maxMatch";//error code if history size is not an int >0

  private TregexGUI gui;

  final JButton highlightButton;
  private JTextField setEncoding;//declared here because may change in different places

  public PreferencesPanel(TregexGUI gui) {
    super(gui, "Preferences");

    this.gui = gui;

    this.setResizable(false);
    final JPanel prefPanel = new JPanel();
    prefPanel.setLayout(new GridBagLayout());

    //display prefs box
    Box displayPrefs = Box.createVerticalBox();
    displayPrefs.setBorder(BorderFactory.createTitledBorder("Display"));
    JPanel displayOptions = new JPanel();

    displayOptions.setLayout(new GridLayout(3,2,0,2));

    JLabel historyLabel = new JLabel("Recent matches length: ");
    final JTextField historySizeField =
      new JTextField(Integer.toString(Preferences.getHistorySize()));
    displayOptions.add(historyLabel);
    displayOptions.add(historySizeField);

    JLabel maxMatchesLabel = new JLabel("Max displayed trees: ");
    final JTextField maxMatchesSizeField
      = new JTextField(Integer.toString(Preferences.getMaxMatches()));
    displayOptions.add(maxMatchesLabel);
    displayOptions.add(maxMatchesSizeField);

    JLabel highlightLabel = new JLabel("Highlight color:");
    highlightButton = makeColorButton("Pick a new highlight color: ",
                                      Preferences.getHighlightColor(), prefPanel);
    highlightButton.putClientProperty("JButton.buttonType","icon");
    displayOptions.add(highlightLabel);
    displayOptions.add(highlightButton);
    displayPrefs.add(displayOptions);

    //tree display prefs box
    Box treeDisplayPrefs = Box.createVerticalBox();
    treeDisplayPrefs.setBorder(BorderFactory.createTitledBorder("Tree Display"));
    JPanel treeDisplayOptions = new JPanel();
    treeDisplayOptions.setLayout(new GridLayout(4,2));
    JLabel fontName = new JLabel("Font: ");
    final JComboBox fontPicker = new JComboBox(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames());
    fontPicker.setSelectedItem(Preferences.getFont());

    JLabel sizeLabel = new JLabel("Font size: ");
    final JTextField size =
      new JTextField(Integer.toString(Preferences.getFontSize()));

    treeDisplayOptions.add(fontName);
    treeDisplayOptions.add(fontPicker);
    treeDisplayOptions.add(sizeLabel);
    treeDisplayOptions.add(size);

    JLabel defaultColorLabel = new JLabel("Tree color: ");
    final JButton defaultColorButton = makeColorButton("Pick a new tree color: ",
                                                       Preferences.getTreeColor(), prefPanel);
    treeDisplayOptions.add(defaultColorLabel);
    treeDisplayOptions.add(defaultColorButton);

    JLabel matchedLabel = new JLabel("Matched node color: ");
    final JButton matchedButton = makeColorButton("Pick a new color for matched nodes: ",
                                                  Preferences.getMatchedColor(),
                                                  prefPanel);
    treeDisplayOptions.add(matchedLabel);
    treeDisplayOptions.add(matchedButton);

    //----add to tree display box
    treeDisplayPrefs.add(treeDisplayOptions);

    //advanced preferences - headfinder, tree reader factory
    JPanel advOptions = new JPanel();
    advOptions.setBorder(BorderFactory.createTitledBorder("Advanced "));
    advOptions.setLayout(new GridLayout(3,2,0,4));
    JLabel headfinderName = new JLabel("Head finder:");
    final JComboBox headfinderPicker = new JComboBox(new String[] {"ArabicHeadFinder", "BikelChineseHeadFinder", "ChineseHeadFinder", "ChineseSemanticHeadFinder", "CollinsHeadFinder", "DybroFrenchHeadFinder", "LeftHeadFinder", "ModCollinsHeadFinder", "NegraHeadFinder", "SemanticHeadFinder", "SunJurafskyChineseHeadFinder", "TueBaDZHeadFinder", "UniversalSemanticHeadFinder"}); //
    headfinderPicker.setEditable(true);
    headfinderPicker.setSelectedItem(Preferences.getHeadFinder()
                                     .getClass().getSimpleName());
    JLabel treeReaderFactoryName = new JLabel("Tree reader factory:");
    final JComboBox trfPicker = new JComboBox(new String[] {"ArabicTreeReaderFactory", "ArabicTreeReaderFactory.ArabicRawTreeReaderFactory", "CTBTreeReaderFactory", "Basic categories only (LabeledScoredTreeReaderFactory)", "FrenchTreeReaderFactory","NoEmptiesCTBTreeReaderFactory", "PennTreeReaderFactory", "TregexTreeReaderFactory" });
    trfPicker.setEditable(true);
    trfPicker.setSelectedItem(Preferences.getTreeReaderFactory()
                              .getClass().getSimpleName());
    JLabel encodingLabel = new JLabel("Character encoding: ");
    setEncoding = new JTextField(Preferences.getEncoding());
    setEncoding.setPreferredSize(headfinderName.getPreferredSize());
    advOptions.add(headfinderName);
    advOptions.add(headfinderPicker);
    advOptions.add(treeReaderFactoryName);
    advOptions.add(trfPicker);
    advOptions.add(encodingLabel);
    advOptions.add(setEncoding);
    //tsurgeon enabled box
    final JCheckBox tsurgeonCheck = new JCheckBox("Enable Tsurgeon");
    tsurgeonCheck.setSelected(Preferences.getEnableTsurgeon());

    //matched portions only box
    final JCheckBox matchPortion = new JCheckBox("Show only matched portions of tree");
    matchPortion.setSelected(Preferences.getMatchPortionOnly());

    //add everything
    GridBagConstraints c = new GridBagConstraints();
    c.ipady = 3;
    c.fill = GridBagConstraints.BOTH;
    c.weightx = 1;
    c.gridwidth = GridBagConstraints.REMAINDER;
    prefPanel.add(displayPrefs,c);
    prefPanel.add(treeDisplayPrefs,c);
    prefPanel.add(advOptions,c);
    prefPanel.add(tsurgeonCheck,c);
    c.gridheight = GridBagConstraints.REMAINDER;
    prefPanel.add(matchPortion,c);

    JButton[] options = new JButton[2];
    JButton okay = new JButton("Okay");


    JButton cancel = new JButton("Cancel");

    options[1] = cancel;
    options[0] = okay;


    final JOptionPane prefPane = new JOptionPane();
    prefPane.setMessage(prefPanel);

    prefPane.setOptions(options);
    prefPane.setOpaque(true);
    this.setContentPane(prefPane);
    this.getRootPane().setDefaultButton(okay);
  //--------- wire buttons
    okay.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent arg0) {
        try {
          //check appropriate headfinder/tree reader
          HeadFinder hf = Preferences.lookupHeadFinder(headfinderPicker.getSelectedItem().toString());
          if (hf == null) {
            JOptionPane.showMessageDialog(PreferencesPanel.this, "Sorry, there was an error finding or instantiating the head finder. Please choose another head finder.", "Head Finder Error", JOptionPane.ERROR_MESSAGE);
            throw new Exception("Headfinder error");
          }

          TreeReaderFactory trf = Preferences.lookupTreeReaderFactory(trfPicker.getSelectedItem().toString());
          if (trf == null) {
            JOptionPane.showMessageDialog(PreferencesPanel.this, "Sorry, there was an error finding or instantiating the tree reader factory. Please choose another tree reader factory.", "Tree Reader Factory Error", JOptionPane.ERROR_MESSAGE);
            throw new Exception("Tree reader factory error");
          }

          //check appropriate number formats
          Integer historySize = checkNumberFormat(historySizeField, PreferencesPanel.HISTORY_ERROR);
          Integer maxMatchSize = checkNumberFormat(maxMatchesSizeField, PreferencesPanel.MAX_MATCH_ERROR);
          Integer textSize = checkNumberFormat(size, PreferencesPanel.FONT_ERROR);

          syncFromPrefPanel(fontPicker.getSelectedItem().toString(),
              textSize,
              ((ColorIcon) defaultColorButton.getIcon()).getColor(),
              ((ColorIcon) matchedButton.getIcon()).getColor(),
              ((ColorIcon) highlightButton.getIcon()).getColor(),
              historySize,
              maxMatchSize,
              tsurgeonCheck.isSelected(), matchPortion.isSelected(), hf, trf, setEncoding.getText().trim());
          PreferencesPanel.this.setVisible(false);
        } catch(NumberFormatException e) {
         //System.out.println("Error is: " + e.getMessage());
          if (e.getMessage() == PreferencesPanel.FONT_ERROR)
            JOptionPane.showMessageDialog(prefPanel, "Please enter an integer greater than 0 for the font size.", "Font size error", JOptionPane.ERROR_MESSAGE);
          else if (e.getMessage() == PreferencesPanel.HISTORY_ERROR)
            JOptionPane.showMessageDialog(prefPanel, "Please enter an integer greater than or equal to 0 for the number of recent matches to remember.", "History size error", JOptionPane.ERROR_MESSAGE);
          else if (e.getMessage() == PreferencesPanel.HISTORY_ERROR)
            JOptionPane.showMessageDialog(prefPanel, "Please enter an integer greater than or equal to 0 for the maximum number of matches to display.", "Max Matches size error", JOptionPane.ERROR_MESSAGE);
          else
            JOptionPane.showMessageDialog(prefPanel, "Please check that the font size, max matches to display, and number of recent matches to remember are all integers greater than 0.", "Size error", JOptionPane.ERROR_MESSAGE);
        } catch (Exception e) {
          // ignore
        }

      }

    });

    cancel.addActionListener(arg0 -> PreferencesPanel.this.setVisible(false));

  }

  private static Integer checkNumberFormat(JTextField component, String errorType) throws NumberFormatException {
    Integer number = null;
    String txt = component.getText();
    if(txt!= null && !"".equals(txt)) {
      try {
        number = Integer.parseInt(txt);
        if(number <= 0)
          throw new NumberFormatException(errorType);
      } catch(NumberFormatException e) {//we catch and throw so that we catch both the one we threw and the one that could be thrown by Integer.parseInt
        throw new NumberFormatException(errorType);
      }
    }
    return number;
  }

  public static void alignLeft(JComponent box) {
    for(Component comp: box.getComponents()) {
      ((JComponent) comp).setAlignmentX(Box.LEFT_ALIGNMENT);
    }
  }

  private void syncFromPrefPanel(String font, Integer fontSize, Color treeColor, Color matchedColor, Color highlightColor,
      Integer historySize, Integer maxMatches, boolean enableTsurgeon, boolean matchPortionOnly, HeadFinder hf, TreeReaderFactory trf, String encoding) {
    Preferences.setFont(font);
    Preferences.setFontSize(fontSize == null ? 0 : fontSize);
    Preferences.setTreeColor(treeColor);
    Preferences.setMatchedColor(matchedColor);
    Preferences.setHighlightColor(highlightColor);
    Preferences.setHistorySize(historySize == null ? 0 : historySize);
    Preferences.setMaxMatches(maxMatches == null ? 0 : maxMatches);
    Preferences.setEnableTsurgeon(enableTsurgeon);
    Preferences.setMatchPortionOnly(matchPortionOnly);
    Preferences.setHeadFinder(hf);
    Preferences.setTreeReaderFactory(trf);
    Preferences.setEncoding(encoding);

    gui.loadPreferences();
  }

  void checkEncodingAndDisplay(String headFinder, String trf) {
    boolean prompt = false;
    String defaultEncoding = "";
    String curEncoding = FileTreeModel.getCurEncoding();
    if(isChinese(headFinder, trf)) {
      if(!curEncoding.equals(FileTreeModel.DEFAULT_CHINESE_ENCODING)) {
        prompt = true;
        defaultEncoding = FileTreeModel.DEFAULT_CHINESE_ENCODING;
      }
    } else if(isNegra(headFinder, trf)) {
      if(!curEncoding.equals(FileTreeModel.DEFAULT_NEGRA_ENCODING)) {
        prompt = true;
        defaultEncoding = FileTreeModel.DEFAULT_NEGRA_ENCODING;
      }
    } else if(!curEncoding.equals(FileTreeModel.DEFAULT_ENCODING)) {
      prompt = true;
      defaultEncoding = FileTreeModel.DEFAULT_ENCODING;
    }


    if(prompt) {
      doEncodingPrompt(defaultEncoding, curEncoding);
    }
  }


  private void doEncodingPrompt(final String encoding, final String oldEncoding) {

    final JPanel encodingPanel = new JPanel();
    encodingPanel.setLayout(new BoxLayout(encodingPanel, BoxLayout.PAGE_AXIS));
    JLabel text = new JLabel("A head finder or tree reader was selected that has the default encoding " + encoding
        + "; this differs from " + oldEncoding + ", which was being used. If the encoding is changed, all newly loaded" +
        "treebanks will be read using the new encoding. Choosing an encoding that is not the true encoding of your tree " +
        "files may cause errors and unexpected behavior.");
    //text.setBorder(BorderFactory.createLineBorder(Color.black));
    text.setAlignmentX(SwingConstants.LEADING);
    JPanel textPanel = new JPanel(new BorderLayout());
    textPanel.setPreferredSize(new Dimension(100,100));
    textPanel.add(text);
    encodingPanel.add(textPanel);
    encodingPanel.add(Box.createVerticalStrut(5));
    final JOptionPane fileFilterDialog = new JOptionPane();
    fileFilterDialog.setMessage(encodingPanel);
    JButton[] options = new JButton[3];
    JButton useNewEncoding = new JButton("Use " + encoding);
    JButton useOldEncoding = new JButton("Use " + oldEncoding);
    JButton useAnotherEncoding = new JButton("Use encoding...");

    options[0] = useNewEncoding;
    options[1] = useOldEncoding;
    options[2] = useAnotherEncoding;

    fileFilterDialog.setOptions(options);

    final JDialog dialog = fileFilterDialog.createDialog(null, "Default encoding changed...");
    useNewEncoding.addActionListener(arg0 -> {
      FileTreeModel.setCurEncoding(encoding);
      if(setEncoding == null)
        System.out.println("encoding null!!");
      setEncoding.setText(encoding);
      dialog.setVisible(false);
    });
    useOldEncoding.addActionListener(e -> dialog.setVisible(false));
    useAnotherEncoding.addActionListener(e -> {
      //need to prompt for an encoding
      dialog.setVisible(false);
      alternateEncodingPrompt(encoding);
    });
    dialog.getRootPane().setDefaultButton(useNewEncoding);
    dialog.pack();
    dialog.setLocationRelativeTo(this);
    dialog.setVisible(true);
  }

  /**
   * Prompts the user to enter a new encoding for loading tree files
   */
  private void alternateEncodingPrompt(String newDefaultEncoding) {
    String response = (String) JOptionPane.showInputDialog(this,"Please enter a text encoding: ", "Set Encoding...",
        JOptionPane.QUESTION_MESSAGE,null,null,newDefaultEncoding);
    FileTreeModel.setCurEncoding(response.trim());
    setEncoding.setText(response.trim());
  }

  /**
   * Checks if the given head finder or tree reader factory are for Negra (German).
   */
  static boolean isNegra(String headFinder, String trf) {
    return headFinder.startsWith("Negra");
  }

  /**
   * Checks if the given head finder or tree reader factory are for Chinese; if so, the font chosen in prefs
   * will be overridden for a Chinese compatible font
   */
  static boolean isChinese(String headFinder, String trf) {
    return headFinder.startsWith("Chinese") || headFinder.startsWith("OldChinese") || trf.equalsIgnoreCase("CTBTreeReaderFactory") || trf.equalsIgnoreCase("NoEmptiesCTBTreeReaderFactory");
  }

  /**
   * Checks if the given head finder or tree reader factory are for Arabic; if so, the font chosen in prefs
   * will be overridden for a Arabic compatible font
   */
  static boolean isArabic(String headFinder, String trf) {
    return headFinder.startsWith("Arabic") || trf.startsWith("Arabic");
  }

  /**
   * Makes a color choosing button that displays only an icon with a square of the given color
   */
  public static JButton makeColorButton(final String promptText, Color iconColor, final JPanel parent) {
    final ColorIcon icon = new ColorIcon(iconColor);
    final JButton button = new JButton(icon);
    button.addActionListener(arg0 -> {
      Color newColor = JColorChooser.showDialog(parent,promptText, icon.getColor());
      if (newColor != null) {
        icon.setColor(newColor);
        parent.repaint();
      }
    });
    return button;
  }


  private static class ColorIcon implements Icon {

    private static final int iconHeight = 8;
    private static final int iconWidth = 15;
    private Color color;

    public ColorIcon(Color c) {
      this.color = c;
    }
    public int getIconHeight() {
      return iconHeight;
    }

    public int getIconWidth() {
      return iconWidth;
    }

    public void setColor(Color c) {
      this.color = c;
    }

    public Color getColor() {
      return color;
    }

    public void paintIcon(Component c, Graphics g, int x, int y) {
      Color oldColor = g.getColor();
      g.setColor(color);
      g.fillRect(x, y, getIconWidth(), getIconHeight());
      g.setColor(oldColor);
    }

  } // end static class ColorIcon

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy