/* * 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 */ package nu.fw.jeti.ui; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.net.MalformedURLException; import java.net.URL; import java.util.*; import java.util.List; import javax.swing.*; import javax.swing.border.TitledBorder; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.text.DefaultEditorKit; import javax.swing.text.JTextComponent; import javax.swing.tree.TreeModel; import nu.fw.jeti.backend.Start; import nu.fw.jeti.backend.roster.JIDStatusGroup; import nu.fw.jeti.backend.roster.PrimaryJIDStatus; import nu.fw.jeti.events.PreferenceListener; import nu.fw.jeti.events.PresenceListener; import nu.fw.jeti.events.RosterListener; import nu.fw.jeti.events.StatusChangeListener; 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.*; import nu.fw.jeti.plugins.PluginsInfo; import nu.fw.jeti.plugins.RosterMenuListener; import nu.fw.jeti.ui.models.RosterTreeModel; import nu.fw.jeti.util.*; /** * @author E.S. de Boer */ public class Jeti extends JPanel implements PresenceListener, StatusChangeListener, PreferenceListener { private RosterTree onlinePanel; //private RosterTree offlinePanel; private JPopupMenu popupMenu; private JMenu popdownMenu; private JToggleButton btnJeti; private StatusButton btnStatus; private JPanel pnlMenuButtons; private JPanel empty = new JPanel(); private JScrollPane jScrollPaneTop; private JPanel pnlRoster; private JSplitPane jSplitPane1; private JScrollPane scrollPaneBottom; private ServerTree serverPanel; private int status; private String message = ""; private List menuItems; private JetiFrame jetiFrame; private JetiDialog jetiDialog; private boolean heightInvalid=true; private Map rosterMenuItems= new HashMap(10); private ChatWindows chatWindows; private Image backgroundImage; private Backend backend; private static final String TITLE = "Jeti"+Start.OS2; public Jeti(Backend backend,Container container) { if(container!=null)backend.setMain(this,null,null); else { jetiFrame = new JetiFrame(); backend.setMain(this,jetiFrame,jetiFrame); if(Preferences.getBoolean("jeti","showNotInTaskbar",false)) { jetiFrame.setIconImage(StatusIcons.getOfflineIcon().getImage()); jetiDialog = new JetiDialog(jetiFrame); backend.setMain(this,jetiDialog,null); } } this.backend = backend; backend.addListener(PresenceListener.class, this); backend.addListener(StatusChangeListener.class, this); backend.addListener(PreferenceListener.class, this); RosterTreeModel model = new RosterTreeModel(); backend.addListener(RosterListener.class, model); // Exibe a lista de Contato TreeModel onlineModel = model; if (UIManager.getLookAndFeel().isNativeLookAndFeel()) { System.out.println("using mac hack"); onlineModel = new TreeModelFilter(model, new OnlineSelector()); } onlinePanel = new RosterTree(backend, this, true, onlineModel); serverPanel = new ServerTree(backend, this); chatWindows = new ChatWindows(backend); refreshBackgroundImage(); } public void init() { setLayout(new BorderLayout()); btnStatus = new StatusButton(backend, this); pnlMenuButtons = new JPanel(); jScrollPaneTop = new JScrollPane(); pnlRoster = new JPanel(); jSplitPane1 = new JSplitPane(); scrollPaneBottom = new JScrollPane(); boolean opaque = Preferences.getBoolean("jeti","bmw",true); pnlRoster.setBackground(new Color(255,255,255)); onlinePanel.setBackground(new Color(255,255,255)); serverPanel.setBackground(new Color(255,255,255)); jScrollPaneTop.setOpaque(opaque); jScrollPaneTop.getViewport().setOpaque(opaque); scrollPaneBottom.setOpaque(opaque); scrollPaneBottom.getViewport().setOpaque(opaque); empty.setBackground(new Color(255,255,255)); Font bold =(UIManager.getFont("TitledBorder.font").deriveFont(Font.BOLD)); scrollPaneBottom.setMinimumSize(new Dimension(22, 0)); jScrollPaneTop.getViewport().add(pnlRoster, null); pnlMenuButtons.setLayout(new BoxLayout(pnlMenuButtons, BoxLayout.X_AXIS)); if (Preferences.getBoolean("jeti","menutop",false)) { createJetiMenu(); } pnlMenuButtons.add(btnStatus, null); add(jScrollPaneTop, BorderLayout.CENTER); add(pnlMenuButtons, java.awt.BorderLayout.SOUTH); pnlRoster.setLayout(new BorderLayout()); pnlRoster.add(onlinePanel, BorderLayout.CENTER); if(jetiDialog!=null)jetiDialog.init(this); else if(jetiFrame!=null)jetiFrame.init(this); int divLoc = Preferences.getInteger("jeti","dividerLocation",-10); if(divLoc == -10) jSplitPane1.setDividerLocation(0.75); else jSplitPane1.setDividerLocation(divLoc); initMenu(); updateLF(); } private void createJetiMenu() { JMenuBar menuBar = new JMenuBar(); popdownMenu = new JMenu(TITLE); popdownMenu.setMnemonic('J'); menuBar.add(popdownMenu); jetiFrame.setJMenuBar(menuBar); } private void createBtnJeti() { btnJeti = new JToggleButton(TITLE); btnJeti.setMnemonic('J'); btnJeti.setMaximumSize(new Dimension(500, 23)); btnJeti.setMargin(new Insets(0, 0, 0, 0)); btnJeti.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { if (heightInvalid) { popupMenu.show(Jeti.this, 0, 0); popupMenu.setVisible(false); heightInvalid = false; } popupMenu.show(Jeti.this, btnJeti.getX(), btnJeti.getY() + pnlMenuButtons.getY() - popupMenu.getHeight() ); } }); popupMenu = new JPopupMenu(); popupMenu.addPopupMenuListener(new PopupMenuListener() { public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { btnJeti.setSelected(false); } public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} public void popupMenuCanceled(PopupMenuEvent e) {} }); } public void close() { if(chatWindows.askIfClose()) { saveOpenGroups(); Container w = backend.getMainWindow(); if(w!=null && w instanceof Window)((Window)w).dispose(); System.out.println("Exiting, closing connection please wait...."); //todo disconnect backend.disconnect(); and exit instead of only exit backend.exit(); backend=null; } } private void startChat(final boolean message) { final JDialog dialog = new JDialog(backend.getMainFrame()); if(message)dialog.setTitle(I18N.gettext("main.main.jetimenu.Message")); else dialog.setTitle(I18N.gettext("main.main.jetimenu.Chat")); final JIDInput jidInput = new JIDInput(backend); JButton btnOK = new JButton(I18N.gettext("OK")); btnOK.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JID jid = jidInput.createJID(); if(jid==null)return; if(message) new SendMessage(backend,jid,jid.getUser()).setVisible(true); else startChat(jid); dialog.dispose(); } }); JButton btnCancel = new JButton(); dialog.getRootPane().setDefaultButton(btnOK); dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); Action cancelAction = new AbstractAction(I18N.gettext("Cancel")) { public void actionPerformed(ActionEvent e) { dialog.dispose(); } }; Utils.addCancelButton(dialog, btnCancel, cancelAction); Box panel1 = Box.createVerticalBox(); panel1.add(Box.createHorizontalGlue()); JPanel jPanel1 = new JPanel(); jPanel1.add(btnOK); jPanel1.add(btnCancel); panel1.add(jidInput); panel1.add(jPanel1); dialog.getContentPane().add(panel1, BorderLayout.CENTER); dialog.pack(); dialog.setLocationRelativeTo(this); dialog.setVisible(true); } public void startChat(JID jid) { if (jid == null) return; chatWindows.chat(new UnknownJIDStatus(jid)); } public void startChatResource(JIDStatus jidstatus) { chatWindows.chatResource(jidstatus); } public void chat(JIDStatus jidStatus) { chatWindows.chat(jidStatus); } public JPanel createChatPanel(JIDStatus jidStatus) { return chatWindows.createChatPanel(jidStatus); } public void addToMenu(JMenuItem menuItem) { if( menuItems == null ) menuItems = new LinkedList(); menuItems.add(menuItem); initMenu(); } public Map getRosterMenuItems() { return rosterMenuItems; } public void removeFromMenu(JMenuItem menuItem) { menuItems.remove(menuItem); if(menuItems.isEmpty()) menuItems = null; initMenu(); } public void addToRosterMenu(String name, RosterMenuListener listener) { onlinePanel.addToMenu(name, listener); //offlinePanel.addToMenu(name, listener); rosterMenuItems.put(name,listener); } public void removeFromRosterMenu(String name) { onlinePanel.removeFromMenu(name); //offlinePanel.removeFromMenu(name); rosterMenuItems.remove(name); } public void addToOnlineRosterMenu(String name, RosterMenuListener listener) { onlinePanel.addToMenu(name, listener); rosterMenuItems.put(name,listener); } public void removeFromOnlineRosterMenu(String name) { onlinePanel.removeFromMenu(name); rosterMenuItems.remove(name); } public void addToOfflineRosterMenu(String name, RosterMenuListener listener) { //offlinePanel.addToMenu(name, listener); } public void removeFromOfflineRosterMenu(String name) { //offlinePanel.removeFromMenu(name); } private void addMenuItem(JMenuItem item) { if (popupMenu != null) { popupMenu.add(item); } else { popdownMenu.add(item); } } private void initMenu() { //JETI menu if ( popdownMenu == null && popupMenu == null ) return; if ( popdownMenu != null ) popdownMenu.removeAll(); else popupMenu.removeAll(); JMenuItem menuItem = null; JMenu subMenu = null; if(Preferences.getBoolean("jeti","jetimenuShowMessage",true)) { menuItem = new JMenuItem(I18N.gettext("main.main.jetimenu.Message")+"..."); I18N.setMnemonic("main.main.jetimenu.Message",menuItem); menuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { startChat(true); } }); addMenuItem(menuItem); } if(Preferences.getBoolean("jeti","jetimenuShowChat",true)) { menuItem = new JMenuItem(I18N.gettext("main.main.jetimenu.Chat")+"..."); I18N.setMnemonic("main.main.jetimenu.Chat",menuItem); menuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { startChat(false); } }); addMenuItem(menuItem); } if(Preferences.getBoolean("jeti","jetimenuShowAddContact",true)) { menuItem = new JMenuItem(I18N.gettext("main.main.jetimenu.Add_Contact")+"..."); I18N.setMnemonic("main.main.jetimenu.Add_Contact",menuItem); menuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { new AddContact(backend).setVisible(true); } }); addMenuItem(menuItem); } //add plugin menus if( menuItems != null ) { for(Iterator i = menuItems.iterator();i.hasNext();) { JMenuItem item = (JMenuItem)i.next(); addMenuItem(item); } } menuItem = new JMenuItem(); if(Preferences.getBoolean("jeti","jetimenuShowLog",true)) { I18N.setTextAndMnemonic("main.main.jetimenu.Show_Log",menuItem,true); menuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { serverPanel.clearError(); new LogWindow(backend).setVisible(true); } }); addMenuItem(menuItem); } menuItem = new JMenuItem(); I18N.setTextAndMnemonic("main.main.jetimenu.About",menuItem,true); menuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { new AboutWindow().setVisible(true); } }); addMenuItem(menuItem); if(Preferences.getBoolean("jeti","jetimenuShowExit",true)) { final JMenuItem menuItem2 = new JMenuItem(I18N.gettext("main.main.jetimenu.Exit")); I18N.setMnemonic("main.main.jetimenu.Exit",menuItem2); menuItem2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { //menuItem2.removeActionListener(this); close(); } }); addMenuItem(menuItem2); } heightInvalid=true; } protected void saveOpenGroups() { List groups = onlinePanel.getOpenGroups(); if(groups != null) backend.send(new InfoQuery("set",new IQPrivate(new JetiPrivateRosterExtension((String[]) groups.toArray(new String[] {}))))); } public void openGroups(final JetiPrivateRosterExtension extension) { SwingUtilities.invokeLater(new Runnable() { public void run() { onlinePanel.openGroups(extension); serverPanel.openGroups(); } }); } public void updateLF() { if (popupMenu != null) { SwingUtilities.updateComponentTreeUI(popupMenu); } if (popdownMenu != null) { SwingUtilities.updateComponentTreeUI(popdownMenu); } btnStatus.updateLF(); onlinePanel.updateLF(); //offlinePanel.updateLF(); serverPanel.updateLF(); } public void changeOFFlinePanel(boolean show) { if(show) { pnlRoster.remove(empty); //pnlRoster.add(offlinePanel, BorderLayout.CENTER); } else { //pnlRoster.remove(offlinePanel); pnlRoster.add(empty, BorderLayout.CENTER); } pnlRoster.validate(); pnlRoster.repaint(); } /** * translate the main display if another locale is choosen */ public void translate() { preferencesChanged(); onlinePanel.createPopupMenu(); onlinePanel.setBorder(new TitledBorder(BorderFactory.createEmptyBorder(), I18N.gettext("main.main.List_Contacts"))); } public void refreshBackgroundImage() { String image = Preferences.getString("jeti", "backgroundImage", null); if(image != null) { if(Start.applet) { try { URL url= new URL(image); backgroundImage = new ImageIcon(url).getImage(); } catch(MalformedURLException e) { e.printStackTrace(); } } else backgroundImage = new ImageIcon(image).getImage(); } repaint(); } public void preferencesChanged() { initMenu(); //remake options StatusButton.reloadMessages(); } /*--------------------Status Change events----------------------------------*/ public void presenceChanged(Presence presence) { JIDStatus jidStatus = backend.getJIDStatus(presence.getFrom()); String nick = null; if (jidStatus != null) nick = jidStatus.getNick(); if (nick == null) nick = presence.getFrom().getUser(); if(jetiFrame!=null) jetiFrame.initTimer(nick,Presence.toLongShow(presence.getShow())); //beep(); //chatWindows.presenceChanged(presence); } public void ownPresenceChanged(int astatus, String amessage) { this.status = astatus; this.message = amessage; btnStatus.ownPresenceChanged(status, message); Runnable updateAComponent = new Runnable() { public void run() { if( jetiFrame != null ) { ImageIcon icon = StatusIcons.getStatusIcon(status); jetiFrame.setIconImage(icon.getImage()); } } }; SwingUtilities.invokeLater(updateAComponent); } public void connectionChanged(boolean online) { if ( online ) { if( jetiFrame != null) jetiFrame.setTitle(TITLE); onlinePanel.setVisible(true); serverPanel.setVisible(true); } else { btnStatus.connectionOffline(); Runnable updateAComponent = new Runnable() { public void run() { onlinePanel.setVisible(false); serverPanel.setVisible(false); if(jetiFrame!=null) { jetiFrame.setTitle(I18N.gettext("main.main.Offline")); jetiFrame.setIconImage( StatusIcons.getOfflineIcon().getImage()); } } }; SwingUtilities.invokeLater(updateAComponent); } } public void exit() { //if size of main window changed save Window w = jetiDialog == null ? (Window)jetiFrame : (Window)jetiDialog; if( w != null ) { Preferences.putInteger("jeti","height",w.getHeight()); Preferences.putInteger("jeti","width",w.getWidth()); Preferences.putInteger("jeti","posX",w.getX()); Preferences.putInteger("jeti","posY",w.getY()); Preferences.putInteger("jeti","dividerLocation",jSplitPane1.getDividerLocation()); Preferences.save(); } chatWindows.exit(); } public void paint (Graphics g) { super.paint(g); if(backgroundImage!=null) { if(Preferences.getBoolean("jeti","backgroundImageScaled",true)) { g.drawImage(backgroundImage, 0, 0,getWidth(),getHeight(), null); } else { g.drawImage(backgroundImage, 0, 0,null); } } paintChildren(g); } static { JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP).addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 1),new DefaultEditorKit.PasteAction()); JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP).addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 2),new DefaultEditorKit.CopyAction()); JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP).addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 1),new DefaultEditorKit.CutAction()); Action findAction = new FindAction(); JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP).addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_F, 2),findAction); JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP).addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0),findAction); } //only for filetransfer drag&drop public RosterTree getOnlinePanel() { return onlinePanel; } static class JetiDialog extends JDialog { public JetiDialog(JFrame frame) { super(frame); } public void init(final Jeti jeti) { setContentPane(jeti); this.setTitle(TITLE); if (PluginsInfo.isPluginLoaded("systemtray")) setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); else { addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(WindowEvent e) { setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); jeti.close(); } }); } int heigth = Preferences.getInteger("jeti","height",0); int width = Preferences.getInteger("jeti","width",0); if( heigth ==0 || width == 0) pack(); else setSize(width,heigth); int x = Preferences.getInteger("jeti","posX",50); int y = Preferences.getInteger("jeti","posY",50); int screenX = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(); int screenY = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight(); if(x>screenX) x=50; if(y>screenY) y=50; setLocation(x,y); } } static class JetiFrame extends JFrame { private TitleTimer timer = new TitleTimer(this, TITLE); public void init(final Jeti jeti) { setContentPane(jeti); setIconImage(StatusIcons.getOfflineIcon().getImage()); this.setTitle(TITLE); if (PluginsInfo.isPluginLoaded("systemtray")) setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); else { setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(WindowEvent e) { jeti.close(); } }); } int heigth = Preferences.getInteger("jeti","height",0); int width = Preferences.getInteger("jeti","width",0); if( heigth ==0 || width == 0) pack(); else setSize(width,heigth); int x = Preferences.getInteger("jeti","posX",50); int y = Preferences.getInteger("jeti","posY",50); int screenX = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(); int screenY = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight(); if(x>screenX) x=50; if(y>screenY) y=50; setLocation(x,y); } public void initTimer(String nick, String status) { timer.init(nick,status); } } static class OnlineSelector implements TreeModelSelector { public boolean isVisible(Object o) { if (o instanceof JIDStatus) { return ((JIDStatus)o).isOnline(); } else if (o instanceof PrimaryJIDStatus) { return ((PrimaryJIDStatus)o).getJIDPrimaryStatus().isOnline(); } else if (o instanceof JIDStatusGroup) { return (((JIDStatusGroup)o).getOnlines() > 0); } return false; } } static class OfflineSelector implements TreeModelSelector { public boolean isVisible(Object o) { if (o instanceof JIDStatus) { return !((JIDStatus)o).isOnline(); } else if (o instanceof PrimaryJIDStatus) { return ((PrimaryJIDStatus)o).isAJIDstatusOffline(); } else if (o instanceof JIDStatusGroup) { return true; } return true; } } } /* * Overrides for emacs * Local variables: * tab-width: 4 * End: */