diff --git a/ts3-client/swing/src/main/java/com/ts3client/ui/ContactsDialog.java b/ts3-client/swing/src/main/java/com/ts3client/ui/ContactsDialog.java index e066840..0b9ff02 100644 --- a/ts3-client/swing/src/main/java/com/ts3client/ui/ContactsDialog.java +++ b/ts3-client/swing/src/main/java/com/ts3client/ui/ContactsDialog.java @@ -10,6 +10,7 @@ import com.ts3client.contacts.NicknameDisplay; import com.ts3client.teamspeak.TeamSpeakSettingsDb; import com.ts3client.text.TsLink; +import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; @@ -24,7 +25,6 @@ import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JScrollPane; -import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.KeyStroke; @@ -59,10 +59,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * The contact list window, laid out like TeamSpeak's Contacts: the contacts grouped - * as friends, blocked and neutral on the left, and on the right the selected one's - * custom nickname and its General / Display / Ignore / Whisper pages. Every edit is - * stored as it is made. + * The contact list window: the contacts grouped as friends, blocked and neutral on + * the left, and on the right all of the selected one's settings — TeamSpeak's + * General / Display / Ignore / Whisper pages, in one column rather than as tabs + * since each holds only a few options. Every edit is stored as it is made. * *
Clients can be dragged in from the server tree — the drag carries the * client's TS3 link, which names its unique id. @@ -98,8 +98,7 @@ final class ContactsDialog extends JDialog { private final JCheckBox ignorePokes = new JCheckBox("Ignore Pokes"); private final JCheckBox ignoreAvatar = new JCheckBox("Hide avatar"); private final JCheckBox ignoreAway = new JCheckBox("Hide away message"); - private final JRadioButton allowWhisper = new JRadioButton("Allow whisper"); - private final JRadioButton denyWhisper = new JRadioButton("Deny whisper"); + private final JCheckBox denyWhisper = new JCheckBox("Deny whisper"); private final JPanel details = new JPanel(new BorderLayout(0, UIScale.scale(8))); /** Set while the fields are being filled from a contact, so that does not count as an edit. */ @@ -122,7 +121,7 @@ final class ContactsDialog extends JDialog { details.setBorder(new ScaledEmptyBorder(8, 4, 8, 8)); details.add(buildNicknameRow(), BorderLayout.NORTH); - details.add(buildPages(), BorderLayout.CENTER); + details.add(buildOptions(), BorderLayout.CENTER); JPanel buttons = new JPanel(new BorderLayout()); buttons.setBorder(new ScaledEmptyBorder(0, 8, 8, 8)); @@ -161,7 +160,8 @@ final class ContactsDialog extends JDialog { Dialogs.closeOnEscape(this); setDefaultCloseOperation(DISPOSE_ON_CLOSE); pack(); - setMinimumSize(UIScale.scale(new Dimension(620, 400))); + // Only the list scrolls, so the window never gets shorter than the options column. + setMinimumSize(new Dimension(UIScale.scale(620), getHeight())); setLocationRelativeTo(owner); } @@ -299,35 +299,45 @@ final class ContactsDialog extends JDialog { // ---- details ---- + /** The names, each label on its own line above its field. */ private JComponent buildNicknameRow() { JPanel row = new JPanel(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.insets = UIScale.scale(new Insets(2, 2, 2, 2)); c.anchor = GridBagConstraints.WEST; - c.gridy = 0; c.gridx = 0; + c.gridy = 0; + c.gridwidth = 2; row.add(new JLabel("Custom Nickname:"), c); - c.gridx = 1; + + c.gridy = 1; + c.gridwidth = 1; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; nicknameField.setToolTipText("Enter custom nickname"); nicknameField.addActionListener(e -> applyNickname()); row.add(nicknameField, c); - c.gridx = 2; + c.gridx = 1; c.weightx = 0; c.fill = GridBagConstraints.NONE; nicknameApply.setToolTipText("Apply nickname change"); nicknameApply.addActionListener(e -> applyNickname()); row.add(nicknameApply, c); + + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 2; + row.add(new JLabel("Phonetic Nickname:"), c); + c.gridy = 3; + c.weightx = 1; + c.fill = GridBagConstraints.HORIZONTAL; + row.add(phoneticField, c); return row; } - private JComponent buildPages() { - JTabbedPane pages = new JTabbedPane(); - pages.addTab("General", page( - radioGroup(neutralRadio, blockedRadio, friendRadio), - Box.createVerticalStrut(UIScale.scale(8)), - labelled("Phonetic Nickname:", phoneticField))); + /** Every option at once, one short group under the other. */ + private JComponent buildOptions() { + JComponent contact = group("Contact", radioGroup(neutralRadio, blockedRadio, friendRadio)); neutralRadio.setToolTipText("Mark as neutral"); blockedRadio.setToolTipText("Mark as blocked"); friendRadio.setToolTipText("Mark as friend"); @@ -343,7 +353,7 @@ final class ContactsDialog extends JDialog { } }); - pages.addTab("Display", page(radioGroup(bothRadio, onlyCustomRadio, onlyNicknameRadio))); + JComponent display = group("Display", radioGroup(bothRadio, onlyCustomRadio, onlyNicknameRadio)); bothRadio.setToolTipText("Show custom name and nickname"); onlyCustomRadio.setToolTipText("Show only custom name"); onlyNicknameRadio.setToolTipText("Show nickname only"); @@ -351,7 +361,8 @@ final class ContactsDialog extends JDialog { onlyCustomRadio.addActionListener(e -> edit(c -> c.nicknameDisplay = NicknameDisplay.ONLY_CUSTOM)); onlyNicknameRadio.addActionListener(e -> edit(c -> c.nicknameDisplay = NicknameDisplay.ONLY_NICKNAME)); - pages.addTab("Ignore", page(automute, ignorePublic, ignorePrivate, ignorePokes, ignoreAvatar, ignoreAway)); + JComponent ignore = group("Ignore", automute, ignorePublic, ignorePrivate, ignorePokes, ignoreAvatar, ignoreAway, + denyWhisper); automute.setToolTipText("Automatically mute this person"); ignorePublic.setToolTipText("Ignore messages this person sends to the server or in channels"); ignorePrivate.setToolTipText("Ignore private chat by this person"); @@ -365,26 +376,35 @@ final class ContactsDialog extends JDialog { ignoreAvatar.addActionListener(e -> edit(c -> c.ignoreAvatar = ignoreAvatar.isSelected())); ignoreAway.addActionListener(e -> edit(c -> c.ignoreAwayMessage = ignoreAway.isSelected())); - pages.addTab("Whisper", page(radioGroup(allowWhisper, denyWhisper))); - allowWhisper.setToolTipText("This contact is allowed to whisper to you"); - denyWhisper.setToolTipText("This contact is always denied to whisper to you."); - allowWhisper.addActionListener(e -> edit(c -> c.whisperAllowed = true)); - denyWhisper.addActionListener(e -> edit(c -> c.whisperAllowed = false)); - return pages; + denyWhisper.setToolTipText("This contact is always denied to whisper to you"); + denyWhisper.addActionListener(e -> edit(c -> c.whisperAllowed = !denyWhisper.isSelected())); + return column(contact, display, ignore); } - private static JPanel page(Component... rows) { + private static JPanel column(JComponent... groups) { JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); - p.setBorder(new ScaledEmptyBorder(10, 10, 10, 10)); - for (Component row : rows) { - if (row instanceof JComponent) ((JComponent) row).setAlignmentX(Component.LEFT_ALIGNMENT); - p.add(row); + for (JComponent g : groups) { + g.setAlignmentX(Component.LEFT_ALIGNMENT); + g.setMaximumSize(new Dimension(Integer.MAX_VALUE, g.getPreferredSize().height)); + p.add(g); + p.add(Box.createVerticalStrut(UIScale.scale(6))); } p.add(Box.createVerticalGlue()); return p; } + private static JPanel group(String title, JComponent... rows) { + JPanel p = new JPanel(); + p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); + p.setBorder(BorderFactory.createTitledBorder(title)); + for (JComponent row : rows) { + row.setAlignmentX(Component.LEFT_ALIGNMENT); + p.add(row); + } + return p; + } + private static JPanel radioGroup(JRadioButton... buttons) { ButtonGroup group = new ButtonGroup(); JPanel p = new JPanel(); @@ -397,14 +417,6 @@ final class ContactsDialog extends JDialog { return p; } - private static JPanel labelled(String label, JComponent field) { - JPanel p = new JPanel(new BorderLayout(UIScale.scale(6), 0)); - p.add(new JLabel(label), BorderLayout.WEST); - p.add(field, BorderLayout.CENTER); - p.setMaximumSize(new Dimension(Integer.MAX_VALUE, field.getPreferredSize().height)); - return p; - } - /** Fills the right-hand side from the selected contact, or greys it out. */ private void showSelected() { Contact c = selectedContact(); @@ -429,7 +441,7 @@ final class ContactsDialog extends JDialog { ignorePokes.setSelected(c.ignorePokes); ignoreAvatar.setSelected(c.ignoreAvatar); ignoreAway.setSelected(c.ignoreAwayMessage); - (c.whisperAllowed ? allowWhisper : denyWhisper).setSelected(true); + denyWhisper.setSelected(!c.whisperAllowed); } finally { filling = false; }