/* * Jeti, a Java Jabber client, Copyright (C) 2001 E.S. de Boer * * 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For questions, comments etc, * use the website at http://jeti.jabberstudio.org * or mail/IM me at jeti@jabber.org * * Created on 8-jan-2005 */ package nu.fw.jeti.ui; import java.awt.*; import java.awt.event.*; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import nu.fw.jeti.events.MessageEventListener; import nu.fw.jeti.events.MessageListener; import nu.fw.jeti.events.PresenceListener; import nu.fw.jeti.images.StatusIcons; import nu.fw.jeti.jabber.Backend; import nu.fw.jeti.jabber.JID; import nu.fw.jeti.jabber.JIDStatus; import nu.fw.jeti.jabber.UnknownJIDStatus; import nu.fw.jeti.jabber.elements.Message; import nu.fw.jeti.jabber.elements.Presence; import nu.fw.jeti.jabber.elements.XMessageEvent; import nu.fw.jeti.util.I18N; import nu.fw.jeti.util.Preferences; /** * @author E.S. de Boer * */ public class ChatWindows implements MessageListener, MessageEventListener,PresenceListener { private static final int MAX_TABNAME_LENGTH = 100; private List chatWindows = new ArrayList(); private Backend backend; private JTabbedPane tabs; private JFrame window; private int dividerLocation; private ComponentListener dividerListener; public ChatWindows(Backend backend) { this.backend = backend; backend.addListener(MessageListener.class, this); backend.addListener(MessageEventListener.class, this); backend.addListener(PresenceListener.class, this); } public synchronized void exit() { for(Iterator i = chatWindows.iterator();i.hasNext();) { ((ChatWindow)i.next()).exit(); } if(window!=null)window.dispose(); } /** * Open a new chat window, or add to a existing one. * A chat exists when a chatwindow matching the jid * including the resource exists * @param jidStatus the jid to chat with */ public synchronized void chatResource(JIDStatus jidStatus) { ChatWindow w = getChatwindow(jidStatus.getJID(),true); if(w==null) { w = startChat(jidStatus, backend.createThread()); } chat(w); } /** * Open a new chat window, or add to a existing one. * A chat exists when a chatwindow matching the jid * exists (resources are not considered) * @param jidStatus the jid to chat with */ public synchronized void chat(JIDStatus jidStatus) { ChatWindow w = getChatwindow(jidStatus.getJID(),Preferences.getBoolean("jeti","chatwindowPerResource",false)); if(w==null) w = startChat(jidStatus, backend.createThread()); else { //unminimize chatwindow if it exist if(w.getTopLevelAncestor() instanceof JFrame) { JFrame frame = (JFrame)w.getTopLevelAncestor(); if(frame.getExtendedState()==Frame.ICONIFIED) { frame.setState(Frame.NORMAL); } frame.toFront(); } } chat(w); } /** * Gets a new chat panel * @param jidStatus the jid to chat with */ public synchronized JPanel createChatPanel(JIDStatus jidStatus) { JFrame frame = new JFrame(); ChatWindow chatWindow = new ChatWindow(backend,this,frame, jidStatus,backend.createThread()); chatWindows.add(chatWindow); return chatWindow; } private void chat(ChatWindow w) { if(tabs!=null) { if(tabs.indexOfComponent(w)!=-1) { w.requestFocusInWindow(); tabs.setSelectedComponent(w); } } ((Window)w.getTopLevelAncestor()).toFront(); } private ChatWindow startChat(JIDStatus jidStatus, String thread) { ChatWindow chatWindow; if(Preferences.getBoolean("jeti", "tabs", false)) { if(window==null) makeNewTabWindow(); chatWindow = new ChatWindow(backend,this,window,jidStatus,thread ); if(!window.isDisplayable()) addMenu(chatWindow); addTab(jidStatus, chatWindow); chatWindow.setDividerLocation(dividerLocation); chatWindow.addSplitBarListener(dividerListener); tabs.setBackgroundAt(tabs.getTabCount()-1,Color.BLUE); tabs.setForegroundAt(tabs.getTabCount()-1,Color.RED); window.setVisible(true); } else { chatWindow = new ChatWindow(backend,this,null, jidStatus,thread ); setChatWindowPosition(chatWindow); } chatWindows.add(chatWindow); return chatWindow; } private void addTab(JIDStatus jidStatus, ChatWindow chatWindow) { String name = jidStatus.getNick(); // = new FontMetrics((Font)UIManager.get(name)); FontMetrics fontMetrics = tabs.getFontMetrics(tabs.getFont()); name+=" "; int fontLenght=0; for(int i=0;i=MAX_TABNAME_LENGTH) { name = name.substring(0,i); break; } } tabs.addTab(name,StatusIcons.getStatusIcon(jidStatus),chatWindow); } private void removeTab(ChatWindow chatWindow) { if(tabs.getTabCount()==1) { window.dispose(); window=null; } tabs.remove(chatWindow); } private void makeNewTabWindow() { window = new JFrame(); //window.setIconImage(nu.fw.jeti.images.StatusIcons.getImageIcon("jeti").getImage()); JMenuBar bar = new JMenuBar(); tabs = new JTabbedPane(SwingConstants.LEFT) {//fix problem that change event is not called if there are tabs to the right public void remove(Component component) { super.remove( component ); fireStateChanged(); } }; tabs.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { Runnable updateAComponent = new Runnable() { public void run() { ChatWindow w = (ChatWindow) tabs.getSelectedComponent(); if(w!=null) { JIDStatus j = w.getJIDStatus(); window.setTitle(j.getNick()); window.setIconImage(StatusIcons.getStatusIcon(j).getImage()); tabs.setBackgroundAt(tabs.getSelectedIndex() ,UIManager.getColor("TabbedPane.background")); tabs.setForegroundAt(tabs.getSelectedIndex() ,UIManager.getColor("TabbedPane.foreground")); window.getJMenuBar().removeAll(); addMenu(w); w.setDividerLocation(dividerLocation); } } }; SwingUtilities.invokeLater(updateAComponent); } }); tabs.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { if(e.getButton() == MouseEvent.BUTTON3) { ChatWindow w =(ChatWindow)((JTabbedPane) e.getSource()).getSelectedComponent(); if(w!=null) { JPopupMenu menu = tabMenu(w); menu.show(tabs, e.getX(),e.getY()); } } } }); addCtrlTabFocus(); window.setJMenuBar(bar); window.setSize(Preferences.getInteger("jeti","chatTabWidth",500),Preferences.getInteger("jeti","chatTabHeight",400)); int posX = Preferences.getInteger("jeti","chatTabPosX",100); int posY = Preferences.getInteger("jeti","chatTabPosY",100); int screenX = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(); int screenY = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight(); if(posX>screenX) posX=100; if(posY>screenY) posY=100; window.setLocation(posX,posY); window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); window.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { Preferences.putInteger("jeti","chatTabPosX",window.getX()); Preferences.putInteger("jeti","chatTabPosY",window.getY()); Preferences.putInteger("jeti","chatTabHeight",window.getHeight()); Preferences.putInteger("jeti","chatTabWidth",window.getWidth()); Preferences.putInteger("jeti","chatTabDivider",dividerLocation); if(!askIfClose())return; int tabCount = tabs.getTabCount(); for(int i =0;i1) { int answer = JOptionPane.showConfirmDialog(window,MessageFormat.format(I18N.gettext("main.chat.You_are_about_to_close_{0}_tabs_Are_you_sure_you_want_to_close_them?") ,new Object[]{new Integer(tabCount)}),"" ,JOptionPane.YES_NO_OPTION); if(answer==JOptionPane.NO_OPTION)return false; } return true; } private void addMenu(final ChatWindow chatWindow) { final JMenu menu = chatWindow.getMenu(); if(menu.getItem(menu.getItemCount()-1).getName()==null) { final JMenuItem menuMoveToWindow = new JMenuItem(); final JMenuItem menuClose = new JMenuItem(); I18N.setTextAndMnemonic("main.chat.menu.Move_to_Window",menuMoveToWindow,true); menuMoveToWindow.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { menu.remove(menuMoveToWindow); menu.remove(menuClose); removeTab(chatWindow); chatWindow.removeSplitBarListener(dividerListener); chatWindow.changeToWindow(); setChatWindowPosition(chatWindow); } }); menu.add(menuMoveToWindow); I18N.setTextAndMnemonic("main.chat.menu.Close",menuClose,true); menuClose.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { chatWindow.removeSplitBarListener(dividerListener); chatWindow.exit(); chatWindows.remove(chatWindow); removeTab(chatWindow); } }); menuClose.setName("close"); menu.add(menuClose); } window.getJMenuBar().add(menu); } private JPopupMenu tabMenu(final ChatWindow chatWindow) { JPopupMenu groupPopupMenu = new JPopupMenu(); JMenuItem menuItem = null; menuItem = new JMenuItem(); I18N.setTextAndMnemonic("main.chat.menu.Close",menuItem,true); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { chatWindow.removeSplitBarListener(dividerListener); chatWindow.exit(); chatWindows.remove(chatWindow); removeTab(chatWindow); } }); groupPopupMenu.add(menuItem); return groupPopupMenu; } public void convertToTab(ChatWindow cw,JIDStatus jidStatus) { if(window==null)makeNewTabWindow(); if(!window.isDisplayable()) addMenu(cw); addTab(jidStatus,cw); cw.setDividerLocation(dividerLocation); cw.addSplitBarListener(dividerListener); cw.setParentFrame(window); window.setVisible(true); } public synchronized void presenceChanged(Presence presence) { ChatWindow cw = getChatwindow(presence.getFrom() ,Preferences.getBoolean("jeti","chatwindowPerResource",false)); if(cw!=null) cw.appendPresenceChange(presence); } private void beep() { if (Preferences.getBoolean("jeti","beep",true)) java.awt.Toolkit.getDefaultToolkit().beep(); } public void setTitleAt(ChatWindow cw, String title) { int index = tabs.indexOfComponent(cw); tabs.setTitleAt(index, title); if(tabs.getSelectedIndex()==index) { window.setTitle(title); } } public void setIconAt(ChatWindow cw, ImageIcon icon) { int index = tabs.indexOfComponent(cw); tabs.setIconAt(index, icon); if(tabs.getSelectedIndex()==index) { window.setIconImage(icon.getImage()); } } // ---------------------message event--------------------------- public synchronized void message(Message message) { JID from = message.getFrom(); if (message.getType().equals("chat") || (message.getType().equals("error") && message.getThread() != null)) { beep(); ChatWindow chatWindow; JIDStatus jidStatus = backend.getJIDStatus(message.getFrom()); String server = from.getDomain(); if(server.indexOf("conference")>-1 || server.indexOf("private")>-1 || server.indexOf("groupchat")>-1) {//private messages from groupchat should have a window per resource chatWindow = getChatwindow(from,true); jidStatus = new UnknownJIDStatus(from,from.getResource()); } else chatWindow = getChatwindow(from,Preferences.getBoolean("jeti","chatwindowPerResource",false)); if(tabs!=null) { int index = tabs.indexOfComponent(chatWindow); if(index!=-1) { if(tabs.getSelectedIndex()!=index) { tabs.setBackgroundAt(index,Color.BLUE); tabs.setForegroundAt(index,Color.RED); } tabs.setToolTipTextAt(index,message.getBody()); } } if (chatWindow == null) { if (jidStatus == null) chatWindow = startChat(new UnknownJIDStatus(from),message.getThread()); // ,"images",true,"unknown",e.getThread()); else chatWindow = startChat(jidStatus, message.getThread()); } chatWindow.appendMessage(message); } else if(message.getType().equals("groupchat")) { if(from.getResource()!=null) beep(); } else { beep(); new SendMessage(backend, message); } } private ChatWindow getChatwindow(JID jid,boolean matchResources) { String resource =jid.getResource(); ChatWindow cw=null; for (int tel = 0; tel < chatWindows.size(); tel++) { JID cwJID = ((ChatWindow)chatWindows.get(tel)).getJIDStatus().getCompleteJID(); if (cwJID.equals(jid)) { if(resource!=null && resource.equals(cwJID.getResource())) { return (ChatWindow) chatWindows.get(tel); } else if(!matchResources) cw = (ChatWindow) chatWindows.get(tel); } } return cw; } private void setChatWindowPosition(ChatWindow chatWindow) { if(chatWindows.isEmpty()) { int posX = Preferences.getInteger("jeti","chatPosX",100); int posY = Preferences.getInteger("jeti","chatPosY",100); int screenX = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(); int screenY = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight(); if(posX>screenX) posX=100; if(posY>screenY) posY=100; chatWindow.setLocationOnScreen(posX,posY); } else { ChatWindow oldWindow = (ChatWindow)chatWindows.get(chatWindows.size()-1); chatWindow.setLocationOnScreen(oldWindow); } } public synchronized void removeChatWindow(ChatWindow chatWindow) { chatWindows.remove(chatWindow); } public synchronized void onComposing(JID from, String thread, XMessageEvent messageEvent) { ChatWindow chatWindow = null; { chatWindow = getChatwindow(from,Preferences.getBoolean("jeti","chatwindowPerResource",false)); if(chatWindow!=null)chatWindow.composing(messageEvent.getType()); } } public synchronized void requestComposing(JID from, String id, String thread) { ChatWindow chatWindow = null; { chatWindow = getChatwindow(from,Preferences.getBoolean("jeti","chatwindowPerResource",false)); if(chatWindow!=null)chatWindow.composingID(id); } } }