package com.ts3client.ui; import com.ts3client.config.AwayMessages; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.table.AbstractTableModel; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Frame; /** * Editor for the away-message presets: a plain list of entries that are renamed * by double-clicking them, plus Add and Remove. * *
Backed by a one-column table because that is what gives Swing's list look * inline editing for free. Every change is written straight through to the * {@link AwayMessages} store. */ public final class AwayMessagesDialog extends JDialog { private final AwayMessages messages; private final Runnable onChanged; private final Model model = new Model(); private final JTable table = new JTable(model); public AwayMessagesDialog(Frame owner, AwayMessages messages, Runnable onChanged) { super(owner, "Away Message Presets", true); this.messages = messages; this.onChanged = onChanged; table.setTableHeader(null); table.setShowGrid(false); table.setFillsViewportHeight(true); table.setRowHeight(Math.max(20, table.getRowHeight())); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // Single click selects, double click starts editing — like a renameable list. table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE); JScrollPane scroll = new JScrollPane(table); scroll.setBorder(BorderFactory.createEmptyBorder(8, 8, 4, 8)); getContentPane().setLayout(new BorderLayout()); getContentPane().add(scroll, BorderLayout.CENTER); getContentPane().add(buildButtons(), BorderLayout.SOUTH); Dialogs.closeOnEscape(this, this::closeDialog); setDefaultCloseOperation(DISPOSE_ON_CLOSE); setSize(new Dimension(360, 300)); setLocationRelativeTo(owner); } private JPanel buildButtons() { JPanel buttons = new JPanel(); buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS)); buttons.setBorder(BorderFactory.createEmptyBorder(0, 8, 8, 8)); addButton(buttons, "Add", this::addEntry); addButton(buttons, "Remove", this::removeSelected); buttons.add(Box.createHorizontalGlue()); addButton(buttons, "Close", this::closeDialog); return buttons; } private void addButton(JPanel panel, String text, Runnable action) { JButton b = new JButton(text); b.addActionListener(e -> action.run()); panel.add(b); panel.add(Box.createHorizontalStrut(4)); } private void addEntry() { stopEditing(); messages.add("New away message"); int row = messages.all().size() - 1; model.fireTableRowsInserted(row, row); table.setRowSelectionInterval(row, row); table.scrollRectToVisible(table.getCellRect(row, 0, true)); persist(); table.editCellAt(row, 0); if (table.getEditorComponent() != null) table.getEditorComponent().requestFocusInWindow(); } private void removeSelected() { stopEditing(); int row = table.getSelectedRow(); if (row < 0) return; messages.remove(row); model.fireTableRowsDeleted(row, row); if (!messages.all().isEmpty()) { int next = Math.min(row, messages.all().size() - 1); table.setRowSelectionInterval(next, next); } persist(); } private void closeDialog() { stopEditing(); dispose(); } /** Flushes a cell that is still being edited so its text is not lost. */ private void stopEditing() { if (table.isEditing()) table.getCellEditor().stopCellEditing(); } private void persist() { messages.save(); if (onChanged != null) onChanged.run(); } private final class Model extends AbstractTableModel { @Override public int getRowCount() { return messages.all().size(); } @Override public int getColumnCount() { return 1; } @Override public Object getValueAt(int row, int column) { return messages.all().get(row); } @Override public boolean isCellEditable(int row, int column) { return true; } @Override public void setValueAt(Object value, int row, int column) { String text = value == null ? "" : value.toString().trim(); if (text.isEmpty()) return; // an emptied entry keeps its old text messages.set(row, text); persist(); } } }