diff --git a/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java b/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java index 4d799acca..c705230a6 100644 --- a/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java +++ b/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java @@ -106,15 +106,15 @@ public class UIServiceImpl private LoginManager loginManager; - private ChatWindowManager chatWindowManager + private final ChatWindowManager chatWindowManager = new ChatWindowManager(); - private ConferenceChatManager conferenceChatManager + private final ConferenceChatManager conferenceChatManager = new ConferenceChatManager(); private ConfigurationFrame configurationFrame; - private HistoryWindowManager historyWindowManager + private final HistoryWindowManager historyWindowManager = new HistoryWindowManager(); private SingleWindowContainer singleWindowContainer; diff --git a/src/net/java/sip/communicator/impl/gui/customcontrols/SCScrollPane.java b/src/net/java/sip/communicator/impl/gui/customcontrols/SCScrollPane.java index 932030bcb..3a1ccf089 100644 --- a/src/net/java/sip/communicator/impl/gui/customcontrols/SCScrollPane.java +++ b/src/net/java/sip/communicator/impl/gui/customcontrols/SCScrollPane.java @@ -195,7 +195,8 @@ public void loadSkin() } /** - * Cleanup. + * Releases the resources allocated by this instance throughout its lifetime + * and prepares it for garbage collection. */ public void dispose() { @@ -205,26 +206,32 @@ public void dispose() // they add a PropertyChangeListeners to the CToolkit try { - PropertyChangeListener[] pcl =Toolkit.getDefaultToolkit() - .getPropertyChangeListeners("apple.awt.contentScaleFactor"); + Toolkit defaultToolkit = Toolkit.getDefaultToolkit(); + PropertyChangeListener[] pcl + = defaultToolkit.getPropertyChangeListeners( + "apple.awt.contentScaleFactor"); for(PropertyChangeListener pc : pcl) { // find the reference to the object created the listener Field f = pc.getClass().getDeclaredField("this$0"); + f.setAccessible(true); - // if we are the parent cleanup + // If we are the parent, clean up. if(f.get(pc).equals(this.getViewport())) { - Toolkit.getDefaultToolkit() - .removePropertyChangeListener( - "apple.awt.contentScaleFactor", pc); + defaultToolkit.removePropertyChangeListener( + "apple.awt.contentScaleFactor", + pc); break; } } } catch(Throwable t) - {} + { + if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + } } } } diff --git a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomList.java b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomList.java index 2ca4b17be..edec4b746 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomList.java +++ b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomList.java @@ -38,7 +38,7 @@ public class ChatRoomList /** * All ChatRoomProviderWrapperListener change listeners registered so far. */ - private List providerChangeListeners + private final List providerChangeListeners = new ArrayList(); /** @@ -372,7 +372,7 @@ public synchronized void addChatRoomProviderWrapperListener( public synchronized void removeChatRoomProviderWrapperListener( ChatRoomProviderWrapperListener listener) { - providerChangeListeners.add(listener); + providerChangeListeners.remove(listener); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableDialog.java b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableDialog.java index 226c60dd6..3c80c4b3d 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableDialog.java @@ -30,7 +30,7 @@ * chat rooms, etc. * * @author Yana Stamcheva - * @author Lubomir Marinov + * @author Lyubomir Marinov * @author Damian Minkov */ public class ChatRoomTableDialog @@ -56,24 +56,27 @@ public class ChatRoomTableDialog /** * The add chat room button. */ - private JButton addButton = new JButton("+"); + private final JButton addButton = new JButton("+"); /** * The remove chat room button. */ - private JButton removeButton = new JButton("-"); + private final JButton removeButton = new JButton("-"); /** * The ok button. */ - private JButton okButton = new JButton(GuiActivator.getResources() - .getI18NString("service.gui.OK")); + private final JButton okButton + = new JButton( + GuiActivator.getResources().getI18NString("service.gui.OK")); /** * The cancel button. */ - private JButton cancelButton = new JButton(GuiActivator.getResources() - .getI18NString("service.gui.CANCEL")); + private final JButton cancelButton + = new JButton( + GuiActivator.getResources().getI18NString( + "service.gui.CANCEL")); /** * The editor for the chat room name. @@ -85,6 +88,33 @@ public class ChatRoomTableDialog */ private ChatRoomTableUI chatRoomsTableUI = null; + private final ChatRoomList chatRoomList + = GuiActivator.getUIService().getConferenceChatManager() + .getChatRoomList(); + + /** + * The ChatRoomList.ChatRoomProviderWrapperListener instance which + * has been registered with {@link #chatRoomList} and which is to be + * unregistered when this instance is disposed in order to prevent this + * instance from leaking. + */ + private final ChatRoomList.ChatRoomProviderWrapperListener + chatRoomProviderWrapperListener + = new ChatRoomList.ChatRoomProviderWrapperListener() + { + public void chatRoomProviderWrapperAdded( + ChatRoomProviderWrapper provider) + { + providersCombo.addItem(provider); + } + + public void chatRoomProviderWrapperRemoved( + ChatRoomProviderWrapper provider) + { + providersCombo.removeItem(provider); + } + }; + /** * Shows a ChatRoomTableDialog creating it first if necessary. * The shown instance is shared in order to prevent displaying multiple @@ -272,23 +302,8 @@ public void valueChanged(ListSelectionEvent e) //register listener to listen for newly added chat room providers // and for removed ones - GuiActivator.getUIService().getConferenceChatManager() - .getChatRoomList().addChatRoomProviderWrapperListener( - new ChatRoomList.ChatRoomProviderWrapperListener() - { - - public void chatRoomProviderWrapperAdded( - ChatRoomProviderWrapper provider) - { - providersCombo.addItem(provider); - } - - public void chatRoomProviderWrapperRemoved( - ChatRoomProviderWrapper provider) - { - providersCombo.removeItem(provider); - } - }); + chatRoomList.addChatRoomProviderWrapperListener( + chatRoomProviderWrapperListener); } /** @@ -297,17 +312,13 @@ public void chatRoomProviderWrapperRemoved( */ private JComboBox createProvidersCombobox() { - Iterator providers = - GuiActivator.getUIService().getConferenceChatManager() - .getChatRoomList().getChatRoomProviders(); - + Iterator providers + = chatRoomList.getChatRoomProviders(); JComboBox chatRoomProvidersCombobox = new JComboBox(); - while(providers.hasNext()) - { + while (providers.hasNext()) chatRoomProvidersCombobox.addItem(providers.next()); - } - + chatRoomProvidersCombobox.setRenderer(new ChatRoomProviderRenderer()); return chatRoomProvidersCombobox; @@ -502,10 +513,24 @@ else if(sourceButton.equals(cancelButton)) @Override protected void close(boolean isEscaped) { + dispose(); + } + + /** + * Releases the resources allocated by this instance throughout its + * lifetime. + */ + @Override + public void dispose() + { + if (chatRoomTableDialog == this) + chatRoomTableDialog = null; + + chatRoomList.removeChatRoomProviderWrapperListener( + chatRoomProviderWrapperListener); chatRoomsTableUI.dispose(); - chatRoomTableDialog = null; - dispose(); + super.dispose(); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableModel.java b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableModel.java index 59679d38d..a37a4c718 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableModel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableModel.java @@ -22,6 +22,7 @@ * The model for the table with saved rooms. * * @author Damian Minkov + * @author Lyubomir Marinov */ public class ChatRoomTableModel extends AbstractTableModel @@ -63,22 +64,24 @@ public ChatRoomTableModel(JTable parentTable) { this.parentTable = parentTable; - chatRoomList = GuiActivator.getUIService() - .getConferenceChatManager().getChatRoomList(); - + chatRoomList + = GuiActivator.getUIService().getConferenceChatManager() + .getChatRoomList(); + /* + * XXX The chatRoomList instance will surely outlive this instance so it + * is essential to call the removeChatRoomProviderWrapperListener method + * on it in order to prevent this instance from leaking. + */ chatRoomList.addChatRoomProviderWrapperListener(this); - Iterator iter = - chatRoomList.getChatRoomProviders(); - while (iter.hasNext()) + for (Iterator iter + = chatRoomList.getChatRoomProviders(); + iter.hasNext();) { ChatRoomProviderWrapper provider = iter.next(); - if(!provider.getProtocolProvider().getAccountID().isEnabled()) - { - continue; - } - handleProviderAdded(provider); + if (provider.getProtocolProvider().getAccountID().isEnabled()) + handleProviderAdded(provider); } } @@ -92,9 +95,7 @@ private void handleProviderAdded( ChatRoomProviderWrapper chatProviderWrapper) { for (int i = 0; i < chatProviderWrapper.countChatRooms(); i++) - { addChatRoom(chatProviderWrapper.getChatRoom(i), false); - } OperationSetPresence presence = chatProviderWrapper.getProtocolProvider() @@ -121,10 +122,7 @@ private void handleProviderRemoved( presence.removeProviderPresenceStatusListener(this); for (int i = 0; i < chatProviderWrapper.countChatRooms(); i++) - { - ChatRoomWrapper room = chatProviderWrapper.getChatRoom(i); - removeChatRoom(room); - } + removeChatRoom(chatProviderWrapper.getChatRoom(i)); } /** @@ -280,6 +278,32 @@ else if (evt.getEventID() == ChatRoomListChangeEvent.CHAT_ROOM_CHANGED) } } + /** + * Releases the resources allocated by this instance throughout its lifetime + * and prepares it for garbage collection. + */ + void dispose() + { + chatRoomList.removeChatRoomProviderWrapperListener(this); + + for (Iterator iter + = chatRoomList.getChatRoomProviders(); + iter.hasNext();) + { + ChatRoomProviderWrapper provider = iter.next(); + + try + { + handleProviderRemoved(provider); + } + catch (Throwable t) + { + if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + } + } + } + /** * Remove chat room from the ui. * @param chatRoomWrapper the room wrapper. @@ -287,12 +311,10 @@ else if (evt.getEventID() == ChatRoomListChangeEvent.CHAT_ROOM_CHANGED) private void removeChatRoom(ChatRoomWrapper chatRoomWrapper) { int ix = rooms.indexOf(chatRoomWrapper); - rooms.remove(chatRoomWrapper); + rooms.remove(chatRoomWrapper); if (ix != -1) - { fireTableRowsDeleted(ix, ix); - } } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableUI.java b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableUI.java index 3f58ca503..0c22a71ca 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableUI.java +++ b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableUI.java @@ -27,6 +27,7 @@ * ChatRoomsList. * * @author Damian Minkov + * @author Lyubomir Marinov */ public class ChatRoomTableUI extends SCScrollPane @@ -35,7 +36,7 @@ public class ChatRoomTableUI /** * The table with available rooms. */ - private JTable chatRoomList = new JTable(); + private final JTable chatRoomList = new JTable(); /** * The model of the table with the available rooms. @@ -75,10 +76,14 @@ private void initChatRoomList() this.chatRoomList.setOpaque(false); this.chatRoomList.setModel(chatRoomsTableModel); - ConferenceChatManager confChatManager - = GuiActivator.getUIService().getConferenceChatManager(); - - confChatManager.addChatRoomListChangeListener(chatRoomsTableModel); + /* + * XXX The ConferenceChatManager instance will surely outlive + * chatRoomsTableModel so it is essential to call the + * removeChatRoomListChangeListener method on it in order to prevent the + * leaking of memory. + */ + GuiActivator.getUIService().getConferenceChatManager() + .addChatRoomListChangeListener(chatRoomsTableModel); // this.chatRoomList.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); // this.chatRoomList.getColumnModel().getColumn(0).setMinWidth(250); @@ -279,11 +284,26 @@ public void mousePressed(MouseEvent e) } } + /** + * Releases the resources allocated by this instance throughout its lifetime + * and prepares it for garbage collection. + */ + @Override + public void dispose() + { + GuiActivator.getUIService().getConferenceChatManager() + .removeChatRoomListChangeListener(chatRoomsTableModel); + chatRoomsTableModel.dispose(); + + super.dispose(); + } + /** * Renders the chat room with an icon corresponding its status in the table. */ - private class ChatRoomTableCellRenderer - extends JLabel implements TableCellRenderer + private static class ChatRoomTableCellRenderer + extends JLabel + implements TableCellRenderer { /** * Creates the renderer. @@ -331,8 +351,9 @@ public Component getTableCellRendererComponent( * Renders in the table the account with its protocol icon, which * is corresponding the current status of the protocol. */ - private class ProtocolProviderTableCellRenderer - extends JLabel implements TableCellRenderer + private static class ProtocolProviderTableCellRenderer + extends JLabel + implements TableCellRenderer { /** * Creates the Renderer.