Introducing voice messages user interface.

Instant refresh of call history with new calls, when we're in call history view.
Improved call history interface.
Making sure to remove all operation set related gui listeners when a protocol provider is unregistered.
cusax-fix
Yana Stamcheva 16 years ago
parent 8d2d0bb885
commit 1d0246a997

@ -79,11 +79,8 @@ service.gui.TAB_TITLE_SELECTED=000000
# Custom components GUI constants
# Background color for incoming call lines in the call list.
service.gui.HISTORY_INCOMING_CALL_BACKGROUND=F9FFC5
# Background color for outgoing call lines in the call list.
service.gui.HISTORY_OUTGOING_CALL_BACKGROUND=F3F4F7
# Background color for even records in call history
service.gui.CALL_HISTORY_EVEN_ROW_COLOR=EFEFEF
# Selection color for all lists (contact list, call list, chat rooms list, etc.)
service.gui.LIST_SELECTION_COLOR=ADD2EF

@ -96,6 +96,7 @@ service.gui.icons.CHANGE_ROOM_SUBJECT_16x16=resources/images/impl/gui/common/cha
service.gui.icons.CHANGE_NICKNAME_16x16=resources/images/impl/gui/common/changeNickname16x16.png
service.gui.icons.BAN_16x16=resources/images/impl/gui/common/ban16x16.png
service.gui.icons.KICK_16x16=resources/images/impl/gui/common/kick16x16.png
service.gui.icons.VOICEMAIL=resources/images/impl/gui/common/voicemail.png
# Status icons
service.gui.statusicons.USER_ONLINE_ICON=resources/images/impl/gui/common/statusicons/online.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1013 B

@ -253,7 +253,7 @@ service.gui.LOGIN_WINDOW_TITLE=Login {0}
service.gui.LOGOFF_NOT_SUCCEEDED=An error occurred while logging off with the following account: User name: {0}, Server name: {1}.
service.gui.MEMBER=member
service.gui.MESSAGE=Message:
service.gui.MISSED_CALLS_TOOL_TIP=You have missed calls from:
service.gui.MISSED_CALLS_TOOL_TIP=Missed calls from:
service.gui.MISSED_CALLS_MORE_TOOL_TIP= and {0} more
service.gui.MODERATOR=moderator
service.gui.MORE=See more
@ -413,6 +413,13 @@ service.gui.VIEW_HISTORY=View &history
service.gui.VIEW_SMILEYS=View &smileys
service.gui.VIEW_STYLEBAR=View style &bar
service.gui.VIEW_TOOLBAR=View &toolbar
service.gui.VOICEMAIL_NEW_OLD_RECEIVED={0} new and {1} old messages
service.gui.VOICEMAIL_NEW_RECEIVED={0} new messages
service.gui.VOICEMAIL_OLD_RECEIVED={0} old messages
service.gui.VOICEMAIL_NO_MESSAGES=No messages.
service.gui.VOICEMAIL_TITLE=Voice messages
service.gui.VOICEMAIL_TOOLTIP=Voice messages for:
service.gui.VOICEMAIL_TIP=Click the call button to hear your messages.
service.gui.WARNING=Warning
service.gui.YES=Yes
service.gui.YESTERDAY=Yesterday

