/* * 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.contactsource; 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.contactsource.*; import net.java.sip.communicator.service.customcontactactions.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.swing.*; import org.osgi.framework.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; /** * The ExternalContactSource is the UI abstraction of the * ContactSourceService. * * @author Yana Stamcheva */ public class ExternalContactSource { /** * The data key of the SourceContactDescriptor object used to store a * reference to this object in its corresponding Sourcecontact. */ public static final String UI_CONTACT_DATA_KEY = SourceUIContact.class.getName() + ".uiContactDescriptor"; /** * The SourceUIGroup containing all contacts from this source. */ private final SourceUIGroup sourceUIGroup; /** * The contact source. */ private final ContactSourceService contactSource; /** * The current custom action contact. */ private static SourceContact customActionContact; /** * The list of action buttons for this source contact. */ private static Map, SIPCommButton> customActionButtons; /** * Creates an ExternalContactSource based on the given * ContactSourceService. * * @param contactSource the ContactSourceService, on which this * ExternalContactSource is based */ public ExternalContactSource(ContactSourceService contactSource) { this.contactSource = contactSource; sourceUIGroup = new SourceUIGroup(contactSource.getDisplayName()); } /** * Returns the corresponding ContactSourceService. * * @return the corresponding ContactSourceService */ public ContactSourceService getContactSourceService() { return contactSource; } /** * Returns the UI group for this contact source. There's only one group * descriptor per external source. * * @return the group descriptor */ public UIGroup getUIGroup() { return sourceUIGroup; } /** * 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) { SourceUIContact descriptor = new SourceUIContact(sourceContact, sourceUIGroup); sourceContact.setData(UI_CONTACT_DATA_KEY, descriptor); return descriptor; } /** * Removes the UIContact from the given sourceContact. * @param sourceContact the SourceContact, which corresponding UI * contact we would like to remove */ public static void removeUIContact(SourceContact sourceContact) { sourceContact.setData(UI_CONTACT_DATA_KEY, null); } /** * 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 static UIContact getUIContact(SourceContact sourceContact) { return (UIContact) sourceContact.getData(UI_CONTACT_DATA_KEY); } /** * Returns all custom action buttons for this meta contact. * * @return a list of all custom action buttons for this meta contact */ public static Collection getContactCustomActionButtons( final SourceContact sourceContact) { customActionContact = sourceContact; if (customActionButtons == null) initCustomActionButtons(); Iterator> customActionsIter = customActionButtons.keySet().iterator(); Collection availableCustomActionButtons = new LinkedList(); while (customActionsIter.hasNext()) { ContactAction contactAction = customActionsIter.next(); SIPCommButton actionButton = customActionButtons.get(contactAction); if (isContactActionVisible( contactAction, sourceContact)) { availableCustomActionButtons.add(actionButton); } } return availableCustomActionButtons; } /** * Indicates if the given ContactAction should be visible for the * given SourceContact. * * @param contactAction the ContactAction to verify * if the given action should be visible * @return true if the given ContactAction is visible for * the given SourceContact, false - otherwise */ private static boolean isContactActionVisible( ContactAction contactAction, SourceContact contact) { if (contactAction.isVisible(contact)) return true; return false; } /** * Initializes custom action buttons for this contact source. */ private static void initCustomActionButtons() { customActionButtons = new LinkedHashMap , SIPCommButton>(); CustomContactActionsChangeListener changeListener = new CustomContactActionsChangeListener(); for (CustomContactActionsService ccas : getContactActionsServices()) { ccas.addCustomContactActionsListener(changeListener); Iterator> actionIterator = ccas.getCustomContactActions(); while (actionIterator!= null && actionIterator.hasNext()) { final ContactAction ca = actionIterator.next(); SIPCommButton actionButton = customActionButtons.get(ca); if (actionButton == null) { actionButton = new SIPCommButton( new ImageIcon(ca.getIcon()).getImage(), new ImageIcon(ca.getPressedIcon()).getImage(), null); actionButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { List contactDetails = SourceUIContact.getContactDetails( customActionContact); contactDetails.add( new SourceUIContact.SourceContactDetail( customActionContact.getDisplayName(), customActionContact)); UIContactDetailCustomAction contactAction = new UIContactDetailCustomAction(ca); if (contactDetails.size() > 1) { ChooseUIContactDetailPopupMenu detailsPopupMenu = new ChooseUIContactDetailPopupMenu( (JButton) e.getSource(), contactDetails, contactAction); detailsPopupMenu.showPopupMenu(); } else if (contactDetails.size() == 1) { JButton button = (JButton) e.getSource(); Point location = new Point(button.getX(), button.getY() + button.getHeight()); SwingUtilities.convertPointToScreen( location, GuiActivator.getContactList()); location.y = location.y + GuiActivator.getContactList() .getPathBounds( GuiActivator.getContactList() .getSelectionPath()).y; contactAction.actionPerformed( contactDetails.get(0), location.x, location.y); } } }); customActionButtons.put(ca, actionButton); } } } } /** * Returns a list of all custom contact action services. * * @return a list of all custom contact action services. */ @SuppressWarnings ("unchecked") private static List> getContactActionsServices() { List> contactActionsServices = new ArrayList>(); ServiceReference[] serRefs = null; try { // get all registered provider factories serRefs = GuiActivator.bundleContext.getServiceReferences( CustomContactActionsService.class.getName(), null); } catch (InvalidSyntaxException e) {} if (serRefs != null) { for (ServiceReference serRef : serRefs) { CustomContactActionsService customActionService = (CustomContactActionsService) GuiActivator.bundleContext.getService(serRef); if (customActionService.getContactSourceClass() .equals(SourceContact.class)) { contactActionsServices.add( (CustomContactActionsService) customActionService); } } } return contactActionsServices; } /** * The SourceUIGroup is the implementation of the UIGroup for the * ExternalContactSource. It takes the name of the source and * sets it as a group name. */ private class SourceUIGroup implements UIGroup { /** * The display name of the group. */ private final String displayName; /** * The corresponding group node. */ private GroupNode groupNode; /** * Creates an instance of SourceUIGroup. * @param name the name of the group */ public SourceUIGroup(String name) { this.displayName = name; } /** * Returns null to indicate that this group doesn't have a parent group * and can be added directly to the root group. * @return null */ public UIGroup getParentGroup() { return null; } /** * Returns -1 to indicate that this group doesn't have a source index. * @return -1 */ public int getSourceIndex() { if (contactSource.getIdentifier() .equals(ContactSourceService.CALL_HISTORY)) return Integer.MAX_VALUE; return Integer.MAX_VALUE - 1; } /** * Returns false to indicate that this group is always opened. * @return false */ public boolean isGroupCollapsed() { return false; } /** * Returns the display name of this group. * @return the display name of this group */ public String getDisplayName() { return displayName; } /** * Returns -1 to indicate that the child count is unknown. * @return -1 */ public int countChildContacts() { return -1; } /** * Returns -1 to indicate that the child count is unknown. * @return -1 */ public int countOnlineChildContacts() { return -1; } /** * Returns the display name of the group. * @return the display name of the group */ public Object getDescriptor() { return displayName; } /** * Returns null to indicate that this group doesn't have an identifier. * @return null */ public String getId() { return null; } /** * Returns the corresponding GroupNode. * @return the corresponding GroupNode */ public GroupNode getGroupNode() { return groupNode; } /** * Sets the given groupNode. * @param groupNode the GroupNode to set */ public void setGroupNode(GroupNode groupNode) { this.groupNode = groupNode; } /** * Returns the right button menu for this group. * @return null */ public JPopupMenu getRightButtonMenu() { return null; } } /** * 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 implements UIContactDetailAction { /** * The contact action. */ private final ContactAction contactAction; /** * Creates an instance of UIContactDetailCustomAction. */ public UIContactDetailCustomAction( ContactAction contactAction) { this.contactAction = contactAction; } /** * Performs the action on button click. */ public void actionPerformed(UIContactDetail contactDetail, int x, int y) { try { contactAction.actionPerformed( (SourceContact) contactDetail.getDescriptor(), x, y); } catch (OperationFailedException e) { new ErrorDialog(null, GuiActivator.getResources() .getI18NString("service.gui.ERROR"), e.getMessage()); } } } }