VaadinIRC.GUI.channelGUI.java Source code

Java tutorial

Introduction

Here is the source code for VaadinIRC.GUI.channelGUI.java

Source

/**
 * Copyright (C) 2012 Aleksi Postari (@kulttuuri, aleksi@postari.net)
 * License type: MIT (http://en.wikipedia.org/wiki/MIT_License)
 * This code is part of project Vaadin Irkkia.
 * License in short: You can use this code as you wish, but please keep this license information intach or credit the original author in redistributions.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 
 * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package VaadinIRC.GUI;

import irc.IRCHelper;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import VaadinIRC.settings;
import VaadinIRC.GUI.componentContainers.ChannelGUIComponentContainer;
import VaadinIRC.VaadinIRC.VaIRCInterface;
import VaadinIRC.VaadinIRC.VaadinIRC;

import com.google.gwt.soyc.Settings;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.event.Action;
import com.vaadin.event.Action.Handler;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.event.ShortcutAction;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutListener;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.ThemeResource;
import com.vaadin.terminal.gwt.client.RenderInformation.Size;
import com.vaadin.ui.AbstractLayout;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TabSheet.Tab;
import com.vaadin.ui.Table;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;

/**
 * GUI for VaadinIRC channel.
 * @author Aleksi Postari
 *
 */