@ -29,6 +29,7 @@
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.gui.Container;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.OperationSetMessageWaiting.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
@ -144,6 +145,16 @@ public class MainFrame
*/
private ContactListPane contactListPanel;
/**
* The user interface provider presence listener.
*/
private ProviderPresenceStatusListener uiProviderPresenceListener;
/**
* The user interface call listener.
*/
private CallListener uiCallListener;
/**
* Creates an instance of <tt>MainFrame</tt>.
*/
@ -377,10 +388,13 @@ public void addProtocolSupportedOperationSets(
supportedOperationSets.get(pOpSetClassName);
}
uiProviderPresenceListener
= new GUIProviderPresenceStatusListener();
presence.addProviderPresenceStatusListener(
new GUIProviderPresenceStatusListener());
uiProviderPresenceListener);
presence.addContactPresenceStatusListener(
GuiActivator.getContactList());
GuiActivator.getContactList());
}
// Obtain the basic instant messaging operation set.
@ -424,7 +438,9 @@ public void addProtocolSupportedOperationSets(
= (OperationSetBasicTelephony<?>)
supportedOperationSets.get(telOpSetClassName);
telephony.addCallListener(new CallManager.GuiCallListener());
uiCallListener = new CallManager.GuiCallListener();
telephony.addCallListener(uiCallListener);
}
// Obtain the multi user chat operation set.
@ -467,6 +483,148 @@ public void addProtocolSupportedOperationSets(
{
fileTransferOpSet.addFileTransferListener(getContactListPanel());
}
OperationSetMessageWaiting messageWaiting
= protocolProvider.getOperationSet(OperationSetMessageWaiting.class);
if (messageWaiting != null)
{
messageWaiting.addMessageWaitingNotificationListener(
MessageType.VOICE,
TreeContactList.getNotificationContactSource());
}
}
/**
* Removes all protocol supported operation sets.
*
* @param protocolProvider The protocol provider.
*/
public void removeProtocolSupportedOperationSets(
ProtocolProviderService protocolProvider)
{
Map<String, OperationSet> supportedOperationSets
= protocolProvider.getSupportedOperationSets();
String ppOpSetClassName = OperationSetPersistentPresence
.class.getName();
String pOpSetClassName = OperationSetPresence.class.getName();
// Obtain the presence operation set.
if (supportedOperationSets.containsKey(ppOpSetClassName)
|| supportedOperationSets.containsKey(pOpSetClassName))
{
OperationSetPresence presence = (OperationSetPresence)
supportedOperationSets.get(ppOpSetClassName);
if(presence == null)
{
presence = (OperationSetPresence)
supportedOperationSets.get(pOpSetClassName);
}
if (uiProviderPresenceListener != null)
presence.removeProviderPresenceStatusListener(
uiProviderPresenceListener);
presence.removeContactPresenceStatusListener(
GuiActivator.getContactList());
}
// Obtain the basic instant messaging operation set.
String imOpSetClassName = OperationSetBasicInstantMessaging
.class.getName();
if (supportedOperationSets.containsKey(imOpSetClassName))
{
OperationSetBasicInstantMessaging im
= (OperationSetBasicInstantMessaging)
supportedOperationSets.get(imOpSetClassName);
im.removeMessageListener(getContactListPanel());
}
// Obtain the typing notifications operation set.
String tnOpSetClassName = OperationSetTypingNotifications
.class.getName();
if (supportedOperationSets.containsKey(tnOpSetClassName))
{
OperationSetTypingNotifications tn
= (OperationSetTypingNotifications)
supportedOperationSets.get(tnOpSetClassName);
//Add to all typing notification operation sets the Message
//listener implemented in the ContactListPanel, which handles
//all received messages.
tn.removeTypingNotificationsListener(this.getContactListPanel());
}
// Obtain the basic telephony operation set.
String telOpSetClassName = OperationSetBasicTelephony.class.getName();
if (supportedOperationSets.containsKey(telOpSetClassName))
{
OperationSetBasicTelephony<?> telephony
= (OperationSetBasicTelephony<?>)
supportedOperationSets.get(telOpSetClassName);
if (uiCallListener != null)
telephony.removeCallListener(uiCallListener);
}
// Obtain the multi user chat operation set.
String multiChatClassName = OperationSetMultiUserChat.class.getName();
if (supportedOperationSets.containsKey(multiChatClassName))
{
OperationSetMultiUserChat multiUserChat
= (OperationSetMultiUserChat)
supportedOperationSets.get(multiChatClassName);
ConferenceChatManager conferenceManager
= GuiActivator.getUIService().getConferenceChatManager();
multiUserChat.removeInvitationListener(conferenceManager);
multiUserChat.removeInvitationRejectionListener(conferenceManager);
multiUserChat.removePresenceListener(conferenceManager);
}
// Obtain the ad-hoc multi user chat operation set.
OperationSetAdHocMultiUserChat adHocMultiChatOpSet
= protocolProvider
.getOperationSet(OperationSetAdHocMultiUserChat.class);
if (adHocMultiChatOpSet != null)
{
ConferenceChatManager conferenceManager
= GuiActivator.getUIService().getConferenceChatManager();
adHocMultiChatOpSet
.removeInvitationListener(conferenceManager);
adHocMultiChatOpSet
.removeInvitationRejectionListener(conferenceManager);
adHocMultiChatOpSet
.removePresenceListener(conferenceManager);
}
// Obtain file transfer operation set.
OperationSetFileTransfer fileTransferOpSet
= protocolProvider.getOperationSet(OperationSetFileTransfer.class);
if (fileTransferOpSet != null)
{
fileTransferOpSet.removeFileTransferListener(getContactListPanel());
}
OperationSetMessageWaiting messageWaiting
= protocolProvider.getOperationSet(OperationSetMessageWaiting.class);
if (messageWaiting != null)
{
messageWaiting.removeMessageWaitingNotificationListener(
MessageType.VOICE,
TreeContactList.getNotificationContactSource());
}
}
/**
@ -509,7 +667,7 @@ public void addProtocolProvider(ProtocolProviderService protocolProvider)
{
if (logger.isTraceEnabled())
logger.trace("Add the following protocol provider to the gui: "
+ protocolProvider.getAccountID().getAccountAddress());
+ protocolProvider.getAccountID().getAccountAddress());
this.protocolProviders.put(protocolProvider,
initiateProviderIndex(protocolProvider));
@ -527,6 +685,31 @@ public void addProtocolProvider(ProtocolProviderService protocolProvider)
this.addProviderContactHandler(protocolProvider, contactHandler);
}
/**
* Adds an account to the application.
*
* @param protocolProvider The protocol provider of the account.
*/
public void removeProtocolProvider(ProtocolProviderService protocolProvider)
{
if (logger.isTraceEnabled())
logger.trace("Remove the following protocol provider to the gui: "
+ protocolProvider.getAccountID().getAccountAddress());
this.protocolProviders.remove(protocolProvider);
this.removeProtocolSupportedOperationSets(protocolProvider);
removeProviderContactHandler(protocolProvider);
this.updateProvidersIndexes(protocolProvider);
if (accountStatusPanel.containsAccount(protocolProvider))
{
accountStatusPanel.removeAccount(protocolProvider);
}
}
/**
* Returns the index of the given protocol provider.
* @param protocolProvider the protocol provider to search for
@ -561,22 +744,6 @@ public void addAccount(ProtocolProviderService protocolProvider)
}
}
/**
* Adds an account to the application.
*
* @param protocolProvider The protocol provider of the account.
*/
public void removeProtocolProvider(ProtocolProviderService protocolProvider)
{
this.protocolProviders.remove(protocolProvider);
this.updateProvidersIndexes(protocolProvider);
if (accountStatusPanel.containsAccount(protocolProvider))
{
accountStatusPanel.removeAccount(protocolProvider);
}
}
/**
* Returns the account user id for the given protocol provider.
* @param protocolProvider the protocol provider corresponding to the
@ -954,9 +1121,14 @@ public MainMenu getMainMenu()
}
/**
* Adds the given <tt>contactHandler</tt> to handle contact events for the
* given <tt>protocolProvider</tt>.
*
* @param protocolProvider
* @param contactHandler
* @param protocolProvider the <tt>ProtocolProviderService</tt>, which
* contacts should be handled by the given <tt>contactHandler</tt>
* @param contactHandler the <tt>ContactEventHandler</tt> that would handle
* events coming from the UI for any contacts belonging to the given
* provider
*/
public void addProviderContactHandler(
ProtocolProviderService protocolProvider,
@ -965,6 +1137,19 @@ public void addProviderContactHandler(
providerContactHandlers.put(protocolProvider, contactHandler);
}
/**
* Removes the <tt>ContactEventHandler</tt> corresponding to the given
* <tt>protocolProvider</tt>.
*
* @param protocolProvider the protocol provider, which contact handler
* we would like to remove
*/
public void removeProviderContactHandler(
ProtocolProviderService protocolProvider)
{
providerContactHandlers.remove(protocolProvider);
}
/**
* Returns the <tt>ContactEventHandler</tt> registered for this protocol
* provider.

@ -0,0 +1,83 @@
/*
* SIP Communicator, 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;
import java.util.*;
/**
* The <tt>UINotification</tt> class represents a notification received in the
* user interface. This could be a missed call, voicemail, email notification or
* any other notification.
*
* @author Yana Stamcheva
*/
public class UINotification
{
/**
* The parent notification group.
*/
private final UINotificationGroup parentGroup;
/**
* The name associated with this notification.
*/
private final String notificationName;
/**
* The time when the notification was received.
*/
private final Date notificationTime;
/**
* Creates an instance of <tt>UINotification</tt> by specifying the
* notification name and time.
*
* notification belongs
* @param displayName the name associated to this notification
* @param time the time when the notification was received
* @param parentGroup the group of notifications, to which this notification
* belongs
*/
public UINotification( String displayName,
Date time,
UINotificationGroup parentGroup)
{
this.notificationName = displayName;
this.notificationTime = time;
this.parentGroup = parentGroup;
}
/**
* Returns the name associated with this notification.
*
* @return the name associated with this notification
*/
public String getDisplayName()
{
return notificationName;
}
/**
* Returns the time the notification was received.
*
* @return the time the notification was received
*/
public Date getTime()
{
return notificationTime;
}
/**
* Returns the parent notification group.
*
* @return the parent notification group
*/
public UINotificationGroup getGroup()
{
return parentGroup;
}
}

@ -0,0 +1,114 @@
/*
* SIP Communicator, 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;
import java.util.*;
/**
* The <tt>UINotificationGroup</tt> class represents a group of notifications.
*
* @author Yana Stamcheva
*/
public class UINotificationGroup
{
/**
* A list of all unread notifications.
*/
private Collection<UINotification> unreadNotifications
= new ArrayList<UINotification>();
/**
* The name of the group to which this notification belongs.
*/
private final String groupName;
/**
* The display name of the group to which this notification belongs.
*/
private final String groupDisplayName;
/**
*
* @param groupName the name of the group to which this notification belongs
* @param groupDisplayName the display name of the group to which this
*/
public UINotificationGroup(String groupName, String groupDisplayName)
{
this.groupName = groupName;
this.groupDisplayName = groupDisplayName;
}
/**
* Returns the name of the group, to which this notification belongs.
*
* @return the name of the group, to which this notification belongs
*/
public String getGroupName()
{
return groupName;
}
/**
* Returns the display name of the group, to which this notification
* belongs.
*
* @return the display name of the group, to which this notification
* belongs
*/
public String getGroupDisplayName()
{
return groupDisplayName;
}
/**
* Adds the given notification to the list of unread notifications and
* notifies interested listeners.
*
* @param notification the <tt>UINotification</tt> to add
*/
public void addNotification(UINotification notification)
{
synchronized (unreadNotifications)
{
unreadNotifications.add(notification);
}
}
/**
* Removes all unread notifications.
*/
public void removeAllNotifications()
{
synchronized (unreadNotifications)
{
unreadNotifications.clear();
}
}
/**
* Returns a list of all unread notifications.
*
* @return a list of all unread notifications
*/
public Iterator<UINotification> getUnreadNotifications()
{
return new ArrayList<UINotification>(unreadNotifications).iterator();
}
/**
* Returns the count of unread notifications for this group.
*
* @return the count of unread notifications for this group
*/
public int getUnreadNotificationsCount()
{
synchronized (unreadNotifications)
{
return unreadNotifications.size();
}
}
}

@ -0,0 +1,24 @@
/*
* SIP Communicator, 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;
/**
* The <tt>UINotificationListener</tt> listens for new notifications received
* in the user interface. Notifications could be for example missed calls,
* voicemails or email messages.
*
* @author Yana Stamcheva
*/
public interface UINotificationListener
{
/**
* Indicates that a new notification is received.
*
* @param notification the notification that was received
*/
public void notificationReceived(UINotification notification);
}

@ -0,0 +1,142 @@
/*
* SIP Communicator, 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;
import java.util.*;
/**
* The <tt>UINotificationManager</tt> manages all notifications dedicated to
* be shown in the main application window. These could be missed calls, voice
* messages, etc.
*
* @author Yana Stamcheva
*/
public class UINotificationManager
{
/**
* The list of all notification groups.
*/
private static Collection<UINotificationGroup> notificationGroups
= new ArrayList<UINotificationGroup>();
/**
* Listener notified for changes in missed calls count.
*/
private static Collection<UINotificationListener> notificationListeners
= new ArrayList<UINotificationListener>();
/**
* Adds the given <tt>UINotificationListener</tt> to the list of listeners
* that would be notified on any changes in missed calls count.
*
* @param l the <tt>UINotificationListener</tt> to add
*/
public static void addNotificationListener(UINotificationListener l)
{
synchronized (l)
{
notificationListeners.add(l);
}
}
/**
* Removes the given <tt>UINotificationListener</tt> from the list of
* listeners that are notified on any changes in missed calls count.
*
* @param l the <tt>UINotificationListener</tt> to remove
*/
public static void removeNotificationListener(UINotificationListener l)
{
synchronized (l)
{
notificationListeners.remove(l);
}
}
/**
* Adds the given notification to the list of unread notifications and
* notifies interested listeners.
*
* @param notification the <tt>UINotification</tt> to add
*/
public static void addNotification(UINotification notification)
{
UINotificationGroup group = notification.getGroup();
if (!notificationGroups.contains(group))
notificationGroups.add(group);
group.addNotification(notification);
fireNotificationEvent(notification);
}
/**
* Removes all unread notifications.
*
* @param group removes all unread notifications for the given notification
* group
*/
public static void removeAllNotifications(UINotificationGroup group)
{
group.removeAllNotifications();
}
/**
* Removes all unread notifications from all notification groups.
*/
public static void removeAllNotifications()
{
Iterator<UINotificationGroup> groups = notificationGroups.iterator();
while (groups.hasNext())
{
groups.next().removeAllNotifications();
}
}
/**
* Returns a list of all unread notifications.
*
* @param group the notification group, which notification we're looking
* for
* @return a list of all unread notifications
*/
public static Iterator<UINotification> getUnreadNotifications(
UINotificationGroup group)
{
return group.getUnreadNotifications();
}
/**
* Returns a list of all notification groups.
*
* @return a list of all notification groups
*/
public static Collection<UINotificationGroup> getNotificationGroups()
{
return new ArrayList<UINotificationGroup>(notificationGroups);
}
/**
* Notifies interested <tt>UINotificationListener</tt> that a new
* notification has been received.
*
* @param notification the new notification
*/
private static void fireNotificationEvent(UINotification notification)
{
synchronized (notificationListeners)
{
Iterator<UINotificationListener> listeners
= notificationListeners.iterator();
while (listeners.hasNext())
listeners.next().notificationReceived(notification);
}
}
}

@ -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.impl.gui.utils.*;
import net.java.sip.communicator.util.*;
@ -27,7 +28,7 @@
*/
public class CallHistoryButton
extends SIPCommTextButton
implements MissedCallsListener,
implements UINotificationListener,
Skinnable
{
/**
@ -46,17 +47,10 @@ public class CallHistoryButton
private boolean isHistoryVisible = false;
/**
* Indicates if this button currently shows the number of missed calls or
* the just the history icon.
* Indicates if this button currently shows the number of unread
* notifications or the just the history icon.
*/
private boolean isMissedCallView = false;
/**
* The tool tip shown when there are missed calls.
*/
private final static String missedCallsToolTip
= GuiActivator.getResources().getI18NString(
"service.gui.MISSED_CALLS_TOOL_TIP");
private boolean isNotificationsView = false;
/**
* The tool tip shown by default over the history button.
@ -79,7 +73,7 @@ public CallHistoryButton()
{
super("");
CallManager.setMissedCallsListener(this);
UINotificationManager.addNotificationListener(this);
this.setPreferredSize(new Dimension(29, 22));
this.setForeground(Color.WHITE);
@ -95,7 +89,7 @@ public CallHistoryButton()
{
public void actionPerformed(ActionEvent e)
{
if (isHistoryVisible && !isMissedCallView)
if (isHistoryVisible && !isNotificationsView)
{
GuiActivator.getContactList()
.setDefaultFilter(TreeContactList.presenceFilter);
@ -109,7 +103,7 @@ public void actionPerformed(ActionEvent e)
.setDefaultFilter(TreeContactList.historyFilter);
GuiActivator.getContactList().applyDefaultFilter();
CallManager.clearMissedCalls();
UINotificationManager.removeAllNotifications();
isHistoryVisible = true;
}
@ -122,14 +116,18 @@ public void actionPerformed(ActionEvent e)
}
/**
* Indicates that missed calls count has changed.
* @param missedCalls the list of missed calls
* Indicates that a new notification is received.
*
* @param notification the notification that was received
*/
public void missedCallCountChanged(Collection<MissedCall> missedCalls)
public void notificationReceived(UINotification notification)
{
if (!missedCalls.isEmpty())
Collection<UINotificationGroup> notificationGroups
= UINotificationManager.getNotificationGroups();
if (!isHistoryVisible && notificationGroups.size() > 0)
{
setMissedCallsView(missedCalls);
setNotificationView(notificationGroups);
}
else
{
@ -145,7 +143,7 @@ public void missedCallCountChanged(Collection<MissedCall> missedCalls)
*/
private void setHistoryView()
{
isMissedCallView = false;
isNotificationsView = false;
if (isHistoryVisible)
{
@ -161,36 +159,53 @@ private void setHistoryView()
}
/**
* Sets the missed calls view of this button.
* @param missedCalls the list of missed calls
* Sets the notifications view of this button.
*
* @param notificationGroups the list of unread notification groups
*/
private void setMissedCallsView(Collection<MissedCall> missedCalls)
private void setNotificationView(
Collection<UINotificationGroup> notificationGroups)
{
isMissedCallView = true;
int notificationCount = 0;
isNotificationsView = true;
this.setBgImage(null);
String tooltipText = "<html><b>" + missedCallsToolTip + "</b><br/>";
Iterator<UINotificationGroup> groupsIter
= notificationGroups.iterator();
String tooltipText = "<html>";
int visibleCallCount = 5;
Iterator<MissedCall> callsIter = missedCalls.iterator();
while (callsIter.hasNext() && visibleCallCount > 0)
while (groupsIter.hasNext())
{
MissedCall missedCall = callsIter.next();
tooltipText += GuiUtils.formatTime(missedCall.getCallTime())
+ " "+ missedCall.getCallName() + "<br/>";
visibleCallCount--;
if (visibleCallCount == 0 && callsIter.hasNext())
tooltipText
+= GuiActivator.getResources()
UINotificationGroup group = groupsIter.next();
tooltipText += "<b>" + group.getGroupDisplayName() + "</b><br/>";
notificationCount += group.getUnreadNotificationsCount();
int visibleNotifsPerGroup = 5;
Iterator<UINotification> notifsIter = group.getUnreadNotifications();
while (notifsIter.hasNext() && visibleNotifsPerGroup > 0)
{
UINotification missedCall = notifsIter.next();
tooltipText += GuiUtils.formatTime(missedCall.getTime())
+ " " + missedCall.getDisplayName() + "<br/>";
visibleNotifsPerGroup--;
if (visibleNotifsPerGroup == 0 && notifsIter.hasNext())
tooltipText += GuiActivator.getResources()
.getI18NString("service.gui.MISSED_CALLS_MORE_TOOL_TIP",
new String[]{
new Integer(missedCalls.size() - 5).toString()});
new String[]{ new Integer(
notificationCount - 5).toString()});
}
}
this.setToolTipText(tooltipText + "</html>");
this.setBackground(new Color(200, 0, 0));
this.setText(new Integer(missedCalls.size()).toString());
this.setText(new Integer(notificationCount).toString());
}
/**

@ -14,6 +14,8 @@
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.main.contactlist.*;
import net.java.sip.communicator.impl.gui.utils.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.neomedia.device.*;
@ -44,17 +46,6 @@ public class CallManager
private static Hashtable<Call, CallDialog> activeCalls
= new Hashtable<Call, CallDialog>();
/**
* A list of the currently missed calls. Only the names of the first
* participant of each call is stored in the list.
*/
private static Collection<MissedCall> missedCalls;
/**
* Listener notified for changes in missed calls count.
*/
private static MissedCallsListener missedCallsListener;
/**
* The property indicating if the user should be warned when starting a
* desktop sharing session.
@ -63,6 +54,11 @@ public class CallManager
= "net.java.sip.communicator.impl.gui.main"
+ ".call.SHOW_DESKTOP_SHARING_WARNING";
/**
* The group of notifications dedicated to missed calls.
*/
private static UINotificationGroup missedCallGroup;
/**
* A call listener.
*/
@ -100,18 +96,34 @@ public void incomingCallReceived(CallEvent event)
@Override
public void callStateChanged(CallChangeEvent evt)
{
if (evt.getNewValue().equals(CallState.CALL_ENDED)
&& evt.getOldValue()
.equals(CallState.CALL_INITIALIZATION))
if (evt.getNewValue().equals(CallState.CALL_ENDED))
{
// if call was answered elsewhere, don't add it
// to missed calls
if(evt.getCause() == null
|| (evt.getCause().getReasonCode() !=
CallPeerChangeEvent.NORMAL_CALL_CLEARING))
addMissedCall(new MissedCall(peerName, callDate));
evt.getSourceCall().removeCallChangeListener(this);
if (evt.getOldValue()
.equals(CallState.CALL_INITIALIZATION))
{
// if call was answered elsewhere, don't add it
// to missed calls
if(evt.getCause() == null
|| (evt.getCause().getReasonCode() !=
CallPeerChangeEvent.NORMAL_CALL_CLEARING))
{
addMissedCallNotification(peerName, callDate);
}
evt.getSourceCall().removeCallChangeListener(this);
}
// If we're currently in the call history view refresh
// the view.
TreeContactList contactList
= GuiActivator.getContactList();
if (contactList.getCurrentFilter()
.equals(TreeContactList.historyFilter))
{
contactList.applyFilter(
TreeContactList.historyFilter);
}
}
}
});
@ -730,51 +742,6 @@ public static CallDialog getActiveCallDialog(Call call)
return activeCalls.get(call);
}
/**
* Sets the given <tt>MissedCallsListener</tt> that would be notified on
* any changes in missed calls count.
* @param l the listener to set
*/
public static void setMissedCallsListener(MissedCallsListener l)
{
missedCallsListener = l;
}
/**
* Adds a missed call.
* @param missedCall the missed call to add to the list of missed calls
*/
private static void addMissedCall(MissedCall missedCall)
{
if (missedCalls == null)
{
missedCalls = new LinkedList<MissedCall>();
}
missedCalls.add(missedCall);
fireMissedCallCountChangeEvent(missedCalls);
}
/**
* Clears the count of missed calls. Sets it to 0.
*/
public static void clearMissedCalls()
{
missedCalls = null;
}
/**
* Notifies interested <tt>MissedCallListener</tt> that the count has
* changed.
* @param missedCalls the new missed calls
*/
private static void fireMissedCallCountChangeEvent(
Collection<MissedCall> missedCalls)
{
if (missedCallsListener != null)
missedCallsListener.missedCallCountChanged(missedCalls);
}
/**
* Returns the image corresponding to the given <tt>peer</tt>.
*
@ -854,6 +821,27 @@ public void callStateChanged(CallChangeEvent evt)
}
}
/**
* Adds a missed call notification.
*
* @param peerName the name of the peer
* @param callDate the date of the call
*/
private static void addMissedCallNotification( String peerName,
Date callDate)
{
if (missedCallGroup == null)
missedCallGroup
= new UINotificationGroup("MissedCalls",
GuiActivator.getResources().getI18NString(
"service.gui.MISSED_CALLS_TOOL_TIP"));
UINotificationManager.addNotification(new UINotification(
peerName,
callDate,
missedCallGroup));
}
/**
* Creates a call from a given Contact or a given String.
*/

@ -1,52 +0,0 @@
/*
* SIP Communicator, 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.call;
import java.util.*;
/**
* The <tt>MissedCall</tt> class wraps a missed call in order to provide
* information about the call later.
*
* @author Yana Stamcheva
*/
public class MissedCall
{
private final String callName;
private final Date callTime;
/**
* Creates an instance of <tt>MissedCall</tt> by specifying the call name
* and time.
* @param callName the name associated to this call
* @param callTime the time of the missed call
*/
public MissedCall(String callName, Date callTime)
{
this.callName = callName;
this.callTime = callTime;
}
/**
* Returns the name associated with this call.
* @return the name associated with this call
*/
public String getCallName()
{
return callName;
}
/**
* Returns the time the call was made.
* @return the time the call was made
*/
public Date getCallTime()
{
return callTime;
}
}

@ -1,25 +0,0 @@
/*
* SIP Communicator, 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.call;
import java.util.*;
/**
* The <tt>MissedCallsListener</tt> listens for changes in the missed calls
* count. It is notified each time when a missed calls is registered by the
* <tt>CallManager</tt>.
*
* @author Yana Stamcheva
*/
public interface MissedCallsListener
{
/**
* Indicates the missed calls count has changed.
* @param missedCalls the new missed calls list
*/
public void missedCallCountChanged(Collection<MissedCall> missedCalls);
}

@ -10,6 +10,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.main.contactlist.notifsource.*;
import net.java.sip.communicator.service.contactsource.*;
/**
@ -22,14 +23,23 @@ public class CallHistoryFilter
{
/**
* Applies this filter and stores the result in the given <tt>treeModel</tt>.
*
* @param filterQuery the <tt>FilterQuery</tt> that tracks the results of
* this filtering
*/
public void applyFilter(FilterQuery filterQuery)
{
// First add all notifications.
NotificationContactSource notificationSource
= TreeContactList.getNotificationContactSource();
if (notificationSource != null)
addMatching(notificationSource);
Collection<ExternalContactSource> contactSources
= TreeContactList.getContactSources();
// Then add Call history contact source.
for (ExternalContactSource contactSource : contactSources)
{
ContactSourceService sourceService
@ -57,6 +67,7 @@ public void applyFilter(FilterQuery filterQuery)
/**
* Indicates if the given <tt>uiContact</tt> is matching this filter.
*
* @param uiContact the <tt>UIContact</tt> to check for match
* @return <tt>true</tt> if the given <tt>uiContact</tt> is matching this
* filter, <tt>false</tt> otherwise
@ -73,21 +84,33 @@ public boolean isMatching(UIContact uiContact)
.equals(ContactSourceService.CALL_HISTORY)))
return true;
}
else if (uiContact instanceof NotificationContact)
{
return true;
}
return false;
}
/**
* No group could match this filter.
*
* @param uiGroup the <tt>UIGroup</tt> to check for match
* @return <tt>false</tt> to indicate that no group could match this filter
*/
public boolean isMatching(UIGroup uiGroup)
{
if (uiGroup instanceof NotificationGroup)
{
return true;
}
return false;
}
/**
* Adds matching <tt>sourceContacts</tt> to the result tree model.
*
* @param sourceContacts the list of <tt>SourceContact</tt>s to add
* @param uiSource the <tt>ExternalContactSource</tt>, which contacts
* we're adding
@ -105,4 +128,31 @@ private void addMatching( List<SourceContact> sourceContacts,
false);
}
}
/**
* Adds matching notification contacts to the result tree model.
*
* @param notifSource
*/
private void addMatching(NotificationContactSource notifSource)
{
Iterator<? extends UIGroup> notifGroups
= notifSource.getNotificationGroups();
while (notifGroups.hasNext())
{
UIGroup uiGroup = notifGroups.next();
Iterator<? extends UIContact> notfications
= notifSource.getNotifications(uiGroup);
while (notfications.hasNext())
{
GuiActivator.getContactList()
.addContact(notfications.next(),
uiGroup,
false);
}
}
}
}

@ -176,7 +176,7 @@ public ContactListTreeCellRenderer()
loadSkin();
this.setOpaque(false);
this.setOpaque(true);
this.nameLabel.setOpaque(false);
this.displayDetailsLabel.setFont(getFont().deriveFont(9f));
@ -299,6 +299,26 @@ public Component getTreeCellRendererComponent(JTree tree, Object value,
DefaultTreeContactList contactList = (DefaultTreeContactList) tree;
// Set background color.
if (contactList instanceof TreeContactList)
{
ContactListFilter filter
= ((TreeContactList) contactList).getCurrentFilter();
if (filter != null
&& filter.equals(TreeContactList.historyFilter)
&& value instanceof ContactNode
&& row%2 == 0)
{
setBackground(Constants.CALL_HISTORY_EVEN_ROW_COLOR);
}
else
{
setBackground(Color.WHITE);
}
}
// Make appropriate adjustments for contact nodes and group nodes.
if (value instanceof ContactNode)
{
UIContact contact

@ -14,12 +14,10 @@
import javax.swing.event.*;
import javax.swing.tree.*;
import org.osgi.framework.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.*;
import net.java.sip.communicator.impl.gui.main.MainFrame.*;
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.impl.gui.utils.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.contactlist.event.*;
@ -29,6 +27,8 @@
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
import org.osgi.framework.*;
/**
* The <tt>TreeContactList</tt> is a contact list based on JTree.
*
@ -115,6 +115,8 @@ public class TreeContactList
private static final Collection<ExternalContactSource> contactSources
= new LinkedList<ExternalContactSource>();
private static NotificationContactSource notificationSource;
private FilterQuery currentFilterQuery;
private FilterThread filterThread;
@ -627,7 +629,9 @@ public void queryStatusChanged(ContactQueryStatusEvent event)
if (eventType == ContactQueryStatusEvent.QUERY_ERROR)
{
//TODO: Show the error to the user??
if (logger.isInfoEnabled())
logger.info("Contact query error occured: "
+ event.getQuerySource());
}
event.getQuerySource().removeContactQueryListener(this);
}
@ -758,7 +762,9 @@ public void run()
if (isSorted)
groupNode = parentNode.sortedAddContactGroup(group);
else
{
groupNode = parentNode.addContactGroup(group);
}
}
}
@ -875,6 +881,29 @@ public void run()
}
}
/**
* Indicates that the information corresponding to the given
* <tt>contact</tt> has changed.
*
* @param contact the contact that has changed
*/
public void refreshContact(final UIContact contact)
{
if (!SwingUtilities.isEventDispatchThread())
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
refreshContact(contact);
}
});
return;
}
treeModel.nodeChanged(contact.getContactNode());
}
/**
* Adds the given group to this list.
* @param group the <tt>UIGroup</tt> to add
@ -1715,6 +1744,19 @@ public static Collection<ExternalContactSource> getContactSources()
return contactSources;
}
/**
* Returns the notification contact source.
*
* @return the notification contact source
*/
public static NotificationContactSource getNotificationContactSource()
{
if (notificationSource == null)
notificationSource = new NotificationContactSource();
return notificationSource;
}
/**
* Returns the <tt>ExternalContactSource</tt> corresponding to the given
* <tt>ContactSourceService</tt>.

@ -24,12 +24,14 @@ 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();
@ -37,18 +39,21 @@ public interface UIContact
/**
* 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
@ -59,6 +64,7 @@ public interface UIContact
/**
* 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
*/
@ -67,18 +73,21 @@ public interface UIContact
/**
* Creates a tool tip for this contact. If such tooltip is
* provided it would be shown on mouse over over this <tt>UIContact</tt>.
*
* @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();
@ -86,6 +95,7 @@ public interface UIContact
/**
* Sets the given <tt>UIGroup</tt> to be the parent group of this
* <tt>UIContact</tt>.
*
* @param parentGroup the parent <tt>UIGroup</tt> of this contact
*/
public void setParentGroup(UIGroup parentGroup);
@ -93,6 +103,7 @@ public interface UIContact
/**
* Returns an <tt>Iterator</tt> over a list of the search strings of this
* contact.
*
* @return an <tt>Iterator</tt> over a list of the search strings of this
* contact
*/
@ -101,6 +112,7 @@ public interface UIContact
/**
* Returns the corresponding <tt>ContactNode</tt>. The <tt>ContactNode</tt>
* is the real node that is stored in the contact list component data model.
*
* @return the corresponding <tt>ContactNode</tt>
*/
public ContactNode getContactNode();
@ -108,6 +120,7 @@ public interface UIContact
/**
* Sets the given <tt>contactNode</tt>. The <tt>ContactNode</tt>
* is the real node that is stored in the contact list component data model.
*
* @param contactNode the <tt>ContactNode</tt> that corresponds to this
* <tt>UIGroup</tt>
*/
@ -116,6 +129,7 @@ public interface UIContact
/**
* Returns the default <tt>ContactDetail</tt> to use for any operations
* depending to the given <tt>OperationSet</tt> class.
*
* @param opSetClass the <tt>OperationSet</tt> class we're interested in
* @return the default <tt>ContactDetail</tt> to use for any operations
* depending to the given <tt>OperationSet</tt> class
@ -126,6 +140,7 @@ public UIContactDetail getDefaultContactDetail(
/**
* Returns a list of all <tt>UIContactDetail</tt>s corresponding to the
* given <tt>OperationSet</tt> class.
*
* @param opSetClass the <tt>OperationSet</tt> class we're looking for
* @return a list of all <tt>UIContactDetail</tt>s corresponding to the
* given <tt>OperationSet</tt> class

@ -18,6 +18,7 @@ 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();
@ -25,6 +26,7 @@ public interface UIGroup
/**
* 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();
@ -32,18 +34,21 @@ public interface UIGroup
/**
* 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 <tt>true</tt> to indicate that the group is collapsed,
* <tt>false</tt> to indicate that it's expanded
*/
@ -51,18 +56,21 @@ public interface UIGroup
/**
* 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();
@ -70,12 +78,14 @@ public interface UIGroup
/**
* Returns the <tt>GroupNode</tt> corresponding to this <tt>UIGroup</tt>.
* The is the actual node used in the contact list component data model.
*
* @return the <tt>GroupNode</tt> corresponding to this <tt>UIGroup</tt>
*/
public GroupNode getGroupNode();
/**
* Sets the <tt>GroupNode</tt> corresponding to this <tt>UIGroup</tt>.
*
* @param groupNode the <tt>GroupNode</tt> to set. The is the actual
* node used in the contact list component data model.
*/
@ -83,6 +93,7 @@ public interface UIGroup
/**
* Returns the right button menu for this group.
*
* @return the right button menu component for this group
*/
public JPopupMenu getRightButtonMenu();

