From 9931f4b8004a35f3d5cdfc2b408723d9201f340a Mon Sep 17 00:00:00 2001 From: Yana Stamcheva Date: Thu, 30 Aug 2012 10:56:36 +0000 Subject: Making the contact list component available from outside the gui bundle. --- .../impl/callhistory/CallHistorySourceContact.java | 10 + .../contactlist/MetaContactListServiceImpl.java | 2 + .../sip/communicator/impl/gui/GuiActivator.java | 3 - .../sip/communicator/impl/gui/UIServiceImpl.java | 11 + .../impl/gui/customcontrols/SCScrollPane.java | 238 ---- .../impl/gui/lookandfeel/ExtendedTreeUI.java | 49 + .../impl/gui/lookandfeel/SIPCommTreeUI.java | 274 ---- .../gui/main/account/AccountRegSummaryPage.java | 2 +- .../impl/gui/main/call/CallTransferHandler.java | 1 + .../gui/main/call/ChooseCallAccountPopupMenu.java | 11 +- .../impl/gui/main/call/OneToOneCallPeerPanel.java | 3 +- .../impl/gui/main/call/ReceivedCallDialog.java | 2 +- .../impl/gui/main/chat/ChatConversationPanel.java | 2 +- .../impl/gui/main/chat/ChatTransferHandler.java | 1 + .../impl/gui/main/chat/ChatWritePanel.java | 2 +- .../impl/gui/main/chat/ContactPhotoPanel.java | 1 + .../chat/conference/ChatRoomMemberListPanel.java | 4 +- .../impl/gui/main/chat/history/DatesPanel.java | 2 +- .../impl/gui/main/chat/toolBars/MainToolBar.java | 2 +- .../gui/main/chatroomslist/ChatRoomListUI.java | 4 +- .../gui/main/chatroomslist/ChatRoomTableUI.java | 2 +- .../gui/main/contactlist/CallHistoryFilter.java | 14 +- .../ChooseUIContactDetailPopupMenu.java | 10 +- .../impl/gui/main/contactlist/ContactList.java | 1416 ------------------- .../gui/main/contactlist/ContactListEvent.java | 96 -- .../gui/main/contactlist/ContactListFilter.java | 41 - .../gui/main/contactlist/ContactListListener.java | 32 - .../impl/gui/main/contactlist/ContactListNode.java | 23 - .../impl/gui/main/contactlist/ContactListPane.java | 17 +- .../main/contactlist/ContactListSourceFilter.java | 4 +- .../contactlist/ContactListTransferHandler.java | 1 + .../contactlist/ContactListTreeCellRenderer.java | 50 +- .../gui/main/contactlist/ContactListTreeModel.java | 6 +- .../impl/gui/main/contactlist/ContactNode.java | 15 +- .../gui/main/contactlist/DefaultContactList.java | 2 +- .../main/contactlist/DefaultTreeContactList.java | 5 +- .../impl/gui/main/contactlist/FilterQuery.java | 344 ----- .../gui/main/contactlist/FilterQueryListener.java | 29 - .../impl/gui/main/contactlist/GroupNode.java | 37 +- .../contactlist/MetaContactRightButtonMenu.java | 11 + .../contactlist/MoveSubcontactMessageDialog.java | 1 + .../impl/gui/main/contactlist/PresenceFilter.java | 1 + .../impl/gui/main/contactlist/SearchField.java | 2 + .../impl/gui/main/contactlist/SearchFilter.java | 32 +- .../gui/main/contactlist/SimpleContactList.java | 1417 ++++++++++++++++++++ .../impl/gui/main/contactlist/TreeContactList.java | 291 +++- .../impl/gui/main/contactlist/UIContact.java | 166 --- .../impl/gui/main/contactlist/UIContactDetail.java | 222 --- .../main/contactlist/UIContactDetailAction.java | 25 - .../gui/main/contactlist/UIContactDetailImpl.java | 83 ++ .../impl/gui/main/contactlist/UIContactImpl.java | 56 + .../impl/gui/main/contactlist/UIFilterQuery.java | 356 +++++ .../impl/gui/main/contactlist/UIGroup.java | 100 -- .../impl/gui/main/contactlist/UIGroupImpl.java | 23 + .../contactsource/ExternalContactSource.java | 78 +- .../contactsource/MetaContactListSource.java | 73 +- .../contactlist/contactsource/MetaUIContact.java | 9 +- .../contactlist/contactsource/MetaUIGroup.java | 3 +- .../contactlist/contactsource/ShowMoreContact.java | 22 +- .../contactlist/contactsource/SourceUIContact.java | 21 +- .../notifsource/NotificationContact.java | 7 +- .../notifsource/NotificationContactSource.java | 1 + .../contactlist/notifsource/NotificationGroup.java | 3 +- .../impl/gui/utils/ExtendedTooltip.java | 415 ------ .../gui/utils/InviteContactTransferHandler.java | 1 + .../service/contactsource/ContactChangedEvent.java | 61 + .../contactsource/ContactQueryListener.java | 7 + .../contactsource/GenericSourceContact.java | 10 + .../service/contactsource/SourceContact.java | 7 + .../CustomContactActionsEvent.java | 26 - .../CustomContactActionsListener.java | 20 - .../CustomContactActionsService.java | 18 - .../sip/communicator/service/gui/ContactList.java | 172 +++ .../service/gui/ContactListFilter.java | 41 + .../communicator/service/gui/ContactListNode.java | 23 + .../sip/communicator/service/gui/FilterQuery.java | 84 ++ .../sip/communicator/service/gui/UIContact.java | 139 ++ .../communicator/service/gui/UIContactDetail.java | 203 +++ .../service/gui/UIContactDetailAction.java | 25 + .../communicator/service/gui/UIContactSource.java | 60 + .../java/sip/communicator/service/gui/UIGroup.java | 137 ++ .../sip/communicator/service/gui/UIService.java | 7 + .../service/gui/event/ContactListEvent.java | 110 ++ .../service/gui/event/ContactListListener.java | 50 + .../service/gui/event/FilterQueryListener.java | 31 + .../sip/communicator/service/gui/gui.manifest.mf | 3 +- .../protocol/event/ContactPropertyChangeEvent.java | 6 + .../communicator/util/swing/ExtendedTooltip.java | 414 ++++++ .../communicator/util/swing/SIPCommScrollPane.java | 236 ++++ .../util/swing/plaf/SIPCommTreeUI.java | 258 ++++ .../java/sip/communicator/util/util.manifest.mf | 1 + 91 files changed, 4581 insertions(+), 3755 deletions(-) delete mode 100644 src/net/java/sip/communicator/impl/gui/customcontrols/SCScrollPane.java create mode 100644 src/net/java/sip/communicator/impl/gui/lookandfeel/ExtendedTreeUI.java delete mode 100644 src/net/java/sip/communicator/impl/gui/lookandfeel/SIPCommTreeUI.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/ContactList.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListEvent.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListFilter.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListListener.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListNode.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/FilterQuery.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/FilterQueryListener.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/SimpleContactList.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/UIContact.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetail.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailAction.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailImpl.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactImpl.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/UIFilterQuery.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/UIGroup.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/UIGroupImpl.java delete mode 100644 src/net/java/sip/communicator/impl/gui/utils/ExtendedTooltip.java create mode 100644 src/net/java/sip/communicator/service/contactsource/ContactChangedEvent.java delete mode 100644 src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsEvent.java delete mode 100644 src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsListener.java create mode 100644 src/net/java/sip/communicator/service/gui/ContactList.java create mode 100644 src/net/java/sip/communicator/service/gui/ContactListFilter.java create mode 100644 src/net/java/sip/communicator/service/gui/ContactListNode.java create mode 100644 src/net/java/sip/communicator/service/gui/FilterQuery.java create mode 100644 src/net/java/sip/communicator/service/gui/UIContact.java create mode 100644 src/net/java/sip/communicator/service/gui/UIContactDetail.java create mode 100644 src/net/java/sip/communicator/service/gui/UIContactDetailAction.java create mode 100644 src/net/java/sip/communicator/service/gui/UIContactSource.java create mode 100644 src/net/java/sip/communicator/service/gui/UIGroup.java create mode 100644 src/net/java/sip/communicator/service/gui/event/ContactListEvent.java create mode 100644 src/net/java/sip/communicator/service/gui/event/ContactListListener.java create mode 100644 src/net/java/sip/communicator/service/gui/event/FilterQueryListener.java create mode 100644 src/net/java/sip/communicator/util/swing/ExtendedTooltip.java create mode 100644 src/net/java/sip/communicator/util/swing/SIPCommScrollPane.java create mode 100644 src/net/java/sip/communicator/util/swing/plaf/SIPCommTreeUI.java diff --git a/src/net/java/sip/communicator/impl/callhistory/CallHistorySourceContact.java b/src/net/java/sip/communicator/impl/callhistory/CallHistorySourceContact.java index 9144727..3fe42c5 100644 --- a/src/net/java/sip/communicator/impl/callhistory/CallHistorySourceContact.java +++ b/src/net/java/sip/communicator/impl/callhistory/CallHistorySourceContact.java @@ -349,4 +349,14 @@ public class CallHistorySourceContact return time; } + + /** + * Returns the status of the source contact. And null if such information + * is not available. + * @return the PresenceStatus representing the state of this source contact. + */ + public PresenceStatus getPresenceStatus() + { + return null; + } } diff --git a/src/net/java/sip/communicator/impl/contactlist/MetaContactListServiceImpl.java b/src/net/java/sip/communicator/impl/contactlist/MetaContactListServiceImpl.java index 3c38ec1..7188454 100644 --- a/src/net/java/sip/communicator/impl/contactlist/MetaContactListServiceImpl.java +++ b/src/net/java/sip/communicator/impl/contactlist/MetaContactListServiceImpl.java @@ -2492,6 +2492,8 @@ public class MetaContactListServiceImpl (byte[])evt.getNewValue()); } else if(ContactPropertyChangeEvent.PROPERTY_PERSISTENT_DATA + .equals(evt.getPropertyName()) + || ContactPropertyChangeEvent.PROPERTY_DISPLAY_DETAILS .equals(evt.getPropertyName())) { // if persistent data changed fire an event to store it diff --git a/src/net/java/sip/communicator/impl/gui/GuiActivator.java b/src/net/java/sip/communicator/impl/gui/GuiActivator.java index faebc73..026dd4a 100644 --- a/src/net/java/sip/communicator/impl/gui/GuiActivator.java +++ b/src/net/java/sip/communicator/impl/gui/GuiActivator.java @@ -689,9 +689,6 @@ public class GuiActivator implements BundleActivator */ public static List getContactSources() { - if (contactSources != null) - return contactSources; - contactSources = new Vector(); ServiceReference[] serRefs = null; diff --git a/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java b/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java index c7d1b8c..a7e98d9 100644 --- a/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java +++ b/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java @@ -31,6 +31,7 @@ import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.impl.gui.utils.Constants; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.gui.ContactList; import net.java.sip.communicator.service.gui.Container; import net.java.sip.communicator.service.gui.event.*; import net.java.sip.communicator.service.protocol.*; @@ -1512,4 +1513,14 @@ public class UIServiceImpl else throw new IllegalArgumentException("participants"); } + + /** + * Creates a contact list component. + * + * @return the created ContactList + */ + public ContactList createContactListComponent() + { + return new TreeContactList(); + } } diff --git a/src/net/java/sip/communicator/impl/gui/customcontrols/SCScrollPane.java b/src/net/java/sip/communicator/impl/gui/customcontrols/SCScrollPane.java deleted file mode 100644 index d56dab5..0000000 --- a/src/net/java/sip/communicator/impl/gui/customcontrols/SCScrollPane.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.customcontrols; - -import java.awt.*; -import java.awt.image.*; -import java.beans.*; -import java.lang.reflect.*; - -import javax.swing.*; - -import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.utils.*; -import net.java.sip.communicator.util.skin.*; -import net.java.sip.communicator.util.swing.*; - -import org.jitsi.util.*; - -/** - * The SCScrollPane is a JScrollPane with a custom viewport that allows to - * set an image as a background. Depending on the - * "impl.gui.IS_CONTACT_LIST_TEXTURE_BG_ENABLED" property we'll be setting a - * single image or a texture of images. - * - * @author Yana Stamcheva - * @author Adam Netocny - */ -public class SCScrollPane - extends JScrollPane - implements Skinnable -{ - private static final long serialVersionUID = 0L; - - /** - * Creates an SCSCrollPane. - */ - public SCScrollPane() - { - this.setBorder(BorderFactory.createMatteBorder( - 1, 0, 1, 0, Color.GRAY)); - - this.setViewport(new SCViewport()); - - this.getVerticalScrollBar().setUnitIncrement(100); - } - - /** - * Sets the view of this JViewport. - * - * @param view the view to set. - */ - @Override - public void setViewportView(Component view) - { - if (view instanceof JComponent) - { - JComponent viewAsJComponent = (JComponent) view; - - viewAsJComponent.setBorder( - BorderFactory.createEmptyBorder(3, 3, 3, 3)); - viewAsJComponent.setOpaque(false); - } - - super.setViewportView(view); - } - - /** - * Reloads skin information in viewport. - */ - public void loadSkin() - { - ((SCViewport) getViewport()).loadSkin(); - } - - /** - * The SCViewport used as viewport in this scrollpane. - */ - private static class SCViewport - extends JViewport - implements Skinnable - { - private static final long serialVersionUID = 1L; - - private BufferedImage bgImage; - - private Color color; - - private TexturePaint texture; - - /** - * Creates the SCViewport. - */ - public SCViewport() - { - this.setBackground(Color.WHITE); - - loadSkin(); - } - - /** - * Returns the boolean value of the property given by key. - * @param key the key of the property we look for - * @return the boolean value of the searched property - */ - private boolean getSettingsBoolean(String key) - { - return - Boolean.parseBoolean( - GuiActivator.getResources().getSettingsString(key)); - } - - /** - * Paints this viewport. - * @param g the Graphics object used for painting - */ - @Override - public void paintComponent(Graphics g) - { - super.paintComponent(g); - - g = g.create(); - try - { - AntialiasingManager.activateAntialiasing(g); - - Graphics2D g2 = (Graphics2D) g; - int width = getWidth(); - int height = getHeight(); - - // paint the image - if (bgImage != null) - { - if (texture != null) - { - g2.setPaint(texture); - - g2.fillRect(0, 0, width, height); - } - else - { - g.setColor(color); - - // paint the background with the chosen color - g.fillRect(0, 0, width, height); - - g2.drawImage(bgImage, width - bgImage.getWidth(), - height - bgImage.getHeight(), this); - } - } - } - finally - { - g.dispose(); - } - } - - /** - * Reloads background. - */ - public void loadSkin() - { - if(getSettingsBoolean("impl.gui.IS_CONTACT_LIST_IMG_BG_ENABLED")) - { - bgImage = - ImageLoader.getImage(ImageLoader.MAIN_WINDOW_BACKGROUND); - - if (getSettingsBoolean( - "impl.gui.IS_CONTACT_LIST_TEXTURE_BG_ENABLED") - && (bgImage != null)) - { - texture = - new TexturePaint(bgImage, new Rectangle(0, 0, bgImage - .getWidth(null), bgImage.getHeight(null))); - - color = null; - } - else - { - texture = null; - color = - new Color(GuiActivator.getResources().getColor( - "service.gui.CONTACT_LIST_BACKGROUND")); - } - } - else - { - bgImage = null; - texture = null; - color = null; - } - } - } - - /** - * Releases the resources allocated by this instance throughout its lifetime - * and prepares it for garbage collection. - */ - public void dispose() - { - if(OSUtils.IS_MAC) - { - // Apple introduced a memory leak in JViewport class - - // they add a PropertyChangeListeners to the CToolkit - try - { - 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, clean up. - if(f.get(pc).equals(this.getViewport())) - { - 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/lookandfeel/ExtendedTreeUI.java b/src/net/java/sip/communicator/impl/gui/lookandfeel/ExtendedTreeUI.java new file mode 100644 index 0000000..8fb3cd3 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/lookandfeel/ExtendedTreeUI.java @@ -0,0 +1,49 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.lookandfeel; + +import java.awt.event.*; + +import javax.swing.tree.*; + +import net.java.sip.communicator.impl.gui.main.contactlist.*; +import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.util.swing.plaf.*; + +/** + * The ExtendedTreeUI is an extended implementation of the + * SIPCommTreeUI specific for the gui implementation. + */ +public class ExtendedTreeUI + extends SIPCommTreeUI +{ + /** + * Do not select the ShowMoreContact. + * + * @param path the TreePath to select + * @param event the MouseEvent that provoked the select + */ + protected void selectPathForEvent(TreePath path, MouseEvent event) + { + Object lastComponent = path.getLastPathComponent(); + + // Open right button menu when right mouse is pressed. + if (lastComponent instanceof ContactNode) + { + UIContact uiContact + = ((ContactNode) lastComponent).getContactDescriptor(); + + if (!(uiContact instanceof ShowMoreContact)) + { + super.selectPathForEvent(path, event); + } + } + else + super.selectPathForEvent(path, event); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/lookandfeel/SIPCommTreeUI.java b/src/net/java/sip/communicator/impl/gui/lookandfeel/SIPCommTreeUI.java deleted file mode 100644 index f67dc0c..0000000 --- a/src/net/java/sip/communicator/impl/gui/lookandfeel/SIPCommTreeUI.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.lookandfeel; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; -import javax.swing.tree.*; - -import net.java.sip.communicator.impl.gui.main.contactlist.*; -import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; - -/** - * SIPCommTreeUI implementation. - * - * @author Yana Stamcheva - */ -public class SIPCommTreeUI - extends BasicTreeUI - implements HierarchyListener, - TreeSelectionListener -{ - private static JTree tree; - - private JViewport parentViewport; - - private VariableLayoutCache layoutCache; - - /** - * Last selected index. - */ - private int lastSelectedIndex; - - /** - * Creates the UI for the given component. - * @param c the component for which we're create an UI - * @return this UI implementation - */ - public static ComponentUI createUI(JComponent c) - { - return new SIPCommTreeUI(); - } - - /** - * Installs this UI to the given component. - * @param c the component to which to install this UI - */ - public void installUI(JComponent c) - { - if ( c == null ) - throw new NullPointerException( - "null component passed to BasicTreeUI.installUI()" ); - - tree = (JTree)c; - - JViewport v = getFirstParentViewport(tree); - if(v != null) - this.parentViewport = v; - else - tree.addHierarchyListener(this); - - tree.getSelectionModel().addTreeSelectionListener(this); - - super.installUI(c); - } - - /** - * Returns the first parent view port found. - * @param c the component parents we search - * @return the first parent view port found. - */ - private JViewport getFirstParentViewport(Container c) - { - if(c == null) - return null; - else - if(c instanceof JViewport) - return (JViewport)c; - else - return getFirstParentViewport(c.getParent()); - } - - /** - * On uninstalling the ui remove the listeners. - * @param c - */ - public void uninstallUI(JComponent c) - { - tree.getSelectionModel().clearSelection(); - tree.getSelectionModel().removeTreeSelectionListener(this); - tree.removeHierarchyListener(this); - - super.uninstallUI(c); - } - - /** - * HierarchyListener's method. - * @param e the event. - */ - public void hierarchyChanged(HierarchyEvent e) - { - if (e.getID() == HierarchyEvent.HIERARCHY_CHANGED - && (e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0 - && e.getChangedParent() instanceof JViewport) - { - parentViewport = (JViewport) e.getChangedParent(); - } - } - - /** - * The TreeSelectionListener's method. - * @param e the event. - */ - public void valueChanged(TreeSelectionEvent e) - { - // Update cell size. - selectionChanged( e.getOldLeadSelectionPath(), - e.getNewLeadSelectionPath()); - } - - /** - * Installs the defaults of this UI. - */ - protected void installDefaults() - { - if(tree.getBackground() == null || - tree.getBackground() instanceof UIResource) { - tree.setBackground(UIManager.getColor("Tree.background")); - } - if(getHashColor() == null || getHashColor() instanceof UIResource) { - setHashColor(UIManager.getColor("Tree.hash")); - } - if (tree.getFont() == null || tree.getFont() instanceof UIResource) - tree.setFont( UIManager.getFont("Tree.font") ); - // JTree's original row height is 16. To correctly display the - // contents on Linux we should have set it to 18, Windows 19 and - // Solaris 20. As these values vary so much it's too hard to - // be backward compatable and try to update the row height, we're - // therefor NOT going to adjust the row height based on font. If the - // developer changes the font, it's there responsibility to update - // the row height. - - setExpandedIcon(null); - setCollapsedIcon(null); - - setLeftChildIndent(0); - setRightChildIndent(0); - - LookAndFeel.installProperty(tree, "rowHeight", - UIManager.get("Tree.rowHeight")); - - largeModel = (tree.isLargeModel() && tree.getRowHeight() > 0); - - Object scrollsOnExpand = UIManager.get("Tree.scrollsOnExpand"); - if (scrollsOnExpand != null) { - LookAndFeel.installProperty( - tree, "scrollsOnExpand", scrollsOnExpand); - } - - UIManager.getDefaults().put("Tree.paintLines", false); - UIManager.getDefaults().put("Tree.lineTypeDashed", false); - } - - /** - * Creates the object responsible for managing what is expanded, as - * well as the size of nodes. - * @return the created layout cache - */ - protected AbstractLayoutCache createLayoutCache() - { - layoutCache = new VariableLayoutCache(); - return layoutCache; - } - - /** - * Do not select the ShowMoreContact. - * - * @param path the TreePath to select - * @param event the MouseEvent that provoked the select - */ - protected void selectPathForEvent(TreePath path, MouseEvent event) - { - Object lastComponent = path.getLastPathComponent(); - - // Open right button menu when right mouse is pressed. - if (lastComponent instanceof ContactNode) - { - UIContact uiContact - = ((ContactNode) lastComponent).getContactDescriptor(); - - if (!(uiContact instanceof ShowMoreContact)) - { - super.selectPathForEvent(path, event); - } - } - else - super.selectPathForEvent(path, event); - } - - /** - * A custom layout cache that recalculates the width of the cell the match - * the width of the tree (i.e. expands the cell to the right). - */ - private class VariableLayoutCache extends VariableHeightLayoutCache - { - /** - * Returns the preferred width of the receiver. - * @param path the path, which bounds we obtain - * @param placeIn the initial rectangle of the path - * @return the bounds of the path - */ - public Rectangle getBounds(TreePath path, Rectangle placeIn) - { - Rectangle rect = super.getBounds(path, placeIn); - - if (rect != null && parentViewport != null) - { - rect.width = parentViewport.getWidth() - 2; - } - - return rect; - } - } - - /** - * Ensures the tree size. - */ - private void ensureTreeSize() - { - // Update tree height. - updateSize(); - - // Finally repaint in order the change to take place. - tree.repaint(); - } - - /** - * Refreshes row sizes corresponding to the given paths. - * - * @param oldPath the old selection path - * @param newPath the new selection path - */ - public void selectionChanged(TreePath oldPath, TreePath newPath) - { - if (oldPath != null) - layoutCache.invalidatePathBounds(oldPath); - - if (newPath != null) - { - layoutCache.invalidatePathBounds(newPath); - lastSelectedIndex = tree.getRowForPath(newPath); - } - // If the selection has disappeared, for example when the selected row - // has been removed, refresh the previously selected row. - else - { - int nextRow = (tree.getRowCount() > lastSelectedIndex) - ? lastSelectedIndex : tree.getRowCount() - 1; - - layoutCache.invalidatePathBounds( - tree.getPathForRow(nextRow)); - } - - ensureTreeSize(); - } -} diff --git a/src/net/java/sip/communicator/impl/gui/main/account/AccountRegSummaryPage.java b/src/net/java/sip/communicator/impl/gui/main/account/AccountRegSummaryPage.java index 0d107e7..1d3919f 100644 --- a/src/net/java/sip/communicator/impl/gui/main/account/AccountRegSummaryPage.java +++ b/src/net/java/sip/communicator/impl/gui/main/account/AccountRegSummaryPage.java @@ -24,7 +24,7 @@ import net.java.sip.communicator.util.swing.*; * @author Yana Stamcheva */ public class AccountRegSummaryPage - extends SCScrollPane + extends SIPCommScrollPane implements WizardPage { private final Logger logger = Logger.getLogger(AccountRegSummaryPage.class); diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java b/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java index df54503..5f3f0cd 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java @@ -15,6 +15,7 @@ import javax.swing.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.swing.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/call/ChooseCallAccountPopupMenu.java b/src/net/java/sip/communicator/impl/gui/main/call/ChooseCallAccountPopupMenu.java index a2ade87..d5019eb 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/ChooseCallAccountPopupMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/ChooseCallAccountPopupMenu.java @@ -147,8 +147,9 @@ public class ChooseCallAccountPopupMenu for (Object o : telephonyObjects) { - if (o instanceof UIContactDetail) - this.addTelephonyContactItem((UIContactDetail) o, opSetClass); + if (o instanceof UIContactDetailImpl) + this.addTelephonyContactItem( + (UIContactDetailImpl) o, opSetClass); else if (o instanceof ChatTransport) this.addTelephonyChatTransportItem((ChatTransport) o, opSetClass); @@ -225,7 +226,7 @@ public class ChooseCallAccountPopupMenu * would be performed when an item is selected */ private void addTelephonyContactItem( - final UIContactDetail telephonyContact, + final UIContactDetailImpl telephonyContact, final Class opSetClass) { final ContactMenuItem contactItem @@ -473,9 +474,9 @@ public class ChooseCallAccountPopupMenu */ private static final long serialVersionUID = 0L; - private final UIContactDetail contact; + private final UIContactDetailImpl contact; - public ContactMenuItem(UIContactDetail contact) + public ContactMenuItem(UIContactDetailImpl contact) { this.contact = contact; diff --git a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java index 0add775..7242a22 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java @@ -15,7 +15,6 @@ import javax.swing.*; import javax.swing.text.*; import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; @@ -503,7 +502,7 @@ public class OneToOneCallPeerPanel { if (image == null || image.length <= 0) { - TreeContactList.setSourceContactImage( + GuiActivator.getContactList().setSourceContactImage( peerName, photoLabel, 100, 100); } else diff --git a/src/net/java/sip/communicator/impl/gui/main/call/ReceivedCallDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/ReceivedCallDialog.java index e97c2f5..81807bc 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/ReceivedCallDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/ReceivedCallDialog.java @@ -129,7 +129,7 @@ public class ReceivedCallDialog { public void run() { - TreeContactList + GuiActivator.getContactList() .setSourceContactImage( peer.getAddress(), callLabel[0], 50, 50); diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java index ff6859a..fba0eee 100755 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java @@ -47,7 +47,7 @@ import net.java.sip.communicator.util.swing.SwingWorker; * @author Adam Netocny */ public class ChatConversationPanel - extends SCScrollPane + extends SIPCommScrollPane implements HyperlinkListener, MouseListener, ClipboardOwner, diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransferHandler.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransferHandler.java index b49a2c4..5e36b20 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransferHandler.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransferHandler.java @@ -19,6 +19,7 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.swing.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java index 855dd77..7cdb61f 100755 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java @@ -71,7 +71,7 @@ public class ChatWritePanel private final ArrayList menuListeners = new ArrayList(); - private final SCScrollPane scrollPane = new SCScrollPane(); + private final SIPCommScrollPane scrollPane = new SIPCommScrollPane(); private ChatTransportSelectorBox transportSelectorBox; diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ContactPhotoPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ContactPhotoPanel.java index 54c8ac6..1f5f1da 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ContactPhotoPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ContactPhotoPanel.java @@ -17,6 +17,7 @@ import net.java.sip.communicator.impl.gui.main.chat.conference.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.swing.*; /** * The photo label corresponding to the current chat. diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatRoomMemberListPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatRoomMemberListPanel.java index 25364e9..d3ef1b3 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatRoomMemberListPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatRoomMemberListPanel.java @@ -11,11 +11,11 @@ import java.awt.event.*; import javax.swing.*; -import net.java.sip.communicator.impl.gui.customcontrols.*; import net.java.sip.communicator.impl.gui.main.chat.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.skin.*; +import net.java.sip.communicator.util.swing.*; /** * The ChatContactListPanel is the panel added on the right of the @@ -99,7 +99,7 @@ public class ChatRoomMemberListPanel } - JScrollPane contactsScrollPane = new SCScrollPane(); + JScrollPane contactsScrollPane = new SIPCommScrollPane(); contactsScrollPane.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); contactsScrollPane.setOpaque(false); diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/history/DatesPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/history/DatesPanel.java index 45d71f2..1f1595e 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/history/DatesPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/history/DatesPanel.java @@ -23,7 +23,7 @@ import net.java.sip.communicator.util.swing.*; * @author Lubomir Marinov */ public class DatesPanel - extends SCScrollPane + extends SIPCommScrollPane implements ListSelectionListener { private final JList datesList = new JList(); diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java b/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java index a2fa7f2..14faa61 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java @@ -605,7 +605,7 @@ public class MainToolBar } UIContactDetail cd = - new UIContactDetail( + new UIContactDetailImpl( pnd.getNumber(), pnd.getNumber() + " (" + localizedType + ")", diff --git a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomListUI.java b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomListUI.java index 4ca0420..c9f4a9f 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomListUI.java +++ b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomListUI.java @@ -12,9 +12,9 @@ import java.awt.event.*; import javax.swing.*; import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.customcontrols.*; import net.java.sip.communicator.impl.gui.main.chat.*; import net.java.sip.communicator.impl.gui.main.chat.conference.*; +import net.java.sip.communicator.util.swing.*; /** * The ChatRoomsListPanel is the panel that contains the @@ -24,7 +24,7 @@ import net.java.sip.communicator.impl.gui.main.chat.conference.*; * @author Lubomir Marinov */ public class ChatRoomListUI - extends SCScrollPane + extends SIPCommScrollPane implements MouseListener, ChatRoomListChangeListener, AdHocChatRoomListChangeListener 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 55f30df..fba6560 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 @@ -30,7 +30,7 @@ import net.java.sip.communicator.util.swing.*; * @author Lyubomir Marinov */ public class ChatRoomTableUI - extends SCScrollPane + extends SIPCommScrollPane implements MouseListener { /** diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/CallHistoryFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/CallHistoryFilter.java index 8ccf6aa..b688c21 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/CallHistoryFilter.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/CallHistoryFilter.java @@ -9,9 +9,9 @@ package net.java.sip.communicator.impl.gui.main.contactlist; import java.util.*; import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.impl.gui.main.contactlist.notifsource.*; import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; /** * The CallHistoryFilter is a filter over the history contact sources. @@ -36,11 +36,11 @@ public class CallHistoryFilter if (notificationSource != null) addMatching(notificationSource); - Collection contactSources - = TreeContactList.getContactSources(); + Collection contactSources + = GuiActivator.getContactList().getContactSources(); // Then add Call history contact source. - for (ExternalContactSource contactSource : contactSources) + for (UIContactSource contactSource : contactSources) { ContactSourceService sourceService = contactSource.getContactSourceService(); @@ -54,8 +54,8 @@ public class CallHistoryFilter filterQuery.addContactQuery(query); // Add first available results. - this.addMatching( query.getQueryResults(), - contactSource); + addMatching(query.getQueryResults(), + contactSource); // We know that this query should be finished here and we do not // expect any further results from it. @@ -109,7 +109,7 @@ public class CallHistoryFilter * we're adding */ private void addMatching( List sourceContacts, - ExternalContactSource uiSource) + UIContactSource uiSource) { Iterator contactsIter = sourceContacts.iterator(); diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ChooseUIContactDetailPopupMenu.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ChooseUIContactDetailPopupMenu.java index c1bbcd5..0568aa6 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ChooseUIContactDetailPopupMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ChooseUIContactDetailPopupMenu.java @@ -16,6 +16,7 @@ import javax.swing.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.skin.*; import net.java.sip.communicator.util.swing.*; @@ -61,7 +62,8 @@ public class ChooseUIContactDetailPopupMenu for (UIContactDetail detail : contactDetails) { - this.addContactDetailItem(detail, action); + if (detail instanceof UIContactDetailImpl) + this.addContactDetailItem((UIContactDetailImpl) detail, action); } } @@ -91,7 +93,7 @@ public class ChooseUIContactDetailPopupMenu * would be performed when an item is selected */ private void addContactDetailItem( - final UIContactDetail contactDetail, + final UIContactDetailImpl contactDetail, final UIContactDetailAction contactDetailAction) { final ContactMenuItem contactItem @@ -168,9 +170,9 @@ public class ChooseUIContactDetailPopupMenu */ private static final long serialVersionUID = 0L; - private final UIContactDetail contact; + private final UIContactDetailImpl contact; - public ContactMenuItem(UIContactDetail contact) + public ContactMenuItem(UIContactDetailImpl contact) { this.contact = contact; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactList.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactList.java deleted file mode 100644 index ae2a392..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactList.java +++ /dev/null @@ -1,1416 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -import java.awt.*; -import java.awt.event.*; -import java.util.*; - -import javax.swing.*; -import javax.swing.event.*; - -import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.customcontrols.*; -import net.java.sip.communicator.impl.gui.main.*; -import net.java.sip.communicator.impl.gui.utils.*; -import net.java.sip.communicator.service.contactlist.*; -import net.java.sip.communicator.service.contactlist.event.*; -import net.java.sip.communicator.service.protocol.*; -import net.java.sip.communicator.service.systray.*; -import net.java.sip.communicator.util.*; - -/** - * The ContactList is a JList that represents the contact list. A - * custom data model and a custom list cell renderer is used. This class manages - * all meta contact list events, like metaContactAdded, - * metaContactMoved, metaContactGroupAdded, etc. - * - * @author Yana Stamcheva - * @author Lubomir Marinov - */ -public class ContactList - extends DefaultContactList - implements MetaContactListListener, - MouseListener -{ - /** - * Serial version UID. - */ - private static final long serialVersionUID = 0L; - - private static final String ADD_OPERATION = "AddOperation"; - - private static final String REMOVE_OPERATION = "RemoveOperation"; - - private static final String MODIFY_OPERATION = "ModifyOperation"; - - private final Logger logger = Logger.getLogger(ContactList.class); - - private final MetaContactListService contactListService; - - private final ContactListModel listModel; - - private Object currentlySelectedObject; - - private final java.util.List contactListListeners - = new Vector(); - - private final java.util.List excContactListListeners - = new Vector(); - - private final MainFrame mainFrame; - - private final Map contentToRefresh - = new Hashtable(); - - private boolean refreshEnabled = true; - - private GroupRightButtonMenu groupRightButtonMenu; - - private MetaContactRightButtonMenu contactRightButtonMenu; - - /** - * A list of all contacts that are currently "active". An "active" contact - * is a contact that has been sent a message. The list is used to indicate - * these contacts with a special icon. - */ - private final java.util.List activeContacts - = new Vector(); - - /** - * If set to true prevents groups to be closed or opened using the mouse. - */ - private boolean disableOpenClose = false; - - /** - * Creates an instance of the ContactList. - * - * @param mainFrame The main application window. - */ - public ContactList(MainFrame mainFrame) - { - this.mainFrame = mainFrame; - - this.contactListService = GuiActivator.getContactListService(); - - this.listModel = new ContactListModel(contactListService); - this.setModel(listModel); - - this.setShowOffline(ConfigurationManager.isShowOffline()); - - this.initListeners(); - - new ContactListRefresh().start(); - } - - /** - * Initialize all listeners. - */ - private void initListeners() - { - this.contactListService.addMetaContactListListener(this); - - this.addMouseListener(this); - - this.addKeyListener(new CListKeySearchListener(this)); - - this.addListSelectionListener(new ListSelectionListener() - { - public void valueChanged(ListSelectionEvent e) - { - if (!e.getValueIsAdjusting()) - { - currentlySelectedObject = getSelectedValue(); - } - } - }); - } - - /** - * Handles the MetaContactEvent. Refreshes the list model. - * @param evt the MetaContactEvent that notified us of the add - */ - public void metaContactAdded(MetaContactEvent evt) - { - this.addContact(evt.getSourceMetaContact()); - } - - /** - * Handles the MetaContactRenamedEvent. Refreshes the list when - * a meta contact is renamed. - * @param evt the MetaContactRnamedEvent that notified us of the - * rename - */ - public void metaContactRenamed(MetaContactRenamedEvent evt) - { - this.refreshContact(evt.getSourceMetaContact()); - } - - /** - * Handles the MetaContactModifiedEvent. - * Indicates that a MetaContact has been modified. - * @param evt the MetaContactModifiedEvent containing the corresponding - * contact - */ - public void metaContactModified(MetaContactModifiedEvent evt) {} - - /** - * Handles the ProtoContactEvent. Refreshes the list when a - * protocol contact has been added. - * @param evt the ProtoContactEvent that notified us of the add - */ - public void protoContactAdded(ProtoContactEvent evt) - { - this.refreshContact(evt.getNewParent()); - } - - /** - * Handles the ProtoContactEvent. Refreshes the list when a - * protocol contact has been removed. - * @param evt the ProtoContactEvent that notified us of the remove - */ - public void protoContactRemoved(ProtoContactEvent evt) - { - this.refreshContact(evt.getOldParent()); - } - - /** - * Handles the ProtoContactEvent. Refreshes the list when a - * protocol contact has been moved. - * @param evt the ProtoContactEvent that notified us of the move - */ - public void protoContactMoved(ProtoContactEvent evt) - { - this.refreshContact(evt.getOldParent()); - this.refreshContact(evt.getNewParent()); - } - - /** - * Implements the MetaContactListListener.protoContactModified - * method with an empty body since we are not interested in proto contact - * specific changes (such as the persistent data) in the user interface. - * @param evt the ProtoContactEvent that notified us of the - * modification - */ - public void protoContactModified(ProtoContactEvent evt) - { - // currently ignored - } - - /** - * Handles the MetaContactEvent. Refreshes the list when a meta - * contact has been removed. - * @param evt the MetaContactEvent that notified us of the remove - */ - public void metaContactRemoved(MetaContactEvent evt) - { - this.removeContact(evt); - } - - /** - * Handles the MetaContactMovedEvent. Refreshes the list when a - * meta contact has been moved. - * @param evt the MetaContactEvent that notified us of the move - */ - public void metaContactMoved(MetaContactMovedEvent evt) - { - this.modifyGroup(evt.getNewParent()); - this.modifyGroup(evt.getOldParent()); - } - - public void metaContactAvatarUpdated(MetaContactAvatarUpdateEvent evt) {} - - /** - * Handles the MetaContactGroupEvent. Refreshes the list model - * when a new meta contact group has been added. - * @param evt the MetaContactGroupEvent that notified us of the add - */ - public void metaContactGroupAdded(MetaContactGroupEvent evt) - { - MetaContactGroup group = evt.getSourceMetaContactGroup(); - - if (!group.equals(contactListService.getRoot())) - this.addGroup(group); - } - - /** - * Handles the MetaContactGroupEvent. Refreshes the list when a - * meta contact group has been modified. - * @param evt the MetaContactGroupEvent that notified us of the - * modification - */ - public void metaContactGroupModified(MetaContactGroupEvent evt) - { - MetaContactGroup group = evt.getSourceMetaContactGroup(); - - if (!group.equals(contactListService.getRoot())) - this.modifyGroup(group); - } - - /** - * Handles the MetaContactGroupEvent. Refreshes the list when a - * meta contact group has been removed. - * @param evt the MetaContactGroupEvent that notified us of the - * remove - */ - public void metaContactGroupRemoved(MetaContactGroupEvent evt) - { - MetaContactGroup group = evt.getSourceMetaContactGroup(); - - if (!group.equals(contactListService.getRoot())) - this.removeGroup(group); - } - - /** - * Handles the MetaContactGroupEvent. Refreshes the list model - * when the contact list groups has been reordered. Moves the selection - * index to the index of the contact that was selected before the reordered - * event. This way the selection depends on the contact and not on the - * index. - * @param evt the MetaContactGroupEvent that notified us of the - * reordering - */ - public void childContactsReordered(MetaContactGroupEvent evt) - { - if (currentlySelectedObject != null) - setSelectedValue(currentlySelectedObject); - this.modifyGroup(evt.getSourceMetaContactGroup()); - } - - /** - * Returns the list of all groups. - * - * @return The list of all groups. - */ - public Iterator getAllGroups() - { - return contactListService.getRoot().getSubgroups(); - } - - /** - * Returns the Meta Contact Group corresponding to the given MetaUID. - * - * @param metaUID An identifier of a group. - * @return The Meta Contact Group corresponding to the given MetaUID. - */ - public MetaContactGroup getGroupByID(String metaUID) - { - Iterator i - = contactListService.getRoot().getSubgroups(); - while (i.hasNext()) - { - MetaContactGroup group = i.next(); - - if (group.getMetaUID().equals(metaUID)) - return group; - } - return null; - } - - /** - * Adds a listener for ContactListEvents. - * - * @param listener the listener to add - */ - public void addContactListListener(ContactListListener listener) - { - synchronized (contactListListeners) - { - if (!contactListListeners.contains(listener)) - contactListListeners.add(listener); - } - } - - /** - * Removes a listener previously added with addContactListListener. - * - * @param listener the listener to remove - */ - public void removeContactListListener(ContactListListener listener) - { - synchronized (contactListListeners) - { - contactListListeners.remove(listener); - } - } - - /** - * Adds a listener for ContactListEvents. - * - * @param listener the listener to add - */ - public void addExcContactListListener(ContactListListener listener) - { - synchronized (excContactListListeners) - { - if (!excContactListListeners.contains(listener)) - excContactListListeners.add(listener); - } - } - - /** - * Removes a listener previously added with addContactListListener. - * - * @param listener the listener to remove - */ - public void removeExcContactListListener(ContactListListener listener) - { - synchronized (excContactListListeners) - { - excContactListListeners.remove(listener); - } - } - - /** - * Creates the corresponding ContactListEvent and notifies all - * ContactListListeners that a contact is selected. - * - * @param source the contact that this event is about. - * @param eventID the id indicating the exact type of the event to fire. - * @param clickCount the number of clicks accompanying the event. - */ - public void fireContactListEvent(Object source, int eventID, int clickCount) - { - ContactListEvent evt = new ContactListEvent(source, eventID, clickCount); - - synchronized (excContactListListeners) - { - if (excContactListListeners.size() > 0) - { - fireContactListEvent( - new Vector(excContactListListeners), - evt); - return; - } - } - - fireContactListEvent(contactListListeners, evt); - } - - /** - * Creates the corresponding ContactListEvent and notifies all - * ContactListListeners that a contact is selected. - * - * @param sourceContact the contact that this event is about - * @param eventID the id indicating the exact type of the event to fire. - * @param clickCount - */ - public void fireContactListEvent( MetaContact sourceContact, - int eventID, - int clickCount) - { - fireContactListEvent( - contactListListeners, - new ContactListEvent(sourceContact, eventID, clickCount)); - } - - /** - * - * @param contactListListeners - * @param event - */ - protected void fireContactListEvent( - java.util.List contactListListeners, - ContactListEvent event) - { - synchronized (contactListListeners) - { - for (ContactListListener listener : contactListListeners) - { - switch (event.getEventID()) - { - case ContactListEvent.CONTACT_CLICKED: - listener.contactClicked(event); - break; - case ContactListEvent.GROUP_CLICKED: - listener.groupClicked(event); - break; - default: - logger.error("Unknown event type " + event.getEventID()); - } - } - } - } - - /** - * Manages a mouse click over the contact list. - * - * When the left mouse button is clicked on a contact cell different things - * may happen depending on the contained component under the mouse. If the - * mouse is double clicked on the "contact name" the chat window is opened, - * configured to use the default protocol contact for the selected - * MetaContact. If the mouse is clicked on one of the protocol icons, the - * chat window is opened, configured to use the protocol contact - * corresponding to the given icon. - * - * When the right mouse button is clicked on a contact cell, the cell is - * selected and the ContactRightButtonMenu is opened. - * - * When the right mouse button is clicked on a group cell, the cell is - * selected and the GroupRightButtonMenu is opened. - * - * When the middle mouse button is clicked on a cell, the cell is selected. - * @param e the MouseEvent that notified us of the click - */ - public void mouseClicked(MouseEvent e) - { - int selectedIndex = this.getSelectedIndex(); - Object selectedValue = this.getSelectedValue(); - - // If there's no index selected we have nothing to do here. - if (selectedIndex < 0) - return; - - ContactListCellRenderer renderer - = (ContactListCellRenderer) this.getCellRenderer() - .getListCellRendererComponent( this, - selectedValue, - selectedIndex, - true, - true); - - Point selectedCellPoint = this.indexToLocation(selectedIndex); - - int translatedX = e.getX() - selectedCellPoint.x; - - if (selectedValue instanceof MetaContactGroup) - { - MetaContactGroup group = (MetaContactGroup) selectedValue; - - if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0 - || (e.isControlDown() && !e.isMetaDown())) - { - - groupRightButtonMenu = new GroupRightButtonMenu(mainFrame, - group); - - SwingUtilities.convertPointToScreen(selectedCellPoint, this); - - groupRightButtonMenu.setInvoker(this); - - groupRightButtonMenu.setLocation(selectedCellPoint.x, - selectedCellPoint.y + renderer.getHeight()); - - groupRightButtonMenu.setVisible(true); - } - else if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) - { - if(!disableOpenClose) - { - if (listModel.isGroupClosed(group)) - listModel.openGroup(group); - else - listModel.closeGroup(group); - } - - fireContactListEvent( group, - ContactListEvent.GROUP_CLICKED, - e.getClickCount()); - - if(!disableOpenClose) - { - // get the component under the mouse - Component component - = this.getHorizontalComponent(renderer, translatedX); - - if ((component instanceof JPanel) - && ("buttonsPanel".equals(component.getName()))) - { - JPanel panel = (JPanel) component; - int internalX - = translatedX - - (renderer.getWidth() - panel.getWidth() - 2); - Component c = getHorizontalComponent(panel, internalX); - - if (c instanceof JLabel) - { - if (listModel.isGroupClosed(group)) - listModel.openGroup(group); - else - listModel.closeGroup(group); - } - } - } - } - } - - // Open message window, right button menu or contact info when - // mouse is pressed. Distinguish on which component was pressed - // the mouse and make the appropriate work. - if (selectedValue instanceof MetaContact) - { - MetaContact contact = (MetaContact) selectedValue; - - // Right click and Ctrl+LeftClick on the contact label opens - // Popup menu - if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0 - || (e.isControlDown() && !e.isMetaDown())) - { - -// contactRightButtonMenu = new ContactRightButtonMenu(this, -// contact); - - SwingUtilities - .convertPointToScreen(selectedCellPoint, this); - - contactRightButtonMenu.setInvoker(this); - - contactRightButtonMenu.setLocation(selectedCellPoint.x, - selectedCellPoint.y + renderer.getHeight()); - - contactRightButtonMenu.setVisible(true); - } - // Left click on the contact label opens Chat window - else if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0 - && e.getClickCount() > 1) - { - fireContactListEvent(contact, - ContactListEvent.CONTACT_CLICKED, e.getClickCount()); - } - } - } - - /** - * Selects the contact or group under the right mouse click. - * @param e the MouseEvent that notified us of the press - */ - public void mousePressed(MouseEvent e) - { - // Select the meta contact under the right button click. - if ((e.getModifiers() & InputEvent.BUTTON2_MASK) != 0 - || (e.getModifiers() & InputEvent.BUTTON3_MASK) != 0 - || (e.isControlDown() && !e.isMetaDown())) - { - int index = this.locationToIndex(e.getPoint()); - - if (index != -1) - this.setSelectedIndex(index); - } - } - - public void mouseEntered(MouseEvent e) {} - - public void mouseExited(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - /** - * Returns the component positioned at the given x in the given container. - * It's used like getComponentAt. - * - * @param c the container where to search - * @param x the x coordinate of the searched component - * @return the component positioned at the given x in the given container - */ - private Component getHorizontalComponent(Container c, int x) - { - for (int i = 0; i < c.getComponentCount(); i++) - { - Component component = c.getComponent(i); - int componentX = component.getX(); - - if ((x > componentX) && (x < componentX + component.getWidth())) - return component; - } - return null; - } - - /** - * If set to true prevents groups to be closed or opened using the mouse. - * @param disableOpenClose the disableOpenClose to set - */ - public void setDisableOpenClose(boolean disableOpenClose) - { - this.disableOpenClose = disableOpenClose; - } - - /** - * Takes care of keeping the contact list up to date. - */ - private class ContactListRefresh - extends Thread - { - public void run() - { - try - { - while (refreshEnabled) - { - Map copyContentToRefresh; - - synchronized (contentToRefresh) - { - if (contentToRefresh.isEmpty()) - contentToRefresh.wait(); - - copyContentToRefresh - = new Hashtable(contentToRefresh); - contentToRefresh.clear(); - } - - for (Map.Entry groupEntry - : copyContentToRefresh.entrySet()) - { - String operation = groupEntry.getValue(); - Object o = groupEntry.getKey(); - - if (o instanceof MetaContactGroup) - { - MetaContactGroup group = (MetaContactGroup) o; - - SwingUtilities.invokeLater(new RefreshGroup(group, - operation)); - } - else if (o instanceof MetaContact) - { - MetaContact contact = (MetaContact) o; - - SwingUtilities.invokeLater(new RefreshContact( - contact, contact.getParentMetaContactGroup(), - operation)); - } - else if (o instanceof MetaContactEvent) - { - MetaContactEvent event = (MetaContactEvent) o; - MetaContact contact = event.getSourceMetaContact(); - MetaContactGroup parentGroup = event - .getParentGroup(); - - SwingUtilities.invokeLater(new RefreshContact( - contact, parentGroup, operation)); - } - } - } - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - - /** - * Refreshes the given group content. - */ - private class RefreshGroup - implements Runnable - { - private final MetaContactGroup group; - - private final String operation; - - public RefreshGroup(MetaContactGroup group, String operation) - { - this.group = group; - this.operation = operation; - } - - public void run() - { - if (operation.equals(MODIFY_OPERATION)) - { - if (!listModel.isGroupClosed(group)) - { - int groupIndex = listModel.indexOf(group); - int lastIndex = listModel - .countContactsAndSubgroups(group); - - listModel.contentChanged(groupIndex, lastIndex); - } - } - else if (operation.equals(ADD_OPERATION)) - { - int groupIndex = listModel.indexOf(group); - int addedCount = listModel.countContactsAndSubgroups(group); - int listSize = listModel.getSize(); - if (listSize > 0) - { - listModel.contentChanged( - groupIndex, listSize - addedCount - 1); - listModel.contentAdded( - listSize - addedCount, listSize - 1); - } - } - else if (operation.equals(REMOVE_OPERATION)) - { - int groupIndex = listModel.indexOf(group); - int removeCount = listModel - .countContactsAndSubgroups(group); - int listSize = listModel.getSize(); - - if (listSize > 0) - { - listModel.contentRemoved(listSize - 1, listSize - + removeCount - 1); - listModel.contentChanged(groupIndex, listSize - 1); - } - } - } - } - - /** - * Refreshes the given contact content. - */ - private class RefreshContact - implements Runnable - { - private final MetaContact contact; - - private final MetaContactGroup parentGroup; - - private final String operation; - - public RefreshContact(MetaContact contact, - MetaContactGroup parentGroup, String operation) - { - this.contact = contact; - this.parentGroup = parentGroup; - this.operation = operation; - } - - public void run() - { - if (operation.equals(MODIFY_OPERATION)) - { - int contactIndex = listModel.indexOf(contact); - - listModel.contentChanged(contactIndex, contactIndex); - } - else if (operation.equals(ADD_OPERATION)) - { - int contactIndex = listModel.indexOf(contact); - - if (contactIndex != -1) - listModel.contentAdded(contactIndex, contactIndex); - } - else if (operation.equals(REMOVE_OPERATION)) - { - int groupIndex = listModel.indexOf(parentGroup); - - int listSize = listModel.getSize(); - - if (groupIndex != -1 && listSize > 0) - { - listModel.contentChanged(groupIndex, listSize - 1); - listModel.contentRemoved(listSize, listSize); - } - } - } - } - } - - /** - * Refreshes the given group content. - * - * @param group the group to refresh - */ - public void modifyGroup(MetaContactGroup group) - { - synchronized (contentToRefresh) - { - if (group != null - && (!contentToRefresh.containsKey(group) || contentToRefresh - .get(group).equals(REMOVE_OPERATION))) - { - - contentToRefresh.put(group, MODIFY_OPERATION); - contentToRefresh.notifyAll(); - } - } - } - - /** - * Refreshes all the contact list. - * @param group the MetaContactGroup to add - */ - public void addGroup(MetaContactGroup group) - { - synchronized (contentToRefresh) - { - if (group != null - && (!contentToRefresh.containsKey(group) || contentToRefresh - .get(group).equals(REMOVE_OPERATION))) - { - - contentToRefresh.put(group, ADD_OPERATION); - contentToRefresh.notifyAll(); - } - } - } - - /** - * Refreshes all the contact list. - * @param group the MetaContactGroup to remove - */ - public void removeGroup(MetaContactGroup group) - { - synchronized (contentToRefresh) - { - if (group != null - && (contentToRefresh.get(group) == null || !contentToRefresh - .get(group).equals(REMOVE_OPERATION))) - { - - contentToRefresh.put(group, REMOVE_OPERATION); - contentToRefresh.notifyAll(); - } - } - } - - /** - * Refreshes the given meta contact content. - * - * @param contact the meta contact to refresh - */ - public void refreshContact(MetaContact contact) - { - synchronized (contentToRefresh) - { - if (contact != null - && !contentToRefresh.containsKey(contact) - && !contentToRefresh.containsKey( - contact.getParentMetaContactGroup())) - { - - contentToRefresh.put(contact, MODIFY_OPERATION); - contentToRefresh.notifyAll(); - } - } - } - - /** - * Refreshes the whole contact list. - */ - public void refreshAll() - { - this.modifyGroup(contactListService.getRoot()); - } - - /** - * Adds the given contact to the contact list. - * @param contact the MetaContact to add - */ - public void addContact(MetaContact contact) - { - synchronized (contentToRefresh) - { - if (contact != null - && !contentToRefresh.containsKey(contact) - && !contentToRefresh.containsKey( - contact.getParentMetaContactGroup())) - { - - contentToRefresh.put(contact, ADD_OPERATION); - contentToRefresh.notifyAll(); - } - } - } - - /** - * Refreshes all the contact list. - * @param event the MetaContactEvent, from which we get the contact - * to remove - */ - public void removeContact(MetaContactEvent event) - { - synchronized (contentToRefresh) - { - if (event.getSourceMetaContact() != null - && !contentToRefresh.containsKey(event)) - { - contentToRefresh.put(event, REMOVE_OPERATION); - contentToRefresh.notifyAll(); - } - } - } - - /** - * Selects the given object in the list. - * - * @param o the object to select - */ - public void setSelectedValue(Object o) - { - setSelectedIndex((o == null) ? -1 : listModel.indexOf(o)); - } - - /** - * Returns the right button menu for a contact. - * - * @return the right button menu for a contact - */ - public MetaContactRightButtonMenu getContactRightButtonMenu() - { - return contactRightButtonMenu; - } - - /** - * Returns the right button menu for a group. - * - * @return the right button menu for a group - */ - public GroupRightButtonMenu getGroupRightButtonMenu() - { - return groupRightButtonMenu; - } - - /** - * Sets the showOffline property. - * - * @param isShowOffline TRUE to show all offline users, FALSE to hide - * offline users. - */ - public void setShowOffline(boolean isShowOffline) - { - Object selectedObject = null; - int currentlySelectedIndex = this.getSelectedIndex(); - - if(currentlySelectedIndex != -1) - { - selectedObject = listModel.getElementAt(currentlySelectedIndex); - } - - int listSize = listModel.getSize(); - - listModel.setShowOffline(isShowOffline); - - ConfigurationManager.setShowOffline(isShowOffline); - - int newListSize = listModel.getSize(); - - //hide offline users - if(!isShowOffline && listSize > 0) - { - if(newListSize > 0) - { - listModel.contentChanged(0, newListSize - 1); - listModel.contentRemoved(newListSize - 1, listSize - 1); - } - else - listModel.contentRemoved(0, listSize - 1); - } - //show offline users - else if(isShowOffline && newListSize > 0) - { - if(listSize > 0) - { - listModel.contentChanged(0, listSize - 1); - listModel.contentAdded(listSize - 1, newListSize - 1); - } - else - listModel.contentAdded(0, newListSize - 1); - } - - // Try to set the previously selected object. - if (selectedObject != null) - { - this.setSelectedIndex(listModel.indexOf(selectedObject)); - } - } - - /** - * Returns the main frame. - * - * @return the main frame - */ - public MainFrame getMainFrame() - { - return mainFrame; - } - - /** - * Moves the given srcContact to the destMetaContact. - * @param srcContact the Contact to move - * @param destMetaContact the destination MetaContact to move to - */ - public void moveContactToMetaContact( Contact srcContact, - MetaContact destMetaContact) - { - new MoveContactToMetaContactThread(srcContact, destMetaContact).start(); - } - - /** - * Moves the given Contact to the given MetaContact and - * asks user for confirmation. - */ - private class MoveContactToMetaContactThread extends Thread - { - private final Contact srcContact; - private final MetaContact destMetaContact; - - public MoveContactToMetaContactThread( Contact srcContact, - MetaContact destMetaContact) - { - this.srcContact = srcContact; - this.destMetaContact = destMetaContact; - } - - @SuppressWarnings("fallthrough") //intentional - public void run() - { - if (!ConfigurationManager.isMoveContactConfirmationRequested()) - { - // we move the specified contact - GuiActivator.getContactListService().moveContact( - srcContact, destMetaContact); - - return; - } - - String message = GuiActivator.getResources().getI18NString( - "service.gui.MOVE_SUBCONTACT_QUESTION", - new String[]{ srcContact.getDisplayName(), - destMetaContact.getDisplayName()}); - - MessageDialog dialog = new MessageDialog( - mainFrame, - GuiActivator.getResources() - .getI18NString("service.gui.MOVE_CONTACT"), - message, - GuiActivator.getResources() - .getI18NString("service.gui.MOVE")); - - switch (dialog.showDialog()) - { - case MessageDialog.OK_DONT_ASK_CODE: - ConfigurationManager.setMoveContactConfirmationRequested(false); - // do fall through - - case MessageDialog.OK_RETURN_CODE: - // we move the specified contact - GuiActivator.getContactListService().moveContact( - srcContact, destMetaContact); - break; - } - } - } - - /** - * Moves the given srcMetaContact to the destMetaContact. - * @param srcMetaContact the MetaContact to move - * @param destMetaContact the destination MetaContact to move to - */ - public void moveMetaContactToMetaContact( MetaContact srcMetaContact, - MetaContact destMetaContact) - { - new MoveMetaContactToMetaContactThread(srcMetaContact, destMetaContact) - .start(); - } - - /** - * Moves the given Contact to the given MetaContact and - * asks user for confirmation. - */ - private class MoveMetaContactToMetaContactThread extends Thread - { - private final MetaContact srcMetaContact; - private final MetaContact destMetaContact; - - public MoveMetaContactToMetaContactThread( MetaContact srcContact, - MetaContact destMetaContact) - { - this.srcMetaContact = srcContact; - this.destMetaContact = destMetaContact; - } - - @SuppressWarnings("fallthrough") //intentional - public void run() - { - if (!ConfigurationManager.isMoveContactConfirmationRequested()) - { - // We move all subcontacts of the source MetaContact to the - // destination MetaContact. - this.moveAllSubcontacts(); - - return; - } - - String message = GuiActivator.getResources().getI18NString( - "service.gui.MOVE_SUBCONTACT_QUESTION", - new String[]{ srcMetaContact.getDisplayName(), - destMetaContact.getDisplayName()}); - - MessageDialog dialog = new MessageDialog( - mainFrame, - GuiActivator.getResources() - .getI18NString("service.gui.MOVE_CONTACT"), - message, - GuiActivator.getResources() - .getI18NString("service.gui.MOVE")); - - switch (dialog.showDialog()) - { - case MessageDialog.OK_DONT_ASK_CODE: - ConfigurationManager.setMoveContactConfirmationRequested(false); - // do fall through - - case MessageDialog.OK_RETURN_CODE: - // We move all subcontacts of the source MetaContact to the - // destination MetaContact. - this.moveAllSubcontacts(); - break; - } - } - - /** - * Move all subcontacts of the srcMetaContact to - * destMetaContact. - */ - private void moveAllSubcontacts() - { - Iterator contacts = srcMetaContact.getContacts(); - while(contacts.hasNext()) - { - GuiActivator.getContactListService().moveContact( - contacts.next(), destMetaContact); - } - } - } - - /** - * Moves the given srcContact to the destGroup. - * @param srcContact the Contact to move - * @param destGroup the destination MetaContactGroup to move to - */ - public void moveContactToGroup( Contact srcContact, - MetaContactGroup destGroup) - { - new MoveContactToGroupThread(srcContact, destGroup).start(); - } - - /** - * Moves the given Contact to the given MetaContactGroup - * and asks user for confirmation. - */ - @SuppressWarnings("fallthrough") - private class MoveContactToGroupThread extends Thread - { - private final Contact srcContact; - private final MetaContactGroup destGroup; - - public MoveContactToGroupThread(Contact srcContact, - MetaContactGroup destGroup) - { - this.srcContact = srcContact; - this.destGroup = destGroup; - } - - public void run() - { - if (!ConfigurationManager.isMoveContactConfirmationRequested()) - { - // we move the specified contact - GuiActivator.getContactListService().moveContact( - srcContact, destGroup); - - return; - } - - String message = GuiActivator.getResources().getI18NString( - "service.gui.MOVE_SUBCONTACT_QUESTION", - new String[]{ srcContact.getDisplayName(), - destGroup.getGroupName()}); - - MessageDialog dialog = new MessageDialog( - mainFrame, - GuiActivator.getResources() - .getI18NString("service.gui.MOVE_CONTACT"), - message, - GuiActivator.getResources() - .getI18NString("service.gui.MOVE")); - - switch (dialog.showDialog()) - { - case MessageDialog.OK_DONT_ASK_CODE: - ConfigurationManager.setMoveContactConfirmationRequested(false); - // do fall through - - case MessageDialog.OK_RETURN_CODE: - // we move the specified contact - GuiActivator.getContactListService().moveContact( - srcContact, destGroup); - break; - } - } - } - - /** - * Moves the given srcContact to the destGroup. - * @param srcContact the MetaContact to move - * @param destGroup the destination MetaContactGroup to move to - */ - public void moveMetaContactToGroup( MetaContact srcContact, - MetaContactGroup destGroup) - { - new MoveMetaContactThread(srcContact, destGroup).start(); - } - - /** - * Moves the given MetaContact to the given MetaContactGroup - * and asks user for confirmation. - */ - private class MoveMetaContactThread - extends Thread - { - private final MetaContact srcContact; - private final MetaContactGroup destGroup; - - public MoveMetaContactThread( MetaContact srcContact, - MetaContactGroup destGroup) - { - this.srcContact = srcContact; - this.destGroup = destGroup; - } - - @SuppressWarnings("fallthrough") - public void run() - { - if (!ConfigurationManager.isMoveContactConfirmationRequested()) - { - // we move the specified contact - try - { - GuiActivator.getContactListService().moveMetaContact( - srcContact, destGroup); - } - catch (MetaContactListException e) - { - - } - - return; - } - - String message = GuiActivator.getResources().getI18NString( - "service.gui.MOVE_SUBCONTACT_QUESTION", - new String[]{ srcContact.getDisplayName(), - destGroup.getGroupName()}); - - MessageDialog dialog = new MessageDialog( - mainFrame, - GuiActivator.getResources() - .getI18NString("service.gui.MOVE_CONTACT"), - message, - GuiActivator.getResources() - .getI18NString("service.gui.MOVE")); - - switch (dialog.showDialog()) - { - case MessageDialog.OK_DONT_ASK_CODE: - ConfigurationManager.setMoveContactConfirmationRequested(false); - // do fall through - - case MessageDialog.OK_RETURN_CODE: - // we move the specified contact - GuiActivator.getContactListService().moveMetaContact( - srcContact, destGroup); - break; - } - } - } - - /** - * Adds the given MetaContact to the list of active contacts. - * - * @param metaContact the MetaContact to add. - */ - public void addActiveContact(MetaContact metaContact) - { - synchronized (activeContacts) - { - if(activeContacts.size() == 0) - { - SystrayService stray = GuiActivator.getSystrayService(); - - if (stray != null) - stray.setSystrayIcon(SystrayService.ENVELOPE_IMG_TYPE); - } - - if(!activeContacts.contains(metaContact)) - activeContacts.add(metaContact); - } - - this.refreshContact(metaContact); - } - - /** - * Removes the given MetaContact from the list of active contacts. - * - * @param metaContact the MetaContact to remove. - */ - public void removeActiveContact(MetaContact metaContact) - { - synchronized (activeContacts) - { - activeContacts.remove(metaContact); - - if(activeContacts.size() == 0) - GuiActivator.getSystrayService().setSystrayIcon( - SystrayService.SC_IMG_TYPE); - } - - this.refreshContact(metaContact); - } - - /** - * Removes all contacts from the list of active contacts. - */ - public void removeAllActiveContacts() - { - synchronized (activeContacts) - { - if(activeContacts.size() > 0) - { - activeContacts.clear(); - - GuiActivator.getSystrayService().setSystrayIcon( - SystrayService.SC_IMG_TYPE); - } - } - - this.refreshAll(); - } - - /** - * Checks if the given contact is currently active. - * - * @param metaContact the MetaContact to verify - * @return TRUE if the given MetaContact is active, FALSE - - * otherwise - */ - public boolean isMetaContactActive(MetaContact metaContact) - { - synchronized (activeContacts) - { - return activeContacts.contains(metaContact); - } - } - - /** - * Resets the contained mouse listeners and adds the given one. This allows - * other components to integrate the contact list by specifying their own - * mouse events. - * - * @param l the mouse listener to set. - */ - public void setMouseListener(MouseListener l) - { - this.removeMouseListener(this); - this.addMouseListener(l); - } - - /** - * Checks whether the group is closed. - * - * @param group The group to check. - * @return True if the group is closed, false - otherwise. - */ - @Override - public boolean isGroupClosed(MetaContactGroup group) - { - return this.listModel.isGroupClosed(group); - } -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListEvent.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListEvent.java deleted file mode 100644 index 8a8a9af..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListEvent.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -import java.util.*; - -/** - * The ContactListEvent is triggered when a contact or a group is - * clicked in the contact list. - * @author Yana Stamcheva - */ -public class ContactListEvent - extends EventObject -{ - private int eventID = -1; - - /** - * Indicates that the ContactListEvent instance was triggered by - * selecting a contact in the contact list. - */ - public static final int CONTACT_CLICKED = 1; - - /** - * Indicates that the ContactListEvent instance was triggered by selecting - * a group in the contact list. - */ - public static final int GROUP_CLICKED = 2; - - /** - * Indicated the number of click accompanying the event - */ - private int clickCount; - - /** - * Creates a new ContactListEvent according to the specified parameters. - * @param source the MetaContact which was selected - * @param eventID one of the XXX_SELECTED static fields indicating the - * nature of the event. - * @param clickCount the number of clicks that was produced when clicking - * over the contact list - */ - public ContactListEvent(Object source, int eventID, int clickCount) - { - super(source); - - this.eventID = eventID; - this.clickCount = clickCount; - } - - /** - * Returns an event id specifying whether the type of this event - * (CONTACT_SELECTED or PROTOCOL_CONTACT_SELECTED) - * @return one of the XXX_SELECTED int fields of this class. - */ - public int getEventID() - { - return eventID; - } - - /** - * Returns the UIContactDescriptor for which this event occured. - * @return the UIContactDescriptor for which this event occured - */ - public UIContact getSourceContact() - { - if(getSource() instanceof UIContact) - return (UIContact) getSource(); - - return null; - } - - /** - * Returns the UIGroupDescriptor for which this event occured. - * @return the UIGroupDescriptor for which this event occured - */ - public UIGroup getSourceGroup() - { - if(getSource() instanceof UIGroup) - return (UIGroup) getSource(); - - return null; - } - - /** - * Returns the number of click of this event. - * @return the number of click of this event. - */ - public int getClickCount() - { - return clickCount; - } -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListFilter.java deleted file mode 100644 index 901be8f..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListFilter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -/** - * The ContactListFilter is an interface meant to be implemented by - * modules interested in filtering the contact list. An implementation of this - * interface should be able to answer if an UIContact or an - * UIGroup is matching the corresponding filter. - * - * @author Yana Stamcheva - */ -public interface ContactListFilter -{ - /** - * Indicates if the given uiGroup is matching the current filter. - * @param uiContact the UIContact to check - * @return true to indicate that the given uiContact - * matches this filter, false - otherwise - */ - public boolean isMatching(UIContact uiContact); - - /** - * Indicates if the given uiGroup is matching the current filter. - * @param uiGroup the UIGroup to check - * @return true to indicate that the given uiGroup - * matches this filter, false - otherwise - */ - public boolean isMatching(UIGroup uiGroup); - - /** - * Applies this filter to any interested sources - * @param filterQuery the FilterQuery that tracks the results of - * this filtering - */ - public void applyFilter(FilterQuery filterQuery); -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListListener.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListListener.java deleted file mode 100644 index e6f31e0..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListListener.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -import java.util.*; - -/** - * Listens for events coming from mouse events over the contact list. For - * example a contact been clicked or a group been selected. - * - * @author Yana Stamcheva - */ -public interface ContactListListener extends EventListener -{ - /** - * Indicates that a group has been selected. - * @param evt the ContactListEvent that has been triggered from - * the user selection - */ - public void groupClicked(ContactListEvent evt); - - /** - * Indicates that a contact has been clicked. - * @param evt the ContactListEvent that has been triggered from - * the user click - */ - public void contactClicked(ContactListEvent evt); -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListNode.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListNode.java deleted file mode 100644 index eb12943..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListNode.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -/** - * The ContactListNode represents a node in the contact list data - * model. An implementation of this interface should be able to determine the - * index of this node in its contact source. - * - * @author Yana Stamcheva - */ -public interface ContactListNode -{ - /** - * Returns the index of this node in the MetaContactListService. - * @return the index of this node in the MetaContactListService - */ - public int getSourceIndex(); -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java index 9243cb9..1707f6b 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java @@ -14,7 +14,6 @@ import javax.swing.*; import javax.swing.Timer; import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.customcontrols.*; import net.java.sip.communicator.impl.gui.event.*; import net.java.sip.communicator.impl.gui.main.*; import net.java.sip.communicator.impl.gui.main.chat.*; @@ -22,6 +21,7 @@ import net.java.sip.communicator.service.contacteventhandler.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.gui.Container; +import net.java.sip.communicator.service.gui.event.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; @@ -37,7 +37,7 @@ import org.osgi.framework.*; * @author Yana Stamcheva */ public class ContactListPane - extends SCScrollPane + extends SIPCommScrollPane implements MessageListener, TypingNotificationsListener, FileTransferListener, @@ -212,8 +212,17 @@ public class ContactListPane * Implements the ContactListListener.groupSelected method. * @param evt the ContactListEvent that notified us */ - public void groupClicked(ContactListEvent evt) - {} + public void groupClicked(ContactListEvent evt) {} + + /** + * We're not interested in group selection events here. + */ + public void groupSelected(ContactListEvent evt) {} + + /** + * We're not interested in contact selection events here. + */ + public void contactSelected(ContactListEvent evt) {} /** * When a message is received determines whether to open a new chat window diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListSourceFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListSourceFilter.java index 0f71721..aecad64 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListSourceFilter.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListSourceFilter.java @@ -10,6 +10,7 @@ import java.util.*; import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; /** * The ContactListSourceFilter is a ContactListFilter that @@ -17,7 +18,8 @@ import net.java.sip.communicator.service.contactsource.*; * * @author Yana Stamcheva */ -public interface ContactListSourceFilter extends ContactListFilter +public interface ContactListSourceFilter + extends ContactListFilter { /** * Applies this filter to the given contactSource. diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTransferHandler.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTransferHandler.java index e763466..21c4859 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTransferHandler.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTransferHandler.java @@ -17,6 +17,7 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.chat.*; import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.swing.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java index c6b6fe2..951cc1c 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java @@ -22,6 +22,7 @@ import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.ServerStoredDetails.FaxDetail; import net.java.sip.communicator.service.protocol.ServerStoredDetails.GenericDetail; @@ -182,7 +183,7 @@ public class ContactListTreeCellRenderer /** * The icon showing the contact status. */ - protected ImageIcon statusIcon = new ImageIcon(); + protected Icon statusIcon = new ImageIcon(); /** * Indicates if the current list cell is selected. @@ -372,7 +373,7 @@ public class ContactListTreeCellRenderer // Make appropriate adjustments for contact nodes and group nodes. if (value instanceof ContactNode) { - UIContact contact + UIContactImpl contact = ((ContactNode) value).getContactDescriptor(); String displayName = contact.getDisplayName(); @@ -387,10 +388,13 @@ public class ContactListTreeCellRenderer this.nameLabel.setText(displayName); - if(statusIcon != null && contactList.isContactActive(contact)) - statusIcon.setImage(msgReceivedImage); + if(statusIcon != null + && contactList.isContactActive(contact) + && statusIcon instanceof ImageIcon) + ((ImageIcon) statusIcon).setImage(msgReceivedImage); else statusIcon = contact.getStatusIcon(); + this.statusLabel.setIcon(statusIcon); this.nameLabel.setFont(this.getFont().deriveFont(Font.PLAIN)); @@ -400,7 +404,7 @@ public class ContactListTreeCellRenderer // Initializes status message components if the given meta contact // contains a status message. - this.initDisplayDetails(contact); + this.initDisplayDetails(contact.getDisplayDetails()); this.initButtonsPanel(contact); @@ -417,7 +421,7 @@ public class ContactListTreeCellRenderer avatarHeight = AVATAR_HEIGHT; } - ImageIcon avatar + Icon avatar = contact.getAvatar(isSelected, avatarWidth, avatarHeight); if (avatar != null) @@ -441,7 +445,7 @@ public class ContactListTreeCellRenderer } else if (value instanceof GroupNode) { - UIGroup groupItem + UIGroupImpl groupItem = ((GroupNode) value).getGroupDescriptor(); this.nameLabel.setText(groupItem.getDisplayName()); @@ -485,6 +489,7 @@ public class ContactListTreeCellRenderer + "/" + groupItem.countChildContacts()); } + this.initDisplayDetails(groupItem.getDisplayDetails()); this.setToolTipText(groupItem.getDescriptor().toString()); } @@ -579,21 +584,36 @@ public class ContactListTreeCellRenderer public Dimension getPreferredSize() { Dimension preferredSize = new Dimension(); + int preferredHeight; if (treeNode instanceof ContactNode) { UIContact contact = ((ContactNode) treeNode).getContactDescriptor(); - if (contact instanceof ShowMoreContact) + preferredHeight = contact.getPreferredHeight(); + + if (preferredHeight > 0) + preferredSize.height = preferredHeight; + else if (contact instanceof ShowMoreContact) preferredSize.height = 18; else if (isSelected) preferredSize.height = 70; else preferredSize.height = 30; } - else - preferredSize.height = 18; + else if (treeNode instanceof GroupNode) + { + UIGroup group + = ((GroupNode) treeNode).getGroupDescriptor(); + + preferredHeight = group.getPreferredHeight(); + + if (preferredHeight > 0) + preferredSize.height = preferredHeight; + else + preferredSize.height = 18; + } return preferredSize; } @@ -646,16 +666,13 @@ public class ContactListTreeCellRenderer /** * Initializes the display details component for the given * UIContact. - * @param contact the UIContact, for which we initialize the - * details component + * @param details the display details to show */ - private void initDisplayDetails(UIContact contact) + private void initDisplayDetails(String displayDetails) { remove(displayDetailsLabel); displayDetailsLabel.setText(""); - String displayDetails = contact.getDisplayDetails(); - if (displayDetails != null && displayDetails.length() > 0) { // Replace all occurrences of new line with slash. @@ -829,6 +846,7 @@ public class ContactListTreeCellRenderer this.add(callButton, constraints); callButton.setBounds(x, y, 28, 28); + callButton.setEnabled(telephonyContact != null || hasPhone); x += callButton.getWidth(); @@ -1415,7 +1433,7 @@ public class ContactListTreeCellRenderer phones.add(pnd.getNumber()); UIContactDetail cd = - new UIContactDetail( + new UIContactDetailImpl( pnd.getNumber(), pnd.getNumber() + " (" + localizedType + ")", diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeModel.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeModel.java index 579464c..41d6390 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeModel.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeModel.java @@ -11,6 +11,8 @@ import java.lang.reflect.*; import javax.swing.*; import javax.swing.tree.*; +import net.java.sip.communicator.service.gui.*; + /** * The data model of the contact list. * @@ -40,7 +42,7 @@ public class ContactListTreeModel this.parentTree = tree; - RootUIGroup rootDescriptor = new RootUIGroup(); + UIGroupImpl rootDescriptor = new RootUIGroup(); rootGroupNode = new GroupNode(this, rootDescriptor); rootDescriptor.setGroupNode(rootGroupNode); @@ -157,7 +159,7 @@ public class ContactListTreeModel * The RootUIGroup is the root group in this contact list model. */ private static class RootUIGroup - implements UIGroup + extends UIGroupImpl { /** * The corresponding group node. diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactNode.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactNode.java index 7fc66d4..c756518 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactNode.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactNode.java @@ -8,6 +8,8 @@ package net.java.sip.communicator.impl.gui.main.contactlist; import javax.swing.tree.*; +import net.java.sip.communicator.service.gui.*; + /** * The ContactNode is a ContactListNode corresponding to a * given UIContact. @@ -31,21 +33,22 @@ public class ContactNode /** * Creates a ContactNode by specifying the corresponding * contact. - * @param contact the UIContact corresponding to this node + * @param contact the UIContactImpl corresponding to this node */ - public ContactNode(UIContact contact) + public ContactNode(UIContactImpl contact) { super(contact); this.contact = contact; } /** - * Returns the corresponding UIContact. - * @return the corresponding UIContact + * Returns the corresponding UIContactImpl. + * + * @return the corresponding UIContactImpl */ - public UIContact getContactDescriptor() + public UIContactImpl getContactDescriptor() { - return (UIContact) getUserObject(); + return (UIContactImpl) getUserObject(); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultContactList.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultContactList.java index 3ff9626..7113a6a 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultContactList.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultContactList.java @@ -16,10 +16,10 @@ import javax.swing.text.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.chat.*; import net.java.sip.communicator.impl.gui.main.chat.conference.*; -import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.skin.*; +import net.java.sip.communicator.util.swing.*; /** * DeafultContactlist used to display JLists with contacts. diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultTreeContactList.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultTreeContactList.java index b795c48..aebf844 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultTreeContactList.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultTreeContactList.java @@ -18,9 +18,10 @@ import net.java.sip.communicator.impl.gui.lookandfeel.*; import net.java.sip.communicator.impl.gui.main.*; import net.java.sip.communicator.impl.gui.main.chat.*; import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; -import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.util.skin.*; +import net.java.sip.communicator.util.swing.*; /** * DeafultContactlist used to display JLists with contacts. @@ -47,7 +48,7 @@ public class DefaultTreeContactList static { UIManager.getDefaults().put(uiClassID, - SIPCommTreeUI.class.getName()); + ExtendedTreeUI.class.getName()); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/FilterQuery.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/FilterQuery.java deleted file mode 100644 index 4ac17b9..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/FilterQuery.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -import java.util.*; - -import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; -import net.java.sip.communicator.service.contactsource.*; - -/** - * The FilterQuery gives information about a current filtering. - * - * @author Yana Stamcheva - */ -public class FilterQuery - implements ContactQueryListener, - MetaContactQueryListener -{ - /** - * The maximum result count for each contact source. - */ - public static final int MAX_EXTERNAL_RESULT_COUNT = 10; - - /** - * A listener, which is notified when this query finishes. - */ - private FilterQueryListener filterQueryListener; - - /** - * Indicates if the query succeeded, i.e. if any of the filters associated - * with this query has returned any results. - */ - private boolean isSucceeded = false; - - /** - * Indicates if this query has been canceled. - */ - private boolean isCanceled = false; - - /** - * Indicates if this query is closed, means no more queries could be added - * to it. A FilterQuery, which is closed knows that it has to wait - * for a final number of queries to finish before notifying interested - * parties of the result. - */ - private boolean isClosed = false; - - /** - * The list of filter queries. - */ - private final Map> filterQueries - = Collections.synchronizedMap( - new Hashtable>()); - - /** - * Indicates the number of running queries. - */ - private int runningQueries = 0; - - /** - * Adds the given contactQuery to the list of filterQueries. - * @param contactQuery the ContactQuery to add - */ - public void addContactQuery(Object contactQuery) - { - synchronized (filterQueries) - { - // If this filter query has been already canceled and someone wants - // to add something to it, we just cancel the incoming query and - // return. - if (isCanceled) - { - cancelQuery(contactQuery); - return; - } - - List queryResults = new ArrayList(); - - if (contactQuery instanceof ContactQuery) - { - ContactQuery externalQuery = (ContactQuery) contactQuery; - - List externalResults - = externalQuery.getQueryResults(); - - if (externalResults != null && externalResults.size() > 0) - queryResults = new ArrayList(externalResults); - - externalQuery.addContactQueryListener(this); - } - else if (contactQuery instanceof MetaContactQuery) - ((MetaContactQuery) contactQuery).addContactQueryListener(this); - - filterQueries.put(contactQuery, queryResults); - runningQueries++; - } - } - - /** - * Sets the isSucceeded property. - * @param isSucceeded indicates if this query has succeeded - */ - public void setSucceeded(boolean isSucceeded) - { - this.isSucceeded = isSucceeded; - } - - /** - * Indicates if this query has succeeded. - * @return true if this query has succeeded, false - - * otherwise - */ - public boolean isSucceeded() - { - return isSucceeded; - } - - /** - * Indicates if this query is canceled. - * @return true if this query is canceled, false otherwise - */ - public boolean isCanceled() - { - synchronized (filterQueries) - { - return isCanceled; - } - } - - /** - * Cancels this filter query. - */ - public void cancel() - { - synchronized(filterQueries) - { - isCanceled = true; - - Iterator queriesIter = filterQueries.keySet().iterator(); - - while (queriesIter.hasNext()) - cancelQuery(queriesIter.next()); - } - } - - /** - * Closes this query to indicate that no more contact sub-queries would be - * added to it. - */ - public void close() - { - isClosed = true; - - if (runningQueries == 0) - fireFilterQueryEvent(); - } - - /** - * Sets the given FilterQueryListener. - * @param l the FilterQueryListener to set - */ - public void setQueryListener(FilterQueryListener l) - { - filterQueryListener = l; - } - - /** - * Notifies the FilterQueryListener of the result status of - * this query. - */ - private void fireFilterQueryEvent() - { - if (filterQueryListener == null) - return; - - if (isSucceeded) - filterQueryListener.filterQuerySucceeded(this); - else - filterQueryListener.filterQueryFailed(this); - } - - /** - * Indicates that a query has changed its status. - * @param event the ContactQueryStatusEvent that notified us - */ - public void queryStatusChanged(ContactQueryStatusEvent event) - { - ContactQuery query = event.getQuerySource(); - - // Check if this query is in our filter queries list. - if (!filterQueries.containsKey(query) - || event.getEventType() == ContactQuery.QUERY_IN_PROGRESS) - return; - - removeQuery(query); - } - - /** - * Removes the given query from this filter query, updates the related data - * and notifies interested parties if this was the last query to process. - * @param query the ContactQuery to remove. - */ - public void removeQuery(ContactQuery query) - { - // First set the isSucceeded property. - if (!isSucceeded() && !query.getQueryResults().isEmpty()) - setSucceeded(true); - - // Then remove the wait result from the filterQuery. - runningQueries--; - query.removeContactQueryListener(this); - - // If no queries have rest we notify interested listeners that query - // has finished. - if (runningQueries == 0 && isClosed) - fireFilterQueryEvent(); - } - - /** - * Indicates that a query has changed its status. - * @param event the ContactQueryStatusEvent that notified us - */ - public void metaContactQueryStatusChanged(MetaContactQueryStatusEvent event) - { - MetaContactQuery query = event.getQuerySource(); - - // Check if this query is in our filter queries list. - if (!filterQueries.containsKey(query)) - return; - - // First set the isSucceeded property. - if (!isSucceeded() && query.getResultCount() > 0) - setSucceeded(true); - - // We don't remove the query from our list, because even if the query - // has finished its GUI part is scheduled in the Swing thread and we - // don't know anything about these events, so if someone calls cancel() - // we need to explicitly cancel all contained queries even they are - // finished. - runningQueries--; - query.removeContactQueryListener(this); - - // If no queries have rest we notify interested listeners that query - // has finished. - if (runningQueries == 0 && isClosed) - fireFilterQueryEvent(); - } - - /** - * Cancels the given query. - * @param query the query to cancel - */ - private void cancelQuery(Object query) - { - if (query instanceof ContactQuery) - { - ContactQuery contactQuery = (ContactQuery) query; - contactQuery.cancel(); - contactQuery.removeContactQueryListener( - GuiActivator.getContactList()); - if (!isSucceeded && contactQuery.getQueryResults().size() > 0) - isSucceeded = true; - } - else if (query instanceof MetaContactQuery) - { - MetaContactQuery metaContactQuery = (MetaContactQuery) query; - metaContactQuery.cancel(); - metaContactQuery.removeContactQueryListener( - GuiActivator.getContactList()); - if (!isSucceeded && metaContactQuery.getResultCount() > 0) - isSucceeded = true; - } - } - - /** - * Verifies if the given query is contained in this filter query. - * - * @param query the query we're looking for - * @return true if the given query is contained in this - * filter query, false - otherwise - */ - public boolean containsQuery(Object query) - { - return filterQueries.containsKey(query); - } - - /** - * Cancels asynchronous queries after the maximum desired result count is - * reached. - * - * @param query the query we're interested in - * @param contact the source contact we just received as a result of the - * given query - */ - private void contactReceived(ContactQuery query, SourceContact contact) - { - List queryResults = filterQueries.get(query); - - queryResults.add(contact); - - if (queryResults.size() == MAX_EXTERNAL_RESULT_COUNT) - { - query.removeContactQueryListener(GuiActivator.getContactList()); - - ShowMoreContact moreInfoContact - = new ShowMoreContact(query, queryResults); - - ContactSourceService contactSource = query.getContactSource(); - - GuiActivator.getContactList().addContact( - query, - moreInfoContact, - TreeContactList.getContactSource(contactSource).getUIGroup(), - false); - } - } - - /** - * Indicates that a contact has been received as a result of a query. - * - * @param event the ContactReceivedEvent that notified us - */ - public void contactReceived(ContactReceivedEvent event) - { - contactReceived(event.getQuerySource(), event.getContact()); - } - - /** - * Indicates that a contact has been removed after a search. - * @param event the ContactQueryEvent containing information - * about the received SourceContact - */ - public void contactRemoved(ContactRemovedEvent event) - {} - - public void metaContactReceived(MetaContactQueryEvent event) {} - - public void metaGroupReceived(MetaGroupQueryEvent event) {} -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/FilterQueryListener.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/FilterQueryListener.java deleted file mode 100644 index cd4eaa3..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/FilterQueryListener.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -/** - * The FilterQueryListener is notified when a filter query finishes. - * - * @author Yana Stamcheva - */ -public interface FilterQueryListener -{ - /** - * Indicates that the given query has finished with success, i.e. - * the filter has returned results. - * @param query the FilterQuery, where this listener is registered - */ - public void filterQuerySucceeded(FilterQuery query); - - /** - * Indicates that the given query has finished with failure, i.e. - * no results for the filter were found. - * @param query the FilterQuery, where this listener is registered - */ - public void filterQueryFailed(FilterQuery query); -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/GroupNode.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/GroupNode.java index 11753db..2d053ae 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/GroupNode.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/GroupNode.java @@ -12,8 +12,9 @@ import javax.swing.*; import javax.swing.plaf.*; import javax.swing.tree.*; -import net.java.sip.communicator.impl.gui.lookandfeel.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.swing.plaf.*; /** * The GroupNode is a ContactListNode corresponding to a @@ -39,7 +40,7 @@ public class GroupNode /** * The corresponding UIGroup. */ - private final UIGroup group; + private final UIGroupImpl group; /** * The ContactListNode Comparator used to sort the list of @@ -62,10 +63,10 @@ public class GroupNode * and the corresponding uiGroup. * * @param treeModel the parent tree model containing this group - * @param uiGroup the corresponding UIGroup + * @param uiGroup the corresponding UIGroupImpl */ public GroupNode( ContactListTreeModel treeModel, - UIGroup uiGroup) + UIGroupImpl uiGroup) { super(uiGroup, true); @@ -78,10 +79,10 @@ public class GroupNode /** * Creates a ContactNode for the given uiContact * and adds it to this group. - * @param uiContact the UIContact to add + * @param uiContact the UIContactImpl to add * @return the created ContactNode */ - public ContactNode addContact(UIContact uiContact) + public ContactNode addContact(UIContactImpl uiContact) { if (logger.isDebugEnabled()) logger.debug("Group node add contact: " @@ -107,11 +108,11 @@ public class GroupNode /** * Creates a ContactNode for the given uiContact, * adds it to this group and performs a sort at the end. - * @param uiContact the UIContact to add + * @param uiContact the UIContactImpl to add * @return the created ContactNode */ @SuppressWarnings("unchecked") - public ContactNode sortedAddContact(UIContact uiContact) + public ContactNode sortedAddContact(UIContactImpl uiContact) { if (logger.isDebugEnabled()) logger.debug("Group node sorted add contact: " @@ -136,9 +137,9 @@ public class GroupNode /** * Removes the node corresponding to the given uiContact from this * group. - * @param uiContact the UIContact to remove + * @param uiContact the UIContactImpl to remove */ - public void removeContact(UIContact uiContact) + public void removeContact(UIContactImpl uiContact) { final ContactNode contactNode = uiContact.getContactNode(); @@ -164,10 +165,10 @@ public class GroupNode /** * Creates a GroupNode for the given uiGroup and * adds it to this group. - * @param uiGroup the UIGroup to add + * @param uiGroup the UIGroupImpl to add * @return the created GroupNode */ - public GroupNode addContactGroup(UIGroup uiGroup) + public GroupNode addContactGroup(UIGroupImpl uiGroup) { int selectedIndex = getLeadSelectionRow(); @@ -189,9 +190,9 @@ public class GroupNode /** * Removes the node corresponding to the given uiGroup from this * group node. - * @param uiGroup the UIGroup to remove + * @param uiGroup the UIGroupImpl to remove */ - public void removeContactGroup(UIGroup uiGroup) + public void removeContactGroup(UIGroupImpl uiGroup) { GroupNode groupNode = uiGroup.getGroupNode(); @@ -216,11 +217,11 @@ public class GroupNode /** * Creates a GroupNode for the given uiGroup, * adds it to this group node and performs a sort at the end. - * @param uiGroup the UIGroup to add + * @param uiGroup the UIGroupImpl to add * @return the created GroupNode */ @SuppressWarnings("unchecked") - public GroupNode sortedAddContactGroup(UIGroup uiGroup) + public GroupNode sortedAddContactGroup(UIGroupImpl uiGroup) { GroupNode groupNode = new GroupNode(treeModel, uiGroup); @@ -243,9 +244,9 @@ public class GroupNode * Returns the UIGroup corresponding to this GroupNode. * @return the UIGroup corresponding to this GroupNode */ - public UIGroup getGroupDescriptor() + public UIGroupImpl getGroupDescriptor() { - return (UIGroup) getUserObject(); + return (UIGroupImpl) getUserObject(); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/MetaContactRightButtonMenu.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/MetaContactRightButtonMenu.java index 7a21c08..9a543cb 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/MetaContactRightButtonMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/MetaContactRightButtonMenu.java @@ -26,6 +26,7 @@ import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.gui.Container; +import net.java.sip.communicator.service.gui.event.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.OperationSetExtendedAuthorizations.SubscriptionStatus; import net.java.sip.communicator.service.protocol.ServerStoredDetails.FaxDetail; @@ -1198,6 +1199,16 @@ public class MetaContactRightButtonMenu } /** + * We're not interested in group selection events here. + */ + public void groupSelected(ContactListEvent evt) {} + + /** + * We're not interested in contact selection events here. + */ + public void contactSelected(ContactListEvent evt) {} + + /** * Moves the previously chosen sub-contact in the given toMetaContact. * * @param toMetaContact the MetaContact, where to move the previously diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/MoveSubcontactMessageDialog.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/MoveSubcontactMessageDialog.java index 787efb9..2d95a87 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/MoveSubcontactMessageDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/MoveSubcontactMessageDialog.java @@ -15,6 +15,7 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.customcontrols.*; import net.java.sip.communicator.impl.gui.main.*; import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.gui.event.*; import net.java.sip.communicator.util.skin.*; import net.java.sip.communicator.util.swing.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java index 1393569..3bf255e 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java @@ -12,6 +12,7 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchField.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchField.java index 931eed7..c97ad48 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchField.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchField.java @@ -13,6 +13,8 @@ import javax.swing.event.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.gui.event.*; import net.java.sip.communicator.util.skin.*; import net.java.sip.communicator.util.swing.*; import net.java.sip.communicator.util.swing.event.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java index aa36661..202ae0c 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java @@ -12,6 +12,7 @@ import java.util.regex.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; /** * The SearchFilter is a ContactListFilter that filters the @@ -50,7 +51,7 @@ public class SearchFilter /** * The list of external contact sources to search in. */ - private Collection contactSources; + private Collection contactSources; /** * The type of the search source. One of the above defined DEFAUT_SOURCE or @@ -88,13 +89,14 @@ public class SearchFilter if (filterQuery.isCanceled()) return; - Iterator filterSources + Iterator filterSources = getContactSources().iterator(); // Then we apply the filter on all its contact sources. while (filterSources.hasNext()) { - final ExternalContactSource filterSource = filterSources.next(); + final UIContactSource filterSource + = filterSources.next(); // If we have stopped filtering in the mean time we return here. if (filterQuery.isCanceled()) @@ -115,7 +117,7 @@ public class SearchFilter * filter to * @return the ContactQuery that tracks this filter */ - public ContactQuery applyFilter(ExternalContactSource contactSource) + public ContactQuery applyFilter(UIContactSource contactSource) { ContactSourceService sourceService = contactSource.getContactSourceService(); @@ -236,8 +238,9 @@ public class SearchFilter { ContactSourceService contactSource = sourceContact.getContactSource(); - ExternalContactSource sourceUI - = TreeContactList.getContactSource(contactSource); + + UIContactSource sourceUI + = GuiActivator.getContactList().getContactSource(contactSource); if (sourceUI != null // ExtendedContactSourceService has already matched the @@ -252,7 +255,7 @@ public class SearchFilter true); } else - ExternalContactSource.removeUIContact(sourceContact); + sourceUI.removeUIContact(sourceContact); } /** @@ -266,14 +269,15 @@ public class SearchFilter switch(searchSourceType) { case DEFAULT_SOURCE: - contactSources = TreeContactList.getContactSources(); + contactSources + = GuiActivator.getContactList().getContactSources(); break; case HISTORY_SOURCE: { - Collection historySources - = new LinkedList(); - ExternalContactSource historySource - = TreeContactList.getContactSource( + Collection historySources + = new LinkedList(); + UIContactSource historySource + = GuiActivator.getContactList().getContactSource( ContactSourceService.CALL_HISTORY); historySources.add(historySource); @@ -289,10 +293,10 @@ public class SearchFilter * @return the list of ExternalContactSource this filter searches * in */ - public Collection getContactSources() + public Collection getContactSources() { if (contactSources == null) - contactSources = TreeContactList.getContactSources(); + contactSources = GuiActivator.getContactList().getContactSources(); return contactSources; } diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/SimpleContactList.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/SimpleContactList.java new file mode 100644 index 0000000..15eeb86 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/SimpleContactList.java @@ -0,0 +1,1417 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.contactlist; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +import javax.swing.*; +import javax.swing.event.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.impl.gui.customcontrols.*; +import net.java.sip.communicator.impl.gui.main.*; +import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.contactlist.event.*; +import net.java.sip.communicator.service.gui.event.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.systray.*; +import net.java.sip.communicator.util.*; + +/** + * The ContactList is a JList that represents the contact list. A + * custom data model and a custom list cell renderer is used. This class manages + * all meta contact list events, like metaContactAdded, + * metaContactMoved, metaContactGroupAdded, etc. + * + * @author Yana Stamcheva + * @author Lubomir Marinov + */ +public class SimpleContactList + extends DefaultContactList + implements MetaContactListListener, + MouseListener +{ + /** + * Serial version UID. + */ + private static final long serialVersionUID = 0L; + + private static final String ADD_OPERATION = "AddOperation"; + + private static final String REMOVE_OPERATION = "RemoveOperation"; + + private static final String MODIFY_OPERATION = "ModifyOperation"; + + private final Logger logger = Logger.getLogger(SimpleContactList.class); + + private final MetaContactListService contactListService; + + private final ContactListModel listModel; + + private Object currentlySelectedObject; + + private final java.util.List contactListListeners + = new Vector(); + + private final java.util.List excContactListListeners + = new Vector(); + + private final MainFrame mainFrame; + + private final Map contentToRefresh + = new Hashtable(); + + private boolean refreshEnabled = true; + + private GroupRightButtonMenu groupRightButtonMenu; + + private MetaContactRightButtonMenu contactRightButtonMenu; + + /** + * A list of all contacts that are currently "active". An "active" contact + * is a contact that has been sent a message. The list is used to indicate + * these contacts with a special icon. + */ + private final java.util.List activeContacts + = new Vector(); + + /** + * If set to true prevents groups to be closed or opened using the mouse. + */ + private boolean disableOpenClose = false; + + /** + * Creates an instance of the ContactList. + * + * @param mainFrame The main application window. + */ + public SimpleContactList(MainFrame mainFrame) + { + this.mainFrame = mainFrame; + + this.contactListService = GuiActivator.getContactListService(); + + this.listModel = new ContactListModel(contactListService); + this.setModel(listModel); + + this.setShowOffline(ConfigurationManager.isShowOffline()); + + this.initListeners(); + + new ContactListRefresh().start(); + } + + /** + * Initialize all listeners. + */ + private void initListeners() + { + this.contactListService.addMetaContactListListener(this); + + this.addMouseListener(this); + + this.addKeyListener(new CListKeySearchListener(this)); + + this.addListSelectionListener(new ListSelectionListener() + { + public void valueChanged(ListSelectionEvent e) + { + if (!e.getValueIsAdjusting()) + { + currentlySelectedObject = getSelectedValue(); + } + } + }); + } + + /** + * Handles the MetaContactEvent. Refreshes the list model. + * @param evt the MetaContactEvent that notified us of the add + */ + public void metaContactAdded(MetaContactEvent evt) + { + this.addContact(evt.getSourceMetaContact()); + } + + /** + * Handles the MetaContactRenamedEvent. Refreshes the list when + * a meta contact is renamed. + * @param evt the MetaContactRnamedEvent that notified us of the + * rename + */ + public void metaContactRenamed(MetaContactRenamedEvent evt) + { + this.refreshContact(evt.getSourceMetaContact()); + } + + /** + * Handles the MetaContactModifiedEvent. + * Indicates that a MetaContact has been modified. + * @param evt the MetaContactModifiedEvent containing the corresponding + * contact + */ + public void metaContactModified(MetaContactModifiedEvent evt) {} + + /** + * Handles the ProtoContactEvent. Refreshes the list when a + * protocol contact has been added. + * @param evt the ProtoContactEvent that notified us of the add + */ + public void protoContactAdded(ProtoContactEvent evt) + { + this.refreshContact(evt.getNewParent()); + } + + /** + * Handles the ProtoContactEvent. Refreshes the list when a + * protocol contact has been removed. + * @param evt the ProtoContactEvent that notified us of the remove + */ + public void protoContactRemoved(ProtoContactEvent evt) + { + this.refreshContact(evt.getOldParent()); + } + + /** + * Handles the ProtoContactEvent. Refreshes the list when a + * protocol contact has been moved. + * @param evt the ProtoContactEvent that notified us of the move + */ + public void protoContactMoved(ProtoContactEvent evt) + { + this.refreshContact(evt.getOldParent()); + this.refreshContact(evt.getNewParent()); + } + + /** + * Implements the MetaContactListListener.protoContactModified + * method with an empty body since we are not interested in proto contact + * specific changes (such as the persistent data) in the user interface. + * @param evt the ProtoContactEvent that notified us of the + * modification + */ + public void protoContactModified(ProtoContactEvent evt) + { + // currently ignored + } + + /** + * Handles the MetaContactEvent. Refreshes the list when a meta + * contact has been removed. + * @param evt the MetaContactEvent that notified us of the remove + */ + public void metaContactRemoved(MetaContactEvent evt) + { + this.removeContact(evt); + } + + /** + * Handles the MetaContactMovedEvent. Refreshes the list when a + * meta contact has been moved. + * @param evt the MetaContactEvent that notified us of the move + */ + public void metaContactMoved(MetaContactMovedEvent evt) + { + this.modifyGroup(evt.getNewParent()); + this.modifyGroup(evt.getOldParent()); + } + + public void metaContactAvatarUpdated(MetaContactAvatarUpdateEvent evt) {} + + /** + * Handles the MetaContactGroupEvent. Refreshes the list model + * when a new meta contact group has been added. + * @param evt the MetaContactGroupEvent that notified us of the add + */ + public void metaContactGroupAdded(MetaContactGroupEvent evt) + { + MetaContactGroup group = evt.getSourceMetaContactGroup(); + + if (!group.equals(contactListService.getRoot())) + this.addGroup(group); + } + + /** + * Handles the MetaContactGroupEvent. Refreshes the list when a + * meta contact group has been modified. + * @param evt the MetaContactGroupEvent that notified us of the + * modification + */ + public void metaContactGroupModified(MetaContactGroupEvent evt) + { + MetaContactGroup group = evt.getSourceMetaContactGroup(); + + if (!group.equals(contactListService.getRoot())) + this.modifyGroup(group); + } + + /** + * Handles the MetaContactGroupEvent. Refreshes the list when a + * meta contact group has been removed. + * @param evt the MetaContactGroupEvent that notified us of the + * remove + */ + public void metaContactGroupRemoved(MetaContactGroupEvent evt) + { + MetaContactGroup group = evt.getSourceMetaContactGroup(); + + if (!group.equals(contactListService.getRoot())) + this.removeGroup(group); + } + + /** + * Handles the MetaContactGroupEvent. Refreshes the list model + * when the contact list groups has been reordered. Moves the selection + * index to the index of the contact that was selected before the reordered + * event. This way the selection depends on the contact and not on the + * index. + * @param evt the MetaContactGroupEvent that notified us of the + * reordering + */ + public void childContactsReordered(MetaContactGroupEvent evt) + { + if (currentlySelectedObject != null) + setSelectedValue(currentlySelectedObject); + this.modifyGroup(evt.getSourceMetaContactGroup()); + } + + /** + * Returns the list of all groups. + * + * @return The list of all groups. + */ + public Iterator getAllGroups() + { + return contactListService.getRoot().getSubgroups(); + } + + /** + * Returns the Meta Contact Group corresponding to the given MetaUID. + * + * @param metaUID An identifier of a group. + * @return The Meta Contact Group corresponding to the given MetaUID. + */ + public MetaContactGroup getGroupByID(String metaUID) + { + Iterator i + = contactListService.getRoot().getSubgroups(); + while (i.hasNext()) + { + MetaContactGroup group = i.next(); + + if (group.getMetaUID().equals(metaUID)) + return group; + } + return null; + } + + /** + * Adds a listener for ContactListEvents. + * + * @param listener the listener to add + */ + public void addContactListListener(ContactListListener listener) + { + synchronized (contactListListeners) + { + if (!contactListListeners.contains(listener)) + contactListListeners.add(listener); + } + } + + /** + * Removes a listener previously added with addContactListListener. + * + * @param listener the listener to remove + */ + public void removeContactListListener(ContactListListener listener) + { + synchronized (contactListListeners) + { + contactListListeners.remove(listener); + } + } + + /** + * Adds a listener for ContactListEvents. + * + * @param listener the listener to add + */ + public void addExcContactListListener(ContactListListener listener) + { + synchronized (excContactListListeners) + { + if (!excContactListListeners.contains(listener)) + excContactListListeners.add(listener); + } + } + + /** + * Removes a listener previously added with addContactListListener. + * + * @param listener the listener to remove + */ + public void removeExcContactListListener(ContactListListener listener) + { + synchronized (excContactListListeners) + { + excContactListListeners.remove(listener); + } + } + + /** + * Creates the corresponding ContactListEvent and notifies all + * ContactListListeners that a contact is selected. + * + * @param source the contact that this event is about. + * @param eventID the id indicating the exact type of the event to fire. + * @param clickCount the number of clicks accompanying the event. + */ + public void fireContactListEvent(Object source, int eventID, int clickCount) + { + ContactListEvent evt = new ContactListEvent(source, eventID, clickCount); + + synchronized (excContactListListeners) + { + if (excContactListListeners.size() > 0) + { + fireContactListEvent( + new Vector(excContactListListeners), + evt); + return; + } + } + + fireContactListEvent(contactListListeners, evt); + } + + /** + * Creates the corresponding ContactListEvent and notifies all + * ContactListListeners that a contact is selected. + * + * @param sourceContact the contact that this event is about + * @param eventID the id indicating the exact type of the event to fire. + * @param clickCount + */ + public void fireContactListEvent( MetaContact sourceContact, + int eventID, + int clickCount) + { + fireContactListEvent( + contactListListeners, + new ContactListEvent(sourceContact, eventID, clickCount)); + } + + /** + * + * @param contactListListeners + * @param event + */ + protected void fireContactListEvent( + java.util.List contactListListeners, + ContactListEvent event) + { + synchronized (contactListListeners) + { + for (ContactListListener listener : contactListListeners) + { + switch (event.getEventID()) + { + case ContactListEvent.CONTACT_CLICKED: + listener.contactClicked(event); + break; + case ContactListEvent.GROUP_CLICKED: + listener.groupClicked(event); + break; + default: + logger.error("Unknown event type " + event.getEventID()); + } + } + } + } + + /** + * Manages a mouse click over the contact list. + * + * When the left mouse button is clicked on a contact cell different things + * may happen depending on the contained component under the mouse. If the + * mouse is double clicked on the "contact name" the chat window is opened, + * configured to use the default protocol contact for the selected + * MetaContact. If the mouse is clicked on one of the protocol icons, the + * chat window is opened, configured to use the protocol contact + * corresponding to the given icon. + * + * When the right mouse button is clicked on a contact cell, the cell is + * selected and the ContactRightButtonMenu is opened. + * + * When the right mouse button is clicked on a group cell, the cell is + * selected and the GroupRightButtonMenu is opened. + * + * When the middle mouse button is clicked on a cell, the cell is selected. + * @param e the MouseEvent that notified us of the click + */ + public void mouseClicked(MouseEvent e) + { + int selectedIndex = this.getSelectedIndex(); + Object selectedValue = this.getSelectedValue(); + + // If there's no index selected we have nothing to do here. + if (selectedIndex < 0) + return; + + ContactListCellRenderer renderer + = (ContactListCellRenderer) this.getCellRenderer() + .getListCellRendererComponent( this, + selectedValue, + selectedIndex, + true, + true); + + Point selectedCellPoint = this.indexToLocation(selectedIndex); + + int translatedX = e.getX() - selectedCellPoint.x; + + if (selectedValue instanceof MetaContactGroup) + { + MetaContactGroup group = (MetaContactGroup) selectedValue; + + if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0 + || (e.isControlDown() && !e.isMetaDown())) + { + + groupRightButtonMenu = new GroupRightButtonMenu(mainFrame, + group); + + SwingUtilities.convertPointToScreen(selectedCellPoint, this); + + groupRightButtonMenu.setInvoker(this); + + groupRightButtonMenu.setLocation(selectedCellPoint.x, + selectedCellPoint.y + renderer.getHeight()); + + groupRightButtonMenu.setVisible(true); + } + else if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) + { + if(!disableOpenClose) + { + if (listModel.isGroupClosed(group)) + listModel.openGroup(group); + else + listModel.closeGroup(group); + } + + fireContactListEvent( group, + ContactListEvent.GROUP_CLICKED, + e.getClickCount()); + + if(!disableOpenClose) + { + // get the component under the mouse + Component component + = this.getHorizontalComponent(renderer, translatedX); + + if ((component instanceof JPanel) + && ("buttonsPanel".equals(component.getName()))) + { + JPanel panel = (JPanel) component; + int internalX + = translatedX + - (renderer.getWidth() - panel.getWidth() - 2); + Component c = getHorizontalComponent(panel, internalX); + + if (c instanceof JLabel) + { + if (listModel.isGroupClosed(group)) + listModel.openGroup(group); + else + listModel.closeGroup(group); + } + } + } + } + } + + // Open message window, right button menu or contact info when + // mouse is pressed. Distinguish on which component was pressed + // the mouse and make the appropriate work. + if (selectedValue instanceof MetaContact) + { + MetaContact contact = (MetaContact) selectedValue; + + // Right click and Ctrl+LeftClick on the contact label opens + // Popup menu + if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0 + || (e.isControlDown() && !e.isMetaDown())) + { + +// contactRightButtonMenu = new ContactRightButtonMenu(this, +// contact); + + SwingUtilities + .convertPointToScreen(selectedCellPoint, this); + + contactRightButtonMenu.setInvoker(this); + + contactRightButtonMenu.setLocation(selectedCellPoint.x, + selectedCellPoint.y + renderer.getHeight()); + + contactRightButtonMenu.setVisible(true); + } + // Left click on the contact label opens Chat window + else if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0 + && e.getClickCount() > 1) + { + fireContactListEvent(contact, + ContactListEvent.CONTACT_CLICKED, e.getClickCount()); + } + } + } + + /** + * Selects the contact or group under the right mouse click. + * @param e the MouseEvent that notified us of the press + */ + public void mousePressed(MouseEvent e) + { + // Select the meta contact under the right button click. + if ((e.getModifiers() & InputEvent.BUTTON2_MASK) != 0 + || (e.getModifiers() & InputEvent.BUTTON3_MASK) != 0 + || (e.isControlDown() && !e.isMetaDown())) + { + int index = this.locationToIndex(e.getPoint()); + + if (index != -1) + this.setSelectedIndex(index); + } + } + + public void mouseEntered(MouseEvent e) {} + + public void mouseExited(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + /** + * Returns the component positioned at the given x in the given container. + * It's used like getComponentAt. + * + * @param c the container where to search + * @param x the x coordinate of the searched component + * @return the component positioned at the given x in the given container + */ + private Component getHorizontalComponent(Container c, int x) + { + for (int i = 0; i < c.getComponentCount(); i++) + { + Component component = c.getComponent(i); + int componentX = component.getX(); + + if ((x > componentX) && (x < componentX + component.getWidth())) + return component; + } + return null; + } + + /** + * If set to true prevents groups to be closed or opened using the mouse. + * @param disableOpenClose the disableOpenClose to set + */ + public void setDisableOpenClose(boolean disableOpenClose) + { + this.disableOpenClose = disableOpenClose; + } + + /** + * Takes care of keeping the contact list up to date. + */ + private class ContactListRefresh + extends Thread + { + public void run() + { + try + { + while (refreshEnabled) + { + Map copyContentToRefresh; + + synchronized (contentToRefresh) + { + if (contentToRefresh.isEmpty()) + contentToRefresh.wait(); + + copyContentToRefresh + = new Hashtable(contentToRefresh); + contentToRefresh.clear(); + } + + for (Map.Entry groupEntry + : copyContentToRefresh.entrySet()) + { + String operation = groupEntry.getValue(); + Object o = groupEntry.getKey(); + + if (o instanceof MetaContactGroup) + { + MetaContactGroup group = (MetaContactGroup) o; + + SwingUtilities.invokeLater(new RefreshGroup(group, + operation)); + } + else if (o instanceof MetaContact) + { + MetaContact contact = (MetaContact) o; + + SwingUtilities.invokeLater(new RefreshContact( + contact, contact.getParentMetaContactGroup(), + operation)); + } + else if (o instanceof MetaContactEvent) + { + MetaContactEvent event = (MetaContactEvent) o; + MetaContact contact = event.getSourceMetaContact(); + MetaContactGroup parentGroup = event + .getParentGroup(); + + SwingUtilities.invokeLater(new RefreshContact( + contact, parentGroup, operation)); + } + } + } + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + /** + * Refreshes the given group content. + */ + private class RefreshGroup + implements Runnable + { + private final MetaContactGroup group; + + private final String operation; + + public RefreshGroup(MetaContactGroup group, String operation) + { + this.group = group; + this.operation = operation; + } + + public void run() + { + if (operation.equals(MODIFY_OPERATION)) + { + if (!listModel.isGroupClosed(group)) + { + int groupIndex = listModel.indexOf(group); + int lastIndex = listModel + .countContactsAndSubgroups(group); + + listModel.contentChanged(groupIndex, lastIndex); + } + } + else if (operation.equals(ADD_OPERATION)) + { + int groupIndex = listModel.indexOf(group); + int addedCount = listModel.countContactsAndSubgroups(group); + int listSize = listModel.getSize(); + if (listSize > 0) + { + listModel.contentChanged( + groupIndex, listSize - addedCount - 1); + listModel.contentAdded( + listSize - addedCount, listSize - 1); + } + } + else if (operation.equals(REMOVE_OPERATION)) + { + int groupIndex = listModel.indexOf(group); + int removeCount = listModel + .countContactsAndSubgroups(group); + int listSize = listModel.getSize(); + + if (listSize > 0) + { + listModel.contentRemoved(listSize - 1, listSize + + removeCount - 1); + listModel.contentChanged(groupIndex, listSize - 1); + } + } + } + } + + /** + * Refreshes the given contact content. + */ + private class RefreshContact + implements Runnable + { + private final MetaContact contact; + + private final MetaContactGroup parentGroup; + + private final String operation; + + public RefreshContact(MetaContact contact, + MetaContactGroup parentGroup, String operation) + { + this.contact = contact; + this.parentGroup = parentGroup; + this.operation = operation; + } + + public void run() + { + if (operation.equals(MODIFY_OPERATION)) + { + int contactIndex = listModel.indexOf(contact); + + listModel.contentChanged(contactIndex, contactIndex); + } + else if (operation.equals(ADD_OPERATION)) + { + int contactIndex = listModel.indexOf(contact); + + if (contactIndex != -1) + listModel.contentAdded(contactIndex, contactIndex); + } + else if (operation.equals(REMOVE_OPERATION)) + { + int groupIndex = listModel.indexOf(parentGroup); + + int listSize = listModel.getSize(); + + if (groupIndex != -1 && listSize > 0) + { + listModel.contentChanged(groupIndex, listSize - 1); + listModel.contentRemoved(listSize, listSize); + } + } + } + } + } + + /** + * Refreshes the given group content. + * + * @param group the group to refresh + */ + public void modifyGroup(MetaContactGroup group) + { + synchronized (contentToRefresh) + { + if (group != null + && (!contentToRefresh.containsKey(group) || contentToRefresh + .get(group).equals(REMOVE_OPERATION))) + { + + contentToRefresh.put(group, MODIFY_OPERATION); + contentToRefresh.notifyAll(); + } + } + } + + /** + * Refreshes all the contact list. + * @param group the MetaContactGroup to add + */ + public void addGroup(MetaContactGroup group) + { + synchronized (contentToRefresh) + { + if (group != null + && (!contentToRefresh.containsKey(group) || contentToRefresh + .get(group).equals(REMOVE_OPERATION))) + { + + contentToRefresh.put(group, ADD_OPERATION); + contentToRefresh.notifyAll(); + } + } + } + + /** + * Refreshes all the contact list. + * @param group the MetaContactGroup to remove + */ + public void removeGroup(MetaContactGroup group) + { + synchronized (contentToRefresh) + { + if (group != null + && (contentToRefresh.get(group) == null || !contentToRefresh + .get(group).equals(REMOVE_OPERATION))) + { + + contentToRefresh.put(group, REMOVE_OPERATION); + contentToRefresh.notifyAll(); + } + } + } + + /** + * Refreshes the given meta contact content. + * + * @param contact the meta contact to refresh + */ + public void refreshContact(MetaContact contact) + { + synchronized (contentToRefresh) + { + if (contact != null + && !contentToRefresh.containsKey(contact) + && !contentToRefresh.containsKey( + contact.getParentMetaContactGroup())) + { + + contentToRefresh.put(contact, MODIFY_OPERATION); + contentToRefresh.notifyAll(); + } + } + } + + /** + * Refreshes the whole contact list. + */ + public void refreshAll() + { + this.modifyGroup(contactListService.getRoot()); + } + + /** + * Adds the given contact to the contact list. + * @param contact the MetaContact to add + */ + public void addContact(MetaContact contact) + { + synchronized (contentToRefresh) + { + if (contact != null + && !contentToRefresh.containsKey(contact) + && !contentToRefresh.containsKey( + contact.getParentMetaContactGroup())) + { + + contentToRefresh.put(contact, ADD_OPERATION); + contentToRefresh.notifyAll(); + } + } + } + + /** + * Refreshes all the contact list. + * @param event the MetaContactEvent, from which we get the contact + * to remove + */ + public void removeContact(MetaContactEvent event) + { + synchronized (contentToRefresh) + { + if (event.getSourceMetaContact() != null + && !contentToRefresh.containsKey(event)) + { + contentToRefresh.put(event, REMOVE_OPERATION); + contentToRefresh.notifyAll(); + } + } + } + + /** + * Selects the given object in the list. + * + * @param o the object to select + */ + public void setSelectedValue(Object o) + { + setSelectedIndex((o == null) ? -1 : listModel.indexOf(o)); + } + + /** + * Returns the right button menu for a contact. + * + * @return the right button menu for a contact + */ + public MetaContactRightButtonMenu getContactRightButtonMenu() + { + return contactRightButtonMenu; + } + + /** + * Returns the right button menu for a group. + * + * @return the right button menu for a group + */ + public GroupRightButtonMenu getGroupRightButtonMenu() + { + return groupRightButtonMenu; + } + + /** + * Sets the showOffline property. + * + * @param isShowOffline TRUE to show all offline users, FALSE to hide + * offline users. + */ + public void setShowOffline(boolean isShowOffline) + { + Object selectedObject = null; + int currentlySelectedIndex = this.getSelectedIndex(); + + if(currentlySelectedIndex != -1) + { + selectedObject = listModel.getElementAt(currentlySelectedIndex); + } + + int listSize = listModel.getSize(); + + listModel.setShowOffline(isShowOffline); + + ConfigurationManager.setShowOffline(isShowOffline); + + int newListSize = listModel.getSize(); + + //hide offline users + if(!isShowOffline && listSize > 0) + { + if(newListSize > 0) + { + listModel.contentChanged(0, newListSize - 1); + listModel.contentRemoved(newListSize - 1, listSize - 1); + } + else + listModel.contentRemoved(0, listSize - 1); + } + //show offline users + else if(isShowOffline && newListSize > 0) + { + if(listSize > 0) + { + listModel.contentChanged(0, listSize - 1); + listModel.contentAdded(listSize - 1, newListSize - 1); + } + else + listModel.contentAdded(0, newListSize - 1); + } + + // Try to set the previously selected object. + if (selectedObject != null) + { + this.setSelectedIndex(listModel.indexOf(selectedObject)); + } + } + + /** + * Returns the main frame. + * + * @return the main frame + */ + public MainFrame getMainFrame() + { + return mainFrame; + } + + /** + * Moves the given srcContact to the destMetaContact. + * @param srcContact the Contact to move + * @param destMetaContact the destination MetaContact to move to + */ + public void moveContactToMetaContact( Contact srcContact, + MetaContact destMetaContact) + { + new MoveContactToMetaContactThread(srcContact, destMetaContact).start(); + } + + /** + * Moves the given Contact to the given MetaContact and + * asks user for confirmation. + */ + private class MoveContactToMetaContactThread extends Thread + { + private final Contact srcContact; + private final MetaContact destMetaContact; + + public MoveContactToMetaContactThread( Contact srcContact, + MetaContact destMetaContact) + { + this.srcContact = srcContact; + this.destMetaContact = destMetaContact; + } + + @SuppressWarnings("fallthrough") //intentional + public void run() + { + if (!ConfigurationManager.isMoveContactConfirmationRequested()) + { + // we move the specified contact + GuiActivator.getContactListService().moveContact( + srcContact, destMetaContact); + + return; + } + + String message = GuiActivator.getResources().getI18NString( + "service.gui.MOVE_SUBCONTACT_QUESTION", + new String[]{ srcContact.getDisplayName(), + destMetaContact.getDisplayName()}); + + MessageDialog dialog = new MessageDialog( + mainFrame, + GuiActivator.getResources() + .getI18NString("service.gui.MOVE_CONTACT"), + message, + GuiActivator.getResources() + .getI18NString("service.gui.MOVE")); + + switch (dialog.showDialog()) + { + case MessageDialog.OK_DONT_ASK_CODE: + ConfigurationManager.setMoveContactConfirmationRequested(false); + // do fall through + + case MessageDialog.OK_RETURN_CODE: + // we move the specified contact + GuiActivator.getContactListService().moveContact( + srcContact, destMetaContact); + break; + } + } + } + + /** + * Moves the given srcMetaContact to the destMetaContact. + * @param srcMetaContact the MetaContact to move + * @param destMetaContact the destination MetaContact to move to + */ + public void moveMetaContactToMetaContact( MetaContact srcMetaContact, + MetaContact destMetaContact) + { + new MoveMetaContactToMetaContactThread(srcMetaContact, destMetaContact) + .start(); + } + + /** + * Moves the given Contact to the given MetaContact and + * asks user for confirmation. + */ + private class MoveMetaContactToMetaContactThread extends Thread + { + private final MetaContact srcMetaContact; + private final MetaContact destMetaContact; + + public MoveMetaContactToMetaContactThread( MetaContact srcContact, + MetaContact destMetaContact) + { + this.srcMetaContact = srcContact; + this.destMetaContact = destMetaContact; + } + + @SuppressWarnings("fallthrough") //intentional + public void run() + { + if (!ConfigurationManager.isMoveContactConfirmationRequested()) + { + // We move all subcontacts of the source MetaContact to the + // destination MetaContact. + this.moveAllSubcontacts(); + + return; + } + + String message = GuiActivator.getResources().getI18NString( + "service.gui.MOVE_SUBCONTACT_QUESTION", + new String[]{ srcMetaContact.getDisplayName(), + destMetaContact.getDisplayName()}); + + MessageDialog dialog = new MessageDialog( + mainFrame, + GuiActivator.getResources() + .getI18NString("service.gui.MOVE_CONTACT"), + message, + GuiActivator.getResources() + .getI18NString("service.gui.MOVE")); + + switch (dialog.showDialog()) + { + case MessageDialog.OK_DONT_ASK_CODE: + ConfigurationManager.setMoveContactConfirmationRequested(false); + // do fall through + + case MessageDialog.OK_RETURN_CODE: + // We move all subcontacts of the source MetaContact to the + // destination MetaContact. + this.moveAllSubcontacts(); + break; + } + } + + /** + * Move all subcontacts of the srcMetaContact to + * destMetaContact. + */ + private void moveAllSubcontacts() + { + Iterator contacts = srcMetaContact.getContacts(); + while(contacts.hasNext()) + { + GuiActivator.getContactListService().moveContact( + contacts.next(), destMetaContact); + } + } + } + + /** + * Moves the given srcContact to the destGroup. + * @param srcContact the Contact to move + * @param destGroup the destination MetaContactGroup to move to + */ + public void moveContactToGroup( Contact srcContact, + MetaContactGroup destGroup) + { + new MoveContactToGroupThread(srcContact, destGroup).start(); + } + + /** + * Moves the given Contact to the given MetaContactGroup + * and asks user for confirmation. + */ + @SuppressWarnings("fallthrough") + private class MoveContactToGroupThread extends Thread + { + private final Contact srcContact; + private final MetaContactGroup destGroup; + + public MoveContactToGroupThread(Contact srcContact, + MetaContactGroup destGroup) + { + this.srcContact = srcContact; + this.destGroup = destGroup; + } + + public void run() + { + if (!ConfigurationManager.isMoveContactConfirmationRequested()) + { + // we move the specified contact + GuiActivator.getContactListService().moveContact( + srcContact, destGroup); + + return; + } + + String message = GuiActivator.getResources().getI18NString( + "service.gui.MOVE_SUBCONTACT_QUESTION", + new String[]{ srcContact.getDisplayName(), + destGroup.getGroupName()}); + + MessageDialog dialog = new MessageDialog( + mainFrame, + GuiActivator.getResources() + .getI18NString("service.gui.MOVE_CONTACT"), + message, + GuiActivator.getResources() + .getI18NString("service.gui.MOVE")); + + switch (dialog.showDialog()) + { + case MessageDialog.OK_DONT_ASK_CODE: + ConfigurationManager.setMoveContactConfirmationRequested(false); + // do fall through + + case MessageDialog.OK_RETURN_CODE: + // we move the specified contact + GuiActivator.getContactListService().moveContact( + srcContact, destGroup); + break; + } + } + } + + /** + * Moves the given srcContact to the destGroup. + * @param srcContact the MetaContact to move + * @param destGroup the destination MetaContactGroup to move to + */ + public void moveMetaContactToGroup( MetaContact srcContact, + MetaContactGroup destGroup) + { + new MoveMetaContactThread(srcContact, destGroup).start(); + } + + /** + * Moves the given MetaContact to the given MetaContactGroup + * and asks user for confirmation. + */ + private class MoveMetaContactThread + extends Thread + { + private final MetaContact srcContact; + private final MetaContactGroup destGroup; + + public MoveMetaContactThread( MetaContact srcContact, + MetaContactGroup destGroup) + { + this.srcContact = srcContact; + this.destGroup = destGroup; + } + + @SuppressWarnings("fallthrough") + public void run() + { + if (!ConfigurationManager.isMoveContactConfirmationRequested()) + { + // we move the specified contact + try + { + GuiActivator.getContactListService().moveMetaContact( + srcContact, destGroup); + } + catch (MetaContactListException e) + { + + } + + return; + } + + String message = GuiActivator.getResources().getI18NString( + "service.gui.MOVE_SUBCONTACT_QUESTION", + new String[]{ srcContact.getDisplayName(), + destGroup.getGroupName()}); + + MessageDialog dialog = new MessageDialog( + mainFrame, + GuiActivator.getResources() + .getI18NString("service.gui.MOVE_CONTACT"), + message, + GuiActivator.getResources() + .getI18NString("service.gui.MOVE")); + + switch (dialog.showDialog()) + { + case MessageDialog.OK_DONT_ASK_CODE: + ConfigurationManager.setMoveContactConfirmationRequested(false); + // do fall through + + case MessageDialog.OK_RETURN_CODE: + // we move the specified contact + GuiActivator.getContactListService().moveMetaContact( + srcContact, destGroup); + break; + } + } + } + + /** + * Adds the given MetaContact to the list of active contacts. + * + * @param metaContact the MetaContact to add. + */ + public void addActiveContact(MetaContact metaContact) + { + synchronized (activeContacts) + { + if(activeContacts.size() == 0) + { + SystrayService stray = GuiActivator.getSystrayService(); + + if (stray != null) + stray.setSystrayIcon(SystrayService.ENVELOPE_IMG_TYPE); + } + + if(!activeContacts.contains(metaContact)) + activeContacts.add(metaContact); + } + + this.refreshContact(metaContact); + } + + /** + * Removes the given MetaContact from the list of active contacts. + * + * @param metaContact the MetaContact to remove. + */ + public void removeActiveContact(MetaContact metaContact) + { + synchronized (activeContacts) + { + activeContacts.remove(metaContact); + + if(activeContacts.size() == 0) + GuiActivator.getSystrayService().setSystrayIcon( + SystrayService.SC_IMG_TYPE); + } + + this.refreshContact(metaContact); + } + + /** + * Removes all contacts from the list of active contacts. + */ + public void removeAllActiveContacts() + { + synchronized (activeContacts) + { + if(activeContacts.size() > 0) + { + activeContacts.clear(); + + GuiActivator.getSystrayService().setSystrayIcon( + SystrayService.SC_IMG_TYPE); + } + } + + this.refreshAll(); + } + + /** + * Checks if the given contact is currently active. + * + * @param metaContact the MetaContact to verify + * @return TRUE if the given MetaContact is active, FALSE - + * otherwise + */ + public boolean isMetaContactActive(MetaContact metaContact) + { + synchronized (activeContacts) + { + return activeContacts.contains(metaContact); + } + } + + /** + * Resets the contained mouse listeners and adds the given one. This allows + * other components to integrate the contact list by specifying their own + * mouse events. + * + * @param l the mouse listener to set. + */ + public void setMouseListener(MouseListener l) + { + this.removeMouseListener(this); + this.addMouseListener(l); + } + + /** + * Checks whether the group is closed. + * + * @param group The group to check. + * @return True if the group is closed, false - otherwise. + */ + @Override + public boolean isGroupClosed(MetaContactGroup group) + { + return this.listModel.isGroupClosed(group); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java index e11ad77..545955c 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java @@ -23,6 +23,8 @@ import net.java.sip.communicator.impl.gui.main.contactlist.notifsource.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.gui.event.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.Logger; @@ -38,11 +40,13 @@ import org.osgi.framework.*; */ public class TreeContactList extends DefaultTreeContactList - implements ContactQueryListener, + implements ContactList, + ContactQueryListener, MetaContactQueryListener, MouseListener, MouseMotionListener, - TreeExpansionListener + TreeExpansionListener, + TreeSelectionListener { /** * Serial version UID. @@ -63,7 +67,7 @@ public class TreeContactList /** * The right button menu. */ - private JPopupMenu rightButtonMenu; + private Component rightButtonMenu; /** * A list of all contacts that are currently "active". An "active" contact @@ -107,7 +111,7 @@ public class TreeContactList /** * The current filter. */ - private ContactListFilter currentFilter; + private ContactListFilter currentFilter = defaultFilter; /** * Indicates if the click on a group node has been already consumed. This @@ -120,12 +124,12 @@ public class TreeContactList */ private MouseListener[] originalMouseListeners; - private static final Collection contactSources - = new LinkedList(); + private final Collection + contactSources = new LinkedList(); private static NotificationContactSource notificationSource; - private FilterQuery currentFilterQuery; + private UIFilterQuery currentFilterQuery; private FilterThread filterThread; @@ -148,6 +152,7 @@ public class TreeContactList this.addMouseListener(this); this.addMouseMotionListener(this); this.addTreeExpansionListener(this); + this.addTreeSelectionListener(this); GuiActivator.getContactListService() .addMetaContactListListener(mclSource); @@ -176,8 +181,7 @@ public class TreeContactList ContactSourceService contactSource = sourceContact.getContactSource(); - ExternalContactSource sourceUI - = TreeContactList.getContactSource(contactSource); + UIContactSource sourceUI = getContactSource(contactSource); if (sourceUI == null) return; @@ -196,7 +200,7 @@ public class TreeContactList } else { - ExternalContactSource.removeUIContact(sourceContact); + sourceUI.removeUIContact(sourceContact); uiContact = null; } } @@ -213,14 +217,13 @@ public class TreeContactList ContactSourceService contactSource = sourceContact.getContactSource(); - ExternalContactSource sourceUI - = TreeContactList.getContactSource(contactSource); + UIContactSource sourceUI = getContactSource(contactSource); if (sourceUI == null) return; UIContact uiContact - = ExternalContactSource.getUIContact(sourceContact); + = sourceUI.getUIContact(sourceContact); if(uiContact == null) return; @@ -235,6 +238,35 @@ public class TreeContactList } /** + * Indicates that a contact has been updated after a search. + * @param event the ContactQueryEvent containing information + * about the updated SourceContact + */ + public void contactChanged(ContactChangedEvent event) + { + final SourceContact sourceContact = event.getContact(); + + ContactSourceService contactSource + = sourceContact.getContactSource(); + + UIContactSource sourceUI = getContactSource(contactSource); + + if (sourceUI == null) + return; + + UIContact uiContact + = sourceUI.getUIContact(sourceContact); + + if(uiContact == null || !(uiContact instanceof UIContactImpl)) + return; + + ContactNode contactNode = ((UIContactImpl) uiContact).getContactNode(); + + if (contactNode != null) + nodeChanged(contactNode); + } + + /** * Indicates that a MetaContact has been received for a search in * the MetaContactListService. * @param event the received MetaContactQueryEvent @@ -355,7 +387,7 @@ public class TreeContactList */ public void setActiveContact(MetaContact metaContact, boolean isActive) { - UIContact uiContact + UIContactImpl uiContact = MetaContactListSource.getUIContact(metaContact); if (uiContact == null) @@ -389,7 +421,7 @@ public class TreeContactList * @return true if the given metaContact has been * previously set to active, otherwise returns false */ - public boolean isContactActive(UIContact contact) + public boolean isContactActive(UIContactImpl contact) { ContactNode contactNode = contact.getContactNode(); @@ -423,30 +455,40 @@ public class TreeContactList return; } - GroupNode groupNode; + GroupNode groupNode = null; if (group == null) groupNode = treeModel.getRoot(); - else + else if (group instanceof UIGroupImpl) { - groupNode = group.getGroupNode(); + UIGroupImpl contactImpl = (UIGroupImpl) group; + + groupNode = contactImpl.getGroupNode(); if (groupNode == null) { GroupNode parentNode = treeModel.getRoot(); if (isGroupSorted) - groupNode = parentNode.sortedAddContactGroup(group); + groupNode = parentNode.sortedAddContactGroup(contactImpl); else - groupNode = parentNode.addContactGroup(group); + groupNode = parentNode.addContactGroup(contactImpl); } } + if (groupNode == null) + return; + contact.setParentGroup(groupNode.getGroupDescriptor()); + if (!(contact instanceof UIContactImpl)) + return; + + UIContactImpl contactImpl = (UIContactImpl) contact; + if (isContactSorted) - groupNode.sortedAddContact(contact); + groupNode.sortedAddContact(contactImpl); else - groupNode.addContact(contact); + groupNode.addContact(contactImpl); if ((!currentFilter.equals(presenceFilter) || !groupNode.isCollapsed())) @@ -526,7 +568,8 @@ public class TreeContactList * @param contact the UIContact to remove * @param removeEmptyGroup whether we should delete the group if is empty */ - public void removeContact(final UIContact contact, final boolean removeEmptyGroup) + public void removeContact( final UIContact contact, + final boolean removeEmptyGroup) { if (!SwingUtilities.isEventDispatchThread()) { @@ -540,7 +583,10 @@ public class TreeContactList return; } - UIGroup parentGroup = contact.getParentGroup(); + if (!(contact instanceof UIContactImpl)) + return; + + UIGroupImpl parentGroup = (UIGroupImpl) contact.getParentGroup(); if (parentGroup == null) return; @@ -551,7 +597,7 @@ public class TreeContactList if (parentGroupNode == null) return; - parentGroupNode.removeContact(contact); + parentGroupNode.removeContact((UIContactImpl) contact); // If the parent group is empty remove it. if (removeEmptyGroup && parentGroupNode.getChildCount() == 0) @@ -593,7 +639,10 @@ public class TreeContactList return; } - treeModel.nodeChanged(contact.getContactNode()); + if (!(contact instanceof UIContactImpl)) + return; + + treeModel.nodeChanged(((UIContactImpl) contact).getContactNode()); } /** @@ -616,16 +665,21 @@ public class TreeContactList return; } - GroupNode groupNode = group.getGroupNode(); - + if (!(group instanceof UIGroupImpl)) + return; + + UIGroupImpl groupImpl = (UIGroupImpl) group; + + GroupNode groupNode = groupImpl.getGroupNode(); + if(groupNode == null) { GroupNode parentNode = treeModel.getRoot(); if (isSorted) - parentNode.sortedAddContactGroup(group); + parentNode.sortedAddContactGroup(groupImpl); else - parentNode.addContactGroup(group); + parentNode.addContactGroup(groupImpl); } expandGroup(treeModel.getRoot()); @@ -649,7 +703,10 @@ public class TreeContactList return; } - UIGroup parentGroup = group.getParentGroup(); + if (!(group instanceof UIGroupImpl)) + return; + + UIGroupImpl parentGroup = (UIGroupImpl) group.getParentGroup(); GroupNode parentGroupNode; @@ -667,7 +724,7 @@ public class TreeContactList if (parentGroupNode == null) return; - parentGroupNode.removeContactGroup(group); + parentGroupNode.removeContactGroup((UIGroupImpl) group); // If the parent group is empty remove it. if (parentGroupNode.getChildCount() == 0) @@ -765,7 +822,7 @@ public class TreeContactList if (currentFilterQuery != null && !currentFilterQuery.isCanceled()) currentFilterQuery.cancel(); - currentFilterQuery = new FilterQuery(); + currentFilterQuery = new UIFilterQuery(); if (filterThread == null) { @@ -803,7 +860,7 @@ public class TreeContactList { while (true) { - FilterQuery filterQuery = currentFilterQuery; + UIFilterQuery filterQuery = currentFilterQuery; ContactListFilter filter = this.filter; treeModel.clear(); @@ -945,6 +1002,12 @@ public class TreeContactList case ContactListEvent.GROUP_CLICKED: listener.groupClicked(event); break; + case ContactListEvent.CONTACT_SELECTED: + listener.contactSelected(event); + break; + case ContactListEvent.GROUP_SELECTED: + listener.groupSelected(event); + break; default: logger.error("Unknown event type " + event.getEventID()); } @@ -1152,7 +1215,9 @@ public class TreeContactList SwingUtilities.convertPointToScreen(contactListPoint, this); - rightButtonMenu.setInvoker(this); + if (rightButtonMenu instanceof JPopupMenu) + ((JPopupMenu) rightButtonMenu).setInvoker(this); + rightButtonMenu.setLocation(contactListPoint.x, contactListPoint.y); rightButtonMenu.setVisible(true); } @@ -1443,7 +1508,7 @@ public class TreeContactList for (ContactSourceService contactSource : GuiActivator.getContactSources()) { - contactSources.add(new ExternalContactSource(contactSource)); + contactSources.add(new ExternalContactSource(contactSource, this)); } GuiActivator.bundleContext.addServiceListener( new ContactSourceServiceListener()); @@ -1453,7 +1518,7 @@ public class TreeContactList * Returns the list of registered contact sources to search in. * @return the list of registered contact sources to search in */ - public static Collection getContactSources() + public Collection getContactSources() { return contactSources; } @@ -1478,15 +1543,14 @@ public class TreeContactList * @return the ExternalContactSource corresponding to the given * ContactSourceService */ - public static ExternalContactSource getContactSource( - ContactSourceService contactSource) + public UIContactSource getContactSource(ContactSourceService contactSource) { - Iterator extSourcesIter + Iterator extSourcesIter = contactSources.iterator(); while (extSourcesIter.hasNext()) { - ExternalContactSource extSource = extSourcesIter.next(); + UIContactSource extSource = extSourcesIter.next(); if (extSource.getContactSourceService().equals(contactSource)) return extSource; @@ -1499,14 +1563,14 @@ public class TreeContactList * @param identifier the identifier we're looking for * @return the contact source with the given identifier */ - public static ExternalContactSource getContactSource(String identifier) + public UIContactSource getContactSource(String identifier) { - Iterator extSourcesIter + Iterator extSourcesIter = contactSources.iterator(); while (extSourcesIter.hasNext()) { - ExternalContactSource extSource = extSourcesIter.next(); + UIContactSource extSource = extSourcesIter.next(); if (extSource.getContactSourceService().getIdentifier() .equals(identifier)) @@ -1524,7 +1588,7 @@ public class TreeContactList * @param imgWidth the desired image width * @param imgHeight the desired image height */ - public static void setSourceContactImage( String contactString, + public void setSourceContactImage( String contactString, final JLabel label, final int imgWidth, final int imgHeight) @@ -1536,8 +1600,8 @@ public class TreeContactList Pattern filterPattern = Pattern.compile( "^" + Pattern.quote(contactString) + "$", Pattern.UNICODE_CASE); - Iterator contactSources - = TreeContactList.getContactSources().iterator(); + Iterator contactSources + = getContactSources().iterator(); final Vector loadedQueries = new Vector(); @@ -1589,6 +1653,14 @@ public class TreeContactList */ public void contactRemoved(ContactRemovedEvent event) {} + + /** + * Indicates that a contact has been updated after a search. + * @param event the ContactQueryEvent containing information + * about the updated SourceContact + */ + public void contactChanged(ContactChangedEvent event) + {} }); // If the image search has been canceled from one of the @@ -1792,12 +1864,13 @@ public class TreeContactList { case ServiceEvent.REGISTERED: ExternalContactSource contactSource - = new ExternalContactSource((ContactSourceService) service); + = new ExternalContactSource( + (ContactSourceService) service, TreeContactList.this); contactSources.add(contactSource); changed = true; break; case ServiceEvent.UNREGISTERING: - ExternalContactSource cSource + UIContactSource cSource = getContactSource((ContactSourceService) service); if (cSource != null) contactSources.remove(cSource); @@ -1887,4 +1960,124 @@ public class TreeContactList { return mclSource; } + + public Component getComponent() + { + return this; + } + + /** + * Selects the given UIContact in the contact list. + * + * @param uiContact the contact to select + */ + public void setSelectedContact(final UIContact uiContact) + { + if (!SwingUtilities.isEventDispatchThread()) + { + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + setSelectedContact(uiContact); + } + }); + return; + } + + if (!(uiContact instanceof UIContactImpl)) + return; + + setSelectionPath(new TreePath( + ((UIContactImpl) uiContact).getContactNode().getPath())); + } + + /** + * Selects the given UIGroup in the contact list. + * + * @param uiGroup the group to select + */ + public void setSelectedGroup(final UIGroup uiGroup) + { + if (!SwingUtilities.isEventDispatchThread()) + { + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + setSelectedGroup(uiGroup); + } + }); + return; + } + + if (!(uiGroup instanceof UIGroupImpl)) + return; + + setSelectionPath(new TreePath( + ((UIGroupImpl) uiGroup).getGroupNode().getPath())); + } + + /** + * Returns the currently selected UIContact if there's one. + * + * @return the currently selected UIContact if there's one. + */ + public UIContact getSelectedContact() + { + TreePath selectionPath = getSelectionPath(); + + if (selectionPath != null + && selectionPath.getLastPathComponent() instanceof ContactNode) + { + return ((ContactNode) selectionPath.getLastPathComponent()) + .getContactDescriptor(); + } + + return null; + } + + /** + * Returns the currently selected UIGroup if there's one. + * + * @return the currently selected UIGroup if there's one. + */ + public UIGroup getSelectedGroup() + { + TreePath selectionPath = getSelectionPath(); + + if (selectionPath != null + && selectionPath.getLastPathComponent() instanceof GroupNode) + { + return ((GroupNode) selectionPath.getLastPathComponent()) + .getGroupDescriptor(); + } + + return null; + } + + /** + * Indicates that a selection has occurred on the tree. + * + * @param e the TreeSelectionEvent that notified us of the change + */ + public void valueChanged(TreeSelectionEvent e) + { + UIGroup selectedGroup = getSelectedGroup(); + + if (selectedGroup != null) + { + fireContactListEvent( + selectedGroup, ContactListEvent.GROUP_SELECTED, 0); + } + else + { + UIContact selectedContact = getSelectedContact(); + if (selectedContact != null) + { + fireContactListEvent( + selectedContact, ContactListEvent.GROUP_SELECTED, 0); + } + } + } } diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContact.java deleted file mode 100644 index 770a2a4..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContact.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -import java.util.*; - -import javax.swing.*; - -import net.java.sip.communicator.impl.gui.utils.*; -import net.java.sip.communicator.service.protocol.*; -import net.java.sip.communicator.util.swing.*; - -/** - * The UIContact represents the user interface contact contained in the - * contact list component. - * - * @author Yana Stamcheva - */ -public interface UIContact -{ - /** - * Returns the descriptor of this contact. - * - * @return the descriptor of this contact - */ - public Object getDescriptor(); - - /** - * Returns the display name of this contact. - * - * @return the display name of this contact - */ - public String getDisplayName(); - - /** - * Returns the display details of this contact. These would be shown - * whenever the contact is selected. - * - * @return the display details of this contact - */ - public String getDisplayDetails(); - - /** - * Returns the index of this contact in its source. - * - * @return the source index - */ - public int getSourceIndex(); - - /** - * Returns the avatar of this contact. - * - * @param isSelected indicates if the contact is selected - * @param width the width of the avatar - * @param height the height of the avatar - * @return the avatar of this contact - */ - public ImageIcon getAvatar(boolean isSelected, int width, int height); - - /** - * Returns the status icon of this contact or null if no status is - * available. - * - * @return the status icon of this contact or null if no status is - * available - */ - public ImageIcon getStatusIcon(); - - /** - * Creates a tool tip for this contact. If such tooltip is - * provided it would be shown on mouse over over this UIContact. - * - * @return the tool tip for this contact descriptor - */ - public ExtendedTooltip getToolTip(); - - /** - * Returns the right button menu component. - * - * @return the right button menu component - */ - public JPopupMenu getRightButtonMenu(); - - /** - * Returns the parent group. - * - * @return the parent group - */ - public UIGroup getParentGroup(); - - /** - * Sets the given UIGroup to be the parent group of this - * UIContact. - * - * @param parentGroup the parent UIGroup of this contact - */ - public void setParentGroup(UIGroup parentGroup); - - /** - * Returns an Iterator over a list of the search strings of this - * contact. - * - * @return an Iterator over a list of the search strings of this - * contact - */ - public Iterator getSearchStrings(); - - /** - * Returns the corresponding ContactNode. The ContactNode - * is the real node that is stored in the contact list component data model. - * - * @return the corresponding ContactNode - */ - public ContactNode getContactNode(); - - /** - * Sets the given contactNode. The ContactNode - * is the real node that is stored in the contact list component data model. - * - * @param contactNode the ContactNode that corresponds to this - * UIGroup - */ - public void setContactNode(ContactNode contactNode); - - /** - * Returns the default ContactDetail to use for any operations - * depending to the given OperationSet class. - * - * @param opSetClass the OperationSet class we're interested in - * @return the default ContactDetail to use for any operations - * depending to the given OperationSet class - */ - public UIContactDetail getDefaultContactDetail( - Class opSetClass); - - /** - * Returns a list of all UIContactDetails corresponding to the - * given OperationSet class. - * - * @param opSetClass the OperationSet class we're looking for - * @return a list of all UIContactDetails corresponding to the - * given OperationSet class - */ - public List getContactDetailsForOperationSet( - Class opSetClass); - - /** - * Returns a list of all UIContactDetails within this - * UIContact. - * - * @return a list of all UIContactDetails within this - * UIContact - */ - public List getContactDetails(); - - /** - * Returns all custom action buttons for this notification contact. - * - * @return a list of all custom action buttons for this notification contact - */ - public Collection getContactCustomActionButtons(); -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetail.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetail.java deleted file mode 100644 index 3790f68..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetail.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -import java.util.*; - -import javax.swing.*; - -import net.java.sip.communicator.service.protocol.*; - -/** - * The UIContactDetail corresponds to a particular contact detail, - * phone number, IM identifier, email, etc. which has it's preferred mode of - * transport ProtocolProviderService. - * - * @author Yana Stamcheva - */ -public abstract class UIContactDetail -{ - /** - * The prefix to be used when calling this contact detail. - */ - private String prefix; - - /** - * The address of this detail. - */ - private final String address; - - /** - * The display name of this detail. - */ - private final String displayName; - - /** - * The status icon of this contact detail. - */ - private final ImageIcon statusIcon; - - /** - * The ProtocolProviderService corresponding to this detail. - */ - private final ProtocolProviderService protocolProvider; - - /** - * The protocol to be used for this contact detail if no protocol provider - * is set. - */ - private final String preferredProtocol; - - /** - * The collection of labels associated with this detail. - */ - private final Collection labels; - - /** - * The category of the underlying contact detail. - */ - private final String category; - - /** - * The underlying object that this class is wrapping - */ - private final Object descriptor; - - /** - * Creates a UIContactDetail by specifying the contact - * address, the displayName and preferredProvider. - * @param address the contact address - * @param displayName the contact display name - * @param category the category of the underlying contact detail - * @param labels the collection of labels associated with this detail - * @param statusIcon the status icon of this contact detail - * @param preferredProvider the preferred protocol provider - * @param preferredProtocol the preferred protocol if no protocol provider - * is set - * @param descriptor the underlying object that this class is wrapping - */ - public UIContactDetail( - String address, - String displayName, - String category, - Collection labels, - ImageIcon statusIcon, - ProtocolProviderService preferredProvider, - String preferredProtocol, - Object descriptor) - { - this.address = address; - this.displayName = displayName; - this.category = category; - this.labels = labels; - this.statusIcon = statusIcon; - this.protocolProvider = preferredProvider; - this.preferredProtocol = preferredProtocol; - this.descriptor = descriptor; - } - - /** - * Returns the display name of this detail. - * @return the display name of this detail - */ - public String getDisplayName() - { - return displayName; - } - - /** - * Returns the address of this detail. - * @return the address of this detail - */ - public String getAddress() - { - if (prefix != null && prefix.trim().length() >= 0) - return prefix + address; - - return address; - } - - /** - * Returns the category of the underlying detail. - * - * @return the category of the underlying detail - */ - public String getCategory() - { - return category; - } - - /** - * Returns an iterator over the collection of labels associated with this - * detail. - * - * @return an iterator over the collection of labels associated with this - * detail - */ - public Iterator getLabels() - { - if (labels != null) - return labels.iterator(); - - return null; - } - - /** - * Returns the status icon of this contact detail. - * - * @return the status icon of this contact detail - */ - public ImageIcon getStatusIcon() - { - return statusIcon; - } - - /** - * Returns the protocol provider preferred for contacting this detail for - * the given OperationSet class. - * @param opSetClass the OperationSet class for which we're looking - * for provider - * @return the protocol provider preferred for contacting this detail - */ - public ProtocolProviderService getPreferredProtocolProvider( - Class opSetClass) - { - return protocolProvider; - } - - /** - * Returns the name of the protocol preferred for contacting this detail for - * the given OperationSet class if no preferred protocol provider - * is set. - * @param opSetClass the OperationSet class for which we're looking - * for protocol - * @return the name of the protocol preferred for contacting this detail - */ - public String getPreferredProtocol(Class opSetClass) - { - return preferredProtocol; - } - - /** - * Returns the prefix to be used when calling this contact detail. - * - * @return the prefix to be used when calling this contact detail - */ - public String getPrefix() - { - return prefix; - } - - /** - * Sets the prefix to be used when calling this contact detail. - * - * @param prefix the prefix to be used when calling this contact detail - */ - public void setPrefix(String prefix) - { - this.prefix = prefix; - } - - /** - * Returns the underlying object that this class is wrapping - * - * @return the underlying object that this class is wrapping - */ - public Object getDescriptor() - { - return descriptor; - } - - /** - * Returns the PresenceStatus of this ContactDetail or - * null if the detail doesn't support presence. - * @return the PresenceStatus of this ContactDetail or - * null if the detail doesn't support presence - */ - public abstract PresenceStatus getPresenceStatus(); -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailAction.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailAction.java deleted file mode 100644 index fb20936..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailAction.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -/** - * Defines an action for an UIContactDetail. - * - * @author Yana Stamcheva - */ -public interface UIContactDetailAction -{ - /** - * Indicates this action is executed for the given UIContactDetail. - * - * @param contactDetail the UIContactDetail for which this action - * is performed - * @param x the x coordinate of the action - * @param y the y coordinate of the action - */ - public void actionPerformed (UIContactDetail contactDetail, int x, int y); -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailImpl.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailImpl.java new file mode 100644 index 0000000..71b3634 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactDetailImpl.java @@ -0,0 +1,83 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.contactlist; + +import java.util.*; + +import javax.swing.*; + +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; + +/** + * The UIContactDetail implementation + * + * @author Yana Stamcheva + */ +public class UIContactDetailImpl + extends UIContactDetail +{ + /** + * The status icon of this contact detail. + */ + private ImageIcon statusIcon; + + /** + * Creates a UIContactDetailImpl by specifying the contact + * address, the displayName and preferredProvider. + * @param address the contact address + * @param displayName the contact display name + * @param category the category of the underlying contact detail + * @param labels the collection of labels associated with this detail + * @param statusIcon the status icon of this contact detail + * @param preferredProvider the preferred protocol provider + * @param preferredProtocol the preferred protocol if no protocol provider + * is set + * @param descriptor the underlying object that this class is wrapping + */ + public UIContactDetailImpl( + String address, + String displayName, + String category, + Collection labels, + ImageIcon statusIcon, + ProtocolProviderService preferredProvider, + String preferredProtocol, + Object descriptor) + { + super(address, displayName, category, labels, preferredProvider, + preferredProtocol, descriptor); + + setStatusIcon(statusIcon); + } + + /** + * Sets the given status icon. + * + * @param statusIcon the status icon to set + */ + public void setStatusIcon(ImageIcon statusIcon) + { + this.statusIcon = statusIcon; + } + + /** + * Returns the status icon of this contact detail. + * + * @return the status icon of this contact detail + */ + public ImageIcon getStatusIcon() + { + return statusIcon; + } + + @Override + public PresenceStatus getPresenceStatus() + { + return null; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactImpl.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactImpl.java new file mode 100644 index 0000000..bd15e4b --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContactImpl.java @@ -0,0 +1,56 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.contactlist; + +import javax.swing.*; + +import net.java.sip.communicator.service.gui.*; + +public abstract class UIContactImpl + extends UIContact +{ + /** + * Returns the corresponding ContactNode. The ContactNode + * is the real node that is stored in the contact list component data model. + * + * @return the corresponding ContactNode + */ + public abstract ContactNode getContactNode(); + + /** + * Sets the given contactNode. The ContactNode + * is the real node that is stored in the contact list component data model. + * + * @param contactNode the ContactNode that corresponds to this + * UIGroup + */ + public abstract void setContactNode(ContactNode contactNode); + + /** + * Returns the general status icon of the given MetaContact. Detects the + * status using the priority status table. The priority is defined on + * the "availability" factor and here the most "available" status is + * returned. + * + * @return PresenceStatus The most "available" status from all + * sub-contact statuses. + */ + public abstract ImageIcon getStatusIcon(); + + /** + * Gets the avatar of a specific MetaContact in the form of an + * ImageIcon value. + * + * @param isSelected indicates if the contact is selected + * @param width the desired icon width + * @param height the desired icon height + * @return an ImageIcon which represents the avatar of the + * specified MetaContact + */ + public abstract ImageIcon getAvatar( + boolean isSelected, int width, int height); +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIFilterQuery.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIFilterQuery.java new file mode 100644 index 0000000..441737d --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIFilterQuery.java @@ -0,0 +1,356 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.contactlist; + +import java.util.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.gui.event.*; + +/** + * The FilterQuery gives information about a current filtering. + * + * @author Yana Stamcheva + */ +public class UIFilterQuery + extends FilterQuery + implements ContactQueryListener, + MetaContactQueryListener +{ + /** + * The maximum result count for each contact source. + */ + public static final int MAX_EXTERNAL_RESULT_COUNT = 10; + + /** + * A listener, which is notified when this query finishes. + */ + private FilterQueryListener filterQueryListener; + + /** + * Indicates if the query succeeded, i.e. if any of the filters associated + * with this query has returned any results. + */ + private boolean isSucceeded = false; + + /** + * Indicates if this query has been canceled. + */ + private boolean isCanceled = false; + + /** + * Indicates if this query is closed, means no more queries could be added + * to it. A FilterQuery, which is closed knows that it has to wait + * for a final number of queries to finish before notifying interested + * parties of the result. + */ + private boolean isClosed = false; + + /** + * The list of filter queries. + */ + private final Map> filterQueries + = Collections.synchronizedMap( + new Hashtable>()); + + /** + * Indicates the number of running queries. + */ + private int runningQueries = 0; + + /** + * Adds the given contactQuery to the list of filterQueries. + * @param contactQuery the ContactQuery to add + */ + public void addContactQuery(Object contactQuery) + { + synchronized (filterQueries) + { + // If this filter query has been already canceled and someone wants + // to add something to it, we just cancel the incoming query and + // return. + if (isCanceled) + { + cancelQuery(contactQuery); + return; + } + + List queryResults = new ArrayList(); + + if (contactQuery instanceof ContactQuery) + { + ContactQuery externalQuery = (ContactQuery) contactQuery; + + List externalResults + = externalQuery.getQueryResults(); + + if (externalResults != null && externalResults.size() > 0) + queryResults = new ArrayList(externalResults); + + externalQuery.addContactQueryListener(this); + } + else if (contactQuery instanceof MetaContactQuery) + ((MetaContactQuery) contactQuery).addContactQueryListener(this); + + filterQueries.put(contactQuery, queryResults); + runningQueries++; + } + } + + /** + * Sets the isSucceeded property. + * @param isSucceeded indicates if this query has succeeded + */ + public void setSucceeded(boolean isSucceeded) + { + this.isSucceeded = isSucceeded; + } + + /** + * Indicates if this query has succeeded. + * @return true if this query has succeeded, false - + * otherwise + */ + public boolean isSucceeded() + { + return isSucceeded; + } + + /** + * Indicates if this query is canceled. + * @return true if this query is canceled, false otherwise + */ + public boolean isCanceled() + { + synchronized (filterQueries) + { + return isCanceled; + } + } + + /** + * Cancels this filter query. + */ + public void cancel() + { + synchronized(filterQueries) + { + isCanceled = true; + + Iterator queriesIter = filterQueries.keySet().iterator(); + + while (queriesIter.hasNext()) + cancelQuery(queriesIter.next()); + } + } + + /** + * Closes this query to indicate that no more contact sub-queries would be + * added to it. + */ + public void close() + { + isClosed = true; + + if (runningQueries == 0) + fireFilterQueryEvent(); + } + + /** + * Sets the given FilterQueryListener. + * @param l the FilterQueryListener to set + */ + public void setQueryListener(FilterQueryListener l) + { + filterQueryListener = l; + } + + /** + * Notifies the FilterQueryListener of the result status of + * this query. + */ + private void fireFilterQueryEvent() + { + if (filterQueryListener == null) + return; + + if (isSucceeded) + filterQueryListener.filterQuerySucceeded(this); + else + filterQueryListener.filterQueryFailed(this); + } + + /** + * Indicates that a query has changed its status. + * @param event the ContactQueryStatusEvent that notified us + */ + public void queryStatusChanged(ContactQueryStatusEvent event) + { + ContactQuery query = event.getQuerySource(); + + // Check if this query is in our filter queries list. + if (!filterQueries.containsKey(query) + || event.getEventType() == ContactQuery.QUERY_IN_PROGRESS) + return; + + removeQuery(query); + } + + /** + * Removes the given query from this filter query, updates the related data + * and notifies interested parties if this was the last query to process. + * @param query the ContactQuery to remove. + */ + public void removeQuery(ContactQuery query) + { + // First set the isSucceeded property. + if (!isSucceeded() && !query.getQueryResults().isEmpty()) + setSucceeded(true); + + // Then remove the wait result from the filterQuery. + runningQueries--; + query.removeContactQueryListener(this); + + // If no queries have rest we notify interested listeners that query + // has finished. + if (runningQueries == 0 && isClosed) + fireFilterQueryEvent(); + } + + /** + * Indicates that a query has changed its status. + * @param event the ContactQueryStatusEvent that notified us + */ + public void metaContactQueryStatusChanged(MetaContactQueryStatusEvent event) + { + MetaContactQuery query = event.getQuerySource(); + + // Check if this query is in our filter queries list. + if (!filterQueries.containsKey(query)) + return; + + // First set the isSucceeded property. + if (!isSucceeded() && query.getResultCount() > 0) + setSucceeded(true); + + // We don't remove the query from our list, because even if the query + // has finished its GUI part is scheduled in the Swing thread and we + // don't know anything about these events, so if someone calls cancel() + // we need to explicitly cancel all contained queries even they are + // finished. + runningQueries--; + query.removeContactQueryListener(this); + + // If no queries have rest we notify interested listeners that query + // has finished. + if (runningQueries == 0 && isClosed) + fireFilterQueryEvent(); + } + + /** + * Cancels the given query. + * @param query the query to cancel + */ + private void cancelQuery(Object query) + { + if (query instanceof ContactQuery) + { + ContactQuery contactQuery = (ContactQuery) query; + contactQuery.cancel(); + contactQuery.removeContactQueryListener( + GuiActivator.getContactList()); + if (!isSucceeded && contactQuery.getQueryResults().size() > 0) + isSucceeded = true; + } + else if (query instanceof MetaContactQuery) + { + MetaContactQuery metaContactQuery = (MetaContactQuery) query; + metaContactQuery.cancel(); + metaContactQuery.removeContactQueryListener( + GuiActivator.getContactList()); + if (!isSucceeded && metaContactQuery.getResultCount() > 0) + isSucceeded = true; + } + } + + /** + * Verifies if the given query is contained in this filter query. + * + * @param query the query we're looking for + * @return true if the given query is contained in this + * filter query, false - otherwise + */ + public boolean containsQuery(Object query) + { + return filterQueries.containsKey(query); + } + + /** + * Cancels asynchronous queries after the maximum desired result count is + * reached. + * + * @param query the query we're interested in + * @param contact the source contact we just received as a result of the + * given query + */ + private void contactReceived(ContactQuery query, SourceContact contact) + { + List queryResults = filterQueries.get(query); + + queryResults.add(contact); + + if (queryResults.size() == MAX_EXTERNAL_RESULT_COUNT) + { + query.removeContactQueryListener(GuiActivator.getContactList()); + + ShowMoreContact moreInfoContact + = new ShowMoreContact(query, queryResults); + + ContactSourceService contactSource = query.getContactSource(); + + GuiActivator.getContactList().addContact( + query, + moreInfoContact, + GuiActivator.getContactList() + .getContactSource(contactSource).getUIGroup(), + false); + } + } + + /** + * Indicates that a contact has been received as a result of a query. + * + * @param event the ContactReceivedEvent that notified us + */ + public void contactReceived(ContactReceivedEvent event) + { + contactReceived(event.getQuerySource(), event.getContact()); + } + + /** + * Indicates that a contact has been removed after a search. + * @param event the ContactQueryEvent containing information + * about the received SourceContact + */ + public void contactRemoved(ContactRemovedEvent event) + {} + + /** + * Indicates that a contact has been updated after a search. + * @param event the ContactQueryEvent containing information + * about the updated SourceContact + */ + public void contactChanged(ContactChangedEvent event) + {} + + public void metaContactReceived(MetaContactQueryEvent event) {} + + public void metaGroupReceived(MetaGroupQueryEvent event) {} +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIGroup.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIGroup.java deleted file mode 100644 index caa2cb9..0000000 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIGroup.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.main.contactlist; - -import javax.swing.*; - -/** - * The UIGroup represents the user interface contact list group. - * - * @author Yana Stamcheva - */ -public interface UIGroup -{ - /** - * Returns the descriptor of the group. This would be the underlying object - * that should provide all other necessary information for the group. - * - * @return the descriptor of the group - */ - public Object getDescriptor(); - - /** - * The display name of the group. The display name is the name to be shown - * in the contact list group row. - * - * @return the display name of the group - */ - public String getDisplayName(); - - /** - * Returns the index of this group in its source. In other words this is - * the descriptor index. - * - * @return the index of this group in its source - */ - public int getSourceIndex(); - - /** - * Returns the parent group. - * - * @return the parent group - */ - public UIGroup getParentGroup(); - - /** - * Indicates if the group is collapsed or expanded. - * - * @return true to indicate that the group is collapsed, - * false to indicate that it's expanded - */ - public boolean isGroupCollapsed(); - - /** - * Returns the count of online child contacts. - * - * @return the count of online child contacts - */ - public int countOnlineChildContacts(); - - /** - * Returns the child contacts count. - * - * @return child contacts count - */ - public int countChildContacts(); - - /** - * Returns the identifier of this group. - * - * @return the identifier of this group - */ - public String getId(); - - /** - * Returns the GroupNode corresponding to this UIGroup. - * The is the actual node used in the contact list component data model. - * - * @return the GroupNode corresponding to this UIGroup - */ - public GroupNode getGroupNode(); - - /** - * Sets the GroupNode corresponding to this UIGroup. - * - * @param groupNode the GroupNode to set. The is the actual - * node used in the contact list component data model. - */ - public void setGroupNode(GroupNode groupNode); - - /** - * Returns the right button menu for this group. - * - * @return the right button menu component for this group - */ - public JPopupMenu getRightButtonMenu(); -} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIGroupImpl.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIGroupImpl.java new file mode 100644 index 0000000..92658c4 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIGroupImpl.java @@ -0,0 +1,23 @@ +package net.java.sip.communicator.impl.gui.main.contactlist; + +import net.java.sip.communicator.service.gui.*; + +public abstract class UIGroupImpl + extends UIGroup +{ + /** + * Returns the GroupNode corresponding to this UIGroup. + * The is the actual node used in the contact list component data model. + * + * @return the GroupNode corresponding to this UIGroup + */ + public abstract GroupNode getGroupNode(); + + /** + * Sets the GroupNode corresponding to this UIGroup. + * + * @param groupNode the GroupNode to set. The is the actual + * node used in the contact list component data model. + */ + public abstract void setGroupNode(GroupNode groupNode); +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ExternalContactSource.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ExternalContactSource.java index d60a214..805e00b 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ExternalContactSource.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ExternalContactSource.java @@ -7,11 +7,13 @@ package net.java.sip.communicator.impl.gui.main.contactlist.contactsource; import javax.swing.*; +import javax.swing.tree.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.service.contactsource.*; import net.java.sip.communicator.service.customcontactactions.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.swing.*; import org.osgi.framework.*; @@ -28,6 +30,7 @@ import java.util.List; * @author Yana Stamcheva */ public class ExternalContactSource + implements UIContactSource { /** * The data key of the SourceContactDescriptor object used to store a @@ -57,6 +60,8 @@ public class ExternalContactSource private static Map, SIPCommButton> customActionButtons; + private final JTree contactListTree; + /** * Creates an ExternalContactSource based on the given * ContactSourceService. @@ -64,11 +69,13 @@ public class ExternalContactSource * @param contactSource the ContactSourceService, on which this * ExternalContactSource is based */ - public ExternalContactSource(ContactSourceService contactSource) + public ExternalContactSource( ContactSourceService contactSource, + JTree contactListTree) { this.contactSource = contactSource; + this.contactListTree = contactListTree; - sourceUIGroup = new SourceUIGroup(contactSource.getDisplayName()); + sourceUIGroup = new SourceUIGroup(contactSource.getDisplayName(), this); } /** @@ -116,7 +123,7 @@ public class ExternalContactSource * @param sourceContact the SourceContact, which corresponding UI * contact we would like to remove */ - public static void removeUIContact(SourceContact sourceContact) + public void removeUIContact(SourceContact sourceContact) { sourceContact.setData(UI_CONTACT_DATA_KEY, null); } @@ -129,7 +136,7 @@ public class ExternalContactSource * @return the UIContact corresponding to the given * MetaContact */ - public static UIContact getUIContact(SourceContact sourceContact) + public UIContact getUIContact(SourceContact sourceContact) { return (UIContact) sourceContact.getData(UI_CONTACT_DATA_KEY); } @@ -139,7 +146,7 @@ public class ExternalContactSource * * @return a list of all custom action buttons for this meta contact */ - public static Collection getContactCustomActionButtons( + public Collection getContactCustomActionButtons( final SourceContact sourceContact) { customActionContact = sourceContact; @@ -192,19 +199,14 @@ public class ExternalContactSource /** * Initializes custom action buttons for this contact source. */ - private static void initCustomActionButtons() + private void initCustomActionButtons() { customActionButtons = new LinkedHashMap , SIPCommButton>(); - CustomContactActionsChangeListener changeListener - = new CustomContactActionsChangeListener(); - for (CustomContactActionsService ccas : getContactActionsServices()) { - ccas.addCustomContactActionsListener(changeListener); - Iterator> actionIterator = ccas.getCustomContactActions(); @@ -254,13 +256,15 @@ public class ExternalContactSource button.getY() + button.getHeight()); SwingUtilities.convertPointToScreen( - location, GuiActivator.getContactList()); + location, contactListTree); - location.y = location.y - + GuiActivator.getContactList() - .getPathBounds( - GuiActivator.getContactList() - .getSelectionPath()).y; + TreePath selectionPath + = contactListTree.getSelectionPath(); + + if (selectionPath != null) + location.y = location.y + + contactListTree.getPathBounds( + selectionPath).y; contactAction.actionPerformed( contactDetails.get(0), @@ -326,8 +330,8 @@ public class ExternalContactSource * ExternalContactSource. It takes the name of the source and * sets it as a group name. */ - private class SourceUIGroup - implements UIGroup + public class SourceUIGroup + extends UIGroupImpl { /** * The display name of the group. @@ -339,13 +343,22 @@ public class ExternalContactSource */ private GroupNode groupNode; + private ExternalContactSource parentUISource; + /** * Creates an instance of SourceUIGroup. * @param name the name of the group */ - public SourceUIGroup(String name) + public SourceUIGroup( String name, + ExternalContactSource parentUISource) { this.displayName = name; + this.parentUISource = parentUISource; + } + + public ExternalContactSource getParentUISource() + { + return parentUISource; } /** @@ -413,7 +426,7 @@ public class ExternalContactSource */ public Object getDescriptor() { - return displayName; + return contactSource; } /** @@ -454,29 +467,6 @@ public class ExternalContactSource } /** - * Listens for updates on actions and when received update the source contact. - */ - private static class CustomContactActionsChangeListener - implements CustomContactActionsListener - { - /** - * Update for custom action has occurred. - * @param event the event containing the source which was updated. - */ - public void updated(CustomContactActionsEvent event) - { - if(!(event.getSource() instanceof SourceContact)) - return; - - ContactNode contactNode - = getUIContact((SourceContact)event.getSource()).getContactNode(); - - if (contactNode != null) - GuiActivator.getContactList().nodeChanged(contactNode); - } - } - - /** * An implementation of UIContactDetail for a custom action. */ private static class UIContactDetailCustomAction diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactListSource.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactListSource.java index 8a8d69a..82ea955 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactListSource.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaContactListSource.java @@ -21,6 +21,7 @@ import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.contactlist.event.*; import net.java.sip.communicator.service.customcontactactions.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; @@ -91,9 +92,9 @@ public class MetaContactListSource * @return the UIContact corresponding to the given * MetaContact */ - public static UIContact getUIContact(MetaContact metaContact) + public static UIContactImpl getUIContact(MetaContact metaContact) { - return (UIContact) metaContact.getData(UI_CONTACT_DATA_KEY); + return (UIContactImpl) metaContact.getData(UI_CONTACT_DATA_KEY); } /** @@ -101,12 +102,12 @@ public class MetaContactListSource * MetaContactGroup. * @param metaGroup the MetaContactGroup, which UI group we're * looking for - * @return the UIGroup corresponding to the given + * @return the UIGroupImpl corresponding to the given * MetaContactGroup */ - public static UIGroup getUIGroup(MetaContactGroup metaGroup) + public static UIGroupImpl getUIGroup(MetaContactGroup metaGroup) { - return (UIGroup) metaGroup.getData(UI_GROUP_DATA_KEY); + return (UIGroupImpl) metaGroup.getData(UI_GROUP_DATA_KEY); } /** @@ -126,7 +127,7 @@ public class MetaContactListSource * create an UIContact * @return an UIContact for the given metaContact */ - public static UIContact createUIContact(final MetaContact metaContact) + public static UIContactImpl createUIContact(final MetaContact metaContact) { final MetaUIContact descriptor = new MetaUIContact(metaContact); @@ -367,7 +368,7 @@ public class MetaContactListSource boolean uiContactCreated = false; - UIContact uiContact; + UIContactImpl uiContact; synchronized (metaContact) { @@ -439,7 +440,7 @@ public class MetaContactListSource public void childContactsReordered(MetaContactGroupEvent evt) { MetaContactGroup metaGroup = evt.getSourceMetaContactGroup(); - UIGroup uiGroup; + UIGroupImpl uiGroup; ContactListTreeModel treeModel = GuiActivator.getContactList().getTreeModel(); @@ -577,7 +578,7 @@ public class MetaContactListSource { final MetaContactGroup metaGroup = evt.getSourceMetaContactGroup(); - UIGroup uiGroup; + UIGroupImpl uiGroup; synchronized (metaGroup) { uiGroup = MetaContactListSource.getUIGroup(metaGroup); @@ -622,7 +623,7 @@ public class MetaContactListSource { MetaContact metaContact = evt.getSourceMetaContact(); - UIContact uiContact; + UIContactImpl uiContact; synchronized (metaContact) { uiContact = MetaContactListSource.getUIContact(metaContact); @@ -744,7 +745,7 @@ public class MetaContactListSource { MetaContact metaContact = evt.getSourceMetaContact(); - UIContact uiContact; + UIContactImpl uiContact; synchronized (metaContact) { uiContact = MetaContactListSource.getUIContact(metaContact); @@ -768,7 +769,7 @@ public class MetaContactListSource { MetaContact metaContact = evt.getSourceMetaContact(); - UIContact uiContact; + UIContactImpl uiContact; synchronized (metaContact) { uiContact = MetaContactListSource.getUIContact(metaContact); @@ -850,7 +851,7 @@ public class MetaContactListSource { MetaContact metaContact = evt.getNewParent(); - UIContact uiContact; + UIContactImpl uiContact; synchronized (metaContact) { uiContact = MetaContactListSource.getUIContact(metaContact); @@ -948,7 +949,7 @@ public class MetaContactListSource { final MetaContact oldParent = evt.getOldParent(); - UIContact oldUIContact; + UIContactImpl oldUIContact; synchronized (oldParent) { oldUIContact = MetaContactListSource.getUIContact(oldParent); @@ -1030,14 +1031,9 @@ public class MetaContactListSource customActionButtons = new LinkedHashMap, SIPCommButton>(); - CustomContactActionsChangeListener changeListener - = new CustomContactActionsChangeListener(); - for (CustomContactActionsService ccas : getContactActionsServices()) { - ccas.addCustomContactActionsListener(changeListener); - Iterator> actionIterator = ccas.getCustomContactActions(); @@ -1105,45 +1101,6 @@ public class MetaContactListSource } /** - * Listens for updates on actions and when received update the contact. - */ - private static class CustomContactActionsChangeListener - implements CustomContactActionsListener - { - /** - * Update for custom action has occured. - * @param event the event containing the source which was updated. - */ - public void updated(CustomContactActionsEvent event) - { - if(!(event.getSource() instanceof Contact)) - return; - - MetaContact metaContact - = GuiActivator.getContactListService().findMetaContactByContact( - (Contact)event.getSource()); - - if (metaContact == null) - return; - - UIContact uiContact; - synchronized (metaContact) - { - uiContact = MetaContactListSource.getUIContact(metaContact); - } - - if (uiContact != null) - { - ContactNode contactNode - = uiContact.getContactNode(); - - if (contactNode != null) - GuiActivator.getContactList().nodeChanged(contactNode); - } - } - } - - /** * An implementation of UIContactDetail for a custom action. */ private static class UIContactDetailCustomAction diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java index 1cf6c2f..bb4b2f5 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java @@ -14,6 +14,7 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.OperationSetExtendedAuthorizations.SubscriptionStatus; @@ -34,7 +35,7 @@ import net.java.sip.communicator.util.swing.*; * @author Yana Stamcheva */ public class MetaUIContact - implements UIContact + extends UIContactImpl { /** * The key of the user data in MetaContact which specifies @@ -593,7 +594,8 @@ public class MetaUIContact * The implementation of the UIContactDetail interface for the * MetaContactListService. */ - private class MetaContactDetail extends UIContactDetail + private class MetaContactDetail + extends UIContactDetailImpl { /** * The underlying protocol contact. @@ -612,8 +614,7 @@ public class MetaUIContact contact.getDisplayName(), null, null, - new ImageIcon( - contact.getPresenceStatus().getStatusIcon()), + new ImageIcon(contact.getPresenceStatus().getStatusIcon()), contact.getProtocolProvider(), contact.getProtocolProvider().getProtocolName(), contact); diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIGroup.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIGroup.java index 536e7b2..2824d84 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIGroup.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIGroup.java @@ -12,6 +12,7 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; /** * The MetaUIGroup is the implementation of the UIGroup for the @@ -21,7 +22,7 @@ import net.java.sip.communicator.service.contactlist.*; * @author Yana Stamcheva */ public class MetaUIGroup - implements UIGroup + extends UIGroupImpl { /** * The MetaContactGroup, on which this UI group is based. diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ShowMoreContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ShowMoreContact.java index 904142b..d3ed3da 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ShowMoreContact.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/ShowMoreContact.java @@ -14,6 +14,8 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.gui.event.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.swing.*; @@ -22,8 +24,8 @@ import net.java.sip.communicator.util.swing.*; * @author Yana Stamcheva */ public class ShowMoreContact - implements UIContact, - ContactListListener + extends UIContactImpl + implements ContactListListener { /** * The string associated with this contact. @@ -54,7 +56,7 @@ public class ShowMoreContact /** * The count of shown contacts corresponding to the underlying query. */ - private int shownResultsCount = FilterQuery.MAX_EXTERNAL_RESULT_COUNT; + private int shownResultsCount = UIFilterQuery.MAX_EXTERNAL_RESULT_COUNT; /** * Creates an instance of MoreInfoContact. @@ -262,7 +264,7 @@ public class ShowMoreContact = new ArrayList(queryResults); int newCount - = shownResultsCount + FilterQuery.MAX_EXTERNAL_RESULT_COUNT; + = shownResultsCount + UIFilterQuery.MAX_EXTERNAL_RESULT_COUNT; int resultSize = contacts.size(); @@ -283,7 +285,7 @@ public class ShowMoreContact GuiActivator.getContactList().addContact( contactQuery, this, - TreeContactList.getContactSource( + GuiActivator.getContactList().getContactSource( contactQuery.getContactSource()).getUIGroup(), false); @@ -293,6 +295,16 @@ public class ShowMoreContact public void groupClicked(ContactListEvent evt) {} /** + * We're not interested in group selection events here. + */ + public void groupSelected(ContactListEvent evt) {} + + /** + * We're not interested in contact selection events here. + */ + public void contactSelected(ContactListEvent evt) {} + + /** * Returns all custom action buttons for this meta contact. * * @return a list of all custom action buttons for this meta contact diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java index 0098beb..2bbd010 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java @@ -16,12 +16,11 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactsource.*; -import net.java.sip.communicator.service.customcontactactions.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.globalstatus.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.swing.*; -import org.osgi.framework.*; /** * The SourceUIContact is the implementation of the UIContact for the @@ -30,7 +29,7 @@ import org.osgi.framework.*; * @author Yana Stamcheva */ public class SourceUIContact - implements UIContact + extends UIContactImpl { /** * The corresponding SourceContact, on which this abstraction is @@ -46,7 +45,7 @@ public class SourceUIContact /** * The parent UIGroup. */ - private UIGroup uiGroup; + private ExternalContactSource.SourceUIGroup uiGroup; /** * The search strings for this UIContact. @@ -63,7 +62,7 @@ public class SourceUIContact * @param parentGroup the parent UIGroup */ public SourceUIContact( SourceContact contact, - UIGroup parentGroup) + ExternalContactSource.SourceUIGroup parentGroup) { this.sourceContact = contact; this.uiGroup = parentGroup; @@ -121,6 +120,11 @@ public class SourceUIContact */ public ImageIcon getStatusIcon() { + PresenceStatus status = sourceContact.getPresenceStatus(); + + if (status != null) + return new ImageIcon(Constants.getStatusIcon(status)); + return new ImageIcon(GlobalStatusEnum.OFFLINE.getStatusIcon()); } @@ -284,14 +288,15 @@ public class SourceUIContact { this.contactNode = contactNode; if (contactNode == null) - ExternalContactSource.removeUIContact(sourceContact); + uiGroup.getParentUISource().removeUIContact(sourceContact); } /** * The implementation of the UIContactDetail interface for the * external source ContactDetails. */ - protected static class SourceContactDetail extends UIContactDetail + protected static class SourceContactDetail + extends UIContactDetailImpl { /** * Creates an instance of SourceContactDetail by specifying @@ -479,7 +484,7 @@ public class SourceUIContact public Collection getContactCustomActionButtons() { if (sourceContact != null) - return ExternalContactSource + return uiGroup.getParentUISource() .getContactCustomActionButtons(sourceContact); return null; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContact.java index 95aec4e..aab3c20 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContact.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContact.java @@ -14,6 +14,7 @@ import javax.swing.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.OperationSetMessageWaiting.*; import net.java.sip.communicator.service.protocol.event.*; @@ -31,8 +32,8 @@ import org.jitsi.service.resources.*; * @author Yana Stamcheva */ public class NotificationContact - implements UIContact, - RegistrationStateChangeListener, + extends UIContact + implements RegistrationStateChangeListener, ProviderPresenceStatusListener { /** @@ -453,7 +454,7 @@ public class NotificationContact * external source ContactDetails. */ private class MessageWaitingDetail - extends UIContactDetail + extends UIContactDetailImpl { /** * Creates an instance of SourceContactDetail by specifying diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContactSource.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContactSource.java index 5697fdb..efbe4d5 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContactSource.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContactSource.java @@ -18,6 +18,7 @@ import org.osgi.framework.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.service.customcontactactions.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.OperationSetMessageWaiting.MessageType; import net.java.sip.communicator.service.protocol.event.*; diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationGroup.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationGroup.java index 0df6e66..d566366 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationGroup.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationGroup.java @@ -13,6 +13,7 @@ import javax.swing.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; @@ -24,7 +25,7 @@ import net.java.sip.communicator.service.protocol.event.*; * @author Yana Stamcheva */ public class NotificationGroup - implements UIGroup + extends UIGroup { /** * The type of the notification message, identifying this group. diff --git a/src/net/java/sip/communicator/impl/gui/utils/ExtendedTooltip.java b/src/net/java/sip/communicator/impl/gui/utils/ExtendedTooltip.java deleted file mode 100644 index 750806b..0000000 --- a/src/net/java/sip/communicator/impl/gui/utils/ExtendedTooltip.java +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.impl.gui.utils; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.plaf.*; -import javax.swing.plaf.metal.*; - -import net.java.sip.communicator.util.*; -import net.java.sip.communicator.util.swing.*; - -/** - * The tooltip shown over a contact in the contact list. - * - * @author Yana Stamcheva - */ -public class ExtendedTooltip - extends JToolTip -{ - private static final Logger logger - = Logger.getLogger(ExtendedTooltip.class); - - /** - * Class id key used in UIDefaults. - */ - private static final String uiClassID = - ExtendedTooltip.class.getName() + "ToolTipUI"; - - /** - * Adds the ui class to UIDefaults. - */ - static - { - UIManager.getDefaults().put(uiClassID, - ImageToolTipUI.class.getName()); - } - - private final JLabel imageLabel = new JLabel(); - - private final JLabel titleLabel = new JLabel(); - - private final JPanel linesPanel = new JPanel(); - - private final JTextArea bottomTextArea = new JTextArea(); - - private int textWidth = 0; - - private int textHeight = 0; - - private boolean isListViewEnabled; - - /** - * Created a MetaContactTooltip. - * @param isListViewEnabled indicates if the list view is enabled - */ - public ExtendedTooltip(final Window parentWindow, boolean isListViewEnabled) - { - this.isListViewEnabled = isListViewEnabled; - - this.setLayout(new BorderLayout()); - - JPanel mainPanel = new JPanel(new BorderLayout(5, 5)); - JPanel centerPanel = new JPanel(new BorderLayout()); - - mainPanel.setOpaque(false); - centerPanel.setOpaque(false); - linesPanel.setOpaque(false); - bottomTextArea.setOpaque(false); - - titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD)); - - if (isListViewEnabled) - { - linesPanel.setLayout( - new BoxLayout(linesPanel, BoxLayout.Y_AXIS)); - - mainPanel.add(imageLabel, BorderLayout.WEST); - mainPanel.add(centerPanel, BorderLayout.CENTER); - - centerPanel.add(titleLabel, BorderLayout.NORTH); - centerPanel.add(linesPanel, BorderLayout.CENTER); - } - else - { - titleLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT); - mainPanel.add(imageLabel, BorderLayout.CENTER); - mainPanel.add(titleLabel, BorderLayout.NORTH); - } - - bottomTextArea.setEditable(false); - bottomTextArea.setLineWrap(true); - bottomTextArea.setWrapStyleWord(true); - bottomTextArea.setFont(bottomTextArea.getFont().deriveFont(10f)); - mainPanel.add(bottomTextArea, BorderLayout.SOUTH); - - // Hide the tooltip when the parent window hides. - /* - * FIXME The parentWindow will surely outlive this ExtendedTooltip so - * adding a WindowFocusListener without removing the same - * WindowFocusListener later on is guaranteed to cause a memory leak. - */ - parentWindow.addWindowFocusListener(new WindowFocusListener() - { - public void windowLostFocus(WindowEvent e) - { - Window popupWindow - = SwingUtilities.getWindowAncestor(ExtendedTooltip.this); - - if ((popupWindow != null) - && popupWindow.isVisible() - // The popup window should normally be a JWindow, so we - // check here explicitly if for some reason we didn't get - // something else. - && (popupWindow instanceof JWindow)) - { - if (logger.isInfoEnabled()) - logger.info("Tooltip window ancestor to hide: " - + popupWindow); - - popupWindow.setVisible(false); - } - } - - public void windowGainedFocus(WindowEvent e) {} - }); - - // Hide the tooltip if the parent window isn't active - addComponentListener(new ComponentAdapter() - { - public void componentResized(ComponentEvent evt) - { - if (!parentWindow.isActive()) - { - Window popupWindow - = SwingUtilities.getWindowAncestor( - ExtendedTooltip.this); - - if (popupWindow != null - && popupWindow.isVisible() - && !(popupWindow instanceof JFrame) - // The popup window should normally be a JWindow, so we - // check here explicitly if for some reason we didn't get - // something else. - && (popupWindow instanceof JWindow)) - { - if (logger.isInfoEnabled()) - logger.info("Tooltip window ancestor to hide: " - + popupWindow); - - popupWindow.setVisible(false); - } - } - } - }); - - this.add(mainPanel); - } - - /** - * Sets the given image to this tooltip. - * - * @param imageIcon The image icon to set. - */ - public void setImage(ImageIcon imageIcon) - { - imageLabel.setIcon(imageIcon); - } - - /** - * Sets the title of the tooltip. The text would be shown in bold on the top - * of the tooltip panel. - * - * @param titleText The title of the tooltip. - */ - public void setTitle(String titleText) - { - titleLabel.setText(titleText); - - Dimension labelSize = GuiUtils.getStringSize(titleLabel,titleText); - recalculateTooltipSize(labelSize.width, labelSize.height); - } - - /** - * Adds an icon-string list, which would appear on the right of the image - * panel. - * - * @param icon the icon to show - * @param text the name to show - */ - public void addLine(Icon icon, - String text) - { - JLabel lineLabel = new JLabel( text, - icon, - JLabel.LEFT); - - linesPanel.add(lineLabel); - - Dimension labelSize = calculateLabelSize(lineLabel); - - recalculateTooltipSize(labelSize.width, labelSize.height); - } - - /** - * Adds the given array of labels as one line in this tool tip. - * - * @param labels the labels to add - */ - public void addLine(JLabel[] labels) - { - Dimension lineSize = null; - JPanel labelPanel = null; - - if (labels.length > 0) - { - labelPanel = new TransparentPanel( - new FlowLayout(FlowLayout.LEFT, 2, 0)); - linesPanel.add(labelPanel); - } - else - return; - - if (labelPanel != null) - for (JLabel label : labels) - { - labelPanel.add(label); - if (lineSize == null) - lineSize = calculateLabelSize(label); - else - lineSize = new Dimension( - lineSize.width + calculateLabelSize(label).width, - lineSize.height); - } - - recalculateTooltipSize(lineSize.width, lineSize.height); - } - - /** - * Clear all lines. - */ - public void removeAllLines() - { - linesPanel.removeAll(); - } - - /** - * Sets the text that would appear on the bottom of the tooltip. - * @param text the text to set - */ - public void setBottomText(String text) - { - this.bottomTextArea.setText(text); - } - - /** - * Calculates label size. - * - * @param label the label, which size we should calculate - * @return the Dimension indicating the label size - */ - private Dimension calculateLabelSize(JLabel label) - { - Icon icon = label.getIcon(); - String text = label.getText(); - - int iconWidth = 0; - int iconHeight = 0; - if (icon != null) - { - iconWidth = icon.getIconWidth(); - iconHeight = icon.getIconHeight(); - } - - int labelWidth - = GuiUtils.getStringWidth(label, text) - + iconWidth - + label.getIconTextGap(); - - int textHeight = GuiUtils.getStringSize(label, text).height; - - int labelHeight = (iconHeight > textHeight) ? iconHeight : textHeight; - - return new Dimension(labelWidth, labelHeight); - } - - /** - * Re-calculates the tooltip size. - * - * @param newTextWidth the width of the newly added text that should be - * added to the global width - * @param newTextHeight the height of the newly added text that should be - * added to the global height - */ - private void recalculateTooltipSize(int newTextWidth, int newTextHeight) - { - if (textWidth < newTextWidth) - textWidth = newTextWidth; - - textHeight += newTextHeight; - } - - /** - * Customized UI for this MetaContactTooltip. - */ - public static class ImageToolTipUI extends MetalToolTipUI - { - static ImageToolTipUI sharedInstance = new ImageToolTipUI(); - - /** - * Creates the UI. - * @param c - * @return - */ - public static ComponentUI createUI(JComponent c) - { - return sharedInstance; - } - - /** - * Overwrite the UI paint method to do nothing in order fix double - * painting of the tooltip text. - * @param g the Graphics object - * @param c the component used to render the tooltip - */ - @Override - public void paint(Graphics g, JComponent c) - {} - - /** - * Override ComponentUI update method to set visibility of bottomText. - * @param g Graphics object - * @param c the component used to render the tooltip - */ - @Override - public void update(Graphics g, JComponent c) - { - JTextArea bottomTextArea = - ((ExtendedTooltip)c).bottomTextArea; - - String bottomText = bottomTextArea.getText(); - if(bottomText == null || bottomText.length() <= 0) - bottomTextArea.setVisible(false); - else - bottomTextArea.setVisible(true); - super.update(g, c); - } - - /** - * Returns the size of the given component. - * @param c the component used to render the tooltip - * @return the size of the given component. - */ - @Override - public Dimension getPreferredSize(JComponent c) - { - ExtendedTooltip tooltip = (ExtendedTooltip)c; - - Icon icon = tooltip.imageLabel.getIcon(); - int width = 0; - if (icon != null) - width += icon.getIconWidth(); - - if (tooltip.isListViewEnabled) - width += tooltip.textWidth + 15; - else - width = tooltip.textWidth > width ? tooltip.textWidth : width; - - int imageHeight = 0; - if (icon != null) - imageHeight = icon.getIconHeight(); - - int height = 0; - if (tooltip.isListViewEnabled) - { - height = imageHeight > tooltip.textHeight - ? imageHeight : tooltip.textHeight; - } - else - height = imageHeight + tooltip.textHeight; - - String bottomText = tooltip.bottomTextArea.getText(); - if(bottomText != null && bottomText.length() > 0) - { - // Seems a little messy, but sets the proper size. - tooltip.bottomTextArea.setColumns(5); - tooltip.bottomTextArea.setSize(0,0); - tooltip.bottomTextArea.setSize( - tooltip.bottomTextArea.getPreferredSize()); - - height += tooltip.bottomTextArea.getPreferredSize().height; - } - - return new Dimension(width, height); - } - } - - /** - * Returns the name of the L&F class that renders this component. - * - * @return the string "TreeUI" - * @see JComponent#getUIClassID - * @see UIDefaults#getUI - */ - public String getUIClassID() - { - return uiClassID; - } -} diff --git a/src/net/java/sip/communicator/impl/gui/utils/InviteContactTransferHandler.java b/src/net/java/sip/communicator/impl/gui/utils/InviteContactTransferHandler.java index 5d96bb2..e4be964 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/InviteContactTransferHandler.java +++ b/src/net/java/sip/communicator/impl/gui/utils/InviteContactTransferHandler.java @@ -14,6 +14,7 @@ import javax.swing.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.swing.*; diff --git a/src/net/java/sip/communicator/service/contactsource/ContactChangedEvent.java b/src/net/java/sip/communicator/service/contactsource/ContactChangedEvent.java new file mode 100644 index 0000000..ae88932 --- /dev/null +++ b/src/net/java/sip/communicator/service/contactsource/ContactChangedEvent.java @@ -0,0 +1,61 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.contactsource; + +import java.util.*; + +/** + * The ContactChangedEvent indicates that a + * SourceContact has been updated as a result of a + * ContactQuery. + * @author Yana Stamcheva + */ +public class ContactChangedEvent + extends EventObject +{ + /** + * Serial version UID. + */ + private static final long serialVersionUID = 0L; + + /** + * The contact that has been updated. + */ + private final SourceContact contact; + + /** + * Creates a ContactChangedEvent by specifying the contact search + * source and the updated searchContact. + * @param source the source that triggered this event + * @param contact the updated contact + */ + public ContactChangedEvent(ContactQuery source, + SourceContact contact) + { + super(source); + + this.contact = contact; + } + + /** + * Returns the ContactQuery that triggered this event. + * @return the ContactQuery that triggered this event + */ + public ContactQuery getQuerySource() + { + return (ContactQuery) source; + } + + /** + * Returns the updated contact. + * @return the updated contact + */ + public SourceContact getContact() + { + return contact; + } +} diff --git a/src/net/java/sip/communicator/service/contactsource/ContactQueryListener.java b/src/net/java/sip/communicator/service/contactsource/ContactQueryListener.java index 0610331..37e57c9 100644 --- a/src/net/java/sip/communicator/service/contactsource/ContactQueryListener.java +++ b/src/net/java/sip/communicator/service/contactsource/ContactQueryListener.java @@ -35,4 +35,11 @@ public interface ContactQueryListener * about the received SourceContact */ public void contactRemoved(ContactRemovedEvent event); + + /** + * Indicates that a contact has been updated after a search. + * @param event the ContactQueryEvent containing information + * about the updated SourceContact + */ + public void contactChanged(ContactChangedEvent event); } diff --git a/src/net/java/sip/communicator/service/contactsource/GenericSourceContact.java b/src/net/java/sip/communicator/service/contactsource/GenericSourceContact.java index ab382ee..4214c16 100644 --- a/src/net/java/sip/communicator/service/contactsource/GenericSourceContact.java +++ b/src/net/java/sip/communicator/service/contactsource/GenericSourceContact.java @@ -192,4 +192,14 @@ public class GenericSourceContact { this.image = image; } + + /** + * Returns the status of the source contact. And null if such information + * is not available. + * @return the PresenceStatus representing the state of this source contact. + */ + public PresenceStatus getPresenceStatus() + { + return null; + } } diff --git a/src/net/java/sip/communicator/service/contactsource/SourceContact.java b/src/net/java/sip/communicator/service/contactsource/SourceContact.java index d013d7f..99d9bdb 100644 --- a/src/net/java/sip/communicator/service/contactsource/SourceContact.java +++ b/src/net/java/sip/communicator/service/contactsource/SourceContact.java @@ -123,4 +123,11 @@ public interface SourceContact * specified key */ public void setData(Object key, Object value); + + /** + * Returns the status of the source contact. And null if such information + * is not available. + * @return the PresenceStatus representing the state of this source contact. + */ + public PresenceStatus getPresenceStatus(); } diff --git a/src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsEvent.java b/src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsEvent.java deleted file mode 100644 index aa7b104..0000000 --- a/src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsEvent.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.service.customcontactactions; - -import java.util.*; - -/** - * An event from custom actions. - * @author Damian Minkov - */ -public class CustomContactActionsEvent - extends EventObject -{ - /** - * Creates the event with source. - * @param source the source of the event. - */ - public CustomContactActionsEvent(Object source) - { - super(source); - } -} diff --git a/src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsListener.java b/src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsListener.java deleted file mode 100644 index e87dbad..0000000 --- a/src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsListener.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.sip.communicator.service.customcontactactions; - -/** - * Notifies for events coming from custom actions. - * @author Damian Minkov - */ -public interface CustomContactActionsListener -{ - /** - * Notifies that object has been updated. - * @param event the event containing the source which was updated. - */ - public void updated(CustomContactActionsEvent event); -} diff --git a/src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsService.java b/src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsService.java index 955ee5c..3aaf0ba 100644 --- a/src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsService.java +++ b/src/net/java/sip/communicator/service/customcontactactions/CustomContactActionsService.java @@ -29,22 +29,4 @@ public interface CustomContactActionsService * @return an iterator over a list of ContactActions */ public Iterator> getCustomContactActions(); - - /** - * Registers a CustomContactActionsListener with this service so that it gets - * notifications of various events. - * - * @param listener the CustomContactActionsListener to register. - */ - public void addCustomContactActionsListener( - CustomContactActionsListener listener); - - /** - * Unregisters listener so that it won't receive any further - * notifications. - * - * @param listener the CustomContactActionsListener to unregister. - */ - public void removeCustomContactActionsListener( - CustomContactActionsListener listener); } diff --git a/src/net/java/sip/communicator/service/gui/ContactList.java b/src/net/java/sip/communicator/service/gui/ContactList.java new file mode 100644 index 0000000..1a448ba --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/ContactList.java @@ -0,0 +1,172 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +import java.awt.*; +import java.util.*; + +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.event.*; + +/** + * The ContactList interface represents a contact list. All contact + * list components that need to be available as a service could implement + * this interface. + * + * @author Yana Stamcheva + */ +public interface ContactList +{ + /** + * Returns the actual component corresponding to the contact list. + * + * @return the actual component corresponding to the contact list + */ + public Component getComponent(); + + /** + * Returns the list of registered contact sources to search in. + * @return the list of registered contact sources to search in + */ + public Collection getContactSources(); + + /** + * Returns the ExternalContactSource corresponding to the given + * ContactSourceService. + * @param contactSource the ContactSourceService, which + * corresponding external source implementation we're looking for + * @return the ExternalContactSource corresponding to the given + * ContactSourceService + */ + public UIContactSource getContactSource(ContactSourceService contactSource); + + /** + * Adds the given group to this list. + * @param group the UIGroup to add + * @param isSorted indicates if the contact should be sorted regarding to + * the GroupNode policy + */ + public void addGroup(final UIGroup group, final boolean isSorted); + + /** + * Removes the given group and its children from the list. + * @param group the UIGroup to remove + */ + public void removeGroup(final UIGroup group); + + /** + * Adds the given contact to this list. + * @param contact the UIContact to add + * @param group the UIGroup to add to + * @param isContactSorted indicates if the contact should be sorted + * regarding to the GroupNode policy + * @param isGroupSorted indicates if the group should be sorted regarding to + * the GroupNode policy in case it doesn't exist and should be + * added + */ + public void addContact( final UIContact contact, + final UIGroup group, + final boolean isContactSorted, + final boolean isGroupSorted); + + /** + * Adds the given contact to this list. + * @param query the ContactQuery that adds the given contact + * @param contact the UIContact to add + * @param group the UIGroup to add to + * @param isSorted indicates if the contact should be sorted regarding to + * the GroupNode policy + */ + public void addContact(final ContactQuery query, + final UIContact contact, + final UIGroup group, + final boolean isSorted); + + /** + * Removes the node corresponding to the given MetaContact from + * this list. + * @param contact the UIContact to remove + * @param removeEmptyGroup whether we should delete the group if is empty + */ + public void removeContact( final UIContact contact, + final boolean removeEmptyGroup); + + /** + * Removes the node corresponding to the given MetaContact from + * this list. + * @param contact the UIContact to remove + */ + public void removeContact(UIContact contact); + + /** + * Returns the currently applied filter. + * @return the currently applied filter + */ + public ContactListFilter getCurrentFilter(); + + /** + * Applies the given filter. + * @param filter the ContactListFilter to apply. + * @return the filter query + */ + public FilterQuery applyFilter(ContactListFilter filter); + + /** + * Applies the default filter. + * @return the filter query that keeps track of the filtering results + */ + public FilterQuery applyDefaultFilter(); + + /** + * Returns the currently selected UIContact if there's one. + * + * @return the currently selected UIContact if there's one. + */ + public UIContact getSelectedContact(); + + /** + * Returns the currently selected UIGroup if there's one. + * + * @return the currently selected UIGroup if there's one. + */ + public UIGroup getSelectedGroup(); + + /** + * Selects the given UIContact in the contact list. + * + * @param uiContact the contact to select + */ + public void setSelectedContact(UIContact uiContact); + + /** + * Selects the given UIGroup in the contact list. + * + * @param uiGroup the group to select + */ + public void setSelectedGroup(UIGroup uiGroup); + + /** + * Adds a listener for ContactListEvents. + * + * @param listener the listener to add + */ + public void addContactListListener(ContactListListener listener); + + /** + * Removes a listener previously added with addContactListListener. + * + * @param listener the listener to remove + */ + public void removeContactListListener(ContactListListener listener); + + /** + * Refreshes the given UIContact. + * + * @param uiContact the contact to refresh + */ + public void refreshContact(UIContact uiContact); +} diff --git a/src/net/java/sip/communicator/service/gui/ContactListFilter.java b/src/net/java/sip/communicator/service/gui/ContactListFilter.java new file mode 100644 index 0000000..328415f --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/ContactListFilter.java @@ -0,0 +1,41 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +/** + * The ContactListFilter is an interface meant to be implemented by + * modules interested in filtering the contact list. An implementation of this + * interface should be able to answer if an UIContact or an + * UIGroup is matching the corresponding filter. + * + * @author Yana Stamcheva + */ +public interface ContactListFilter +{ + /** + * Indicates if the given uiGroup is matching the current filter. + * @param uiContact the UIContact to check + * @return true to indicate that the given uiContact + * matches this filter, false - otherwise + */ + public boolean isMatching(UIContact uiContact); + + /** + * Indicates if the given uiGroup is matching the current filter. + * @param uiGroup the UIGroup to check + * @return true to indicate that the given uiGroup + * matches this filter, false - otherwise + */ + public boolean isMatching(UIGroup uiGroup); + + /** + * Applies this filter to any interested sources + * @param filterQuery the FilterQuery that tracks the results of + * this filtering + */ + public void applyFilter(FilterQuery filterQuery); +} diff --git a/src/net/java/sip/communicator/service/gui/ContactListNode.java b/src/net/java/sip/communicator/service/gui/ContactListNode.java new file mode 100644 index 0000000..8d9ddaa --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/ContactListNode.java @@ -0,0 +1,23 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +/** + * The ContactListNode represents a node in the contact list data + * model. An implementation of this interface should be able to determine the + * index of this node in its contact source. + * + * @author Yana Stamcheva + */ +public interface ContactListNode +{ + /** + * Returns the index of this node in the MetaContactListService. + * @return the index of this node in the MetaContactListService + */ + public int getSourceIndex(); +} diff --git a/src/net/java/sip/communicator/service/gui/FilterQuery.java b/src/net/java/sip/communicator/service/gui/FilterQuery.java new file mode 100644 index 0000000..7b2cda9 --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/FilterQuery.java @@ -0,0 +1,84 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.event.*; + +/** + * The FilterQuery gives information about a current filtering. + * + * @author Yana Stamcheva + */ +public abstract class FilterQuery +{ + /** + * A listener, which is notified when this query finishes. + */ + private FilterQueryListener filterQueryListener; + + /** + * Adds the given contactQuery to the list of filterQueries. + * @param contactQuery the ContactQuery to add + */ + public abstract void addContactQuery(Object contactQuery); + + /** + * Sets the isSucceeded property. + * @param isSucceeded indicates if this query has succeeded + */ + public abstract void setSucceeded(boolean isSucceeded); + + /** + * Indicates if this query has succeeded. + * @return true if this query has succeeded, false - + * otherwise + */ + public abstract boolean isSucceeded(); + + /** + * Indicates if this query is canceled. + * @return true if this query is canceled, false otherwise + */ + public abstract boolean isCanceled(); + + /** + * Cancels this filter query. + */ + public abstract void cancel(); + + /** + * Closes this query to indicate that no more contact sub-queries would be + * added to it. + */ + public abstract void close(); + + /** + * Sets the given FilterQueryListener. + * @param l the FilterQueryListener to set + */ + public void setQueryListener(FilterQueryListener l) + { + filterQueryListener = l; + } + + /** + * Removes the given query from this filter query, updates the related data + * and notifies interested parties if this was the last query to process. + * @param query the ContactQuery to remove. + */ + public abstract void removeQuery(ContactQuery query); + + /** + * Verifies if the given query is contained in this filter query. + * + * @param query the query we're looking for + * @return true if the given query is contained in this + * filter query, false - otherwise + */ + public abstract boolean containsQuery(Object query); +} diff --git a/src/net/java/sip/communicator/service/gui/UIContact.java b/src/net/java/sip/communicator/service/gui/UIContact.java new file mode 100644 index 0000000..774d65e --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/UIContact.java @@ -0,0 +1,139 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +import java.awt.*; +import java.util.*; +import java.util.List; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.swing.*; + +/** + * The UIContact represents the user interface contact contained in the + * contact list component. + * + * @author Yana Stamcheva + */ +public abstract class UIContact +{ + /** + * Returns the descriptor of this contact. + * + * @return the descriptor of this contact + */ + public abstract Object getDescriptor(); + + /** + * Returns the display name of this contact. + * + * @return the display name of this contact + */ + public abstract String getDisplayName(); + + /** + * Returns the display details of this contact. These would be shown + * whenever the contact is selected. + * + * @return the display details of this contact + */ + public abstract String getDisplayDetails(); + + /** + * Returns the index of this contact in its source. + * + * @return the source index + */ + public abstract int getSourceIndex(); + + /** + * Creates a tool tip for this contact. If such tooltip is + * provided it would be shown on mouse over over this UIContact. + * + * @return the tool tip for this contact descriptor + */ + public abstract ExtendedTooltip getToolTip(); + + /** + * Returns the right button menu component. + * + * @return the right button menu component + */ + public abstract Component getRightButtonMenu(); + + /** + * Returns the parent group. + * + * @return the parent group + */ + public abstract UIGroup getParentGroup(); + + /** + * Sets the given UIGroup to be the parent group of this + * UIContact. + * + * @param parentGroup the parent UIGroup of this contact + */ + public abstract void setParentGroup(UIGroup parentGroup); + + /** + * Returns an Iterator over a list of the search strings of this + * contact. + * + * @return an Iterator over a list of the search strings of this + * contact + */ + public abstract Iterator getSearchStrings(); + + /** + * Returns the default ContactDetail to use for any operations + * depending to the given OperationSet class. + * + * @param opSetClass the OperationSet class we're interested in + * @return the default ContactDetail to use for any operations + * depending to the given OperationSet class + */ + public abstract UIContactDetail getDefaultContactDetail( + Class opSetClass); + + /** + * Returns a list of all UIContactDetails corresponding to the + * given OperationSet class. + * + * @param opSetClass the OperationSet class we're looking for + * @return a list of all UIContactDetails corresponding to the + * given OperationSet class + */ + public abstract List getContactDetailsForOperationSet( + Class opSetClass); + + /** + * Returns a list of all UIContactDetails within this + * UIContact. + * + * @return a list of all UIContactDetails within this + * UIContact + */ + public abstract List getContactDetails(); + + /** + * Returns all custom action buttons for this notification contact. + * + * @return a list of all custom action buttons for this notification contact + */ + public abstract Collection getContactCustomActionButtons(); + + /** + * Returns the preferred height of this group in the contact list. + * + * @return the preferred height of this group in the contact list + */ + public int getPreferredHeight() + { + return -1; + } +} diff --git a/src/net/java/sip/communicator/service/gui/UIContactDetail.java b/src/net/java/sip/communicator/service/gui/UIContactDetail.java new file mode 100644 index 0000000..88f8a8e --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/UIContactDetail.java @@ -0,0 +1,203 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +import java.util.*; + +import net.java.sip.communicator.service.protocol.*; + +/** + * The UIContactDetail corresponds to a particular contact detail, + * phone number, IM identifier, email, etc. which has it's preferred mode of + * transport ProtocolProviderService. + * + * @author Yana Stamcheva + */ +public abstract class UIContactDetail +{ + /** + * The prefix to be used when calling this contact detail. + */ + private String prefix; + + /** + * The address of this detail. + */ + private final String address; + + /** + * The display name of this detail. + */ + private final String displayName; + + /** + * The ProtocolProviderService corresponding to this detail. + */ + private final ProtocolProviderService protocolProvider; + + /** + * The protocol to be used for this contact detail if no protocol provider + * is set. + */ + private final String preferredProtocol; + + /** + * The collection of labels associated with this detail. + */ + private final Collection labels; + + /** + * The category of the underlying contact detail. + */ + private final String category; + + /** + * The underlying object that this class is wrapping + */ + private final Object descriptor; + + /** + * Creates a UIContactDetail by specifying the contact + * address, the displayName and preferredProvider. + * @param address the contact address + * @param displayName the contact display name + * @param category the category of the underlying contact detail + * @param labels the collection of labels associated with this detail + * @param statusIcon the status icon of this contact detail + * @param preferredProvider the preferred protocol provider + * @param preferredProtocol the preferred protocol if no protocol provider + * is set + * @param descriptor the underlying object that this class is wrapping + */ + public UIContactDetail( + String address, + String displayName, + String category, + Collection labels, + ProtocolProviderService preferredProvider, + String preferredProtocol, + Object descriptor) + { + this.address = address; + this.displayName = displayName; + this.category = category; + this.labels = labels; + this.protocolProvider = preferredProvider; + this.preferredProtocol = preferredProtocol; + this.descriptor = descriptor; + } + + /** + * Returns the display name of this detail. + * @return the display name of this detail + */ + public String getDisplayName() + { + return displayName; + } + + /** + * Returns the address of this detail. + * @return the address of this detail + */ + public String getAddress() + { + if (prefix != null && prefix.trim().length() >= 0) + return prefix + address; + + return address; + } + + /** + * Returns the category of the underlying detail. + * + * @return the category of the underlying detail + */ + public String getCategory() + { + return category; + } + + /** + * Returns an iterator over the collection of labels associated with this + * detail. + * + * @return an iterator over the collection of labels associated with this + * detail + */ + public Iterator getLabels() + { + if (labels != null) + return labels.iterator(); + + return null; + } + + /** + * Returns the protocol provider preferred for contacting this detail for + * the given OperationSet class. + * @param opSetClass the OperationSet class for which we're looking + * for provider + * @return the protocol provider preferred for contacting this detail + */ + public ProtocolProviderService getPreferredProtocolProvider( + Class opSetClass) + { + return protocolProvider; + } + + /** + * Returns the name of the protocol preferred for contacting this detail for + * the given OperationSet class if no preferred protocol provider + * is set. + * @param opSetClass the OperationSet class for which we're looking + * for protocol + * @return the name of the protocol preferred for contacting this detail + */ + public String getPreferredProtocol(Class opSetClass) + { + return preferredProtocol; + } + + /** + * Returns the prefix to be used when calling this contact detail. + * + * @return the prefix to be used when calling this contact detail + */ + public String getPrefix() + { + return prefix; + } + + /** + * Sets the prefix to be used when calling this contact detail. + * + * @param prefix the prefix to be used when calling this contact detail + */ + public void setPrefix(String prefix) + { + this.prefix = prefix; + } + + /** + * Returns the underlying object that this class is wrapping + * + * @return the underlying object that this class is wrapping + */ + public Object getDescriptor() + { + return descriptor; + } + + /** + * Returns the PresenceStatus of this ContactDetail or + * null if the detail doesn't support presence. + * @return the PresenceStatus of this ContactDetail or + * null if the detail doesn't support presence + */ + public abstract PresenceStatus getPresenceStatus(); +} diff --git a/src/net/java/sip/communicator/service/gui/UIContactDetailAction.java b/src/net/java/sip/communicator/service/gui/UIContactDetailAction.java new file mode 100644 index 0000000..1286ee0 --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/UIContactDetailAction.java @@ -0,0 +1,25 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +/** + * Defines an action for an UIContactDetail. + * + * @author Yana Stamcheva + */ +public interface UIContactDetailAction +{ + /** + * Indicates this action is executed for the given UIContactDetail. + * + * @param contactDetail the UIContactDetail for which this action + * is performed + * @param x the x coordinate of the action + * @param y the y coordinate of the action + */ + public void actionPerformed (UIContactDetail contactDetail, int x, int y); +} diff --git a/src/net/java/sip/communicator/service/gui/UIContactSource.java b/src/net/java/sip/communicator/service/gui/UIContactSource.java new file mode 100644 index 0000000..f2b6028 --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/UIContactSource.java @@ -0,0 +1,60 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +import net.java.sip.communicator.service.contactsource.*; + +/** + * The user interface representation of a contact source. + * + * @author Yana Stamcheva + */ +public interface UIContactSource +{ + /** + * Returns the UI group for this contact source. There's only one group + * descriptor per external source. + * + * @return the group descriptor + */ + public UIGroup getUIGroup(); + + /** + * Returns the UIContact corresponding to the given + * sourceContact. + * + * @param sourceContact the SourceContact, for which we search a + * corresponding UIContact + * @return the UIContact corresponding to the given + * sourceContact + */ + public UIContact createUIContact(SourceContact sourceContact); + + /** + * Removes the UIContact from the given sourceContact. + * @param sourceContact the SourceContact, which corresponding UI + * contact we would like to remove + */ + public void removeUIContact(SourceContact sourceContact); + + /** + * Returns the UIContact corresponding to the given + * SourceContact. + * @param sourceContact the SourceContact, which corresponding UI + * contact we're looking for + * @return the UIContact corresponding to the given + * MetaContact + */ + public UIContact getUIContact(SourceContact sourceContact); + + /** + * Returns the corresponding ContactSourceService. + * + * @return the corresponding ContactSourceService + */ + public ContactSourceService getContactSourceService(); +} diff --git a/src/net/java/sip/communicator/service/gui/UIGroup.java b/src/net/java/sip/communicator/service/gui/UIGroup.java new file mode 100644 index 0000000..9bdfa07 --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/UIGroup.java @@ -0,0 +1,137 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui; + +import java.awt.*; + +/** + * The UIGroup represents the user interface contact list group. + * + * @author Yana Stamcheva + */ +public abstract class UIGroup +{ + /** + * The preferred height of this group in the contact list. + */ + private int preferredGroupHeight = -1; + + /** + * The display details of this group. + */ + private String displayDetails = ""; + + /** + * Returns the descriptor of the group. This would be the underlying object + * that should provide all other necessary information for the group. + * + * @return the descriptor of the group + */ + public abstract Object getDescriptor(); + + /** + * The display name of the group. The display name is the name to be shown + * in the contact list group row. + * + * @return the display name of the group + */ + public abstract String getDisplayName(); + + /** + * Returns the display details of this contact. These would be shown + * whenever the contact is selected. The display details aren't obligatory, + * so we return an empty string. + * + * @return the display details of this contact + */ + public String getDisplayDetails() + { + return displayDetails; + } + + /** + * Sets the display details of this group. + * + * @return the display details of this group + */ + public void setDisplayDetails(String displayDetails) + { + this.displayDetails = displayDetails; + } + + /** + * Returns the index of this group in its source. In other words this is + * the descriptor index. + * + * @return the index of this group in its source + */ + public abstract int getSourceIndex(); + + /** + * Returns the parent group. + * + * @return the parent group + */ + public abstract UIGroup getParentGroup(); + + /** + * Indicates if the group is collapsed or expanded. + * + * @return true to indicate that the group is collapsed, + * false to indicate that it's expanded + */ + public abstract boolean isGroupCollapsed(); + + /** + * Returns the count of online child contacts. + * + * @return the count of online child contacts + */ + public abstract int countOnlineChildContacts(); + + /** + * Returns the child contacts count. + * + * @return child contacts count + */ + public abstract int countChildContacts(); + + /** + * Returns the identifier of this group. + * + * @return the identifier of this group + */ + public abstract String getId(); + + /** + * Returns the right button menu for this group. + * + * @return the right button menu component for this group + */ + public abstract Component getRightButtonMenu(); + + /** + * Returns the preferred height of this group in the contact list. + * + * @return the preferred height of this group in the contact list + */ + public int getPreferredHeight() + { + return preferredGroupHeight; + } + + /** + * Sets the preferred height of this group in the contact list. + * + * @param preferredHeight the preferred height of this group in the contact + * list + */ + public void setPreferredHeight(int preferredHeight) + { + this.preferredGroupHeight = preferredHeight; + } +} diff --git a/src/net/java/sip/communicator/service/gui/UIService.java b/src/net/java/sip/communicator/service/gui/UIService.java index 45f4dfd..add11c0 100644 --- a/src/net/java/sip/communicator/service/gui/UIService.java +++ b/src/net/java/sip/communicator/service/gui/UIService.java @@ -455,4 +455,11 @@ public interface UIService * participants to be included into the newly created Chat */ public void startChat(String[] participants); + + /** + * Creates a contact list component. + * + * @return the created ContactList + */ + public ContactList createContactListComponent(); } diff --git a/src/net/java/sip/communicator/service/gui/event/ContactListEvent.java b/src/net/java/sip/communicator/service/gui/event/ContactListEvent.java new file mode 100644 index 0000000..623788c --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/event/ContactListEvent.java @@ -0,0 +1,110 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui.event; + +import java.util.*; + +import net.java.sip.communicator.service.gui.*; + +/** + * The ContactListEvent is triggered when a contact or a group is + * clicked in the contact list. + * @author Yana Stamcheva + */ +public class ContactListEvent + extends EventObject +{ + private int eventID = -1; + + /** + * Indicates that the ContactListEvent instance was triggered by + * selecting a contact in the contact list. + */ + public static final int CONTACT_CLICKED = 1; + + /** + * Indicates that the ContactListEvent instance was triggered by selecting + * a group in the contact list. + */ + public static final int GROUP_CLICKED = 2; + + /** + * Indicates that the ContactListEvent instance was triggered by + * selecting a contact in the contact list. + */ + public static final int CONTACT_SELECTED = 3; + + /** + * Indicates that the ContactListEvent instance was triggered by selecting + * a group in the contact list. + */ + public static final int GROUP_SELECTED = 4; + + /** + * Indicated the number of click accompanying the event + */ + private int clickCount; + + /** + * Creates a new ContactListEvent according to the specified parameters. + * @param source the MetaContact which was selected + * @param eventID one of the XXX_SELECTED static fields indicating the + * nature of the event. + * @param clickCount the number of clicks that was produced when clicking + * over the contact list + */ + public ContactListEvent(Object source, int eventID, int clickCount) + { + super(source); + + this.eventID = eventID; + this.clickCount = clickCount; + } + + /** + * Returns an event id specifying whether the type of this event + * (CONTACT_SELECTED or PROTOCOL_CONTACT_SELECTED) + * @return one of the XXX_SELECTED int fields of this class. + */ + public int getEventID() + { + return eventID; + } + + /** + * Returns the UIContactDescriptor for which this event occured. + * @return the UIContactDescriptor for which this event occured + */ + public UIContact getSourceContact() + { + if(getSource() instanceof UIContact) + return (UIContact) getSource(); + + return null; + } + + /** + * Returns the UIGroupDescriptor for which this event occured. + * @return the UIGroupDescriptor for which this event occured + */ + public UIGroup getSourceGroup() + { + if(getSource() instanceof UIGroup) + return (UIGroup) getSource(); + + return null; + } + + /** + * Returns the number of click of this event. + * @return the number of click of this event. + */ + public int getClickCount() + { + return clickCount; + } +} diff --git a/src/net/java/sip/communicator/service/gui/event/ContactListListener.java b/src/net/java/sip/communicator/service/gui/event/ContactListListener.java new file mode 100644 index 0000000..f6fa602 --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/event/ContactListListener.java @@ -0,0 +1,50 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui.event; + +import java.util.*; + +/** + * Listens for events coming from mouse events over the contact list. For + * example a contact been clicked or a group been selected. + * + * @author Yana Stamcheva + */ +public interface ContactListListener extends EventListener +{ + /** + * Indicates that a group has been selected. + * + * @param evt the ContactListEvent that has been triggered from + * the user selection + */ + public void groupClicked(ContactListEvent evt); + + /** + * Indicates that a group has been selected. + * + * @param evt the ContactListEvent that has been triggered from + * the user selection + */ + public void groupSelected(ContactListEvent evt); + + /** + * Indicates that a contact has been clicked. + * + * @param evt the ContactListEvent that has been triggered from + * the user click + */ + public void contactClicked(ContactListEvent evt); + + /** + * Indicates that a contact has been selected. + * + * @param evt the ContactListEvent that has been triggered from + * the user selection + */ + public void contactSelected(ContactListEvent evt); +} diff --git a/src/net/java/sip/communicator/service/gui/event/FilterQueryListener.java b/src/net/java/sip/communicator/service/gui/event/FilterQueryListener.java new file mode 100644 index 0000000..1f7747f --- /dev/null +++ b/src/net/java/sip/communicator/service/gui/event/FilterQueryListener.java @@ -0,0 +1,31 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.gui.event; + +import net.java.sip.communicator.service.gui.*; + +/** + * The FilterQueryListener is notified when a filter query finishes. + * + * @author Yana Stamcheva + */ +public interface FilterQueryListener +{ + /** + * Indicates that the given query has finished with success, i.e. + * the filter has returned results. + * @param query the FilterQuery, where this listener is registered + */ + public void filterQuerySucceeded(FilterQuery query); + + /** + * Indicates that the given query has finished with failure, i.e. + * no results for the filter were found. + * @param query the FilterQuery, where this listener is registered + */ + public void filterQueryFailed(FilterQuery query); +} diff --git a/src/net/java/sip/communicator/service/gui/gui.manifest.mf b/src/net/java/sip/communicator/service/gui/gui.manifest.mf index ea63780..0708371 100644 --- a/src/net/java/sip/communicator/service/gui/gui.manifest.mf +++ b/src/net/java/sip/communicator/service/gui/gui.manifest.mf @@ -5,7 +5,8 @@ Bundle-Vendor: jitsi.org Bundle-Version: 0.0.1 System-Bundle: yes Import-Package: org.osgi.framework, - org.jitsi.service.resources, net.java.sip.communicator.service.resources, + org.jitsi.service.resources, + net.java.sip.communicator.service.resources, net.java.sip.communicator.util Export-Package: net.java.sip.communicator.service.gui, net.java.sip.communicator.service.gui.event, diff --git a/src/net/java/sip/communicator/service/protocol/event/ContactPropertyChangeEvent.java b/src/net/java/sip/communicator/service/protocol/event/ContactPropertyChangeEvent.java index 6f324bc..f69caeb 100644 --- a/src/net/java/sip/communicator/service/protocol/event/ContactPropertyChangeEvent.java +++ b/src/net/java/sip/communicator/service/protocol/event/ContactPropertyChangeEvent.java @@ -36,6 +36,12 @@ public class ContactPropertyChangeEvent public static final String PROPERTY_PERSISTENT_DATA = "PersistentData"; /** + * Indicates that a change has occurred in the display details of the source + * contact. + */ + public static final String PROPERTY_DISPLAY_DETAILS = "DisplayDetails"; + + /** * Creates a ContactPropertyChangeEvent indicating that a change has * occurred for property propertyName in the source * contact and that its value has changed from oldValue to diff --git a/src/net/java/sip/communicator/util/swing/ExtendedTooltip.java b/src/net/java/sip/communicator/util/swing/ExtendedTooltip.java new file mode 100644 index 0000000..2c24646 --- /dev/null +++ b/src/net/java/sip/communicator/util/swing/ExtendedTooltip.java @@ -0,0 +1,414 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.util.swing; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; +import javax.swing.plaf.*; +import javax.swing.plaf.metal.*; + +import net.java.sip.communicator.util.*; + +/** + * The tooltip shown over a contact in the contact list. + * + * @author Yana Stamcheva + */ +public class ExtendedTooltip + extends JToolTip +{ + private static final Logger logger + = Logger.getLogger(ExtendedTooltip.class); + + /** + * Class id key used in UIDefaults. + */ + private static final String uiClassID = + ExtendedTooltip.class.getName() + "ToolTipUI"; + + /** + * Adds the ui class to UIDefaults. + */ + static + { + UIManager.getDefaults().put(uiClassID, + ImageToolTipUI.class.getName()); + } + + private final JLabel imageLabel = new JLabel(); + + private final JLabel titleLabel = new JLabel(); + + private final JPanel linesPanel = new JPanel(); + + private final JTextArea bottomTextArea = new JTextArea(); + + private int textWidth = 0; + + private int textHeight = 0; + + private boolean isListViewEnabled; + + /** + * Created a MetaContactTooltip. + * @param isListViewEnabled indicates if the list view is enabled + */ + public ExtendedTooltip(final Window parentWindow, boolean isListViewEnabled) + { + this.isListViewEnabled = isListViewEnabled; + + this.setLayout(new BorderLayout()); + + JPanel mainPanel = new JPanel(new BorderLayout(5, 5)); + JPanel centerPanel = new JPanel(new BorderLayout()); + + mainPanel.setOpaque(false); + centerPanel.setOpaque(false); + linesPanel.setOpaque(false); + bottomTextArea.setOpaque(false); + + titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD)); + + if (isListViewEnabled) + { + linesPanel.setLayout( + new BoxLayout(linesPanel, BoxLayout.Y_AXIS)); + + mainPanel.add(imageLabel, BorderLayout.WEST); + mainPanel.add(centerPanel, BorderLayout.CENTER); + + centerPanel.add(titleLabel, BorderLayout.NORTH); + centerPanel.add(linesPanel, BorderLayout.CENTER); + } + else + { + titleLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT); + mainPanel.add(imageLabel, BorderLayout.CENTER); + mainPanel.add(titleLabel, BorderLayout.NORTH); + } + + bottomTextArea.setEditable(false); + bottomTextArea.setLineWrap(true); + bottomTextArea.setWrapStyleWord(true); + bottomTextArea.setFont(bottomTextArea.getFont().deriveFont(10f)); + mainPanel.add(bottomTextArea, BorderLayout.SOUTH); + + // Hide the tooltip when the parent window hides. + /* + * FIXME The parentWindow will surely outlive this ExtendedTooltip so + * adding a WindowFocusListener without removing the same + * WindowFocusListener later on is guaranteed to cause a memory leak. + */ + parentWindow.addWindowFocusListener(new WindowFocusListener() + { + public void windowLostFocus(WindowEvent e) + { + Window popupWindow + = SwingUtilities.getWindowAncestor(ExtendedTooltip.this); + + if ((popupWindow != null) + && popupWindow.isVisible() + // The popup window should normally be a JWindow, so we + // check here explicitly if for some reason we didn't get + // something else. + && (popupWindow instanceof JWindow)) + { + if (logger.isInfoEnabled()) + logger.info("Tooltip window ancestor to hide: " + + popupWindow); + + popupWindow.setVisible(false); + } + } + + public void windowGainedFocus(WindowEvent e) {} + }); + + // Hide the tooltip if the parent window isn't active + addComponentListener(new ComponentAdapter() + { + public void componentResized(ComponentEvent evt) + { + if (!parentWindow.isActive()) + { + Window popupWindow + = SwingUtilities.getWindowAncestor( + ExtendedTooltip.this); + + if (popupWindow != null + && popupWindow.isVisible() + && !(popupWindow instanceof JFrame) + // The popup window should normally be a JWindow, so we + // check here explicitly if for some reason we didn't get + // something else. + && (popupWindow instanceof JWindow)) + { + if (logger.isInfoEnabled()) + logger.info("Tooltip window ancestor to hide: " + + popupWindow); + + popupWindow.setVisible(false); + } + } + } + }); + + this.add(mainPanel); + } + + /** + * Sets the given image to this tooltip. + * + * @param imageIcon The image icon to set. + */ + public void setImage(ImageIcon imageIcon) + { + imageLabel.setIcon(imageIcon); + } + + /** + * Sets the title of the tooltip. The text would be shown in bold on the top + * of the tooltip panel. + * + * @param titleText The title of the tooltip. + */ + public void setTitle(String titleText) + { + titleLabel.setText(titleText); + + Dimension labelSize = GuiUtils.getStringSize(titleLabel,titleText); + recalculateTooltipSize(labelSize.width, labelSize.height); + } + + /** + * Adds an icon-string list, which would appear on the right of the image + * panel. + * + * @param icon the icon to show + * @param text the name to show + */ + public void addLine(Icon icon, + String text) + { + JLabel lineLabel = new JLabel( text, + icon, + JLabel.LEFT); + + linesPanel.add(lineLabel); + + Dimension labelSize = calculateLabelSize(lineLabel); + + recalculateTooltipSize(labelSize.width, labelSize.height); + } + + /** + * Adds the given array of labels as one line in this tool tip. + * + * @param labels the labels to add + */ + public void addLine(JLabel[] labels) + { + Dimension lineSize = null; + JPanel labelPanel = null; + + if (labels.length > 0) + { + labelPanel = new TransparentPanel( + new FlowLayout(FlowLayout.LEFT, 2, 0)); + linesPanel.add(labelPanel); + } + else + return; + + if (labelPanel != null) + for (JLabel label : labels) + { + labelPanel.add(label); + if (lineSize == null) + lineSize = calculateLabelSize(label); + else + lineSize = new Dimension( + lineSize.width + calculateLabelSize(label).width, + lineSize.height); + } + + recalculateTooltipSize(lineSize.width, lineSize.height); + } + + /** + * Clear all lines. + */ + public void removeAllLines() + { + linesPanel.removeAll(); + } + + /** + * Sets the text that would appear on the bottom of the tooltip. + * @param text the text to set + */ + public void setBottomText(String text) + { + this.bottomTextArea.setText(text); + } + + /** + * Calculates label size. + * + * @param label the label, which size we should calculate + * @return the Dimension indicating the label size + */ + private Dimension calculateLabelSize(JLabel label) + { + Icon icon = label.getIcon(); + String text = label.getText(); + + int iconWidth = 0; + int iconHeight = 0; + if (icon != null) + { + iconWidth = icon.getIconWidth(); + iconHeight = icon.getIconHeight(); + } + + int labelWidth + = GuiUtils.getStringWidth(label, text) + + iconWidth + + label.getIconTextGap(); + + int textHeight = GuiUtils.getStringSize(label, text).height; + + int labelHeight = (iconHeight > textHeight) ? iconHeight : textHeight; + + return new Dimension(labelWidth, labelHeight); + } + + /** + * Re-calculates the tooltip size. + * + * @param newTextWidth the width of the newly added text that should be + * added to the global width + * @param newTextHeight the height of the newly added text that should be + * added to the global height + */ + private void recalculateTooltipSize(int newTextWidth, int newTextHeight) + { + if (textWidth < newTextWidth) + textWidth = newTextWidth; + + textHeight += newTextHeight; + } + + /** + * Customized UI for this MetaContactTooltip. + */ + public static class ImageToolTipUI extends MetalToolTipUI + { + static ImageToolTipUI sharedInstance = new ImageToolTipUI(); + + /** + * Creates the UI. + * @param c + * @return + */ + public static ComponentUI createUI(JComponent c) + { + return sharedInstance; + } + + /** + * Overwrite the UI paint method to do nothing in order fix double + * painting of the tooltip text. + * @param g the Graphics object + * @param c the component used to render the tooltip + */ + @Override + public void paint(Graphics g, JComponent c) + {} + + /** + * Override ComponentUI update method to set visibility of bottomText. + * @param g Graphics object + * @param c the component used to render the tooltip + */ + @Override + public void update(Graphics g, JComponent c) + { + JTextArea bottomTextArea = + ((ExtendedTooltip)c).bottomTextArea; + + String bottomText = bottomTextArea.getText(); + if(bottomText == null || bottomText.length() <= 0) + bottomTextArea.setVisible(false); + else + bottomTextArea.setVisible(true); + super.update(g, c); + } + + /** + * Returns the size of the given component. + * @param c the component used to render the tooltip + * @return the size of the given component. + */ + @Override + public Dimension getPreferredSize(JComponent c) + { + ExtendedTooltip tooltip = (ExtendedTooltip)c; + + Icon icon = tooltip.imageLabel.getIcon(); + int width = 0; + if (icon != null) + width += icon.getIconWidth(); + + if (tooltip.isListViewEnabled) + width += tooltip.textWidth + 15; + else + width = tooltip.textWidth > width ? tooltip.textWidth : width; + + int imageHeight = 0; + if (icon != null) + imageHeight = icon.getIconHeight(); + + int height = 0; + if (tooltip.isListViewEnabled) + { + height = imageHeight > tooltip.textHeight + ? imageHeight : tooltip.textHeight; + } + else + height = imageHeight + tooltip.textHeight; + + String bottomText = tooltip.bottomTextArea.getText(); + if(bottomText != null && bottomText.length() > 0) + { + // Seems a little messy, but sets the proper size. + tooltip.bottomTextArea.setColumns(5); + tooltip.bottomTextArea.setSize(0,0); + tooltip.bottomTextArea.setSize( + tooltip.bottomTextArea.getPreferredSize()); + + height += tooltip.bottomTextArea.getPreferredSize().height; + } + + return new Dimension(width, height); + } + } + + /** + * Returns the name of the L&F class that renders this component. + * + * @return the string "TreeUI" + * @see JComponent#getUIClassID + * @see UIDefaults#getUI + */ + public String getUIClassID() + { + return uiClassID; + } +} diff --git a/src/net/java/sip/communicator/util/swing/SIPCommScrollPane.java b/src/net/java/sip/communicator/util/swing/SIPCommScrollPane.java new file mode 100644 index 0000000..84b73f8 --- /dev/null +++ b/src/net/java/sip/communicator/util/swing/SIPCommScrollPane.java @@ -0,0 +1,236 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.util.swing; + +import java.awt.*; +import java.awt.image.*; +import java.beans.*; +import java.lang.reflect.*; + +import javax.swing.*; + +import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.skin.*; + +import org.jitsi.util.*; + +/** + * The SCScrollPane is a JScrollPane with a custom viewport that allows to + * set an image as a background. Depending on the + * "impl.gui.IS_CONTACT_LIST_TEXTURE_BG_ENABLED" property we'll be setting a + * single image or a texture of images. + * + * @author Yana Stamcheva + * @author Adam Netocny + */ +public class SIPCommScrollPane + extends JScrollPane + implements Skinnable +{ + private static final long serialVersionUID = 0L; + + /** + * Creates an SCSCrollPane. + */ + public SIPCommScrollPane() + { + this.setBorder(BorderFactory.createMatteBorder( + 1, 0, 1, 0, Color.GRAY)); + + this.setViewport(new SCViewport()); + + this.getVerticalScrollBar().setUnitIncrement(100); + } + + /** + * Sets the view of this JViewport. + * + * @param view the view to set. + */ + @Override + public void setViewportView(Component view) + { + if (view instanceof JComponent) + { + JComponent viewAsJComponent = (JComponent) view; + + viewAsJComponent.setBorder( + BorderFactory.createEmptyBorder(3, 3, 3, 3)); + viewAsJComponent.setOpaque(false); + } + + super.setViewportView(view); + } + + /** + * Reloads skin information in viewport. + */ + public void loadSkin() + { + ((SCViewport) getViewport()).loadSkin(); + } + + /** + * The SCViewport used as viewport in this scrollpane. + */ + private static class SCViewport + extends JViewport + implements Skinnable + { + private static final long serialVersionUID = 1L; + + private BufferedImage bgImage; + + private Color color; + + private TexturePaint texture; + + /** + * Creates the SCViewport. + */ + public SCViewport() + { + this.setBackground(Color.WHITE); + + loadSkin(); + } + + /** + * Returns the boolean value of the property given by key. + * @param key the key of the property we look for + * @return the boolean value of the searched property + */ + private boolean getSettingsBoolean(String key) + { + return + Boolean.parseBoolean( + UtilActivator.getResources().getSettingsString(key)); + } + + /** + * Paints this viewport. + * @param g the Graphics object used for painting + */ + @Override + public void paintComponent(Graphics g) + { + super.paintComponent(g); + + g = g.create(); + try + { + AntialiasingManager.activateAntialiasing(g); + + Graphics2D g2 = (Graphics2D) g; + int width = getWidth(); + int height = getHeight(); + + // paint the image + if (bgImage != null) + { + if (texture != null) + { + g2.setPaint(texture); + + g2.fillRect(0, 0, width, height); + } + else + { + g.setColor(color); + + // paint the background with the chosen color + g.fillRect(0, 0, width, height); + + g2.drawImage(bgImage, width - bgImage.getWidth(), + height - bgImage.getHeight(), this); + } + } + } + finally + { + g.dispose(); + } + } + + /** + * Reloads background. + */ + public void loadSkin() + { + if(getSettingsBoolean("impl.gui.IS_CONTACT_LIST_IMG_BG_ENABLED")) + { + bgImage = + UtilActivator.getImage("service.gui.MAIN_WINDOW_BACKGROUND"); + + if (getSettingsBoolean( + "impl.gui.IS_CONTACT_LIST_TEXTURE_BG_ENABLED") + && (bgImage != null)) + { + texture = + new TexturePaint(bgImage, new Rectangle(0, 0, bgImage + .getWidth(null), bgImage.getHeight(null))); + + color = null; + } + else + { + texture = null; + color = + new Color(UtilActivator.getResources().getColor( + "service.gui.CONTACT_LIST_BACKGROUND")); + } + } + else + { + bgImage = null; + texture = null; + color = null; + } + } + } + + /** + * Releases the resources allocated by this instance throughout its lifetime + * and prepares it for garbage collection. + */ + public void dispose() + { + if(OSUtils.IS_MAC) + { + // Apple introduced a memory leak in JViewport class - + // they add a PropertyChangeListeners to the CToolkit + try + { + 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, clean up. + if(f.get(pc).equals(this.getViewport())) + { + 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/util/swing/plaf/SIPCommTreeUI.java b/src/net/java/sip/communicator/util/swing/plaf/SIPCommTreeUI.java new file mode 100644 index 0000000..7aff92f --- /dev/null +++ b/src/net/java/sip/communicator/util/swing/plaf/SIPCommTreeUI.java @@ -0,0 +1,258 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.util.swing.plaf; + +import java.awt.*; +import java.awt.Container; +import java.awt.event.*; + +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.plaf.*; +import javax.swing.plaf.basic.*; +import javax.swing.tree.*; + +/** + * SIPCommTreeUI implementation. + * + * @author Yana Stamcheva + */ +public class SIPCommTreeUI + extends BasicTreeUI + implements HierarchyListener, + TreeSelectionListener +{ + private static JTree tree; + + private JViewport parentViewport; + + private VariableLayoutCache layoutCache; + + /** + * Last selected index. + */ + private int lastSelectedIndex; + + /** + * Creates the UI for the given component. + * @param c the component for which we're create an UI + * @return this UI implementation + */ + public static ComponentUI createUI(JComponent c) + { + return new SIPCommTreeUI(); + } + + /** + * Installs this UI to the given component. + * @param c the component to which to install this UI + */ + public void installUI(JComponent c) + { + if ( c == null ) + throw new NullPointerException( + "null component passed to BasicTreeUI.installUI()" ); + + tree = (JTree)c; + + JViewport v = getFirstParentViewport(tree); + if(v != null) + this.parentViewport = v; + else + tree.addHierarchyListener(this); + + tree.getSelectionModel().addTreeSelectionListener(this); + + super.installUI(c); + } + + /** + * Returns the first parent view port found. + * @param c the component parents we search + * @return the first parent view port found. + */ + private JViewport getFirstParentViewport(Container c) + { + if(c == null) + return null; + else + if(c instanceof JViewport) + return (JViewport)c; + else + return getFirstParentViewport(c.getParent()); + } + + /** + * On uninstalling the ui remove the listeners. + * @param c + */ + public void uninstallUI(JComponent c) + { + tree.getSelectionModel().clearSelection(); + tree.getSelectionModel().removeTreeSelectionListener(this); + tree.removeHierarchyListener(this); + + super.uninstallUI(c); + } + + /** + * HierarchyListener's method. + * @param e the event. + */ + public void hierarchyChanged(HierarchyEvent e) + { + if (e.getID() == HierarchyEvent.HIERARCHY_CHANGED + && (e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0 + && e.getChangedParent() instanceof JViewport) + { + parentViewport = (JViewport) e.getChangedParent(); + } + } + + /** + * The TreeSelectionListener's method. + * @param e the event. + */ + public void valueChanged(TreeSelectionEvent e) + { + // Update cell size. + selectionChanged( e.getOldLeadSelectionPath(), + e.getNewLeadSelectionPath()); + } + + /** + * Installs the defaults of this UI. + */ + protected void installDefaults() + { + if(tree.getBackground() == null || + tree.getBackground() instanceof UIResource) { + tree.setBackground(UIManager.getColor("Tree.background")); + } + if(getHashColor() == null || getHashColor() instanceof UIResource) { + setHashColor(UIManager.getColor("Tree.hash")); + } + if (tree.getFont() == null || tree.getFont() instanceof UIResource) + tree.setFont( UIManager.getFont("Tree.font") ); + // JTree's original row height is 16. To correctly display the + // contents on Linux we should have set it to 18, Windows 19 and + // Solaris 20. As these values vary so much it's too hard to + // be backward compatable and try to update the row height, we're + // therefor NOT going to adjust the row height based on font. If the + // developer changes the font, it's there responsibility to update + // the row height. + + setExpandedIcon(null); + setCollapsedIcon(null); + + setLeftChildIndent(0); + setRightChildIndent(0); + + LookAndFeel.installProperty(tree, "rowHeight", + UIManager.get("Tree.rowHeight")); + + largeModel = (tree.isLargeModel() && tree.getRowHeight() > 0); + + Object scrollsOnExpand = UIManager.get("Tree.scrollsOnExpand"); + if (scrollsOnExpand != null) { + LookAndFeel.installProperty( + tree, "scrollsOnExpand", scrollsOnExpand); + } + + UIManager.getDefaults().put("Tree.paintLines", false); + UIManager.getDefaults().put("Tree.lineTypeDashed", false); + } + + /** + * Creates the object responsible for managing what is expanded, as + * well as the size of nodes. + * @return the created layout cache + */ + protected AbstractLayoutCache createLayoutCache() + { + layoutCache = new VariableLayoutCache(); + return layoutCache; + } + + /** + * Do not select the ShowMoreContact. + * + * @param path the TreePath to select + * @param event the MouseEvent that provoked the select + */ + protected void selectPathForEvent(TreePath path, MouseEvent event) + { + super.selectPathForEvent(path, event); + } + + /** + * A custom layout cache that recalculates the width of the cell the match + * the width of the tree (i.e. expands the cell to the right). + */ + private class VariableLayoutCache extends VariableHeightLayoutCache + { + /** + * Returns the preferred width of the receiver. + * @param path the path, which bounds we obtain + * @param placeIn the initial rectangle of the path + * @return the bounds of the path + */ + public Rectangle getBounds(TreePath path, Rectangle placeIn) + { + Rectangle rect = super.getBounds(path, placeIn); + + if (rect != null && parentViewport != null) + { + rect.width = parentViewport.getWidth() - 2; + } + + return rect; + } + } + + /** + * Ensures the tree size. + */ + private void ensureTreeSize() + { + // Update tree height. + updateSize(); + + // Finally repaint in order the change to take place. + tree.repaint(); + } + + /** + * Refreshes row sizes corresponding to the given paths. + * + * @param oldPath the old selection path + * @param newPath the new selection path + */ + public void selectionChanged(TreePath oldPath, TreePath newPath) + { + if (oldPath != null) + layoutCache.invalidatePathBounds(oldPath); + + if (newPath != null) + { + layoutCache.invalidatePathBounds(newPath); + lastSelectedIndex = tree.getRowForPath(newPath); + } + // If the selection has disappeared, for example when the selected row + // has been removed, refresh the previously selected row. + else + { + int nextRow = (tree.getRowCount() > lastSelectedIndex) + ? lastSelectedIndex : tree.getRowCount() - 1; + + layoutCache.invalidatePathBounds( + tree.getPathForRow(nextRow)); + } + + ensureTreeSize(); + } +} diff --git a/src/net/java/sip/communicator/util/util.manifest.mf b/src/net/java/sip/communicator/util/util.manifest.mf index 8f2c502..004bc74 100644 --- a/src/net/java/sip/communicator/util/util.manifest.mf +++ b/src/net/java/sip/communicator/util/util.manifest.mf @@ -20,6 +20,7 @@ Import-Package: com.sun.awt, javax.swing.text, javax.swing.text.html, javax.swing.text.html.parser, + javax.swing.tree, javax.xml.parsers, javax.xml.transform, javax.xml.transform.dom, -- cgit v1.1