public class channelGUI extends ChannelGUIComponentContainer
        implements Button.ClickListener, Serializable, Handler, ItemClickListener, FocusListener, BlurListener {
    /** Name of the channel. */
    private String channelName;
    /** Reference to IRCInterface. */
    private VaIRCInterface ircInterface;
    /** Reference to VaadinIRC */
    private VaadinIRC vaIRC;
    /** Amount of messages sent into the channel. If they are over {@link settings#MAX_CHANNEL_MESSAGES} all old messages will be cleared from the channel. */
    private int channelMessages = 0;

    /** User table right click option whois. */
    private static final Action ACTION_WHOIS = new Action("Whois");
    /** User table right click option private chat. */
    private static final Action ACTION_PRIVMSG = new Action("Private chat");
    /** User table right click option op. */
    private static final Action ACTION_OP = new Action("Op");
    /** User table right click option voice. */
    private static final Action ACTION_VOICE = new Action("Voice");
    /** All user table right click actions. */
    private static final Action[] ACTIONS_NICKNAMES = new Action[] { ACTION_WHOIS, ACTION_PRIVMSG, ACTION_OP,
            ACTION_VOICE };

    /**
     * Constructor to create new Channel GUI object.
     * @param channelName Name of the channel.
     * @param vaIRC Reference to VaadinIRC.
     * @param ircInterface Reference to ircInterface.
     */
    public channelGUI(String channelName, VaadinIRC vaIRC, VaIRCInterface ircInterface) {
        super(null);
        this.channelName = channelName;
        this.vaIRC = vaIRC;
        this.ircInterface = ircInterface;
        //this.ircChannel = new IRCChannel(channelName, networkName);
        labelTitle = new Label("", Label.CONTENT_RAW);
        panelMessages = new Panel();
        tableNicknames = new Table();
        textfieldMessagefield = new TextField();
        buttonSendMessage = new Button("Send");
        buttonSettings = new Button("");
        buttonChangeNick = new Button("");
        buttonRefreshUsernames = new Button("");
    }

    /**
     * Adds standard channel message to the channel textarea. Repaints the panel and scrolls to bottom.
     * @param username Message sender's nickname.
     * @param newMessage Message to be sent.
     */
    public void addStandardChannelMessage(String username, String newMessage) {
        channelMessages++;
        if (channelMessages > settings.MAX_CHANNEL_MESSAGES) {
            panelMessages.removeAllComponents();
            channelMessages = 0;
        }

        newMessage = IRCHelper.removeTags(newMessage);
        newMessage = IRCHelper.convertURLsToHTMLLinks(newMessage);
        newMessage = IRCHelper.formatIRCTextToHTML(newMessage);

        Label label = new Label(IRCHelper.getTimestamp(false) + "<b>" + username + "</b> " + newMessage);
        label.setContentMode(Label.CONTENT_RAW);
        label.setWidth(550, Sizeable.UNITS_PIXELS);
        panelMessages.addComponent(label);

        // Scroll messages panel to bottom message
        panelMessages.setScrollTop(Short.MAX_VALUE);
        panelMessages.requestRepaint();

        ircInterface.setNewActivityToTab(channelName);
        ircInterface.pushChangesToClient();
    }

    /**
     * Adds new message to the channel textarea, repaints the panel and scrolls to bottom.
     * @param newMessage Message to be added.
     */
    public void addMessageToChannelTextarea(String newMessage) {
        channelMessages++;
        if (channelMessages > settings.MAX_CHANNEL_MESSAGES) {
            panelMessages.removeAllComponents();
            System.out.println("Removing all labels!!!");
            channelMessages = 0;
        }

        newMessage = IRCHelper.removeTags(newMessage);
        newMessage = IRCHelper.convertURLsToHTMLLinks(newMessage);

        Label label = new Label(IRCHelper.getTimestamp(false) + newMessage);
        label.setContentMode(Label.CONTENT_RAW);
        label.setWidth(100, Sizeable.UNITS_PERCENTAGE);
        panelMessages.addComponent(label);

        // Scroll messages panel to bottom message
        panelMessages.setScrollTop(Short.MAX_VALUE);
        panelMessages.requestRepaint();

        ircInterface.setNewActivityToTab(channelName);
        ircInterface.pushChangesToClient();
    }

    /**
     * Returns the channel name.
     * @return Channel name.
     */
    public String getChannelName() {
        return channelName;
    }

    /**
     * Clears nickname table for this channel and sets sent nicknames to the table.
     * @param nicknames ArrayList of nicknames.
     */
    public void addChannelUsersToTable(ArrayList<String> nicknames) {
        tableNicknames.removeAllItems();
        for (String nickname : nicknames)
            addUserToChannel(nickname);
        sortNicknameTable();
        ircInterface.pushChangesToClient();
    }

    /**
     * Adds user to channel table.
     * User will only be added if it did exist.
     * @param nickname Nickname to be added.
     */
    public void addUserToChannel(String nickname) {
        String userLevel = "";
        if (nickname.startsWith("@")) {
            userLevel = "@";
            nickname = nickname.substring(1);
        } else if (nickname.startsWith("+")) {
            userLevel = "+";
            nickname = nickname.substring(1);
        }

        tableNicknames.addItem(new Object[] { userLevel, nickname }, new Integer(tableNicknames.size()));
        sortNicknameTable();
        ircInterface.pushChangesToClient();
    }

    /**
     * Changes given user nickname. Does not alter the user level (leaves it to the same it was before for the nickname)
     * @param nickname Nickname of the user without user level tag.
     * @param newNickname New nickname which you want the nickname to be changed to without user level tag.
     * @return Returns true if user was found and nickname changed. Otherwise false.
     */
    public boolean changeUserNickname(String nickname, String newNickname) {
        List<Property> foundUsers = new ArrayList<Property>();
        // Iterate through all table items in row Nicknames and get all found rows to list
        for (Object id : tableNicknames.getItemIds()) {
            String row = (String) tableNicknames.getContainerProperty(id, "Nicknames").getValue();
            if (row.toString().trim().equals(nickname.toString().trim())) {
                foundUsers.add(tableNicknames.getContainerProperty(id, "Nicknames"));
            }
        }

        // Change nickname on found users.
        for (Property id : foundUsers) {
            id.setValue(newNickname);
            addMessageToChannelTextarea(nickname + " is now known as " + newNickname);
        }
        sortNicknameTable();
        ircInterface.pushChangesToClient();
        return false;
    }

    /**
     * Removes user from channel table if it did exist there.
     * Deletes all found users, so if user was somehow added multiple times to table,
     * all the user nicknames will be removed from channel table.
     * @param nickname Nickname to be removed.
     * @param reason Quit reason.
     * @param announceReason Announce reason message?
     */
    public void removeUserFromChannel(String nickname, String reason, boolean announceReason) {
        List<Object> toDelete = new ArrayList<Object>();

        // Iterate through all table items in row Nicknames and get all found rows to list
        for (Object id : tableNicknames.getItemIds()) {
            String row = (String) tableNicknames.getContainerProperty(id, "Nicknames").getValue();
            if (row.toString().trim().equals(nickname.toString().trim()))
                toDelete.add(id);
        }

        // Delete all found items
        for (Object id : toDelete) {
            tableNicknames.removeItem(id);
            if (announceReason)
                addMessageToChannelTextarea(nickname + " " + reason);
        }
        sortNicknameTable();
        ircInterface.pushChangesToClient();
    }

    /**
     * Styles the channel GUI components.
     */
    public void styleComponents() {
        // Style title label
        labelTitle.setStyleName("channelTitleLabel");
        labelTitle.setSizeFull();
        // Style messages panel
        panelMessages.setSizeFull();
        panelMessages.setScrollable(true);
        // Style nicknames panel
        tableNicknames.setSizeFull();
        tableNicknames.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN);
        tableNicknames.setColumnWidth("Rights", 1);
        tableNicknames.setColumnAlignment("Rights", Table.ALIGN_RIGHT);
        tableNicknames.setColumnAlignment("Nicknames", Table.ALIGN_LEFT);
        // Style messagefield
        textfieldMessagefield.setStyleName("channelMessageTextfield");
        textfieldMessagefield.setWidth(100, Sizeable.UNITS_PERCENTAGE);
        textfieldMessagefield.setHeight(100, Sizeable.UNITS_PERCENTAGE);
        // Style send message button
        buttonSendMessage.setStyleName("buttonSendMessage");
        buttonSendMessage.setHeight(100, Sizeable.UNITS_PERCENTAGE);
        // Style settings button
        buttonSettings.setIcon(new ThemeResource("images/cog.png"));
        buttonSettings.setWidth(33, Sizeable.UNITS_PIXELS);
        buttonSettings.setDescription("Settings");
        buttonSettings.addListener(new ClickListener() {
            public void buttonClick(ClickEvent event) {
                vaIRC.showSettingsWindow();
            }
        });
        // Style change nickname button
        buttonChangeNick.setIcon(new ThemeResource("images/user_edit.png"));
        buttonChangeNick.setWidth(33, Sizeable.UNITS_PIXELS);
        buttonChangeNick.setDescription("Change nickname");
        buttonChangeNick.addListener(new ClickListener() {
            public void buttonClick(ClickEvent event) {
                vaIRC.showNicknameChangeWindow();
            }
        });
        // Style refresh nicknames button
        buttonRefreshUsernames.setIcon(new ThemeResource("images/arrow_refresh.png"));
        buttonRefreshUsernames.setWidth(33, Sizeable.UNITS_PIXELS);
        buttonRefreshUsernames.setDescription("Refresh channel usernames");
        buttonRefreshUsernames.addListener(new ClickListener() {
            public void buttonClick(ClickEvent event) {
                refreshNicknameList();
            }
        });

        // Add action listeners
        buttonSendMessage.addListener((Button.ClickListener) this);
        getChannelGUI().addAction(new ShortcutListener(channelName, KeyCode.ENTER, null) {
            @Override
            public void handleAction(Object sender, Object target) {
                if (isMsgTextfieldFocused)
                    sendMessage(textfieldMessagefield.getValue().toString());
            }
        });
        tableNicknames.addListener((ItemClickListener) this);
        tableNicknames.addActionHandler((Action.Handler) this);
        textfieldMessagefield.addListener((FocusListener) this);
        textfieldMessagefield.addListener((BlurListener) this);
    }

    /**
     * Creates the GUI for a channel.
     */
    public void createChannelGUI() {
        panel = new Panel();
        panel.setCaption(channelName);
        panel.setSizeFull();
        panel.getContent().setSizeFull();
        AbstractLayout panelLayout = (AbstractLayout) panel.getContent();
        panelLayout.setMargin(false);
        panel.setImmediate(true);
        labelTitle.setValue("<b>" + channelName + "</b>");

        VerticalLayout mainVerticalLayout = new VerticalLayout();
        mainVerticalLayout.setSizeFull();
        // Top bar containing channel title & topright buttons
        GridLayout topGrid = new GridLayout(2, 1);
        topGrid.setStyleName("topBar");
        topGrid.addComponent(labelTitle);
        topGrid.setSizeFull();
        labelTitle.setSizeFull();
        HorizontalLayout hori = new HorizontalLayout();
        hori.setStyleName("rightTopBar");
        hori.setWidth(100, Sizeable.UNITS_PIXELS);
        hori.addComponent(buttonSettings);
        hori.addComponent(buttonChangeNick);
        hori.addComponent(buttonRefreshUsernames);
        topGrid.addComponent(hori);
        topGrid.setComponentAlignment(hori, Alignment.TOP_RIGHT);
        mainVerticalLayout.addComponent(topGrid);
        mainVerticalLayout.setExpandRatio(topGrid, 0.05f);
        // Message area & table of nicknames
        HorizontalLayout horizontal = new HorizontalLayout();
        horizontal.setSpacing(false);
        horizontal.setMargin(false);
        horizontal.setSizeFull();
        horizontal.addComponent(panelMessages);
        mainVerticalLayout.addComponent(horizontal);
        mainVerticalLayout.setExpandRatio(horizontal, 0.90f);
        if (channelName.startsWith("#")) {
            horizontal.addComponent(tableNicknames);
            horizontal.setExpandRatio(panelMessages, 0.8f);
            horizontal.setExpandRatio(tableNicknames, 0.2f);
        }
        // Send message textfield & send button
        HorizontalLayout bottomBar = new HorizontalLayout();
        //bottomBar.setWidth(100, Sizeable.UNITS_PERCENTAGE);
        bottomBar.setSizeFull();
        //bottomBar.setSpacing(true);
        //bottomBar.setMargin(true, false, false, false);
        bottomBar.addComponent(textfieldMessagefield);
        bottomBar.addComponent(buttonSendMessage);
        bottomBar.setExpandRatio(textfieldMessagefield, 1f);
        bottomBar.setExpandRatio(buttonSendMessage, 0f);
        mainVerticalLayout.addComponent(bottomBar);
        mainVerticalLayout.setExpandRatio(bottomBar, 0.05f);

        horizontal.setImmediate(true);
        panelMessages.setImmediate(true);
        tableNicknames.setImmediate(true);
        textfieldMessagefield.setImmediate(true);
        tableNicknames.addContainerProperty("Rights", String.class, null);
        tableNicknames.addContainerProperty("Nicknames", String.class, null);
        tableNicknames.setSelectable(true);

        textfieldMessagefield.focus();

        //mainVerticalLayout.setSizeFull();
        panel.addComponent(mainVerticalLayout);
    }

    /**
     * Returns the panel containing reference to this channel's graphical user interface.
     * @return Reference to channel GUI member variable.
     */
    public Panel getChannelGUI() {
        if (panel == null)
            createChannelGUI();
        return panel;
    }

    /**
     * Sends message to server.
     * If text does not start with slash: adds the current message to channel GUI and writes to IRC.
     * If command starts with slash, directly sends the command without slash to server write buffer.
     * @param message Message to be sent.
     */
    private void sendMessage(String message) {
        if (message == null || message.trim().equalsIgnoreCase(""))
            return;

        if (!ircInterface.isConnectionRunning()) {
            ircInterface.receivedNoConnectionInitializedMessage();
            textfieldMessagefield.setValue("");
            ircInterface.pushChangesToClient();
            return;
        }

        if (settings.debug) {
            ircInterface.debugSendMessage(message);
            return;
        }

        if (message.startsWith("/")) {
            ircInterface.sendMessageToServer(message);
        } else {
            // Channel messages cannot be sent if channel is "status".
            if (channelName.equals("status"))
                return;

            ircInterface.sendMessageToChannel(channelName, message);
        }
        textfieldMessagefield.setValue("");
        ircInterface.pushChangesToClient();
    }

    /**
     * Queries new list of nicknames from the server.
     */
    private void refreshNicknameList() {
        if (channelName.startsWith("#"))
            sendMessage("/NAMES " + channelName);
    }

    /**
     * Sorts the table containing the nicknames.
     */
    private void sortNicknameTable() {
        tableNicknames.sort(new Object[] { "Rights", "Nicknames" }, new boolean[] { false, false });
    }

    /**
     * Sets the channel topic.
     * @param topic Topic.
     */
    public void setChannelTopic(String topic) {
        labelTitle.setValue("<b>" + channelName + "</b> <small><small>" + topic + "</small></small>");
        ircInterface.pushChangesToClient();
    }

    /**
     * Sets level for user (opped, voiced, normal user).
     * @param nickname Who is going to have this change.
     * @param newLevel New level. This can be +o, -o, +v, -v.
     * @return Returns true if user was found and level changed. Otherwise false.
     */
    public boolean setUserLevel(String nickname, String newLevel) {
        List<Property> foundUsers = new ArrayList<Property>();
        // Iterate through all table items in row Nicknames and get found nickname level row references to list
        for (Object id : tableNicknames.getItemIds()) {
            String row = (String) tableNicknames.getContainerProperty(id, "Nicknames").getValue();
            if (row.toString().trim().equals(nickname.toString().trim()))
                foundUsers.add(tableNicknames.getContainerProperty(id, "Rights"));
        }

        // Change userlevel on found users
        for (Property id : foundUsers) {
            String oldLevel = id.getValue().toString();
            if (newLevel.startsWith("+")) {
                String lvl = newLevel.substring(1, 2);
                //System.out.println("old value: " + oldLevel + " & new val: " + lvl);
                if (oldLevel.equals("") && lvl.equals("o")) {
                    id.setValue("@");
                    addMessageToChannelTextarea("User " + nickname + " was opped.");
                    sortNicknameTable();
                    return true;
                } else if (oldLevel.equals("") && lvl.equals("v")) {
                    id.setValue("+");
                    addMessageToChannelTextarea("User " + nickname + " was voiced.");
                    sortNicknameTable();
                    return true;
                } else if (oldLevel.equals("+") && lvl.equals("o")) {
                    id.setValue("@");
                    addMessageToChannelTextarea("User " + nickname + " was opped.");
                    sortNicknameTable();
                    return true;
                }
                return false;
            } else if (newLevel.startsWith("-")) {
                String lvl = newLevel.substring(1, 2);
                if (oldLevel.equals("@") && lvl.equals("o")) {
                    id.setValue("");
                    addMessageToChannelTextarea("User " + nickname + " was deopped.");
                    sortNicknameTable();
                    return true;
                } else if (oldLevel.equals("v") && lvl.equals("v")) {
                    id.setValue("");
                    addMessageToChannelTextarea("User " + nickname + " was devoiced.");
                    sortNicknameTable();
                    return true;
                } else if (oldLevel.equals("+") && lvl.equals("v")) {
                    id.setValue("");
                    addMessageToChannelTextarea("User " + nickname + " was devoiced.");
                    sortNicknameTable();
                    return true;
                } else
                    return false;
            }
        }
        ircInterface.pushChangesToClient();
        return false;
    }

    /**
     * When button is clicked.
     */
    public void buttonClick(ClickEvent event) {
        if (event.getComponent().equals(buttonSendMessage)) {
            sendMessage(textfieldMessagefield.getValue().toString());
        } else if (event.getComponent().equals(buttonSettings)) {
            vaIRC.showSettingsWindow();
        }
    }

    /**
     * Returns the nicknames list right menu actions.
     */
    public Action[] getActions(Object target, Object sender) {
        return ACTIONS_NICKNAMES;
    }

    /**
     * Handles the right mouse button action for user.
     */
    public void handleAction(Action action, Object sender, Object target) {
        if (ACTION_WHOIS == action) {
            ircInterface.sendMessageToServer("/WHOIS " + selectedNickname);
        } else if (ACTION_PRIVMSG == action) {
            ircInterface.sendMessageToServer("/QUERY " + selectedNickname);
        } else if (ACTION_OP == action) {
            ircInterface.sendMessageToServer("/MODE " + channelName + " +o " + selectedNickname);
        } else if (ACTION_VOICE == action) {
            ircInterface.sendMessageToServer("/MODE " + channelName + " +v " + selectedNickname);
        }
        ircInterface.pushChangesToClient();
    }

    /**
     * When nickname row in table of nicknames is clicked.
     */
    public void itemClick(ItemClickEvent event) {
        String selectedItem = event.getItem().getItemProperty("Nicknames").toString();
        if (selectedItem != null)
            selectedNickname = selectedItem;
    }

    /**
     * When textfield gets focus.
     */
    public void focus(FocusEvent event) {
        isMsgTextfieldFocused = true;
    }

    /**
     * When textfield loses focus.
     */
    public void blur(BlurEvent event) {
        isMsgTextfieldFocused = false;
    }
}