@ -29,18 +29,20 @@ public class ExternalContactSource
/**
* Creates an <tt>ExternalContactSource</tt> based on the given
* <tt>ContactSourceService</tt>.
*
* @param contactSource the <tt>ContactSourceService</tt>, on which this
* <tt>ExternalContactSource</tt> is based
*/
public ExternalContactSource(ContactSourceService contactSource)
{
this.contactSource = contactSource;
sourceUIGroup
= new SourceUIGroup(contactSource.getDisplayName());
sourceUIGroup = new SourceUIGroup(contactSource.getDisplayName());
}
/**
* Returns the corresponding <tt>ContactSourceService</tt>.
*
* @return the corresponding <tt>ContactSourceService</tt>
*/
public ContactSourceService getContactSourceService()
@ -51,6 +53,7 @@ public ContactSourceService getContactSourceService()
/**
* Returns the UI group for this contact source. There's only one group
* descriptor per external source.
*
* @return the group descriptor
*/
public UIGroup getUIGroup()
@ -61,6 +64,7 @@ public UIGroup getUIGroup()
/**
* Returns the <tt>UIContact</tt> corresponding to the given
* <tt>sourceContact</tt>.
*
* @param sourceContact the <tt>SourceContact</tt>, for which we search a
* corresponding <tt>UIContact</tt>
* @return the <tt>UIContact</tt> corresponding to the given

@ -0,0 +1,456 @@
/*
* SIP Communicator, 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.notifsource;
import java.beans.*;
import java.util.*;
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.protocol.*;
import net.java.sip.communicator.service.protocol.OperationSetMessageWaiting.MessageType;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.service.resources.*;
/**
* The <tt>NotificationContact</tt> represents a notification entry shown in
* the contact list history view. It could represent a voice message entry,
* email notification or something else.
*
* @author Yana Stamcheva
*/
public class NotificationContact
implements UIContact,
RegistrationStateChangeListener,
ProviderPresenceStatusListener
{
/**
* The tip explaining to the user how to hear its voice messages.
*/
private static final String VOICEMAIL_TIP
= GuiActivator.getResources()
.getI18NString("service.gui.VOICEMAIL_TIP");
/**
* The parent contact list group.
*/
private NotificationGroup parentGroup;
/**
* The corresponding protocol provider.
*/
private final ProtocolProviderService protocolProvider;
/**
* The corresponding <tt>ContactNode</tt> in the contact list component
* data model.
*/
private ContactNode contactNode;
/**
* The notification detail.
*/
private UIContactDetail notificationDetail;
/**
* The count of unread messages attached to this notification.
*/
private int unreadMessageCount = 0;
/**
* The count of read messages attached to this notification.
*/
private int readMessageCount = 0;
/**
* Creates an instance of <tt>NotificationContact</tt> by specifying the
* parent group and the corresponding <tt>ProtocolProviderService</tt>.
*
* @param group the parent group
* @param protocolProvider the corresponding protocol provider
*/
public NotificationContact( NotificationGroup group,
ProtocolProviderService protocolProvider)
{
this.parentGroup = group;
this.protocolProvider = protocolProvider;
protocolProvider.addRegistrationStateChangeListener(this);
OperationSetPresence presenceOpSet
= protocolProvider.getOperationSet(OperationSetPresence.class);
if (presenceOpSet != null)
presenceOpSet.addProviderPresenceStatusListener(this);
}
/**
* Returns the descriptor of this contact.
*
* @return the descriptor of this contact
*/
public Object getDescriptor()
{
return protocolProvider;
}
/**
* Returns the display name of this contact.
*
* @return the display name of this contact
*/
public String getDisplayName()
{
return protocolProvider.getAccountID().getAccountAddress();
}
/**
* Returns the display details of this contact. These would be shown
* whenever the contact is selected. In the <tt>NotificationContact</tt>
* these contain information about unread and read messages.
*
* @return the display details of this contact
*/
public String getDisplayDetails()
{
String displayDetails;
ResourceManagementService resources = GuiActivator.getResources();
if (unreadMessageCount > 0 && readMessageCount > 0)
{
displayDetails = resources.getI18NString(
"service.gui.VOICEMAIL_NEW_OLD_RECEIVED",
new String[]{ Integer.toString(unreadMessageCount),
Integer.toString(readMessageCount)});
}
else if (unreadMessageCount > 0)
{
displayDetails = resources.getI18NString(
"service.gui.VOICEMAIL_NEW_RECEIVED",
new String[]{ Integer.toString(unreadMessageCount)});
}
else if (readMessageCount > 0)
{
displayDetails = resources.getI18NString(
"service.gui.VOICEMAIL_OLD_RECEIVED",
new String[]{ Integer.toString(readMessageCount)});
}
else
{
displayDetails = resources.getI18NString(
"service.gui.VOICEMAIL_NO_MESSAGES");
}
return displayDetails;
}
/**
* Returns the index of this contact in its source.
*
* @return the source index
*/
public int getSourceIndex()
{
return 0;
}
/**
* Returns the icon indicating that this is a notification 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)
{
ImageIcon avatarIcon = null;
if (parentGroup.getMessageType().equals(MessageType.VOICE))
{
avatarIcon = GuiActivator.getResources().getImage(
"service.gui.icons.VOICEMAIL");
}
return avatarIcon;
}
/**
* 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()
{
OperationSetPresence presence = protocolProvider
.getOperationSet(OperationSetPresence.class);
if (presence != null)
{
return new ImageIcon(
Constants.getStatusIcon(presence.getPresenceStatus()));
}
else if (protocolProvider.isRegistered())
{
return new ImageIcon(
Constants.getStatusIcon(Constants.ONLINE_STATUS));
}
return new ImageIcon(
Constants.getStatusIcon(Constants.OFFLINE_STATUS));
}
/**
* Creates a tool tip for this contact. If such tooltip is
* provided it would be shown on mouse over over this <tt>UIContact</tt>.
*
* @return the tool tip for this contact descriptor
*/
/**
* Returns the tool tip opened on mouse over.
* @return the tool tip opened on mouse over
*/
public ExtendedTooltip getToolTip()
{
ExtendedTooltip tip = new ExtendedTooltip(true);
ImageIcon avatarImage = getAvatar(true, 64, 64);
if (avatarImage != null)
tip.setImage(avatarImage);
tip.setTitle(getDisplayName());
tip.addLine(null, getDisplayDetails());
tip.setBottomText(VOICEMAIL_TIP);
return tip;
}
/**
* Returns null to indicate that no right button menu is provided for this
* contact.
*
* @return null
*/
public JPopupMenu getRightButtonMenu()
{
return null;
}
/**
* Returns the parent group.
*
* @return the parent group
*/
public UIGroup getParentGroup()
{
return parentGroup;
}
/**
* Sets the given <tt>UIGroup</tt> to be the parent group of this
* <tt>UIContact</tt>.
*
* @param parentGroup the parent <tt>UIGroup</tt> of this contact
*/
public void setParentGroup(UIGroup parentGroup)
{
if (!(parentGroup instanceof NotificationGroup))
return;
this.parentGroup = (NotificationGroup) parentGroup;
}
/**
* No search strings are provided for this contact.
*
* @return null
*/
public Iterator<String> getSearchStrings()
{
return null;
}
/**
* Returns the corresponding <tt>ContactNode</tt>. The <tt>ContactNode</tt>
* is the real node that is stored in the contact list component data model.
*
* @return the corresponding <tt>ContactNode</tt>
*/
public ContactNode getContactNode()
{
return contactNode;
}
/**
* Sets the given <tt>contactNode</tt>. The <tt>ContactNode</tt>
* is the real node that is stored in the contact list component data model.
*
* @param contactNode the <tt>ContactNode</tt> that corresponds to this
* <tt>UIGroup</tt>
*/
public void setContactNode(ContactNode contactNode)
{
this.contactNode = contactNode;
}
/**
* Returns the default <tt>ContactDetail</tt> to use for any operations
* depending to the given <tt>OperationSet</tt> class.
*
* @param opSetClass the <tt>OperationSet</tt> class we're interested in
* @return the default <tt>ContactDetail</tt> to use for any operations
* depending to the given <tt>OperationSet</tt> class
*/
public UIContactDetail getDefaultContactDetail(
Class<? extends OperationSet> opSetClass)
{
if (opSetClass.equals(OperationSetBasicTelephony.class))
return notificationDetail;
return null;
}
/**
* Returns a list of <tt>UIContactDetail</tt>s supporting the given
* <tt>OperationSet</tt> class.
*
* @param opSetClass the <tt>OperationSet</tt> class we're interested in
* @return a list of <tt>UIContactDetail</tt>s supporting the given
* <tt>OperationSet</tt> class
*/
public List<UIContactDetail> getContactDetailsForOperationSet(
Class<? extends OperationSet> opSetClass)
{
List<UIContactDetail> resultList = new LinkedList<UIContactDetail>();
if (opSetClass.equals(OperationSetBasicTelephony.class))
resultList.add(notificationDetail);
return resultList;
}
/**
* Sets the corresponding message account.
*
* @param messageAccount the message account corresponding to the contained
* notification
*/
public void setMessageAccount(String messageAccount)
{
notificationDetail
= new MessageWaitingDetail(protocolProvider, messageAccount);
}
/**
* Sets the number of unread messages, this notification is about.
*
* @param count the number of unread messages, this notification is about
*/
public void setUnreadMessageCount(int count)
{
this.unreadMessageCount = count;
}
/**
* Returns the number of unread messages, this notification is about.
*
* @return the number of unread messages, this notification is about
*/
public int getUnreadMessageCount()
{
return unreadMessageCount;
}
/**
* Sets the number of read messages, this notification is about.
*
* @param count the number of read messages, this notification is about
*/
public void setReadMessageCount(int count)
{
this.readMessageCount = count;
}
/**
* The implementation of the <tt>UIContactDetail</tt> interface for the
* external source <tt>ContactDetail</tt>s.
*/
private class MessageWaitingDetail
extends UIContactDetail
{
/**
* Creates an instance of <tt>SourceContactDetail</tt> by specifying
* the underlying <tt>detail</tt> and the <tt>OperationSet</tt> class
* for it.
*
* @param protocolProvider the protocol provider corresponding to this
* detail
* @param messageAccount the message account corresponding to this
* detail
*/
public MessageWaitingDetail(ProtocolProviderService protocolProvider,
String messageAccount)
{
super( messageAccount,
messageAccount,
protocolProvider,
protocolProvider.getProtocolName());
}
/**
* Returns null to indicate that this detail doesn't support presence.
* @return null
*/
public PresenceStatus getPresenceStatus()
{
return null;
}
}
/**
* Refresh the notification contact corresponding the the attached provider
* in order to better reflect its state.
*
* @param evt the <tt>ProviderPresenceStatusChangeEvent</tt> that has
* notified us of the state change
*/
public void registrationStateChanged(RegistrationStateChangeEvent evt)
{
RegistrationState newState = evt.getNewState();
if (newState.equals(RegistrationState.UNREGISTERED)
|| newState.equals(RegistrationState.REGISTERED))
{
TreeContactList contactList = GuiActivator.getContactList();
contactList.refreshContact(this);
}
}
/**
* Refresh the notification contact corresponding the the attached provider
* in order to better reflect its status.
*
* @param evt the <tt>ProviderPresenceStatusChangeEvent</tt> that has
* notified us of the status change
*/
public void providerStatusChanged(ProviderPresenceStatusChangeEvent evt)
{
TreeContactList contactList = GuiActivator.getContactList();
contactList.refreshContact(this);
}
public void providerStatusMessageChanged(PropertyChangeEvent evt) {}
}

