Package com.valhalla.jbother.groupchat

Source Code of com.valhalla.jbother.groupchat.ChatRoomPanel

/*
Copyright (C) 2003 Adam Olsen

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package com.valhalla.jbother.groupchat;

import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.File;
import java.util.*;
import java.util.regex.*;

import javax.swing.*;
import javax.swing.text.JTextComponent;
import javax.swing.text.html.HTMLDocument;

import org.jivesoftware.smack.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smackx.Form;
import org.jivesoftware.smackx.muc.DiscussionHistory;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.packet.MUCUser;

import com.valhalla.gui.*;
import com.valhalla.jbother.*;
import com.valhalla.jbother.jabber.BuddyStatus;
import com.valhalla.jbother.jabber.MUCBuddyStatus;
import com.valhalla.jbother.jabber.smack.InvitationRejectionPacketListener;
import com.valhalla.jbother.plugins.events.MUCEvent;
import com.valhalla.pluginmanager.PluginChain;
import com.valhalla.settings.Settings;
import net.infonode.tabbedpanel.*;
import net.infonode.tabbedpanel.titledtab.*;
import net.infonode.util.*;

/**
* This is the panel that contains a groupchat conversation. It is placed in a
* JTabbedPane in GroupChat frame.
*
* @author Adam Olsen
*/
public class ChatRoomPanel extends JPanel implements LogViewerCaller,
        TabFramePanel, UserChooserListener {
    private ResourceBundle resources = ResourceBundle.getBundle(
            "JBotherBundle", Locale.getDefault());

    private MJTextArea textEntryArea = new MJTextArea(true,2, 0);

    private StringBuffer conversationText = new StringBuffer();

    private ConversationArea conversationArea = new ConversationArea();

    private JMenuItem logItem = new JMenuItem(resources.getString("viewLog")),
            newItem = new JMenuItem(resources.getString("joinRoom")),
            leaveItem = new JMenuItem(resources.getString("leaveRoom")),
            nickItem = new JMenuItem(resources.getString("changeNickname")),
            registerItem = new JMenuItem(resources.getString("registerForRoom")),
            viewAdmins = new JMenuItem(resources.getString("viewAdmins")),
            viewModerators = new JMenuItem(resources
                    .getString("viewModerators")), viewMembers = new JMenuItem(
                    resources.getString("viewMembers")),
            viewParticipants = new JMenuItem(resources
                    .getString("viewParticipants")),
            viewOwners = new JMenuItem(resources.getString("viewOwners")),
            viewOutcasts = new JMenuItem(resources.getString("viewOutcasts")),
            destroyRoom = new JMenuItem(resources.getString("destroyRoom")),
            invite = new JMenuItem(resources.getString("inviteUser"));

    private JPopupMenu popMenu = new JPopupMenu();
    private TitledTab tab;

    private int oldMaximum = 0;

    private JPanel scrollPanel = new JPanel(new GridLayout(1, 0));

    private JSplitPane mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);

    private MultiUserChat chat;

    private String chatroom, nickname, pass;

    private Hashtable buddyStatuses = new Hashtable();

    private GroupChatNickList nickList;

    private String subject = resources.getString("noSubject");

    private MJTextField subjectField = new MJTextField();

    private boolean listenersAdded = false;

    private GroupParticipantListener participantListener = new GroupParticipantListener(this);

    private InvitationRejectionPacketListener invitationRejectionPacketListener = new InvitationRejectionPacketListener();

    private GroupChatMessagePacketListener messageListener = new GroupChatMessagePacketListener(
            this);

    private SubjectListener subjectListener = new SubjectListener(this);

    private StatusListener statusListener = new StatusListener(this);

    private UserStatusListener userStatusListener = new UserStatusListener(this);

    private boolean messageToMe = false;
    private boolean removed = false;
    private int joins = 0;

    /**
     * This sets up the appearance of the chatroom window
     *
     * @param chatroom
     *            the chatroom address
     * @param nickname
     *            the nickname to use when joining
     */
    public ChatRoomPanel(String chatroom, String nickname, String pass) {
        this.chatroom = chatroom;
        this.nickname = nickname;
        this.pass = pass;
        chat = new MultiUserChat(BuddyList.getInstance().getConnection(),
                chatroom);

        BuddyList.getInstance().startTabFrame();

        setLayout(new BorderLayout(5, 5));
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        subjectField.setText(resources.getString("noSubject"));

        JPanel subjectPanel = new JPanel();
        subjectPanel.setLayout(new BorderLayout());
        subjectPanel.add(new JLabel("<html><b>"
                + resources.getString("subject") + ":&nbsp;&nbsp;</b></html>"),
                BorderLayout.WEST);
        subjectPanel.add(subjectField, BorderLayout.CENTER);

        add(subjectPanel, BorderLayout.NORTH);

        add(mainPanel);

        nickList = new GroupChatNickList(this);

        String divLocString = Settings.getInstance().getProperty(
                "chatWindowDividerLocation");
        int divLoc = 0;
        Dimension dimension = BuddyList.getInstance().getTabFrame().getSize();

        if (divLocString != null) {
            divLoc = Integer.parseInt(divLocString);
        } else {
            divLoc = (int) dimension.getWidth() - 127;
        }

        if (divLoc == 0)
            divLoc = (int) dimension.getWidth() - 127;

        mainPanel.setDividerLocation(divLoc);
        mainPanel.setOneTouchExpandable(true);
        mainPanel.setResizeWeight(1);
        mainPanel.addPropertyChangeListener("lastDividerLocation",
                new DividerListener("chatWindowDividerLocation"));

        conversationArea.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

        setUpPopMenu();

        scrollPanel.add(conversationArea);

        JSplitPane containerPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
                scrollPanel, new JScrollPane(textEntryArea));
        containerPanel.setResizeWeight(1);

        textEntryArea.setLineWrap(true);
        textEntryArea.setWrapStyleWord(true);

        divLocString = Settings.getInstance().getProperty(
                "chatRoomPanelDividerLocation");
        divLoc = 0;

        try {
            if (divLocString != null) {
                divLoc = Integer.parseInt(divLocString);
            } else {
                divLoc = (int) dimension.getWidth() - 100;
                Settings.getInstance().setProperty(
                        "chatRoomPanelDividerLocation", divLoc + "" );
            }
        } catch (NumberFormatException ex) {
        }

        if (divLoc == 0)
            divLoc = 290;
        containerPanel.setDividerLocation(divLoc);
        containerPanel.addPropertyChangeListener("lastDividerLocation",
                new DividerListener("chatRoomPanelDividerLocation"));
        containerPanel.repaint();

        mainPanel.add(containerPanel);
        mainPanel.add(nickList);

        textEntryArea.grabFocus();
        textEntryArea.setFocusTraversalKeysEnabled(false); //for disable focus
                                                           // traversal with TAB
        setSubject(subject);

        addListeners();
    }

    public void removed() { removed = true; }

    public void updateStyle(Font font){}

    public void setTab( TitledTab tab ) { this.tab = tab; }
    public TitledTab getTab() { return tab; }

    public ConversationArea getConversationArea() {
        return conversationArea;
    }

    public GroupChatNickList getGroupChatNickList() {
        return nickList;
    }

    public void removeMe()
    {
  nickList.removeBuddy(chatroom + "/" + nickname);
    }

    public void disconnect() {
        if(nickList != null) nickList.clear();
    }

    public void doAction(String command, MUCBuddyStatus buddy) {
        MUCUser user = buddy.getMUCUser();
        if (user == null) {
            serverErrorMessage(resources.getString("jidNotFound"));
            return;
        }

        MUCUser.Item item = user.getItem();

        if (item == null) {
            serverErrorMessage(resources.getString("jidNotFound"));
            return;
        }

        if (item.getJid() == null) {
            serverErrorMessage(resources.getString("jidNotFound"));
            return;
        }

        com.valhalla.Logger.debug("Running " + command + " on "
                + buddy.getUser());
        Thread thread = new Thread(new RunTaskThread(resources
                .getString("error")
                + ": ", command, item.getJid()));
        thread.start();
    }

    public String getUser() {
        return chat.getRoom() + "/" + chat.getNickname();
    }

    /**
     * @return true if the TabFrame panel listeners have already been added to
     *         this panel
     */
    public boolean listenersAdded() {
        return listenersAdded;
    }

    /**
     * Sets whether or not the TabFrame panel listeners have been added
     *
     * @param added
     *            true if they have been added
     */
    public void setListenersAdded(boolean added) {
        this.listenersAdded = added;
    }

    /**
     * @return the input area of this panel
     */
    public JComponent getInputComponent() {
        return textEntryArea;
    }

    /**
     * @return the JList representing the nicklist
     */
    public JList getNickList() {
        return nickList.getList();
    }

    /**
     * @return the text entry area
     */
    public JTextComponent getTextEntryArea() {
        return textEntryArea;
    }

    /**
     * Listens for a change in the divider location, and saves it for later
     * retreival
     *
     * @author Adam Olsen
     * @version 1.0
     */
    private class DividerListener implements PropertyChangeListener {
        String prop;

        public DividerListener(String prop) {
            this.prop = prop;
        }

        public void propertyChange(PropertyChangeEvent e) {
            if (e.getOldValue().toString().equals("-1"))
                return;
            Settings.getInstance()
                    .setProperty(prop, e.getOldValue().toString());
            BuddyList.getInstance().getTabFrame().saveStates();
        }
    }


    /**
     * Look for a right click, and show a pop up menu
     *
     * @author Adam Olsen
     * @version 1.0
     */
    class RightClickListener extends MouseAdapter {
        public void mousePressed(MouseEvent e) {
            checkPop(e);
        }

        public void mouseReleased(MouseEvent e) {
            checkPop(e);
        }

        public void mouseClicked(MouseEvent e) {
            checkPop(e);
        }

        public void checkPop(MouseEvent e) {
            // look for the popup trigger.. usually a right click
            if (e.isPopupTrigger()) {
                if (conversationArea.getSelectedText() == null) {
                    popMenu.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        }
    }

    /**
     * Add the various menu items to the popup menu
     */
    private void setUpPopMenu() {
        MenuItemListener listener = new MenuItemListener();

        conversationArea.getTextPane().addMouseListener(new RightClickListener());
        CopyPasteContextMenu.registerComponent(conversationArea.getTextPane());

        popMenu.add(nickItem);
        popMenu.add(newItem);
        popMenu.add(logItem);

        popMenu.addSeparator();

        popMenu.add(viewAdmins);
        popMenu.add(viewModerators);
        popMenu.add(viewMembers);
        popMenu.add(viewParticipants);
        popMenu.add(viewOwners);
        popMenu.add(viewOutcasts);
        popMenu.add(invite);
        popMenu.add(registerItem);
        popMenu.add(destroyRoom);

        popMenu.addSeparator();
        popMenu.add(leaveItem);

        logItem.addActionListener(listener);
        newItem.addActionListener(listener);
        leaveItem.addActionListener(listener);
        nickItem.addActionListener(listener);
        registerItem.addActionListener(listener);
        viewAdmins.addActionListener(listener);
        viewOutcasts.addActionListener(listener);
        viewMembers.addActionListener(listener);
        invite.addActionListener(listener);
        viewParticipants.addActionListener(listener);
        viewOwners.addActionListener(listener);
        viewModerators.addActionListener(listener);
        destroyRoom.addActionListener(listener);
    }

    /**
     * Listens for items to be selected in the menu
     *
     * @author Adam Olsen
     * @version 1.0
     */
    private class MenuItemListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == nickItem)
                changeNickHandler();
            else if (e.getSource() == leaveItem) {
                BuddyList.getInstance().getTabFrame().removePanel(ChatRoomPanel.this);
                BuddyList.getInstance().stopTabFrame();
            } else if (e.getSource() == newItem) {
                GroupChatBookmarks gc = new GroupChatBookmarks(BuddyList
                        .getInstance().getTabFrame());
                gc.load();
                gc.setVisible(true);
                gc.toFront();
            } else if (e.getSource() == logItem)
                new LogViewerDialog(ChatRoomPanel.this, getRoomName());
            else if (e.getSource() == registerItem)
                configurationHandler("registerFor");
            else if (e.getSource() == viewAdmins)
                new ListViewDialog(ChatRoomPanel.this, ListViewDialog.TYPE_ADMIN);
            else if (e.getSource() == viewOutcasts)
                new ListViewDialog(ChatRoomPanel.this, ListViewDialog.TYPE_OUTCASTS);
            else if (e.getSource() == viewMembers)
                new ListViewDialog(ChatRoomPanel.this, ListViewDialog.TYPE_MEMBERS);
            else if (e.getSource() == viewParticipants)
                new ListViewDialog(ChatRoomPanel.this,
                        ListViewDialog.TYPE_PARTICIPANTS);
            else if (e.getSource() == viewOwners)
                new ListViewDialog(ChatRoomPanel.this, ListViewDialog.TYPE_OWNERS);
            else if (e.getSource() == invite)
            {
                UserChooser chooser = new UserChooser(BuddyList.getInstance().getTabFrame(), resources.getString("inviteUser"));
                chooser.addListener(ChatRoomPanel.this);
                chooser.setVisible(true);
            }

            else if (e.getSource() == viewModerators)
                new ListViewDialog(ChatRoomPanel.this, ListViewDialog.TYPE_MODERATORS);
            else if (e.getSource() == destroyRoom)
                destroyHandler();
        }
    }
   
    public void usersChosen(UserChooser.Item[] items)
    {
        usersChosen((Object[])items);
    }

    /**
     *  Description of the Method
     *
     * @param  array  Description of the Parameter
     */
    public void usersChosen(Object[] us) {
        String result = (String) JOptionPane.showInputDialog(BuddyList.getInstance().getTabFrame(), resources
                .getString("enterReasonForInvite"), resources
                .getString("inviteUser"), JOptionPane.QUESTION_MESSAGE, null,
                null, "Come join us!");


         if(result == null || result.equals("")) return;
       
         if(us[0] instanceof String)
         {
            inviteUsers(new String[] {(String)us[0]}, result);
            return;
         }

         ArrayList u = new ArrayList();
         for(int i = 0; i < us.length; i++)
         {
             UserChooser.Item item = (UserChooser.Item)us[i];
             u.add(item.getJID());
         }
         inviteUsers((String[])u.toArray(new String[u.size()]), result);
    }


    protected void inviteUsers(final String[] users, final String reason) {
        Thread thread = new Thread(new Runnable() {
            public void run() {
                for(int i = 0; i < users.length; i++)
                {
                    chat.invite(users[i], reason);
                }
            }
        });

        thread.start();

    }

    private void destroyHandler() {
        final int r = JOptionPane.showConfirmDialog(BuddyList.getInstance()
                .getTabFrame(), resources.getString("sureDestroyRoom"),
                resources.getString("destroyRoom"), JOptionPane.YES_NO_OPTION);

        if (r == JOptionPane.YES_OPTION) {
            final String reason = (String) JOptionPane.showInputDialog(
                    BuddyList.getInstance().getTabFrame(), resources
                            .getString("enterReasonForDestroy"), resources
                            .getString("destroyRoom"),
                    JOptionPane.QUESTION_MESSAGE, null, null,
                    "Room has been moved");

            if (reason == null)
                return;

            final String result = (String) JOptionPane.showInputDialog(
                    BuddyList.getInstance().getTabFrame(), resources
                            .getString("enterAlternate"), resources
                            .getString("destroyRoom"),
                    JOptionPane.QUESTION_MESSAGE, null, null, "");

            if (result == null)
                return;

            new Thread(new DestroyThread(reason, result)).start();
        }
    }

    class DestroyThread implements Runnable {
        String reason, result;

        public DestroyThread(String reason, String result) {
            this.reason = reason;
            this.result = result;
        }

        public void run() {
            String error = null;
            try {
                chat.destroy(reason, result);
            } catch (XMPPException ex) {
                error = ex.getMessage();
            }

            final String e = error;

            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    if (e != null) {
                        serverErrorMessage(e);
                    } else {
                        serverErrorMessage("Room has been destroyed");
                    }
                }
            });
        }
    }

    /**
     * Collects a Data Form to be filled out
     *
     * @param type
     *            the type of form. Either "configure" or "registerFor"
     */
    public void configurationHandler(String type) {
        Thread thread = new Thread(new ConfigThread(type));
        thread.start();
    }

    /**
     * Collects the data form and displays it.
     *
     * @author Adam Olsen
     */
    private class ConfigThread implements Runnable {
        private String type = "configure";

        /**
         * @param type
         *            the type of form to collect.
         */
        public ConfigThread(String type) {
            this.type = type;
        }

        /**
         * Called by the enclosing thread
         */
        public void run() {
            try {
                Form temp;

                // get the form
                if (type.equals("configure")) {
                    temp = chat.getConfigurationForm();
                } else {
                    temp = chat.getRegistrationForm();
                }

                if (temp == null) {
                    serverErrorMessage(resources
                            .getString("couldNotCollectForm"));
                    return;
                }

                final Form form = temp;
                final JBDataForm f = new JBDataForm(BuddyList.getInstance().getTabFrame(), form);
                f.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        // if the cancel button is pressed, close the form
                        if (e.getActionCommand().equals("cancel")) {
                            SwingUtilities.invokeLater(new Runnable() {
                                public void run() {
                                    f.dispose();
                                }
                            });
                        }

                        // else submit the form
                        else if (e.getActionCommand().equals("ok")) {
                            SwingUtilities.invokeLater(new Runnable() {
                                public void run() {
                                    if (submitConfigurationForm(f, type)) {
                                        f.setVisible(false);
                                    }
                                }
                            });
                        }
                    }
                });

                // show the form
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        f.setVisible(true);
                    }
                });
            }

            // if there was an error collecting the form
            catch (XMPPException ex) {
                String message = ex.getMessage();
                if (ex.getXMPPError() != null) {
                    message = resources.getString("xmppError"
                            + ex.getXMPPError().getCode());
                }

                serverErrorMessage(resources.getString(type + "Room") + ": "
                        + message);
            }
        }
    }

    /**
     * Submits the form
     *
     * @param form
     *            the form to submit
     * @param type
     *            the type of form, either "configure" or "registerFor"
     * @return false if the required fields have not been filled out
     */
    private boolean submitConfigurationForm(JBDataForm form, final String type) {
        final Form answer = form.getAnswerForm();
        if (answer == null)
            return false;

        Thread thread = new Thread(new Runnable() {
            public void run() {
                try {
                    if (type.equals("configure")) {
                        chat.sendConfigurationForm(answer);
                    } else {
                        chat.sendRegistrationForm(answer);
                    }
                } catch (XMPPException ex) {
                }

                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        if (type.equals("configure")) {
                            serverNoticeMessage(resources
                                    .getString("configureSubmitted"));
                        } else {
                            serverNoticeMessage(resources
                                    .getString("registerSubmitted"));
                        }
                    }
                });
            }
        });
        thread.start();

        return true;
    }

    /**
     * Opens the log window for this chat room
     */
    public void openLogWindow() {
        new LogViewerDialog(this, getRoomName());
    }

    /**
     * Adds a buddy to the nickname list
     *
     * @param buddy
     *            the buddy to add
     */
    public void addBuddy(String buddy) {
        if( nickList == null || buddy == null ) return;
        nickList.addBuddy(buddy);
    }

    /**
     * Removes a buddy from the nick list
     *
     * @param buddy
     *            the buddy to remove
     */
    public void removeBuddy(String buddy) {
        if( nickList == null || buddy == null ) return;

        nickList.removeBuddy(buddy);
    }

    /**
     * Opens the log file
     */
    public void startLog() {
        // for loggingg
        if (Settings.getInstance().getBoolean("keepLogs")) {
            String logFileName = LogViewerDialog.getDateName() + ".log";
            String logFileDir = JBother.profileDir
                    + File.separatorChar
                    + "logs"
                    + File.separatorChar
                    + getRoomName().replaceAll("@", "_at_").replaceAll("\\/",
                            "-");

            File logDir = new File(logFileDir);

            if (!logDir.isDirectory() && !logDir.mkdirs())
                Standard.warningMessage(this, resources.getString("log"),
                        resources.getString("couldNotCreateLogDir"));

            String logEnc =
                Settings.getInstance().getProperty("keepLogsEncoding");
            conversationArea.setLogFile(new File(logDir, logFileName), logEnc);
        }
    }

    /**
     * Gets the BuddyStatus represending a user in the room
     *
     * @param user
     *            the BuddyStatus to get
     * @return the requested BuddyStatus
     */
    public MUCBuddyStatus getBuddyStatus(String user) {
        if (!buddyStatuses.containsKey(user)) {
            MUCBuddyStatus buddy = new MUCBuddyStatus(user);
            buddy.setMUC(chat);
            buddy.setName(user.substring(user.indexOf("/") + 1, user.length()));
            buddyStatuses.put(user, buddy);
        }

        return (MUCBuddyStatus) buddyStatuses.get(user);
    }

    /**
     * Returns the tab name for the TabFramePanel
     *
     * @return the panel name
     */
    public String getPanelName() {
        return getShortRoomName();
    }

    /**
     * Returns the tooltip for the tab in the TabFrame
     *
     * @return the tooltip for this tab in the tab frame
     */
    public String getTooltip() {
        return getRoomName();
    }

    /**
     * Returns the window title
     *
     * @return the window title for the TabFrame when this tab is selected
     */
    public String getWindowTitle() {
        return resources.getString("groupChat") + ": " + getRoomName();
    }

    /**
     * Gets the short room name - for example, if you are talking in
     * jdev@conference.jabber.org, it would return "jdev"
     *
     * @return short room name
     */
    public String getShortRoomName() {
        return chatroom.replaceAll("\\@.*", "");
    }

    /**
     * Gets the entire room name, server included
     *
     * @return gets the room address
     */
    public String getRoomName() {
        return chatroom;
    }

    /**
     * Returns the nickname of a user in a group chat.
     *
     * @param id
     *            The full id of someone in a room, ie:
     *            jdev@conference.jabber.org/synic
     * @return the nickname of the person in the room
     */
    public String getNickname(String id) {
        int index = id.indexOf("/");
        if (index == -1)
            return id;
        return id.substring(index + 1);
    }

    public MultiUserChat getChat() {
        return chat;
    }

    public GroupParticipantListener getParticipantListener() {
        return participantListener;
    }

    /**
     * Starts the groupchat. Sets up a thread to connect, and start that thread
     */
    public void startChat() {
        if (!BuddyList.getInstance().checkConnection())
            return;

        serverNoticeMessage("Connecting to " + getRoomName() + " ... ");
        BuddyList.getInstance().addTabPanel(this);

        JoinChatThread t = new JoinChatThread();
        t.start();

        startLog();
    }

    private void leaveChat() {
        if (chat == null)
            return;

        buddyStatuses.clear();
        com.valhalla.Logger.debug("Leaving " + chat.getRoom());
        Presence p = new Presence(Presence.Type.UNAVAILABLE);
        p.setTo(chat.getRoom());
        if (BuddyList.getInstance().checkConnection())
            BuddyList.getInstance().getConnection().sendPacket(p);
        chat.removeMessageListener(messageListener);
        chat.removeParticipantListener(participantListener);
        chat.removeSubjectUpdatedListener(subjectListener);
        chat.removeParticipantStatusListener(statusListener);
        chat.removeUserStatusListener(userStatusListener);
        chat.removeInvitationRejectionListener(invitationRejectionPacketListener);

        chat = null;
        System.gc();
    }

    /**
     * Asks for a new topic, then sets the new topic
     */
    private void topicHandler(final String subject) {
        Thread thread = new Thread(new Runnable() {
            public void run() {
                try {
                    chat.changeSubject(subject);
                } catch (final XMPPException e) {
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            String message = e.getMessage();
                            serverErrorMessage(resources
                                    .getString("errorSettingSubject")
                                    + ": " + message);
                        }
                    });
                }

                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        subjectField.setEnabled(true);
                    }
                });

            }
        });

        thread.start();
    }

    private class RunTaskThread implements Runnable {
        private String err, method;

        private Object param;

        public RunTaskThread(String err, String method, Object param) {
            this.err = err;
            this.method = method;
            this.param = param;
        }

        public void run() {
            java.lang.reflect.Method m;
            try {
                m = chat.getClass().getMethod(this.method,
                        new Class[] { param.getClass() });
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }

            try {
                m.invoke(chat, new Object[] { param });
            } catch (final java.lang.reflect.InvocationTargetException ex) {
                final XMPPException xmpp = (XMPPException) ex.getCause();
                if (xmpp == null)
                    return;

                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        serverErrorMessage(err
                                + ": "
                                + resources.getString("xmppError"
                                        + xmpp.getXMPPError().getCode()));
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Asks for a new nickname, and sends a nickname change request
     */
    private void changeNickHandler() {
        String result = (String) JOptionPane.showInputDialog(null, resources
                .getString("enterNickname"),
                resources.getString("setNickname"),
                JOptionPane.QUESTION_MESSAGE, null, null, chat.getNickname());

        if (result != null && !result.equals("")) {
            Thread thread = new Thread(new RunTaskThread(resources
                    .getString("couldNotChangeNick"), "changeNickname", result));
            thread.start();
        }
    }

    /**
     * Adds the event listeners for the various components in this chatwindows
     */
    public void addListeners() {
        //set up the window so you can press enter in the text box and
        //that will send the message.
        Action SendMessageAction = new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                sendHandler();
            }
        };

        Action nickCompletionAction = new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                nickCompletionHandler();
            }
        };

        //set it up so that if they drag in the conversation window, it grabs
        // the focus
        conversationArea.getTextPane().addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent e) {
                //conversationArea.grabFocus();
            }
        });

        //set it up so that if there isn't any selected text in the
        // conversation area
        //the textentryarea grabs the focus.
        conversationArea.getTextPane().addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent e) {
                if (conversationArea.getSelectedText() == null) {
                    textEntryArea.requestFocus();
                }
            }
        });

        Action closeAction = new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                BuddyList.getInstance().getTabFrame().removePanel(ChatRoomPanel.this);
                BuddyList.getInstance().stopTabFrame();
            }
        };

        subjectField.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                subjectField.setEnabled(false);
                topicHandler(subjectField.getText());
                setSubject(subject);
            }
        });

        KeyStroke enterStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
        textEntryArea.getInputMap().put(enterStroke, SendMessageAction);

        KeyStroke tabStroke = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
        textEntryArea.getInputMap().put(tabStroke, nickCompletionAction);

        textEntryArea.getInputMap().put(
                KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit
                        .getDefaultToolkit().getMenuShortcutKeyMask()),
                closeAction);

    }

    /**
     * Leaves this room and removes it from the groupchat frame
     */
    public void leave() {
        closeLog();
        leaveChat();
    } //leave the chatroom

    /**
     * Gets the nickname currently being used in the chat room
     *
     * @return the nickname being used in the chatroom
     */
    public String getNickname() {
        if (chat == null || chat.getNickname() == null)
            return nickname;
        return chat.getNickname();
    }

    /**
     * Displays a server notice message
     *
     * @param message
     *            the message to display
     */
    public void serverNoticeMessage(String message) {
        conversationArea.append(getDate(null));
        conversationArea.append(" -> " + message + "\n", ConversationArea.SERVER);
    }

    public void serverErrorMessage(String message) {
        conversationArea.append(getDate(null));
        conversationArea.append(" -> " + message + "\n", ConversationArea.SENDER);
    }

    /**
     * Receives a message
     *
     * @param from
     *            who it's from
     * @param message
     *            the message
     */
    public void receiveMessage(String from, String message,
            Date date) {

        String curNick = nickname;
        if( chat != null && chat.getNickname() != null) curNick = chat.getNickname();
        if (from.equals("")
                || from.toLowerCase().equals(chat.getRoom().toLowerCase())) {
            //server message
            serverNoticeMessage(message);
            return;
        } else {

            boolean highLightedSound = false;

            if (message.startsWith("/me ")) {
                message = message.replaceAll("^\\/me ", "");
                conversationArea.append(getDate(date));
                conversationArea.append(" *" + from+ " ", ConversationArea.SENDER, true);
                conversationArea.append(message + "\n", ConversationArea.BLACK);
            } else if (message.toLowerCase().replaceAll("<[^>]*>", "").matches(
                    ".*(^|\\W)" + curNick.toLowerCase() + "\\W.*") &&
                    !from.toLowerCase().equals(curNick.toLowerCase())) {
                TabbedPanel tabPane = BuddyList.getInstance().getTabFrame()
                        .getTabPane();

                if (tabPane.getSelectedTab().getContentComponent() != this)
                    messageToMe = true;
                conversationArea.append(getDate(date), Color.BLACK, false, ConversationArea.HL);
                conversationArea.append(" " +from + ": ", ConversationArea.RECEIVER, true, ConversationArea.HL);
                conversationArea.append(message + "\n", ConversationArea.BLACK, false, ConversationArea.HL);

                com.valhalla.jbother.sound.SoundPlayer
                        .play("groupHighlightedSound");

                if (!BuddyList.getInstance().getTabFrame().isFocused()) {
                    NotificationPopup.showSingleton(BuddyList.getInstance()
                            .getTabFrame(), resources
                            .getString("messageReceived"), "<b>"
                            + resources.getString("from") + ":</b>&nbsp;&nbsp;"
                            + from,this);
                }

                highLightedSound = true;
            } else {
                conversationArea.append(getDate(date));
                conversationArea.append(" " + from +": ", ConversationArea.RECEIVER, true);
                conversationArea.append(message + "\n", ConversationArea.BLACK);
            }

            if (!highLightedSound)
            {
                com.valhalla.jbother.sound.SoundPlayer
                        .play("groupReceivedSound");

                if( Settings.getInstance().getBoolean("usePopup") &&
                    Settings.getInstance().getBoolean("popupForGroupMessage" ))
                {
                   NotificationPopup.showSingleton(BuddyList.getInstance().getTabFrame(), resources
                            .getString("groupMessageReceived"), from,this);
                }
            }
        }

        // fire MUCEvent for message received
        PluginChain.fireEvent(new MUCEvent(from,
                MUCEvent.EVENT_MESSAGE_RECEIVED, message, date));

        int tabCount = BuddyList.getInstance().getTabFrame().markTab(this);
        try {
            TabbedPanel tabPane = BuddyList.getInstance().getTabFrame()
                    .getTabPane();
            if (tabPane.getSelectedTab().getContentComponent() != this && messageToMe) {
                String title = this.getShortRoomName() + " (" + tabCount + ")";
                if (messageToMe)
                    title = "*" + title;

                tab.setText(title);
            }
        } catch (Exception ex) {
        }
    }

    public void resetMessageToMe() {
        messageToMe = false;
    }

    /**
     * Closes the log file
     */
    public void closeLog() {
        conversationArea.closeLog();
    }

    /**
     * @return a String representing the current time the format:
     *         [Hour:Minute:Second]
     */
    public String getDate(Date d) {
        return ConversationPanel.getDate(d);
    }

    public MJTextField getSubjectField() {
        return subjectField;
    }

    /**
     * Sets the subject of the room
     *
     * @param subject
     *            the subject to set
     */
    public void setSubject(String subject) {
        this.subject = subject;
        if (BuddyList.getInstance().getTabFrame() != null)
            BuddyList.getInstance().getTabFrame().setSubject(this);

        subjectField.setText(subject);
        subjectField.setCaretPosition(0);
        subjectField.setToolTipText(subject);
    }

    /**
     * Returns the current room subject
     *
     * @return the current room subject
     */
    public String getSubject() {
        return this.subject;
    }

    /**
     * Gets all the buddy statuses in the room
     *
     * @return all BuddyStatuses
     */
    public Hashtable getBuddyStatuses() {
        return this.buddyStatuses;
    }

    /**
     * Sends the message currently in the textentryarea
     */
    private void sendHandler() {
        String text = textEntryArea.getText();

        Message message = chat.createMessage();
        message.setBody(text);

        if (!textEntryArea.getText().equals("")) {
            try {
                chat.sendMessage(message);
            } catch (XMPPException e) {
                com.valhalla.Logger.debug("Could not send message.");
            } catch (IllegalStateException ex) {
                serverErrorMessage(resources.getString("notConnected"));
            }

            textEntryArea.setText("");
        }
    }

    /**
     * Implementation of Tab nick completion in the textEntryArea
     */
    private void nickCompletionHandler() {
        String text = textEntryArea.getText();

        /* if we have nothing => do nothing */
        if (!text.equals("")) {
            int caretPosition = textEntryArea.getCaretPosition();
            int startPosition = text.lastIndexOf(" ", caretPosition - 1) + 1;
            String nickPart = text.substring(startPosition, caretPosition);
            Vector matches = new Vector();

            java.util.List keys = new ArrayList(buddyStatuses.keySet());
            Iterator iterator = keys.iterator();

            while (iterator.hasNext()) {
                BuddyStatus buddy = (BuddyStatus) buddyStatuses.get(iterator
                        .next());
                if (!nickList.contains(buddy))
                    continue;
                try {
                    String nick = buddy.getUser().substring(
                            buddy.getUser().lastIndexOf("/") + 1);
                    if (nick.toLowerCase().startsWith(nickPart.toLowerCase())) {
                        matches.add(nick);
                    }
                } catch (java.lang.NullPointerException e) {
                }
            }

            if (matches.size() > 0) {
                String append = "";

                if (matches.size() > 1) {
                    String nickPartNew = (String) matches.firstElement();
                    String nick = "";
                    String hint = nickPartNew + ", ";
                    int nickPartLen = nickPart.length();
                    for (int i = 1; i < matches.size(); i++) {
                        nick = (String) matches.get(i);
                        hint += nick + ", ";
                        for (int j = 1; j <= nick.length() - nickPartLen; j++) {
                            if (!nickPartNew.regionMatches(true, nickPartLen,
                                    nick, nickPartLen, j)) {
                                nickPartNew = nickPartNew.substring(0,
                                        nickPartLen + j - 1);
                                break;
                            }
                        }
                    }
                    if (nickPart.length() != nickPartNew.length()) {
                        nickPart = nickPartNew;
                    }
                    // emphasize differense in matches by bold and append hint
                    // to the conversationArea
                    // hint = hint.replaceAll() can't be used here because of
                    // its case sensitive nature
                    //Pattern pattern = Pattern.compile("(" + nickPart
                    //        + ")([^,]+), ", Pattern.CASE_INSENSITIVE);
                    //hint = pattern.matcher(hint).replaceAll("$1<b>$2</b>, ");
                    conversationArea.append(hint.substring(0, hint.length() - 2) + "\n", ConversationArea.RECEIVER, true);
                } else {
                    nickPart = (String) matches.firstElement();
                    if (startPosition == 0)
                        append = ": ";
                    else
                        append = " ";
                }

                String newText = text.substring(0, startPosition);
                newText += nickPart + append;
                newText += text.substring(caretPosition);
                textEntryArea.setText(newText);
                /* Set caret to the appropriate position */
                textEntryArea.setCaretPosition(startPosition
                        + nickPart.length() + append.length());
            }

        } /* end of the lazy "if" */
    }

    /**
     * Joins the chatroom and adds this chatroomwindow to the TabFrame
     *
     * @author Adam Olsen
     * @version 1.0
     */
    class JoinChatThread extends Thread {
        private String errorMessage;

        private boolean cancelled = false;


        public void cancel() {
            interrupt();
            cancelled = true;
        }

        public void run() {
            chat.addMessageListener(messageListener);
            chat.addParticipantListener(participantListener);
            chat.addSubjectUpdatedListener(subjectListener);
            chat.addParticipantStatusListener(statusListener);
            chat.addUserStatusListener(userStatusListener);
            chat.addInvitationRejectionListener(invitationRejectionPacketListener);

            int errorCode = 0;

            try {
                chat.join(nickname, pass, new DiscussionHistory(),
                        SmackConfiguration.getPacketReplyTimeout());
            } catch (XMPPException e) {
                if (!cancelled) {
                    if (e.getXMPPError() == null)
        {
                        errorMessage = e.getMessage();

        }
                    else {
                        errorMessage = resources.getString("xmppError"
                                + e.getXMPPError().getCode());
      errorCode = e.getXMPPError().getCode();
        }


                }
            }

            final int tempError = errorCode;
            if (!cancelled) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        if (errorMessage != null) {
                            if(tempError == 409 && joins++ < 1 && !removed)
                            {
                                nickname += "_";
                                leaveChat();
                                ChatRoomPanel window = new ChatRoomPanel(chatroom, nickname, pass);
                                BuddyList.getInstance().removeTabPanel(ChatRoomPanel.this);
                                window.startChat();


                                return;
                            }

                            serverErrorMessage(errorMessage);
                        } else {
                            if (cancelled) {
                                errorMessage = "error";
                            } else {
                                //set up a packet to be sent to my user in
                                // every groupchat
                                Presence presence = new Presence(
                                        Presence.Type.AVAILABLE, BuddyList
                                                .getInstance()
                                                .getCurrentStatusString(), 0,
                                        BuddyList.getInstance()
                                                .getCurrentPresenceMode());
                                presence.setTo(getRoomName() + '/'
                                        + getNickname());

                                BuddyList.getInstance().getConnection()
                                        .sendPacket(presence);
                            }
                        }
                    }
                });
            } else {
                errorMessage = "cancelled";
            }

            if (errorMessage != null) {
                try {
                    Thread.sleep(1000);
                    leaveChat();
                } catch (Exception neverCaught) {
                }
            }
        }
    }
}
TOP

Related Classes of com.valhalla.jbother.groupchat.ChatRoomPanel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.