package com.ts3client.ui; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; import java.awt.Component; import java.awt.Dimension; /** * Asks for the reason text that goes with a moderation action. The server caps * such messages, so the field refuses anything longer. */ final class ReasonDialog { /** The longest reason the protocol carries with a kick. */ static final int KICK_REASON_LIMIT = 40; private ReasonDialog() { } /** @return the reason (possibly empty), or {@code null} when the dialog was cancelled */ static String prompt(Component owner, String title, String message, int maxLength) { JTextField field = reasonField(maxLength); focusWhenShown(field); JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); panel.add(label(message)); panel.add(field); int result = JOptionPane.showConfirmDialog(owner, panel, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); return result == JOptionPane.OK_OPTION ? field.getText().trim() : null; } static JTextField reasonField(int maxLength) { JTextField field = new JTextField(24); field.setDocument(new LimitedDocument(maxLength)); field.setAlignmentX(Component.LEFT_ALIGNMENT); fixHeight(field); return field; } /** A left-aligned label with a little air below it, for use in a box layout. */ static JLabel label(String text) { JLabel label = new JLabel(text); label.setAlignmentX(Component.LEFT_ALIGNMENT); label.setBorder(BorderFactory.createEmptyBorder(0, 0, 4, 0)); return label; } /** Keeps a component from stretching taller than it needs in a box layout. */ static void fixHeight(Component c) { c.setMaximumSize(new Dimension(Integer.MAX_VALUE, c.getPreferredSize().height)); } /** Puts the caret in a field as soon as its dialog appears. */ static void focusWhenShown(JComponent field) { field.addAncestorListener(new AncestorListener() { @Override public void ancestorAdded(AncestorEvent event) { field.requestFocusInWindow(); } @Override public void ancestorRemoved(AncestorEvent event) { } @Override public void ancestorMoved(AncestorEvent event) { } }); } /** A document that silently drops anything past its length limit. */ private static final class LimitedDocument extends PlainDocument { private final int limit; LimitedDocument(int limit) { this.limit = limit; } @Override public void insertString(int offset, String text, AttributeSet attrs) throws BadLocationException { if (text == null) return; int room = limit - getLength(); if (room <= 0) return; super.insertString(offset, text.length() > room ? text.substring(0, room) : text, attrs); } } }