@ -0,0 +1,86 @@
/*
* SIP Communicator, 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.notifsource;
import java.util.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.contactlist.*;
import net.java.sip.communicator.service.protocol.OperationSetMessageWaiting.MessageType;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
/**
* The <tt>NotificationContactSource</tt> represents a contact source that would
* listen for message waiting notifications and would display them in the
* history view of the contact list.
*
* @author Yana Stamcheva
*/
public class NotificationContactSource
implements MessageWaitingListener
{
/**
* A mapping attaching to each <tt>NotificationGroup</tt> the
* corresponding <tt>MessageType</tt>, for which notifications
* are received.
*/
private final Hashtable<MessageType, NotificationGroup> groups
= new Hashtable<MessageType, NotificationGroup>();
/**
* Adds the received waiting message to the corresponding group and contact.
* Also adds it the <tt>UINotificationManager</tt> that would take care of
* notifying the user.
*
* @param evt the notification event.
*/
public void messageWaitingNotify(MessageWaitingEvent evt)
{
MessageType type = evt.getMessageType();
NotificationGroup group = groups.get(type);
if (group == null)
{
group = new NotificationGroup(type);
groups.put(type, group);
}
group.messageWaitingNotify(evt);
}
/**
* Returns an <tt>Iterator</tt> over a list of all notification groups
* contained in this source.
*
* @return an <tt>Iterator</tt> over a list of all notification groups
* contained in this source
*/
public Iterator<? extends UIGroup> getNotificationGroups()
{
return groups.values().iterator();
}
/**
* Returns an <tt>Iterator</tt> over a list of all notification contacts
* contained in the given group.
*
* @param group the group, which notification contacts we're looking for
* @return an <tt>Iterator</tt> over a list of all notification contacts
* contained in the given group
*/
public Iterator<? extends UIContact> getNotifications(UIGroup group)
{
if (!(group instanceof NotificationGroup))
return null;
NotificationGroup notifGroup = (NotificationGroup) group;
return notifGroup.getNotifications();
}
}

