package chatty.gui.components.settings; import chatty.Helper; import chatty.gui.GuiUtil; import chatty.gui.components.menus.ContextMenu; import chatty.gui.components.menus.TestContextMenu; import chatty.util.commands.CustomCommand; import java.awt.Component; import java.awt.GridBagConstraints; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; /** * * @author tduva */ public class CommandSettings extends SettingsPanel { private static String getInfo(String type) { String info = INFO_HEADER + "<ul>" + "<li>" + "Add Custom Commands as <code>/Command</code> (no parameters), " + "separated by spaces (several per line), <code>//Command</code> " + "to put into submenu, <code>|</code> (vertical bar) to add " + "separator." + "</li>" + "<li>" + "Add timeouts by specifying a number (<code>30</code> interpreted " + "as 30 seconds, <code>30s/m/h/d</code> as seconds/minutes/hours " + "days respectively)." + "</li>" + "<li>" + "Or add a command directly (without it having to be added as a " + "Custom Command), one per line:<br />" + "<code>Slap=/me slaps $$1 around a bit with a large trout</code>" + "</li>"; if (type.equals("userDialog")) { info += "<li>" + "Put buttons in different rows, e.g. <code>@a1</code> on " + "a line, subsequent lines to put into that row starting " + "with a <code>.</code> (point). <code>@a1</code> is the " + "default row, <code>@b1</code> the default bottom row " + "(otherwise <code>//Command</code>), <code>@a2</code> to " + "put into second top row and so on:<br />" + "<code>@a2<br />./No_Spam /No_Spoilers<br />.Spoiler=/timeout $$1 600 no spoilers</code>"; } else { info += "<li>" + "Add custom submenus, <code>@Name of menu</code> on a line, " + "subsequent lines to put in that menu starting with a " + "<code>.</code> (point):<br />" + "<code>@Rules<br />./No_Spam /No_Spoilers<br />.Spoiler=/timeout $$1 600 no spoilers</code>" + "</li>"; } switch(type) { case "userDialog": info += "<li>" + "User Dialog specific parameters: " + "<code>$1</code> Name of user, " + "<code>$2-</code> Ban reason (if selected)" + "</li>"; break; case "streamsMenu": info += "<li>" + "Streams Context Menu specific parameters: " + "<code>$1-</code> Names of selected streams" + "</li>"; break; case "channelMenu": info += "<li>" + "Channel Context Menu specific parameters: " + "<code>$1</code> Name of currently active channel " + "(without leading #)" + "</li>"; break; case "userMenu": info += "<li>" + "User Context Menu specific parameters: " + "<code>$1</code> Name of the user" + "</li>"; break; } info += "</ul>"; if (type.equals("userDialog")) { info += "<p><em>Note:</em> You can also add [help-commands:shortcuts shortcuts] in brackets, " + "which can be triggered when the User Dialog has focus " + "(<code>/Ban[B]</code>)."; } info += INFO_MORE; return info; } private static final String INFO_HEADER = "<html>" + "<style type='text/css'>" + "code { background: white; color: black; }" + "p { margin: 2px; }" + "ul { margin-left: 10px; }" + "li { margin-top: 2px; }" + "</style>" + "<body style='width:300px;font-weight:normal;'>"; private static final String INFO_MORE = "<p>See the help for more information on " + "[help-commands: Custom Commands] and adding them to " + "[help-commands:menus Menus/User Dialog Buttons].</p>"; private static final String INFO_COMMANDS = INFO_HEADER + "<p>Each entry is one custom command:<br /><code>/commandName Text to send to chat or regular command</code></p>" + "<p>Parameters (replaced when executing the command): " + "<code>$1</code> first parameter (optional), <code>$$1</code> first parameter (required) " + ", <code>$2-</code> second parameter to end.</p>" + "<p>Example: <code>/hello /me welcomes $$1 to chat</code></p>" + "<p>Backslash (<code>\\</code>) is used as an " + "escape character, which means the subsequent character is " + "taken literal (instead of a special meaning). Example: " + "<code>\\$1</code> would output <code>$1</code> instead of " + "being replaced with the first parameter. To have the " + "<code>\\</code> itself show up you have to escape it as well " + "(<code>\\\\</code> shows up as <code>\\</code>).</p>" + "<p>You can restrict commands to a channel by adding it " + "to the command name: <code>/hello#joshimuz /me welcomes ..</code></p>" + INFO_MORE; public CommandSettings(SettingsDialog d) { super(true); JPanel base = addTitledPanel("Custom Commands", 0, true); GridBagConstraints gbc; gbc = d.makeGbc(0, 0, 1, 1); ListSelector items = d.addListSetting("commands", 400, 150, true, true); items.setDataFormatter(new DataFormatter<String>() { @Override public String format(String input) { return input.trim(); } }); items.setTester(new Editor.Tester() { @Override public void test(Component component, int x, int y, String value) { CustomCommand command = null; String[] split = value.split(" ", 2); if (split.length == 2) { command = CustomCommand.parse(split[1].trim()); } showCommandInfoPopup(component, command); } }); items.setInfo(INFO_COMMANDS); items.setInfoLinkLabelListener(d.getLinkLabelListener()); gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1; gbc.weighty = 1; base.add(items, gbc); JPanel menus = addTitledPanel("Menu/Button Commands", 1); Editor.Tester menuTester = new Editor.Tester() { @Override public void test(Component component, int x, int y, String value) { ContextMenu m = new TestContextMenu(value); m.show(component, x, y); } }; gbc = d.makeGbc(0, 0, 1, 1); gbc.anchor = GridBagConstraints.EAST; menus.add(new JLabel("User Context Menu:"), gbc); gbc = d.makeGbc(1, 0, 1, 1); EditorStringSetting userContextMenu = d.addEditorStringSetting("userContextMenu", 20, true, "Edit User Context Menu:", true, getInfo("userMenu"), menuTester); userContextMenu.setLinkLabelListener(d.getLinkLabelListener()); menus.add(userContextMenu, gbc); gbc = d.makeGbc(0, 1, 1, 1); gbc.anchor = GridBagConstraints.EAST; menus.add(new JLabel("Channel Context Menu:"), gbc); gbc = d.makeGbc(1, 1, 1, 1); EditorStringSetting channelContextMenu = d.addEditorStringSetting("channelContextMenu", 20, true, "Edit Channel Context Menu:", true, getInfo("channelMenu"), menuTester); channelContextMenu.setLinkLabelListener(d.getLinkLabelListener()); menus.add(channelContextMenu, gbc); gbc = d.makeGbc(0, 2, 1, 1); gbc.anchor = GridBagConstraints.EAST; menus.add(new JLabel("Streams Context Menu:"), gbc); gbc = d.makeGbc(1, 2, 1, 1); EditorStringSetting streamsContextMenu = d.addEditorStringSetting("streamsContextMenu", 20, true, "Edit Streams Context Menu:", true, getInfo("streamsMenu"), menuTester); streamsContextMenu.setLinkLabelListener(d.getLinkLabelListener()); menus.add(streamsContextMenu, gbc); gbc = d.makeGbc(0, 3, 1, 1); gbc.anchor = GridBagConstraints.EAST; menus.add(new JLabel("User Dialog Buttons:"), gbc); gbc = d.makeGbc(1, 3, 1, 1); EditorStringSetting userDialogButtons = d.addEditorStringSetting("timeoutButtons", 20, true, "Edit User Dialog Buttons:", true, getInfo("userDialog")); userDialogButtons.setLinkLabelListener(d.getLinkLabelListener()); menus.add(userDialogButtons, gbc); } public static void showCommandInfoPopup(Component parent, CustomCommand command) { String message = "<p style='font-family:sans-serif;'>This shows how the " + "parser understands the part to be executed. It may not be " + "very obvious what it means, but it can be helpful for " + "debugging.</p><br />"; if (command == null) { message += "No command."; } else if (command.hasError()) { message += Helper.htmlspecialchars_encode(command.getError()); } else { message += Helper.htmlspecialchars_encode(command.toString()); } GuiUtil.showNonModalMessage(parent, "Custom Command", message, JOptionPane.INFORMATION_MESSAGE, true); } }