/*
* 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());
}
}
}
}