@ -0,0 +1,262 @@
/*
* SIP Communicator, 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.notifsource;
import java.util.*;
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.protocol.OperationSetMessageWaiting.MessageType;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
/**
* The <tt>NotificationGroup</tt> represents a group of notification entries
* shown in the contact list history view. It could represent the voice
* messages,.emails, etc.
*
* @author Yana Stamcheva
*/
public class NotificationGroup
implements UIGroup
{
/**
* The type of the notification message, identifying this group.
*/
private final MessageType type;
/**
* The corresponding group node in the contact list component.
*/
private GroupNode groupNode;
/**
* A mapping attaching to each <tt>NotificationContact</tt> the
* corresponding <tt>ProtocolProviderService</tt>, for which notifications
* are received.
*/
private final Hashtable<ProtocolProviderService, NotificationContact>
contacts
= new Hashtable<ProtocolProviderService, NotificationContact>();
/**
* The group of UI notifications.
*/
private static UINotificationGroup uiNotificationGroup;
/**
* Creates an instance of <tt>NotificationGroup</tt> by specifying the
* message type.
*
* @param type the type of messages that this group would contain
*/
public NotificationGroup(MessageType type)
{
this.type = type;
}
/**
* 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()
{
return type;
}
/**
* 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()
{
String displayName;
if (type.equals(MessageType.VOICE))
displayName = GuiActivator.getResources()
.getI18NString("service.gui.VOICEMAIL_TITLE");
else
displayName = type.toString();
return displayName;
}
/**
* 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()
{
return 0;
}
/**
* Returns null to indicate that the parent group is the root group.
*
* @return null
*/
public UIGroup getParentGroup()
{
return null;
}
/**
* Returns <tt>false</tt> to indicate that this group is never collapsed.
*
* @return <tt>false</tt>
*/
public boolean isGroupCollapsed()
{
return false;
}
/**
* Returns the count of online child contacts.
*
* @return the count of online child contacts
*/
public int countOnlineChildContacts()
{
return contacts.size();
}
/**
* Returns the child contacts count.
*
* @return child contacts count
*/
public int countChildContacts()
{
return contacts.size();
}
/**
* Returns the identifier of this group.
*
* @return the identifier of this group
*/
public String getId()
{
return null;
}
/**
* Returns the <tt>GroupNode</tt> corresponding to this <tt>UIGroup</tt>.
* The is the actual node used in the contact list component data model.
*
* @return the <tt>GroupNode</tt> corresponding to this <tt>UIGroup</tt>
*/
public GroupNode getGroupNode()
{
return groupNode;
}
/**
* Sets the <tt>GroupNode</tt> corresponding to this <tt>UIGroup</tt>.
*
* @param groupNode the <tt>GroupNode</tt> to set. The is the actual
* node used in the contact list component data model.
*/
public void setGroupNode(GroupNode groupNode)
{
this.groupNode = groupNode;
}
/**
* Returns null to indicate that there's no right button menu provided for
* this group.
*
* @return null
*/
public JPopupMenu getRightButtonMenu()
{
return null;
}
/**
* Returns an <tt>Iterator</tt> over a list of all notification contacts
* contained in this group.
*
* @return an <tt>Iterator</tt> over a list of all notification contacts
* contained in this group
*/
public Iterator<? extends UIContact> getNotifications()
{
return contacts.values().iterator();
}
/**
* Returns the message type indicating the identity of this group.
*
* @return the message type corresponding to this group
*/
public MessageType getMessageType()
{
return type;
}
/**
* Creates all necessary notification contacts coming from the given
* <tt>MessageWaitingEvent</tt>.
*
* @param event the <tt>MessageWaitingEvent</tt> that notified us
*/
public void messageWaitingNotify(MessageWaitingEvent event)
{
ProtocolProviderService protocolProvider = event.getSourceProvider();
NotificationContact contact = contacts.get(protocolProvider);
TreeContactList contactList = GuiActivator.getContactList();
boolean isNew = false;
if (contact == null)
{
contact = new NotificationContact(this, protocolProvider);
contacts.put(protocolProvider, contact);
isNew = true;
}
contact.setMessageAccount(event.getAccount());
contact.setUnreadMessageCount(event.getUnreadMessages());
contact.setReadMessageCount(event.getReadMessages());
if (contactList.getCurrentFilter().isMatching(contact))
{
if (isNew)
contactList.addContact(contact, this, true);
else
contactList.refreshContact(contact);
}
if (contact.getUnreadMessageCount() > 0)
{
if (uiNotificationGroup == null)
uiNotificationGroup
= new UINotificationGroup(
getDisplayName(),
GuiActivator.getResources()
.getI18NString("service.gui.VOICEMAIL_TOOLTIP"));
UINotificationManager.addNotification(
new UINotification(
contact.getDisplayName()
+ " : " + contact.getDisplayDetails() ,
new Date(),
uiNotificationGroup));
}
}
}

