diff --git a/resources/colors/colors.properties b/resources/colors/colors.properties index 7a9c77af2..a4b9cf74f 100644 --- a/resources/colors/colors.properties +++ b/resources/colors/colors.properties @@ -83,10 +83,10 @@ service.gui.TAB_TITLE_SELECTED=000000 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 +service.gui.LIST_SELECTION_COLOR=9ae8fc # Selection color for contact list gradient -service.gui.LIST_SELECTION_COLOR_GRADIENT=FFFFFF +service.gui.LIST_SELECTION_COLOR_GRADIENT=0cc0f4 # Selection border color of all lists (contact list, call list, chat rooms list, etc.) service.gui.LIST_SELECTION_BORDER_COLOR=daeefd @@ -131,10 +131,10 @@ plugin.simpleaccreg.ACCOUNT_REGISTRATION_BACKGROUND=C2CEE0 service.gui.LIST_ROW=E7E7E7 # Contact list group row background color. -service.gui.CONTACT_LIST_GROUP_ROW=C3C3C3 +service.gui.CONTACT_LIST_GROUP_ROW=dde4eb # Contact list gradient group color. -service.gui.CONTACT_LIST_GROUP_GRADIENT=FFFFFF +service.gui.CONTACT_LIST_GROUP_GRADIENT=e3eaf1 # Main window background color. service.gui.MAIN_WINDOW_BACKGROUND=FFFFFF @@ -155,10 +155,10 @@ service.gui.CONTACT_LIST_CONTACT_FOREGROUND=000000 service.gui.CONTACT_LIST_GROUP_FOREGROUND=000000 # The background color of all windows and dialogs. -service.gui.MAIN_BACKGROUND=4A9BDB +service.gui.MAIN_BACKGROUND=dfedf6 # The end color of the gradient painted to all windows. -service.gui.MAIN_BACKGROUND_GRADIENT=E1F0FD +service.gui.MAIN_BACKGROUND_GRADIENT=dcebf4 service.gui.FAVORITES_PANEL_BACKGROUND=474747 @@ -214,8 +214,16 @@ service.gui.SECURITY_ON=6FC93C # The security off status color. service.gui.SECURITY_OFF=ED0000 -# Going secure status color. +# Call toolbar backgroundn color. +service.gui.CALL_TOOL_BAR=DFDFDF + +# Call toolbar sound background color. +service.gui.CALL_TOOL_BAR_SOUND_BG=282828 + +# Call toolbar full screen background color. +service.gui.CALL_TOOL_BAR_FULL_SCREEN=313131 + service.gui.GOING_SECURE=FFC01B # Chat editor correction message background color. -service.gui.CHAT_EDIT_MESSAGE_BACKGROUND=fffbc3 \ No newline at end of file +service.gui.CHAT_EDIT_MESSAGE_BACKGROUND=fffbc3 diff --git a/resources/images/images.properties b/resources/images/images.properties index b96951911..11516498b 100644 --- a/resources/images/images.properties +++ b/resources/images/images.properties @@ -15,6 +15,7 @@ service.gui.WINDOW_TITLE_BAR_BG=resources/images/impl/gui/common/windowTitleBar. service.gui.USER_PHOTO_FRAME=resources/images/impl/gui/common/personPhotoFrame.png service.gui.USER_PHOTO_SHADOW=resources/images/impl/gui/common/personPhotoShadow.png service.gui.DEFAULT_USER_PHOTO=resources/images/impl/gui/common/personPhoto.png +service.gui.DEFAULT_USER_PHOTO_SMALL=resources/images/impl/gui/common/personPhotoSmall.png # service gui icons service.gui.icons.ADD_ICON=resources/images/impl/gui/buttons/add.png @@ -22,6 +23,7 @@ service.gui.icons.ACCOUNT_ICON=resources/images/impl/gui/buttons/addAccount.png service.gui.icons.ADD_ACCOUNT_MENU_ICON=resources/images/impl/gui/buttons/addAccountMenu.png service.gui.icons.CONFIGURE_ICON=resources/images/impl/gui/common/configureIcon.png service.gui.icons.SHOW_HIDE_OFFLINE_ICON=resources/images/impl/gui/common/showHideOffline.png +service.gui.icons.NO_SOUND_ICON=resources/images/impl/gui/common/noSound.png service.gui.icons.SOUND_MENU_ICON=resources/images/impl/gui/common/soundMenu.png service.gui.icons.QUICK_MENU_ADD_ICON=resources/images/impl/gui/buttons/addContactIcon.png service.gui.icons.QUICK_MENU_CONFIGURE_ICON=resources/images/impl/gui/buttons/configureIcon.png @@ -34,7 +36,6 @@ service.gui.icons.QUICK_MENU_MY_CHAT_ROOMS_ICON=resources/images/impl/gui/button service.gui.icons.SEARCH_ICON=resources/images/impl/gui/common/searchIcon.png service.gui.icons.SEARCH_ICON_16x16=resources/images/impl/gui/common/searchIcon16x16.png service.gui.icons.ADD_TO_CHAT_ICON=resources/images/impl/gui/buttons/addToChat.png -service.gui.icons.RIGHT_ARROW_ICON=resources/images/impl/gui/common/rightArrow.png service.gui.icons.DOWN_ARROW_ICON=resources/images/impl/gui/common/downArrow.png service.gui.icons.INVITE_DIALOG_ICON=resources/images/impl/gui/common/inviteDialogIcon.png service.gui.icons.SEND_SMS_ICON=resources/images/impl/gui/common/gsm.png @@ -112,6 +113,8 @@ service.gui.icons.SD_VIDEO_ICON=resources/images/impl/gui/common/sdVideoIcon.png service.gui.icons.HD_VIDEO_ICON=resources/images/impl/gui/common/hdVideoIcon.png service.gui.icons.UNAUTHORIZED_CONTACT_PHOTO=resources/images/impl/gui/common/unauthorizedContact.png service.gui.icons.UNAUTHORIZED_CONTACT_16x16=resources/images/impl/gui/common/unauthorizedContact16x16.png +service.gui.icons.CALL_TOOLBAR_SEPARATOR=resources/images/impl/gui/common/callToolbarSeparator.png +service.gui.icons.CALL_HISTORY_BUTTON_NOTIFICATION=resources/images/impl/gui/common/callHistoryButtonNotification.png service.gui.icons.AUTO_ANSWER_CHECK=resources/images/impl/gui/common/autoAnswerCheck.png # Status icons @@ -125,6 +128,11 @@ service.gui.statusicons.USER_OCCUPIED_ICON=resources/images/impl/gui/common/stat service.gui.statusicons.USER_ON_THE_PHONE_ICON=resources/images/impl/gui/common/statusicons/onThePhone.png # service gui buttons +service.gui.buttons.CONTACT_LIST_BUTTON_BG_LEFT=resources/images/impl/gui/buttons/contactListButtonBgLeft.png +service.gui.buttons.CONTACT_LIST_BUTTON_BG_RIGHT=resources/images/impl/gui/buttons/contactListButtonBgRight.png +service.gui.buttons.CONTACT_LIST_BUTTON_BG_MIDDLE=resources/images/impl/gui/buttons/contactListButtonBgMiddle.png +service.gui.buttons.CONTACT_LIST_ONE_BUTTON_BG=resources/images/impl/gui/buttons/contactListOneButtonBg.png +service.gui.buttons.CONTACT_LIST_BUTTON_SEPARATOR=resources/images/impl/gui/buttons/contactListButtonSeparator.png service.gui.buttons.CALL_BUTTON_BG=resources/images/impl/gui/buttons/callButton.png service.gui.buttons.MERGE_CALL_BUTTON_BG=resources/images/impl/gui/buttons/mergeToCall.png service.gui.buttons.CALL_VIDEO_BUTTON_BG=resources/images/impl/gui/buttons/videoCallButton.png @@ -240,6 +248,7 @@ service.gui.buttons.HIDE_ACTIONS_ROLLOVER_BUTTON=resources/images/impl/gui/butto service.gui.buttons.CALL_PEER_TOOLS=resources/images/impl/gui/buttons/tools.png service.gui.buttons.CHAT_ROOM_CONFIG=resources/images/impl/gui/buttons/chatRoomConfig.png service.gui.buttons.CHAT_CALL=resources/images/impl/gui/buttons/chatCall.png +service.gui.buttons.CHAT_VIDEO_CALL=resources/images/impl/gui/buttons/chatVideoCall.png service.gui.buttons.CHAT_DESKTOP_SHARING=resources/images/impl/gui/buttons/chatDesktopSharing.png service.gui.buttons.CALL_HISTORY_BUTTON=resources/images/impl/gui/buttons/callHistoryButton.png service.gui.buttons.CALL_HISTORY_BUTTON_PRESSED=resources/images/impl/gui/buttons/callHistoryButtonPressed.png @@ -262,8 +271,14 @@ service.gui.buttons.CALL_INFO=resources/images/impl/gui/buttons/callInfo.png service.gui.buttons.ZRTP_ID_BUTTON=resources/images/impl/gui/buttons/zrtpEditId.png # Sound level icons -service.gui.soundlevel.SOUND_LEVEL_ACTIVE=resources/images/impl/gui/common/soundlevel/soundActive.png -service.gui.soundlevel.SOUND_LEVEL_INACTIVE=resources/images/impl/gui/common/soundlevel/soundInactive.png +service.gui.soundlevel.SOUND_LEVEL_ACTIVE_LEFT=resources/images/impl/gui/common/soundlevel/soundActiveLeft.png +service.gui.soundlevel.SOUND_LEVEL_ACTIVE_LEFT_GRADIENT=resources/images/impl/gui/common/soundlevel/soundActiveLeftGradient.png +service.gui.soundlevel.SOUND_LEVEL_ACTIVE_MIDDLE=resources/images/impl/gui/common/soundlevel/soundActiveMiddle.png +service.gui.soundlevel.SOUND_LEVEL_ACTIVE_RIGHT=resources/images/impl/gui/common/soundlevel/soundActiveRight.png +service.gui.soundlevel.SOUND_LEVEL_ACTIVE_RIGHT_GRADIENT=resources/images/impl/gui/common/soundlevel/soundActiveRightGradient.png +service.gui.soundlevel.SOUND_LEVEL_INACTIVE_LEFT=resources/images/impl/gui/common/soundlevel/soundInactiveLeft.png +service.gui.soundlevel.SOUND_LEVEL_INACTIVE_MIDDLE=resources/images/impl/gui/common/soundlevel/soundInactiveMiddle.png +service.gui.soundlevel.SOUND_LEVEL_INACTIVE_RIGHT=resources/images/impl/gui/common/soundlevel/soundInactiveRight.png service.gui.soundlevel.MICROPHONE=resources/images/impl/gui/common/soundlevel/Microphone.png service.gui.soundlevel.HEADPHONE=resources/images/impl/gui/common/soundlevel/Headphone.png service.gui.soundlevel.SOUND_SETTING_BUTTON_BG=resources/images/impl/gui/common/soundlevel/volumeButton.png @@ -312,6 +327,18 @@ service.gui.lookandfeel.SCROLLBAR_HORIZONTAL=resources/images/impl/gui/lookandfe service.gui.lookandfeel.SCROLLBAR_VERTICAL=resources/images/impl/gui/lookandfeel/scrollbar_vert1.png service.gui.lookandfeel.SCROLLBAR_THUMB_HORIZONTAL=resources/images/impl/gui/lookandfeel/horizThumbHandle.png service.gui.lookandfeel.SCROLLBAR_THUMB_VERTICAL=resources/images/impl/gui/lookandfeel/vertThumbHandle.png +service.gui.lookandfeel.INCOMING_MESSAGE_BACKGROUND=resources/images/impl/gui/lookandfeel/yellowBackground.png +service.gui.lookandfeel.INCOMING_MESSAGE_BACKGROUND_RIGHT=resources/images/impl/gui/lookandfeel/yellowBackgroundRight.png +service.gui.lookandfeel.INCOMING_MESSAGE_INDICATOR=resources/images/impl/gui/lookandfeel/yellowIndicator.png +service.gui.lookandfeel.INCOMING_MESSAGE_CURVES=resources/images/impl/gui/lookandfeel/yellowCurves.png +service.gui.lookandfeel.INCOMING_MESSAGE_CURVES_TOP=resources/images/impl/gui/lookandfeel/yellowCurvesTop.png +service.gui.lookandfeel.CHAT_MESSAGE_LINE=resources/images/impl/gui/lookandfeel/chatLine.png + +service.gui.lookandfeel.OUTGOING_MESSAGE_BACKGROUND=resources/images/impl/gui/lookandfeel/blueBackground.png +service.gui.lookandfeel.OUTGOING_MESSAGE_BACKGROUND_RIGHT=resources/images/impl/gui/lookandfeel/blueBackgroundRight.png +service.gui.lookandfeel.OUTGOING_MESSAGE_INDICATOR=resources/images/impl/gui/lookandfeel/blueIndicator.png +service.gui.lookandfeel.OUTGOING_MESSAGE_CURVES=resources/images/impl/gui/lookandfeel/blueCurves.png +service.gui.lookandfeel.OUTGOING_MESSAGE_CURVES_TOP=resources/images/impl/gui/lookandfeel/blueCurvesTop.png service.gui.htmllookandfeel.PROGRESS_BAR_DEFAULT_BG=resources/images/impl/gui/common/bg_bar.gif service.gui.htmllookandfeel.PROGRESS_BAR_BG=resources/images/impl/gui/common/bar.gif diff --git a/resources/images/impl/gui/buttons/addAccount.png b/resources/images/impl/gui/buttons/addAccount.png index 28b469c36..faa27498e 100644 Binary files a/resources/images/impl/gui/buttons/addAccount.png and b/resources/images/impl/gui/buttons/addAccount.png differ diff --git a/resources/images/impl/gui/buttons/addAccountMenu.png b/resources/images/impl/gui/buttons/addAccountMenu.png index b871a0695..5f2838b92 100644 Binary files a/resources/images/impl/gui/buttons/addAccountMenu.png and b/resources/images/impl/gui/buttons/addAccountMenu.png differ diff --git a/resources/images/impl/gui/buttons/addContactSmall.png b/resources/images/impl/gui/buttons/addContactSmall.png index 4c0bda75c..46402c860 100644 Binary files a/resources/images/impl/gui/buttons/addContactSmall.png and b/resources/images/impl/gui/buttons/addContactSmall.png differ diff --git a/resources/images/impl/gui/buttons/addContactSmallPressed.png b/resources/images/impl/gui/buttons/addContactSmallPressed.png index 4bebb7ef1..774551d63 100644 Binary files a/resources/images/impl/gui/buttons/addContactSmallPressed.png and b/resources/images/impl/gui/buttons/addContactSmallPressed.png differ diff --git a/resources/images/impl/gui/buttons/addToCall.png b/resources/images/impl/gui/buttons/addToCall.png index 5051da419..f9142d432 100644 Binary files a/resources/images/impl/gui/buttons/addToCall.png and b/resources/images/impl/gui/buttons/addToCall.png differ diff --git a/resources/images/impl/gui/buttons/addToChat.png b/resources/images/impl/gui/buttons/addToChat.png index 792d85505..df52ce5b7 100644 Binary files a/resources/images/impl/gui/buttons/addToChat.png and b/resources/images/impl/gui/buttons/addToChat.png differ diff --git a/resources/images/impl/gui/buttons/callButton.png b/resources/images/impl/gui/buttons/callButton.png index 06c4a43f4..1b53155b4 100644 Binary files a/resources/images/impl/gui/buttons/callButton.png and b/resources/images/impl/gui/buttons/callButton.png differ diff --git a/resources/images/impl/gui/buttons/callButtonPressed.png b/resources/images/impl/gui/buttons/callButtonPressed.png index b45be018e..16d864e2a 100644 Binary files a/resources/images/impl/gui/buttons/callButtonPressed.png and b/resources/images/impl/gui/buttons/callButtonPressed.png differ diff --git a/resources/images/impl/gui/buttons/callDesktopSharing.png b/resources/images/impl/gui/buttons/callDesktopSharing.png index e60c96f3e..0e1b2ec48 100644 Binary files a/resources/images/impl/gui/buttons/callDesktopSharing.png and b/resources/images/impl/gui/buttons/callDesktopSharing.png differ diff --git a/resources/images/impl/gui/buttons/callHistoryButton.png b/resources/images/impl/gui/buttons/callHistoryButton.png index 78a9f38ae..e3473ff7b 100644 Binary files a/resources/images/impl/gui/buttons/callHistoryButton.png and b/resources/images/impl/gui/buttons/callHistoryButton.png differ diff --git a/resources/images/impl/gui/buttons/callHistoryButtonPressed.png b/resources/images/impl/gui/buttons/callHistoryButtonPressed.png index 4a123b48c..310ea86db 100644 Binary files a/resources/images/impl/gui/buttons/callHistoryButtonPressed.png and b/resources/images/impl/gui/buttons/callHistoryButtonPressed.png differ diff --git a/resources/images/impl/gui/buttons/callInfo.png b/resources/images/impl/gui/buttons/callInfo.png index 65a415bb4..fe6741146 100644 Binary files a/resources/images/impl/gui/buttons/callInfo.png and b/resources/images/impl/gui/buttons/callInfo.png differ diff --git a/resources/images/impl/gui/buttons/callSettingButton.png b/resources/images/impl/gui/buttons/callSettingButton.png index 2cf63b667..117ec51b1 100644 Binary files a/resources/images/impl/gui/buttons/callSettingButton.png and b/resources/images/impl/gui/buttons/callSettingButton.png differ diff --git a/resources/images/impl/gui/buttons/callSettingButtonPressed.png b/resources/images/impl/gui/buttons/callSettingButtonPressed.png index bfdd0a133..f326c82d8 100644 Binary files a/resources/images/impl/gui/buttons/callSettingButtonPressed.png and b/resources/images/impl/gui/buttons/callSettingButtonPressed.png differ diff --git a/resources/images/impl/gui/buttons/callSmall.png b/resources/images/impl/gui/buttons/callSmall.png index 02b8e491d..5cc20dce8 100644 Binary files a/resources/images/impl/gui/buttons/callSmall.png and b/resources/images/impl/gui/buttons/callSmall.png differ diff --git a/resources/images/impl/gui/buttons/callSmallPressed.png b/resources/images/impl/gui/buttons/callSmallPressed.png index db8b8200c..8a32ec696 100644 Binary files a/resources/images/impl/gui/buttons/callSmallPressed.png and b/resources/images/impl/gui/buttons/callSmallPressed.png differ diff --git a/resources/images/impl/gui/buttons/callVideoSmall.png b/resources/images/impl/gui/buttons/callVideoSmall.png index 1c260465b..15f4dc8fa 100644 Binary files a/resources/images/impl/gui/buttons/callVideoSmall.png and b/resources/images/impl/gui/buttons/callVideoSmall.png differ diff --git a/resources/images/impl/gui/buttons/callVideoSmallPressed.png b/resources/images/impl/gui/buttons/callVideoSmallPressed.png index f2f7169c4..74c4adcf3 100644 Binary files a/resources/images/impl/gui/buttons/callVideoSmallPressed.png and b/resources/images/impl/gui/buttons/callVideoSmallPressed.png differ diff --git a/resources/images/impl/gui/buttons/chatCall.png b/resources/images/impl/gui/buttons/chatCall.png index 9b4ee9e66..ccaf91802 100644 Binary files a/resources/images/impl/gui/buttons/chatCall.png and b/resources/images/impl/gui/buttons/chatCall.png differ diff --git a/resources/images/impl/gui/buttons/chatDesktopSharing.png b/resources/images/impl/gui/buttons/chatDesktopSharing.png index c22eb06b4..af0705c0b 100644 Binary files a/resources/images/impl/gui/buttons/chatDesktopSharing.png and b/resources/images/impl/gui/buttons/chatDesktopSharing.png differ diff --git a/resources/images/impl/gui/buttons/chatRoomConfig.png b/resources/images/impl/gui/buttons/chatRoomConfig.png index d9e420813..a17dd1330 100644 Binary files a/resources/images/impl/gui/buttons/chatRoomConfig.png and b/resources/images/impl/gui/buttons/chatRoomConfig.png differ diff --git a/resources/images/impl/gui/buttons/chatSmall.png b/resources/images/impl/gui/buttons/chatSmall.png index b4a563772..37353c570 100644 Binary files a/resources/images/impl/gui/buttons/chatSmall.png and b/resources/images/impl/gui/buttons/chatSmall.png differ diff --git a/resources/images/impl/gui/buttons/chatSmallPressed.png b/resources/images/impl/gui/buttons/chatSmallPressed.png index 1a3c32eb6..99bac44c2 100644 Binary files a/resources/images/impl/gui/buttons/chatSmallPressed.png and b/resources/images/impl/gui/buttons/chatSmallPressed.png differ diff --git a/resources/images/impl/gui/buttons/chatSmallWhite.png b/resources/images/impl/gui/buttons/chatSmallWhite.png index 49b1a2df1..f15f678ee 100644 Binary files a/resources/images/impl/gui/buttons/chatSmallWhite.png and b/resources/images/impl/gui/buttons/chatSmallWhite.png differ diff --git a/resources/images/impl/gui/buttons/chatVideoCall.png b/resources/images/impl/gui/buttons/chatVideoCall.png new file mode 100644 index 000000000..11e54ec2a Binary files /dev/null and b/resources/images/impl/gui/buttons/chatVideoCall.png differ diff --git a/resources/images/impl/gui/buttons/close.png b/resources/images/impl/gui/buttons/close.png index 6fab7b711..47fba7775 100644 Binary files a/resources/images/impl/gui/buttons/close.png and b/resources/images/impl/gui/buttons/close.png differ diff --git a/resources/images/impl/gui/buttons/closeTab.png b/resources/images/impl/gui/buttons/closeTab.png index d8bb99e1d..02e2c6a42 100644 Binary files a/resources/images/impl/gui/buttons/closeTab.png and b/resources/images/impl/gui/buttons/closeTab.png differ diff --git a/resources/images/impl/gui/buttons/contactListButtonBgLeft.png b/resources/images/impl/gui/buttons/contactListButtonBgLeft.png new file mode 100644 index 000000000..966aac3d9 Binary files /dev/null and b/resources/images/impl/gui/buttons/contactListButtonBgLeft.png differ diff --git a/resources/images/impl/gui/buttons/contactListButtonBgMiddle.png b/resources/images/impl/gui/buttons/contactListButtonBgMiddle.png new file mode 100644 index 000000000..b61d69ad4 Binary files /dev/null and b/resources/images/impl/gui/buttons/contactListButtonBgMiddle.png differ diff --git a/resources/images/impl/gui/buttons/contactListButtonBgRight.png b/resources/images/impl/gui/buttons/contactListButtonBgRight.png new file mode 100644 index 000000000..716bd2d2d Binary files /dev/null and b/resources/images/impl/gui/buttons/contactListButtonBgRight.png differ diff --git a/resources/images/impl/gui/buttons/contactListButtonSeparator.png b/resources/images/impl/gui/buttons/contactListButtonSeparator.png new file mode 100644 index 000000000..fa63cd547 Binary files /dev/null and b/resources/images/impl/gui/buttons/contactListButtonSeparator.png differ diff --git a/resources/images/impl/gui/buttons/contactListDialButton.png b/resources/images/impl/gui/buttons/contactListDialButton.png index 50bd8e085..3d8433e2d 100644 Binary files a/resources/images/impl/gui/buttons/contactListDialButton.png and b/resources/images/impl/gui/buttons/contactListDialButton.png differ diff --git a/resources/images/impl/gui/buttons/contactListOneButtonBg.png b/resources/images/impl/gui/buttons/contactListOneButtonBg.png new file mode 100644 index 000000000..8e5c2a7f5 Binary files /dev/null and b/resources/images/impl/gui/buttons/contactListOneButtonBg.png differ diff --git a/resources/images/impl/gui/buttons/copy.png b/resources/images/impl/gui/buttons/copy.png index 067022415..fc7d8267d 100644 Binary files a/resources/images/impl/gui/buttons/copy.png and b/resources/images/impl/gui/buttons/copy.png differ diff --git a/resources/images/impl/gui/buttons/cut.png b/resources/images/impl/gui/buttons/cut.png index 4aa43ef2d..d4f9203b3 100644 Binary files a/resources/images/impl/gui/buttons/cut.png and b/resources/images/impl/gui/buttons/cut.png differ diff --git a/resources/images/impl/gui/buttons/desktopSharingSmall.png b/resources/images/impl/gui/buttons/desktopSharingSmall.png index fab65c551..ec47587c2 100644 Binary files a/resources/images/impl/gui/buttons/desktopSharingSmall.png and b/resources/images/impl/gui/buttons/desktopSharingSmall.png differ diff --git a/resources/images/impl/gui/buttons/desktopSharingSmallPressed.png b/resources/images/impl/gui/buttons/desktopSharingSmallPressed.png index ff247eac1..4d336c087 100644 Binary files a/resources/images/impl/gui/buttons/desktopSharingSmallPressed.png and b/resources/images/impl/gui/buttons/desktopSharingSmallPressed.png differ diff --git a/resources/images/impl/gui/buttons/dialButton.png b/resources/images/impl/gui/buttons/dialButton.png index 2e5417131..48631fa7f 100644 Binary files a/resources/images/impl/gui/buttons/dialButton.png and b/resources/images/impl/gui/buttons/dialButton.png differ diff --git a/resources/images/impl/gui/buttons/encrypted_verified.png b/resources/images/impl/gui/buttons/encrypted_verified.png index c9fd25f42..d5ba1638e 100755 Binary files a/resources/images/impl/gui/buttons/encrypted_verified.png and b/resources/images/impl/gui/buttons/encrypted_verified.png differ diff --git a/resources/images/impl/gui/buttons/enterFullScreen.png b/resources/images/impl/gui/buttons/enterFullScreen.png index f0971035c..9e932e68c 100644 Binary files a/resources/images/impl/gui/buttons/enterFullScreen.png and b/resources/images/impl/gui/buttons/enterFullScreen.png differ diff --git a/resources/images/impl/gui/buttons/exitFullScreen.png b/resources/images/impl/gui/buttons/exitFullScreen.png index a01c05162..502fff66e 100644 Binary files a/resources/images/impl/gui/buttons/exitFullScreen.png and b/resources/images/impl/gui/buttons/exitFullScreen.png differ diff --git a/resources/images/impl/gui/buttons/hangupButton.png b/resources/images/impl/gui/buttons/hangupButton.png index 2741d5460..430f47a0d 100644 Binary files a/resources/images/impl/gui/buttons/hangupButton.png and b/resources/images/impl/gui/buttons/hangupButton.png differ diff --git a/resources/images/impl/gui/buttons/hangupButtonPressed.png b/resources/images/impl/gui/buttons/hangupButtonPressed.png index 49eee1b74..92bc68fce 100644 Binary files a/resources/images/impl/gui/buttons/hangupButtonPressed.png and b/resources/images/impl/gui/buttons/hangupButtonPressed.png differ diff --git a/resources/images/impl/gui/buttons/hdVideo.png b/resources/images/impl/gui/buttons/hdVideo.png index c057d6e90..e3175f370 100644 Binary files a/resources/images/impl/gui/buttons/hdVideo.png and b/resources/images/impl/gui/buttons/hdVideo.png differ diff --git a/resources/images/impl/gui/buttons/history.png b/resources/images/impl/gui/buttons/history.png index d76db0a95..09cd2e4eb 100644 Binary files a/resources/images/impl/gui/buttons/history.png and b/resources/images/impl/gui/buttons/history.png differ diff --git a/resources/images/impl/gui/buttons/holdButton.png b/resources/images/impl/gui/buttons/holdButton.png index 41c56a21f..570ea1b78 100644 Binary files a/resources/images/impl/gui/buttons/holdButton.png and b/resources/images/impl/gui/buttons/holdButton.png differ diff --git a/resources/images/impl/gui/buttons/holdButtonPressed.png b/resources/images/impl/gui/buttons/holdButtonPressed.png index 9eff2d7e1..2727a750e 100644 Binary files a/resources/images/impl/gui/buttons/holdButtonPressed.png and b/resources/images/impl/gui/buttons/holdButtonPressed.png differ diff --git a/resources/images/impl/gui/buttons/infoIcon.png b/resources/images/impl/gui/buttons/infoIcon.png index 48dc82184..9a4c9a4a7 100644 Binary files a/resources/images/impl/gui/buttons/infoIcon.png and b/resources/images/impl/gui/buttons/infoIcon.png differ diff --git a/resources/images/impl/gui/buttons/loVideo.png b/resources/images/impl/gui/buttons/loVideo.png index 076b09d18..22d37e49a 100644 Binary files a/resources/images/impl/gui/buttons/loVideo.png and b/resources/images/impl/gui/buttons/loVideo.png differ diff --git a/resources/images/impl/gui/buttons/localVideoButton.png b/resources/images/impl/gui/buttons/localVideoButton.png index f2c715173..92b3bcf3c 100644 Binary files a/resources/images/impl/gui/buttons/localVideoButton.png and b/resources/images/impl/gui/buttons/localVideoButton.png differ diff --git a/resources/images/impl/gui/buttons/localVideoButtonPressed.png b/resources/images/impl/gui/buttons/localVideoButtonPressed.png index 69c35cd9c..03e0f39fe 100644 Binary files a/resources/images/impl/gui/buttons/localVideoButtonPressed.png and b/resources/images/impl/gui/buttons/localVideoButtonPressed.png differ diff --git a/resources/images/impl/gui/buttons/muteButton.png b/resources/images/impl/gui/buttons/muteButton.png index 5a08d72fa..0ffb0d060 100644 Binary files a/resources/images/impl/gui/buttons/muteButton.png and b/resources/images/impl/gui/buttons/muteButton.png differ diff --git a/resources/images/impl/gui/buttons/muteButtonPressed.png b/resources/images/impl/gui/buttons/muteButtonPressed.png index 852c01099..420975f0a 100644 Binary files a/resources/images/impl/gui/buttons/muteButtonPressed.png and b/resources/images/impl/gui/buttons/muteButtonPressed.png differ diff --git a/resources/images/impl/gui/buttons/next.png b/resources/images/impl/gui/buttons/next.png index 1d610ff06..d9d45ed97 100644 Binary files a/resources/images/impl/gui/buttons/next.png and b/resources/images/impl/gui/buttons/next.png differ diff --git a/resources/images/impl/gui/buttons/paste.png b/resources/images/impl/gui/buttons/paste.png index 592d5f9a6..f2abed9f8 100644 Binary files a/resources/images/impl/gui/buttons/paste.png and b/resources/images/impl/gui/buttons/paste.png differ diff --git a/resources/images/impl/gui/buttons/previous.png b/resources/images/impl/gui/buttons/previous.png index 867bef560..f31868df5 100644 Binary files a/resources/images/impl/gui/buttons/previous.png and b/resources/images/impl/gui/buttons/previous.png differ diff --git a/resources/images/impl/gui/buttons/recordButton.png b/resources/images/impl/gui/buttons/recordButton.png index 10931c4d1..4aaea30e6 100644 Binary files a/resources/images/impl/gui/buttons/recordButton.png and b/resources/images/impl/gui/buttons/recordButton.png differ diff --git a/resources/images/impl/gui/buttons/recordButtonPressed.png b/resources/images/impl/gui/buttons/recordButtonPressed.png index 4affa9b6f..58619b1d0 100644 Binary files a/resources/images/impl/gui/buttons/recordButtonPressed.png and b/resources/images/impl/gui/buttons/recordButtonPressed.png differ diff --git a/resources/images/impl/gui/buttons/save.png b/resources/images/impl/gui/buttons/save.png index 74008fa5e..3a91f9555 100644 Binary files a/resources/images/impl/gui/buttons/save.png and b/resources/images/impl/gui/buttons/save.png differ diff --git a/resources/images/impl/gui/buttons/sdVideo.png b/resources/images/impl/gui/buttons/sdVideo.png index 27a6d5d75..ca487e83f 100644 Binary files a/resources/images/impl/gui/buttons/sdVideo.png and b/resources/images/impl/gui/buttons/sdVideo.png differ diff --git a/resources/images/impl/gui/buttons/searchCallIcon.png b/resources/images/impl/gui/buttons/searchCallIcon.png index 4c50ecb11..a751929c5 100644 Binary files a/resources/images/impl/gui/buttons/searchCallIcon.png and b/resources/images/impl/gui/buttons/searchCallIcon.png differ diff --git a/resources/images/impl/gui/buttons/searchCallRolloverIcon.png b/resources/images/impl/gui/buttons/searchCallRolloverIcon.png index 46cee5a32..79add6cd1 100644 Binary files a/resources/images/impl/gui/buttons/searchCallRolloverIcon.png and b/resources/images/impl/gui/buttons/searchCallRolloverIcon.png differ diff --git a/resources/images/impl/gui/buttons/secureAudioOff.png b/resources/images/impl/gui/buttons/secureAudioOff.png index d32800c32..201e78297 100644 Binary files a/resources/images/impl/gui/buttons/secureAudioOff.png and b/resources/images/impl/gui/buttons/secureAudioOff.png differ diff --git a/resources/images/impl/gui/buttons/secureAudioOn.png b/resources/images/impl/gui/buttons/secureAudioOn.png index c408c4f8d..7bbbb5196 100644 Binary files a/resources/images/impl/gui/buttons/secureAudioOn.png and b/resources/images/impl/gui/buttons/secureAudioOn.png differ diff --git a/resources/images/impl/gui/buttons/secureVideoOff.png b/resources/images/impl/gui/buttons/secureVideoOff.png index d4d144b05..546aaad31 100644 Binary files a/resources/images/impl/gui/buttons/secureVideoOff.png and b/resources/images/impl/gui/buttons/secureVideoOff.png differ diff --git a/resources/images/impl/gui/buttons/secureVideoOn.png b/resources/images/impl/gui/buttons/secureVideoOn.png index 4f020a6da..489784b0a 100644 Binary files a/resources/images/impl/gui/buttons/secureVideoOn.png and b/resources/images/impl/gui/buttons/secureVideoOn.png differ diff --git a/resources/images/impl/gui/buttons/sendFile.png b/resources/images/impl/gui/buttons/sendFile.png index e8c40d9c6..bd08bd4d0 100644 Binary files a/resources/images/impl/gui/buttons/sendFile.png and b/resources/images/impl/gui/buttons/sendFile.png differ diff --git a/resources/images/impl/gui/buttons/showHideLocalVideo.png b/resources/images/impl/gui/buttons/showHideLocalVideo.png index 60ad55d99..dc1f4b95e 100644 Binary files a/resources/images/impl/gui/buttons/showHideLocalVideo.png and b/resources/images/impl/gui/buttons/showHideLocalVideo.png differ diff --git a/resources/images/impl/gui/buttons/showHideLocalVideoPressed.png b/resources/images/impl/gui/buttons/showHideLocalVideoPressed.png index 3a4d6ec6a..036a0f77d 100644 Binary files a/resources/images/impl/gui/buttons/showHideLocalVideoPressed.png and b/resources/images/impl/gui/buttons/showHideLocalVideoPressed.png differ diff --git a/resources/images/impl/gui/buttons/smiley.png b/resources/images/impl/gui/buttons/smiley.png index b16f70045..fb7d83868 100644 Binary files a/resources/images/impl/gui/buttons/smiley.png and b/resources/images/impl/gui/buttons/smiley.png differ diff --git a/resources/images/impl/gui/buttons/transferCallButton.png b/resources/images/impl/gui/buttons/transferCallButton.png index 2367d4638..1b5b56331 100644 Binary files a/resources/images/impl/gui/buttons/transferCallButton.png and b/resources/images/impl/gui/buttons/transferCallButton.png differ diff --git a/resources/images/impl/gui/buttons/videoCallButton.png b/resources/images/impl/gui/buttons/videoCallButton.png index ba4923382..e6fa71950 100644 Binary files a/resources/images/impl/gui/buttons/videoCallButton.png and b/resources/images/impl/gui/buttons/videoCallButton.png differ diff --git a/resources/images/impl/gui/buttons/videoCallButtonPressed.png b/resources/images/impl/gui/buttons/videoCallButtonPressed.png index 9fe4f79fb..681f02d15 100644 Binary files a/resources/images/impl/gui/buttons/videoCallButtonPressed.png and b/resources/images/impl/gui/buttons/videoCallButtonPressed.png differ diff --git a/resources/images/impl/gui/buttons/volumeControl.png b/resources/images/impl/gui/buttons/volumeControl.png index 8b2e214d7..aa0180a60 100644 Binary files a/resources/images/impl/gui/buttons/volumeControl.png and b/resources/images/impl/gui/buttons/volumeControl.png differ diff --git a/resources/images/impl/gui/common/addContact16x16.png b/resources/images/impl/gui/common/addContact16x16.png index d61945082..c59031f90 100644 Binary files a/resources/images/impl/gui/common/addContact16x16.png and b/resources/images/impl/gui/common/addContact16x16.png differ diff --git a/resources/images/impl/gui/common/addContactDialogIcon.png b/resources/images/impl/gui/common/addContactDialogIcon.png index bd9b28488..5b1f4ed13 100644 Binary files a/resources/images/impl/gui/common/addContactDialogIcon.png and b/resources/images/impl/gui/common/addContactDialogIcon.png differ diff --git a/resources/images/impl/gui/common/addGroup.png b/resources/images/impl/gui/common/addGroup.png index c9219fca1..2872b7e56 100644 Binary files a/resources/images/impl/gui/common/addGroup.png and b/resources/images/impl/gui/common/addGroup.png differ diff --git a/resources/images/impl/gui/common/admin.png b/resources/images/impl/gui/common/admin.png index 09ef1808f..030dc0b27 100644 Binary files a/resources/images/impl/gui/common/admin.png and b/resources/images/impl/gui/common/admin.png differ diff --git a/resources/images/impl/gui/common/browser16x16.png b/resources/images/impl/gui/common/browser16x16.png index 302b0fdf2..b5ffc2d17 100644 Binary files a/resources/images/impl/gui/common/browser16x16.png and b/resources/images/impl/gui/common/browser16x16.png differ diff --git a/resources/images/impl/gui/common/call16x16.png b/resources/images/impl/gui/common/call16x16.png index b1482f730..e237e5a5e 100644 Binary files a/resources/images/impl/gui/common/call16x16.png and b/resources/images/impl/gui/common/call16x16.png differ diff --git a/resources/images/impl/gui/common/callHistoryButtonNotification.png b/resources/images/impl/gui/common/callHistoryButtonNotification.png new file mode 100644 index 000000000..b6f29f855 Binary files /dev/null and b/resources/images/impl/gui/common/callHistoryButtonNotification.png differ diff --git a/resources/images/impl/gui/common/callToolbarSeparator.png b/resources/images/impl/gui/common/callToolbarSeparator.png new file mode 100644 index 000000000..268140dea Binary files /dev/null and b/resources/images/impl/gui/common/callToolbarSeparator.png differ diff --git a/resources/images/impl/gui/common/changeNickname16x16.png b/resources/images/impl/gui/common/changeNickname16x16.png index 4a1befe42..cf7c9f18c 100644 Binary files a/resources/images/impl/gui/common/changeNickname16x16.png and b/resources/images/impl/gui/common/changeNickname16x16.png differ diff --git a/resources/images/impl/gui/common/changeSubject16x16.png b/resources/images/impl/gui/common/changeSubject16x16.png index eafc56578..573258c91 100644 Binary files a/resources/images/impl/gui/common/changeSubject16x16.png and b/resources/images/impl/gui/common/changeSubject16x16.png differ diff --git a/resources/images/impl/gui/common/chatRoom16x16.png b/resources/images/impl/gui/common/chatRoom16x16.png index 2bbc423af..f07f5160b 100644 Binary files a/resources/images/impl/gui/common/chatRoom16x16.png and b/resources/images/impl/gui/common/chatRoom16x16.png differ diff --git a/resources/images/impl/gui/common/closedGroup.png b/resources/images/impl/gui/common/closedGroup.png index 85350923a..999b85f4d 100644 Binary files a/resources/images/impl/gui/common/closedGroup.png and b/resources/images/impl/gui/common/closedGroup.png differ diff --git a/resources/images/impl/gui/common/delete16x16.png b/resources/images/impl/gui/common/delete16x16.png index 8086c8bef..87a3d2a29 100644 Binary files a/resources/images/impl/gui/common/delete16x16.png and b/resources/images/impl/gui/common/delete16x16.png differ diff --git a/resources/images/impl/gui/common/desktopSharing16x16.png b/resources/images/impl/gui/common/desktopSharing16x16.png index ca336dd0e..9a037095c 100644 Binary files a/resources/images/impl/gui/common/desktopSharing16x16.png and b/resources/images/impl/gui/common/desktopSharing16x16.png differ diff --git a/resources/images/impl/gui/common/downArrow.png b/resources/images/impl/gui/common/downArrow.png index fc78bb043..3ba9bc2e2 100644 Binary files a/resources/images/impl/gui/common/downArrow.png and b/resources/images/impl/gui/common/downArrow.png differ diff --git a/resources/images/impl/gui/common/envelope.png b/resources/images/impl/gui/common/envelope.png index be012e9e2..ce802a503 100644 Binary files a/resources/images/impl/gui/common/envelope.png and b/resources/images/impl/gui/common/envelope.png differ diff --git a/resources/images/impl/gui/common/groups16x16.png b/resources/images/impl/gui/common/groups16x16.png index c35dd64ee..8c33c9803 100644 Binary files a/resources/images/impl/gui/common/groups16x16.png and b/resources/images/impl/gui/common/groups16x16.png differ diff --git a/resources/images/impl/gui/common/hdVideo.png b/resources/images/impl/gui/common/hdVideo.png new file mode 100644 index 000000000..e3175f370 Binary files /dev/null and b/resources/images/impl/gui/common/hdVideo.png differ diff --git a/resources/images/impl/gui/common/history16x16.png b/resources/images/impl/gui/common/history16x16.png index 67ba572f5..30e70fe20 100644 Binary files a/resources/images/impl/gui/common/history16x16.png and b/resources/images/impl/gui/common/history16x16.png differ diff --git a/resources/images/impl/gui/common/incomingCall.png b/resources/images/impl/gui/common/incomingCall.png index bbcc12cee..993bfca58 100644 Binary files a/resources/images/impl/gui/common/incomingCall.png and b/resources/images/impl/gui/common/incomingCall.png differ diff --git a/resources/images/impl/gui/common/incomingCallBgLeft.png b/resources/images/impl/gui/common/incomingCallBgLeft.png new file mode 100644 index 000000000..494621c99 Binary files /dev/null and b/resources/images/impl/gui/common/incomingCallBgLeft.png differ diff --git a/resources/images/impl/gui/common/incomingCallBgMiddle.png b/resources/images/impl/gui/common/incomingCallBgMiddle.png new file mode 100644 index 000000000..5cfd84243 Binary files /dev/null and b/resources/images/impl/gui/common/incomingCallBgMiddle.png differ diff --git a/resources/images/impl/gui/common/incomingCallBgRight.png b/resources/images/impl/gui/common/incomingCallBgRight.png new file mode 100644 index 000000000..b37d5dcea Binary files /dev/null and b/resources/images/impl/gui/common/incomingCallBgRight.png differ diff --git a/resources/images/impl/gui/common/leave.png b/resources/images/impl/gui/common/leave.png index 6778929ec..5fff3ed82 100644 Binary files a/resources/images/impl/gui/common/leave.png and b/resources/images/impl/gui/common/leave.png differ diff --git a/resources/images/impl/gui/common/leaveold.png b/resources/images/impl/gui/common/leaveold.png new file mode 100644 index 000000000..a61219d59 Binary files /dev/null and b/resources/images/impl/gui/common/leaveold.png differ diff --git a/resources/images/impl/gui/common/loVideo.png b/resources/images/impl/gui/common/loVideo.png new file mode 100644 index 000000000..22d37e49a Binary files /dev/null and b/resources/images/impl/gui/common/loVideo.png differ diff --git a/resources/images/impl/gui/common/missedCall.png b/resources/images/impl/gui/common/missedCall.png index 5bc2e9691..6502180d9 100644 Binary files a/resources/images/impl/gui/common/missedCall.png and b/resources/images/impl/gui/common/missedCall.png differ diff --git a/resources/images/impl/gui/common/moderator.png b/resources/images/impl/gui/common/moderator.png index d36008cef..9a8376d4a 100644 Binary files a/resources/images/impl/gui/common/moderator.png and b/resources/images/impl/gui/common/moderator.png differ diff --git a/resources/images/impl/gui/common/moveContact.png b/resources/images/impl/gui/common/moveContact.png index cd14c7488..05cfc6ffe 100644 Binary files a/resources/images/impl/gui/common/moveContact.png and b/resources/images/impl/gui/common/moveContact.png differ diff --git a/resources/images/impl/gui/common/moveToGroup16x16.png b/resources/images/impl/gui/common/moveToGroup16x16.png index 28166d847..1746a12a0 100644 Binary files a/resources/images/impl/gui/common/moveToGroup16x16.png and b/resources/images/impl/gui/common/moveToGroup16x16.png differ diff --git a/resources/images/impl/gui/common/noSound.png b/resources/images/impl/gui/common/noSound.png new file mode 100644 index 000000000..593ea2353 Binary files /dev/null and b/resources/images/impl/gui/common/noSound.png differ diff --git a/resources/images/impl/gui/common/openedGroup.png b/resources/images/impl/gui/common/openedGroup.png index cc7bda3d6..37bec6a3d 100644 Binary files a/resources/images/impl/gui/common/openedGroup.png and b/resources/images/impl/gui/common/openedGroup.png differ diff --git a/resources/images/impl/gui/common/outgoingCall.png b/resources/images/impl/gui/common/outgoingCall.png index 849fec4a6..f780a8adc 100644 Binary files a/resources/images/impl/gui/common/outgoingCall.png and b/resources/images/impl/gui/common/outgoingCall.png differ diff --git a/resources/images/impl/gui/common/owner.png b/resources/images/impl/gui/common/owner.png index 2e7d0c3dc..585624ed4 100644 Binary files a/resources/images/impl/gui/common/owner.png and b/resources/images/impl/gui/common/owner.png differ diff --git a/resources/images/impl/gui/common/padlock.png b/resources/images/impl/gui/common/padlock.png index 9c91c6d7f..9c9762b8a 100644 Binary files a/resources/images/impl/gui/common/padlock.png and b/resources/images/impl/gui/common/padlock.png differ diff --git a/resources/images/impl/gui/common/personPhoto.png b/resources/images/impl/gui/common/personPhoto.png index 37b38f147..c2b04bd5a 100644 Binary files a/resources/images/impl/gui/common/personPhoto.png and b/resources/images/impl/gui/common/personPhoto.png differ diff --git a/resources/images/impl/gui/common/personPhotoFrame.png b/resources/images/impl/gui/common/personPhotoFrame.png index 265289dbe..fe9fcb55a 100644 Binary files a/resources/images/impl/gui/common/personPhotoFrame.png and b/resources/images/impl/gui/common/personPhotoFrame.png differ diff --git a/resources/images/impl/gui/common/personPhotoSmall.png b/resources/images/impl/gui/common/personPhotoSmall.png new file mode 100644 index 000000000..0fcffe37e Binary files /dev/null and b/resources/images/impl/gui/common/personPhotoSmall.png differ diff --git a/resources/images/impl/gui/common/regionSharing16x16.png b/resources/images/impl/gui/common/regionSharing16x16.png index 0aeb0d968..c6255f61f 100644 Binary files a/resources/images/impl/gui/common/regionSharing16x16.png and b/resources/images/impl/gui/common/regionSharing16x16.png differ diff --git a/resources/images/impl/gui/common/rename16x16.png b/resources/images/impl/gui/common/rename16x16.png index b18cc5a42..c70be019f 100644 Binary files a/resources/images/impl/gui/common/rename16x16.png and b/resources/images/impl/gui/common/rename16x16.png differ diff --git a/resources/images/impl/gui/common/renameDialogIcon.png b/resources/images/impl/gui/common/renameDialogIcon.png index 7de974e65..56f59640c 100644 Binary files a/resources/images/impl/gui/common/renameDialogIcon.png and b/resources/images/impl/gui/common/renameDialogIcon.png differ diff --git a/resources/images/impl/gui/common/searchIcon.png b/resources/images/impl/gui/common/searchIcon.png index d81f01916..5d635cd0a 100644 Binary files a/resources/images/impl/gui/common/searchIcon.png and b/resources/images/impl/gui/common/searchIcon.png differ diff --git a/resources/images/impl/gui/common/sendFile16x16.png b/resources/images/impl/gui/common/sendFile16x16.png index 0b3a15dbb..8da89a650 100644 Binary files a/resources/images/impl/gui/common/sendFile16x16.png and b/resources/images/impl/gui/common/sendFile16x16.png differ diff --git a/resources/images/impl/gui/common/sendMessage16x16.png b/resources/images/impl/gui/common/sendMessage16x16.png index 753b06fa8..9f2970d0c 100644 Binary files a/resources/images/impl/gui/common/sendMessage16x16.png and b/resources/images/impl/gui/common/sendMessage16x16.png differ diff --git a/resources/images/impl/gui/common/separator.png b/resources/images/impl/gui/common/separator.png new file mode 100644 index 000000000..8b9fa7dd1 Binary files /dev/null and b/resources/images/impl/gui/common/separator.png differ diff --git a/resources/images/impl/gui/common/showHideOffline.png b/resources/images/impl/gui/common/showHideOffline.png index d41394511..c98bfe6ce 100644 Binary files a/resources/images/impl/gui/common/showHideOffline.png and b/resources/images/impl/gui/common/showHideOffline.png differ diff --git a/resources/images/impl/gui/common/silent.png b/resources/images/impl/gui/common/silent.png index b1ddbbfc6..6772019ca 100644 Binary files a/resources/images/impl/gui/common/silent.png and b/resources/images/impl/gui/common/silent.png differ diff --git a/resources/images/impl/gui/common/soundMenu.png b/resources/images/impl/gui/common/soundMenu.png index dc7c68df4..ef1993889 100644 Binary files a/resources/images/impl/gui/common/soundMenu.png and b/resources/images/impl/gui/common/soundMenu.png differ diff --git a/resources/images/impl/gui/common/soundlevel/Headphone.png b/resources/images/impl/gui/common/soundlevel/Headphone.png index b6459b713..27d343e58 100644 Binary files a/resources/images/impl/gui/common/soundlevel/Headphone.png and b/resources/images/impl/gui/common/soundlevel/Headphone.png differ diff --git a/resources/images/impl/gui/common/soundlevel/Microphone.png b/resources/images/impl/gui/common/soundlevel/Microphone.png index 835354a70..24b55aa43 100644 Binary files a/resources/images/impl/gui/common/soundlevel/Microphone.png and b/resources/images/impl/gui/common/soundlevel/Microphone.png differ diff --git a/resources/images/impl/gui/common/soundlevel/soundActiveLeft.png b/resources/images/impl/gui/common/soundlevel/soundActiveLeft.png new file mode 100644 index 000000000..01f4d90a2 Binary files /dev/null and b/resources/images/impl/gui/common/soundlevel/soundActiveLeft.png differ diff --git a/resources/images/impl/gui/common/soundlevel/soundActiveLeftGradient.png b/resources/images/impl/gui/common/soundlevel/soundActiveLeftGradient.png new file mode 100644 index 000000000..88117177a Binary files /dev/null and b/resources/images/impl/gui/common/soundlevel/soundActiveLeftGradient.png differ diff --git a/resources/images/impl/gui/common/soundlevel/soundActiveMiddle.png b/resources/images/impl/gui/common/soundlevel/soundActiveMiddle.png new file mode 100644 index 000000000..0ae6202c2 Binary files /dev/null and b/resources/images/impl/gui/common/soundlevel/soundActiveMiddle.png differ diff --git a/resources/images/impl/gui/common/soundlevel/soundActiveRight.png b/resources/images/impl/gui/common/soundlevel/soundActiveRight.png new file mode 100644 index 000000000..f1ba8dedf Binary files /dev/null and b/resources/images/impl/gui/common/soundlevel/soundActiveRight.png differ diff --git a/resources/images/impl/gui/common/soundlevel/soundActiveRightGradient.png b/resources/images/impl/gui/common/soundlevel/soundActiveRightGradient.png new file mode 100644 index 000000000..d32046bc2 Binary files /dev/null and b/resources/images/impl/gui/common/soundlevel/soundActiveRightGradient.png differ diff --git a/resources/images/impl/gui/common/soundlevel/soundInactiveLeft.png b/resources/images/impl/gui/common/soundlevel/soundInactiveLeft.png new file mode 100644 index 000000000..07adc0810 Binary files /dev/null and b/resources/images/impl/gui/common/soundlevel/soundInactiveLeft.png differ diff --git a/resources/images/impl/gui/common/soundlevel/soundInactiveMiddle.png b/resources/images/impl/gui/common/soundlevel/soundInactiveMiddle.png new file mode 100644 index 000000000..ea879f44a Binary files /dev/null and b/resources/images/impl/gui/common/soundlevel/soundInactiveMiddle.png differ diff --git a/resources/images/impl/gui/common/soundlevel/soundInactiveRight.png b/resources/images/impl/gui/common/soundlevel/soundInactiveRight.png new file mode 100644 index 000000000..e23d8079e Binary files /dev/null and b/resources/images/impl/gui/common/soundlevel/soundInactiveRight.png differ diff --git a/resources/images/impl/gui/common/soundlevel/volumeButton.png b/resources/images/impl/gui/common/soundlevel/volumeButton.png index ed49c242d..dd6302a8b 100644 Binary files a/resources/images/impl/gui/common/soundlevel/volumeButton.png and b/resources/images/impl/gui/common/soundlevel/volumeButton.png differ diff --git a/resources/images/impl/gui/common/soundlevel/volumeButtonPressed.png b/resources/images/impl/gui/common/soundlevel/volumeButtonPressed.png index 4b91193e6..c75fe5afe 100644 Binary files a/resources/images/impl/gui/common/soundlevel/volumeButtonPressed.png and b/resources/images/impl/gui/common/soundlevel/volumeButtonPressed.png differ diff --git a/resources/images/impl/gui/common/standard.png b/resources/images/impl/gui/common/standard.png index 5135bac31..2765b0ff8 100644 Binary files a/resources/images/impl/gui/common/standard.png and b/resources/images/impl/gui/common/standard.png differ diff --git a/resources/images/impl/gui/common/statusicons/away.png b/resources/images/impl/gui/common/statusicons/away.png index dda259608..bf4747ea4 100644 Binary files a/resources/images/impl/gui/common/statusicons/away.png and b/resources/images/impl/gui/common/statusicons/away.png differ diff --git a/resources/images/impl/gui/common/statusicons/dnd.png b/resources/images/impl/gui/common/statusicons/dnd.png index 1e24bc90c..7f47cd2f8 100644 Binary files a/resources/images/impl/gui/common/statusicons/dnd.png and b/resources/images/impl/gui/common/statusicons/dnd.png differ diff --git a/resources/images/impl/gui/common/statusicons/freeForChat.png b/resources/images/impl/gui/common/statusicons/freeForChat.png index 41365b2f6..2b68e71c6 100644 Binary files a/resources/images/impl/gui/common/statusicons/freeForChat.png and b/resources/images/impl/gui/common/statusicons/freeForChat.png differ diff --git a/resources/images/impl/gui/common/statusicons/offline.png b/resources/images/impl/gui/common/statusicons/offline.png index 213838841..7832614f2 100644 Binary files a/resources/images/impl/gui/common/statusicons/offline.png and b/resources/images/impl/gui/common/statusicons/offline.png differ diff --git a/resources/images/impl/gui/common/statusicons/online.png b/resources/images/impl/gui/common/statusicons/online.png index 152670811..3ad0e6ae7 100644 Binary files a/resources/images/impl/gui/common/statusicons/online.png and b/resources/images/impl/gui/common/statusicons/online.png differ diff --git a/resources/images/impl/gui/common/unauthorizedContact16x16.png b/resources/images/impl/gui/common/unauthorizedContact16x16.png index aedaf0e18..333e5f0a5 100644 Binary files a/resources/images/impl/gui/common/unauthorizedContact16x16.png and b/resources/images/impl/gui/common/unauthorizedContact16x16.png differ diff --git a/resources/images/impl/gui/common/videoCall16x16.png b/resources/images/impl/gui/common/videoCall16x16.png index 39d82d57c..55717856d 100644 Binary files a/resources/images/impl/gui/common/videoCall16x16.png and b/resources/images/impl/gui/common/videoCall16x16.png differ diff --git a/resources/images/impl/gui/common/voicemail.png b/resources/images/impl/gui/common/voicemail.png index 737c73b90..e6445b0ba 100644 Binary files a/resources/images/impl/gui/common/voicemail.png and b/resources/images/impl/gui/common/voicemail.png differ diff --git a/resources/images/impl/gui/lookandfeel/blueBackground.png b/resources/images/impl/gui/lookandfeel/blueBackground.png new file mode 100644 index 000000000..5e7f771a8 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/blueBackground.png differ diff --git a/resources/images/impl/gui/lookandfeel/blueBackgroundRight.png b/resources/images/impl/gui/lookandfeel/blueBackgroundRight.png new file mode 100644 index 000000000..56d39b681 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/blueBackgroundRight.png differ diff --git a/resources/images/impl/gui/lookandfeel/blueCurves.png b/resources/images/impl/gui/lookandfeel/blueCurves.png new file mode 100644 index 000000000..5fc7185b1 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/blueCurves.png differ diff --git a/resources/images/impl/gui/lookandfeel/blueCurvesTop.png b/resources/images/impl/gui/lookandfeel/blueCurvesTop.png new file mode 100644 index 000000000..db6cad3d8 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/blueCurvesTop.png differ diff --git a/resources/images/impl/gui/lookandfeel/blueIndicator.png b/resources/images/impl/gui/lookandfeel/blueIndicator.png new file mode 100644 index 000000000..23fe03f9b Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/blueIndicator.png differ diff --git a/resources/images/impl/gui/lookandfeel/box-bg.png b/resources/images/impl/gui/lookandfeel/box-bg.png new file mode 100755 index 000000000..48baa5493 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/box-bg.png differ diff --git a/resources/images/impl/gui/lookandfeel/chatLine.png b/resources/images/impl/gui/lookandfeel/chatLine.png new file mode 100644 index 000000000..25dec1de0 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/chatLine.png differ diff --git a/resources/images/impl/gui/lookandfeel/selectedTabLeft.png b/resources/images/impl/gui/lookandfeel/selectedTabLeft.png index bb426c76a..10d31412b 100644 Binary files a/resources/images/impl/gui/lookandfeel/selectedTabLeft.png and b/resources/images/impl/gui/lookandfeel/selectedTabLeft.png differ diff --git a/resources/images/impl/gui/lookandfeel/selectedTabMiddle.png b/resources/images/impl/gui/lookandfeel/selectedTabMiddle.png index 3364e9df5..3b31cab41 100644 Binary files a/resources/images/impl/gui/lookandfeel/selectedTabMiddle.png and b/resources/images/impl/gui/lookandfeel/selectedTabMiddle.png differ diff --git a/resources/images/impl/gui/lookandfeel/selectedTabRight.png b/resources/images/impl/gui/lookandfeel/selectedTabRight.png index 5474d788f..e2e78ac18 100644 Binary files a/resources/images/impl/gui/lookandfeel/selectedTabRight.png and b/resources/images/impl/gui/lookandfeel/selectedTabRight.png differ diff --git a/resources/images/impl/gui/lookandfeel/tabLeft.png b/resources/images/impl/gui/lookandfeel/tabLeft.png index c8e32f886..9da002716 100644 Binary files a/resources/images/impl/gui/lookandfeel/tabLeft.png and b/resources/images/impl/gui/lookandfeel/tabLeft.png differ diff --git a/resources/images/impl/gui/lookandfeel/tabMiddle.png b/resources/images/impl/gui/lookandfeel/tabMiddle.png index 93b1418f0..c6a357ad6 100644 Binary files a/resources/images/impl/gui/lookandfeel/tabMiddle.png and b/resources/images/impl/gui/lookandfeel/tabMiddle.png differ diff --git a/resources/images/impl/gui/lookandfeel/tabRight.png b/resources/images/impl/gui/lookandfeel/tabRight.png index 4d706795d..57802f827 100644 Binary files a/resources/images/impl/gui/lookandfeel/tabRight.png and b/resources/images/impl/gui/lookandfeel/tabRight.png differ diff --git a/resources/images/impl/gui/lookandfeel/yellowBackground.png b/resources/images/impl/gui/lookandfeel/yellowBackground.png new file mode 100644 index 000000000..5e7f771a8 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/yellowBackground.png differ diff --git a/resources/images/impl/gui/lookandfeel/yellowBackgroundRight.png b/resources/images/impl/gui/lookandfeel/yellowBackgroundRight.png new file mode 100644 index 000000000..56d39b681 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/yellowBackgroundRight.png differ diff --git a/resources/images/impl/gui/lookandfeel/yellowCurves.png b/resources/images/impl/gui/lookandfeel/yellowCurves.png new file mode 100644 index 000000000..5fc7185b1 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/yellowCurves.png differ diff --git a/resources/images/impl/gui/lookandfeel/yellowCurvesTop.png b/resources/images/impl/gui/lookandfeel/yellowCurvesTop.png new file mode 100644 index 000000000..db6cad3d8 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/yellowCurvesTop.png differ diff --git a/resources/images/impl/gui/lookandfeel/yellowIndicator.png b/resources/images/impl/gui/lookandfeel/yellowIndicator.png new file mode 100644 index 000000000..96d2fd9f5 Binary files /dev/null and b/resources/images/impl/gui/lookandfeel/yellowIndicator.png differ diff --git a/resources/images/impl/media/audioConfig.png b/resources/images/impl/media/audioConfig.png index 79f1a2717..3eec96cf9 100644 Binary files a/resources/images/impl/media/audioConfig.png and b/resources/images/impl/media/audioConfig.png differ diff --git a/resources/images/impl/media/videoConfig.png b/resources/images/impl/media/videoConfig.png index 750e7b798..287ab1d12 100644 Binary files a/resources/images/impl/media/videoConfig.png and b/resources/images/impl/media/videoConfig.png differ diff --git a/resources/images/impl/systray/dock-away.png b/resources/images/impl/systray/dock-away.png index a79a2aabf..febe9d169 100644 Binary files a/resources/images/impl/systray/dock-away.png and b/resources/images/impl/systray/dock-away.png differ diff --git a/resources/images/impl/systray/dock-chatty.png b/resources/images/impl/systray/dock-chatty.png index a4f87e26e..c7b9334a2 100644 Binary files a/resources/images/impl/systray/dock-chatty.png and b/resources/images/impl/systray/dock-chatty.png differ diff --git a/resources/images/impl/systray/dock-dnd.png b/resources/images/impl/systray/dock-dnd.png index 4ac6cb272..d0a1446e4 100644 Binary files a/resources/images/impl/systray/dock-dnd.png and b/resources/images/impl/systray/dock-dnd.png differ diff --git a/resources/images/impl/systray/dock-offline.png b/resources/images/impl/systray/dock-offline.png index 3af41a9ae..f3eeec2d2 100644 Binary files a/resources/images/impl/systray/dock-offline.png and b/resources/images/impl/systray/dock-offline.png differ diff --git a/resources/images/impl/systray/dock-online.png b/resources/images/impl/systray/dock-online.png index 086912dcc..41dd760fc 100644 Binary files a/resources/images/impl/systray/dock-online.png and b/resources/images/impl/systray/dock-online.png differ diff --git a/resources/images/impl/systray/envelope.png b/resources/images/impl/systray/envelope.png index 08dc32afd..04ffbf7e3 100644 Binary files a/resources/images/impl/systray/envelope.png and b/resources/images/impl/systray/envelope.png differ diff --git a/resources/images/impl/systray/envelopeMacOSX.png b/resources/images/impl/systray/envelopeMacOSX.png index 916cfcd96..f107507b3 100644 Binary files a/resources/images/impl/systray/envelopeMacOSX.png and b/resources/images/impl/systray/envelopeMacOSX.png differ diff --git a/resources/images/impl/systray/envelopeMacOSXWhite.png b/resources/images/impl/systray/envelopeMacOSXWhite.png index 202b2699d..a6a9b1d6d 100644 Binary files a/resources/images/impl/systray/envelopeMacOSXWhite.png and b/resources/images/impl/systray/envelopeMacOSXWhite.png differ diff --git a/resources/images/impl/systray/envelopeWindows.png b/resources/images/impl/systray/envelopeWindows.png index b3f5de5a2..da200b1f1 100644 Binary files a/resources/images/impl/systray/envelopeWindows.png and b/resources/images/impl/systray/envelopeWindows.png differ diff --git a/resources/images/impl/systray/systrayIcon.png b/resources/images/impl/systray/systrayIcon.png index 85bc142a4..7f50214ae 100644 Binary files a/resources/images/impl/systray/systrayIcon.png and b/resources/images/impl/systray/systrayIcon.png differ diff --git a/resources/images/impl/systray/systrayIconAway.png b/resources/images/impl/systray/systrayIconAway.png index f50342936..70466bfca 100644 Binary files a/resources/images/impl/systray/systrayIconAway.png and b/resources/images/impl/systray/systrayIconAway.png differ diff --git a/resources/images/impl/systray/systrayIconDND.png b/resources/images/impl/systray/systrayIconDND.png index 9e45b4c0e..82afd6275 100644 Binary files a/resources/images/impl/systray/systrayIconDND.png and b/resources/images/impl/systray/systrayIconDND.png differ diff --git a/resources/images/impl/systray/systrayIconFFC.png b/resources/images/impl/systray/systrayIconFFC.png index 46a8200c5..7f39e508f 100644 Binary files a/resources/images/impl/systray/systrayIconFFC.png and b/resources/images/impl/systray/systrayIconFFC.png differ diff --git a/resources/images/impl/systray/systrayIconOffline.png b/resources/images/impl/systray/systrayIconOffline.png index 7db6479be..39e1c8f5e 100644 Binary files a/resources/images/impl/systray/systrayIconOffline.png and b/resources/images/impl/systray/systrayIconOffline.png differ diff --git a/resources/images/impl/systray/systrayIconWindows.png b/resources/images/impl/systray/systrayIconWindows.png index 970877203..51939c77c 100644 Binary files a/resources/images/impl/systray/systrayIconWindows.png and b/resources/images/impl/systray/systrayIconWindows.png differ diff --git a/resources/images/impl/systray/systrayIconWindowsAway.png b/resources/images/impl/systray/systrayIconWindowsAway.png index a5a110a69..498fbcb52 100644 Binary files a/resources/images/impl/systray/systrayIconWindowsAway.png and b/resources/images/impl/systray/systrayIconWindowsAway.png differ diff --git a/resources/images/impl/systray/systrayIconWindowsDND.png b/resources/images/impl/systray/systrayIconWindowsDND.png index d7413981b..5991993ed 100644 Binary files a/resources/images/impl/systray/systrayIconWindowsDND.png and b/resources/images/impl/systray/systrayIconWindowsDND.png differ diff --git a/resources/images/impl/systray/systrayIconWindowsFFC.png b/resources/images/impl/systray/systrayIconWindowsFFC.png index 97e9994c8..60cb1bd34 100644 Binary files a/resources/images/impl/systray/systrayIconWindowsFFC.png and b/resources/images/impl/systray/systrayIconWindowsFFC.png differ diff --git a/resources/images/impl/systray/systrayIconWindowsOffline.png b/resources/images/impl/systray/systrayIconWindowsOffline.png index 8d3f8beea..2b7907e75 100644 Binary files a/resources/images/impl/systray/systrayIconWindowsOffline.png and b/resources/images/impl/systray/systrayIconWindowsOffline.png differ diff --git a/resources/images/plugin/advancedconfig/configIcon.png b/resources/images/plugin/advancedconfig/configIcon.png index 0689b0d35..0b450db2e 100644 Binary files a/resources/images/plugin/advancedconfig/configIcon.png and b/resources/images/plugin/advancedconfig/configIcon.png differ diff --git a/resources/images/plugin/chatconfig/chatIcon.png b/resources/images/plugin/chatconfig/chatIcon.png index 7b8db43df..a97cdfdb1 100644 Binary files a/resources/images/plugin/chatconfig/chatIcon.png and b/resources/images/plugin/chatconfig/chatIcon.png differ diff --git a/resources/images/plugin/contactinfo/userInfo16x16.png b/resources/images/plugin/contactinfo/userInfo16x16.png index 19210b353..7a2ef6670 100644 Binary files a/resources/images/plugin/contactinfo/userInfo16x16.png and b/resources/images/plugin/contactinfo/userInfo16x16.png differ diff --git a/resources/images/plugin/generalconfig/configureIcon.png b/resources/images/plugin/generalconfig/configureIcon.png index f28d5cf57..06014b3e9 100644 Binary files a/resources/images/plugin/generalconfig/configureIcon.png and b/resources/images/plugin/generalconfig/configureIcon.png differ diff --git a/resources/images/plugin/notificationconfiguration/folder.png b/resources/images/plugin/notificationconfiguration/folder.png index 35cf94fc7..a8b10ff3e 100644 Binary files a/resources/images/plugin/notificationconfiguration/folder.png and b/resources/images/plugin/notificationconfiguration/folder.png differ diff --git a/resources/images/plugin/notificationconfiguration/playIcon.png b/resources/images/plugin/notificationconfiguration/playIcon.png index ae438d101..4883c3fe1 100644 Binary files a/resources/images/plugin/notificationconfiguration/playIcon.png and b/resources/images/plugin/notificationconfiguration/playIcon.png differ diff --git a/resources/images/plugin/notificationconfiguration/popupIcon.png b/resources/images/plugin/notificationconfiguration/popupIcon.png index aa38c9664..541da246f 100644 Binary files a/resources/images/plugin/notificationconfiguration/popupIcon.png and b/resources/images/plugin/notificationconfiguration/popupIcon.png differ diff --git a/resources/images/plugin/notificationconfiguration/progIcon.png b/resources/images/plugin/notificationconfiguration/progIcon.png index b18a858a9..13ab51b96 100644 Binary files a/resources/images/plugin/notificationconfiguration/progIcon.png and b/resources/images/plugin/notificationconfiguration/progIcon.png differ diff --git a/resources/images/plugin/notificationconfiguration/soundIcon.png b/resources/images/plugin/notificationconfiguration/soundIcon.png index 1630ec861..620173be5 100644 Binary files a/resources/images/plugin/notificationconfiguration/soundIcon.png and b/resources/images/plugin/notificationconfiguration/soundIcon.png differ diff --git a/resources/images/plugin/otr/encrypted22x22.png b/resources/images/plugin/otr/encrypted22x22.png index aebe70da1..8fdf6f2a2 100644 Binary files a/resources/images/plugin/otr/encrypted22x22.png and b/resources/images/plugin/otr/encrypted22x22.png differ diff --git a/resources/images/plugin/otr/encrypted_unverified22x22.png b/resources/images/plugin/otr/encrypted_unverified22x22.png index 83e053302..c4cd15d82 100644 Binary files a/resources/images/plugin/otr/encrypted_unverified22x22.png and b/resources/images/plugin/otr/encrypted_unverified22x22.png differ diff --git a/resources/images/plugin/otr/finished22x22.png b/resources/images/plugin/otr/finished22x22.png index ce1ab2631..e196297c0 100644 Binary files a/resources/images/plugin/otr/finished22x22.png and b/resources/images/plugin/otr/finished22x22.png differ diff --git a/resources/images/plugin/otr/otr_menu_icon.png b/resources/images/plugin/otr/otr_menu_icon.png index e29ac3946..7909f88f4 100644 Binary files a/resources/images/plugin/otr/otr_menu_icon.png and b/resources/images/plugin/otr/otr_menu_icon.png differ diff --git a/resources/images/plugin/otr/plaintext16x16.png b/resources/images/plugin/otr/plaintext16x16.png index 843036877..9b190a1f3 100644 Binary files a/resources/images/plugin/otr/plaintext16x16.png and b/resources/images/plugin/otr/plaintext16x16.png differ diff --git a/resources/images/plugin/otr/plaintext22x22.png b/resources/images/plugin/otr/plaintext22x22.png index f105d845e..6f38b3964 100644 Binary files a/resources/images/plugin/otr/plaintext22x22.png and b/resources/images/plugin/otr/plaintext22x22.png differ diff --git a/resources/images/plugin/securityconfig/security.png b/resources/images/plugin/securityconfig/security.png index d10c256ef..11e8bbd5b 100644 Binary files a/resources/images/plugin/securityconfig/security.png and b/resources/images/plugin/securityconfig/security.png differ diff --git a/resources/images/protocol/aim/aim16x16-away.png b/resources/images/protocol/aim/aim16x16-away.png index 91629def7..c049b756e 100644 Binary files a/resources/images/protocol/aim/aim16x16-away.png and b/resources/images/protocol/aim/aim16x16-away.png differ diff --git a/resources/images/protocol/aim/aim16x16-invisible.png b/resources/images/protocol/aim/aim16x16-invisible.png index aa5a20dd6..b62512c74 100644 Binary files a/resources/images/protocol/aim/aim16x16-invisible.png and b/resources/images/protocol/aim/aim16x16-invisible.png differ diff --git a/resources/images/protocol/aim/aim16x16-offline.png b/resources/images/protocol/aim/aim16x16-offline.png index 053c3b894..7057429fa 100644 Binary files a/resources/images/protocol/aim/aim16x16-offline.png and b/resources/images/protocol/aim/aim16x16-offline.png differ diff --git a/resources/images/protocol/aim/aim16x16-online.png b/resources/images/protocol/aim/aim16x16-online.png index 4530209db..d85cbeb55 100644 Binary files a/resources/images/protocol/aim/aim16x16-online.png and b/resources/images/protocol/aim/aim16x16-online.png differ diff --git a/resources/images/protocol/aim/cr16-action-aim_connecting.png b/resources/images/protocol/aim/cr16-action-aim_connecting.png new file mode 100644 index 000000000..fc52b3e94 Binary files /dev/null and b/resources/images/protocol/aim/cr16-action-aim_connecting.png differ diff --git a/resources/images/protocol/facebook/facebook-idle.png b/resources/images/protocol/facebook/facebook-idle.png index 719698f39..42654a400 100644 Binary files a/resources/images/protocol/facebook/facebook-idle.png and b/resources/images/protocol/facebook/facebook-idle.png differ diff --git a/resources/images/protocol/facebook/status16x16-away.png b/resources/images/protocol/facebook/status16x16-away.png index 771d75f76..fa449b864 100644 Binary files a/resources/images/protocol/facebook/status16x16-away.png and b/resources/images/protocol/facebook/status16x16-away.png differ diff --git a/resources/images/protocol/facebook/status16x16-connecting.png b/resources/images/protocol/facebook/status16x16-connecting.png new file mode 100644 index 000000000..c205d7fb8 Binary files /dev/null and b/resources/images/protocol/facebook/status16x16-connecting.png differ diff --git a/resources/images/protocol/facebook/status16x16-dnd.png b/resources/images/protocol/facebook/status16x16-dnd.png index 0bef0c369..22976e6d1 100644 Binary files a/resources/images/protocol/facebook/status16x16-dnd.png and b/resources/images/protocol/facebook/status16x16-dnd.png differ diff --git a/resources/images/protocol/facebook/status16x16-ffc.png b/resources/images/protocol/facebook/status16x16-ffc.png index 7e081bdc5..196856bcc 100644 Binary files a/resources/images/protocol/facebook/status16x16-ffc.png and b/resources/images/protocol/facebook/status16x16-ffc.png differ diff --git a/resources/images/protocol/facebook/status16x16-invisible.png b/resources/images/protocol/facebook/status16x16-invisible.png new file mode 100644 index 000000000..2571abc60 Binary files /dev/null and b/resources/images/protocol/facebook/status16x16-invisible.png differ diff --git a/resources/images/protocol/facebook/status16x16-offline.png b/resources/images/protocol/facebook/status16x16-offline.png index 50ed131c1..246972c11 100644 Binary files a/resources/images/protocol/facebook/status16x16-offline.png and b/resources/images/protocol/facebook/status16x16-offline.png differ diff --git a/resources/images/protocol/facebook/status16x16-online.png b/resources/images/protocol/facebook/status16x16-online.png index bc42cf9b0..4bc93a21e 100644 Binary files a/resources/images/protocol/facebook/status16x16-online.png and b/resources/images/protocol/facebook/status16x16-online.png differ diff --git a/resources/images/protocol/facebook/status16x16-phone.png b/resources/images/protocol/facebook/status16x16-phone.png index 0e96c2011..9b3b4fc3b 100644 Binary files a/resources/images/protocol/facebook/status16x16-phone.png and b/resources/images/protocol/facebook/status16x16-phone.png differ diff --git a/resources/images/protocol/facebook/status16x16-xa.png b/resources/images/protocol/facebook/status16x16-xa.png index 719698f39..ba5adb857 100644 Binary files a/resources/images/protocol/facebook/status16x16-xa.png and b/resources/images/protocol/facebook/status16x16-xa.png differ diff --git a/resources/images/protocol/gibberish/gibberish-away.png b/resources/images/protocol/gibberish/gibberish-away.png index cec400507..8304c5f36 100644 Binary files a/resources/images/protocol/gibberish/gibberish-away.png and b/resources/images/protocol/gibberish/gibberish-away.png differ diff --git a/resources/images/protocol/gibberish/gibberish-dnd.png b/resources/images/protocol/gibberish/gibberish-dnd.png index c76cb0543..148837573 100644 Binary files a/resources/images/protocol/gibberish/gibberish-dnd.png and b/resources/images/protocol/gibberish/gibberish-dnd.png differ diff --git a/resources/images/protocol/gibberish/gibberish-ffc.png b/resources/images/protocol/gibberish/gibberish-ffc.png index c1bdfe96b..cdd346185 100644 Binary files a/resources/images/protocol/gibberish/gibberish-ffc.png and b/resources/images/protocol/gibberish/gibberish-ffc.png differ diff --git a/resources/images/protocol/gibberish/gibberish-invisible.png b/resources/images/protocol/gibberish/gibberish-invisible.png index 6dbac63d5..7999f5c73 100644 Binary files a/resources/images/protocol/gibberish/gibberish-invisible.png and b/resources/images/protocol/gibberish/gibberish-invisible.png differ diff --git a/resources/images/protocol/gibberish/gibberish-na.png b/resources/images/protocol/gibberish/gibberish-na.png index b61d45cbd..ff952044d 100644 Binary files a/resources/images/protocol/gibberish/gibberish-na.png and b/resources/images/protocol/gibberish/gibberish-na.png differ diff --git a/resources/images/protocol/gibberish/gibberish-occupied.png b/resources/images/protocol/gibberish/gibberish-occupied.png index 5e1b736fb..f3de24de5 100644 Binary files a/resources/images/protocol/gibberish/gibberish-occupied.png and b/resources/images/protocol/gibberish/gibberish-occupied.png differ diff --git a/resources/images/protocol/gibberish/gibberish-offline.png b/resources/images/protocol/gibberish/gibberish-offline.png index fc892fa6a..085cad25f 100644 Binary files a/resources/images/protocol/gibberish/gibberish-offline.png and b/resources/images/protocol/gibberish/gibberish-offline.png differ diff --git a/resources/images/protocol/gibberish/gibberish-online.png b/resources/images/protocol/gibberish/gibberish-online.png index fdbb63395..98b845c74 100644 Binary files a/resources/images/protocol/gibberish/gibberish-online.png and b/resources/images/protocol/gibberish/gibberish-online.png differ diff --git a/resources/images/protocol/googletalk/status16x16-away.png b/resources/images/protocol/googletalk/status16x16-away.png index ae8bb42f6..57f908c14 100644 Binary files a/resources/images/protocol/googletalk/status16x16-away.png and b/resources/images/protocol/googletalk/status16x16-away.png differ diff --git a/resources/images/protocol/googletalk/status16x16-connecting.png b/resources/images/protocol/googletalk/status16x16-connecting.png new file mode 100644 index 000000000..88dc3f13a Binary files /dev/null and b/resources/images/protocol/googletalk/status16x16-connecting.png differ diff --git a/resources/images/protocol/googletalk/status16x16-dnd.png b/resources/images/protocol/googletalk/status16x16-dnd.png index e3b0e7502..fb9f60279 100644 Binary files a/resources/images/protocol/googletalk/status16x16-dnd.png and b/resources/images/protocol/googletalk/status16x16-dnd.png differ diff --git a/resources/images/protocol/googletalk/status16x16-ffc.png b/resources/images/protocol/googletalk/status16x16-ffc.png index 0c734e779..8ac108a6b 100644 Binary files a/resources/images/protocol/googletalk/status16x16-ffc.png and b/resources/images/protocol/googletalk/status16x16-ffc.png differ diff --git a/resources/images/protocol/googletalk/status16x16-offline.png b/resources/images/protocol/googletalk/status16x16-offline.png index 6071549a1..8f5325e92 100644 Binary files a/resources/images/protocol/googletalk/status16x16-offline.png and b/resources/images/protocol/googletalk/status16x16-offline.png differ diff --git a/resources/images/protocol/googletalk/status16x16-online.png b/resources/images/protocol/googletalk/status16x16-online.png index e80b03b16..c707f2a42 100644 Binary files a/resources/images/protocol/googletalk/status16x16-online.png and b/resources/images/protocol/googletalk/status16x16-online.png differ diff --git a/resources/images/protocol/googletalk/status16x16-phone.png b/resources/images/protocol/googletalk/status16x16-phone.png index 5ede5dc21..d8dfc8fa4 100644 Binary files a/resources/images/protocol/googletalk/status16x16-phone.png and b/resources/images/protocol/googletalk/status16x16-phone.png differ diff --git a/resources/images/protocol/googletalk/status16x16-xa.png b/resources/images/protocol/googletalk/status16x16-xa.png index a0ecc4f03..d2e1f9521 100644 Binary files a/resources/images/protocol/googletalk/status16x16-xa.png and b/resources/images/protocol/googletalk/status16x16-xa.png differ diff --git a/resources/images/protocol/icq/cr16-action-icq_connecting-1.png b/resources/images/protocol/icq/cr16-action-icq_connecting-1.png new file mode 100644 index 000000000..b89179ca5 Binary files /dev/null and b/resources/images/protocol/icq/cr16-action-icq_connecting-1.png differ diff --git a/resources/images/protocol/icq/googletalk3_157.png b/resources/images/protocol/icq/googletalk3_157.png new file mode 100644 index 000000000..de4e733e0 Binary files /dev/null and b/resources/images/protocol/icq/googletalk3_157.png differ diff --git a/resources/images/protocol/icq/icq16x16-away.png b/resources/images/protocol/icq/icq16x16-away.png index 79b5e0ebc..739b4c12b 100644 Binary files a/resources/images/protocol/icq/icq16x16-away.png and b/resources/images/protocol/icq/icq16x16-away.png differ diff --git a/resources/images/protocol/icq/icq16x16-dnd.png b/resources/images/protocol/icq/icq16x16-dnd.png index 3db1c0004..670dbeb9b 100644 Binary files a/resources/images/protocol/icq/icq16x16-dnd.png and b/resources/images/protocol/icq/icq16x16-dnd.png differ diff --git a/resources/images/protocol/icq/icq16x16-ffc.png b/resources/images/protocol/icq/icq16x16-ffc.png index 70ab6af60..e8826aa18 100644 Binary files a/resources/images/protocol/icq/icq16x16-ffc.png and b/resources/images/protocol/icq/icq16x16-ffc.png differ diff --git a/resources/images/protocol/icq/icq16x16-invisible.png b/resources/images/protocol/icq/icq16x16-invisible.png index c7e37ce9c..832e3ecc5 100644 Binary files a/resources/images/protocol/icq/icq16x16-invisible.png and b/resources/images/protocol/icq/icq16x16-invisible.png differ diff --git a/resources/images/protocol/icq/icq16x16-na.png b/resources/images/protocol/icq/icq16x16-na.png index 2e0b0d347..524714108 100644 Binary files a/resources/images/protocol/icq/icq16x16-na.png and b/resources/images/protocol/icq/icq16x16-na.png differ diff --git a/resources/images/protocol/icq/icq16x16-occupied.png b/resources/images/protocol/icq/icq16x16-occupied.png index 4b08b579b..a6f3ea27b 100644 Binary files a/resources/images/protocol/icq/icq16x16-occupied.png and b/resources/images/protocol/icq/icq16x16-occupied.png differ diff --git a/resources/images/protocol/icq/icq16x16-offline.png b/resources/images/protocol/icq/icq16x16-offline.png index a9d110316..1a6fdeffd 100644 Binary files a/resources/images/protocol/icq/icq16x16-offline.png and b/resources/images/protocol/icq/icq16x16-offline.png differ diff --git a/resources/images/protocol/icq/icq16x16-online.png b/resources/images/protocol/icq/icq16x16-online.png index 900ee440a..ea66631ce 100644 Binary files a/resources/images/protocol/icq/icq16x16-online.png and b/resources/images/protocol/icq/icq16x16-online.png differ diff --git a/resources/images/protocol/ippi/sip16x16-away.png b/resources/images/protocol/ippi/sip16x16-away.png index 24ef080a0..9189f18c6 100644 Binary files a/resources/images/protocol/ippi/sip16x16-away.png and b/resources/images/protocol/ippi/sip16x16-away.png differ diff --git a/resources/images/protocol/ippi/sip16x16-busy.png b/resources/images/protocol/ippi/sip16x16-busy.png index 27a0dde04..fcc61813e 100644 Binary files a/resources/images/protocol/ippi/sip16x16-busy.png and b/resources/images/protocol/ippi/sip16x16-busy.png differ diff --git a/resources/images/protocol/ippi/sip16x16-offline.png b/resources/images/protocol/ippi/sip16x16-offline.png index 9502b8746..fc888ad1f 100644 Binary files a/resources/images/protocol/ippi/sip16x16-offline.png and b/resources/images/protocol/ippi/sip16x16-offline.png differ diff --git a/resources/images/protocol/ippi/sip16x16-online.png b/resources/images/protocol/ippi/sip16x16-online.png index e30b77c85..e203a6992 100644 Binary files a/resources/images/protocol/ippi/sip16x16-online.png and b/resources/images/protocol/ippi/sip16x16-online.png differ diff --git a/resources/images/protocol/ippi/sip16x16-phone.png b/resources/images/protocol/ippi/sip16x16-phone.png index 321ce8a35..1db411fbb 100644 Binary files a/resources/images/protocol/ippi/sip16x16-phone.png and b/resources/images/protocol/ippi/sip16x16-phone.png differ diff --git a/resources/images/protocol/iptel/sip-connecting.png b/resources/images/protocol/iptel/sip-connecting.png new file mode 100644 index 000000000..23f16ff8f Binary files /dev/null and b/resources/images/protocol/iptel/sip-connecting.png differ diff --git a/resources/images/protocol/iptel/sip16x16-away.png b/resources/images/protocol/iptel/sip16x16-away.png index 826ccf5c5..9c7e93c0f 100644 Binary files a/resources/images/protocol/iptel/sip16x16-away.png and b/resources/images/protocol/iptel/sip16x16-away.png differ diff --git a/resources/images/protocol/iptel/sip16x16-busy.png b/resources/images/protocol/iptel/sip16x16-busy.png index 4847c4486..3b8431ff8 100644 Binary files a/resources/images/protocol/iptel/sip16x16-busy.png and b/resources/images/protocol/iptel/sip16x16-busy.png differ diff --git a/resources/images/protocol/iptel/sip16x16-offline.png b/resources/images/protocol/iptel/sip16x16-offline.png index 4295d206c..499d85fcf 100644 Binary files a/resources/images/protocol/iptel/sip16x16-offline.png and b/resources/images/protocol/iptel/sip16x16-offline.png differ diff --git a/resources/images/protocol/iptel/sip16x16-online.png b/resources/images/protocol/iptel/sip16x16-online.png index b361b7f60..68b460b69 100644 Binary files a/resources/images/protocol/iptel/sip16x16-online.png and b/resources/images/protocol/iptel/sip16x16-online.png differ diff --git a/resources/images/protocol/iptel/sip16x16-phone.png b/resources/images/protocol/iptel/sip16x16-phone.png index 01db50a5a..10de01e1b 100644 Binary files a/resources/images/protocol/iptel/sip16x16-phone.png and b/resources/images/protocol/iptel/sip16x16-phone.png differ diff --git a/resources/images/protocol/irc/cr16-action-irc_away.png b/resources/images/protocol/irc/cr16-action-irc_away.png index d7572e1f8..9fb5e1927 100644 Binary files a/resources/images/protocol/irc/cr16-action-irc_away.png and b/resources/images/protocol/irc/cr16-action-irc_away.png differ diff --git a/resources/images/protocol/irc/cr16-action-irc_connecting-1.png b/resources/images/protocol/irc/cr16-action-irc_connecting-1.png new file mode 100644 index 000000000..0df64873f Binary files /dev/null and b/resources/images/protocol/irc/cr16-action-irc_connecting-1.png differ diff --git a/resources/images/protocol/irc/cr16-action-irc_offline.png b/resources/images/protocol/irc/cr16-action-irc_offline.png index fe5894a85..f4c69dd2f 100644 Binary files a/resources/images/protocol/irc/cr16-action-irc_offline.png and b/resources/images/protocol/irc/cr16-action-irc_offline.png differ diff --git a/resources/images/protocol/irc/cr16-action-irc_online.png b/resources/images/protocol/irc/cr16-action-irc_online.png index c5678d1ef..147ad6f3a 100644 Binary files a/resources/images/protocol/irc/cr16-action-irc_online.png and b/resources/images/protocol/irc/cr16-action-irc_online.png differ diff --git a/resources/images/protocol/irc/cr16-action-irc_op.png b/resources/images/protocol/irc/cr16-action-irc_op.png index 6b14cf14a..dbdaf1af1 100644 Binary files a/resources/images/protocol/irc/cr16-action-irc_op.png and b/resources/images/protocol/irc/cr16-action-irc_op.png differ diff --git a/resources/images/protocol/irc/cr16-action-irc_server.png b/resources/images/protocol/irc/cr16-action-irc_server.png index b7a3cc24c..7a19deaf0 100644 Binary files a/resources/images/protocol/irc/cr16-action-irc_server.png and b/resources/images/protocol/irc/cr16-action-irc_server.png differ diff --git a/resources/images/protocol/irc/cr16-action-irc_voice.png b/resources/images/protocol/irc/cr16-action-irc_voice.png index 6a9b5aafe..a3a171d6e 100644 Binary files a/resources/images/protocol/irc/cr16-action-irc_voice.png and b/resources/images/protocol/irc/cr16-action-irc_voice.png differ diff --git a/resources/images/protocol/irc/googletalk3_131.png b/resources/images/protocol/irc/googletalk3_131.png new file mode 100644 index 000000000..6ed26c489 Binary files /dev/null and b/resources/images/protocol/irc/googletalk3_131.png differ diff --git a/resources/images/protocol/jabber/status16x16-away.png b/resources/images/protocol/jabber/status16x16-away.png index 23ba92f99..27459b936 100644 Binary files a/resources/images/protocol/jabber/status16x16-away.png and b/resources/images/protocol/jabber/status16x16-away.png differ diff --git a/resources/images/protocol/jabber/status16x16-connecting.png b/resources/images/protocol/jabber/status16x16-connecting.png new file mode 100644 index 000000000..4fc092993 Binary files /dev/null and b/resources/images/protocol/jabber/status16x16-connecting.png differ diff --git a/resources/images/protocol/jabber/status16x16-dnd.png b/resources/images/protocol/jabber/status16x16-dnd.png index 265505779..b9c18d108 100644 Binary files a/resources/images/protocol/jabber/status16x16-dnd.png and b/resources/images/protocol/jabber/status16x16-dnd.png differ diff --git a/resources/images/protocol/jabber/status16x16-ffc.png b/resources/images/protocol/jabber/status16x16-ffc.png index 3e553ba96..cbe204ef8 100644 Binary files a/resources/images/protocol/jabber/status16x16-ffc.png and b/resources/images/protocol/jabber/status16x16-ffc.png differ diff --git a/resources/images/protocol/jabber/status16x16-offline.png b/resources/images/protocol/jabber/status16x16-offline.png index 7989eb70c..9b5466131 100644 Binary files a/resources/images/protocol/jabber/status16x16-offline.png and b/resources/images/protocol/jabber/status16x16-offline.png differ diff --git a/resources/images/protocol/jabber/status16x16-online.png b/resources/images/protocol/jabber/status16x16-online.png index 918cd6e76..81b2cf6fb 100644 Binary files a/resources/images/protocol/jabber/status16x16-online.png and b/resources/images/protocol/jabber/status16x16-online.png differ diff --git a/resources/images/protocol/jabber/status16x16-phone.png b/resources/images/protocol/jabber/status16x16-phone.png index b9e3d7cdd..94599ffc7 100644 Binary files a/resources/images/protocol/jabber/status16x16-phone.png and b/resources/images/protocol/jabber/status16x16-phone.png differ diff --git a/resources/images/protocol/jabber/status16x16-xa.png b/resources/images/protocol/jabber/status16x16-xa.png index 7602bb5aa..87048707b 100644 Binary files a/resources/images/protocol/jabber/status16x16-xa.png and b/resources/images/protocol/jabber/status16x16-xa.png differ diff --git a/resources/images/protocol/msn/msn16x16-away.png b/resources/images/protocol/msn/msn16x16-away.png index 67e3468f6..77887afa7 100644 Binary files a/resources/images/protocol/msn/msn16x16-away.png and b/resources/images/protocol/msn/msn16x16-away.png differ diff --git a/resources/images/protocol/msn/msn16x16-brb.png b/resources/images/protocol/msn/msn16x16-brb.png index 3853ab692..f59d99b34 100644 Binary files a/resources/images/protocol/msn/msn16x16-brb.png and b/resources/images/protocol/msn/msn16x16-brb.png differ diff --git a/resources/images/protocol/msn/msn16x16-busy.png b/resources/images/protocol/msn/msn16x16-busy.png index c7153640a..e77cec36c 100644 Binary files a/resources/images/protocol/msn/msn16x16-busy.png and b/resources/images/protocol/msn/msn16x16-busy.png differ diff --git a/resources/images/protocol/msn/msn16x16-connecting.png b/resources/images/protocol/msn/msn16x16-connecting.png new file mode 100644 index 000000000..58e5502e3 Binary files /dev/null and b/resources/images/protocol/msn/msn16x16-connecting.png differ diff --git a/resources/images/protocol/msn/msn16x16-invisible.png b/resources/images/protocol/msn/msn16x16-invisible.png index 5997618e2..7c803b6fc 100644 Binary files a/resources/images/protocol/msn/msn16x16-invisible.png and b/resources/images/protocol/msn/msn16x16-invisible.png differ diff --git a/resources/images/protocol/msn/msn16x16-lunch.png b/resources/images/protocol/msn/msn16x16-lunch.png index e9b54cae5..c4381b3e5 100644 Binary files a/resources/images/protocol/msn/msn16x16-lunch.png and b/resources/images/protocol/msn/msn16x16-lunch.png differ diff --git a/resources/images/protocol/msn/msn16x16-na.png b/resources/images/protocol/msn/msn16x16-na.png index ad76824bf..2d9f65364 100644 Binary files a/resources/images/protocol/msn/msn16x16-na.png and b/resources/images/protocol/msn/msn16x16-na.png differ diff --git a/resources/images/protocol/msn/msn16x16-offline.png b/resources/images/protocol/msn/msn16x16-offline.png index 1662d652c..b16e848df 100644 Binary files a/resources/images/protocol/msn/msn16x16-offline.png and b/resources/images/protocol/msn/msn16x16-offline.png differ diff --git a/resources/images/protocol/msn/msn16x16-online.png b/resources/images/protocol/msn/msn16x16-online.png index a6dcfe9b5..61c08c884 100644 Binary files a/resources/images/protocol/msn/msn16x16-online.png and b/resources/images/protocol/msn/msn16x16-online.png differ diff --git a/resources/images/protocol/msn/msn16x16-phone.png b/resources/images/protocol/msn/msn16x16-phone.png index d04b37832..92b797a8b 100644 Binary files a/resources/images/protocol/msn/msn16x16-phone.png and b/resources/images/protocol/msn/msn16x16-phone.png differ diff --git a/resources/images/protocol/sip/sip-connecting.png b/resources/images/protocol/sip/sip-connecting.png new file mode 100644 index 000000000..3709a52a0 Binary files /dev/null and b/resources/images/protocol/sip/sip-connecting.png differ diff --git a/resources/images/protocol/sip/sip16x16-away.png b/resources/images/protocol/sip/sip16x16-away.png index 94539c3f6..787205675 100644 Binary files a/resources/images/protocol/sip/sip16x16-away.png and b/resources/images/protocol/sip/sip16x16-away.png differ diff --git a/resources/images/protocol/sip/sip16x16-busy.png b/resources/images/protocol/sip/sip16x16-busy.png index 295dcfc73..299e2fc31 100644 Binary files a/resources/images/protocol/sip/sip16x16-busy.png and b/resources/images/protocol/sip/sip16x16-busy.png differ diff --git a/resources/images/protocol/sip/sip16x16-offline.png b/resources/images/protocol/sip/sip16x16-offline.png index ab47e5a55..ecb6d4cac 100644 Binary files a/resources/images/protocol/sip/sip16x16-offline.png and b/resources/images/protocol/sip/sip16x16-offline.png differ diff --git a/resources/images/protocol/sip/sip16x16-online.png b/resources/images/protocol/sip/sip16x16-online.png index cc8e0d476..b6801b64c 100644 Binary files a/resources/images/protocol/sip/sip16x16-online.png and b/resources/images/protocol/sip/sip16x16-online.png differ diff --git a/resources/images/protocol/sip/sip16x16-phone.png b/resources/images/protocol/sip/sip16x16-phone.png index b056a34f1..279d39651 100644 Binary files a/resources/images/protocol/sip/sip16x16-phone.png and b/resources/images/protocol/sip/sip16x16-phone.png differ diff --git a/resources/images/protocol/sip2sip/sip16x16-away.png b/resources/images/protocol/sip2sip/sip16x16-away.png index 2212efdd1..cc2d146e7 100644 Binary files a/resources/images/protocol/sip2sip/sip16x16-away.png and b/resources/images/protocol/sip2sip/sip16x16-away.png differ diff --git a/resources/images/protocol/sip2sip/sip16x16-busy.png b/resources/images/protocol/sip2sip/sip16x16-busy.png index 257c307f6..b3e14e2a5 100644 Binary files a/resources/images/protocol/sip2sip/sip16x16-busy.png and b/resources/images/protocol/sip2sip/sip16x16-busy.png differ diff --git a/resources/images/protocol/sip2sip/sip16x16-offline.png b/resources/images/protocol/sip2sip/sip16x16-offline.png index 8506462fc..ca74f6485 100644 Binary files a/resources/images/protocol/sip2sip/sip16x16-offline.png and b/resources/images/protocol/sip2sip/sip16x16-offline.png differ diff --git a/resources/images/protocol/sip2sip/sip16x16-online.png b/resources/images/protocol/sip2sip/sip16x16-online.png index 389e58351..cd05e31a0 100644 Binary files a/resources/images/protocol/sip2sip/sip16x16-online.png and b/resources/images/protocol/sip2sip/sip16x16-online.png differ diff --git a/resources/images/protocol/sip2sip/sip16x16-phone.png b/resources/images/protocol/sip2sip/sip16x16-phone.png index 914d2e78c..0babcebe8 100644 Binary files a/resources/images/protocol/sip2sip/sip16x16-phone.png and b/resources/images/protocol/sip2sip/sip16x16-phone.png differ diff --git a/resources/images/protocol/ssh/ssh-connected.png b/resources/images/protocol/ssh/ssh-connected.png index 9135523ba..ac168e08c 100644 Binary files a/resources/images/protocol/ssh/ssh-connected.png and b/resources/images/protocol/ssh/ssh-connected.png differ diff --git a/resources/images/protocol/ssh/ssh-connecting.png b/resources/images/protocol/ssh/ssh-connecting.png index 47f61aeb5..5ae7f03de 100644 Binary files a/resources/images/protocol/ssh/ssh-connecting.png and b/resources/images/protocol/ssh/ssh-connecting.png differ diff --git a/resources/images/protocol/ssh/ssh-filetransfer.png b/resources/images/protocol/ssh/ssh-filetransfer.png index d92d6aa3b..50eca81af 100644 Binary files a/resources/images/protocol/ssh/ssh-filetransfer.png and b/resources/images/protocol/ssh/ssh-filetransfer.png differ diff --git a/resources/images/protocol/ssh/ssh-na.png b/resources/images/protocol/ssh/ssh-na.png index d0d6265c7..90e502848 100644 Binary files a/resources/images/protocol/ssh/ssh-na.png and b/resources/images/protocol/ssh/ssh-na.png differ diff --git a/resources/images/protocol/ssh/ssh-offline.png b/resources/images/protocol/ssh/ssh-offline.png index 51c83b2cf..c8c429aaf 100644 Binary files a/resources/images/protocol/ssh/ssh-offline.png and b/resources/images/protocol/ssh/ssh-offline.png differ diff --git a/resources/images/protocol/ssh/ssh-online.png b/resources/images/protocol/ssh/ssh-online.png index 14683db95..e67f41879 100644 Binary files a/resources/images/protocol/ssh/ssh-online.png and b/resources/images/protocol/ssh/ssh-online.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-away.png b/resources/images/protocol/yahoo/yahoo16x16-away.png index 43df89d0d..84233cb30 100644 Binary files a/resources/images/protocol/yahoo/yahoo16x16-away.png and b/resources/images/protocol/yahoo/yahoo16x16-away.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-busy.png b/resources/images/protocol/yahoo/yahoo16x16-busy.png index 760da06f7..22d2a0262 100644 Binary files a/resources/images/protocol/yahoo/yahoo16x16-busy.png and b/resources/images/protocol/yahoo/yahoo16x16-busy.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-connecting.png b/resources/images/protocol/yahoo/yahoo16x16-connecting.png new file mode 100644 index 000000000..ff2e1d0ba Binary files /dev/null and b/resources/images/protocol/yahoo/yahoo16x16-connecting.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-idle.png b/resources/images/protocol/yahoo/yahoo16x16-idle.png index 155544bc8..9965aec3c 100644 Binary files a/resources/images/protocol/yahoo/yahoo16x16-idle.png and b/resources/images/protocol/yahoo/yahoo16x16-idle.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-invisible.png b/resources/images/protocol/yahoo/yahoo16x16-invisible.png index 076f22e05..6141e8925 100644 Binary files a/resources/images/protocol/yahoo/yahoo16x16-invisible.png and b/resources/images/protocol/yahoo/yahoo16x16-invisible.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-lunch.png b/resources/images/protocol/yahoo/yahoo16x16-lunch.png index 534cf418b..3ebf9853a 100644 Binary files a/resources/images/protocol/yahoo/yahoo16x16-lunch.png and b/resources/images/protocol/yahoo/yahoo16x16-lunch.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-na.png b/resources/images/protocol/yahoo/yahoo16x16-na.png index 0fea3c64d..9fe7984f0 100644 Binary files a/resources/images/protocol/yahoo/yahoo16x16-na.png and b/resources/images/protocol/yahoo/yahoo16x16-na.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-offline.png b/resources/images/protocol/yahoo/yahoo16x16-offline.png index e3e8733c1..a6144f8f1 100644 Binary files a/resources/images/protocol/yahoo/yahoo16x16-offline.png and b/resources/images/protocol/yahoo/yahoo16x16-offline.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-online.png b/resources/images/protocol/yahoo/yahoo16x16-online.png index d144cab00..a04a0fb11 100644 Binary files a/resources/images/protocol/yahoo/yahoo16x16-online.png and b/resources/images/protocol/yahoo/yahoo16x16-online.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-phone.png b/resources/images/protocol/yahoo/yahoo16x16-phone.png index 01fa92b3c..0ef5cf847 100644 Binary files a/resources/images/protocol/yahoo/yahoo16x16-phone.png and b/resources/images/protocol/yahoo/yahoo16x16-phone.png differ diff --git a/resources/images/protocol/yahoo/yahoo16x16-vacation.png b/resources/images/protocol/yahoo/yahoo16x16-vacation.png index de0f7e718..5ebb3dc5a 100644 Binary files a/resources/images/protocol/yahoo/yahoo16x16-vacation.png and b/resources/images/protocol/yahoo/yahoo16x16-vacation.png differ diff --git a/resources/images/protocol/zeroconf/zeroconf-away.png b/resources/images/protocol/zeroconf/zeroconf-away.png index 2ecf4bc4c..8265d5a0f 100644 Binary files a/resources/images/protocol/zeroconf/zeroconf-away.png and b/resources/images/protocol/zeroconf/zeroconf-away.png differ diff --git a/resources/images/protocol/zeroconf/zeroconf-dnd.png b/resources/images/protocol/zeroconf/zeroconf-dnd.png index 23bd06780..fa1b70bc0 100644 Binary files a/resources/images/protocol/zeroconf/zeroconf-dnd.png and b/resources/images/protocol/zeroconf/zeroconf-dnd.png differ diff --git a/resources/images/protocol/zeroconf/zeroconf-invisible.png b/resources/images/protocol/zeroconf/zeroconf-invisible.png index 35dd6b42a..e3bd0cfc8 100644 Binary files a/resources/images/protocol/zeroconf/zeroconf-invisible.png and b/resources/images/protocol/zeroconf/zeroconf-invisible.png differ diff --git a/resources/images/protocol/zeroconf/zeroconf-offline.png b/resources/images/protocol/zeroconf/zeroconf-offline.png index 35609ffd2..de37240bd 100644 Binary files a/resources/images/protocol/zeroconf/zeroconf-offline.png and b/resources/images/protocol/zeroconf/zeroconf-offline.png differ diff --git a/resources/images/protocol/zeroconf/zeroconf-online.png b/resources/images/protocol/zeroconf/zeroconf-online.png index 3bde6f69b..be66b1b8f 100644 Binary files a/resources/images/protocol/zeroconf/zeroconf-online.png and b/resources/images/protocol/zeroconf/zeroconf-online.png differ diff --git a/resources/styles/defaultStyle.css b/resources/styles/defaultStyle.css index a737e43bf..356cecd82 100644 --- a/resources/styles/defaultStyle.css +++ b/resources/styles/defaultStyle.css @@ -1,6 +1,6 @@ h1 { - background-color: #c6d0e1; + background-color: #6a6868; margin: 0px; text-align: center; font-weight: bold; @@ -10,14 +10,18 @@ h1 h2 { margin: 0px; - font-size: 100%; - color: #ef7b1e; + padding-top: 4px; + padding-left: 10px; + font-size: 10px; + color: #488fe7; } h3 { margin: 0px; - font-size: 100%; + padding-top: 4px; + padding-left: 10px; + font-size: 10px; color: #2e538b; } @@ -47,8 +51,8 @@ h6 p { margin: 0px; + width: 100%; font-size: 100%; - font-weight: bold; color: #62BD80; } diff --git a/resources/styles/defaultStyle.txt b/resources/styles/defaultStyle.txt new file mode 100644 index 000000000..60badf593 --- /dev/null +++ b/resources/styles/defaultStyle.txt @@ -0,0 +1,65 @@ +h1 +{ + background-color: #6a6868; + margin: 0px; + text-align: center; + font-weight: bold; + font-size: 100%; +} + +h2 +{ + margin: 0px; + font-size: 100%; + color: #488fe7; +} + +h3 +{ + margin: 0px; + font-size: 100%; + color: #2e538b; +} + +h4 +{ + margin: 0px; + font-size: 100%; + font-weight: bold; + color: #FFC875; +} + +h5 +{ + margin: 0px; + font-size: 100%; + font-weight: bold; + color: #CC0000; +} + +h6 +{ + margin: 0px; + font-size: 100%; + font-weight: bold; + color: #990000; +} +p +{ + margin: 0px; + width: 100%; + font-size: 100%; + font-weight: bold; + color: #62BD80; +} + +div +{ + font-size: 100%; + color: #000000; +} + +h7 +{ + background-color: #FFF4AB; +} diff --git a/resources/styles/stylebackup.txt b/resources/styles/stylebackup.txt new file mode 100644 index 000000000..acedf9892 --- /dev/null +++ b/resources/styles/stylebackup.txt @@ -0,0 +1,1949 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat; + +import java.awt.*; +import java.awt.datatransfer.*; +import java.awt.event.*; +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.Map.Entry; +import java.util.Map; +import java.util.regex.*; + +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.text.*; +import javax.swing.text.html.*; +import javax.swing.text.html.HTML.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.impl.gui.customcontrols.*; +import net.java.sip.communicator.impl.gui.main.chat.history.*; +import net.java.sip.communicator.impl.gui.main.chat.menus.*; +import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.replacement.*; +import net.java.sip.communicator.service.replacement.smilies.*; +import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.skin.*; +import net.java.sip.communicator.util.swing.*; +import net.java.sip.communicator.util.swing.SwingWorker; + +/** + * The ChatConversationPanel is the panel, where all sent and received + * messages appear. All data is stored in an HTML document. An external CSS file + * is applied to the document to provide the look&feel. All smileys and link + * strings are processed and finally replaced by corresponding images and HTML + * links. + * + * @author Yana Stamcheva + * @author Lubomir Marinov + * @author Adam Netocny + */ +public class ChatConversationPanel + extends SCScrollPane + implements HyperlinkListener, + MouseListener, + ClipboardOwner, + Skinnable +{ + /** + * The Logger used by the ChatConversationPanel class and + * its instances for logging output. + */ + private static final Logger logger + = Logger.getLogger(ChatConversationPanel.class); + + /** + * The closing tag of the PLAINTEXT HTML element. + */ + private static final String END_PLAINTEXT_TAG = ""; + + /** + * The opening tag of the PLAINTEXT HTML element. + */ + private static final String START_PLAINTEXT_TAG = ""; + + /** + * The regular expression (in the form of compiled <tt>Pattern</tt>) which + * matches URLs for the purposed of turning them into links. + */ + private static final Pattern URL_PATTERN + = Pattern.compile( + "(" + + "(\\bwww\\.[^\\s<>\"]+\\.[^\\s<>\"]+/*[?#]*(\\w+[&=;?]\\w+)*\\b)" // wwwURL + + "|" + + "(\\bjitsi\\:[^\\s<>\"]+\\.[^\\s<>\"]*\\b)" // internalURL + + "|" + + "(\\b\\w+://[^\\s<>\"]+/*[?#]*(\\w+[&=;?]\\w+)*\\b)" // protocolURL + + ")"); + + /** + * List for observing text messages. + */ + private Set<ChatLinkClickedListener> chatLinkClickedListeners = + new HashSet<ChatLinkClickedListener>(); + + /** + * The component rendering chat conversation panel text. + */ + private final JTextPane chatTextPane = new MyTextPane(); + + /** + * The editor kit used by the text component. + */ + private final HTMLEditorKit editorKit; + + /** + * The document used by the text component. + */ + private HTMLDocument document; + + /** + * The parent container. + */ + private final ChatConversationContainer chatContainer; + + /** + * The menu shown on right button mouse click. + */ + private final ChatRightButtonMenu rightButtonMenu; + + /** + * The currently shown href. + */ + private String currentHref; + + /** + * The copy link item, contained in the right mouse click menu. + */ + private final JMenuItem copyLinkItem; + + /** + * The open link item, contained in the right mouse click menu. + */ + private final JMenuItem openLinkItem; + + /** + * The right mouse click menu separator. + */ + private final JSeparator copyLinkSeparator = new JSeparator(); + + /** + * The timestamp of the last incoming message. + */ + private long lastIncomingMsgTimestamp; + + /** + * Indicates if this component is rendering a history conversation. + */ + private final boolean isHistory; + + /** + * The html text content type. + */ + public static final String HTML_CONTENT_TYPE = "text/html"; + + /** + * The plain text content type. + */ + public static final String TEXT_CONTENT_TYPE = "text/plain"; + + /** + * The indicator which determines whether an automatic scroll to the bottom + * of {@link #chatTextPane} is to be performed. + */ + private boolean scrollToBottomIsPending = false; + + private final static String INCOMING_MESSAGE_IMAGE_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.INCOMING_MESSAGE_BACKGROUND").toString(); + + /** + * The implementation of the routine which scrolls {@link #chatTextPane} to its + * bottom. + */ + private final Runnable scrollToBottomRunnable = new Runnable() + { + /* + * Implements Runnable#run(). + */ + public void run() + { + JScrollBar verticalScrollBar = getVerticalScrollBar(); + + if (verticalScrollBar != null) + { + // We need to call both methods in order to be sure to scroll + // to the bottom of the text even when the user has selected + // something (changed the caret) or when a new tab has been + // added or the window has been resized. + verticalScrollBar.setValue(verticalScrollBar.getMaximum()); + chatTextPane.setCaretPosition(document.getLength()); + } + } + }; + + /** + * Creates an instance of <tt>ChatConversationPanel</tt>. + * + * @param chatContainer The parent <tt>ChatConversationContainer</tt>. + */ + public ChatConversationPanel(ChatConversationContainer chatContainer) + { + editorKit = new SIPCommHTMLEditorKit(this); + + this.chatContainer = chatContainer; + + isHistory = (chatContainer instanceof HistoryWindow); + + this.rightButtonMenu = new ChatRightButtonMenu(this); + + this.document = (HTMLDocument) editorKit.createDefaultDocument(); + + this.chatTextPane.setEditorKitForContentType("text/html", editorKit); + this.chatTextPane.setEditorKit(editorKit); + this.chatTextPane.setEditable(false); + this.chatTextPane.setDocument(document); + this.chatTextPane.setDragEnabled(true); + + chatTextPane.putClientProperty( + JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE); + Constants.loadSimpleStyle( + document.getStyleSheet(), chatTextPane.getFont()); + + this.chatTextPane.addHyperlinkListener(this); + this.chatTextPane.addMouseListener(this); + this.chatTextPane.setCursor( + Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); + + this.setWheelScrollingEnabled(true); + + this.setViewportView(chatTextPane); + + this.setBorder(null); + + this.setHorizontalScrollBarPolicy( + JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + ToolTipManager.sharedInstance().registerComponent(chatTextPane); + + String copyLinkString + = GuiActivator.getResources().getI18NString("service.gui.COPY_LINK"); + + copyLinkItem + = new JMenuItem(copyLinkString, + new ImageIcon(ImageLoader.getImage(ImageLoader.COPY_ICON))); + + copyLinkItem.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + StringSelection stringSelection = new StringSelection( + currentHref); + Clipboard clipboard = Toolkit.getDefaultToolkit() + .getSystemClipboard(); + clipboard.setContents(stringSelection, + ChatConversationPanel.this); + } + }); + + String openLinkString + = GuiActivator.getResources().getI18NString( + "service.gui.OPEN_IN_BROWSER"); + + openLinkItem = + new JMenuItem( + openLinkString, + new ImageIcon(ImageLoader.getImage(ImageLoader.BROWSER_ICON))); + + openLinkItem.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + GuiActivator.getBrowserLauncher().openURL(currentHref); + + // after opening the link remove the currentHref to avoid + // clicking on the window to gain focus to open the link again + ChatConversationPanel.this.currentHref = ""; + } + }); + + openLinkItem.setMnemonic( + GuiActivator.getResources().getI18nMnemonic( + "service.gui.OPEN_IN_BROWSER")); + + copyLinkItem.setMnemonic( + GuiActivator.getResources().getI18nMnemonic( + "service.gui.COPY_LINK")); + + /* + * When we append a new message (regardless of whether it is a string or + * an UI component), we want to make it visible in the viewport of this + * JScrollPane so that the user can see it. + */ + ComponentListener componentListener = new ComponentAdapter() + { + @Override + public void componentResized(ComponentEvent e) + { + synchronized (scrollToBottomRunnable) + { + if (!scrollToBottomIsPending) + return; + scrollToBottomIsPending = false; + + /* + * Yana Stamcheva, pointed out that Java 5 (on Linux only?) + * needs invokeLater for JScrollBar. + */ + SwingUtilities.invokeLater(scrollToBottomRunnable); + } + } + }; + + chatTextPane.addComponentListener(componentListener); + getViewport().addComponentListener(componentListener); + } + + /** + * Overrides Component#setBounds(int, int, int, int) in order to determine + * whether an automatic scroll of #chatTextPane to its bottom will be + * necessary at a later time in order to keep its vertical scroll bar to its + * bottom after the realization of the resize if it is at its bottom before + * the resize. + */ + @Override + public void setBounds(int x, int y, int width, int height) + { + synchronized (scrollToBottomRunnable) + { + JScrollBar verticalScrollBar = getVerticalScrollBar(); + + if (verticalScrollBar != null) + { + BoundedRangeModel verticalScrollBarModel + = verticalScrollBar.getModel(); + + if ((verticalScrollBarModel.getValue() + + verticalScrollBarModel.getExtent() + >= verticalScrollBarModel.getMaximum()) + || !verticalScrollBar.isVisible()) + scrollToBottomIsPending = true; + } + } + + super.setBounds(x, y, width, height); + } + + /** + * Initializes the editor by adding a header containing the date. + * TODO: remove if not used anymore + */ +// private void initEditor() +// { +// Element root = this.document.getDefaultRootElement(); +// +// Date date = new Date(System.currentTimeMillis()); +// +// String chatHeader = "<h1>" + GuiUtils.formatDate(date) + " " + "</h1>"; +// +// try +// { +// this.document.insertAfterStart(root, chatHeader); +// } +// catch (BadLocationException e) +// { +// logger.error("Insert in the HTMLDocument failed.", e); +// } +// catch (IOException e) +// { +// logger.error("Insert in the HTMLDocument failed.", e); +// } +// } + + /** + * Retrieves the contents of the sent message with the given ID. + * + * @param messageUID The ID of the message to retrieve. + * @return The contents of the message, or null if the message is not found. + */ + public String getMessageContents(String messageUID) + { + Element root = document.getDefaultRootElement(); + Element e = document.getElement(root, Attribute.ID, messageUID); + if (e == null) + { + logger.warn("Could not find message with ID" + messageUID); + return null; + } + + int elemLen = e.getEndOffset() - e.getStartOffset(); + String res = null; + try + { + res = document.getText(e.getStartOffset(), elemLen); + } + catch (BadLocationException exc) + { + logger.warn("Could not get message contents for message " + + "with ID" + messageUID, exc); + } + return res; + } + + /** + * Creates a tag that shows the last edit time of a message, in the format + * (Edited at ...). + * If <tt>date < 0</tt>, returns an empty tag that serves as a placeholder + * for future corrections of this message. + * + * @param messageUID The ID of the edited message. + * @param date The date when the message was last edited, or -1 to generate + * an empty tag. + * @return The string representation of the tag. + */ + private String generateEditedAtTag(String messageUID, long date) + { + StringBuilder res = new StringBuilder(); + // Use a <cite /> tag here as most of the other inline tags (e.g. h1-7, + // b, i) cause different problems when used in setOuterHTML. + res.append("<cite id='"); + res.append(messageUID); + res.append("-editedAt'> "); + if (date > 0) + { + res.append("&nbsp;"); + String contents = GuiActivator.getResources().getI18NString( + "service.gui.EDITED_AT", + new String[] { GuiUtils.formatTime(date) } + ); + res.append(contents); + } + res.append("</cite>"); + return res.toString(); + } + + /** + * Processes the message given by the parameters. + * + * @param chatMessage the message + * @param keyword a substring of <tt>chatMessage</tt> to be highlighted upon + * display of <tt>chatMessage</tt> in the UI + * @return the processed message + */ + public String processMessage(ChatMessage chatMessage, String keyword) + { + String contactName = chatMessage.getContactName(); + String contactDisplayName = chatMessage.getContactDisplayName(); + if (contactDisplayName == null + || contactDisplayName.trim().length() <= 0) + contactDisplayName = contactName; + + String contentType = chatMessage.getContentType(); + long date = chatMessage.getDate(); + String messageType = chatMessage.getMessageType(); + String messageTitle = chatMessage.getMessageTitle(); + String message = chatMessage.getMessage(); + String messageUID = chatMessage.getMessageUID(); + + String msgID = "message"; + String msgHeaderID = "messageHeader"; + String chatString = ""; + String endHeaderTag = ""; + String dateString = getDateString(date); + String idAttr = messageUID == null ? "" : " id='" + messageUID + "'"; + String dateAttr = " date='" + date + "'"; + String editedAtTag = generateEditedAtTag(messageUID, -1); + + String startHistoryDivTag + = "<DIV identifier=\"" + msgID + "\" style=\"color:#707070;\">"; + String startSystemDivTag + = "<DIV identifier=\"systemMessage\" style=\"color:#627EB7;\">"; + String endDivTag = "</DIV>"; + + String startPlainTextTag; + String endPlainTextTag; + + if (HTML_CONTENT_TYPE.equals(contentType)) + { + startPlainTextTag = ""; + endPlainTextTag = ""; + } + else + { + startPlainTextTag = START_PLAINTEXT_TAG; + endPlainTextTag = END_PLAINTEXT_TAG; + } + + if (messageType.equals(Chat.INCOMING_MESSAGE)) + { + this.lastIncomingMsgTimestamp = System.currentTimeMillis(); + + StringBuffer headerBuffer = new StringBuffer(); + + headerBuffer.append("<h2 identifier=\"" + msgHeaderID + "\""); + headerBuffer.append(dateAttr + ">"); + headerBuffer.append("<a style=\"color:#488fe7;"); + headerBuffer.append("font-weight:bold;"); + headerBuffer.append("text-decoration:none;\" "); + headerBuffer.append("href=\"" + contactName + "\">"); + headerBuffer.append(dateString + contactDisplayName + " at " + + GuiUtils.formatTime(date) + editedAtTag); + headerBuffer.append("</a></h2>"); + + chatString = createIncomingMessageTag(msgID + "\"" + idAttr, + headerBuffer.toString(), + startPlainTextTag + + formatMessage(message, contentType, keyword) + + endPlainTextTag); +System.out.println("CHAT STRING OSHTE TUUUUUK=======" + chatString); +// chatString = "<h2 identifier=\"" + msgHeaderID + "\"" +// + " date=\"" + date + "\">" +// + "<a style=\"color:#488fe7;" +// + "font-weight:bold;" +// + "text-decoration:none;\" " +// + "href=\"" + contactName + "\">"; +// +// endHeaderTag = "</a></h2>"; + +// String startDivTag = "<DIV identifier=\"" + msgID +// + "\" style=\""+ createIncomingMessageStyle()+"\">"; +// +// chatString +// += dateString + contactDisplayName + " at " +// + GuiUtils.formatTime(date) +// + endHeaderTag + startDivTag + startPlainTextTag +// + formatMessage(message, contentType, keyword) +// + endPlainTextTag + endDivTag; + + } + else if (messageType.equals(Chat.SMS_MESSAGE)) + { + chatString = "<h2 identifier=\"" + + msgHeaderID + + "\" date=\"" + + date + "\">"; + + endHeaderTag = "</h2>"; + + String startDivTag = "<DIV identifier=\"" + msgID + + "\" style=\""+ createSmsMessageStyle()+"\">"; + + chatString + += "SMS: " + dateString + contactName + " at " + + GuiUtils.formatTime(date) + endHeaderTag + startDivTag + + startPlainTextTag + + formatMessage(message, contentType, keyword) + + endPlainTextTag + endDivTag; + } + else if (messageType.equals(Chat.OUTGOING_MESSAGE)) + { + chatString = "<h3 identifier=\"" + msgHeaderID + "\"" + + dateAttr + ">" + + "<a style=\"color:#6a6868;" + + "font-weight:bold;" + + "text-decoration:none;\" " + + "href=\"" + contactName + "\">"; + + endHeaderTag = "</a></h3>"; + + String startDivTag = "<DIV identifier=\"" + msgID + + "\" style=\""+ createOutgoingMessageStyle()+"\">"; + + chatString + += dateString + contactDisplayName + " at " + + GuiUtils.formatTime(date) + editedAtTag + endHeaderTag + + startDivTag + startPlainTextTag + + formatMessage(message, contentType, keyword) + + endPlainTextTag + endDivTag; + } + else if (messageType.equals(Chat.STATUS_MESSAGE)) + { + chatString = "<h4 identifier=\"statusMessage\" date=\"" + + date + "\">"; + endHeaderTag = "</h4>"; + + chatString + += GuiUtils.formatTime(date) + " " + contactName + " " + message + + endHeaderTag; + } + else if (messageType.equals(Chat.ACTION_MESSAGE)) + { + chatString = "<p identifier=\"actionMessage\" date=\"" + + date + "\">"; + endHeaderTag = "</p>"; + + chatString += "* " + GuiUtils.formatTime(date) + + " " + contactName + " " + + message + + endHeaderTag; + } + else if (messageType.equals(Chat.SYSTEM_MESSAGE)) + { + chatString + += startSystemDivTag + startPlainTextTag + + formatMessage(message, contentType, keyword) + + endPlainTextTag + endDivTag; + } + else if (messageType.equals(Chat.ERROR_MESSAGE)) + { + chatString = "<h6 identifier=\"" + + msgHeaderID + + "\" date=\"" + + date + "\">"; + + endHeaderTag = "</h6>"; + + String errorIcon = "<IMG SRC='" + + ImageLoader.getImageUri(ImageLoader.EXCLAMATION_MARK) + + "' </IMG>"; + + chatString += errorIcon + + messageTitle + + endHeaderTag + "<h5>" + message + "</h5>"; + } + else if (messageType.equals(Chat.HISTORY_INCOMING_MESSAGE)) + { + chatString = "<h2 identifier=\"" + msgHeaderID + "\"" + + dateAttr + ">" + + "<a style=\"color:#488fe7;" + + "font-weight:bold;" + + "text-decoration:none;\" " + + "href=\"" + contactName + "\">"; + + endHeaderTag = "</a></h2>"; + + chatString + += dateString + contactDisplayName + + " at " + GuiUtils.formatTime(date) + endHeaderTag + + editedAtTag + startHistoryDivTag + startPlainTextTag + + formatMessage(message, contentType, keyword) + + endPlainTextTag + endDivTag; + } + else if (messageType.equals(Chat.HISTORY_OUTGOING_MESSAGE)) + { + chatString = "<h3 identifier=\"" + msgHeaderID + "\"" + + dateAttr + ">" + + "<a style=\"color:#6a6868;" + + "font-weight:bold;" + + "text-decoration:none;\" " + + "href=\"" + contactName + "\">"; + + endHeaderTag = "</h3>"; + + chatString + += dateString + + contactDisplayName + " at " + GuiUtils.formatTime(date) + + editedAtTag + endHeaderTag + + startHistoryDivTag + startPlainTextTag + + formatMessage(message, contentType, keyword) + + endPlainTextTag + endDivTag; + } + + return chatString; + } + + /** + * Processes the message given by the parameters. + * + * @param chatMessage the message. + * @return the formatted message + */ + public String processMessage(ChatMessage chatMessage) + { + return processMessage(chatMessage, null); + } + + /** + * Replaces the contents of the message with ID of the corrected message + * specified in chatMessage, with this message. + * + * @param chatMessage A <tt>ChatMessage</tt> that contains all the required + * information to correct the old message. + */ + public void correctMessage(ChatMessage chatMessage) + { + String correctedUID = chatMessage.getCorrectedMessageUID(); + Element root = document.getDefaultRootElement(); + Element e = document.getElement(root, Attribute.ID, correctedUID); + if (e == null) + { + logger.warn("Could not find message with ID " + correctedUID); + return; + } + int len = e.getEndOffset() - e.getStartOffset(); + + StringBuilder newContents = new StringBuilder(); + String bgColor = GuiActivator.getResources().getColorString( + "service.gui.CHAT_EDIT_MESSAGE_BACKGROUND"); + newContents.append("<div identifier='message' id='"); + newContents.append(chatMessage.getMessageUID()); + newContents.append("' bgcolor='"); + newContents.append(bgColor); + newContents.append("'>"); + if (chatMessage.getContentType().equals(TEXT_CONTENT_TYPE)) + { + newContents.append(START_PLAINTEXT_TAG); + newContents.append(chatMessage.getMessage()); + newContents.append(END_PLAINTEXT_TAG); + } + else + { + newContents.append(chatMessage.getMessage()); + } + newContents.append("</div>"); + + Element header = document.getElement(root, Attribute.ID, + correctedUID + "-editedAt"); + + try + { + if (header != null) + { + String newHeaderContents = generateEditedAtTag( + chatMessage.getMessageUID(), chatMessage.getDate()); + document.setOuterHTML(header, newHeaderContents); + } + document.setOuterHTML(e, newContents.toString()); + } + catch (BadLocationException ex) + { + logger.error("Could not replace chat message", ex); + } + catch (IOException ex) + { + logger.error("Could not replace chat message", ex); + } + } + + /** + * Appends the given string at the end of the contained in this panel + * document. + * + * @param chatString the string to append + */ + public void appendMessageToEnd(String chatString, String contentType) + { + synchronized (scrollToBottomRunnable) + { + Element root = document.getDefaultRootElement(); + +// Need to call explicitly scrollToBottom, because for some +// reason the componentResized event isn't fired every time we +// add text. +// Replaced by the code on line: 573. +// +// scrollToBottomIsPending = true; +System.out.println("CHAT STRING+=========" + chatString); + try + { + document + .insertAfterEnd( + root.getElement(root.getElementCount() - 1), + chatString); + + // Need to call explicitly scrollToBottom, because for some + // reason the componentResized event isn't fired every time we + // add text. + SwingUtilities.invokeLater(scrollToBottomRunnable); + } + catch (BadLocationException e) + { + logger.error("Insert in the HTMLDocument failed.", e); + } + catch (IOException e) + { + logger.error("Insert in the HTMLDocument failed.", e); + } + if (!isHistory) + ensureDocumentSize(); + + // Process replacements. + final Element elem; + /* + * Check to make sure element isn't the first element in the HTML + * document. + */ + if (!(root.getElementCount() < 2)) + { + elem = root.getElement(root.getElementCount() - 2); + } + else + elem = root.getElement(1); + + /* + * Replacements will be processed only if it is enabled in the + * property + */ + if (GuiActivator.getConfigurationService().getBoolean( + ReplacementProperty.REPLACEMENT_ENABLE, true) + || GuiActivator.getConfigurationService().getBoolean( + ReplacementProperty.getPropertyName("SMILEY"), true)) + { + processReplacement(elem, chatString, contentType); + } + } + } + + /** + * Formats the given message. Processes the messages and replaces links to + * video/image sources with their previews or any other substitution. Spawns + * a separate thread for replacement. + * + * @param elem the element in the HTML Document. + * @param chatString the message. + */ + private void processReplacement(final Element elem, + final String chatString, + final String contentType) + { + final String chatFinal = chatString; + + SwingWorker worker = new SwingWorker() + { + public Object construct() throws Exception + { + String temp = "", msgStore = chatFinal; + + boolean isEnabled + = GuiActivator.getConfigurationService().getBoolean( + ReplacementProperty.REPLACEMENT_ENABLE, true); + + Map<String, ReplacementService> listSources + = GuiActivator.getReplacementSources(); + + Iterator<Entry<String, ReplacementService>> entrySetIter + = listSources.entrySet().iterator(); + + for (int i = 0; i < listSources.size(); i++) + { + Map.Entry<String, ReplacementService> entry + = entrySetIter.next(); + + ReplacementService source = entry.getValue(); + + boolean isSmiley + = source instanceof SmiliesReplacementService; + + if (!(GuiActivator.getConfigurationService().getBoolean( + ReplacementProperty.getPropertyName(source + .getSourceName()), true) && (isEnabled || isSmiley))) + continue; + + String sourcePattern = source.getPattern(); + Pattern p = Pattern.compile(sourcePattern, + Pattern.CASE_INSENSITIVE | Pattern.DOTALL); + + Matcher m = p.matcher(msgStore); + + String startPlainTextTag = ""; + String endPlainTextTag = ""; + + if (!HTML_CONTENT_TYPE.equals(contentType)) + { + startPlainTextTag = START_PLAINTEXT_TAG; + endPlainTextTag = END_PLAINTEXT_TAG; + } + + int count = 0, startPos = 0; + StringBuffer msgBuff = new StringBuffer(); + + while (m.find()) + { + count++; + msgBuff.append(msgStore.substring(startPos, m.start())); + startPos = m.end(); + + temp = source.getReplacement(m.group()); + + if(!temp.equals(m.group(0)) || source.getSourceName() + .equals("DIRECTIMAGE")) + { + if(isSmiley) + { + msgBuff.append(endPlainTextTag); + msgBuff.append("<IMG SRC=\""); + } + else + { + msgBuff.append( + "<IMG HEIGHT=\"90\" WIDTH=\"120\" SRC=\""); + } + + msgBuff.append(temp); + msgBuff.append("\" BORDER=\"0\" ALT=\""); + msgBuff.append(m.group(0)); + msgBuff.append("\"></IMG>"); + + if(isSmiley) + msgBuff.append(startPlainTextTag); + } + else + { + msgBuff.append( + msgStore.substring(m.start(), m.end())); + } + } + + msgBuff.append(msgStore.substring(startPos)); + + /* + * replace the msgStore variable with the current replaced + * message before next iteration + */ + if (!msgBuff.toString().equals(msgStore)) + { + msgStore = msgBuff.toString(); + } + } + + if (!msgStore.equals(chatFinal)) + { + synchronized (scrollToBottomRunnable) + { + scrollToBottomIsPending = true; + document.setOuterHTML(elem, msgStore.toString() + .substring(msgStore.indexOf("<DIV"))); + } + } + return ""; + } + }; + worker.start(); + } + + /** + * Ensures that the document won't become too big. When the document reaches + * a certain size the first message in the page is removed. + */ + private void ensureDocumentSize() + { + if (document.getLength() > Chat.CHAT_BUFFER_SIZE) + { + int msgElementCount = 0; + + Element firstMsgElement = null; + + int firstMsgIndex = 0; + + Element rootElement = this.document.getDefaultRootElement(); + // Count how many messages we have in the document. + for (int i = 0; i < rootElement.getElementCount(); i++) + { + String idAttr = (String) rootElement.getElement(i) + .getAttributes().getAttribute("identifier"); + + if(idAttr != null + && (idAttr.equals("message") + || idAttr.equals("statusMessage") + || idAttr.equals("systemMessage"))) + { + if(firstMsgElement == null) + { + firstMsgElement = rootElement.getElement(i); + firstMsgIndex = i; + } + + msgElementCount++; + } + } + + // If we doesn't have any known elements in the document or if we + // have only one long message we don't want to remove it. + if(firstMsgElement == null || msgElementCount < 2) + return; + + try + { + // Remove the header of the message if such exists. + if(firstMsgIndex > 0) + { + Element headerElement = rootElement.getElement(firstMsgIndex - 1); + + String idAttr = (String) headerElement + .getAttributes().getAttribute("identifier"); + + if(idAttr != null && idAttr.equals("messageHeader")) + { + this.document.remove(headerElement.getStartOffset(), + headerElement.getEndOffset() + - headerElement.getStartOffset()); + } + } + + // Remove the message itself. + this.document.remove(firstMsgElement.getStartOffset(), + firstMsgElement.getEndOffset() + - firstMsgElement.getStartOffset()); + } + catch (BadLocationException e) + { + logger.error("Error removing messages from chat: ", e); + } + } + } + + /** + * Highlights keywords searched in the history. + * + * @param message the source message + * @param contentType the content type + * @param keyword the searched keyword + * @return the formatted message + */ + private String processKeyword( String message, + String contentType, + String keyword) + { + String startPlainTextTag; + String endPlainTextTag; + + if (HTML_CONTENT_TYPE.equals(contentType)) + { + startPlainTextTag = ""; + endPlainTextTag = ""; + } + else + { + startPlainTextTag = START_PLAINTEXT_TAG; + endPlainTextTag = END_PLAINTEXT_TAG; + } + + Matcher m + = Pattern.compile(Pattern.quote(keyword), Pattern.CASE_INSENSITIVE) + .matcher(message); + StringBuffer msgBuffer = new StringBuffer(); + int prevEnd = 0; + + while (m.find()) + { + msgBuffer.append(message.substring(prevEnd, m.start())); + prevEnd = m.end(); + + String keywordMatch = m.group().trim(); + + msgBuffer.append(endPlainTextTag); + msgBuffer.append("<b>"); + msgBuffer.append(keywordMatch); + msgBuffer.append("</b>"); + msgBuffer.append(startPlainTextTag); + } + + /* + * If the keyword didn't match, let the outside world be able to + * discover it. + */ + if (prevEnd == 0) + return message; + + msgBuffer.append(message.substring(prevEnd)); + return msgBuffer.toString(); + } + + /** + * Formats the given message. Processes all smiley chars, new lines and + * links. + * + * @param message the message to be formatted + * @param contentType the content type of the message to be formatted + * @param keyword the word to be highlighted + * @return the formatted message + */ + private String formatMessage(String message, + String contentType, + String keyword) + { + // If the message content type is HTML we won't process links and + // new lines, but only the smileys. + if (!HTML_CONTENT_TYPE.equals(contentType)) + { + + /* + * We disallow HTML in plain-text messages. But processKeyword + * introduces HTML. So we'll allow HTML if processKeyword has + * introduced it in order to not break highlighting. + */ + boolean processHTMLChars; + + if ((keyword != null) && (keyword.length() != 0)) + { + String messageWithProcessedKeyword + = processKeyword(message, contentType, keyword); + + /* + * The same String instance will be returned if there was no + * keyword match. Calling #equals() is expensive so == is + * intentional. + */ + processHTMLChars = (messageWithProcessedKeyword == message); + message = messageWithProcessedKeyword; + } + else + processHTMLChars = true; + + message + = processNewLines( + processLinksAndHTMLChars(message, processHTMLChars)); + } + // If the message content is HTML, we process br and img tags. + else + { + if ((keyword != null) && (keyword.length() != 0)) + message = processKeyword(message, contentType, keyword); + message = processImgTags(processBrTags(message)); + } + + return message; + } + + /** + * Formats all links in a given message and optionally escapes special HTML + * characters such as &lt;, &gt;, &amp; and &quot; in order to prevent HTML + * injection in plain-text messages such as writing + * <code>&lt;/PLAINTEXT&gt;</code>, HTML which is going to be rendered as + * such and <code>&lt;PLAINTEXT&gt;</code>. The two procedures are carried + * out in one call in order to not break URLs which contain special HTML + * characters such as &amp;. + * + * @param message The source message string. + * @param processHTMLChars <tt>true</tt> to escape the special HTML chars; + * otherwise, <tt>false</tt> + * @return The message string with properly formatted links. + */ + private String processLinksAndHTMLChars(String message, + boolean processHTMLChars) + { + Matcher m = URL_PATTERN.matcher(message); + StringBuffer msgBuffer = new StringBuffer(); + int prevEnd = 0; + + while (m.find()) + { + String fromPrevEndToStart = message.substring(prevEnd, m.start()); + + if (processHTMLChars) + fromPrevEndToStart = processHTMLChars(fromPrevEndToStart); + msgBuffer.append(fromPrevEndToStart); + prevEnd = m.end(); + + String url = m.group().trim(); + + msgBuffer.append(END_PLAINTEXT_TAG); + msgBuffer.append("<A href=\""); + if (url.startsWith("www")) + msgBuffer.append("http://"); + msgBuffer.append(url); + msgBuffer.append("\">"); + msgBuffer.append(url); + msgBuffer.append("</A>"); + msgBuffer.append(START_PLAINTEXT_TAG); + } + + String fromPrevEndToEnd = message.substring(prevEnd); + + if (processHTMLChars) + fromPrevEndToEnd = processHTMLChars(fromPrevEndToEnd); + msgBuffer.append(fromPrevEndToEnd); + + return msgBuffer.toString(); + } + + /** + * Escapes special HTML characters such as &lt;, &gt;, &amp; and &quot; in + * the specified message. + * + * @param message the message to be processed + * @return the processed message with escaped special HTML characters + */ + private String processHTMLChars(String message) + { + return + message + .replace("&", "&amp;") + .replace("<", "&lt;") + .replace(">", "&gt;") + .replace("\"", "&quot;"); + } + + /** + * Formats message new lines. + * + * @param message The source message string. + * @return The message string with properly formatted new lines. + */ + private String processNewLines(String message) + { + + /* + * <br> tags are needed to visualize a new line in the html format, but + * when copied to the clipboard they are exported to the plain text + * format as ' ' and not as '\n'. + * + * See bug N4988885: + * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4988885 + * + * To fix this we need "&#10;" - the HTML-Code for ASCII-Character No.10 + * (Line feed). + */ + return + message + .replaceAll( + "\n", + END_PLAINTEXT_TAG + "<BR/>&#10;" + START_PLAINTEXT_TAG); + } + + /** + * Opens a link in the default browser when clicked and shows link url in a + * popup on mouseover. + * + * @param e The HyperlinkEvent. + */ + public void hyperlinkUpdate(HyperlinkEvent e) + { + if (e.getEventType() == HyperlinkEvent.EventType.ENTERED) + { + String href = e.getDescription(); + + this.currentHref = href; + } + else if (e.getEventType() == HyperlinkEvent.EventType.EXITED) + { + this.currentHref = ""; + } + } + + /** + * Returns the text pane of this conversation panel. + * + * @return The text pane of this conversation panel. + */ + public JTextPane getChatTextPane() + { + return chatTextPane; + } + + /** + * Returns the time of the last received message. + * + * @return The time of the last received message. + */ + public long getLastIncomingMsgTimestamp() + { + return lastIncomingMsgTimestamp; + } + + /** + * When a right button click is performed in the editor pane, a popup menu + * is opened. + * In case of the Scheme being internal, it won't open the Browser but + * instead it will trigger the forwarded action. + * + * @param e The MouseEvent. + */ + public void mouseClicked(MouseEvent e) + { + Point p = e.getPoint(); + SwingUtilities.convertPointToScreen(p, e.getComponent()); + + if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0 + || (e.isControlDown() && !e.isMetaDown())) + { + openContextMenu(p); + } + else if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0 + && currentHref != null && currentHref.length() != 0) + { + URI uri; + try + { + uri = new URI(currentHref); + } + catch (URISyntaxException e1) + { + logger.error("Invalid URL", e1); + return; + } + if(uri.getScheme().equals("jitsi")) + { + for(ChatLinkClickedListener l:chatLinkClickedListeners) + { + l.chatLinkClicked(uri); + } + } + else + GuiActivator.getBrowserLauncher().openURL(currentHref); + + // after opening the link remove the currentHref to avoid + // clicking on the window to gain focus to open the link again + this.currentHref = ""; + } + } + + /** + * Opens this panel context menu at the given point. + * + * @param p the point where to position the left-top cornet of the context + * menu + */ + private void openContextMenu(Point p) + { + if (currentHref != null && currentHref.length() != 0 + && !currentHref.startsWith("jitsi://")) + { + rightButtonMenu.insert(openLinkItem, 0); + rightButtonMenu.insert(copyLinkItem, 1); + rightButtonMenu.insert(copyLinkSeparator, 2); + } + else + { + rightButtonMenu.remove(openLinkItem); + rightButtonMenu.remove(copyLinkItem); + rightButtonMenu.remove(copyLinkSeparator); + } + + if (chatTextPane.getSelectedText() != null) + { + rightButtonMenu.enableCopy(); + } + else + { + rightButtonMenu.disableCopy(); + } + rightButtonMenu.setInvoker(chatTextPane); + rightButtonMenu.setLocation(p.x, p.y); + rightButtonMenu.setVisible(true); + } + + public void mousePressed(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseExited(MouseEvent e) {} + + public void lostOwnership(Clipboard clipboard, Transferable contents) {} + + /** + * Returns the chat container. + * + * @return the chat container + */ + public ChatConversationContainer getChatContainer() + { + return chatContainer; + } + + /** + * Copies the selected conversation panel content to the clipboard. + */ + public void copyConversation() + { + this.chatTextPane.copy(); + } + + /** + * Creates new document and all the messages that will be processed in the + * future will be appended in it. + */ + public void clear() + { + this.document = (HTMLDocument) editorKit.createDefaultDocument(); + Constants.loadSimpleStyle( + document.getStyleSheet(), chatTextPane.getFont()); + } + + /** + * Sets the given document to the editor pane in this panel. + * + * @param document the document to set + */ + public void setContent(HTMLDocument document) + { + synchronized (scrollToBottomRunnable) + { + scrollToBottomIsPending = true; + + this.document = document; + chatTextPane.setDocument(this.document); + } + } + + /** + * Sets the default document contained in this panel, created on init or + * when clear is invoked. + */ + public void setDefaultContent() + { + setContent(document); + } + + /** + * Returns the document contained in this panel. + * + * @return the document contained in this panel + */ + public HTMLDocument getContent() + { + return (HTMLDocument) this.chatTextPane.getDocument(); + } + + /** + * Returns the right button popup menu. + * + * @return the right button popup menu + */ + public ChatRightButtonMenu getRightButtonMenu() + { + return rightButtonMenu; + } + + /** + * Returns the date of the first message in the current page. + * + * @return the date of the first message in the current page + */ + public Date getPageFirstMsgTimestamp() + { + Element rootElement = this.document.getDefaultRootElement(); + + Element firstMessageElement = null; + + for(int i = 0; i < rootElement.getElementCount(); i ++) + { + String idAttr = (String) rootElement.getElement(i) + .getAttributes().getAttribute("identifier"); + + if (idAttr != null && idAttr.equals("messageHeader")) + { + firstMessageElement = rootElement.getElement(i); + break; + } + } + + if(firstMessageElement == null) + return new Date(Long.MAX_VALUE); + + String dateObject = firstMessageElement + .getAttributes().getAttribute("date").toString(); + + return new Date(Long.parseLong(dateObject)); + } + + /** + * Returns the date of the last message in the current page. + * + * @return the date of the last message in the current page + */ + public Date getPageLastMsgTimestamp() + { + Element rootElement = this.document.getDefaultRootElement(); + + Element lastMessageElement = null; + + for(int i = rootElement.getElementCount() - 1; i >= 0; i --) + { + String idAttr = (String) rootElement.getElement(i) + .getAttributes().getAttribute("identifier"); + + if (idAttr != null && idAttr.equals("messageHeader")) + { + lastMessageElement = rootElement.getElement(i); + break; + } + } + + if(lastMessageElement == null) + return new Date(0); + + String dateObject = lastMessageElement + .getAttributes().getAttribute("date").toString(); + + return new Date(Long.parseLong(dateObject)); + } + + /** + * Formats HTML tags &lt;br/&gt; to &lt;br&gt; or &lt;BR/&gt; to &lt;BR&gt;. + * The reason of this function is that the ChatPanel does not support + * &lt;br /&gt; closing tags (XHTML syntax), thus we have to remove every + * slash from each &lt;br /&gt; tags. + * @param message The source message string. + * @return The message string with properly formatted &lt;br&gt; tags. + */ + private String processBrTags(String message) + { + // The resulting message after being processed by this function. + StringBuffer processedMessage = new StringBuffer(); + + // Compile the regex to match something like <br .. /> or <BR .. />. + // This regex is case sensitive and keeps the style or other + // attributes of the <br> tag. + Matcher m + = Pattern.compile("<\\s*[bB][rR](.*?)(/\\s*>)").matcher(message); + int start = 0; + + // while we find some <br /> closing tags with a slash inside. + while(m.find()) + { + // First, we have to copy all the message preceding the <br> tag. + processedMessage.append(message.substring(start, m.start())); + // Then, we find the position of the slash inside the tag. + int slash_index = m.group().lastIndexOf("/"); + // We copy the <br> tag till the slash exclude. + processedMessage.append(m.group().substring(0, slash_index)); + // We copy all the end of the tag following the slash exclude. + processedMessage.append(m.group().substring(slash_index+1)); + start = m.end(); + } + // Finally, we have to add the end of the message following the last + // <br> tag, or the whole message if there is no <br> tag. + processedMessage.append(message.substring(start)); + + return processedMessage.toString(); + } + + /** + * Formats HTML tags &lt;img ... /&gt; to &lt; img ... &gt;&lt;/img&gt; or + * &lt;IMG ... /&gt; to &lt;IMG&gt;&lt;/IMG&gt;. + * The reason of this function is that the ChatPanel does not support + * &lt;img /&gt; tags (XHTML syntax). + * Thus, we remove every slash from each &lt;img /&gt; and close it with a + * separate closing tag. + * @param message The source message string. + * @return The message string with properly formatted &lt;img&gt; tags. + */ + private String processImgTags(String message) + { + // The resulting message after being processed by this function. + StringBuffer processedMessage = new StringBuffer(); + + // Compile the regex to match something like <img ... /> or + // <IMG ... />. This regex is case sensitive and keeps the style, + // src or other attributes of the <img> tag. + Pattern p = Pattern.compile("<\\s*[iI][mM][gG](.*?)(/\\s*>)"); + Matcher m = p.matcher(message); + int slash_index; + int start = 0; + + // while we find some <img /> self-closing tags with a slash inside. + while(m.find()){ + // First, we have to copy all the message preceding the <img> tag. + processedMessage.append(message.substring(start, m.start())); + // Then, we find the position of the slash inside the tag. + slash_index = m.group().lastIndexOf("/"); + // We copy the <img> tag till the slash exclude. + processedMessage.append(m.group().substring(0, slash_index)); + // We copy all the end of the tag following the slash exclude. + processedMessage.append(m.group().substring(slash_index+1)); + // We close the tag with a separate closing tag. + processedMessage.append("</img>"); + start = m.end(); + } + // Finally, we have to add the end of the message following the last + // <img> tag, or the whole message if there is no <img> tag. + processedMessage.append(message.substring(start)); + + return processedMessage.toString(); + } + + /** + * Extend Editor pane to add URL tooltips. + */ + private class MyTextPane + extends JTextPane + { + /** + * Returns the string to be used as the tooltip for <i>event</i>. + * + * @param event the <tt>MouseEvent</tt> + * @return the string to be used as the tooltip for <i>event</i>. + */ + @Override + public String getToolTipText(MouseEvent event) + { + return + ((currentHref != null) && (currentHref.length() != 0)) + ? currentHref + : null; + } + } + + /** + * Adds a custom component at the end of the conversation. + * + * @param component the component to add at the end of the conversation. + */ + public void addComponent(ChatConversationComponent component) + { + synchronized (scrollToBottomRunnable) + { + StyleSheet styleSheet = document.getStyleSheet(); + Style style + = styleSheet + .addStyle( + StyleConstants.ComponentElementName, + styleSheet.getStyle("body")); + + // The image must first be wrapped in a style + style + .addAttribute( + AbstractDocument.ElementNameAttribute, + StyleConstants.ComponentElementName); + + TransparentPanel wrapPanel + = new TransparentPanel(new BorderLayout()); + + wrapPanel.add(component, BorderLayout.NORTH); + + style + .addAttribute(StyleConstants.ComponentAttribute, wrapPanel); + style.addAttribute("identifier", "messageHeader"); + style.addAttribute("date", component.getDate().getTime()); + + scrollToBottomIsPending = true; + + // Insert the component style at the end of the text + try + { + document + .insertString(document.getLength(), "ignored text", style); + } + catch (BadLocationException e) + { + logger.error("Insert in the HTMLDocument failed.", e); + } + } + } + + /** + * Registers a new link click listener. + * + * @param listener the object that should be notified when an internal + * link was clicked. + */ + public void addChatLinkClickedListener(ChatLinkClickedListener listener) + { + if(!chatLinkClickedListeners.contains(listener)) + chatLinkClickedListeners.add(listener); + } + + /** + * Remove a registered link click listener. + * + * @param listener a registered click listener to remove + */ + public void removeChatLinkClickedListener(ChatLinkClickedListener listener) + { + chatLinkClickedListeners.remove(listener); + } + + /** + * Returns the date string to show for the given date. + * + * @param date the date to format + * @return the date string to show for the given date + */ + public static String getDateString(long date) + { + if (GuiUtils.compareDatesOnly(date, System.currentTimeMillis()) < 0) + { + StringBuffer dateStrBuf = new StringBuffer(); + + GuiUtils.formatDate(date, dateStrBuf); + dateStrBuf.append(" "); + return dateStrBuf.toString(); + } + + return ""; + } + + /** + * Reloads images. + */ + public void loadSkin() + { + openLinkItem.setIcon( + new ImageIcon(ImageLoader.getImage(ImageLoader.BROWSER_ICON))); + copyLinkItem.setIcon( + new ImageIcon(ImageLoader.getImage(ImageLoader.COPY_ICON))); + + getRightButtonMenu().loadSkin(); + } + + /** + * Highlights the string in multi user chat. + * + * @param message the message to process + * @param contentType the content type of the message + * @param keyWord the keyword to highlight + * @return the message string with the keyword highlighted + */ + public String processChatRoomHighlight(String message, String contentType, + String keyWord) + { + return processKeyword(message, contentType, keyWord); + } + + public String processMeCommand(ChatMessage chatMessage) + { + String contentType = chatMessage.getContentType(); + String message = chatMessage.getMessage(); + + String msgID = "message"; + String chatString = ""; + String endHeaderTag = ""; + + String startDivTag = "<DIV identifier=\"" + msgID + "\">"; + String endDivTag = "</DIV>"; + + String startPlainTextTag; + String endPlainTextTag; + + if (HTML_CONTENT_TYPE.equals(contentType)) + { + startPlainTextTag = ""; + endPlainTextTag = ""; + } + else + { + startPlainTextTag = START_PLAINTEXT_TAG; + endPlainTextTag = END_PLAINTEXT_TAG; + } + + if (message.length() > 4 && message.substring(0, 4).equals("/me ")) + { + chatString = startDivTag + "<B><I>"; + + endHeaderTag = "</I></B>" + endDivTag; + + chatString += + + processHTMLChars("*** " + chatMessage.getContactName() + " " + + message.substring(4)) + + endHeaderTag; + + Map<String, ReplacementService> listSources = + GuiActivator.getReplacementSources(); + + Iterator<Entry<String, ReplacementService>> entrySetIter = + listSources.entrySet().iterator(); + StringBuffer msgStore = new StringBuffer(chatString); + + for (int i = 0; i < listSources.size(); i++) + { + Map.Entry<String, ReplacementService> entry = + entrySetIter.next(); + + ReplacementService source = entry.getValue(); + + boolean isSmiley = source instanceof SmiliesReplacementService; + if (isSmiley) + { + String sourcePattern = source.getPattern(); + Pattern p = + Pattern.compile(sourcePattern, Pattern.CASE_INSENSITIVE + | Pattern.DOTALL); + Matcher m = p.matcher(msgStore); + + StringBuffer msgTemp = new StringBuffer(chatString); + + while (m.find()) + { + msgTemp.insert(m.start(), startPlainTextTag); + msgTemp.insert(m.end() + startPlainTextTag.length(), + endPlainTextTag); + + } + if (msgTemp.length() != msgStore.length()) + msgStore = msgTemp; + } + } + + return msgStore.toString(); + } + else + return ""; + } + + private static String createIncomingMessageTag( + String messageID, + String incomingMessageHeader, + String incomingMessageParagraph) + { + StringBuffer messageBuff = new StringBuffer(); + +// <div class="box"> +// <div class="topleft"> +// <div class="topright"> +// <div class="messageDiv"> +// <h3>Header</h3> +// <p>Text</p> +// </div> +// </div> +// </div> +// <div class="bottomleft"> +// <div class="bottomright"> +// </div> +// </div> +// </div> + + messageBuff.append("<div " + createBoxStyle() + ">"); + messageBuff.append("<div " + createTopLeftStyle() + ">"); + messageBuff.append("<div " + createTopRightStyle() + ">"); + messageBuff.append("<div identifier=\"" + messageID + + "\" " + createMessageDivStyle() + ">"); + messageBuff.append(incomingMessageHeader); + messageBuff.append(incomingMessageParagraph); + messageBuff.append("</div>"); + messageBuff.append("</div>"); + messageBuff.append("</div>"); + messageBuff.append("<div " + createBottomLeftStyle() + ">"); + messageBuff.append("<div " + createBottomRightStyle() + ">"); + messageBuff.append("</div>"); + messageBuff.append("</div>"); + messageBuff.append("</div>"); + + return messageBuff.toString(); + } + + private static String createOutgoingMessageStyle() + { + StringBuffer styleBuff = new StringBuffer(); + + styleBuff.append("background-image:"); + styleBuff.append("url('bundle://30.0:1/resources/images/impl/gui/lookandfeel/selectedTabMiddle.png');"); + styleBuff.append("background-repeat:"); + styleBuff.append("repeat-x;"); + + return styleBuff.toString(); + } + + private static String createSmsMessageStyle() + { + StringBuffer styleBuff = new StringBuffer(); + + styleBuff.append("background-image:"); + styleBuff.append("url('bundle://30.0:1/resources/images/impl/gui/lookandfeel/tabRight.png');"); + styleBuff.append("background-repeat:"); + styleBuff.append("repeat-x;"); + + return styleBuff.toString(); + } + +// .box { +// width: 100%; +// margin: 0px auto; +// } + private static String createBoxStyle() + { + return "style=\"width: 100%;" + + " margin-top: 0px;" + + " margin-bottom: 0px;" + + " margin-left: auto;" + + " margin-right: auto;\""; + } + +// .box div.topleft { +// display: block; +// background: url("i/box-bg.png") top left no-repeat white; +// padding: 0em 0em 0em 1.0em; +// } + private static String createTopLeftStyle() + { + return "style=\"display: block;" + + " background-image: url('"+INCOMING_MESSAGE_IMAGE_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: top left;" + + " background-color: #FFFFFF;" + + " padding-top: 0em;" + + " padding-right: 0em;" + + " padding-bottom: 0em;" + + " padding-left: 0em;" + + "\""; + } + +// .box div.topright { +// display: block; +// background: url("i/box-bg.png") top right no-repeat white; +// padding: 1.0em; +// margin: -1.0em 0 0 1.0em; +// } + private static String createTopRightStyle() + { + return "style=\"display: block;" + + " background-image: url('"+INCOMING_MESSAGE_IMAGE_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: top right;" + + " background-color: #FFFFFF;" + + " padding-top: 1em;" + + " padding-right: 1em;" + + " padding-bottom: 1em;" + + " padding-left: 1em;" + + " margin-top: -1.0em;" + + " margin-right: 0em;" + + " margin-bottom: 0em;" + + " margin-left: 1.0em;" + + "\""; + } + +// .box div.bottomleft { +// display: block; +// height: 55px; +// margin-top: -1.0em; +// background: url("i/box-bg.png") bottom left no-repeat white; +// } + private static String createBottomLeftStyle() + { + return "style=\"display: block;" + + " height: 25px;" + + " margin-top: -1.0em;" + + " background-image: url('"+INCOMING_MESSAGE_IMAGE_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: bottom left;" + + " background-color: #FFFFFF;" + + "\""; + } + +// .box div.bottomright { +// display: block; +// background: url("i/box-bg.png") bottom right no-repeat white; +// height: 55px; +// margin-left: 3.0em; +// } + private static String createBottomRightStyle() + { + return "style=\"display: block;" + + " height: 25px;" + + " margin-left: 3.0em;" + + " background-image: url('"+INCOMING_MESSAGE_IMAGE_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: bottom right;" + + " background-color: #FFFFFF;" + + "\""; + } + +// .box div.topright div { +// margin-right: 1.5em; +// } + private static String createMessageDivStyle() + { + return "style=\"margin-right: 1.5em;\""; + } + +// .box h4 { +// margin-bottom: 0.4em; +// background-image: none; +// background-repeat: no-repeat; +// margin:0; +// padding:0; +// text-align:center; +// padding-bottom:15px; +// } +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/contactlist/MetaContactImpl.java b/src/net/java/sip/communicator/impl/contactlist/MetaContactImpl.java index 8b1573d13..81528e486 100644 --- a/src/net/java/sip/communicator/impl/contactlist/MetaContactImpl.java +++ b/src/net/java/sip/communicator/impl/contactlist/MetaContactImpl.java @@ -6,7 +6,6 @@ */ package net.java.sip.communicator.impl.contactlist; -import java.io.*; import java.util.*; import net.java.sip.communicator.service.contactlist.*; @@ -14,8 +13,6 @@ import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; -import org.jitsi.service.fileaccess.*; - /** * A default implementation of the <code>MetaContact</code> interface. * @@ -93,34 +90,11 @@ public class MetaContactImpl */ private Map<String, List<String>> details; - /** - * The name (i.e. not the whole path) of the directory in which the avatar - * files are to be cached for later reuse. - */ - private final static String AVATAR_DIR = "avatarcache"; - /** * Whether user has renamed this meta contact. */ private boolean isDisplayNameUserDefined = false; - /** - * Characters and their replacement in created folder names - */ - private final static String[][] ESCAPE_SEQUENCES = new String[][] - { - {"&", "&_amp"}, - {"/", "&_sl"}, - {"\\\\", "&_bs"}, // the char \ - {":", "&_co"}, - {"\\*", "&_as"}, // the char * - {"\\?", "&_qm"}, // the char ? - {"\"", "&_pa"}, // the char " - {"<", "&_lt"}, - {">", "&_gt"}, - {"\\|", "&_pp"} // the char | - }; - /** * Creates new meta contact with a newly generated meta contact UID. */ @@ -636,16 +610,8 @@ public byte[] getAvatar(boolean isLazy) while (iter.hasNext()) { Contact protoContact = iter.next(); - String avatarPath = AVATAR_DIR - + File.separator - + escapeSpecialCharacters( - protoContact - .getProtocolProvider() - .getAccountID().getAccountUniqueID()) - + File.separator - + escapeSpecialCharacters(protoContact.getAddress()); - - cachedAvatar = getLocallyStoredAvatar(avatarPath); + + cachedAvatar = AvatarCacheUtils.getCachedAvatar(protoContact); /* * Caching a zero-length avatar happens but such an avatar isn't * very useful. @@ -1103,136 +1069,7 @@ public void cacheAvatar( Contact protoContact, this.cachedAvatar = avatarBytes; this.avatarFileCacheAlreadyQueried = true; - String avatarDirPath - = AVATAR_DIR - + File.separator - + escapeSpecialCharacters( - protoContact - .getProtocolProvider() - .getAccountID().getAccountUniqueID()); - String avatarFileName - = escapeSpecialCharacters(protoContact.getAddress()); - - File avatarDir = null; - File avatarFile = null; - try - { - FileAccessService fileAccessService - = ContactlistActivator.getFileAccessService(); - - avatarDir - = fileAccessService.getPrivatePersistentDirectory( - avatarDirPath); - avatarFile - = fileAccessService.getPrivatePersistentFile( - avatarDirPath + File.separator + avatarFileName); - - if(!avatarFile.exists()) - { - if (!avatarDir.exists() && !avatarDir.mkdirs()) - { - throw - new IOException( - "Failed to create directory: " - + avatarDir.getAbsolutePath()); - } - - if (!avatarFile.createNewFile()) - { - throw - new IOException( - "Failed to create file" - + avatarFile.getAbsolutePath()); - } - } - - FileOutputStream fileOutStream = new FileOutputStream(avatarFile); - - try - { - fileOutStream.write(avatarBytes); - fileOutStream.flush(); - } - finally - { - fileOutStream.close(); - } - } - catch (Exception ex) - { - logger.error( - "Failed to store avatar. dir =" + avatarDir - + " file=" + avatarFile, - ex); - } - } - - /** - * Returns the avatar image corresponding to the given avatar path. - * - * @param avatarPath The path to the lovally stored avatar. - * @return the avatar image corresponding to the given avatar path. - */ - private byte[] getLocallyStoredAvatar(String avatarPath) - { - try - { - File avatarFile - = ContactlistActivator - .getFileAccessService() - .getPrivatePersistentFile(avatarPath); - - if(avatarFile.exists()) - { - FileInputStream avatarInputStream - = new FileInputStream(avatarFile); - byte[] bs = null; - - try - { - int available = avatarInputStream.available(); - - if (available > 0) - { - bs = new byte[available]; - avatarInputStream.read(bs); - } - } - finally - { - avatarInputStream.close(); - } - if (bs != null) - return bs; - } - } - catch (Exception ex) - { - logger.error( - "Could not read avatar image from file " + avatarPath, - ex); - } - return null; - } - - /** - * Replaces the characters that we must escape used for the created - * filename. - * - * @param id the <tt>String</tt> which is to have its characters escaped - * @return a <tt>String</tt> derived from the specified <tt>id</tt> by - * escaping characters - */ - private String escapeSpecialCharacters(String id) - { - String resultId = id; - - for (int j = 0; j < ESCAPE_SEQUENCES.length; j++) - { - resultId = resultId. - replaceAll(ESCAPE_SEQUENCES[j][0], ESCAPE_SEQUENCES[j][1]); - } - return resultId; + AvatarCacheUtils.cacheAvatar(protoContact, avatarBytes); } /** 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 a0f2eb9db..7bc1ea72a 100644 --- a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java +++ b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java @@ -276,7 +276,7 @@ private void init() this.setJMenuBar(menu); TransparentPanel searchPanel - = new TransparentPanel(new BorderLayout(2, 0)); + = new TransparentPanel(new BorderLayout(5, 0)); searchPanel.add(searchField); searchPanel.add(new DialPadButton(), BorderLayout.WEST); diff --git a/src/net/java/sip/communicator/impl/gui/main/call/AbstractCallToggleButton.java b/src/net/java/sip/communicator/impl/gui/main/call/AbstractCallToggleButton.java index 7958d68db..0c67e0b72 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/AbstractCallToggleButton.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/AbstractCallToggleButton.java @@ -37,17 +37,17 @@ public abstract class AbstractCallToggleButton /** * The background image. */ - protected ImageID bgImage; + protected ImageID bgImageID; /** * The rollover image */ - protected ImageID bgRolloverImage; + protected ImageID bgRolloverImageID; /** * The pressed image. */ - protected ImageID pressedImage; + protected ImageID pressedImageID; /** * The icon image. @@ -136,27 +136,17 @@ public AbstractCallToggleButton( this.fullScreen = fullScreen; this.settingsPanel = settingsPanel; - if (fullScreen) + if(settingsPanel) { - bgImage = ImageLoader.FULL_SCREEN_BUTTON_BG; - bgRolloverImage = ImageLoader.FULL_SCREEN_BUTTON_BG; - pressedImage = ImageLoader.FULL_SCREEN_BUTTON_BG_PRESSED; + bgRolloverImageID = ImageLoader.CALL_SETTING_BUTTON_BG; + pressedImageID = ImageLoader.CALL_SETTING_BUTTON_PRESSED_BG; } else { - if(settingsPanel) - { - bgImage = ImageLoader.CALL_SETTING_BUTTON_BG; - bgRolloverImage = ImageLoader.CALL_SETTING_BUTTON_BG; - pressedImage = ImageLoader.CALL_SETTING_BUTTON_PRESSED_BG; - } - else - { - bgImage = ImageLoader.SOUND_SETTING_BUTTON_BG; - bgRolloverImage = ImageLoader.SOUND_SETTING_BUTTON_BG; - pressedImage = ImageLoader.SOUND_SETTING_BUTTON_PRESSED; + bgImageID = ImageLoader.SOUND_SETTING_BUTTON_BG; + bgRolloverImageID = ImageLoader.SOUND_SETTING_BUTTON_BG; + pressedImageID = ImageLoader.SOUND_SETTING_BUTTON_PRESSED; - } } if (toolTipTextKey != null) @@ -171,13 +161,6 @@ public AbstractCallToggleButton( // All items are now instantiated and could safely load the skin. loadSkin(); - - int width = getBgImage().getWidth(null); - int height = getBgImage().getHeight(null); - - this.setPreferredSize(new Dimension(width, height)); - this.setMaximumSize(new Dimension(width, height)); - this.setMinimumSize(new Dimension(width, height)); } /** @@ -256,15 +239,30 @@ private void doRun() */ public void loadSkin() { - setBgImage(ImageLoader.getImage(bgImage)); - setBgRolloverImage(ImageLoader.getImage(bgRolloverImage)); - setPressedImage(ImageLoader.getImage(pressedImage)); + int width = CallToolBarButton.DEFAULT_WIDTH; + int height = CallToolBarButton.DEFAULT_HEIGHT; + + if (bgImageID != null) + { + Image bgImage = ImageLoader.getImage(bgImageID); + setBgImage(bgImage); + + width = bgImage.getWidth(this); + height = bgImage.getHeight(this); + } + + setPreferredSize(new Dimension(width, height)); + setMaximumSize(new Dimension(width, height)); + setMinimumSize(new Dimension(width, height)); + + setBgRolloverImage(ImageLoader.getImage(bgRolloverImageID)); + setPressedImage(ImageLoader.getImage(pressedImageID)); if (iconImageID != null) { if (!fullScreen && !settingsPanel) setIconImage(ImageUtils.scaleImageWithinBounds( - ImageLoader.getImage(iconImageID), 12, 12)); + ImageLoader.getImage(iconImageID), 18, 18)); else setIconImage(ImageLoader.getImage(iconImageID)); } @@ -273,7 +271,7 @@ public void loadSkin() { if (!fullScreen && !settingsPanel) setPressedIconImage(ImageUtils.scaleImageWithinBounds( - ImageLoader.getImage(pressedIconImageID), 12, 12)); + ImageLoader.getImage(pressedIconImageID), 18, 18)); else setPressedIconImage(ImageLoader.getImage(pressedIconImageID)); } @@ -290,7 +288,7 @@ public void setIconImageID(ImageID iconImageID) if (!fullScreen && !settingsPanel) setIconImage(ImageUtils.scaleImageWithinBounds( - ImageLoader.getImage(iconImageID), 12, 12)); + ImageLoader.getImage(iconImageID), 18, 18)); else setIconImage(ImageLoader.getImage(iconImageID)); } 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 476ad524f..d00d60d06 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 @@ -41,6 +41,11 @@ public class CallHistoryButton */ private Image pressedImage; + /** + * The notification image. + */ + private Image notificationImage; + /** * Indicates if the history is visible. */ @@ -142,7 +147,10 @@ public void notificationReceived(UINotification notification) */ private void setHistoryView() { - isNotificationsView = false; + if (isNotificationsView) + isNotificationsView = false; + else + setIcon(null); if (isHistoryVisible) { @@ -167,7 +175,6 @@ private void setNotificationView( { int notificationCount = 0; isNotificationsView = true; - this.setBgImage(null); Iterator<UINotificationGroup> groupsIter = notificationGroups.iterator(); @@ -204,7 +211,29 @@ private void setNotificationView( this.setToolTipText(tooltipText + "</html>"); this.setBackground(new Color(200, 0, 0)); - this.setText(new Integer(notificationCount).toString()); + this.setVerticalTextPosition(SwingConstants.TOP); + + Image iconImage = ImageLoader.getImage(notificationImage, + new Integer(notificationCount).toString(), this); + + if (isHistoryVisible) + { + setBgImage(ImageLoader.getImage( + pressedImage, + iconImage, + pressedImage.getWidth(null)/2 + - notificationImage.getWidth(null)/2, + 0)); + } + else + { + setBgImage(ImageLoader.getImage( + historyImage, + iconImage, + pressedImage.getWidth(null)/2 + - notificationImage.getWidth(null)/2, + 0)); + } } /** @@ -218,6 +247,10 @@ public void loadSkin() pressedImage = ImageLoader.getImage(ImageLoader.CALL_HISTORY_BUTTON_PRESSED); + notificationImage + = ImageLoader.getImage( + ImageLoader.CALL_HISTORY_BUTTON_NOTIFICATION); + this.setPreferredSize(new Dimension(historyImage.getWidth(this), historyImage.getHeight(this))); diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java index 966a7a2fb..e8a5c2a26 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallPanel.java @@ -14,7 +14,6 @@ import javax.swing.*; import javax.swing.Timer; -import javax.swing.border.*; import javax.swing.event.*; import net.java.sip.communicator.impl.gui.*; @@ -29,7 +28,6 @@ import net.java.sip.communicator.util.Logger; import net.java.sip.communicator.util.skin.*; import net.java.sip.communicator.util.swing.*; -import net.java.sip.communicator.util.swing.border.*; import org.jitsi.service.neomedia.*; import org.jitsi.service.neomedia.device.*; @@ -105,11 +103,6 @@ public class CallPanel */ private static final String INFO_BUTTON = "INFO_BUTTON"; - /** - * The hang up button name. - */ - private static final String HANGUP_BUTTON = "HANGUP_BUTTON"; - /** * The hang up button name. */ @@ -128,7 +121,7 @@ public class CallPanel /** * The panel containing call settings. */ - private final TransparentPanel settingsPanel = new OrderedTransparentPanel(); + private JComponent settingsPanel; /** * The panel representing the call. For conference calls this would be an @@ -181,17 +174,20 @@ public class CallPanel /** * The dial button, which opens a keypad dialog. */ - private SIPCommButton dialButton = new SIPCommButton( - ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG), - ImageLoader.getImage(ImageLoader.DIAL_BUTTON)); + private CallToolBarButton dialButton = new CallToolBarButton( + ImageLoader.getImage(ImageLoader.DIAL_BUTTON), + DIAL_BUTTON, + GuiActivator.getResources().getI18NString("service.gui.DIALPAD")); /** * The conference button. */ - private SIPCommButton conferenceButton - = new SIPCommButton( - ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG), - ImageLoader.getImage(ImageLoader.ADD_TO_CALL_BUTTON)); + private CallToolBarButton conferenceButton + = new CallToolBarButton( + ImageLoader.getImage(ImageLoader.ADD_TO_CALL_BUTTON), + CONFERENCE_BUTTON, + GuiActivator.getResources().getI18NString( + "service.gui.CREATE_CONFERENCE_CALL")); /** * Chat button. @@ -216,10 +212,12 @@ public class CallPanel /** * Merge button. */ - private SIPCommButton mergeButton = - new SIPCommButton( - ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG), - ImageLoader.getImage(ImageLoader.MERGE_CALL_BUTTON)); + private CallToolBarButton mergeButton = + new CallToolBarButton( + ImageLoader.getImage(ImageLoader.MERGE_CALL_BUTTON), + MERGE_BUTTON, + GuiActivator.getResources().getI18NString( + "service.gui.MERGE_TO_CALL")); /** * The call represented in this dialog. @@ -264,7 +262,7 @@ public class CallPanel /** * Sound remote level label. */ - private OutputVolumeControlButton remoteLevel; + private Component remoteLevel; /** * A collection of listeners, registered for call title change events. @@ -290,23 +288,28 @@ public CallPanel(Call call, CallContainer callWindow) this.call = call; this.callWindow = callWindow; + settingsPanel + = CallPeerRendererUtils.createButtonBar(false, null); + holdButton = new HoldButton(call); recordButton = new RecordButton(call); videoButton = new LocalVideoButton(call); showHideVideoButton = new ShowHideVideoButton(call); desktopSharingButton = new DesktopSharingButton(call); transferCallButton = new TransferCallButton(call); - fullScreenButton = new FullScreenButton(this); - chatButton = new SIPCommButton( - ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG), - ImageLoader.getImage(ImageLoader.CHAT_BUTTON_SMALL_WHITE)); + fullScreenButton = new FullScreenButton(this, false); + chatButton = new CallToolBarButton( + ImageLoader.getImage(ImageLoader.CHAT_BUTTON_SMALL_WHITE), + CHAT_BUTTON, + GuiActivator.getResources().getI18NString("service.gui.CHAT")); + localLevel = new InputVolumeControlButton( call, ImageLoader.MICROPHONE, ImageLoader.MUTE_BUTTON, false, true, false); remoteLevel = new OutputVolumeControlButton( - ImageLoader.VOLUME_CONTROL_BUTTON, false, true); + ImageLoader.VOLUME_CONTROL_BUTTON, false, true).getComponent(); this.callDurationTimer = new Timer(1000, new CallTimerListener()); this.callDurationTimer.setRepeats(true); @@ -345,7 +348,7 @@ public CallPanel(Call call, CallContainer callWindow) callPeers.next().addCallPeerConferenceListener(this); // Initializes all buttons and common panels. - init(); + initToolBar(); initPluginComponents(); } @@ -353,15 +356,12 @@ public CallPanel(Call call, CallContainer callWindow) /** * Initializes all buttons and common panels */ - private void init() + private void initToolBar() { - hangupButton = new SIPCommButton( - ImageLoader.getImage(ImageLoader.HANGUP_BUTTON_BG)); + hangupButton = new HangupButton(this); - holdButton.setIndex(2); - recordButton.setIndex(3); - videoButton.setIndex(11); - showHideVideoButton.setIndex(12); + // Initializes the order of buttons in the call tool bar. + initButtonIndexes(); showHideVideoButton.setPeerRenderer(((CallRenderer) callPanel) .getCallPeerRenderer(call.getCallPeers().next())); @@ -388,42 +388,9 @@ public void stateChanged(ChangeEvent e) } }); - desktopSharingButton.setIndex(8); - transferCallButton.setIndex(5); - fullScreenButton.setIndex(10); - - chatButton.setName(CHAT_BUTTON); - chatButton.setToolTipText( - GuiActivator.getResources().getI18NString("service.gui.CHAT")); chatButton.addActionListener(this); - chatButton.setIndex(19); - - localLevel.setIndex(6); - remoteLevel.setIndex(7); - - dialButton.setIndex(0); - dialButton.setName(DIAL_BUTTON); - dialButton.setToolTipText( - GuiActivator.getResources().getI18NString("service.gui.DIALPAD")); dialButton.addActionListener(this); - - conferenceButton.setIndex(1); - conferenceButton.setName(CONFERENCE_BUTTON); - conferenceButton.setToolTipText( - GuiActivator.getResources().getI18NString( - "service.gui.CREATE_CONFERENCE_CALL")); conferenceButton.addActionListener(this); - - hangupButton.setName(HANGUP_BUTTON); - hangupButton.setToolTipText( - GuiActivator.getResources().getI18NString("service.gui.HANG_UP")); - hangupButton.addActionListener(this); - - mergeButton.setIndex(4); - mergeButton.setName(MERGE_BUTTON); - mergeButton.setToolTipText( - GuiActivator.getResources().getI18NString( - "service.gui.MERGE_TO_CALL")); mergeButton.addActionListener(this); /* @@ -474,24 +441,50 @@ public void stateChanged(ChangeEvent e) if(GuiActivator.getConfigurationService() .getBoolean(SHOW_CALL_INFO_BUTON_PROP, true)) { - infoButton = new SIPCommButton( - ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG), - ImageLoader.getImage(ImageLoader.CALL_INFO)); - infoButton.setName(INFO_BUTTON); - infoButton.setToolTipText( - GuiActivator.getResources().getI18NString( - "service.gui.PRESS_FOR_CALL_INFO")); + infoButton = new CallToolBarButton( + ImageLoader.getImage(ImageLoader.CALL_INFO), + INFO_BUTTON, + GuiActivator.getResources().getI18NString( + "service.gui.PRESS_FOR_CALL_INFO")); + infoButton.addActionListener(this); - infoButton.setIndex(20); settingsPanel.add(infoButton); } - dtmfHandler = new DTMFHandler(this); + settingsPanel.add(hangupButton); - JComponent bottomBar = createBottomBar(); + dtmfHandler = new DTMFHandler(this); add(callPanel, BorderLayout.CENTER); - add(bottomBar, BorderLayout.SOUTH); + add(createBottomBar(), BorderLayout.SOUTH); + } + + /** + * Initializes buttons order in the call tool bar. + */ + private void initButtonIndexes() + { + dialButton.setIndex(0); + conferenceButton.setIndex(1); + holdButton.setIndex(2); + recordButton.setIndex(3); + mergeButton.setIndex(4); + transferCallButton.setIndex(5); + localLevel.setIndex(6); + + if (remoteLevel instanceof OrderedComponent) + ((OrderedComponent) remoteLevel).setIndex(7); + + desktopSharingButton.setIndex(8); + fullScreenButton.setIndex(10); + videoButton.setIndex(11); + showHideVideoButton.setIndex(12); + chatButton.setIndex(19); + + if (infoButton != null) + infoButton.setIndex(20); + + hangupButton.setIndex(100); } /** @@ -503,11 +496,7 @@ public void actionPerformed(ActionEvent evt) JButton button = (JButton) evt.getSource(); String buttonName = button.getName(); - if (buttonName.equals(HANGUP_BUTTON)) - { - actionPerformedOnHangupButton(false); - } - else if (buttonName.equals(MERGE_BUTTON)) + if (buttonName.equals(MERGE_BUTTON)) { Collection<Call> calls = CallManager.getActiveCalls(); @@ -1612,10 +1601,10 @@ public boolean isRecordingStarted() */ private JComponent createBottomBar() { - JComponent bottomBar = new TransparentPanel(); + JComponent bottomBar + = new TransparentPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); - bottomBar.setBorder( - new ExtendedEtchedBorder(EtchedBorder.LOWERED, 1, 0, 0, 0)); + bottomBar.setBorder(BorderFactory.createEmptyBorder(0, 30, 2, 30)); if (OSUtils.IS_MAC) { @@ -1625,9 +1614,7 @@ private JComponent createBottomBar() .getColor("service.gui.MAC_PANEL_BACKGROUND"))); } - bottomBar.setLayout(new BorderLayout()); - bottomBar.add(settingsPanel, BorderLayout.WEST); - bottomBar.add(hangupButton, BorderLayout.EAST); + bottomBar.add(settingsPanel); return bottomBar; } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRendererUtils.java b/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRendererUtils.java index f6a4656bc..543af5dac 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRendererUtils.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRendererUtils.java @@ -13,7 +13,6 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.utils.*; -import net.java.sip.communicator.util.skin.*; import net.java.sip.communicator.util.swing.*; /** @@ -26,30 +25,6 @@ */ public class CallPeerRendererUtils { - /** - * Creates a new <tt>Component</tt> through which the user would be able to - * exit the full screen mode. - * - * @param renderer the renderer through which we exit the full screen mode - * @return the newly created component - */ - public static Component createExitFullScreenButton( - final CallRenderer renderer) - { - JButton button = new ExitFullScreenButton(); - - button.setToolTipText(GuiActivator.getResources().getI18NString( - "service.gui.EXIT_FULL_SCREEN_TOOL_TIP")); - button.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent event) - { - renderer.exitFullScreen(); - } - }); - return button; - } - /** * Sets the given <tt>background</tt> color to the given <tt>component</tt>. * @@ -87,24 +62,27 @@ public static void addKeyListener(Component component, KeyListener l) /** * Creates a buttons bar from the given list of button components. * - * @param heavyweight indicates if the created button bar should be heavy - * weight component (useful in full screen mode) + * @param fullScreen indicates if the created button bar would be shown in + * full screen mode * @param buttons the list of buttons to add in the created button bar * @return the created button bar */ - public static Component createButtonBar(boolean heavyweight, + public static JComponent createButtonBar(boolean fullScreen, Component[] buttons) { - Container buttonBar - = heavyweight ? new Container() : new TransparentPanel(); + JComponent buttonBar = fullScreen + ? new CallToolBarPanel(true) + : new CallToolBarPanel(false); - buttonBar.setLayout(new FlowLayout(FlowLayout.CENTER, 3, 3)); - - for (Component button : buttons) + if (buttons != null) { - if (button != null) - buttonBar.add(button); + for (Component button : buttons) + { + if (button != null) + ((Container) buttonBar).add(button); + } } + return buttonBar; } @@ -137,32 +115,74 @@ public static Frame getFrame(Component component) } /** - * Full screen exit button. Implements <tt>Skinnable</tt>. + * The tool bar container shown in the call window. */ - public static class ExitFullScreenButton - extends SIPCommButton - implements Skinnable + private static class CallToolBarPanel + extends OrderedTransparentPanel { - /** - * Creates an instance of SIPCommButton. - */ - public ExitFullScreenButton() + final Color settingsColor + = new Color(GuiActivator.getResources().getColor( + "service.gui.CALL_TOOL_BAR")); + + final Color settingsFullScreenColor + = new Color(GuiActivator.getResources().getColor( + "service.gui.CALL_TOOL_BAR_FULL_SCREEN")); + + final Image buttonSeparatorImage + = ImageLoader.getImage(ImageLoader.CALL_TOOLBAR_SEPARATOR); + + private final boolean isFullScreen; + + private final int TOOL_BAR_BORDER = 2; + + private final int TOOL_BAR_X_GAP = 3; + + public CallToolBarPanel(boolean isFullScreen) { - super( - ImageLoader.getImage(ImageLoader.FULL_SCREEN_BUTTON_BG), - ImageLoader.getImage(ImageLoader.EXIT_FULL_SCREEN_BUTTON)); + this.isFullScreen = isFullScreen; + + setLayout(new FlowLayout(FlowLayout.CENTER, 3, 0)); + setBorder(BorderFactory.createEmptyBorder( + TOOL_BAR_BORDER, + TOOL_BAR_BORDER, + TOOL_BAR_BORDER, + TOOL_BAR_BORDER)); } - /** - * Reloads icons. - */ - public void loadSkin() + public void paintComponent(Graphics g) { - setBackgroundImage( - ImageLoader.getImage(ImageLoader.FULL_SCREEN_BUTTON_BG)); - setIconImage( - ImageLoader.getImage(ImageLoader.EXIT_FULL_SCREEN_BUTTON)); - } + super.paintComponent(g); + + g = g.create(); + + AntialiasingManager.activateAntialiasing(g); + + try + { + if (isFullScreen) + g.setColor(settingsFullScreenColor); + else + g.setColor(settingsColor); + + g.fillRoundRect(0, 0, getWidth(), getHeight(), 8, 8); + + // We add the border. + int x = CallToolBarButton.DEFAULT_WIDTH + + TOOL_BAR_BORDER + TOOL_BAR_X_GAP; + + while (x < getWidth() - TOOL_BAR_BORDER - TOOL_BAR_X_GAP) + { + g.drawImage(buttonSeparatorImage, x + 1, + (getHeight() - buttonSeparatorImage.getHeight(this))/2, + this); + x += CallToolBarButton.DEFAULT_WIDTH + TOOL_BAR_X_GAP; + } + } + finally + { + g.dispose(); + } + } } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallToolBarButton.java b/src/net/java/sip/communicator/impl/gui/main/call/CallToolBarButton.java new file mode 100644 index 000000000..c63e63131 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallToolBarButton.java @@ -0,0 +1,72 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.call; + +import java.awt.*; + +import net.java.sip.communicator.util.swing.*; + +/** + * The <tt>CallBarButton</tt> is a button shown in the call window tool bar. + * + * @author Yana Stamcheva + */ +public class CallToolBarButton + extends SIPCommButton +{ + /** + * The default width of a button in the call tool bar. + */ + public static final int DEFAULT_WIDTH = 44; + + /** + * The default height of a button in the call tool bar. + */ + public static final int DEFAULT_HEIGHT = 38; + + /** + * Creates an instance of <tt>CallToolBarButton</tt>. + */ + public CallToolBarButton() + { + this(null, null); + } + + /** + * Creates an instance of <tt>CallToolBarButton</tt> by specifying the icon + * image and the tool tip text. + * + * @param iconImage the icon of this button + * @param tooltipText the text to show in the button tooltip + */ + public CallToolBarButton( Image iconImage, + String tooltipText) + { + this(iconImage, null, tooltipText); + } + + /** + * Creates an instance of <tt>CallToolBarButton</tt> by specifying the icon + * image, the name of the button and the tool tip text. + * + * @param iconImage the icon of this button + * @param buttonName the name of this button + * @param tooltipText the text to show in the button tooltip + */ + public CallToolBarButton( Image iconImage, + String buttonName, + String tooltipText) + { + super(null, iconImage); + + setIconImage(iconImage); + + setPreferredSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT)); + setName(buttonName); + setToolTipText(tooltipText); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/FullScreenButton.java b/src/net/java/sip/communicator/impl/gui/main/call/FullScreenButton.java index 216bde863..714b0fc97 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/FullScreenButton.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/FullScreenButton.java @@ -6,6 +6,7 @@ */ package net.java.sip.communicator.impl.gui.main.call; +import java.awt.*; import java.awt.event.*; import net.java.sip.communicator.impl.gui.*; @@ -23,6 +24,11 @@ public class FullScreenButton extends SIPCommButton implements Skinnable { + /** + * Indicates if this buttons is shown in full screen view or normal window. + */ + private boolean isFullScreen = false; + /** * Initializes a new <tt>FullScreenButton</tt> instance which is to * enter the full screen mode. @@ -30,13 +36,19 @@ public class FullScreenButton * @param callContainer the parent <tt>CallContainer</tt>, where this button * is contained */ - public FullScreenButton(final CallPanel callContainer) + public FullScreenButton(final CallPanel callContainer, + final boolean isFullScreen) { - super( ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG), - ImageLoader.getImage(ImageLoader.ENTER_FULL_SCREEN_BUTTON)); + this.isFullScreen = isFullScreen; + + if (isFullScreen) + setToolTipText(GuiActivator.getResources().getI18NString( + "service.gui.EXIT_FULL_SCREEN_TOOL_TIP")); + else + setToolTipText(GuiActivator.getResources().getI18NString( + "service.gui.ENTER_FULL_SCREEN_TOOL_TIP")); - setToolTipText(GuiActivator.getResources().getI18NString( - "service.gui.ENTER_FULL_SCREEN_TOOL_TIP")); + loadSkin(); addActionListener(new ActionListener() { @@ -49,7 +61,10 @@ public FullScreenButton(final CallPanel callContainer) */ public void actionPerformed(ActionEvent evt) { - callContainer.getCurrentCallRenderer().enterFullScreen(); + if (isFullScreen) + callContainer.getCurrentCallRenderer().exitFullScreen(); + else + callContainer.getCurrentCallRenderer().enterFullScreen(); } }); } @@ -59,10 +74,13 @@ public void actionPerformed(ActionEvent evt) */ public void loadSkin() { - setBackgroundImage(ImageLoader.getImage( - ImageLoader.CALL_SETTING_BUTTON_BG)); + setPreferredSize(new Dimension(44, 38)); - setIconImage(ImageLoader.getImage( + if (isFullScreen) + setIconImage(ImageLoader.getImage( + ImageLoader.EXIT_FULL_SCREEN_BUTTON)); + else + setIconImage(ImageLoader.getImage( ImageLoader.ENTER_FULL_SCREEN_BUTTON)); } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/FullScreenLayout.java b/src/net/java/sip/communicator/impl/gui/main/call/FullScreenLayout.java index 34032b306..6d1e86165 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/FullScreenLayout.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/FullScreenLayout.java @@ -33,18 +33,31 @@ public class FullScreenLayout private Component south; + /** + * The vertical gap between the center and the south components. + */ + private int yGap = 0; + /** * Initializes a new <tt>FullScreenLayout</tt> instance. * * @param overlay <tt>true</tt> to lay out the <tt>Component</tt> at * {@link #SOUTH} on top of the <tt>Component</tt> at {@link #CENTER} i.e as * an overlay; otherwise, <tt>false</tt> + * @oaram yGap the gap betwen the center and the south component */ - public FullScreenLayout(boolean overlay) + public FullScreenLayout(boolean overlay, int yGap) { this.overlay = overlay; + this.yGap = yGap; } + /** + * Adds the given component to this layout. + * + * @param name the name of the constraint (CENTER or SOUTH) + * @param comp the component to add to this layout + */ public void addLayoutComponent(String name, Component comp) { if (CENTER.equals(name)) @@ -72,6 +85,11 @@ private List<Component> getLayoutComponents() return layoutComponents; } + /** + * Lays out the components added in the given parent container + * + * @param parent the parent container to lay out + */ public void layoutContainer(Container parent) { int southWidth; @@ -97,7 +115,7 @@ public void layoutContainer(Container parent) * If the Component at the SOUTH is not to be shown as an overlay, * make room for it bellow the Component at the CENTER. */ - int yOffset = overlay ? 0 : southHeight; + int yOffset = overlay ? 0 : southHeight + yGap; center.setBounds( 0, diff --git a/src/net/java/sip/communicator/impl/gui/main/call/HangupButton.java b/src/net/java/sip/communicator/impl/gui/main/call/HangupButton.java new file mode 100644 index 000000000..645df7537 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/call/HangupButton.java @@ -0,0 +1,42 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.call; + +import java.awt.event.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.impl.gui.utils.*; + +/** + * The hangup button shown in the call window. + * + * @author Yana Stamcheva + */ +public class HangupButton + extends CallToolBarButton +{ + /** + * Creates an instance of <tt>HangupButton</tt>, by specifying the parent + * call panel. + * + * @param callPanel the parent call panel + */ + public HangupButton(final CallPanel callPanel) + { + super( ImageLoader.getImage(ImageLoader.HANGUP_BUTTON_BG), + GuiActivator.getResources() + .getI18NString("service.gui.HANG_UP")); + + addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + callPanel.actionPerformedOnHangupButton(false); + } + }); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/InputVolumeControlButton.java b/src/net/java/sip/communicator/impl/gui/main/call/InputVolumeControlButton.java index f318667ac..d16154817 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/InputVolumeControlButton.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/InputVolumeControlButton.java @@ -51,8 +51,14 @@ public class InputVolumeControlButton */ private final VolumeControl volumeControl; - private final VolumeControlSlider sliderMenu; + /** + * The slider popup menu. + */ + private final JPopupMenu sliderMenu; + /** + * Indicates if this component is shown in full screen mode. + */ private final boolean fullScreen; /** @@ -135,7 +141,9 @@ public InputVolumeControlButton(Call call, volumeControl = getVolumeControl(); // Creates the menu that would contain the volume control component. - sliderMenu = new VolumeControlSlider(volumeControl); + sliderMenu + = new VolumeControlSlider(volumeControl, JSlider.VERTICAL) + .getPopupMenu(); sliderMenu.setInvoker(this); addMouseListener(new MouseAdapter() diff --git a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPanel.java index 476d08968..f3558bb50 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPanel.java @@ -209,7 +209,7 @@ public void enterFullScreen() // Lay out the main Components of the UI. final Container contentPane = frame.getContentPane(); - contentPane.setLayout(new FullScreenLayout(false)); + contentPane.setLayout(new FullScreenLayout(false, 10)); if (buttonBar != null) contentPane.add(buttonBar, FullScreenLayout.SOUTH); if (center != null) @@ -331,7 +331,7 @@ public void exitFullScreen() * * @return the buttons bar <tt>Component</tt> */ - private Component createFullScreenButtonBar() + private JComponent createFullScreenButtonBar() { ShowHideVideoButton showHideButton = new ShowHideVideoButton( call, true, callContainer.isShowHideVideoButtonSelected()); @@ -341,16 +341,17 @@ private Component createFullScreenButtonBar() Component[] buttons = new Component[] { + new OutputVolumeControlButton(true).getComponent(), new InputVolumeControlButton(call, true, callPeer.isMute()), - new OutputVolumeControlButton(true), new HoldButton(call, true, CallPeerState.isOnHold(callPeer.getState())), new RecordButton(call, true, callContainer.isRecordingStarted()), + new FullScreenButton(callContainer, true), new LocalVideoButton( call, true, callContainer.isVideoButtonSelected()), showHideButton, - CallPeerRendererUtils.createExitFullScreenButton(this) + new HangupButton(callContainer) }; return CallPeerRendererUtils.createButtonBar(true, buttons); diff --git a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java index 7242a2296..f60cafd27 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java @@ -142,7 +142,7 @@ public class OneToOneCallPeerPanel /** * Sound remote level label. */ - private OutputVolumeControlButton remoteLevel; + private Component remoteLevel; /** * The center component. @@ -356,7 +356,7 @@ private void createSoundLevelIndicators() ImageLoader.MUTE_BUTTON, false, false, false); remoteLevel = new OutputVolumeControlButton( - ImageLoader.HEADPHONE, false, false); + ImageLoader.HEADPHONE, false, false).getComponent(); final SoundLevelIndicator localLevelIndicator = new SoundLevelIndicator( @@ -831,9 +831,8 @@ public void loadSkin() localLevel.setIcon(new ImageIcon( ImageLoader.getImage(ImageLoader.MICROPHONE))); - if(remoteLevel != null) - remoteLevel.setIcon(new ImageIcon( - ImageLoader.getImage(ImageLoader.HEADPHONE))); + if(remoteLevel != null && remoteLevel instanceof Skinnable) + ((Skinnable) remoteLevel).loadSkin(); if(muteStatusLabel.getIcon() != null) muteStatusLabel.setIcon(new ImageIcon( diff --git a/src/net/java/sip/communicator/impl/gui/main/call/OutputVolumeControlButton.java b/src/net/java/sip/communicator/impl/gui/main/call/OutputVolumeControlButton.java index 78a157d50..13b67718f 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/OutputVolumeControlButton.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/OutputVolumeControlButton.java @@ -14,6 +14,7 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.resources.*; +import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.swing.*; import org.jitsi.service.neomedia.*; @@ -26,7 +27,6 @@ * @author Damian Minkov */ public class OutputVolumeControlButton - extends SIPCommButton { /** * The background image. @@ -43,6 +43,16 @@ public class OutputVolumeControlButton */ private ImageID iconImageID; + /** + * Indicates if we're in full screen mode. + */ + private final boolean fullScreen; + + /** + * + */ + private final boolean inButtonToolBar; + /** * Creates not full screen button. */ @@ -53,68 +63,122 @@ public OutputVolumeControlButton() /** * Creates volume control button. + * * @param fullScreen is full screen. */ public OutputVolumeControlButton(boolean fullScreen) { - this(ImageLoader.VOLUME_CONTROL_BUTTON, fullScreen, false); + this(ImageLoader.VOLUME_CONTROL_BUTTON, fullScreen, true); } /** * Creates volume control button. + * * @param iconImageID the image. * @param fullScreen is full screen. + * @param inButtonToolBar indicates if this button is shown in the button + * tool bar */ public OutputVolumeControlButton(ImageID iconImageID, boolean fullScreen, - boolean inSettingsPanel) + boolean inButtonToolBar) { - super( ImageLoader.getImage(ImageLoader.SOUND_SETTING_BUTTON_PRESSED), - ImageLoader.getImage(iconImageID)); + this.fullScreen = fullScreen; + this.inButtonToolBar = inButtonToolBar; - initVolumeControlButton(fullScreen, inSettingsPanel, iconImageID, - "service.gui.VOLUME_CONTROL_TOOL_TIP"); + this.iconImageID = iconImageID; } /** - * - * @param fullScreen - * @param inSettingsPanel - * @param iconImageID - * @param toolTipTextKey + * Returns the component associated with this output volume control button. + * + * @return the component associated with this output volume control button */ - public void initVolumeControlButton(final boolean fullScreen, - boolean inSettingsPanel, - ImageID iconImageID, - String toolTipTextKey) + public Component getComponent() { - this.iconImageID = iconImageID; - - if (fullScreen) - { - bgImage = ImageLoader.FULL_SCREEN_BUTTON_BG; - pressedImage = ImageLoader.FULL_SCREEN_BUTTON_BG_PRESSED; - } + if (!fullScreen) + return createVolumeControlButton( + inButtonToolBar, + iconImageID, + "service.gui.VOLUME_CONTROL_TOOL_TIP"); else + return createSliderComponent(); + } + + /** + * Creates the slider component for the full screen interface. + * + * @return the created component + */ + public Component createSliderComponent() + { + final Color bgColor + = new Color(GuiActivator.getResources().getColor( + "service.gui.CALL_TOOL_BAR_SOUND_BG")); + + @SuppressWarnings("serial") + TransparentPanel soundPanel = new TransparentPanel( + new FlowLayout(FlowLayout.LEFT, 0, 0)) { - if(inSettingsPanel) + public void paintComponent(Graphics g) { - bgImage = ImageLoader.CALL_SETTING_BUTTON_BG; - pressedImage = ImageLoader.CALL_SETTING_BUTTON_PRESSED_BG; - } - else - { - bgImage = ImageLoader.SOUND_SETTING_BUTTON_BG; - pressedImage = ImageLoader.SOUND_SETTING_BUTTON_PRESSED; + super.paintComponent(g); + + g = g.create(); + + AntialiasingManager.activateAntialiasing(g); + + try + { + g.setColor(bgColor); + + g.fillRoundRect(0, 0, getWidth()-1, getHeight()-1, 8, 8); + } + finally + { + g.dispose(); + } } - } + }; + + soundPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); + final VolumeControl volumeControl + = GuiActivator.getMediaService().getOutputVolumeControl(); + + // Creates the menu that would contain the volume control component. + VolumeControlSlider slider + = new VolumeControlSlider(volumeControl, JSlider.HORIZONTAL); + + soundPanel.add(new JLabel(GuiActivator.getResources() + .getImage("service.gui.icons.NO_SOUND_ICON"))); + soundPanel.add(slider); + soundPanel.add(new JLabel(GuiActivator.getResources() + .getImage("service.gui.icons.SOUND_MENU_ICON"))); + + return soundPanel; + } + + /** + * Initializes the volume control button. + * + * @param fullScreen indicates if we're in fullscreen mode + * @param isButtonBar indicates if this button is shown in the button + * toolbar + * @param iconImageID the identifier of the button icon + * @param toolTipTextKey the key of the tool tip text + */ + public Component createVolumeControlButton( boolean isButtonBar, + ImageID iconImageID, + String toolTipTextKey) + { + this.iconImageID = iconImageID; - // Loads the skin of this button. - loadSkin(); + final SIPCommButton volumeControlButton + = new VolumeControlButton(isButtonBar); if (toolTipTextKey != null) { - setToolTipText( + volumeControlButton.setToolTipText( GuiActivator.getResources().getI18NString(toolTipTextKey)); } @@ -122,40 +186,78 @@ public void initVolumeControlButton(final boolean fullScreen, = GuiActivator.getMediaService().getOutputVolumeControl(); // Creates the menu that would contain the volume control component. - final VolumeControlSlider sliderMenu - = new VolumeControlSlider(volumeControl); + final JPopupMenu sliderMenu + = new VolumeControlSlider(volumeControl, JSlider.VERTICAL) + .getPopupMenu(); - sliderMenu.setInvoker(this); + sliderMenu.setInvoker(volumeControlButton); - this.addActionListener(new ActionListener() + volumeControlButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { - Point location = new Point(getX(), getY() + getHeight()); + Point location = new Point( + volumeControlButton.getX(), + volumeControlButton.getY() + + volumeControlButton.getHeight()); - SwingUtilities.convertPointToScreen(location, - OutputVolumeControlButton.this.getParent()); - - if(fullScreen) - location.setLocation(location.getX(), - location.getY() - - sliderMenu.getPreferredSize().getHeight() - - getHeight()); + SwingUtilities.convertPointToScreen( + location, + volumeControlButton.getParent()); sliderMenu.setLocation(location); sliderMenu.setVisible(!sliderMenu.isVisible()); } }); + + return volumeControlButton; } /** - * Loads images. + * The <tt>VolumeControlButton</tt> */ - public void loadSkin() + @SuppressWarnings("serial") + private class VolumeControlButton + extends SIPCommButton { - setBackgroundImage(ImageLoader.getImage(bgImage)); - setPressedImage(ImageLoader.getImage(pressedImage)); - setIconImage(ImageLoader.getImage(iconImageID)); + public VolumeControlButton(boolean inSettingsPanel) + { + super( + ImageLoader.getImage(ImageLoader.SOUND_SETTING_BUTTON_PRESSED), + ImageLoader.getImage(iconImageID)); + + if(inSettingsPanel) + { + bgImage = ImageLoader.CALL_SETTING_BUTTON_BG; + pressedImage = ImageLoader.CALL_SETTING_BUTTON_PRESSED_BG; + } + else + { + bgImage = ImageLoader.SOUND_SETTING_BUTTON_BG; + pressedImage = ImageLoader.SOUND_SETTING_BUTTON_PRESSED; + } + + // Loads the skin of this button. + loadSkin(); + } + + /** + * Loads images. + */ + public void loadSkin() + { + setBackgroundImage(ImageLoader.getImage(bgImage)); + setPressedImage(ImageLoader.getImage(pressedImage)); + + if (iconImageID != null) + { + if (!fullScreen && !inButtonToolBar) + setIconImage(ImageUtils.scaleImageWithinBounds( + ImageLoader.getImage(iconImageID), 18, 18)); + else + setIconImage(ImageLoader.getImage(iconImageID)); + } + } } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/TransferCallButton.java b/src/net/java/sip/communicator/impl/gui/main/call/TransferCallButton.java index 127a19334..6f31bec20 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/TransferCallButton.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/TransferCallButton.java @@ -12,8 +12,6 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.protocol.*; -import net.java.sip.communicator.util.skin.*; -import net.java.sip.communicator.util.swing.*; /** * Represents an UI means to transfer (the <tt>Call</tt> of) an associated @@ -24,8 +22,7 @@ * @author Adam Netocny */ public class TransferCallButton - extends SIPCommButton - implements Skinnable + extends CallToolBarButton { /** * The <tt>Call</tt> to be transfered. @@ -42,14 +39,12 @@ public class TransferCallButton */ public TransferCallButton(Call c) { - super( ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG), - ImageLoader.getImage(ImageLoader.TRANSFER_CALL_BUTTON)); + super( ImageLoader.getImage(ImageLoader.TRANSFER_CALL_BUTTON), + GuiActivator.getResources().getI18NString( + "service.gui.TRANSFER_BUTTON_TOOL_TIP")); this.call = c; - setToolTipText(GuiActivator.getResources().getI18NString( - "service.gui.TRANSFER_BUTTON_TOOL_TIP")); - OperationSetAdvancedTelephony<?> telephony = call.getProtocolProvider() .getOperationSet(OperationSetAdvancedTelephony.class); @@ -131,16 +126,4 @@ private Collection<CallPeer> getTransferCallPeers() } return transferCalls; } - - /** - * Reloads icons. - */ - public void loadSkin() - { - this.setBackgroundImage(ImageLoader.getImage( - ImageLoader.CALL_SETTING_BUTTON_BG)); - - this.setIconImage(ImageLoader.getImage( - ImageLoader.TRANSFER_CALL_BUTTON)); - } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/VolumeControlSlider.java b/src/net/java/sip/communicator/impl/gui/main/call/VolumeControlSlider.java index 9f8d2f271..e6e19d0b6 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/VolumeControlSlider.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/VolumeControlSlider.java @@ -22,7 +22,7 @@ * @author Yana Stamcheva */ public class VolumeControlSlider - extends SIPCommPopupMenu + extends TransparentPanel implements VolumeChangeListener { private final JSlider volumeSlider; @@ -41,12 +41,19 @@ public class VolumeControlSlider * @param volumeControl the <tt>VolumeControl</tt> that do the actual volume * adjusting. */ - public VolumeControlSlider(final VolumeControl volumeControl) + public VolumeControlSlider( final VolumeControl volumeControl, + int orientation) { + super(new BorderLayout()); + volumeControl.addVolumeChangeListener(this); - volumeSlider = new JSlider(JSlider.VERTICAL, 0, 100, 50); - volumeSlider.setPreferredSize(new Dimension(20, 100)); + volumeSlider = new JSlider(orientation, 0, 100, 50); + + if (orientation == JSlider.VERTICAL) + volumeSlider.setPreferredSize(new Dimension(20, 100)); + else + volumeSlider.setPreferredSize(new Dimension(100, 20)); // Sets the minimum, maximum and default volume values for the volume // slider. @@ -83,4 +90,18 @@ public void volumeChange(VolumeChangeEvent volumeChangeEvent) if (volumeSlider.getValue() != newValue) volumeSlider.setValue(newValue); } + + /** + * Returns this slider in a popup menu. + * + * @return this slider in a popup menu + */ + public JPopupMenu getPopupMenu() + { + SIPCommPopupMenu popupMenu = new SIPCommPopupMenu(); + + popupMenu.add(this); + + return popupMenu; + } } diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationComponent.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationComponent.java index e25a9afb1..219169742 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationComponent.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationComponent.java @@ -296,7 +296,7 @@ protected void openFile(File downloadFile) */ public String getDateString(Date date) { - return ChatConversationPanel.getDateString(date.getTime()) + return ChatHtmlUtils.getDateString(date.getTime()) + GuiUtils.formatTime(date) + " "; } diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java index fba0eee16..3ec57faa2 100755 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java @@ -23,11 +23,11 @@ import javax.swing.text.html.HTML.*; import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.customcontrols.*; import net.java.sip.communicator.impl.gui.main.chat.history.*; import net.java.sip.communicator.impl.gui.main.chat.menus.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.replacement.*; import net.java.sip.communicator.service.replacement.smilies.*; import net.java.sip.communicator.util.*; @@ -60,16 +60,6 @@ public class ChatConversationPanel private static final Logger logger = Logger.getLogger(ChatConversationPanel.class); - /** - * The closing tag of the <code>PLAINTEXT</code> HTML element. - */ - private static final String END_PLAINTEXT_TAG = "</PLAINTEXT>"; - - /** - * The opening tag of the <code>PLAINTEXT</code> HTML element. - */ - private static final String START_PLAINTEXT_TAG = "<PLAINTEXT>"; - /** * The regular expression (in the form of compiled <tt>Pattern</tt>) which * matches URLs for the purposed of turning them into links. @@ -141,19 +131,14 @@ public class ChatConversationPanel private long lastIncomingMsgTimestamp; /** - * Indicates if this component is rendering a history conversation. + * The timestamp of the last message. */ - private final boolean isHistory; + private long lastMessageTimestamp; /** - * The html text content type. - */ - public static final String HTML_CONTENT_TYPE = "text/html"; - - /** - * The plain text content type. + * Indicates if this component is rendering a history conversation. */ - public static final String TEXT_CONTENT_TYPE = "text/plain"; + private final boolean isHistory; /** * The indicator which determines whether an automatic scroll to the bottom @@ -161,6 +146,8 @@ public class ChatConversationPanel */ private boolean scrollToBottomIsPending = false; + private String lastMessageUID = null; + /** * The implementation of the routine which scrolls {@link #chatTextPane} to its * bottom. @@ -338,32 +325,6 @@ public void setBounds(int x, int y, int width, int height) super.setBounds(x, y, width, height); } - /** - * Initializes the editor by adding a header containing the date. - * TODO: remove if not used anymore - */ -// private void initEditor() -// { -// Element root = this.document.getDefaultRootElement(); -// -// Date date = new Date(System.currentTimeMillis()); -// -// String chatHeader = "<h1>" + GuiUtils.formatDate(date) + " " + "</h1>"; -// -// try -// { -// this.document.insertAfterStart(root, chatHeader); -// } -// catch (BadLocationException e) -// { -// logger.error("Insert in the HTMLDocument failed.", e); -// } -// catch (IOException e) -// { -// logger.error("Insert in the HTMLDocument failed.", e); -// } -// } - /** * Retrieves the contents of the sent message with the given ID. * @@ -373,7 +334,11 @@ public void setBounds(int x, int y, int width, int height) public String getMessageContents(String messageUID) { Element root = document.getDefaultRootElement(); - Element e = document.getElement(root, Attribute.ID, messageUID); + Element e = document.getElement( + root, + Attribute.ID, + ChatHtmlUtils.MESSAGE_TEXT_ID + messageUID); + if (e == null) { logger.warn("Could not find message with ID" + messageUID); @@ -394,38 +359,6 @@ public String getMessageContents(String messageUID) return res; } - /** - * Creates a tag that shows the last edit time of a message, in the format - * (Edited at ...). - * If <tt>date < 0</tt>, returns an empty tag that serves as a placeholder - * for future corrections of this message. - * - * @param messageUID The ID of the edited message. - * @param date The date when the message was last edited, or -1 to generate - * an empty tag. - * @return The string representation of the tag. - */ - private String generateEditedAtTag(String messageUID, long date) - { - StringBuilder res = new StringBuilder(); - // Use a <cite /> tag here as most of the other inline tags (e.g. h1-7, - // b, i) cause different problems when used in setOuterHTML. - res.append("<cite id='"); - res.append(messageUID); - res.append("-editedAt'> "); - if (date > 0) - { - res.append("&nbsp;"); - String contents = GuiActivator.getResources().getI18NString( - "service.gui.EDITED_AT", - new String[] { GuiUtils.formatTime(date) } - ); - res.append(contents); - } - res.append("</cite>"); - return res.toString(); - } - /** * Processes the message given by the parameters. * @@ -434,8 +367,20 @@ private String generateEditedAtTag(String messageUID, long date) * display of <tt>chatMessage</tt> in the UI * @return the processed message */ - public String processMessage(ChatMessage chatMessage, String keyword) + public String processMessage( ChatMessage chatMessage, + String keyword, + ProtocolProviderService protocolProvider, + String contactAddress) { + String contentType = chatMessage.getContentType(); + + // If this is a consecutive message don't go through the initiation + // and just append it. + if (appendConsecutiveMessage(chatMessage, keyword, contentType)) + return null; + + lastMessageTimestamp = chatMessage.getDate(); + String contactName = chatMessage.getContactName(); String contactDisplayName = chatMessage.getContactDisplayName(); if (contactDisplayName == null @@ -445,99 +390,88 @@ public String processMessage(ChatMessage chatMessage, String keyword) { // for some reason &apos; is not rendered correctly from our ui, // lets use its equivalent. Other similar chars(< > & ") seem ok. - contactDisplayName = contactDisplayName.replaceAll("&apos;", "&#39;"); + contactDisplayName + = contactDisplayName.replaceAll("&apos;", "&#39;"); } - String contentType = chatMessage.getContentType(); long date = chatMessage.getDate(); String messageType = chatMessage.getMessageType(); String messageTitle = chatMessage.getMessageTitle(); - String message = chatMessage.getMessage(); String messageUID = chatMessage.getMessageUID(); - - String msgID = "message"; - String msgHeaderID = "messageHeader"; + String message = chatMessage.getMessage(); + String msgID = ChatHtmlUtils.MESSAGE_TEXT_ID + messageUID; String chatString = ""; String endHeaderTag = ""; - String dateString = getDateString(date); - String idAttr = messageUID == null ? "" : " id='" + messageUID + "'"; - String dateAttr = " date='" + date + "'"; - String editedAtTag = generateEditedAtTag(messageUID, -1); - - String startDivTag = "<DIV identifier=\"" + msgID + "\"" + idAttr + ">"; - String startHistoryDivTag - = "<DIV identifier=\"" + msgID + "\" style=\"color:#707070;\">"; + String startSystemDivTag = "<DIV identifier=\"systemMessage\" style=\"color:#627EB7;\">"; String endDivTag = "</DIV>"; - String startPlainTextTag; - String endPlainTextTag; + lastMessageUID = messageUID; - if (HTML_CONTENT_TYPE.equals(contentType)) + String startPlainTextTag + = ChatHtmlUtils.createStartPlainTextTag(contentType); + String endPlainTextTag + = ChatHtmlUtils.createEndPlainTextTag(contentType); + + if (messageType.equals(Chat.INCOMING_MESSAGE)) { - startPlainTextTag = ""; - endPlainTextTag = ""; + this.lastIncomingMsgTimestamp = System.currentTimeMillis(); + + chatString = ChatHtmlUtils.createIncomingMessageTag( + msgID, + contactName, + contactDisplayName, + getContactAvatar(protocolProvider, contactAddress), + date, + formatMessage(message, contentType, keyword), + contentType); } - else + else if (messageType.equals(Chat.OUTGOING_MESSAGE)) { - startPlainTextTag = START_PLAINTEXT_TAG; - endPlainTextTag = END_PLAINTEXT_TAG; + chatString = ChatHtmlUtils.createOutgoingMessageTag( + msgID, + contactName, + contactDisplayName, + getContactAvatar(protocolProvider), + date, + formatMessage(message, contentType, keyword), + contentType); } - - if (messageType.equals(Chat.INCOMING_MESSAGE)) + else if (messageType.equals(Chat.HISTORY_INCOMING_MESSAGE)) { this.lastIncomingMsgTimestamp = System.currentTimeMillis(); - chatString = "<h2 identifier=\"" + msgHeaderID + "\"" - + dateAttr + ">" - + "<a style=\"color:#ef7b1e;" - + "font-weight:bold;" - + "text-decoration:none;\" " - + "href=\"" + contactName + "\">"; - - endHeaderTag = "</a></h2>"; - - chatString - += dateString + contactDisplayName + " at " - + GuiUtils.formatTime(date) + editedAtTag + endHeaderTag - + startDivTag + startPlainTextTag - + formatMessage(message, contentType, keyword) - + endPlainTextTag + endDivTag; + chatString = ChatHtmlUtils.createIncomingMessageTag( + msgID, + contactName, + contactDisplayName, + getContactAvatar(protocolProvider, contactAddress), + date, + formatMessage(message, contentType, keyword), + contentType); } - else if (messageType.equals(Chat.SMS_MESSAGE)) + else if (messageType.equals(Chat.HISTORY_OUTGOING_MESSAGE)) { - chatString = "<h2 identifier=\"" - + msgHeaderID - + "\" date=\"" - + date + "\">"; - - endHeaderTag = "</h2>"; - - chatString - += "SMS: " + dateString + contactName + " at " - + GuiUtils.formatTime(date) + endHeaderTag + startDivTag - + startPlainTextTag - + formatMessage(message, contentType, keyword) - + endPlainTextTag + endDivTag; + chatString = ChatHtmlUtils.createOutgoingMessageTag( + msgID, + contactName, + contactDisplayName, + getContactAvatar(protocolProvider), + date, + formatMessage(message, contentType, keyword), + contentType); } - else if (messageType.equals(Chat.OUTGOING_MESSAGE)) + else if (messageType.equals(Chat.SMS_MESSAGE)) { - chatString = "<h3 identifier=\"" + msgHeaderID + "\"" - + dateAttr + ">" - + "<a style=\"color:#2e538b;" - + "font-weight:bold;" - + "text-decoration:none;\" " - + "href=\"" + contactName + "\">"; - - endHeaderTag = "</a></h3>"; - - chatString - += dateString + contactDisplayName + " at " - + GuiUtils.formatTime(date) + editedAtTag + endHeaderTag - + startDivTag + startPlainTextTag - + formatMessage(message, contentType, keyword) - + endPlainTextTag + endDivTag; + chatString = ChatHtmlUtils.createIncomingMessageTag( + msgID, + contactName, + contactDisplayName, + getContactAvatar(protocolProvider, contactAddress), + date, + formatMessage("SMS: " + message, contentType, keyword), + contentType); } else if (messageType.equals(Chat.STATUS_MESSAGE)) { @@ -570,7 +504,7 @@ else if (messageType.equals(Chat.SYSTEM_MESSAGE)) else if (messageType.equals(Chat.ERROR_MESSAGE)) { chatString = "<h6 identifier=\"" - + msgHeaderID + + ChatHtmlUtils.MESSAGE_HEADER_ID + "\" date=\"" + date + "\">"; @@ -584,43 +518,6 @@ else if (messageType.equals(Chat.ERROR_MESSAGE)) + messageTitle + endHeaderTag + "<h5>" + message + "</h5>"; } - else if (messageType.equals(Chat.HISTORY_INCOMING_MESSAGE)) - { - chatString = "<h2 identifier=\"" + msgHeaderID + "\"" - + dateAttr + ">" - + "<a style=\"color:#ef7b1e;" - + "font-weight:bold;" - + "text-decoration:none;\" " - + "href=\"" + contactName + "\">"; - - endHeaderTag = "</a></h2>"; - - chatString - += dateString + contactDisplayName - + " at " + GuiUtils.formatTime(date) + endHeaderTag - + editedAtTag + startHistoryDivTag + startPlainTextTag - + formatMessage(message, contentType, keyword) - + endPlainTextTag + endDivTag; - } - else if (messageType.equals(Chat.HISTORY_OUTGOING_MESSAGE)) - { - chatString = "<h3 identifier=\"" + msgHeaderID + "\"" - + dateAttr + ">" - + "<a style=\"color:#2e538b;" - + "font-weight:bold;" - + "text-decoration:none;\" " - + "href=\"" + contactName + "\">"; - - endHeaderTag = "</h3>"; - - chatString - += dateString - + contactDisplayName + " at " + GuiUtils.formatTime(date) - + editedAtTag + endHeaderTag - + startHistoryDivTag + startPlainTextTag - + formatMessage(message, contentType, keyword) - + endPlainTextTag + endDivTag; - } return chatString; } @@ -631,9 +528,91 @@ else if (messageType.equals(Chat.HISTORY_OUTGOING_MESSAGE)) * @param chatMessage the message. * @return the formatted message */ - public String processMessage(ChatMessage chatMessage) + public String processMessage( ChatMessage chatMessage, + ProtocolProviderService protocolProvider, + String contactAddress) + { + return processMessage( chatMessage, + null, + protocolProvider, + contactAddress); + } + + /** + * Appends a consecutive message to the document. + * + * @param chatMessage the message to append + * @return <tt>true</tt> if the append succeeded, <tt>false</tt> - otherwise + */ + public boolean appendConsecutiveMessage(ChatMessage chatMessage, + String keyword, + String contentType) { - return processMessage(chatMessage, null); + if (lastMessageUID == null) + return false; + + Element root = document.getDefaultRootElement(); + Element lastMsgElement = document.getElement(root, Attribute.ID, + ChatHtmlUtils.MESSAGE_TEXT_ID + lastMessageUID); + + if (lastMsgElement == null) + { + logger.warn("Could not find message with ID " + lastMessageUID); + return false; + } + + String contactAddress + = (String) lastMsgElement.getAttributes() + .getAttribute(Attribute.NAME); + + if (contactAddress != null + && contactAddress.equals(chatMessage.getContactName()) + // And if the new message is within a minute from the last one. + && (chatMessage.getDate() - lastMessageTimestamp + < 60000)) + { + String newMessage = ChatHtmlUtils.createMessageTag( + ChatHtmlUtils.MESSAGE_TEXT_ID + + chatMessage.getMessageUID(), + contactAddress, + formatMessage(chatMessage.getMessage(), + contentType, + keyword), + contentType, + chatMessage.getDate(), + false); + + synchronized (scrollToBottomRunnable) + { + try + { + Element parentElement = lastMsgElement.getParentElement(); + + document.insertBeforeEnd(parentElement, newMessage); + + lastMessageUID = chatMessage.getMessageUID(); + + // Need to call explicitly scrollToBottom, because for some + // reason the componentResized event isn't fired every time + // we add text. + SwingUtilities.invokeLater(scrollToBottomRunnable); + } + catch (BadLocationException ex) + { + logger.error("Could not replace chat message", ex); + } + catch (IOException ex) + { + logger.error("Could not replace chat message", ex); + } + } + + finishMessageAdd(newMessage, contentType); + + return true; + } + + return false; } /** @@ -647,82 +626,78 @@ public void correctMessage(ChatMessage chatMessage) { String correctedUID = chatMessage.getCorrectedMessageUID(); Element root = document.getDefaultRootElement(); - Element e = document.getElement(root, Attribute.ID, correctedUID); - if (e == null) + Element correctedMsgElement + = document.getElement(root, + Attribute.ID, + ChatHtmlUtils.MESSAGE_TEXT_ID + correctedUID); + + if (correctedMsgElement == null) { logger.warn("Could not find message with ID " + correctedUID); return; } - int len = e.getEndOffset() - e.getStartOffset(); - - StringBuilder newContents = new StringBuilder(); - String bgColor = GuiActivator.getResources().getColorString( - "service.gui.CHAT_EDIT_MESSAGE_BACKGROUND"); - newContents.append("<div identifier='message' id='"); - newContents.append(chatMessage.getMessageUID()); - newContents.append("' bgcolor='"); - newContents.append(bgColor); - newContents.append("'>"); - if (chatMessage.getContentType().equals(TEXT_CONTENT_TYPE)) - { - newContents.append(START_PLAINTEXT_TAG); - newContents.append(chatMessage.getMessage()); - newContents.append(END_PLAINTEXT_TAG); - } - else - { - newContents.append(chatMessage.getMessage()); - } - newContents.append("</div>"); - - Element header = document.getElement(root, Attribute.ID, - correctedUID + "-editedAt"); - - try + + String contactAddress + = (String) correctedMsgElement.getAttributes() + .getAttribute(Attribute.NAME); + + String newMessage = ChatHtmlUtils.createMessageTag( + ChatHtmlUtils.MESSAGE_TEXT_ID + + chatMessage.getMessageUID(), + contactAddress, + formatMessage( chatMessage.getMessage(), + chatMessage.getContentType(), + ""), + chatMessage.getContentType(), + chatMessage.getDate(), + true); + + synchronized (scrollToBottomRunnable) { - if (header != null) + try { - String newHeaderContents = generateEditedAtTag( - chatMessage.getMessageUID(), chatMessage.getDate()); - document.setOuterHTML(header, newHeaderContents); + document.setOuterHTML(correctedMsgElement, newMessage); + + lastMessageUID = chatMessage.getMessageUID(); + + // Need to call explicitly scrollToBottom, because for some + // reason the componentResized event isn't fired every time + // we add text. + SwingUtilities.invokeLater(scrollToBottomRunnable); + } + catch (BadLocationException ex) + { + logger.error("Could not replace chat message", ex); + } + catch (IOException ex) + { + logger.error("Could not replace chat message", ex); } - document.setOuterHTML(e, newContents.toString()); - } - catch (BadLocationException ex) - { - logger.error("Could not replace chat message", ex); - } - catch (IOException ex) - { - logger.error("Could not replace chat message", ex); } + + finishMessageAdd(newMessage, chatMessage.getContentType()); } /** * Appends the given string at the end of the contained in this panel * document. * - * @param chatString the string to append + * @param message the message string to append */ - public void appendMessageToEnd(String chatString, String contentType) + public void appendMessageToEnd(String message, String contentType) { + if (message == null) + return; + synchronized (scrollToBottomRunnable) { Element root = document.getDefaultRootElement(); -// Need to call explicitly scrollToBottom, because for some -// reason the componentResized event isn't fired every time we -// add text. -// Replaced by the code on line: 573. -// -// scrollToBottomIsPending = true; - try { - document - .insertAfterEnd( - root.getElement(root.getElementCount() - 1), - chatString); + document.insertAfterEnd( + root.getElement(root.getElementCount() - 1), + message); // Need to call explicitly scrollToBottom, because for some // reason the componentResized event isn't fired every time we @@ -737,33 +712,44 @@ public void appendMessageToEnd(String chatString, String contentType) { logger.error("Insert in the HTMLDocument failed.", e); } - if (!isHistory) - ensureDocumentSize(); + } - // Process replacements. - final Element elem; - /* - * Check to make sure element isn't the first element in the HTML - * document. - */ - if (!(root.getElementCount() < 2)) - { - elem = root.getElement(root.getElementCount() - 2); - } - else - elem = root.getElement(1); + finishMessageAdd(message, contentType); + } - /* - * Replacements will be processed only if it is enabled in the - * property - */ - if (GuiActivator.getConfigurationService().getBoolean( - ReplacementProperty.REPLACEMENT_ENABLE, true) - || GuiActivator.getConfigurationService().getBoolean( - ReplacementProperty.getPropertyName("SMILEY"), true)) - { - processReplacement(elem, chatString, contentType); - } + /** + * Performs all operations needed in order to finish the adding of the + * message to the document. + * + * @param message the message string + * @param contentType + */ + private void finishMessageAdd(String message, String contentType) + { + Element root = document.getDefaultRootElement(); + + // If we're not in chat history case we need to be sure the document + // has not exceeded the required size (number of messages). + if (!isHistory) + ensureDocumentSize(); + + /* + * Check to make sure element isn't the first element in the HTML + * document. + */ + Element elem = document.getElement(root, Attribute.ID, + ChatHtmlUtils.MESSAGE_TEXT_ID + lastMessageUID); + + /* + * Replacements will be processed only if it is enabled in the + * property. + */ + if (GuiActivator.getConfigurationService().getBoolean( + ReplacementProperty.REPLACEMENT_ENABLE, true) + || GuiActivator.getConfigurationService().getBoolean( + ReplacementProperty.getPropertyName("SMILEY"), true)) + { + processReplacement(elem, message, contentType); } } @@ -818,15 +804,6 @@ public Object construct() throws Exception Matcher m = p.matcher(msgStore); - String startPlainTextTag = ""; - String endPlainTextTag = ""; - - if (!HTML_CONTENT_TYPE.equals(contentType)) - { - startPlainTextTag = START_PLAINTEXT_TAG; - endPlainTextTag = END_PLAINTEXT_TAG; - } - int count = 0, startPos = 0; StringBuffer msgBuff = new StringBuffer(); @@ -843,7 +820,9 @@ public Object construct() throws Exception { if(isSmiley) { - msgBuff.append(endPlainTextTag); + msgBuff.append( + ChatHtmlUtils.createEndPlainTextTag( + contentType)); msgBuff.append("<IMG SRC=\""); } else @@ -858,7 +837,9 @@ public Object construct() throws Exception msgBuff.append("\"></IMG>"); if(isSmiley) - msgBuff.append(startPlainTextTag); + msgBuff.append( + ChatHtmlUtils.createStartPlainTextTag( + contentType)); } else { @@ -884,8 +865,12 @@ public Object construct() throws Exception synchronized (scrollToBottomRunnable) { scrollToBottomIsPending = true; + + int msgStartIndex = msgStore.indexOf("<div id"); document.setOuterHTML(elem, msgStore.toString() - .substring(msgStore.indexOf("<DIV"))); + .substring( + msgStartIndex, + msgStore.indexOf("</div>", msgStartIndex))); } } return ""; @@ -916,7 +901,7 @@ private void ensureDocumentSize() .getAttributes().getAttribute("identifier"); if(idAttr != null - && (idAttr.equals("message") + && (idAttr.startsWith(ChatHtmlUtils.MESSAGE_TEXT_ID) || idAttr.equals("statusMessage") || idAttr.equals("systemMessage"))) { @@ -940,7 +925,8 @@ private void ensureDocumentSize() // Remove the header of the message if such exists. if(firstMsgIndex > 0) { - Element headerElement = rootElement.getElement(firstMsgIndex - 1); + Element headerElement + = rootElement.getElement(firstMsgIndex - 1); String idAttr = (String) headerElement .getAttributes().getAttribute("identifier"); @@ -977,20 +963,6 @@ private String processKeyword( String message, String contentType, String keyword) { - String startPlainTextTag; - String endPlainTextTag; - - if (HTML_CONTENT_TYPE.equals(contentType)) - { - startPlainTextTag = ""; - endPlainTextTag = ""; - } - else - { - startPlainTextTag = START_PLAINTEXT_TAG; - endPlainTextTag = END_PLAINTEXT_TAG; - } - Matcher m = Pattern.compile(Pattern.quote(keyword), Pattern.CASE_INSENSITIVE) .matcher(message); @@ -1004,11 +976,11 @@ private String processKeyword( String message, String keywordMatch = m.group().trim(); - msgBuffer.append(endPlainTextTag); + msgBuffer.append(ChatHtmlUtils.createEndPlainTextTag(contentType)); msgBuffer.append("<b>"); msgBuffer.append(keywordMatch); msgBuffer.append("</b>"); - msgBuffer.append(startPlainTextTag); + msgBuffer.append(ChatHtmlUtils.createStartPlainTextTag(contentType)); } /* @@ -1037,7 +1009,7 @@ private String formatMessage(String message, { // If the message content type is HTML we won't process links and // new lines, but only the smileys. - if (!HTML_CONTENT_TYPE.equals(contentType)) + if (!ChatHtmlUtils.HTML_CONTENT_TYPE.equals(contentType)) { /* @@ -1065,7 +1037,8 @@ private String formatMessage(String message, message = processNewLines( - processLinksAndHTMLChars(message, processHTMLChars)); + processLinksAndHTMLChars( + message, processHTMLChars, contentType), contentType); } // If the message content is HTML, we process br and img tags. else @@ -1090,10 +1063,12 @@ private String formatMessage(String message, * @param message The source message string. * @param processHTMLChars <tt>true</tt> to escape the special HTML chars; * otherwise, <tt>false</tt> + * @param contentType the message content type (html or plain text) * @return The message string with properly formatted links. */ private String processLinksAndHTMLChars(String message, - boolean processHTMLChars) + boolean processHTMLChars, + String contentType) { Matcher m = URL_PATTERN.matcher(message); StringBuffer msgBuffer = new StringBuffer(); @@ -1110,7 +1085,7 @@ private String processLinksAndHTMLChars(String message, String url = m.group().trim(); - msgBuffer.append(END_PLAINTEXT_TAG); + msgBuffer.append(ChatHtmlUtils.createEndPlainTextTag(contentType)); msgBuffer.append("<A href=\""); if (url.startsWith("www")) msgBuffer.append("http://"); @@ -1118,7 +1093,7 @@ private String processLinksAndHTMLChars(String message, msgBuffer.append("\">"); msgBuffer.append(url); msgBuffer.append("</A>"); - msgBuffer.append(START_PLAINTEXT_TAG); + msgBuffer.append(ChatHtmlUtils.createStartPlainTextTag(contentType)); } String fromPrevEndToEnd = message.substring(prevEnd); @@ -1151,9 +1126,10 @@ private String processHTMLChars(String message) * Formats message new lines. * * @param message The source message string. + * @param contentType message contentType (html or plain text) * @return The message string with properly formatted new lines. */ - private String processNewLines(String message) + private String processNewLines(String message, String contentType) { /* @@ -1171,7 +1147,9 @@ private String processNewLines(String message) message .replaceAll( "\n", - END_PLAINTEXT_TAG + "<BR/>&#10;" + START_PLAINTEXT_TAG); + ChatHtmlUtils.createEndPlainTextTag(contentType) + + "<BR/>&#10;" + + ChatHtmlUtils.createStartPlainTextTag(contentType)); } /** @@ -1508,7 +1486,8 @@ private String processImgTags(String message) int start = 0; // while we find some <img /> self-closing tags with a slash inside. - while(m.find()){ + while(m.find()) + { // First, we have to copy all the message preceding the <img> tag. processedMessage.append(message.substring(start, m.start())); // Then, we find the position of the slash inside the tag. @@ -1577,13 +1556,16 @@ public void addComponent(ChatConversationComponent component) wrapPanel.add(component, BorderLayout.NORTH); - style - .addAttribute(StyleConstants.ComponentAttribute, wrapPanel); + style.addAttribute(StyleConstants.ComponentAttribute, wrapPanel); style.addAttribute("identifier", "messageHeader"); style.addAttribute("date", component.getDate().getTime()); scrollToBottomIsPending = true; + // We need to reinitialize the last message ID, because we don't + // want components to be taken into account. + lastMessageUID = null; + // Insert the component style at the end of the text try { @@ -1619,26 +1601,6 @@ public void removeChatLinkClickedListener(ChatLinkClickedListener listener) chatLinkClickedListeners.remove(listener); } - /** - * Returns the date string to show for the given date. - * - * @param date the date to format - * @return the date string to show for the given date - */ - public static String getDateString(long date) - { - if (GuiUtils.compareDatesOnly(date, System.currentTimeMillis()) < 0) - { - StringBuffer dateStrBuf = new StringBuffer(); - - GuiUtils.formatDate(date, dateStrBuf); - dateStrBuf.append(" "); - return dateStrBuf.toString(); - } - - return ""; - } - /** * Reloads images. */ @@ -1665,33 +1627,26 @@ public String processChatRoomHighlight(String message, String contentType, { return processKeyword(message, contentType, keyWord); } - + + /** + * Processes /me command in group chats. + * + * @param chatMessage the chat message + * @return the newly processed message string + */ public String processMeCommand(ChatMessage chatMessage) { String contentType = chatMessage.getContentType(); String message = chatMessage.getMessage(); - String msgID = "message"; + String msgID + = ChatHtmlUtils.MESSAGE_TEXT_ID + chatMessage.getMessageUID(); String chatString = ""; String endHeaderTag = ""; - String startDivTag = "<DIV identifier=\"" + msgID + "\">"; + String startDivTag = "<DIV id=\"" + msgID + "\">"; String endDivTag = "</DIV>"; - String startPlainTextTag; - String endPlainTextTag; - - if (HTML_CONTENT_TYPE.equals(contentType)) - { - startPlainTextTag = ""; - endPlainTextTag = ""; - } - else - { - startPlainTextTag = START_PLAINTEXT_TAG; - endPlainTextTag = END_PLAINTEXT_TAG; - } - if (message.length() > 4 && message.substring(0, 4).equals("/me ")) { chatString = startDivTag + "<B><I>"; @@ -1699,7 +1654,6 @@ public String processMeCommand(ChatMessage chatMessage) endHeaderTag = "</I></B>" + endDivTag; chatString += - processHTMLChars("*** " + chatMessage.getContactName() + " " + message.substring(4)) + endHeaderTag; @@ -1731,9 +1685,13 @@ public String processMeCommand(ChatMessage chatMessage) while (m.find()) { - msgTemp.insert(m.start(), startPlainTextTag); - msgTemp.insert(m.end() + startPlainTextTag.length(), - endPlainTextTag); + msgTemp.insert(m.start(), + ChatHtmlUtils.createStartPlainTextTag(contentType)); + msgTemp.insert( + m.end() + + ChatHtmlUtils + .createStartPlainTextTag(contentType).length(), + ChatHtmlUtils.createEndPlainTextTag(contentType)); } if (msgTemp.length() != msgStore.length()) @@ -1746,4 +1704,72 @@ public String processMeCommand(ChatMessage chatMessage) else return ""; } -} + + /** + * Returns the avatar corresponding to the account of the given + * <tt>protocolProvider</tt>. + * + * @param protocolProvider the protocol provider service, which account + * avatar we're looking for + * @return the avatar corresponding to the account of the given + * <tt>protocolProvider</tt> + */ + private static String getContactAvatar( + ProtocolProviderService protocolProvider, + String contactAddress) + { + String avatarPath + = AvatarCacheUtils.getCachedAvatarPath( protocolProvider, + contactAddress); + + File avatarFile; + try + { + avatarFile = GuiActivator.getFileAccessService() + .getPrivatePersistentFile(avatarPath); + } + catch (Exception e) + { + return null; + } + + if(avatarFile.exists() && avatarFile.length() > 0) + return "file:" + avatarFile.getAbsolutePath(); + else + return GuiActivator.getResources().getImageURL( + "service.gui.DEFAULT_USER_PHOTO_SMALL").toString(); + } + + /** + * Returns the avatar corresponding to the account of the given + * <tt>protocolProvider</tt>. + * + * @param protocolProvider the protocol provider service, which account + * avatar we're looking for + * @return the avatar corresponding to the account of the given + * <tt>protocolProvider</tt> + */ + private static String getContactAvatar( + ProtocolProviderService protocolProvider) + { + String avatarPath + = AvatarCacheUtils.getCachedAvatarPath(protocolProvider); + + File avatarFile; + try + { + avatarFile = GuiActivator.getFileAccessService() + .getPrivatePersistentFile(avatarPath); + } + catch (Exception e) + { + return null; + } + + if(avatarFile.exists() && avatarFile.length() > 0) + return "file:" + avatarFile.getAbsolutePath(); + else + return GuiActivator.getResources().getImageURL( + "service.gui.DEFAULT_USER_PHOTO_SMALL").toString(); + } +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatHtmlUtils.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatHtmlUtils.java new file mode 100644 index 000000000..98293f3b4 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatHtmlUtils.java @@ -0,0 +1,412 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.util.*; + +/** + * + * @author Yana Stamcheva + */ +public class ChatHtmlUtils +{ + /** + * The name attribute. + */ + public final static String NAME_ATTRIBUTE = "name"; + + /** + * The date attribute. + */ + public final static String DATE_ATTRIBUTE = "date"; + + /** + * The message header identifier attribute. + */ + public final static String MESSAGE_HEADER_ID = "messageHeader"; + + /** + * The message identifier attribute. + */ + public final static String MESSAGE_TEXT_ID = "message"; + + /** + * The closing tag of the <code>PLAINTEXT</code> HTML element. + */ + private static final String END_PLAINTEXT_TAG = "</PLAINTEXT>"; + + /** + * The opening tag of the <code>PLAINTEXT</code> HTML element. + */ + private static final String START_PLAINTEXT_TAG = "<PLAINTEXT>"; + + /** + * The html text content type. + */ + public static final String HTML_CONTENT_TYPE = "text/html"; + + /** + * The plain text content type. + */ + public static final String TEXT_CONTENT_TYPE = "text/plain"; + + /** + * Creates an incoming message tag. + * + * @param messageID the identifier + * @param contactName the name of the contact sending the message + * @param contactDisplayName the display name of the contact sending the + * message + * @param avatarPath the path to the avatar file + * @param date the date, when the message was sent + * @param message the message content + * @param contentType the content type HTML or PLAIN_TEXT + * @return the created incoming message tag + */ + public static String createIncomingMessageTag( + String messageID, + String contactName, + String contactDisplayName, + String avatarPath, + long date, + String message, + String contentType) + { + StringBuffer headerBuffer = new StringBuffer(); + + headerBuffer.append("<h2 identifier=\"" + MESSAGE_HEADER_ID + "\" "); + headerBuffer.append(DATE_ATTRIBUTE + "='" + date + "'" + ">"); + headerBuffer.append("<a style=\"color:#488fe7;"); + headerBuffer.append("font-weight:bold;"); + headerBuffer.append("text-decoration:none;\" "); + headerBuffer.append("href=\"" + contactName + "\">"); + headerBuffer.append( + contactDisplayName + createEditedAtTag(messageID, -1)); + headerBuffer.append("</a></h2>"); + + StringBuffer messageBuff = new StringBuffer(); + + messageBuff.append("<div " + + IncomingMessageStyle.createMessageStyle() + ">"); + messageBuff.append("<table width=\"100%\">"); + messageBuff.append("<tr>"); + messageBuff.append("<td valign=\"top\">"); + messageBuff.append( + "<table " + IncomingMessageStyle.createTableBubbleStyle() + + " cellspacing=\"0px\" cellpadding=\"0px\">"); + messageBuff.append("<tr>"); + messageBuff.append("<td style=\"width:26px;\"></td>"); + messageBuff.append("<td style=\"width:9px;\"></td>"); + messageBuff.append("<td " + + IncomingMessageStyle.createTableBubbleTlStyle() + ">"); + messageBuff.append( + createMessageTableTag(headerBuffer.toString(), date)); + messageBuff.append("</td>"); + messageBuff.append("<td " + + IncomingMessageStyle.createTableBubbleTrStyle() + "></td>"); + messageBuff.append("</tr>"); + + // Third row. + messageBuff.append("<tr>"); + messageBuff.append("<td><img src=\"" + avatarPath + + "\" width=\"26px\" height=\"26px\"/> </td>"); + messageBuff.append("<td " + + IncomingMessageStyle.createIndicatorStyle() +"></td>"); + messageBuff.append("<td " + + IncomingMessageStyle.createTableBubbleMessageStyle() + ">"); + + messageBuff.append( + createMessageTag( messageID, + contactName, + message, + contentType, + date, + false)); + + messageBuff.append("</td>"); + messageBuff.append("<td " + + IncomingMessageStyle.createTableBubbleMessageRightStyle() + + "></td>"); + messageBuff.append("</tr>"); + + //Forth row. + messageBuff.append("<tr>"); + messageBuff.append("<td style=\"width:26px;\"></td>"); + messageBuff.append("<td style=\"width:9px;\"></td>"); + messageBuff.append("<td " + + IncomingMessageStyle.createTableBubbleBlStyle() + "></td>"); + messageBuff.append("<td " + + IncomingMessageStyle.createTableBubbleBrStyle() + "></td>"); + messageBuff.append("</tr>"); + + messageBuff.append("</table>"); + messageBuff.append("</td>"); + messageBuff.append("</tr>"); + messageBuff.append("</table>"); + messageBuff.append("</div>"); + + return messageBuff.toString(); + } + + /** + * Create an outgoing message tag. + * + * @param messageID the identifier of the message + * @param contactName the name of the account sending the message + * @param contactDisplayName the display name of the account sending the + * message + * @param avatarPath the path to the avatar image + * @param date the date, when the message was sent + * @param message the content of the message + * @param contentType the content type HTML or PLAIN_TEXT + * @return the created outgoing message tag + */ + public static String createOutgoingMessageTag( String messageID, + String contactName, + String contactDisplayName, + String avatarPath, + long date, + String message, + String contentType) + { + StringBuffer headerBuffer = new StringBuffer(); + + headerBuffer.append("<h3 identifier=\"" + MESSAGE_HEADER_ID + "\""); + headerBuffer.append(DATE_ATTRIBUTE + "='" + date + "'" + ">"); + headerBuffer.append("<a style=\"color:#6a6868;"); + headerBuffer.append("font-weight:bold;"); + headerBuffer.append("float:left;"); + headerBuffer.append("text-decoration:none;\" "); + headerBuffer.append("href=\"" + contactName + "\">"); + headerBuffer.append(contactDisplayName + + createEditedAtTag(messageID, -1)); + headerBuffer.append("</a></h3>"); + + StringBuffer messageBuff = new StringBuffer(); + + messageBuff.append("<div " + + OutgoingMessageStyle.createMessageStyle() + ">"); + messageBuff.append("<table width=\"100%\">"); + messageBuff.append("<tr>"); + messageBuff.append("<td valign=\"top\">"); + messageBuff.append( + "<table " + OutgoingMessageStyle.createTableBubbleStyle() + + " cellspacing=\"0px\" cellpadding=\"0px\">"); + + // First row. + messageBuff.append("<tr>"); + messageBuff.append("<td " + + OutgoingMessageStyle.createTableBubbleTlStyle() + ">"); + messageBuff.append( + createMessageTableTag(headerBuffer.toString(), date)); + messageBuff.append("</td>"); + messageBuff.append("<td " + + OutgoingMessageStyle.createTableBubbleTrStyle() + "></td>"); + messageBuff.append("<td style=\"width:9px;\"></td>"); + messageBuff.append("<td style=\"width:26px;\"></td>"); + messageBuff.append("</tr>"); + + // Third row. + messageBuff.append("<tr>"); + messageBuff.append("<td " + + OutgoingMessageStyle.createTableBubbleMessageStyle() + ">"); + + messageBuff.append( + createMessageTag( messageID, + contactName, + message, + contentType, + date, + false)); + + messageBuff.append("</td>"); + messageBuff.append("<td " + + OutgoingMessageStyle.createTableBubbleMessageRightStyle() + + "></td>"); + messageBuff.append("<td " + + OutgoingMessageStyle.createIndicatorStyle() +"></td>"); + messageBuff.append("<td><div width=\"26px\" height=\"26px\"><img src=\"" + + avatarPath + + "\" width=\"26px\" height=\"26px\"/></div></td>"); + messageBuff.append("</tr>"); + + // Forth row. + messageBuff.append("<tr>"); + messageBuff.append("<td " + + OutgoingMessageStyle.createTableBubbleBlStyle() + "></td>"); + messageBuff.append("<td " + + OutgoingMessageStyle.createTableBubbleBrStyle() + "></td>"); + messageBuff.append("<td style=\"width:9px;\"></td>"); + messageBuff.append("<td style=\"width:26px;\"></td>"); + messageBuff.append("</tr>"); + messageBuff.append("</table>"); + messageBuff.append("</td>"); + messageBuff.append("</tr>"); + messageBuff.append("</table>"); + messageBuff.append("</div>"); + + return messageBuff.toString(); + } + + /** + * Creates a message table tag, representing the message header. + * + * @param nameHeader the name of the header. + * @param date the date, when the message was sent or received + * @return the message header tag + */ + public static String createMessageTableTag( String nameHeader, + long date) + { + StringBuffer messageHeader = new StringBuffer(); + + messageHeader.append("<table width=\"100%\">"); + messageHeader.append("<tr>"); + messageHeader.append("<td nowrap=\"nowrap\">"); + messageHeader.append(nameHeader); + messageHeader.append("</td>"); + messageHeader.append("<td nowrap=\"nowrap\" " + + OutgoingMessageStyle.createDateStyle() + ">"); + messageHeader.append(getDateString(date)); + messageHeader.append(GuiUtils.formatTime(date)); + messageHeader.append("</td>"); + messageHeader.append("</tr>"); + messageHeader.append("</table>"); + + return messageHeader.toString(); + } + + /** + * Creates the start tag, which indicates that the next text would be plain + * text. + * + * @param contentType the current content type + * @return the start plaintext tag + */ + public static String createStartPlainTextTag(String contentType) + { + if (HTML_CONTENT_TYPE.equals(contentType)) + { + return ""; + } + else + { + return START_PLAINTEXT_TAG; + } + } + + /** + * Creates the end tag, which indicates that the next text would be plain + * text. + * + * @param contentType the current content type + * @return the end plaintext tag + */ + public static String createEndPlainTextTag(String contentType) + { + if (HTML_CONTENT_TYPE.equals(contentType)) + { + return ""; + } + else + { + return END_PLAINTEXT_TAG; + } + } + + /** + * Creates a tag that shows the last edit time of a message, in the format + * (Edited at ...). + * If <tt>date < 0</tt>, returns an empty tag that serves as a placeholder + * for future corrections of this message. + * + * @param messageUID The ID of the edited message. + * @param date The date when the message was last edited, or -1 to generate + * an empty tag. + * @return The string representation of the tag. + */ + public static String createEditedAtTag(String messageUID, long date) + { + StringBuilder res = new StringBuilder(); + // Use a <cite /> tag here as most of the other inline tags (e.g. h1-7, + // b, i) cause different problems when used in setOuterHTML. + res.append("<cite id='"); + res.append(messageUID); + res.append("-editedAt'> "); + if (date > 0) + { + res.append("&nbsp;"); + String contents = GuiActivator.getResources().getI18NString( + "service.gui.EDITED_AT", + new String[] { GuiUtils.formatTime(date) } + ); + res.append(contents); + } + res.append("</cite>"); + return res.toString(); + } + + /** + * Creates the message tag. + * + * @param messageID the identifier of the message + * @param contactName the name of the sender + * @param message the message content + * @param contentType the content type (html or plain text) + * @param date the date on which the message was sent + * @param isEdited indicates if the given message has been edited + * @return the newly constructed message tag + */ + public static String createMessageTag( String messageID, + String contactName, + String message, + String contentType, + long date, + boolean isEdited) + { + StringBuffer messageTag = new StringBuffer(); + + messageTag.append("<div id=\""); + messageTag.append(messageID); + messageTag.append("\" "); + messageTag.append(NAME_ATTRIBUTE + "=\"" + contactName); + messageTag.append("\" style=\"padding-left:10px;"); + if (isEdited) + messageTag.append("font-style:italic;\">"); + else + messageTag.append("\">"); + messageTag.append(createStartPlainTextTag(contentType)); + messageTag.append(message); + if (isEdited) + messageTag.append(" (edited at " + + GuiUtils.formatTime(date) + ")"); + messageTag.append(createEndPlainTextTag(contentType)); + messageTag.append("</div>"); + + return messageTag.toString(); + } + + /** + * Returns the date string to show for the given date. + * + * @param date the date to format + * @return the date string to show for the given date + */ + public static String getDateString(long date) + { + if (GuiUtils.compareDatesOnly(date, System.currentTimeMillis()) <= 0) + { + StringBuffer dateStrBuf = new StringBuffer(); + + GuiUtils.formatDate(date, dateStrBuf); + dateStrBuf.append(" "); + return dateStrBuf.toString(); + } + + return ""; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java index 9cf6f6275..d39b7a0f1 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java @@ -130,8 +130,6 @@ public class ChatPanel private boolean isHistoryLoaded; - private int autoDividerLocation = 0; - /** * Stores all active file transfer requests and effective transfers with * the identifier of the transfer. @@ -482,7 +480,7 @@ public void memberRoleChanged(ChatRoomMemberRoleChangeEvent evt) new String[]{evt.getSourceMember().getName(), getRoleDescription(evt.getNewRole())}) +"</DIV>", - ChatConversationPanel.HTML_CONTENT_TYPE); + ChatHtmlUtils.HTML_CONTENT_TYPE); } /** @@ -497,7 +495,7 @@ public void localUserRoleChanged(ChatRoomLocalUserRoleChangeEvent evt) +GuiActivator.getResources().getI18NString("service.gui.ARE_NOW", new String[]{ getRoleDescription(evt.getNewRole())}) +"</DIV>", - ChatConversationPanel.HTML_CONTENT_TYPE); + ChatHtmlUtils.HTML_CONTENT_TYPE); } /** @@ -687,7 +685,7 @@ else if (o instanceof FileRecord) if (historyString != null) conversationPanel.appendMessageToEnd( - historyString, ChatConversationPanel.TEXT_CONTENT_TYPE); + historyString, ChatHtmlUtils.TEXT_CONTENT_TYPE); } fireChatHistoryChange(); @@ -839,6 +837,11 @@ public void addErrorMessage(String contactName, message, "text"); } + /** + * Displays the given chat message. + * + * @param chatMessage the chat message to display + */ private void displayChatMessage(ChatMessage chatMessage) { if (chatMessage.getCorrectedMessageUID() != null @@ -863,7 +866,9 @@ private void displayChatMessage(ChatMessage chatMessage) private void appendChatMessage(ChatMessage chatMessage) { String processedMessage - = this.conversationPanel.processMessage(chatMessage); + = this.conversationPanel.processMessage(chatMessage, + chatSession.getCurrentChatTransport().getProtocolProvider(), + chatSession.getCurrentChatTransport().getName()); if (chatSession instanceof ConferenceChatSession) { @@ -963,7 +968,10 @@ private String processHistoryMessage(String contactName, messageType, null, message, contentType, messageId, null); String processedMessage = - this.conversationPanel.processMessage(chatMessage); + this.conversationPanel.processMessage(chatMessage, + chatSession.getCurrentChatTransport().getProtocolProvider(), + chatSession.getCurrentChatTransport().getName()); + if (chatSession instanceof ConferenceChatSession) { String tempMessage = @@ -1004,7 +1012,7 @@ public void addTextInWriteArea(String text){ public String getTextFromWriteArea(String mimeType) { if (mimeType.equals( - OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE)) + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE)) { return writeMessagePanel.getText(); } @@ -2062,7 +2070,7 @@ public void updateChatContactStatus(ChatContact<?> chatContact, System.currentTimeMillis(), Chat.STATUS_MESSAGE, statusMessage, - ChatConversationPanel.TEXT_CONTENT_TYPE); + ChatHtmlUtils.TEXT_CONTENT_TYPE); } /** @@ -2094,7 +2102,7 @@ else if (subject.equals(oldSubject)) "service.gui.CHAT_ROOM_SUBJECT_CHANGED", new String []{ chatSession.getChatName(), subject}), - ChatConversationPanel.TEXT_CONTENT_TYPE); + ChatHtmlUtils.TEXT_CONTENT_TYPE); } } @@ -2461,8 +2469,6 @@ public void setDividerLocation(int location) { int dividerLocation = messagePane.getHeight() - location; - autoDividerLocation = dividerLocation; - messagePane.setDividerLocation(dividerLocation); messagePane.revalidate(); messagePane.repaint(); @@ -2760,8 +2766,7 @@ public void chatRoomPropertyChanged(ChatRoomMemberPropertyChangeEvent event) + event.getOldValue() + " is now known as " + event.getNewValue() + "</DIV>", - ChatConversationPanel.HTML_CONTENT_TYPE); - + ChatHtmlUtils.HTML_CONTENT_TYPE); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java index 12aeeddd0..fc6561b8b 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java @@ -35,7 +35,7 @@ public interface ChatTransport * messaging, otherwise returns <code>false</code> */ public boolean allowsInstantMessage(); - + /** * Returns <tt>true</tt> if this chat transport supports message * corrections and false otherwise. diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java index 7cdb61f5d..160515b69 100755 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java @@ -18,7 +18,6 @@ import javax.swing.undo.*; import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.customcontrols.*; import net.java.sip.communicator.impl.gui.main.chat.conference.*; import net.java.sip.communicator.impl.gui.main.chat.menus.*; import net.java.sip.communicator.impl.gui.utils.*; @@ -654,7 +653,7 @@ else if(e.getKeyCode() == KeyEvent.VK_TAB) chatPanel.getChatConversationPanel() .appendMessageToEnd(contactList, - ChatConversationPanel.HTML_CONTENT_TYPE); + ChatHtmlUtils.HTML_CONTENT_TYPE); } else if(contacts.size() == 1) { @@ -963,7 +962,7 @@ public void setTransportSelectorBoxVisible(boolean isVisible) GuiActivator.getResources(). getI18NString("service.gui.MSG_NOT_POSSIBLE") + "</h5>", - ChatConversationPanel.HTML_CONTENT_TYPE); + ChatHtmlUtils.HTML_CONTENT_TYPE); } else { diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/IncomingMessageStyle.java b/src/net/java/sip/communicator/impl/gui/main/chat/IncomingMessageStyle.java new file mode 100644 index 000000000..e6e5b4e08 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/chat/IncomingMessageStyle.java @@ -0,0 +1,203 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat; + +import net.java.sip.communicator.impl.gui.*; + +/** + * Defines the CSS style of an incoming chat message elements. + * + * @author Yana Stamcheva + */ +public class IncomingMessageStyle +{ + /** + * The incoming message background image path. + */ + private final static String INCOMING_MESSAGE_IMAGE_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.INCOMING_MESSAGE_BACKGROUND").toString(); + + /** + * The incoming message right image path. + */ + private final static String INCOMING_MESSAGE_IMAGE_RIGHT_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.INCOMING_MESSAGE_BACKGROUND_RIGHT") + .toString(); + + /** + * The incoming message indicator image path. + */ + private final static String INCOMING_MESSAGE_INDICATOR_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.INCOMING_MESSAGE_INDICATOR").toString(); + + /** + * The incoming message round border image path. + */ + private final static String INCOMING_MESSAGE_CURVES_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.INCOMING_MESSAGE_CURVES").toString(); + + /** + * The incoming message top image path. + */ + private final static String INCOMING_MESSAGE_CURVES_TOP_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.INCOMING_MESSAGE_CURVES_TOP").toString(); + + /** + * Creates the global message style. + * + * @return the style attribute defining the global message style. + */ + public static String createMessageStyle() + { + return "style=\"" + + "width:100%;" + + "opacity:0.96;" + + "\""; + } + + /** + * Creates the style of the table bubble right element. + * + * @return the style of the table bubble right element + */ + public static String createTableBubbleMessageRightStyle() + { + return "style=\"" + + "width:8px;" + + " background-image: url('" + +INCOMING_MESSAGE_IMAGE_RIGHT_PATH+"');" + + " background-repeat: repeat-y;" + + " background-position: top left;" + + "\""; + } + + /** + * Creates the style of the table bubble (wrapping the message table). + * + * @return the style of the table bubble + */ + public static String createTableBubbleStyle() + { + return "style=\"" + + "width:100%;" + + " position:relative;" + + "\""; + } + + /** + * Creates the style of the message table bubble. + * + * @return the style of the message table bubble + */ + public static String createTableBubbleMessageStyle() + { + return "style=\"" + + "font-size:10px;" + + " background-image: url('"+INCOMING_MESSAGE_IMAGE_PATH+"');" + + " background-repeat: repeat-y;" + + " background-position: top left;" + + "\""; + } + + /** + * Creates the style of the table buuble bottom left corner. + * + * @return the style of the table buuble bottom left corner + */ + public static String createTableBubbleBlStyle() + { + return "style=\"" + + "height:10px;" + + " background-image: url('"+INCOMING_MESSAGE_CURVES_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: 0px -20px;" + + "\""; + } + + /** + * Creates the style of the table buuble bottom right corner. + * + * @return the style of the table buuble bottom right corner + */ + public static String createTableBubbleBrStyle() + { + return "style=\"" + + "width:8px;" + + " height:10px;" + + " background-image: url('"+INCOMING_MESSAGE_CURVES_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: -2999px -20px;" + + "\""; + } + + /** + * Creates the style of the table buuble top left corner. + * + * @return the style of the table buuble top left corner + */ + public static String createTableBubbleTlStyle() + { + return "style=\"" + + "height:23px;" + + " background-image: url('" + +INCOMING_MESSAGE_CURVES_TOP_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: top left;" + + "\""; + } + + /** + * Creates the style of the table buuble top right corner. + * + * @return the style of the table buuble top right corner + */ + public static String createTableBubbleTrStyle() + { + return "style=\"" + + "width:6px;" + + " height:23px;" + + " background-image: url('" + +INCOMING_MESSAGE_CURVES_TOP_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: -2999px 0px;" + + "\""; + } + + /** + * Creates the style of the indicator pointing to the avatar image. + * + * @return the style of the indicator pointing to the avatar image + */ + public static String createIndicatorStyle() + { + return "style =\"" + + "width:9px;" + + " height:19px;" + + " background-image: url('" + + INCOMING_MESSAGE_INDICATOR_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: top right;" + + "\""; + } + + /** + * Creates the style of the avatar image. + * + * @return the style of the avatar image + */ + public static String createAvatarStyle() + { + return "style=\"width:26px;" + + " height:26px;" + + " float:left;\""; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/OutgoingMessageStyle.java b/src/net/java/sip/communicator/impl/gui/main/chat/OutgoingMessageStyle.java new file mode 100644 index 000000000..b64f28730 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/chat/OutgoingMessageStyle.java @@ -0,0 +1,206 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.chat; + +import net.java.sip.communicator.impl.gui.*; + +/** + * Defines the CSS style of an outgoing chat message elements. + * + * @author Yana Stamcheva + */ +public class OutgoingMessageStyle + extends IncomingMessageStyle +{ + /** + * The outgoing message background image path. + */ + private final static String OUTGOING_MESSAGE_IMAGE_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.OUTGOING_MESSAGE_BACKGROUND").toString(); + + /** + * The outgoing message right image path. + */ + private final static String OUTGOING_MESSAGE_IMAGE_RIGHT_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.OUTGOING_MESSAGE_BACKGROUND_RIGHT") + .toString(); + + /** + * The outgoing message indicator image path. + */ + private final static String OUTGOING_MESSAGE_INDICATOR_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.OUTGOING_MESSAGE_INDICATOR").toString(); + + /** + * The outgoing message round border image path. + */ + private final static String OUTGOING_MESSAGE_CURVES_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.OUTGOING_MESSAGE_CURVES").toString(); + + /** + * The outgoing message top image path. + */ + private final static String OUTGOING_MESSAGE_CURVES_TOP_PATH + = GuiActivator.getResources().getImageURL( + "service.gui.lookandfeel.OUTGOING_MESSAGE_CURVES_TOP").toString(); + + /** + * Creates the style of the table bubble (wrapping the message table). + * + * @return the style of the table bubble + */ + public static String createTableBubbleStyle() + { + return "style=\"" + + "width:100%;" + + " position:relative;" + + "\""; + } + + /** + * Creates the style of the table bubble right element. + * + * @return the style of the table bubble right element + */ + public static String createTableBubbleMessageRightStyle() + { + return "style=\"" + + "width:6px;" + + " background-image: url('" + + OUTGOING_MESSAGE_IMAGE_RIGHT_PATH+"');" + + " background-repeat: repeat-y;" + + " background-position: top left;" + + "\""; + } + + /** + * Creates the style of the message table bubble. + * + * @return the style of the message table bubble + */ + public static String createTableBubbleMessageStyle() + { + return "style=\"" + + "font-size:10px;" + + " background-image: url('"+OUTGOING_MESSAGE_IMAGE_PATH+"');" + + " background-repeat: repeat-y;" + + " background-position: top left;" + + "\""; + } + + /** + * Creates the style of the table buuble bottom left corner. + * + * @return the style of the table buuble bottom left corner + */ + public static String createTableBubbleBlStyle() + { + return "style=\"" + + "height:10px;" + + " background-image: url('"+OUTGOING_MESSAGE_CURVES_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: 0px -20px;" + + "\""; + } + + /** + * Creates the style of the table buuble bottom right corner. + * + * @return the style of the table buuble bottom right corner + */ + public static String createTableBubbleBrStyle() + { + return "style=\"" + + "width:6px;" + + " height:10px;" + + " background-image: url('"+OUTGOING_MESSAGE_CURVES_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: -2999px -20px;" + + "\""; + } + + /** + * Creates the style of the table buuble top left corner. + * + * @return the style of the table buuble top left corner + */ + public static String createTableBubbleTlStyle() + { + return "style=\"" + + "height:23px;" + + " background-image: url('" + +OUTGOING_MESSAGE_CURVES_TOP_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: top left;" + + "\""; + } + + /** + * Creates the style of the table buuble top right corner. + * + * @return the style of the table buuble top right corner + */ + public static String createTableBubbleTrStyle() + { + return "style=\"" + + "width:6px;" + + " height:23px;" + + " background-image: url('" + +OUTGOING_MESSAGE_CURVES_TOP_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: -2999px 0px;" + + "\""; + } + + /** + * Creates the style of the indicator pointing to the avatar image. + * + * @return the style of the indicator pointing to the avatar image + */ + public static String createIndicatorStyle() + { + return "style =\"" + + "width:9px;" + + " height:19px;" + + " background-image: url('" + +OUTGOING_MESSAGE_INDICATOR_PATH+"');" + + " background-repeat: no-repeat;" + + " background-position: top left;" + + "\""; + } + + /** + * Creates the style of the avatar image. + * + * @return the style of the avatar image + */ + public static String createAvatarStyle() + { + return "style=\"width:26px;" + + " height:26px;" + + " float:right;\""; + } + + /** + * Creates the style of the date. + * + * @return the style of the date + */ + public static String createDateStyle() + { + return "style =\"" + + "color:#6a6868;" + + " font-size:10px;" + + " padding-top:4px;" + + " text-align:right;" + + "\""; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java b/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java index 2c2b216b0..78dd4f7dd 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java @@ -263,13 +263,14 @@ private HTMLDocument createHistory(Collection<Object> historyRecords) Object o = i.next(); ChatMessage chatMessage = null; + ProtocolProviderService protocolProvider = null; if(o instanceof MessageDeliveredEvent) { MessageDeliveredEvent evt = (MessageDeliveredEvent) o; - ProtocolProviderService protocolProvider = evt - .getDestinationContact().getProtocolProvider(); + protocolProvider + = evt.getDestinationContact().getProtocolProvider(); chatMessage = new ChatMessage( GuiActivator.getUIService().getMainFrame() @@ -288,6 +289,9 @@ else if(o instanceof MessageReceivedEvent) { MessageReceivedEvent evt = (MessageReceivedEvent) o; + protocolProvider + = evt.getSourceContact().getProtocolProvider(); + chatMessage = new ChatMessage( evt.getSourceContact().getAddress(), evt.getSourceContact().getDisplayName(), @@ -304,6 +308,9 @@ else if(o instanceof ChatRoomMessageReceivedEvent) ChatRoomMessageReceivedEvent evt = (ChatRoomMessageReceivedEvent) o; + protocolProvider + = evt.getSourceChatRoom().getParentProvider(); + chatMessage = new ChatMessage( evt.getSourceChatRoomMember().getName(), evt.getTimestamp(), Chat.INCOMING_MESSAGE, @@ -315,6 +322,9 @@ else if(o instanceof ChatRoomMessageDeliveredEvent) ChatRoomMessageDeliveredEvent evt = (ChatRoomMessageDeliveredEvent) o; + protocolProvider + = evt.getSourceChatRoom().getParentProvider(); + chatMessage = new ChatMessage( evt.getSourceChatRoom().getParentProvider() .getAccountID().getUserID(), @@ -326,6 +336,9 @@ else if (o instanceof FileRecord) { FileRecord fileRecord = (FileRecord) o; + protocolProvider + = fileRecord.getContact().getProtocolProvider(); + FileHistoryConversationComponent component = new FileHistoryConversationComponent( this, fileRecord); @@ -336,10 +349,13 @@ else if (o instanceof FileRecord) if (chatMessage != null) { processedMessage = chatConvPanel.processMessage( - chatMessage, searchKeyword); + chatMessage, + searchKeyword, + protocolProvider, + chatMessage.getContactName()); chatConvPanel.appendMessageToEnd(processedMessage, - ChatConversationPanel.TEXT_CONTENT_TYPE); + ChatHtmlUtils.TEXT_CONTENT_TYPE); } } } @@ -875,7 +891,9 @@ private void processMessage(Contact contact, messageContentType); String processedMessage = chatConvPanel.processMessage( - chatMessage, searchKeyword); + chatMessage, searchKeyword, + contact.getProtocolProvider(), + contact.getAddress()); this.appendMessageToDocument(document, processedMessage); } diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/menus/ChatRightButtonMenu.java b/src/net/java/sip/communicator/impl/gui/main/chat/menus/ChatRightButtonMenu.java index c619a3433..93939091a 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/menus/ChatRightButtonMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/menus/ChatRightButtonMenu.java @@ -36,14 +36,6 @@ public class ChatRightButtonMenu GuiActivator.getResources().getI18NString("service.gui.COPY"), new ImageIcon(ImageLoader.getImage(ImageLoader.COPY_ICON))); - private JMenuItem saveMenuItem = new JMenuItem( - GuiActivator.getResources().getI18NString("service.gui.SAVE"), - new ImageIcon(ImageLoader.getImage(ImageLoader.SAVE_ICON))); - - private JMenuItem printMenuItem = new JMenuItem( - GuiActivator.getResources().getI18NString("service.gui.PRINT"), - new ImageIcon(ImageLoader.getImage(ImageLoader.PRINT_ICON))); - private JMenuItem closeMenuItem = new JMenuItem( GuiActivator.getResources().getI18NString("service.gui.CLOSE"), new ImageIcon(ImageLoader.getImage(ImageLoader.CLOSE_ICON))); @@ -71,47 +63,23 @@ private void init() this.addSeparator(); - this.add(saveMenuItem); - this.add(printMenuItem); - - this.addSeparator(); - this.add(closeMenuItem); this.copyMenuItem.setName("copy"); - this.saveMenuItem.setName("save"); - this.printMenuItem.setName("print"); this.closeMenuItem.setName("service.gui.CLOSE"); this.copyMenuItem.addActionListener(this); - this.saveMenuItem.addActionListener(this); - this.printMenuItem.addActionListener(this); this.closeMenuItem.addActionListener(this); this.copyMenuItem.setMnemonic( GuiActivator.getResources().getI18nMnemonic("service.gui.COPY")); - this.saveMenuItem.setMnemonic( - GuiActivator.getResources().getI18nMnemonic("service.gui.SAVE")); - this.printMenuItem.setMnemonic( - GuiActivator.getResources().getI18nMnemonic("service.gui.PRINT")); + this.closeMenuItem.setMnemonic( GuiActivator.getResources().getI18nMnemonic("service.gui.CLOSE")); this.copyMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_MASK)); - - this.saveMenuItem.setAccelerator( - KeyStroke.getKeyStroke(KeyEvent.VK_S, - KeyEvent.CTRL_MASK)); - - this.printMenuItem.setAccelerator( - KeyStroke.getKeyStroke(KeyEvent.VK_R, - KeyEvent.CTRL_MASK)); - - // Disable all menu items that do nothing. - this.saveMenuItem.setEnabled(false); - this.printMenuItem.setEnabled(false); } /** @@ -168,12 +136,6 @@ public void loadSkin() copyMenuItem.setIcon(new ImageIcon( ImageLoader.getImage(ImageLoader.COPY_ICON))); - saveMenuItem.setIcon(new ImageIcon( - ImageLoader.getImage(ImageLoader.SAVE_ICON))); - - printMenuItem.setIcon(new ImageIcon( - ImageLoader.getImage(ImageLoader.PRINT_ICON))); - closeMenuItem.setIcon(new ImageIcon( ImageLoader.getImage(ImageLoader.CLOSE_ICON))); } diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/menus/FileMenu.java b/src/net/java/sip/communicator/impl/gui/main/chat/menus/FileMenu.java index df0a7f5b4..f188fc012 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/menus/FileMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/menus/FileMenu.java @@ -20,7 +20,7 @@ /** * The <tt>FileMenu</tt> is the menu in the chat window menu bar that contains - * save, print and close. + * my chat rooms, history and close. * * @author Yana Stamcheva * @author Adam Netocny diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java b/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java index 14faa61af..1c63daf85 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java @@ -21,7 +21,6 @@ import net.java.sip.communicator.impl.gui.main.chat.conference.*; import net.java.sip.communicator.impl.gui.main.chat.history.*; import net.java.sip.communicator.impl.gui.main.configforms.*; -import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.gui.*; @@ -29,10 +28,8 @@ import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.ServerStoredDetails.FaxDetail; import net.java.sip.communicator.service.protocol.ServerStoredDetails.GenericDetail; -import net.java.sip.communicator.service.protocol.ServerStoredDetails.MobilePhoneDetail; import net.java.sip.communicator.service.protocol.ServerStoredDetails.PagerDetail; import net.java.sip.communicator.service.protocol.ServerStoredDetails.PhoneNumberDetail; -import net.java.sip.communicator.service.protocol.ServerStoredDetails.WorkPhoneDetail; import net.java.sip.communicator.util.skin.*; import net.java.sip.communicator.util.swing.*; @@ -108,6 +105,13 @@ public class MainToolBar = new ChatToolbarButton( ImageLoader.getImage(ImageLoader.CHAT_CALL)); + /** + * The call button. + */ + private final ChatToolbarButton callVideoButton + = new ChatToolbarButton( + ImageLoader.getImage(ImageLoader.CHAT_VIDEO_CALL)); + /** * The options button. */ @@ -181,6 +185,7 @@ protected void init() this.add(leaveChatRoomButton); this.add(callButton); +// this.add(callVideoButton); this.add(desktopSharingButton); this.add(sendFileButton); @@ -235,6 +240,11 @@ protected void init() GuiActivator.getResources().getI18NString( "service.gui.CALL_CONTACT")); + this.callVideoButton.setName("callVideo"); + this.callVideoButton.setToolTipText( + GuiActivator.getResources().getI18NString( + "service.gui.CALL_CONTACT")); + this.desktopSharingButton.setName("desktop"); this.desktopSharingButton.setToolTipText( GuiActivator.getResources().getI18NString( @@ -264,6 +274,7 @@ protected void init() inviteButton.addActionListener(this); leaveChatRoomButton.addActionListener(this); callButton.addActionListener(this); + callVideoButton.addActionListener(this); desktopSharingButton.addActionListener(this); historyButton.addActionListener(this); optionsButton.addActionListener(this); @@ -377,7 +388,7 @@ public void chatChanged(ChatPanel chatPanel) } } } - + callButton.setEnabled(hasTelephony || hasPhone); desktopSharingButton.setEnabled(!getOperationSetForCapabilities( chatPanel.chatSession.getTransportsForOperationSet( @@ -550,84 +561,13 @@ else if (buttonText.equals("call")) List<ChatTransport> contactOpSetSupported = getOperationSetForCapabilities(telTransports, OperationSetBasicTelephony.class); - + MetaContact metaContact = GuiActivator.getUIService().getChatContact(chatPanel); - Iterator<Contact> contacts = metaContact.getContacts(); - List<UIContactDetail> phones = new ArrayList<UIContactDetail>(); - - while(contacts.hasNext()) - { - Contact contact = contacts.next(); - - OperationSetServerStoredContactInfo infoOpSet = - contact.getProtocolProvider().getOperationSet( - OperationSetServerStoredContactInfo.class); - Iterator<GenericDetail> details = null; - - if(infoOpSet != null) - { - details = infoOpSet.getAllDetailsForContact(contact); + + List<UIContactDetail> phones + = CallManager.getAdditionalNumbers(metaContact); - while(details.hasNext()) - { - GenericDetail d = details.next(); - if(d instanceof PhoneNumberDetail && - !(d instanceof PagerDetail) && - !(d instanceof FaxDetail)) - { - PhoneNumberDetail pnd = (PhoneNumberDetail)d; - if(pnd.getNumber() != null && - pnd.getNumber().length() > 0) - { - String localizedType = null; - - if(d instanceof WorkPhoneDetail) - { - localizedType = - GuiActivator.getResources(). - getI18NString( - "service.gui.WORK_PHONE"); - } - else if(d instanceof MobilePhoneDetail) - { - localizedType = - GuiActivator.getResources(). - getI18NString( - "service.gui.MOBILE_PHONE"); - } - else - { - localizedType = - GuiActivator.getResources(). - getI18NString( - "service.gui.PHONE"); - } - - UIContactDetail cd = - new UIContactDetailImpl( - pnd.getNumber(), - pnd.getNumber() + - " (" + localizedType + ")", - null, - new ArrayList<String>(), - null, - null, - null, - pnd) - { - public PresenceStatus getPresenceStatus() - { - return null; - } - }; - phones.add(cd); - } - } - } - } - } - if (telTransports != null || phones.size() > 0) { if (contactOpSetSupported.size() == 1 && phones.size() == 0) @@ -638,7 +578,7 @@ public PresenceStatus getPresenceStatus() transport.getName()); } else if (contactOpSetSupported.size() == 0 - && phones.size() == 1) + && phones.size() == 1) { UIContactDetail detail = phones.get(0); diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListCellRenderer.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListCellRenderer.java index 09ad46f8d..d856041da 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListCellRenderer.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListCellRenderer.java @@ -61,13 +61,13 @@ public class ContactListCellRenderer * The icon indicating an open group. */ private ImageIcon openedGroupIcon = - new ImageIcon(ImageLoader.getImage(ImageLoader.DOWN_ARROW_ICON)); + new ImageIcon(ImageLoader.getImage(ImageLoader.OPENED_GROUP_ICON)); /** * The icon indicating a closed group. */ private ImageIcon closedGroupIcon = - new ImageIcon(ImageLoader.getImage(ImageLoader.RIGHT_ARROW_ICON)); + new ImageIcon(ImageLoader.getImage(ImageLoader.CLOSED_GROUP_ICON)); /** * The foreground color for groups. @@ -494,7 +494,7 @@ public void loadSkin() = new ImageIcon(ImageLoader.getImage(ImageLoader.DOWN_ARROW_ICON)); closedGroupIcon - = new ImageIcon(ImageLoader.getImage(ImageLoader.RIGHT_ARROW_ICON)); + = new ImageIcon(ImageLoader.getImage(ImageLoader.CLOSED_GROUP_ICON)); int groupForegroundProperty = GuiActivator.getResources() .getColor("service.gui.CONTACT_LIST_GROUP_FOREGROUND"); 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 b6a5f75e1..ad6b3dae4 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 @@ -16,6 +16,8 @@ import javax.swing.JPopupMenu.Separator; import javax.swing.tree.*; +import org.jitsi.util.*; + import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.call.*; import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; @@ -73,6 +75,16 @@ public class ContactListTreeCellRenderer */ private static final int EXTENDED_AVATAR_WIDTH = 45; + /** + * The default width of the button. + */ + private static final int BUTTON_WIDTH = 26; + + /** + * The default height of the button. + */ + private static final int BUTTON_HEIGHT = 27; + /** * Left border value. */ @@ -84,14 +96,30 @@ public class ContactListTreeCellRenderer private static final int TOP_BORDER = 2; /** - * Status label right border. + * Bottom border value. + */ + private static final int BOTTOM_BORDER = 2; + + /** + * Right border value. */ - private static final int STATUS_RIGHT_BORDER = 2; + private static final int RIGHT_BORDER = 2; /** - * Status label top border. + * The horizontal gap between columns in pixels; */ - private static final int STATUS_TOP_BORDER = 2; + private static final int H_GAP = 2; + + /** + * The vertical gap between rows in pixels; + */ + private static final int V_GAP = 3; + + /** + * The separator image for the button toolbar. + */ + private static final Image BUTTON_SEPARATOR_IMG + = ImageLoader.getImage(ImageLoader.CONTACT_LIST_BUTTON_SEPARATOR); /** * The icon used for opened groups. @@ -131,18 +159,12 @@ public class ContactListTreeCellRenderer /** * The call video button. */ - private final SIPCommButton callVideoButton = new SIPCommButton( - ImageLoader.getImage(ImageLoader.CALL_VIDEO_BUTTON_SMALL), - ImageLoader.getImage(ImageLoader.CALL_VIDEO_BUTTON_SMALL_PRESSED), - null); + private final SIPCommButton callVideoButton = new SIPCommButton(); /** * The desktop sharing button. */ - private final SIPCommButton desktopSharingButton = new SIPCommButton( - ImageLoader.getImage(ImageLoader.DESKTOP_BUTTON_SMALL), - ImageLoader.getImage(ImageLoader.DESKTOP_BUTTON_SMALL_PRESSED), - null); + private final SIPCommButton desktopSharingButton = new SIPCommButton(); /** * The chat button. @@ -152,10 +174,7 @@ public class ContactListTreeCellRenderer /** * The add contact button. */ - private final SIPCommButton addContactButton = new SIPCommButton( - ImageLoader.getImage(ImageLoader.ADD_CONTACT_BUTTON_SMALL), - ImageLoader.getImage(ImageLoader.ADD_CONTACT_BUTTON_SMALL_PRESSED), - null); + private final SIPCommButton addContactButton = new SIPCommButton(); /** * The constraints used to align components in the <tt>centerPanel</tt>. @@ -208,6 +227,11 @@ public class ContactListTreeCellRenderer */ private List<JButton> customActionButtons; + /** + * The last added button. + */ + private SIPCommButton lastAddedButton; + /** * Initializes the panel containing the node. */ @@ -222,11 +246,11 @@ public ContactListTreeCellRenderer() * correctly calculated problems may occur when clicking buttons! */ this.setBorder(BorderFactory - .createEmptyBorder(TOP_BORDER, LEFT_BORDER, 2, 2)); + .createEmptyBorder( TOP_BORDER, + LEFT_BORDER, + BOTTOM_BORDER, + RIGHT_BORDER)); - statusLabel.setBorder( - BorderFactory.createEmptyBorder(STATUS_TOP_BORDER, - 0, 0, STATUS_RIGHT_BORDER)); loadSkin(); this.setOpaque(true); @@ -237,6 +261,10 @@ public ContactListTreeCellRenderer() this.rightLabel.setHorizontalAlignment(JLabel.RIGHT); + // !! IMPORTANT: General insets used for all components if not + // overwritten! + constraints.insets = new Insets(0, 0, V_GAP, H_GAP); + constraints.anchor = GridBagConstraints.WEST; constraints.fill = GridBagConstraints.NONE; constraints.gridx = 0; @@ -595,11 +623,11 @@ public Dimension getPreferredSize() if (preferredHeight > 0) preferredSize.height = preferredHeight; else if (contact instanceof ShowMoreContact) - preferredSize.height = 18; + preferredSize.height = 20; else if (isSelected && treeContactList.isContactButtonsVisible()) preferredSize.height = 70; else - preferredSize.height = 30; + preferredSize.height = 35; } else if (treeNode instanceof GroupNode) { @@ -611,7 +639,7 @@ else if (treeNode instanceof GroupNode) if (preferredHeight > 0) preferredSize.height = preferredHeight; else - preferredSize.height = 18; + preferredSize.height = 20; } return preferredSize; @@ -639,8 +667,6 @@ private void addLabels(int nameLabelGridWidth) constraints.gridwidth = nameLabelGridWidth; this.add(nameLabel, constraints); - rightLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 2)); - constraints.anchor = GridBagConstraints.NORTHEAST; constraints.fill = GridBagConstraints.VERTICAL; constraints.gridx = nameLabelGridWidth + 1; @@ -719,15 +745,6 @@ private void initButtonsPanel(UIContact uiContact) if (!isSelected) return; - int statusMessageLabelHeight = 0; - if (displayDetailsLabel.getText().length() > 0) - statusMessageLabelHeight = 20; - else - statusMessageLabelHeight = 15; - - int y = TOP_BORDER + STATUS_TOP_BORDER - + nameLabel.getHeight() + statusMessageLabelHeight; - UIContactDetail imContact = null; // For now we support instance messaging only for contacts in our // contact list until it's implemented for external source contacts. @@ -736,9 +753,8 @@ private void initButtonsPanel(UIContact uiContact) OperationSetBasicInstantMessaging.class); int x = (statusIcon == null ? 0 : statusIcon.getIconWidth()) - + (statusLabel == null ? 0 : statusLabel.getIconTextGap()) + LEFT_BORDER - + STATUS_RIGHT_BORDER; + + H_GAP; // Re-initialize the x grid. constraints.gridx = 0; @@ -746,20 +762,7 @@ private void initButtonsPanel(UIContact uiContact) if (imContact != null) { - constraints.anchor = GridBagConstraints.WEST; - constraints.fill = GridBagConstraints.NONE; - constraints.gridx = ++gridX; - constraints.gridy = 2; - constraints.gridwidth = 1; - constraints.gridheight = 1; - constraints.weightx = 0f; - constraints.weighty = 0f; - this.chatButton.setBorder(null); - this.add(chatButton, constraints); - - chatButton.setBounds(x, y, 28, 28); - - x += chatButton.getWidth(); + x += addButton(chatButton, ++gridX, x, false); } UIContactDetail telephonyContact @@ -833,22 +836,7 @@ private void initButtonsPanel(UIContact uiContact) || uiContact.getDescriptor() instanceof SourceContact || (hasPhone && providers.size() > 0)) { - constraints.anchor = GridBagConstraints.WEST; - constraints.fill = GridBagConstraints.NONE; - constraints.gridx = ++gridX; - constraints.gridy = 2; - constraints.gridwidth = 1; - constraints.gridheight = 1; - constraints.weightx = 0f; - constraints.weighty = 0f; - this.callButton.setBorder(null); - this.add(callButton, constraints); - - callButton.setBounds(x, y, 28, 28); - - callButton.setEnabled(telephonyContact != null || hasPhone); - - x += callButton.getWidth(); + x += addButton(callButton, ++gridX, x, false); } UIContactDetail videoContact @@ -864,20 +852,7 @@ private void initButtonsPanel(UIContact uiContact) null, null).size() > 0)) { - constraints.anchor = GridBagConstraints.WEST; - constraints.fill = GridBagConstraints.NONE; - constraints.gridx = ++gridX; - constraints.gridy = 2; - constraints.gridwidth = 1; - constraints.gridheight = 1; - constraints.weightx = 0f; - constraints.weighty = 0f; - this.callVideoButton.setBorder(null); - this.add(callVideoButton, constraints); - - callVideoButton.setBounds(x, y, 28, 28); - - x += callVideoButton.getWidth(); + x += addButton(callVideoButton, ++gridX, x, false); } UIContactDetail desktopContact @@ -893,39 +868,13 @@ private void initButtonsPanel(UIContact uiContact) null, null).size() > 0)) { - constraints.anchor = GridBagConstraints.WEST; - constraints.fill = GridBagConstraints.NONE; - constraints.gridx = ++gridX; - constraints.gridy = 2; - constraints.gridwidth = 1; - constraints.gridheight = 1; - constraints.weightx = 0f; - constraints.weighty = 0f; - this.desktopSharingButton.setBorder(null); - this.add(desktopSharingButton, constraints); - - desktopSharingButton.setBounds(x, y, 28, 28); - - x += desktopSharingButton.getWidth(); + x += addButton(desktopSharingButton, ++gridX, x, false); } if (uiContact.getDescriptor() instanceof SourceContact && !ConfigurationManager.isAddContactDisabled()) { - constraints.anchor = GridBagConstraints.WEST; - constraints.fill = GridBagConstraints.NONE; - constraints.gridx = ++gridX; - constraints.gridy = 2; - constraints.gridwidth = 1; - constraints.gridheight = 1; - constraints.weightx = 0f; - constraints.weighty = 0f; - this.addContactButton.setBorder(null); - this.add(addContactButton, constraints); - - addContactButton.setBounds(x, y, 28, 28); - - x += addContactButton.getWidth(); + x += addButton(addContactButton, ++gridX, x, false); } // The list of the contact actions @@ -933,16 +882,20 @@ private void initButtonsPanel(UIContact uiContact) Collection<SIPCommButton> contactActions = uiContact.getContactCustomActionButtons(); - if (contactActions != null) + if (contactActions != null && contactActions.size() > 0) { - initContactActionButtons(contactActions, gridX, x); + initContactActionButtons(contactActions, ++gridX, x); } else { addLabels(gridX); } - this.setBounds(0, 0, treeContactList.getWidth(), getPreferredSize().height); + if (lastAddedButton != null) + setButtonBg(lastAddedButton, gridX, true); + + this.setBounds(0, 0, treeContactList.getWidth(), + getPreferredSize().height); } /** @@ -970,28 +923,8 @@ private void initContactActionButtons( customActionButtons.add(actionButton); - constraints.anchor = GridBagConstraints.WEST; - constraints.fill = GridBagConstraints.NONE; - constraints.gridx = ++gridX; - constraints.gridy = 2; - constraints.gridwidth = 1; - constraints.gridheight = 1; - constraints.weightx = 0f; - constraints.weighty = 0f; - actionButton.setBorder(null); - this.add(actionButton, constraints); - - int statusMessageLabelHeight = 0; - if (displayDetailsLabel.getText().length() > 0) - statusMessageLabelHeight = 20; - else - statusMessageLabelHeight = 15; - - actionButton.setBounds(xBounds, - nameLabel.getHeight() + statusMessageLabelHeight - + TOP_BORDER + STATUS_TOP_BORDER, 28, 28); - - xBounds += actionButton.getWidth(); + xBounds + += addButton(actionButton, ++gridX, xBounds, false); } } @@ -1035,6 +968,15 @@ public void paintIcon(Component c, Graphics g, int x, int y) } } + /** + * Returns the call button contained in the current cell. + * @return the call button contained in the current cell + */ + public JButton getChatButton() + { + return chatButton; + } + /** * Returns the call button contained in the current cell. * @return the call button contained in the current cell @@ -1365,7 +1307,9 @@ else if (providersCount > 1) else if (desktopContacts.size() > 1) { chooseAccountDialog - = new ChooseCallAccountPopupMenu(treeContactList, desktopContacts, + = new ChooseCallAccountPopupMenu( + treeContactList, + desktopContacts, OperationSetDesktopSharingServer.class); } @@ -1378,7 +1322,8 @@ else if (desktopContacts.size() > 1) SwingUtilities.convertPointToScreen(location, treeContactList); location.y = location.y - + treeContactList.getPathBounds(treeContactList.getSelectionPath()).y; + + treeContactList.getPathBounds( + treeContactList.getSelectionPath()).y; chooseAccountDialog.showPopupMenu(location.x + 8, location.y - 8); } @@ -1487,14 +1432,14 @@ public Icon getDragIcon(JTree tree, Object dragObject, int index) tree.getWidth() - imageWidth, 0, imageWidth, imageHeight); } - statusLabel.setBounds( 0, 0, + dragC.statusLabel.setBounds( 0, 0, statusLabel.getWidth(), statusLabel.getHeight()); - nameLabel.setBounds(statusLabel.getWidth(), 0, + dragC.nameLabel.setBounds(statusLabel.getWidth(), 0, tree.getWidth() - imageWidth - 5, nameLabel.getHeight()); - displayDetailsLabel.setBounds( + dragC.displayDetailsLabel.setBounds( displayDetailsLabel.getX(), nameLabel.getHeight(), displayDetailsLabel.getWidth(), @@ -1509,20 +1454,24 @@ public Icon getDragIcon(JTree tree, Object dragObject, int index) public void loadSkin() { openedGroupIcon - = new ImageIcon(ImageLoader.getImage(ImageLoader.DOWN_ARROW_ICON)); + = new ImageIcon(ImageLoader.getImage(ImageLoader.OPENED_GROUP_ICON)); closedGroupIcon - = new ImageIcon(ImageLoader.getImage(ImageLoader.RIGHT_ARROW_ICON)); + = new ImageIcon(ImageLoader.getImage(ImageLoader.CLOSED_GROUP_ICON)); - callButton.setBackgroundImage(ImageLoader.getImage( + callButton.setIconImage(ImageLoader.getImage( ImageLoader.CALL_BUTTON_SMALL)); + callButton.setRolloverImage(ImageLoader.getImage( + ImageLoader.CALL_BUTTON_SMALL_PRESSED)); callButton.setPressedImage(ImageLoader.getImage( ImageLoader.CALL_BUTTON_SMALL_PRESSED)); - chatButton.setBackgroundImage(ImageLoader.getImage( + chatButton.setIconImage(ImageLoader.getImage( ImageLoader.CHAT_BUTTON_SMALL)); chatButton.setPressedImage(ImageLoader.getImage( ImageLoader.CHAT_BUTTON_SMALL_PRESSED)); + chatButton.setRolloverImage(ImageLoader.getImage( + ImageLoader.CHAT_BUTTON_SMALL_PRESSED)); msgReceivedImage = ImageLoader.getImage(ImageLoader.MESSAGE_RECEIVED_ICON); @@ -1539,17 +1488,40 @@ public void loadSkin() if (contactForegroundProperty > -1) contactForegroundColor = new Color(contactForegroundProperty); - callVideoButton.setBackgroundImage(ImageLoader.getImage( + callVideoButton.setIconImage(ImageLoader.getImage( ImageLoader.CALL_VIDEO_BUTTON_SMALL)); - + callVideoButton.setRolloverImage(ImageLoader.getImage( + ImageLoader.CALL_VIDEO_BUTTON_SMALL_PRESSED)); callVideoButton.setPressedImage(ImageLoader.getImage( ImageLoader.CALL_VIDEO_BUTTON_SMALL_PRESSED)); - desktopSharingButton.setBackgroundImage(ImageLoader.getImage( + desktopSharingButton.setIconImage(ImageLoader.getImage( ImageLoader.DESKTOP_BUTTON_SMALL)); - + desktopSharingButton.setRolloverImage(ImageLoader.getImage( + ImageLoader.DESKTOP_BUTTON_SMALL_PRESSED)); desktopSharingButton.setPressedImage(ImageLoader.getImage( ImageLoader.DESKTOP_BUTTON_SMALL_PRESSED)); + + callVideoButton.setIconImage( + ImageLoader.getImage(ImageLoader.CALL_VIDEO_BUTTON_SMALL)); + callVideoButton.setRolloverImage( + ImageLoader.getImage(ImageLoader.CALL_VIDEO_BUTTON_SMALL_PRESSED)); + callVideoButton.setPressedImage( + ImageLoader.getImage(ImageLoader.CALL_VIDEO_BUTTON_SMALL_PRESSED)); + + desktopSharingButton.setIconImage( + ImageLoader.getImage(ImageLoader.DESKTOP_BUTTON_SMALL)); + desktopSharingButton.setRolloverImage( + ImageLoader.getImage(ImageLoader.DESKTOP_BUTTON_SMALL_PRESSED)); + desktopSharingButton.setPressedImage( + ImageLoader.getImage(ImageLoader.DESKTOP_BUTTON_SMALL_PRESSED)); + + addContactButton.setIconImage( + ImageLoader.getImage(ImageLoader.ADD_CONTACT_BUTTON_SMALL)); + addContactButton.setRolloverImage( + ImageLoader.getImage(ImageLoader.ADD_CONTACT_BUTTON_SMALL_PRESSED)); + addContactButton.setPressedImage( + ImageLoader.getImage(ImageLoader.ADD_CONTACT_BUTTON_SMALL_PRESSED)); } /** @@ -1628,4 +1600,78 @@ public void run() } } } + + private int addButton( SIPCommButton button, + int gridX, + int xBounds, + boolean isLast) + { + lastAddedButton = button; + + constraints.insets = new Insets(0, 0, V_GAP, 0); + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridx = gridX; + constraints.gridy = 2; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.weightx = 0f; + constraints.weighty = 0f; + this.add(button, constraints); + +// addButtonSeparator(gridX); + + int yBounds = TOP_BORDER + BOTTOM_BORDER + 2*V_GAP + + GuiUtils.getStringSize( + nameLabel, nameLabel.getText()).height + + GuiUtils.getStringSize( + displayDetailsLabel, displayDetailsLabel.getText()).height; + + button.setBounds(xBounds, yBounds, BUTTON_WIDTH, BUTTON_HEIGHT); + + button.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + + setButtonBg(button, gridX, isLast); + + return button.getWidth();// + BUTTON_SEPARATOR_IMG.getWidth(this); + } + + private void setButtonBg(SIPCommButton button, + int gridX, + boolean isLast) + { + if (!isLast) + { + if (gridX == 1) + button.setBackgroundImage(ImageLoader.getImage( + ImageLoader.CONTACT_LIST_BUTTON_BG_LEFT)); + else if (gridX > 1) + button.setBackgroundImage(ImageLoader.getImage( + ImageLoader.CONTACT_LIST_BUTTON_BG_MIDDLE)); + } + else + { + if (gridX == 1) // We have only one button shown. + button.setBackgroundImage(ImageLoader.getImage( + ImageLoader.CONTACT_LIST_ONE_BUTTON_BG)); + else // We set the background of the last button in the toolbar + button.setBackgroundImage(ImageLoader.getImage( + ImageLoader.CONTACT_LIST_BUTTON_BG_RIGHT)); + } + } + + private void addButtonSeparator(int buttonGridX) + { + JLabel separatorLabel = new JLabel(new ImageIcon(BUTTON_SEPARATOR_IMG)); + + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridx = ++buttonGridX; + constraints.gridy = 2; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.weightx = 0f; + constraints.weighty = 0f; + this.add(separatorLabel, constraints); + } } 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 f703aaa0f..37d8c9adb 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 @@ -1224,25 +1224,25 @@ else if (lastComponent instanceof GroupNode) /** * Forwards the given mouse <tt>event</tt> to the list of original * <tt>MouseListener</tt>-s. - * @param event the <tt>MouseEvent</tt> that notified us + * @param e the <tt>MouseEvent</tt> that notified us */ - public void mouseEntered(MouseEvent event) + public void mouseEntered(MouseEvent e) { // forward the event to the original listeners for (MouseListener listener : originalMouseListeners) - listener.mouseEntered(event); + listener.mouseEntered(e); } /** * Forwards the given mouse <tt>event</tt> to the list of original * <tt>MouseListener</tt>-s. - * @param event the <tt>MouseEvent</tt> that notified us + * @param e the <tt>MouseEvent</tt> that notified us */ - public void mouseExited(MouseEvent event) + public void mouseExited(MouseEvent e) { // forward the event to the original listeners for (MouseListener listener : originalMouseListeners) - listener.mouseExited(event); + listener.mouseExited(e); } /** @@ -1278,7 +1278,14 @@ private void openRightButtonMenu(Point contactListPoint) rightButtonMenu.setVisible(true); } - public void mouseMoved(MouseEvent e) {} + public void mouseMoved(MouseEvent e) + { + dispatchEventToButtons(e); + + // forward the event to the original listeners + for (MouseListener listener : originalMouseListeners) + listener.mouseReleased(e); + } public void mouseDragged(MouseEvent e) {} @@ -1335,18 +1342,29 @@ private void dispatchEventToButtons(MouseEvent event) TreePath mousePath = this.getPathForLocation(event.getX(), event.getY()); + ContactListTreeCellRenderer renderer + = (ContactListTreeCellRenderer) getCellRenderer() + .getTreeCellRendererComponent( this, + mousePath.getLastPathComponent(), + true, + true, + true, + this.getRowForPath(mousePath), + true); + // If this is not the selection path we have nothing to do here. if (mousePath == null || !mousePath.equals(this.getSelectionPath())) - return; + { + renderer.getChatButton().getModel().setRollover(false); + renderer.getCallButton().getModel().setRollover(false); + renderer.getCallVideoButton().getModel().setRollover(false); + renderer.getDesktopSharingButton().getModel().setRollover(false); + renderer.getAddContactButton().getModel().setRollover(false); - JPanel renderer = (JPanel) getCellRenderer() - .getTreeCellRendererComponent( this, - mousePath.getLastPathComponent(), - true, - true, - true, - this.getRowForPath(mousePath), - true); + this.repaint(); + + return; + } // We need to translate coordinates here. Rectangle r = this.getPathBounds(mousePath); @@ -1373,10 +1391,37 @@ private void dispatchEventToButtons(MouseEvent event) 5, // we're in the button for sure event.getClickCount(), event.isPopupTrigger()); - mouseComponent.dispatchEvent(evt); - this.repaint(); + ((SIPCommButton) mouseComponent).getModel() + .setRollover(event.getID() == MouseEvent.MOUSE_MOVED); + + if (!mouseComponent.equals(renderer.getChatButton())) + renderer.getChatButton().getModel().setRollover(false); + + if (!mouseComponent.equals(renderer.getCallButton())) + renderer.getCallButton().getModel().setRollover(false); + + if (!mouseComponent.equals(renderer.getCallVideoButton())) + renderer.getCallVideoButton().getModel().setRollover(false); + + if (!mouseComponent.equals(renderer.getDesktopSharingButton())) + renderer.getDesktopSharingButton().getModel().setRollover(false); + + if (!mouseComponent.equals(renderer.getAddContactButton())) + renderer.getAddContactButton().getModel().setRollover(false); + + mouseComponent.dispatchEvent(evt); } + else + { + renderer.getChatButton().getModel().setRollover(false); + renderer.getCallButton().getModel().setRollover(false); + renderer.getCallVideoButton().getModel().setRollover(false); + renderer.getDesktopSharingButton().getModel().setRollover(false); + renderer.getAddContactButton().getModel().setRollover(false); + } + + this.repaint(); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java b/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java index a49d02af8..4aa50c804 100644 --- a/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java @@ -345,7 +345,7 @@ public boolean hasSelectedMenus() */ public void registrationStateChanged(RegistrationStateChangeEvent evt) { - ProtocolProviderService protocolProvider = evt.getProvider(); + final ProtocolProviderService protocolProvider = evt.getProvider(); this.updateStatus(protocolProvider); @@ -379,16 +379,30 @@ public void run() { if (currentImage == null) { - byte[] accountImage - = AccountInfoUtils.getImage(accountInfoOpSet); + currentImage + = AvatarCacheUtils + .getCachedAvatar(protocolProvider); - // do not set empty images - if ((accountImage != null) - && (accountImage.length > 0)) + if (currentImage == null) { - currentImage = accountImage; - accountImageLabel.setImageIcon(currentImage); + byte[] accountImage + = AccountInfoUtils + .getImage(accountInfoOpSet); + + // do not set empty images + if ((accountImage != null) + && (accountImage.length > 0)) + { + currentImage = accountImage; + + AvatarCacheUtils.cacheAvatar( + protocolProvider, accountImage); + + accountImageLabel.setImageIcon(currentImage); + } } + else + accountImageLabel.setImageIcon(currentImage); } if(!StringUtils.isNullOrEmpty(globalDisplayName)) @@ -570,6 +584,10 @@ public void avatarChanged(AvatarEvent event) currentImage = ImageUtils.toByteArray( ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO)); } + + AvatarCacheUtils.cacheAvatar( + event.getSourceProvider(), currentImage); + accountImageLabel.setImageIcon(currentImage); } diff --git a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java index e589bd445..63c21f747 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java +++ b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java @@ -195,12 +195,6 @@ public class ImageLoader public static final ImageID MORE_BUTTON = new ImageID("service.gui.buttons.MORE_BUTTON"); - /** - * Closed group icon. - */ - public static final ImageID RIGHT_ARROW_ICON - = new ImageID("service.gui.icons.RIGHT_ARROW_ICON"); - /** * The background of the main window and chat window. */ @@ -275,6 +269,40 @@ public class ImageLoader public static final ImageID CALL_VIDEO_BUTTON_BG = new ImageID("service.gui.buttons.CALL_VIDEO_BUTTON_BG"); + /** + * The background image for a button in contact list that is shown on the + * left of the button toolbar. + */ + public static final ImageID CONTACT_LIST_BUTTON_BG_LEFT + = new ImageID("service.gui.buttons.CONTACT_LIST_BUTTON_BG_LEFT"); + + /** + * The background image for a button in contact list that is shown on the + * right of the button toolbar. + */ + public static final ImageID CONTACT_LIST_BUTTON_BG_RIGHT + = new ImageID("service.gui.buttons.CONTACT_LIST_BUTTON_BG_RIGHT"); + + /** + * The background image for a button in contact list that is shown in the + * middle of other buttons. + */ + public static final ImageID CONTACT_LIST_BUTTON_BG_MIDDLE + = new ImageID("service.gui.buttons.CONTACT_LIST_BUTTON_BG_MIDDLE"); + + /** + * The background image for a button in contact list if there's only one + * button shown. + */ + public static final ImageID CONTACT_LIST_ONE_BUTTON_BG + = new ImageID("service.gui.buttons.CONTACT_LIST_ONE_BUTTON_BG"); + + /** + * The separator image for the button toolbar in the contact list. + */ + public static final ImageID CONTACT_LIST_BUTTON_SEPARATOR + = new ImageID("service.gui.buttons.CONTACT_LIST_BUTTON_SEPARATOR"); + /** * The call button small image. */ @@ -343,12 +371,24 @@ public class ImageLoader public static final ImageID CHAT_BUTTON_SMALL_WHITE = new ImageID("service.gui.buttons.CHAT_BUTTON_SMALL_WHITE"); + /** + * The icon used to separate buttons in the call toolbar. + */ + public static final ImageID CALL_TOOLBAR_SEPARATOR + = new ImageID("service.gui.icons.CALL_TOOLBAR_SEPARATOR"); + /** * The chat call button image. */ public static final ImageID CHAT_CALL = new ImageID("service.gui.buttons.CHAT_CALL"); + /** + * The chat video call button image. + */ + public static final ImageID CHAT_VIDEO_CALL + = new ImageID("service.gui.buttons.CHAT_VIDEO_CALL"); + /** * The chat call button image. */ @@ -367,6 +407,12 @@ public class ImageLoader public static final ImageID CALL_HISTORY_BUTTON_PRESSED = new ImageID("service.gui.buttons.CALL_HISTORY_BUTTON_PRESSED"); + /** + * The call history button missed call notification image. + */ + public static final ImageID CALL_HISTORY_BUTTON_NOTIFICATION + = new ImageID("service.gui.icons.CALL_HISTORY_BUTTON_NOTIFICATION"); + /** * The chat button small pressed image. */ @@ -987,13 +1033,13 @@ public class ImageLoader /** * The image used for opened groups. */ - public static final ImageID OPENED_GROUP + public static final ImageID OPENED_GROUP_ICON = new ImageID("service.gui.icons.OPENED_GROUP"); /** * The image used for closed groups. */ - public static final ImageID CLOSED_GROUP + public static final ImageID CLOSED_GROUP_ICON = new ImageID("service.gui.icons.CLOSED_GROUP"); /** @@ -1763,6 +1809,67 @@ public static Image getIndexedProtocolImage( badged = image; return badged; } + + /** + * Returns the given protocol image with an index allowing to distinguish + * different accounts from the same protocol. + * + * @param bgImage the background image + * @param topImage the image that should be painted on the top of the + * background image + * @param x the x coordinate of the top image + * @param y the y coordinate of the top image + * @return the result merged image + */ + public static Image getImage(Image bgImage, Image topImage, int x, int y) + { + BufferedImage buffImage + = new BufferedImage(bgImage.getWidth(null), + bgImage.getHeight(null), + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = (Graphics2D) buffImage.getGraphics(); + + AntialiasingManager.activateAntialiasing(g); + g.drawImage(bgImage, 0, 0, null); + g.drawImage(topImage, x, y, null); + + return buffImage; + } + + /** + * Returns the given protocol image with an index allowing to distinguish + * different accounts from the same protocol. + * + * @param bgImage the background image + * @param text the text that should be painted on the top of the + * background image + * @return the result merged image + */ + public static Image getImage(Image bgImage, String text, Component c) + { + BufferedImage buffImage + = new BufferedImage(bgImage.getWidth(c), + bgImage.getHeight(c), + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = (Graphics2D) buffImage.getGraphics(); + + AntialiasingManager.activateAntialiasing(g); + g.setColor(Color.WHITE); + g.setFont(c.getFont().deriveFont(Font.BOLD, 9)); + g.drawImage(bgImage, 0, 0, null); + + FontMetrics fontMetrics = g.getFontMetrics(); + int fontHeight = fontMetrics.getHeight(); + int textWidth = fontMetrics.stringWidth(text); + + g.drawString( + text, + (bgImage.getWidth(null) - textWidth)/2 + 1, + (bgImage.getHeight(null) - fontHeight)/2 + fontHeight - 3); + + return buffImage; + } + /** * Loads an image icon from a given image path. * @param imagePath The identifier of the image. diff --git a/src/net/java/sip/communicator/util/AvatarCacheUtils.java b/src/net/java/sip/communicator/util/AvatarCacheUtils.java new file mode 100644 index 000000000..37dcac199 --- /dev/null +++ b/src/net/java/sip/communicator/util/AvatarCacheUtils.java @@ -0,0 +1,344 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.util; + +import java.io.*; + +import org.jitsi.service.fileaccess.*; + +import net.java.sip.communicator.service.protocol.*; + +/** + * The <tt>AvatarCacheUtils</tt> allows to cache an avatar or to obtain the + * image of a cached avatar by specifying a contact or an account address. + * + * @author Yana Stamcheva + */ +public class AvatarCacheUtils +{ + /** + * The logger for this class. + */ + private final static Logger logger + = Logger.getLogger(AvatarCacheUtils.class); + + /** + * The name (i.e. not the whole path) of the directory in which the avatar + * files are to be cached for later reuse. + */ + private final static String AVATAR_DIR = "avatarcache"; + + /** + * Characters and their replacement in created folder names + */ + private final static String[][] ESCAPE_SEQUENCES = new String[][] + { + {"&", "&_amp"}, + {"/", "&_sl"}, + {"\\\\", "&_bs"}, // the char \ + {":", "&_co"}, + {"\\*", "&_as"}, // the char * + {"\\?", "&_qm"}, // the char ? + {"\"", "&_pa"}, // the char " + {"<", "&_lt"}, + {">", "&_gt"}, + {"\\|", "&_pp"} // the char | + }; + + /** + * Returns the bytes of the avatar image stored for the account + * corresponding to the given protocol provider. + * + * @param protocolProvider the <tt>ProtocolProviderService</tt>, which + * account avatar image we're looking for + * @return the bytes of the avatar image stored for the account + * corresponding to the given protocol provider + */ + public static byte[] getCachedAvatar( + ProtocolProviderService protocolProvider) + { + String avatarPath = getCachedAvatarPath(protocolProvider); + + byte[] cachedAvatar = getLocallyStoredAvatar(avatarPath); + + /* + * Caching a zero-length avatar happens but such an avatar isn't + * very useful. + */ + if ((cachedAvatar != null) && (cachedAvatar.length > 0)) + return cachedAvatar; + + return null; + } + + /** + * Returns the bytes of the avatar image stored for the account + * corresponding to the given protocol provider. + * + * @param protocolProvider the <tt>ProtocolProviderService</tt>, which + * account avatar image we're looking for + * @return the bytes of the avatar image stored for the account + * corresponding to the given protocol provider + */ + public static byte[] getCachedAvatar(Contact protocolContact) + { + String avatarPath = getCachedAvatarPath(protocolContact); + + byte[] cachedAvatar = getLocallyStoredAvatar(avatarPath); + + /* + * Caching a zero-length avatar happens but such an avatar isn't + * very useful. + */ + if ((cachedAvatar != null) && (cachedAvatar.length > 0)) + return cachedAvatar; + + return null; + } + + /** + * Returns the bytes of the avatar image stored for the account + * corresponding to the given protocol provider. + * + * @param protocolProvider the <tt>ProtocolProviderService</tt>, which + * account avatar image we're looking for + * @return the bytes of the avatar image stored for the account + * corresponding to the given protocol provider + */ + public static String getCachedAvatarPath( + ProtocolProviderService protocolProvider) + { + return AVATAR_DIR + + File.separator + + escapeSpecialCharacters( + protocolProvider.getAccountID().getAccountUniqueID()) + + File.separator + + escapeSpecialCharacters( + protocolProvider.getAccountID().getAccountUniqueID()); + } + + /** + * Returns the bytes of the avatar image stored for the account + * corresponding to the given protocol provider. + * + * @param protocolProvider the <tt>ProtocolProviderService</tt>, which + * account avatar image we're looking for + * @return the bytes of the avatar image stored for the account + * corresponding to the given protocol provider + */ + public static String getCachedAvatarPath(Contact protocolContact) + { + return AVATAR_DIR + + File.separator + + escapeSpecialCharacters( + protocolContact + .getProtocolProvider() + .getAccountID().getAccountUniqueID()) + + File.separator + + escapeSpecialCharacters(protocolContact.getAddress()); + } + + /** + * Returns the bytes of the avatar image stored for the account + * corresponding to the given protocol provider. + * + * @param protocolProvider the <tt>ProtocolProviderService</tt>, which + * account avatar image we're looking for + * @return the bytes of the avatar image stored for the account + * corresponding to the given protocol provider + */ + public static String getCachedAvatarPath( + ProtocolProviderService protocolProvider, + String contactAddress) + { + return AVATAR_DIR + + File.separator + + escapeSpecialCharacters( + protocolProvider.getAccountID().getAccountUniqueID()) + + File.separator + + escapeSpecialCharacters(contactAddress); + } + + /** + * Returns the avatar image corresponding to the given avatar path. + * + * @param avatarPath The path to the lovally stored avatar. + * @return the avatar image corresponding to the given avatar path. + */ + private static byte[] getLocallyStoredAvatar(String avatarPath) + { + try + { + File avatarFile + = UtilActivator + .getFileAccessService() + .getPrivatePersistentFile(avatarPath); + + if(avatarFile.exists()) + { + FileInputStream avatarInputStream + = new FileInputStream(avatarFile); + byte[] bs = null; + + try + { + int available = avatarInputStream.available(); + + if (available > 0) + { + bs = new byte[available]; + avatarInputStream.read(bs); + } + } + finally + { + avatarInputStream.close(); + } + if (bs != null) + return bs; + } + } + catch (Exception ex) + { + logger.error( + "Could not read avatar image from file " + avatarPath, + ex); + } + return null; + } + + /** + * Replaces the characters that we must escape used for the created + * filename. + * + * @param id the <tt>String</tt> which is to have its characters escaped + * @return a <tt>String</tt> derived from the specified <tt>id</tt> by + * escaping characters + */ + private static String escapeSpecialCharacters(String id) + { + String resultId = id; + + for (int j = 0; j < ESCAPE_SEQUENCES.length; j++) + { + resultId = resultId. + replaceAll(ESCAPE_SEQUENCES[j][0], ESCAPE_SEQUENCES[j][1]); + } + return resultId; + } + + /** + * Stores avatar bytes in the given <tt>Contact</tt>. + * + * @param protoContact The contact in which we store the avatar. + * @param avatarBytes The avatar image bytes. + */ + public static void cacheAvatar( Contact protoContact, + byte[] avatarBytes) + { + String avatarDirPath + = AVATAR_DIR + + File.separator + + escapeSpecialCharacters( + protoContact + .getProtocolProvider() + .getAccountID().getAccountUniqueID()); + String avatarFileName + = escapeSpecialCharacters(protoContact.getAddress()); + + cacheAvatar(avatarDirPath, avatarFileName, avatarBytes); + } + /** + * Stores avatar bytes for the account corresponding to the given + * <tt>protocolProvider</tt>. + * + * @param protocolProvider the protocol provider corresponding to the + * account, which avatar we're storing + * @param avatarBytes the avatar image bytes + */ + public static void cacheAvatar( ProtocolProviderService protocolProvider, + byte[] avatarBytes) + { + String accountUID + = protocolProvider.getAccountID().getAccountUniqueID(); + + String avatarDirPath + = AVATAR_DIR + + File.separator + + escapeSpecialCharacters(accountUID); + + String avatarFileName = escapeSpecialCharacters(accountUID); + + cacheAvatar(avatarDirPath, avatarFileName, avatarBytes); + } + + /** + * Stores avatar bytes for the account corresponding to the given + * <tt>protocolProvider</tt>. + * + * @param avatarDirPath the directory in which the file will be stored + * @param avatarFileName the name of the avatar file + * @param avatarBytes the avatar image bytes + */ + private static void cacheAvatar(String avatarDirPath, + String avatarFileName, + byte[] avatarBytes) + { + File avatarDir = null; + File avatarFile = null; + try + { + FileAccessService fileAccessService + = UtilActivator.getFileAccessService(); + + avatarDir + = fileAccessService.getPrivatePersistentDirectory( + avatarDirPath); + avatarFile + = fileAccessService.getPrivatePersistentFile( + avatarDirPath + File.separator + avatarFileName); + + if(!avatarFile.exists()) + { + if (!avatarDir.exists() && !avatarDir.mkdirs()) + { + throw + new IOException( + "Failed to create directory: " + + avatarDir.getAbsolutePath()); + } + + if (!avatarFile.createNewFile()) + { + throw + new IOException( + "Failed to create file" + + avatarFile.getAbsolutePath()); + } + } + + FileOutputStream fileOutStream = new FileOutputStream(avatarFile); + + try + { + fileOutStream.write(avatarBytes); + fileOutStream.flush(); + } + finally + { + fileOutStream.close(); + } + } + catch (Exception ex) + { + logger.error( + "Failed to store avatar. dir =" + avatarDir + + " file=" + avatarFile, + ex); + } + } +} diff --git a/src/net/java/sip/communicator/util/GuiUtils.java b/src/net/java/sip/communicator/util/GuiUtils.java index a106bdeb6..aad18259e 100644 --- a/src/net/java/sip/communicator/util/GuiUtils.java +++ b/src/net/java/sip/communicator/util/GuiUtils.java @@ -59,6 +59,23 @@ public class GuiUtils // European equivalent. private static final Map<Character, Character> DIGIT_MAPPINGS; + /** + * Characters and their replacement in created folder names + */ + private final static String[][] ESCAPE_SEQUENCES = new String[][] + { + {"&", "&_amp"}, + {"/", "&_sl"}, + {"\\\\", "&_bs"}, // the char \ + {":", "&_co"}, + {"\\*", "&_as"}, // the char * + {"\\?", "&_qm"}, // the char ? + {"\"", "&_pa"}, // the char " + {"<", "&_lt"}, + {">", "&_gt"}, + {"\\|", "&_pp"} // the char | + }; + static { HashMap<Character, Character> digitMap @@ -644,4 +661,24 @@ else if (c instanceof java.awt.Container) updateComponentTreeUI0(children[i]); } } + + /** + * Replaces the characters that we must escape used for the created + * filename. + * + * @param string the <tt>String</tt> which is to have its characters escaped + * @return a <tt>String</tt> derived from the specified <tt>id</tt> by + * escaping characters + */ + public static String escapeFileNameSpecialCharacters(String string) + { + String resultId = string; + + for (int j = 0; j < ESCAPE_SEQUENCES.length; j++) + { + resultId = resultId. + replaceAll(ESCAPE_SEQUENCES[j][0], ESCAPE_SEQUENCES[j][1]); + } + return resultId; + } } diff --git a/src/net/java/sip/communicator/util/ImageUtils.java b/src/net/java/sip/communicator/util/ImageUtils.java index 002dcdea1..dd5933d3f 100644 --- a/src/net/java/sip/communicator/util/ImageUtils.java +++ b/src/net/java/sip/communicator/util/ImageUtils.java @@ -168,7 +168,7 @@ public static Image getScaledRoundedImage( Image image, g.setComposite(AlphaComposite.Src); AntialiasingManager.activateAntialiasing(g); g.setColor(Color.WHITE); - g.fillRoundRect(0, 0, scaledImageWidth, scaledImageHeight, 15, 15); + g.fillRoundRect(0, 0, scaledImageWidth, scaledImageHeight, 5, 5); // We use SrcAtop, which effectively uses the // alpha value as a coverage value for each pixel stored in the diff --git a/src/net/java/sip/communicator/util/UtilActivator.java b/src/net/java/sip/communicator/util/UtilActivator.java index e4f523b95..78d6c5e23 100644 --- a/src/net/java/sip/communicator/util/UtilActivator.java +++ b/src/net/java/sip/communicator/util/UtilActivator.java @@ -18,6 +18,7 @@ import net.java.sip.communicator.service.resources.*; import org.jitsi.service.configuration.*; +import org.jitsi.service.fileaccess.*; import org.jitsi.service.neomedia.*; import org.jitsi.service.resources.*; import org.osgi.framework.*; @@ -51,6 +52,8 @@ public class UtilActivator private static UIService uiService; + private static FileAccessService fileAccessService; + private static BundleContext bundleContext; /** @@ -238,6 +241,23 @@ public static UIService getUIService() return uiService; } + /** + * Returns the <tt>FileAccessService</tt> obtained from the bundle context. + * + * @return the <tt>FileAccessService</tt> obtained from the bundle context + */ + public static FileAccessService getFileAccessService() + { + if (fileAccessService == null) + { + fileAccessService + = ServiceUtils.getService( + bundleContext, + FileAccessService.class); + } + return fileAccessService; + } + /** * Returns the {@link MediaConfigurationService} instance registered in the * <tt>BundleContext</tt> of the <tt>UtilActivator</tt>. diff --git a/src/net/java/sip/communicator/util/swing/OrderedTransparentPanel.java b/src/net/java/sip/communicator/util/swing/OrderedTransparentPanel.java index 9cc93676f..ebc358e55 100644 --- a/src/net/java/sip/communicator/util/swing/OrderedTransparentPanel.java +++ b/src/net/java/sip/communicator/util/swing/OrderedTransparentPanel.java @@ -18,7 +18,7 @@ public class OrderedTransparentPanel extends TransparentPanel { private static final long serialVersionUID = 0L; - + public Component add(Component comp) { if(comp instanceof OrderedComponent) @@ -54,7 +54,7 @@ private Component addOrdered(Component comp) int cIx; if(c instanceof OrderedComponent) { - cIx = ((OrderedComponent)c).getIndex(); + cIx = ((OrderedComponent) c).getIndex(); if(orederIndex < cIx) { diff --git a/src/net/java/sip/communicator/util/swing/SIPCommButton.java b/src/net/java/sip/communicator/util/swing/SIPCommButton.java index cbdea5294..db40d4d58 100755 --- a/src/net/java/sip/communicator/util/swing/SIPCommButton.java +++ b/src/net/java/sip/communicator/util/swing/SIPCommButton.java @@ -221,19 +221,11 @@ private void internalPaintComponent(Graphics g) g.setColor(new Color(1.0f, 1.0f, 1.0f, visibility)); - if (this.bgImage != null) + if (this.bgImage == null + && (isContentAreaFilled() || (visibility != 0.0f))) { g.fillRoundRect( - this.getWidth() / 2 - this.bgImage.getWidth(null) / 2, - this.getHeight() / 2 - this.bgImage.getHeight(null) / 2, - bgImage.getWidth(null), - bgImage.getHeight(null), - 10, 10); - } - else if (isContentAreaFilled() || (visibility != 0.0f)) - { - g.fillRoundRect( - 0, 0, this.getWidth(), this.getHeight(), 10, 10); + 0, 0, this.getWidth(), this.getHeight(), 8, 8); } } diff --git a/src/net/java/sip/communicator/util/swing/SIPCommTextButton.java b/src/net/java/sip/communicator/util/swing/SIPCommTextButton.java index 14b130ee9..eb6fe7ce7 100644 --- a/src/net/java/sip/communicator/util/swing/SIPCommTextButton.java +++ b/src/net/java/sip/communicator/util/swing/SIPCommTextButton.java @@ -91,6 +91,16 @@ public void setBgImage(Image image) this.bgImage = image; } + /** + * Return the background image. + * + * @return the background image of this button + */ + public Image getBgImage() + { + return bgImage; + } + /** * Overrides the <code>paintComponent</code> method of <tt>JButton</tt> to * paint the button background and icon, and all additional effects of this diff --git a/src/net/java/sip/communicator/util/swing/SIPCommToggleButton.java b/src/net/java/sip/communicator/util/swing/SIPCommToggleButton.java index 6a1ca4631..a18e20759 100644 --- a/src/net/java/sip/communicator/util/swing/SIPCommToggleButton.java +++ b/src/net/java/sip/communicator/util/swing/SIPCommToggleButton.java @@ -234,12 +234,17 @@ else if (iconImage != null) } } + int bgWidth = (bgImage != null) + ? bgImage.getWidth(null) + : getWidth(); + int bgHeight = (bgImage != null) + ? bgImage.getHeight(null) + : getHeight(); + if (iconImageFinal != null) g.drawImage(iconImageFinal, - (this.bgImage.getWidth(null) - iconImageFinal - .getWidth(null)) / 2, (this.bgImage - .getHeight(null) - iconImageFinal - .getHeight(null)) / 2, this); + (bgWidth - iconImageFinal.getWidth(null)) / 2, + (bgHeight - iconImageFinal.getHeight(null)) / 2, this); } /** diff --git a/src/net/java/sip/communicator/util/swing/SoundLevelIndicator.java b/src/net/java/sip/communicator/util/swing/SoundLevelIndicator.java index 92b65dd2d..4e81bc9ff 100644 --- a/src/net/java/sip/communicator/util/swing/SoundLevelIndicator.java +++ b/src/net/java/sip/communicator/util/swing/SoundLevelIndicator.java @@ -32,11 +32,29 @@ public class SoundLevelIndicator */ private static final long serialVersionUID = 0L; - private static final String SOUND_LEVEL_ACTIVE - = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE"; + private static final String SOUND_LEVEL_ACTIVE_LEFT + = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE_LEFT"; - private static final String SOUND_LEVEL_INACTIVE - = "service.gui.soundlevel.SOUND_LEVEL_INACTIVE"; + private static final String SOUND_LEVEL_ACTIVE_LEFT_GRADIENT + = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE_LEFT_GRADIENT"; + + private static final String SOUND_LEVEL_ACTIVE_MIDDLE + = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE_MIDDLE"; + + private static final String SOUND_LEVEL_ACTIVE_RIGHT + = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE_RIGHT"; + + private static final String SOUND_LEVEL_ACTIVE_RIGHT_GRADIENT + = "service.gui.soundlevel.SOUND_LEVEL_ACTIVE_RIGHT_GRADIENT"; + + private static final String SOUND_LEVEL_INACTIVE_LEFT + = "service.gui.soundlevel.SOUND_LEVEL_INACTIVE_LEFT"; + + private static final String SOUND_LEVEL_INACTIVE_MIDDLE + = "service.gui.soundlevel.SOUND_LEVEL_INACTIVE_MIDDLE"; + + private static final String SOUND_LEVEL_INACTIVE_RIGHT + = "service.gui.soundlevel.SOUND_LEVEL_INACTIVE_RIGHT"; /** * The maximum possible sound level. @@ -62,12 +80,42 @@ public class SoundLevelIndicator /** * Image when a sound level block is active */ - private ImageIcon soundLevelActiveImage; + private ImageIcon soundLevelActiveImageLeft; + + /** + * Image when a sound level block is active + */ + private ImageIcon soundLevelActiveImageLeftGradient; + + /** + * Image when a sound level block is active + */ + private ImageIcon soundLevelActiveImageMiddle; + + /** + * Image when a sound level block is active + */ + private ImageIcon soundLevelActiveImageRight; + + /** + * Image when a sound level block is active + */ + private ImageIcon soundLevelActiveImageRightGradient; + + /** + * Image when a sound level block is not active + */ + private ImageIcon soundLevelInactiveImageLeft; /** * Image when a sound level block is not active */ - private ImageIcon soundLevelInactiveImage; + private ImageIcon soundLevelInactiveImageMiddle; + + /** + * Image when a sound level block is not active + */ + private ImageIcon soundLevelInactiveImageRight; /** * Initializes a new <tt>SoundLevelIndicator</tt> instance. @@ -143,12 +191,42 @@ else if (soundLevel > maxSoundLevel) if (c instanceof JLabel) { + Icon activeIcon = null; + Icon inactiveIcon = null; + if (i == 0) + { + if (activeSoundBarCount == 1) + activeIcon = soundLevelActiveImageLeftGradient; + else + { + activeIcon = soundLevelActiveImageLeft; + inactiveIcon = soundLevelInactiveImageLeft; + } + } + else if (i == activeSoundBarCount - 1) + { + if (i == components.length - 1) + activeIcon = soundLevelActiveImageRight; + else + activeIcon = soundLevelActiveImageRightGradient; + } + else if (i == components.length - 1) + { + inactiveIcon = soundLevelInactiveImageRight; + } + else + { + activeIcon = soundLevelActiveImageMiddle; + inactiveIcon = soundLevelInactiveImageMiddle; + } + ((JLabel) c).setIcon( (i < activeSoundBarCount) - ? soundLevelActiveImage - : soundLevelInactiveImage); + ? activeIcon + : inactiveIcon); } } + repaint(); } @@ -183,7 +261,13 @@ public void setBounds(int x, int y, int width, int height) } while (soundBarCount < newSoundBarCount) { - JLabel soundBar = new JLabel(soundLevelInactiveImage); + JLabel soundBar; + if (soundBarCount == 0) + soundBar = new JLabel(soundLevelInactiveImageLeft); + else if (soundBarCount == newSoundBarCount - 1) + soundBar = new JLabel(soundLevelInactiveImageRight); + else + soundBar = new JLabel(soundLevelInactiveImageMiddle); soundBar.setVerticalAlignment(JLabel.CENTER); add(soundBar); @@ -206,7 +290,7 @@ public void setBounds(int x, int y, int width, int height) */ private int getSoundBarCount(int width) { - int soundBarWidth = soundLevelActiveImage.getIconWidth(); + int soundBarWidth = soundLevelActiveImageLeft.getIconWidth(); return width / soundBarWidth; } @@ -218,28 +302,43 @@ public void loadSkin() { ResourceManagementService resources = UtilActivator.getResources(); - soundLevelActiveImage = resources.getImage(SOUND_LEVEL_ACTIVE); - soundLevelInactiveImage = resources.getImage(SOUND_LEVEL_INACTIVE); + soundLevelActiveImageLeft + = resources.getImage(SOUND_LEVEL_ACTIVE_LEFT); + soundLevelActiveImageLeftGradient + = resources.getImage(SOUND_LEVEL_ACTIVE_LEFT_GRADIENT); + soundLevelActiveImageMiddle + = resources.getImage(SOUND_LEVEL_ACTIVE_MIDDLE); + soundLevelActiveImageRight + = resources.getImage(SOUND_LEVEL_ACTIVE_RIGHT); + soundLevelActiveImageRightGradient + = resources.getImage(SOUND_LEVEL_ACTIVE_RIGHT_GRADIENT); + + soundLevelInactiveImageLeft + = resources.getImage(SOUND_LEVEL_INACTIVE_LEFT); + soundLevelInactiveImageMiddle + = resources.getImage(SOUND_LEVEL_INACTIVE_MIDDLE); + soundLevelInactiveImageRight + = resources.getImage(SOUND_LEVEL_INACTIVE_RIGHT); if (!isPreferredSizeSet()) { int preferredHeight = 0; int preferredWidth = 0; - if (soundLevelActiveImage != null) + if (soundLevelActiveImageLeft != null) { - int height = soundLevelActiveImage.getIconHeight(); - int width = soundLevelActiveImage.getIconWidth(); + int height = soundLevelActiveImageLeft.getIconHeight(); + int width = soundLevelActiveImageLeft.getIconWidth(); if (preferredHeight < height) preferredHeight = height; if (preferredWidth < width) preferredWidth = width; } - if (soundLevelInactiveImage != null) + if (soundLevelInactiveImageLeft != null) { - int height = soundLevelInactiveImage.getIconHeight(); - int width = soundLevelInactiveImage.getIconWidth(); + int height = soundLevelInactiveImageLeft.getIconHeight(); + int width = soundLevelInactiveImageLeft.getIconWidth(); if (preferredHeight < height) preferredHeight = height; diff --git a/src/net/java/sip/communicator/util/swing/plaf/SIPCommTabbedPaneUI.java b/src/net/java/sip/communicator/util/swing/plaf/SIPCommTabbedPaneUI.java index 554119be6..93f7c6c95 100644 --- a/src/net/java/sip/communicator/util/swing/plaf/SIPCommTabbedPaneUI.java +++ b/src/net/java/sip/communicator/util/swing/plaf/SIPCommTabbedPaneUI.java @@ -78,7 +78,7 @@ public class SIPCommTabbedPaneUI public static final int BUTTONSIZE = 15; - public static final int WIDTHDELTA = 10; + public static final int WIDTHDELTA = 1; private static final Border PRESSEDBORDER = new SoftBevelBorder( SoftBevelBorder.LOWERED); @@ -237,9 +237,10 @@ protected void layoutLabel(int tabPlacement, FontMetrics metrics, tabPane.putClientProperty("html", null); - iconRect.x = tabRect.x + 5; + iconRect.y = iconRect.y + 2; + iconRect.x = tabRect.x + 7; + textRect.y = textRect.y + 2; textRect.x = iconRect.x + iconRect.width + 5; - } protected MouseListener createMouseListener() @@ -649,8 +650,7 @@ protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects, if (cropShape) { save = g2.getClip(); - g2 - .clipRect(tabRect.x, tabRect.y, tabRect.width, + g2.clipRect(tabRect.x, tabRect.y, tabRect.width, tabRect.height); } @@ -687,7 +687,7 @@ protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects, else if (isOver || isSelected) { int dx = tabRect.x + tabRect.width - BUTTONSIZE - WIDTHDELTA; - int dy = (tabRect.y + tabRect.height) / 2 - 7; + int dy = (tabRect.y + tabRect.height) / 2 - 3; if (isCloseButtonEnabled) paintCloseIcon(g2, dx, dy, isOver); diff --git a/src/net/java/sip/communicator/util/swing/plaf/SIPCommTextFieldUI.java b/src/net/java/sip/communicator/util/swing/plaf/SIPCommTextFieldUI.java index 5b6819746..1b1a6431c 100644 --- a/src/net/java/sip/communicator/util/swing/plaf/SIPCommTextFieldUI.java +++ b/src/net/java/sip/communicator/util/swing/plaf/SIPCommTextFieldUI.java @@ -183,7 +183,7 @@ protected void customPaintBackground(Graphics g) if(isRounded) { g2.fillRoundRect(1, 1, c.getWidth() - 1, c.getHeight() - 1, - 20, 20); + 8, 8); } else { @@ -225,8 +225,8 @@ protected void customPaintBackground(Graphics g) if(isRounded) { - g2.drawRoundRect(0, 0, c.getWidth() - 1, c.getHeight() - 1, - 20, 20); + g2.drawRoundRect( + 0, 0, c.getWidth() - 1, c.getHeight() - 1, 8, 8); } else { diff --git a/src/net/java/sip/communicator/util/util.manifest.mf b/src/net/java/sip/communicator/util/util.manifest.mf index 64557f4af..7e08cd4cd 100644 --- a/src/net/java/sip/communicator/util/util.manifest.mf +++ b/src/net/java/sip/communicator/util/util.manifest.mf @@ -41,6 +41,7 @@ Import-Package: com.sun.awt, org.jitsi.service.neomedia, org.jitsi.service.neomedia.codec, org.jitsi.service.resources, + org.jitsi.service.fileaccess, org.jitsi.util, org.jitsi.util.event, org.jitsi.util.swing,