package floobits.windows; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.ui.components.JBList; import com.intellij.uiDesigner.core.GridConstraints; import floobits.actions.Summon; import floobits.common.RunLater; import floobits.common.protocol.FlooUser; import floobits.common.protocol.handlers.FlooHandler; import floobits.dialogs.SetPermissionsDialog; import floobits.impl.ContextImpl; import floobits.utilities.Colors; import floobits.utilities.Flog; import javax.swing.*; import javax.swing.border.TitledBorder; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.HashMap; public class ChatUserForm { class ClickPanel extends JPanel { public ClickPanel(final Runnable clickHandler) { super(); addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (clickHandler == null) { return; } if (SwingUtilities.isRightMouseButton(e)) { return; } clickHandler.run(); } @Override public void mouseEntered(MouseEvent e) { Cursor cursor; Cursor.getDefaultCursor(); cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); setCursor(cursor); } }); } } private final String gravatar; private JList clientList; private JPanel gravatarContainer; private JPanel containerPanel; private JPanel subContainer; private DefaultListModel clientModel; private JPopupMenu menuPopup; private ContextImpl context; private String username; private boolean following = false; private HashMap<Integer, ClientState> clients = new HashMap<Integer, ClientState>(); protected class ClientChatActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { FlooHandler flooHandler = context.getFlooHandler(); if (flooHandler == null) { return; } clientActionPerformed(flooHandler, e); } protected void clientActionPerformed(FlooHandler flooHandler, ActionEvent e) { } } static private class ClientState { public JMenuItem mi; public String label; public int userId; public ClientState(int userId, JMenuItem mi, String label) { this.userId = userId; this.mi = mi; this.label = label; } } private static class ClientCellRenderer extends JLabel implements ListCellRenderer { private static final long serialVersionUID = 1L; @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { setText((String) value); setOpaque(false); return this; } } public ChatUserForm(ContextImpl context, String username, String gravatar) { this.context = context; this.username = username; this.gravatar = gravatar; setupPopupMenu(); containerPanel.setComponentPopupMenu(menuPopup); updateBorder(); updateGravatar(); } public void setFollowing(boolean following) { this.following = following; updateBorder(); } private void setFollowState(FlooHandler flooHandler, String msg) { flooHandler.state.setFollowedUsers(flooHandler.state.followedUsers); flooHandler.context.statusMessage(msg); } private void kickClient(int userId) { Flog.info("Kicking %s with user id %d.", username, userId); FlooHandler flooHandler = context.getFlooHandler(); if (flooHandler == null) { return; } flooHandler.editorEventHandler.kick(userId); } private JMenuItem addKickMenuItem(final int userId, String label) { final JMenuItem kickMenuItem = new JMenuItem(label); kickMenuItem.addActionListener(new ClientChatActionListener() { @Override public void clientActionPerformed(FlooHandler flooHandler, ActionEvent e) { kickClient(userId); } }); menuPopup.add(kickMenuItem); return kickMenuItem; } private void setupPopupMenu() { final JPopupMenu popupMenu = menuPopup; final JMenuItem followMenuItem = new JMenuItem("Follow"); followMenuItem.addActionListener(new ClientChatActionListener() { @Override public void clientActionPerformed(FlooHandler flooHandler, ActionEvent e) { Flog.info("Following %s.", username); if (flooHandler.state.followedUsers.contains(username)) { flooHandler.context.errorMessage(String.format("You are already following %s", username)); return; } flooHandler.state.followedUsers.add(username); setFollowState(flooHandler, String.format("You are now following %s", username)); flooHandler.editorEventHandler.goToLastHighlight(username); } }); followMenuItem.setVisible(false); popupMenu.add(followMenuItem); final JMenuItem unFollowMenuItem = new JMenuItem("Stop following"); unFollowMenuItem.addActionListener(new ClientChatActionListener() { @Override public void clientActionPerformed(FlooHandler flooHandler, ActionEvent e) { Flog.info("Will stop following %s", username); if (!flooHandler.state.followedUsers.contains(username)) { flooHandler.context.errorMessage(String.format("You are not following %s", username)); return; } flooHandler.state.followedUsers.remove(username); setFollowState(flooHandler, String.format("You have stopped following %s", username)); } }); unFollowMenuItem.setVisible(false); popupMenu.add(unFollowMenuItem); final JMenuItem summonMenuItem = new JMenuItem("Summon user"); summonMenuItem.addActionListener(new ClientChatActionListener() { @Override public void clientActionPerformed(FlooHandler flooHandler, ActionEvent e) { ContextImpl context = (ContextImpl) flooHandler.context; Editor selectedTextEditor = FileEditorManager.getInstance(context.project).getSelectedTextEditor(); Summon.summon(selectedTextEditor, flooHandler.editorEventHandler, username, context); } }); popupMenu.add(summonMenuItem); final JMenuItem adminMenuItem = new JMenuItem("Edit Permissions..."); adminMenuItem.addActionListener(new ClientChatActionListener() { @Override public void clientActionPerformed(FlooHandler flooHandler, ActionEvent e) { final int userId = clients.entrySet().iterator().next().getKey(); Flog.info("Opening up permission dialog for %s", username); FlooUser user = flooHandler.state.getUser(userId); if (user == null) { return; } java.util.List<String> permissions = java.util.Arrays.asList(user.perms); SetPermissionsDialog setPermissionsDialog = new SetPermissionsDialog( new RunLater<String[]>() { @Override public void run(String[] permissions) { Flog.info("Submitting permission changes."); FlooHandler flooHandler = context.getFlooHandler(); if (flooHandler == null) { return; } flooHandler.editorEventHandler.changePerms(userId, permissions); } }, permissions.contains("get_buf"), permissions.contains("request_perms"), permissions.contains("patch"), permissions.contains("kick") ); setPermissionsDialog.setUsername(username); setPermissionsDialog.createCenterPanel(); setPermissionsDialog.show(); } }); popupMenu.add(adminMenuItem); String kickAllLabel; if (username == null) { kickAllLabel = "Kick all clients for this user."; } else { kickAllLabel = String.format("Kick all of %s's clients", username); } final JMenuItem kickMenuItem = new JMenuItem(kickAllLabel); kickMenuItem.addActionListener(new ClientChatActionListener() { @Override public void clientActionPerformed(FlooHandler flooHandler, ActionEvent e) { for (ClientState client : clients.values()) { kickClient(client.userId); } } }); popupMenu.add(kickMenuItem); popupMenu.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { FlooHandler floohandler = context.getFlooHandler(); if (floohandler == null) { return; } kickMenuItem.setEnabled(floohandler.state.can("kick")); adminMenuItem.setEnabled(floohandler.state.can("kick")); if (floohandler.state.username.equals(username)) { return; } followMenuItem.setVisible(!following); unFollowMenuItem.setVisible(following); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { } @Override public void popupMenuCanceled(PopupMenuEvent e) { } }); } private void createUIComponents() { gravatarContainer = new ClickPanel(new Runnable() { @Override public void run() { FlooHandler flooHandler = context.getFlooHandler(); if (flooHandler == null) { return; } flooHandler.editorEventHandler.goToLastHighlight(username); } }); subContainer = new JPanel(); clientModel = new DefaultListModel(); clientList = new JBList(); clientList.setOpaque(false); clientList.setModel(clientModel); clientList.setCellRenderer(new ClientCellRenderer()); menuPopup = new JPopupMenu(); subContainer.setComponentPopupMenu(menuPopup); clientList.setComponentPopupMenu(menuPopup); gravatarContainer.setComponentPopupMenu(menuPopup); } public void updateBorder() { TitledBorder border = (TitledBorder) containerPanel.getBorder(); String usernameStr = username; if (following) { usernameStr += "*"; } border.setTitle(usernameStr); containerPanel.validate(); } public void updateGravatar() { if (gravatar == null) { return; } if (gravatarContainer.getComponentCount() != 0) { return; } ContextImpl.BalloonState balloonState = context.gravatars.get(gravatar); if (balloonState == null) { return; } JLabel iconlabel = new JLabel(new ImageIcon(balloonState.largeGravatar)); iconlabel.setBorder(BorderFactory.createLineBorder(Colors.getColorForUser(username), 2)); gravatarContainer.add(iconlabel, new GridConstraints()); containerPanel.validate(); } public void addClient(String client, String platform, int userId) { String label = String.format("<html>· %s <small><i>(%s)</html></i></small>", client, platform); clientModel.addElement(label); JMenuItem mi = addKickMenuItem(userId, String.format("<html>Kick %s <small><i>(%s)</html></i></small>", client, platform)); clients.put(userId, new ClientState(userId, mi, label)); containerPanel.validate(); } private void refreshClientList() { clientModel.clear(); for (ClientState client : clients.values()) { clientModel.addElement(client.label); } containerPanel.validate(); } public void removeClient(int userId) { ClientState client = clients.get(userId); if (client == null) { return; } clients.remove(userId); menuPopup.remove(client.mi); refreshClientList(); } public int getNumClients() { return clients.size(); } public JPanel getContainerPanel() { return containerPanel; } }