@ -76,20 +76,11 @@ public class Constants
* ======================================================================
*/
/**
* The color used to paint the background of an incoming call history
* record.
* Background color for even records in call history.
*/
public static Color HISTORY_IN_CALL_COLOR
public static Color CALL_HISTORY_EVEN_ROW_COLOR
= new Color(GuiActivator.getResources().
getColor("service.gui.HISTORY_INCOMING_CALL_BACKGROUND"));
/**
* The color used to paint the background of an outgoing call history
* record.
*/
public static Color HISTORY_OUT_CALL_COLOR
= new Color(GuiActivator.getResources().
getColor("service.gui.HISTORY_OUTGOING_CALL_BACKGROUND"));
getColor("service.gui.CALL_HISTORY_EVEN_ROW_COLOR"));
/**
* The end color used to paint a gradient selected background of some
@ -414,13 +405,9 @@ public static void loadSimpleStyle(StyleSheet styleSheet, Font defaultFont)
*/
public static void reload()
{
HISTORY_IN_CALL_COLOR
= new Color(GuiActivator.getResources().
getColor("service.gui.HISTORY_INCOMING_CALL_BACKGROUND"));
HISTORY_OUT_CALL_COLOR
CALL_HISTORY_EVEN_ROW_COLOR
= new Color(GuiActivator.getResources().
getColor("service.gui.HISTORY_OUTGOING_CALL_BACKGROUND"));
getColor("service.gui.CALL_HISTORY_EVEN_ROW_COLOR"));
SELECTED_COLOR
= new Color(GuiActivator.getResources().

@ -43,7 +43,8 @@ private MessageType(String type)
}
/**
* Returns the type ot the message type enum element.
* Returns the type of the message type enum element.
*
* @return the message type.
*/
public String toString()
@ -53,6 +54,7 @@ public String toString()
/**
* Returns MessageType by its type name.
*
* @param type the type.
* @return the corresponding MessageType.
*/

@ -81,6 +81,16 @@ public MessageWaitingEvent(
this.readUrgentMessages = readUrgentMessages;
}
/**
* Returns the <tt>ProtocolProviderService</tt> which originated this event.
*
* @return the source <tt>ProtocolProviderService</tt>
*/
public ProtocolProviderService getSourceProvider()
{
return (ProtocolProviderService) getSource();
}
/**
* The URI we can use to reach messages from provider that is firing
* the event.

@ -14,7 +14,8 @@
public interface MessageWaitingListener
{
/**
* Notifies for new messages that are waiting.
* Notifies for new messages that are waiting.
*
* @param evt the notification event.
*/
public void messageWaitingNotify(MessageWaitingEvent evt);

Loading…
Cancel
Save