From 1d0246a99713e7c4ca5ddcbffd78e17f33098df6 Mon Sep 17 00:00:00 2001 From: Yana Stamcheva Date: Tue, 9 Nov 2010 22:41:44 +0000 Subject: [PATCH] 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. --- resources/colors/colors.properties | 7 +- resources/images/images.properties | 1 + .../images/impl/gui/common/incomingCall.png | Bin 1024 -> 965 bytes .../images/impl/gui/common/missedCall.png | Bin 1234 -> 1108 bytes .../images/impl/gui/common/outgoingCall.png | Bin 1186 -> 1095 bytes .../images/impl/gui/common/voicemail.png | Bin 0 -> 1013 bytes resources/languages/resources.properties | 9 +- .../communicator/impl/gui/main/MainFrame.java | 229 ++++++++- .../impl/gui/main/UINotification.java | 83 ++++ .../impl/gui/main/UINotificationGroup.java | 114 +++++ .../impl/gui/main/UINotificationListener.java | 24 + .../impl/gui/main/UINotificationManager.java | 142 ++++++ .../impl/gui/main/call/CallHistoryButton.java | 93 ++-- .../impl/gui/main/call/CallManager.java | 122 +++-- .../impl/gui/main/call/MissedCall.java | 52 -- .../gui/main/call/MissedCallsListener.java | 25 - .../main/contactlist/CallHistoryFilter.java | 50 ++ .../ContactListTreeCellRenderer.java | 22 +- .../gui/main/contactlist/TreeContactList.java | 50 +- .../impl/gui/main/contactlist/UIContact.java | 15 + .../impl/gui/main/contactlist/UIGroup.java | 11 + .../contactsource/ExternalContactSource.java | 8 +- .../notifsource/NotificationContact.java | 456 ++++++++++++++++++ .../NotificationContactSource.java | 86 ++++ .../notifsource/NotificationGroup.java | 262 ++++++++++ .../impl/gui/utils/Constants.java | 23 +- .../protocol/OperationSetMessageWaiting.java | 4 +- .../protocol/event/MessageWaitingEvent.java | 10 + .../event/MessageWaitingListener.java | 3 +- 29 files changed, 1663 insertions(+), 238 deletions(-) create mode 100644 resources/images/impl/gui/common/voicemail.png create mode 100644 src/net/java/sip/communicator/impl/gui/main/UINotification.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/UINotificationGroup.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/UINotificationListener.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/UINotificationManager.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/call/MissedCall.java delete mode 100644 src/net/java/sip/communicator/impl/gui/main/call/MissedCallsListener.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContact.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContactSource.java create mode 100644 src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationGroup.java diff --git a/resources/colors/colors.properties b/resources/colors/colors.properties index 214bf1cf3..f4eb28413 100644 --- a/resources/colors/colors.properties +++ b/resources/colors/colors.properties @@ -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 diff --git a/resources/images/images.properties b/resources/images/images.properties index e67420a58..444228d7a 100644 --- a/resources/images/images.properties +++ b/resources/images/images.properties @@ -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 diff --git a/resources/images/impl/gui/common/incomingCall.png b/resources/images/impl/gui/common/incomingCall.png index 85f68886d46d22eb4bd7b63ce64317bdaeff8797..bbcc12cee8ed788ac51099fbf25a31a2b2fbc961 100644 GIT binary patch delta 918 zcmV;H18Mw#2*n2>iBL{Q4GJ0x0000DNk~Le0000M0000M2nGNE0K~LxJCPw83ku)> z01Ds%3%Ddwkwz$gLPLmA`KsMHq&kZ+Gu5XAWb_PHc<`0YQ@@N_28z2~HeH zNEA3C5)H9LPv!rCk^<8}L4_1IDN>|CqTnQ_aABN|C<3`iMDQiCjeWkmy&pUCQtbKU zbIx`oK53-gcfNUc=G&QfOcKK)u9QZBd0-AG_8P!OudM@rYx(kOZP<7l297JG1%m94 zLE+Lgxd|-$DnuiwTSKj9(B73g`_OGvfv@xB)w`#H<4S29Shm7Di{b2NW>FR;4dj~O znvgV=KDWTdsQDB%t3rMSSjv}I|9t@*S4!gq+56G#^^3veoTY%q>EI-WZXLzXg=;?s ziihyv$n2MYqf1}D6;6F*gYxh&eEJYXSZ)j~ya+5G_6LVG4aTo7rqHt^u!PL`e3_sJWf==aA`Z5xZv7pQ79wfCmx~$knhQIzETF2q*@HcL!8!KQbf61#b!^MEb{U z<_3hXr3vz2hMxa|dv;GQ-amdAiV+qTgTmV;-|DNv!{imholTSWv6(NxUg-e=6WY2% zvh%=y`)>Of(*PAC%N*z(>Fw*yGG+lK0!0~ux> zS%6san+2@$vD>q zr~+#yiMUc)u>8!O?3Hgqd`HxOM{W;%%S>G)hnWXS>eNV*bLyLrYk_M?orCn`!Hs-* z_3lx3`#F65lf`KEb35%wzu<1JmFn>}$gkwft6#yOjV-yYUmtZhe-cUkrHe@tOYsg} z$Ug>_4&^?$=c7fxd;eDF!MEP;{c-Xp1(1VgRcby3xfPChF`RZa!4HJ_X*+k`EH?(3 s0wfL8+D4syrS;UyT}{W}|LZdS4{i_dzlMJgJOBUy07*qoM6N<$g2xc9^Z)<= delta 978 zcmV;@11a|4Hy#<^#&aQ z*FEC&GoXTM6I>3%=YUzJ7yfG11G})!6rQ*f)O{PP1@2?#;66CVF$XujnJdzJ%srSZ z*HC{6dP@e+)QlVQ!*^~0Ujy*cb$Q}$z!f-m0~tL31*QQkz1ul*3B@XGFIp}DZiiYk z7`ZA>%$_cP%sGS+=uWCW$(x~e5d6yLsy{eASS-?bHioma0M`OAciM`G+MCPV!{ z<>G!-0e=6FOV*EO&-6Y1Ojezx^(9^jiU`5){ zK*JP&?0b$;GQRXa3KymAWpU&z6(BpeHzZ=SbW5afxW-!@!;}-5*0A-kfhN1o6VELY{ zwWQYxU8SYO21k2t#k?XwWhL3TD-uQx?}h&VoMSHo(3N4{MHeN#)vZz#q8JN>B-upb97qTbBPeapy!ZU?~9exP<(V zBQMVvb&x~ad;snPu>Grvz5f#iaKEWbzXxXAx&Ylbl0c^qn`3(6MjeOD0&^ AeE z01Ds%3%Ddwkwzzf1JOxDK~y-6rIkx)TxAr;f9JdRP9~FQ)0re~?DRpbRBF2zx+qx~ za4Ckiq983|SH2dF;=%`lShG=)fKXkjpxFot7F-I0R3d~_iUny&YMP|&v`IRXx%0fQ z<04I)vC~-az}b9{-*-6YeE%b=N;AtQlAXX|;1H0x;{eltcYF$%9Ih-Eo86aY;A|o} zV&W}dv>({l9~FvSpYA0B^O?B=X-t}ARNMxdj++Kd|q_ z!0RuGX^#`SE@7!e=(+@@l7?=Xu(amYnFXqs=T(Dn0vH{xEa&e7XA{XSCf;&>;MJ4q ztxrECVc8{rD7l-0L${27dzISEH4V$vc_6b6HyffK-}&~boqaDH6EV^>?;9E={^9W zx<`FBCxh?4ht<`I1_7WLl>FrHL|$#J1MX1{*+8cK;1dneRj)1(-`X#JZb_pcz+WuL z;Mj+M7~4UE5LD49V&SW=$^UjP($K%xvm&6HF=E@9w#Of9h**P2dY^liSaOHp8QJr} z`$(bq!YrVTLdUbxu! zn&W_NAtGyVW2nx|a`p3ZwK|;Us@1?<15dfre>5JpZNyk0vIZBSWneqTb~a^lPj{va zFuDBG&o|uj7w)dsuji;-x{P=87D1svRHpR#wC+t49~{t@bV{AR?)!4AVMI_U z0ZgoG^TyJS=Dz*@>g+ooX;5f76q;IYuv*sITn-JRd0=#X{Vw>9j%M<|{QBKrCr6{g zxv5R7uR%!V(!5qL&!c`Y!3HgcO-2)N#_DM6kEgdwY+DMur;DIaq`r6qKewWOp$L&a h+-Uk2{C^G8e*lP|?-5*nukZi>002ovPDHLkV1h{62L}KE delta 1190 zcmV;X1X=sk2+|25iBL{Q4GJ0x0000DNk~Le0000S0000S2nGNE0CElAl#wAC3k)0p z01O-fw!9h%kwzzf1W!psK~zYIwbo5&R96(h@&CE=-Xvxc&5+o}Xp&K}L4|^L(XDjT zO%{SsgxW<>iqu-AsCCy}Td<`Rx7JllyAfJ&TeKS&g$9dQYiraH(@Knq`I?z~?|b)j zF(1h|mO80kc)Z~;@Z)@N&k|1LsXe;=l^0|^0DMKvG+R24Kp(E4vxg`f~p{Okhi{Yv~IaA;3)dOE6psAC=5 zwlHwwsOj9X4YD!n$^`2OwoGsit-YNkSW9Xh!CBNg)LISR5y}=n^^oHA+bmwcrKpZn zjlFVdP0xOR;A?=s18>N{$)g5M3D)XrFtv_g9jUdb^SHksFn8rwRqFu`m}<@Fe0iq~ zo<8EoDI-zo|^k)PR z=hwB~jke6v)myUZ&9@}Cb31As_UwJJGm}at(|`r*(GUPI0Gg&PVaehmi&w|YmQyFC z^Oao?M@TlNaO5yX+f67I8!_iponHZl@YI-}nZ=Gxnc+`9rfp~li84qgf;dLn+SqjP zZIYRPqO8P%^#qqJr<9O3VbeeSC~;q}wr|~7$L!>kND|BN=Vy>?3~7o2q5#U`?{~QS z*%wOI=t@kjtKU2kKnQ75WSOpYWY?`1JN}o(`7SMuO-M)KB^h}4Fc^cTm6`~k3Nx2} z;@JpYvrYk_w(9|F%n?=Mx6pl z!fGiUclRF>%C>QMT1Rjm5|4(;W~as=8Bq z01Ds%3%Ddwkwzzf1H?&0K~y-6rIpWXTvZguKli@(lF8&plcq`2rp;IviiOh1P&IB0 zf`TpzR>VS!0l|fJQ&)we^-nOX>e8qIQ4uUyr65Ks1c@mTMcc&wNSY?oq)8^3_h#PA zd-om}Gm|FmG!;B>H|L)Fx%Yj~<9n2dP%DxHBP~E5a0p0$R~Eo{WsL!&`Jw)`TIW?Q zaB^VeaKh6c9q37Pb#Hg+XwkGL6-$21jm3!h6(gCfVI{B`;6#3?|J;_~`$0aU{qKee4I-BPdiB=xdkG^;Sh5r%!_B24 z-%s3ObZWsABUs7_VMGSluYtZ-p6b}StId0$0FG9O1oFeg9TJ|VG2zhC;8O2t)(Qr< zB50kf0J?xa4IDby)A&$T7gn|EeWV%JQMg*+ISQp9HWsBS$L~@Oxj_10s_B8i*a*{$ zTD^CFME61c(6a1%>VsEPXa&ZCXdx(C z@?jYm3sQrec4H$HB8#IpL+4i_n(CX?v6ng#z*s>LRs+MCFDF?EO7hw>-O9w9UtA3h zjQ=s?Z@TrbTSaiXp{A^eDd?G6iWAi%cOA)jQ>9E zujhZA3V3|iHgz!7i~>|e%fIJ*&U}4EI$LA$oN{fQ7fH!PazD2W9vi=&Ti@KX!((zT zPbrr5!i$%)oV{>O_H`m^!~dfdR4)P8;5%a)82$FQrTI(O%W`zL)#2z!&QB~7#g=b> z#uoT)VpjHb-qVB{5tjR(0Y-IxsDI6hoOt)sYc`B50FUjiXEL)Y?|=0VQ<*!G+Tm=0 zy9nRf*ULlXJ05 z&Kn}bFdMuWwir#o+2#h_wYS|CFTINY UrM4t>bpQYW07*qoM6N<$f@~uCg#Z8m delta 1142 zcmV-+1d02{2%-rgiBL{Q4GJ0x0000DNk~Le0000S0000S2nGNE0CElAl#wAC3k(YY z01OKOt?aD4kwzzf1RqI6K~zYIz1B-;TvZsr@&9+{&dboq6j~IqabZzgh_r%;HX^vH zE_9;{QxHLl(00`>T)J=}6j!ZKTLcxd)fNOrL|e14+7fHPT2m=Z?ITHJW+u%fbI@Xn3 ze9Z99tunZI0~<>PvEE~?$2zCRIjr><=P)*4eR`ibpWZu%wSk6l%v2M~*XQ-(<#|+5 zRQ8UI>^>rY+g>|7fW+s4!sZ9p^Y$B0MeFLU$Rye|TVfb8(jt#YR^>paH7J%w0G{n;!q6gRVx!Oa_1 zg&E_StSpjdNwk1KFOy0 z?nR_CMFo6N5@VNRHne9Lw`bUexh|~Uu*}vX+574aO6v-UNV7pg2oQ-9g3_>VIpzY! zE{UNk|BBV-Eene|Ik0Pp(z+rdf&e0d_sTbaKV70WpQK>obS2hW(x|l*|AbA?CgkIF za$wgEiussGKmbH=KJejZXBheNtiE&fJB;-#CUzNSoZ^?pFio1?*tHu8j|@B@uROms z4V5Y?=`tGQIQYpZ<*6G%C2;k|tRDUROtjdrJ+Tgm_QcB96M5n3Ej;u1CVXp8YL2;o zdcwOOouo2X4PKk6?*r#1t_BTAFRYWLN*A_}IEuME&u$+eC`2LsV=BUx$r=Yg{azPL zU0c|Sm}xI;N#Sc(ooNUpenF2NKT9N}p9p@waE0&*iD95JKqgAZx$?6QPWUpv+X0Wtg$c_cQ+`x4v#x_J?fSQkr6;)22;3pSU%Wiebj92)48Vgs6pfASDWkGq6&;_b>P*!==v}}x zJ)7<+_dE!f`m@=-LWWF6+8JzpGn1Q*cn!00004b3#c}2nYxW zd6~-+ zZTT=4OMP;~V(-Ob|Lb3C{VXLS0L0UUSAm1TE+EVQI}P9*FqNGso&ZoHLOfk~Q?1%` zBJAA(U8})65DVUb7{r^qe0zuAyu~%ZEF<>z(d#`hj50!!wfUo%huXPl(t& zq7i8_?64Bs^gD@d(?m)^e*4?OK;f+U{r%&p@O+@6p8aB$M_uX6Uc{SlaQBBQ(?2Wi zPu?^^TX!3*lQdlQb=SzD=fo%4{C4~_wzeO5F#>iV25~y?ZvC)NW%_5swU3`t^>shF z^7k(wwztW&#a2uU)K`Q2_G96?$)cHm?=8{gmzu3JAbzKci_b_ja;Q~at3;>(Y?(K{ia1gfvYBT~@|w>PbYL7}7LF`INB@OB^WFPzoYMTEn?> zSj}EdpRcfJwn8MKNmHCn>F1JqWzwTWbFyfdy*_}o4y_$$=5i$3a%i$a0MZ#sTUu>d zU9GIfdWEjvK*fKdwc)1T%=MDN8pFkfKH^ju%2ycftzfO?(p80Z5a5z4;?n=fN~anV z3rMWj-``6bJj=QD^1 zk38V2LBNsr5?Tu!1GSqVvjtGl+;2j1cbb>86UE9uJhx)waA!}x00000NkvXXu0mjfKF#9m literal 0 HcmV?d00001 diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties index 83feeccc4..3f0a8da37 100644 --- a/resources/languages/resources.properties +++ b/resources/languages/resources.properties @@ -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 diff --git a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java index 32a65c389..57cc2f7f2 100644 --- a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java +++ b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java @@ -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 MainFrame. */ @@ -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 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 contactHandler to handle contact events for the + * given protocolProvider. * - * @param protocolProvider - * @param contactHandler + * @param protocolProvider the ProtocolProviderService, which + * contacts should be handled by the given contactHandler + * @param contactHandler the ContactEventHandler 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 ContactEventHandler corresponding to the given + * protocolProvider. + * + * @param protocolProvider the protocol provider, which contact handler + * we would like to remove + */ + public void removeProviderContactHandler( + ProtocolProviderService protocolProvider) + { + providerContactHandlers.remove(protocolProvider); + } + /** * Returns the ContactEventHandler registered for this protocol * provider. diff --git a/src/net/java/sip/communicator/impl/gui/main/UINotification.java b/src/net/java/sip/communicator/impl/gui/main/UINotification.java new file mode 100644 index 000000000..9b88a2bf4 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/UINotification.java @@ -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 UINotification 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 UINotification 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; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/UINotificationGroup.java b/src/net/java/sip/communicator/impl/gui/main/UINotificationGroup.java new file mode 100644 index 000000000..35586613e --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/UINotificationGroup.java @@ -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 UINotificationGroup class represents a group of notifications. + * + * @author Yana Stamcheva + */ +public class UINotificationGroup +{ + /** + * A list of all unread notifications. + */ + private Collection unreadNotifications + = new ArrayList(); + + /** + * 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 UINotification 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 getUnreadNotifications() + { + return new ArrayList(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(); + } + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/UINotificationListener.java b/src/net/java/sip/communicator/impl/gui/main/UINotificationListener.java new file mode 100644 index 000000000..52f583dfe --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/UINotificationListener.java @@ -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 UINotificationListener 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); +} diff --git a/src/net/java/sip/communicator/impl/gui/main/UINotificationManager.java b/src/net/java/sip/communicator/impl/gui/main/UINotificationManager.java new file mode 100644 index 000000000..37d75f233 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/UINotificationManager.java @@ -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 UINotificationManager 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 notificationGroups + = new ArrayList(); + + /** + * Listener notified for changes in missed calls count. + */ + private static Collection notificationListeners + = new ArrayList(); + + /** + * Adds the given UINotificationListener to the list of listeners + * that would be notified on any changes in missed calls count. + * + * @param l the UINotificationListener to add + */ + public static void addNotificationListener(UINotificationListener l) + { + synchronized (l) + { + notificationListeners.add(l); + } + } + + /** + * Removes the given UINotificationListener from the list of + * listeners that are notified on any changes in missed calls count. + * + * @param l the UINotificationListener 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 UINotification 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 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 getUnreadNotifications( + UINotificationGroup group) + { + return group.getUnreadNotifications(); + } + + /** + * Returns a list of all notification groups. + * + * @return a list of all notification groups + */ + public static Collection getNotificationGroups() + { + return new ArrayList(notificationGroups); + } + + /** + * Notifies interested UINotificationListener that a new + * notification has been received. + * + * @param notification the new notification + */ + private static void fireNotificationEvent(UINotification notification) + { + synchronized (notificationListeners) + { + Iterator listeners + = notificationListeners.iterator(); + + while (listeners.hasNext()) + listeners.next().notificationReceived(notification); + } + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallHistoryButton.java b/src/net/java/sip/communicator/impl/gui/main/call/CallHistoryButton.java index eb66f3e51..785235684 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallHistoryButton.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallHistoryButton.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.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 missedCalls) + public void notificationReceived(UINotification notification) { - if (!missedCalls.isEmpty()) + Collection notificationGroups + = UINotificationManager.getNotificationGroups(); + + if (!isHistoryVisible && notificationGroups.size() > 0) { - setMissedCallsView(missedCalls); + setNotificationView(notificationGroups); } else { @@ -145,7 +143,7 @@ public void missedCallCountChanged(Collection 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 missedCalls) + private void setNotificationView( + Collection notificationGroups) { - isMissedCallView = true; + int notificationCount = 0; + isNotificationsView = true; this.setBgImage(null); - String tooltipText = "" + missedCallsToolTip + "
"; + Iterator groupsIter + = notificationGroups.iterator(); + + String tooltipText = ""; - int visibleCallCount = 5; - Iterator callsIter = missedCalls.iterator(); - while (callsIter.hasNext() && visibleCallCount > 0) + while (groupsIter.hasNext()) { - MissedCall missedCall = callsIter.next(); - tooltipText += GuiUtils.formatTime(missedCall.getCallTime()) - + " "+ missedCall.getCallName() + "
"; - visibleCallCount--; - - if (visibleCallCount == 0 && callsIter.hasNext()) - tooltipText - += GuiActivator.getResources() + UINotificationGroup group = groupsIter.next(); + + tooltipText += "" + group.getGroupDisplayName() + "
"; + + notificationCount += group.getUnreadNotificationsCount(); + + int visibleNotifsPerGroup = 5; + Iterator notifsIter = group.getUnreadNotifications(); + + while (notifsIter.hasNext() && visibleNotifsPerGroup > 0) + { + UINotification missedCall = notifsIter.next(); + tooltipText += GuiUtils.formatTime(missedCall.getTime()) + + " " + missedCall.getDisplayName() + "
"; + + 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 + ""); this.setBackground(new Color(200, 0, 0)); - this.setText(new Integer(missedCalls.size()).toString()); + this.setText(new Integer(notificationCount).toString()); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java b/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java index c86b5ca55..e70692dcc 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java @@ -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 activeCalls = new Hashtable(); - /** - * 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 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 MissedCallsListener 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(); - } - - missedCalls.add(missedCall); - fireMissedCallCountChangeEvent(missedCalls); - } - - /** - * Clears the count of missed calls. Sets it to 0. - */ - public static void clearMissedCalls() - { - missedCalls = null; - } - - /** - * Notifies interested MissedCallListener that the count has - * changed. - * @param missedCalls the new missed calls - */ - private static void fireMissedCallCountChangeEvent( - Collection missedCalls) - { - if (missedCallsListener != null) - missedCallsListener.missedCallCountChanged(missedCalls); - } - /** * Returns the image corresponding to the given peer. * @@ -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. */ diff --git a/src/net/java/sip/communicator/impl/gui/main/call/MissedCall.java b/src/net/java/sip/communicator/impl/gui/main/call/MissedCall.java deleted file mode 100644 index be689633d..000000000 --- a/src/net/java/sip/communicator/impl/gui/main/call/MissedCall.java +++ /dev/null @@ -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 MissedCall 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 MissedCall 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; - } -} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/MissedCallsListener.java b/src/net/java/sip/communicator/impl/gui/main/call/MissedCallsListener.java deleted file mode 100644 index 843d2ab4c..000000000 --- a/src/net/java/sip/communicator/impl/gui/main/call/MissedCallsListener.java +++ /dev/null @@ -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 MissedCallsListener listens for changes in the missed calls - * count. It is notified each time when a missed calls is registered by the - * CallManager. - * - * @author Yana Stamcheva - */ -public interface MissedCallsListener -{ - /** - * Indicates the missed calls count has changed. - * @param missedCalls the new missed calls list - */ - public void missedCallCountChanged(Collection missedCalls); -} 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 2c8f450ea..267d4c512 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 @@ -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 treeModel. + * * @param filterQuery the FilterQuery 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 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 uiContact is matching this filter. + * * @param uiContact the UIContact to check for match * @return true if the given uiContact is matching this * filter, false 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 UIGroup to check for match * @return false to indicate that no group could match this filter */ public boolean isMatching(UIGroup uiGroup) { + if (uiGroup instanceof NotificationGroup) + { + return true; + } + return false; } /** * Adds matching sourceContacts to the result tree model. + * * @param sourceContacts the list of SourceContacts to add * @param uiSource the ExternalContactSource, which contacts * we're adding @@ -105,4 +128,31 @@ private void addMatching( List sourceContacts, false); } } + + /** + * Adds matching notification contacts to the result tree model. + * + * @param notifSource + */ + private void addMatching(NotificationContactSource notifSource) + { + Iterator notifGroups + = notifSource.getNotificationGroups(); + + while (notifGroups.hasNext()) + { + UIGroup uiGroup = notifGroups.next(); + + Iterator notfications + = notifSource.getNotifications(uiGroup); + + while (notfications.hasNext()) + { + GuiActivator.getContactList() + .addContact(notfications.next(), + uiGroup, + false); + } + } + } } 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 4b1a6cefa..3f02971a1 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 @@ -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 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 3801677c9..4df88f8cf 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 @@ -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 TreeContactList is a contact list based on JTree. * @@ -115,6 +115,8 @@ public class TreeContactList private static final Collection contactSources = new LinkedList(); + 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 + * contact 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 UIGroup to add @@ -1715,6 +1744,19 @@ public static Collection 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 ExternalContactSource corresponding to the given * ContactSourceService. 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 index 6f9b04b34..1e409b80a 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContact.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIContact.java @@ -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 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(); @@ -86,6 +95,7 @@ public interface UIContact /** * 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); @@ -93,6 +103,7 @@ public interface UIContact /** * 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 */ @@ -101,6 +112,7 @@ public interface 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 ContactNode getContactNode(); @@ -108,6 +120,7 @@ public interface UIContact /** * 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 */ @@ -116,6 +129,7 @@ public interface UIContact /** * 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 @@ -126,6 +140,7 @@ public UIContactDetail getDefaultContactDetail( /** * 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 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 index baf57e277..825d873f3 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/UIGroup.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/UIGroup.java @@ -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 true to indicate that the group is collapsed, * false 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 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. */ @@ -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(); 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 ad09b93ee..87cac63ce 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 @@ -29,18 +29,20 @@ public class ExternalContactSource /** * 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()); + + sourceUIGroup = new SourceUIGroup(contactSource.getDisplayName()); } /** * Returns the corresponding ContactSourceService. + * * @return the corresponding ContactSourceService */ 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 UIContact corresponding to the given * sourceContact. + * * @param sourceContact the SourceContact, for which we search a * corresponding UIContact * @return the UIContact corresponding to the given 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 new file mode 100644 index 000000000..be1249591 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContact.java @@ -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 NotificationContact 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 ContactNode 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 NotificationContact by specifying the + * parent group and the corresponding ProtocolProviderService. + * + * @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 NotificationContact + * 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 UIContact. + * + * @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 UIGroup to be the parent group of this + * UIContact. + * + * @param parentGroup the parent UIGroup 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 getSearchStrings() + { + return null; + } + + /** + * 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() + { + return contactNode; + } + + /** + * 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) + { + this.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) + { + if (opSetClass.equals(OperationSetBasicTelephony.class)) + return notificationDetail; + + return null; + } + + /** + * Returns a list of UIContactDetails supporting the given + * OperationSet class. + * + * @param opSetClass the OperationSet class we're interested in + * @return a list of UIContactDetails supporting the given + * OperationSet class + */ + public List getContactDetailsForOperationSet( + Class opSetClass) + { + List resultList = new LinkedList(); + + 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 UIContactDetail interface for the + * external source ContactDetails. + */ + private class MessageWaitingDetail + extends UIContactDetail + { + /** + * Creates an instance of SourceContactDetail by specifying + * the underlying detail and the OperationSet 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 ProviderPresenceStatusChangeEvent 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 ProviderPresenceStatusChangeEvent 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) {} +} 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 new file mode 100644 index 000000000..9f0f2a21d --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationContactSource.java @@ -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 NotificationContactSource 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 NotificationGroup the + * corresponding MessageType, for which notifications + * are received. + */ + private final Hashtable groups + = new Hashtable(); + + /** + * Adds the received waiting message to the corresponding group and contact. + * Also adds it the UINotificationManager 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 Iterator over a list of all notification groups + * contained in this source. + * + * @return an Iterator over a list of all notification groups + * contained in this source + */ + public Iterator getNotificationGroups() + { + return groups.values().iterator(); + } + + /** + * Returns an Iterator 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 Iterator over a list of all notification contacts + * contained in the given group + */ + public Iterator getNotifications(UIGroup group) + { + if (!(group instanceof NotificationGroup)) + return null; + + NotificationGroup notifGroup = (NotificationGroup) group; + + return notifGroup.getNotifications(); + } +} 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 new file mode 100644 index 000000000..a4b257efc --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/notifsource/NotificationGroup.java @@ -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 NotificationGroup 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 NotificationContact the + * corresponding ProtocolProviderService, for which notifications + * are received. + */ + private final Hashtable + contacts + = new Hashtable(); + + /** + * The group of UI notifications. + */ + private static UINotificationGroup uiNotificationGroup; + + /** + * Creates an instance of NotificationGroup 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 false to indicate that this group is never collapsed. + * + * @return false + */ + 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 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() + { + return groupNode; + } + + /** + * 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) + { + 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 Iterator over a list of all notification contacts + * contained in this group. + * + * @return an Iterator over a list of all notification contacts + * contained in this group + */ + public Iterator 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 + * MessageWaitingEvent. + * + * @param event the MessageWaitingEvent 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)); + } + } +} diff --git a/src/net/java/sip/communicator/impl/gui/utils/Constants.java b/src/net/java/sip/communicator/impl/gui/utils/Constants.java index 6f3a1c873..4a3786197 100755 --- a/src/net/java/sip/communicator/impl/gui/utils/Constants.java +++ b/src/net/java/sip/communicator/impl/gui/utils/Constants.java @@ -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(). diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetMessageWaiting.java b/src/net/java/sip/communicator/service/protocol/OperationSetMessageWaiting.java index bfd2a2963..3e1f39d83 100644 --- a/src/net/java/sip/communicator/service/protocol/OperationSetMessageWaiting.java +++ b/src/net/java/sip/communicator/service/protocol/OperationSetMessageWaiting.java @@ -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. */ diff --git a/src/net/java/sip/communicator/service/protocol/event/MessageWaitingEvent.java b/src/net/java/sip/communicator/service/protocol/event/MessageWaitingEvent.java index a56d9d12e..bcadea22f 100644 --- a/src/net/java/sip/communicator/service/protocol/event/MessageWaitingEvent.java +++ b/src/net/java/sip/communicator/service/protocol/event/MessageWaitingEvent.java @@ -81,6 +81,16 @@ public MessageWaitingEvent( this.readUrgentMessages = readUrgentMessages; } + /** + * Returns the ProtocolProviderService which originated this event. + * + * @return the source ProtocolProviderService + */ + public ProtocolProviderService getSourceProvider() + { + return (ProtocolProviderService) getSource(); + } + /** * The URI we can use to reach messages from provider that is firing * the event. diff --git a/src/net/java/sip/communicator/service/protocol/event/MessageWaitingListener.java b/src/net/java/sip/communicator/service/protocol/event/MessageWaitingListener.java index 0a2c0ef3f..0995bd2c0 100644 --- a/src/net/java/sip/communicator/service/protocol/event/MessageWaitingListener.java +++ b/src/net/java/sip/communicator/service/protocol/event/MessageWaitingListener.java @@ -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);