package com.ts3client.ui; import com.ts3client.hotkey.Hotkey; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; import java.awt.BorderLayout; import java.awt.Font; import java.awt.Window; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; /** * The options dialog's hotkey tab: the list of bindings with the buttons to add, edit * and remove them. Edits happen on a working copy and only reach the running engine * when the dialog is applied. */ final class HotkeysPanel extends JPanel { private static final String[] COLUMNS = {"Action", "Hotkey", "Trigger", "Active server", "On"}; private final HotkeyService service; private final List working = new ArrayList<>(); private final Model model = new Model(); private final JTable table = new JTable(model); HotkeysPanel(HotkeyService service) { super(new BorderLayout(6, 6)); this.service = service; setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); synchronized (service.all()) { for (Hotkey h : service.all()) working.add(h.copy()); } table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); table.setRowHeight(table.getRowHeight() + 4); table.getColumnModel().getColumn(0).setPreferredWidth(240); table.getColumnModel().getColumn(1).setPreferredWidth(150); table.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) edit(); } }); JButton add = new JButton("Add…"); JButton edit = new JButton("Edit…"); JButton remove = new JButton("Remove"); add.addActionListener(e -> add()); edit.addActionListener(e -> edit()); remove.addActionListener(e -> remove()); JPanel buttons = new JPanel(); buttons.add(add); buttons.add(edit); buttons.add(remove); JLabel status = new JLabel(service.status()); status.setFont(status.getFont().deriveFont(Font.ITALIC, status.getFont().getSize2D() - 1f)); add(new JScrollPane(table), BorderLayout.CENTER); JPanel south = new JPanel(new BorderLayout()); south.add(buttons, BorderLayout.WEST); south.add(status, BorderLayout.SOUTH); add(south, BorderLayout.SOUTH); } private void add() { HotkeyDialog dlg = new HotkeyDialog(owner(), service, null); dlg.setVisible(true); if (!dlg.isConfirmed()) return; working.add(dlg.result()); model.fireTableDataChanged(); } private void edit() { int row = table.getSelectedRow(); if (row < 0) return; HotkeyDialog dlg = new HotkeyDialog(owner(), service, working.get(row)); dlg.setVisible(true); if (!dlg.isConfirmed()) return; working.set(row, dlg.result()); model.fireTableRowsUpdated(row, row); } private void remove() { int row = table.getSelectedRow(); if (row < 0) return; working.remove(row); model.fireTableDataChanged(); } private Window owner() { return SwingUtilities.getWindowAncestor(this); } /** Commits the edited list to the engine and to disk. */ void apply() { service.replaceAll(working); } /** Picks the stored bindings up again after something else changed them. */ void reload() { working.clear(); synchronized (service.all()) { for (Hotkey h : service.all()) working.add(h.copy()); } model.fireTableDataChanged(); } private final class Model extends AbstractTableModel { @Override public int getRowCount() { return working.size(); } @Override public int getColumnCount() { return COLUMNS.length; } @Override public String getColumnName(int column) { return COLUMNS[column]; } @Override public Class getColumnClass(int column) { return column >= 3 ? Boolean.class : String.class; } @Override public boolean isCellEditable(int row, int column) { return column == 4 || (column == 3 && working.get(row).isServerScoped()); } @Override public Object getValueAt(int row, int column) { Hotkey h = working.get(row); return switch (column) { case 0 -> h.path(); case 1 -> service.display(h.combo); case 2 -> h.action.momentary() ? "While held" : h.trigger.label(); case 3 -> h.isServerScoped() && h.activeServerOnly; default -> h.enabled; }; } @Override public void setValueAt(Object value, int row, int column) { Hotkey h = working.get(row); if (column == 3) { h.activeServerOnly = Boolean.TRUE.equals(value); } else if (column == 4) { h.enabled = Boolean.TRUE.equals(value); } } } }