package chatty.gui.components.settings; import chatty.gui.components.LinkLabelListener; import chatty.gui.components.settings.Editor.Tester; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; /** * A simple panel to edit (add/remove Strings) a list. * * @author tduva */ public class ListSelector extends JPanel implements ListSetting<String> { private static final Dimension BUTTON_SIZE = new Dimension(27,27); private final JList<String> list = new JList<>(); private final DefaultListModel<String> data = new DefaultListModel<>(); private final JButton add = new JButton(); private final JButton remove = new JButton(); private final JButton change = new JButton(); private final JButton moveUp = new JButton(); private final JButton moveDown = new JButton(); private final JButton sort = new JButton(); private final JTextField input = new JTextField(); private String info; private DataFormatter<String> formatter; private final Editor editor; public ListSelector(Window parent, boolean manualSorting, boolean alphabeticSorting) { // Button actions ActionListener buttonAction = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == add || e.getSource() == input) { addItem(); } else if (e.getSource() == remove) { removeItem(); } else if (e.getSource() == change) { changeItem(); } else if (e.getSource() == moveUp) { moveUp(); } else if (e.getSource() == moveDown) { moveDown(); } else if (e.getSource() == sort) { sort(); } } }; list.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "removeItems"); list.getActionMap().put("removeItems", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { removeItem(); } }); // List double-click list.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { changeItem(); } } }); // List selection changes list.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { updateEditButtons(); } }); // Buttons configureButton(add, "list-add.png", "Add item (or press enter in inputbox)"); configureButton(remove, "list-remove.png", "Remove selected item"); configureButton(change, "edit.png", "Edit selected item (or double-click on item)"); configureButton(moveUp, "go-up.png", "Move selected item up"); configureButton(moveDown, "go-down.png", "Move selected item down"); configureButton(sort, "sort.png", "Sort list alphabetically"); // Listeners add.addActionListener(buttonAction); remove.addActionListener(buttonAction); input.addActionListener(buttonAction); change.addActionListener(buttonAction); moveUp.addActionListener(buttonAction); moveDown.addActionListener(buttonAction); sort.addActionListener(buttonAction); list.setModel(data); setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1; //add(input, gbc); gbc.weightx = 0; gbc.fill = GridBagConstraints.NONE; gbc.gridx = 1; add(add, gbc); gbc.weightx = 0; gbc.gridy = 1; gbc.anchor = GridBagConstraints.NORTH; add(remove, gbc); gbc.gridy = 2; add(change, gbc); if (manualSorting) { gbc.gridy = 3; add(moveUp, gbc); gbc.gridy = 4; add(moveDown, gbc); } if (alphabeticSorting) { gbc.gridy = 5; add(sort, gbc); } gbc.weightx = 1; gbc.gridx = 0; gbc.gridy = 0; gbc.gridheight = 6; gbc.fill = GridBagConstraints.BOTH; gbc.weighty = 1; add(new JScrollPane(list), gbc); updateEditButtons(); editor = new Editor(parent); } public void setInfo(String info) { this.info = info; } public void setInfoLinkLabelListener(LinkLabelListener listener) { editor.setLinkLabelListener(listener); } public void setTester(Tester tester) { editor.setTester(tester); } private void configureButton(JButton button, String icon, String tooltip) { button.setIcon(new ImageIcon(ListSelector.class.getResource(icon))); button.setToolTipText(tooltip); button.setPreferredSize(BUTTON_SIZE); button.setSize(BUTTON_SIZE); button.setMaximumSize(BUTTON_SIZE); button.setMinimumSize(BUTTON_SIZE); } /** * Add the item currently in the input box, but not if it's empty or already * in the list. */ private void addItem() { String item = editor.showDialog("Add entry:", "", info); item = format(item); if (item != null && !item.isEmpty() && !data.contains(item)) { int selectedIndex = list.getSelectedIndex(); if (selectedIndex != -1) { data.add(selectedIndex + 1, item); list.setSelectedValue(item, true); } else { data.addElement(item); } input.setText(""); } } /** * Remove selected items. */ private void removeItem() { int selectedIndex = list.getSelectedIndex(); for (String item : list.getSelectedValuesList()) { data.removeElement(item); } if (selectedIndex > -1) { if (selectedIndex < data.size()) { list.setSelectedValue(data.get(selectedIndex), true); } else if (selectedIndex > 0) { list.setSelectedValue(data.get(selectedIndex - 1), true); } } } private void changeItem() { String selectedValue = list.getSelectedValue(); int selectedIndex = list.getSelectedIndex(); if (selectedIndex > -1) { String newValue = editor.showDialog("Change entry:", selectedValue, info); newValue = format(newValue); if (newValue != null && !newValue.isEmpty()) { data.set(selectedIndex, newValue); } } } private void moveUp() { int selectedIndex = list.getSelectedIndex(); if (selectedIndex > 0) { swap(selectedIndex, selectedIndex -1); list.setSelectedValue(data.get(selectedIndex - 1), true); } } private void moveDown() { int selectedIndex = list.getSelectedIndex(); if (selectedIndex > -1 && selectedIndex < data.size() - 1) { swap(selectedIndex, selectedIndex + 1); list.setSelectedValue(data.get(selectedIndex + 1), true); } } private void swap(int index1, int index2) { String temp = data.get(index2); data.set(index2, data.get(index1)); data.set(index1, temp); } private void sort() { if (JOptionPane.showConfirmDialog(sort, "Sort list alphabetically (case sensitive)?", "Sort", JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION) { List<String> sortData = getData(); Collections.sort(sortData); setData(sortData); } } /** * Checks if an item is selected in the list and enables or disables the * edit buttons accordingly. */ private void updateEditButtons() { boolean somethingIsSelected = list.getSelectedIndex() != -1; boolean exactlyOneIsSelected = list.getSelectedIndices().length == 1; remove.setEnabled(somethingIsSelected); change.setEnabled(exactlyOneIsSelected); moveUp.setEnabled(exactlyOneIsSelected); moveDown.setEnabled(exactlyOneIsSelected); } /** * Gets the current data. * * @return */ public List<String> getData() { List<String> list = new ArrayList<>(); Enumeration<String> e = data.elements(); while (e.hasMoreElements()) { list.add(e.nextElement()); } return list; } /** * Fills the list with the given data. * * @param list */ public void setData(List<String> list) { data.clear(); for (String item : list) { data.addElement(item); } } @Override public List<String> getSettingValue() { return getData(); } @Override public void setSettingValue(List<String> value) { setData(value); } @Override public void setEnabled(boolean enabled) { input.setEnabled(enabled); list.setEnabled(enabled); } public void setDataFormatter(DataFormatter<String> formatter) { this.formatter = formatter; } /** * Formats the given text according to the set {@code DataFormatter}, or * just returns the input if no formatter is set. * * @param input The text to format * @return The input after formatting, or the unchanged input if no * formatter is set (may also be {@code null}, depending on the * implementation of the formatter) */ private String format(String input) { if (formatter != null && input != null) { return formatter.format(input); } return input; } }