diff options
author | Yana Stamcheva <yana@jitsi.org> | 2012-09-23 17:23:33 +0000 |
---|---|---|
committer | Yana Stamcheva <yana@jitsi.org> | 2012-09-23 17:23:33 +0000 |
commit | 86a0325947316d5e4b229a7f178f87a4f12be52c (patch) | |
tree | c83d09fad6da0566b0f4f310ce651da5660c9674 /src/net/java/sip | |
parent | 9dfae463286f44520f3ce9dda3e4ea01ff35f852 (diff) | |
download | jitsi-86a0325947316d5e4b229a7f178f87a4f12be52c.zip jitsi-86a0325947316d5e4b229a7f178f87a4f12be52c.tar.gz jitsi-86a0325947316d5e4b229a7f178f87a4f12be52c.tar.bz2 |
New enhanced interface.
Diffstat (limited to 'src/net/java/sip')
45 files changed, 2801 insertions, 1167 deletions
diff --git a/src/net/java/sip/communicator/impl/contactlist/MetaContactImpl.java b/src/net/java/sip/communicator/impl/contactlist/MetaContactImpl.java index 8b1573d..81528e4 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.contactlist.event.*; 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. * @@ -94,34 +91,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. */ MetaContactImpl() @@ -636,16 +610,8 @@ public class MetaContactImpl 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 class MetaContactImpl 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 a0f2eb9..7bc1ea7 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 @@ public class MainFrame 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 7958d68..0c67e0b 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 abstract class 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 abstract class 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 @@ public abstract class AbstractCallToggleButton */ 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 abstract class AbstractCallToggleButton { 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 abstract class AbstractCallToggleButton 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 476ad52..d00d60d 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 @@ -42,6 +42,11 @@ public class CallHistoryButton private Image pressedImage; /** + * The notification image. + */ + private Image notificationImage; + + /** * Indicates if the history is visible. */ private boolean isHistoryVisible = false; @@ -142,7 +147,10 @@ public class CallHistoryButton */ private void setHistoryView() { - isNotificationsView = false; + if (isNotificationsView) + isNotificationsView = false; + else + setIcon(null); if (isHistoryVisible) { @@ -167,7 +175,6 @@ public class CallHistoryButton { int notificationCount = 0; isNotificationsView = true; - this.setBgImage(null); Iterator<UINotificationGroup> groupsIter = notificationGroups.iterator(); @@ -204,7 +211,29 @@ public class CallHistoryButton 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 class CallHistoryButton 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 966a7a2..e8a5c2a 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 java.util.*; 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.*; 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.*; @@ -108,11 +106,6 @@ public class CallPanel /** * The hang up button name. */ - private static final String HANGUP_BUTTON = "HANGUP_BUTTON"; - - /** - * The hang up button name. - */ private static final String MERGE_BUTTON = "MERGE_BUTTON"; /** @@ -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 class CallPanel 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 class CallPanel callPeers.next().addCallPeerConferenceListener(this); // Initializes all buttons and common panels. - init(); + initToolBar(); initPluginComponents(); } @@ -353,15 +356,12 @@ public class CallPanel /** * 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 class CallPanel } }); - 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 class CallPanel 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 class CallPanel 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 class CallPanel */ 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 @@ public class CallPanel .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 f6a4656..543af5d 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 javax.swing.*; 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.*; /** @@ -27,30 +26,6 @@ import net.java.sip.communicator.util.swing.*; 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>. * * @param component the component to which we set the background @@ -87,24 +62,27 @@ public class CallPeerRendererUtils /** * 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 class CallPeerRendererUtils } /** - * 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 0000000..c63e631 --- /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 216bde8..714b0fc 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.*; @@ -24,19 +25,30 @@ public class FullScreenButton 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. * * @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 class FullScreenButton */ public void actionPerformed(ActionEvent evt) { - callContainer.getCurrentCallRenderer().enterFullScreen(); + if (isFullScreen) + callContainer.getCurrentCallRenderer().exitFullScreen(); + else + callContainer.getCurrentCallRenderer().enterFullScreen(); } }); } @@ -59,10 +74,13 @@ public class FullScreenButton */ 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 34032b3..6d1e861 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 @@ -34,17 +34,30 @@ 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 @@ public class FullScreenLayout 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 class FullScreenLayout * 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 0000000..645df75 --- /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 f318667..d161548 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 class InputVolumeControlButton 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 476d089..f3558bb 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 class OneToOneCallPanel // 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 class OneToOneCallPanel * * @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 @@ public class OneToOneCallPanel 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 7242a22..f60cafd 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 @@ public class OneToOneCallPeerPanel 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 class OneToOneCallPeerPanel 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 78a157d..13b6771 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 javax.swing.*; 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 @@ import org.jitsi.service.neomedia.*; * @author Damian Minkov */ public class OutputVolumeControlButton - extends SIPCommButton { /** * The background image. @@ -44,6 +44,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. */ public OutputVolumeControlButton() @@ -53,68 +63,122 @@ public class 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 class OutputVolumeControlButton = 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 127a193..6f31bec 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 java.util.*; 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 @@ import net.java.sip.communicator.util.swing.*; * @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 @@ public class TransferCallButton } 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 9f8d2f2..e6e19d0 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 @@ import org.jitsi.service.neomedia.event.*; * @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 class VolumeControlSlider 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 e25a9af..2191697 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 @@ public abstract class ChatConversationComponent */ 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 fba0eee..3ec57fa 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.*; 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.*; @@ -61,16 +61,6 @@ public class ChatConversationPanel = 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. @@ -339,32 +326,6 @@ public class ChatConversationPanel } /** - * 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. @@ -373,7 +334,11 @@ public class ChatConversationPanel 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); @@ -395,38 +360,6 @@ public class ChatConversationPanel } /** - * 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(" "); - 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 @@ -434,8 +367,20 @@ public class ChatConversationPanel * 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 class ChatConversationPanel { // for some reason ' is not rendered correctly from our ui, // lets use its equivalent. Other similar chars(< > & ") seem ok. - contactDisplayName = contactDisplayName.replaceAll("'", "'"); + contactDisplayName + = contactDisplayName.replaceAll("'", "'"); } - 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 @@ public class ChatConversationPanel else if (messageType.equals(Chat.ERROR_MESSAGE)) { chatString = "<h6 identifier=\"" - + msgHeaderID + + ChatHtmlUtils.MESSAGE_HEADER_ID + "\" date=\"" + date + "\">"; @@ -584,43 +518,6 @@ public class ChatConversationPanel + 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 @@ public class ChatConversationPanel * @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 class ChatConversationPanel { 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 class ChatConversationPanel { 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 class ChatConversationPanel 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 class ChatConversationPanel { if(isSmiley) { - msgBuff.append(endPlainTextTag); + msgBuff.append( + ChatHtmlUtils.createEndPlainTextTag( + contentType)); msgBuff.append("<IMG SRC=\""); } else @@ -858,7 +837,9 @@ public class ChatConversationPanel msgBuff.append("\"></IMG>"); if(isSmiley) - msgBuff.append(startPlainTextTag); + msgBuff.append( + ChatHtmlUtils.createStartPlainTextTag( + contentType)); } else { @@ -884,8 +865,12 @@ public class ChatConversationPanel 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 @@ public class ChatConversationPanel .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 @@ public class ChatConversationPanel // 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 @@ public class ChatConversationPanel 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 @@ public class ChatConversationPanel 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 @@ public class ChatConversationPanel { // 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 @@ public class ChatConversationPanel 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 @@ public class ChatConversationPanel * @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 @@ public class ChatConversationPanel 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 @@ public class ChatConversationPanel 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 @@ public class ChatConversationPanel * 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 @@ public class ChatConversationPanel message .replaceAll( "\n", - END_PLAINTEXT_TAG + "<BR/> " + START_PLAINTEXT_TAG); + ChatHtmlUtils.createEndPlainTextTag(contentType) + + "<BR/> " + + ChatHtmlUtils.createStartPlainTextTag(contentType)); } /** @@ -1508,7 +1486,8 @@ public class ChatConversationPanel 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 class ChatConversationPanel 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 { @@ -1620,26 +1602,6 @@ public class ChatConversationPanel } /** - * 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() @@ -1665,33 +1627,26 @@ public class ChatConversationPanel { 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 class ChatConversationPanel endHeaderTag = "</I></B>" + endDivTag; chatString += - processHTMLChars("*** " + chatMessage.getContactName() + " " + message.substring(4)) + endHeaderTag; @@ -1731,9 +1685,13 @@ public class ChatConversationPanel 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 class ChatConversationPanel 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 0000000..98293f3 --- /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(" "); + 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 9cf6f62..d39b7a0 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 class ChatPanel new String[]{evt.getSourceMember().getName(), getRoleDescription(evt.getNewRole())}) +"</DIV>", - ChatConversationPanel.HTML_CONTENT_TYPE); + ChatHtmlUtils.HTML_CONTENT_TYPE); } /** @@ -497,7 +495,7 @@ public class ChatPanel +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 @@ public class ChatPanel if (historyString != null) conversationPanel.appendMessageToEnd( - historyString, ChatConversationPanel.TEXT_CONTENT_TYPE); + historyString, ChatHtmlUtils.TEXT_CONTENT_TYPE); } fireChatHistoryChange(); @@ -839,6 +837,11 @@ public class ChatPanel 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 @@ public class ChatPanel 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 @@ public class ChatPanel 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 class ChatPanel public String getTextFromWriteArea(String mimeType) { if (mimeType.equals( - OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE)) + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE)) { return writeMessagePanel.getText(); } @@ -2062,7 +2070,7 @@ public class ChatPanel System.currentTimeMillis(), Chat.STATUS_MESSAGE, statusMessage, - ChatConversationPanel.TEXT_CONTENT_TYPE); + ChatHtmlUtils.TEXT_CONTENT_TYPE); } /** @@ -2094,7 +2102,7 @@ public class ChatPanel "service.gui.CHAT_ROOM_SUBJECT_CHANGED", new String []{ chatSession.getChatName(), subject}), - ChatConversationPanel.TEXT_CONTENT_TYPE); + ChatHtmlUtils.TEXT_CONTENT_TYPE); } } @@ -2461,8 +2469,6 @@ public class ChatPanel { int dividerLocation = messagePane.getHeight() - location; - autoDividerLocation = dividerLocation; - messagePane.setDividerLocation(dividerLocation); messagePane.revalidate(); messagePane.repaint(); @@ -2760,8 +2766,7 @@ public class ChatPanel + 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 12aeedd..fc6561b 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 7cdb61f..160515b 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.text.html.*; 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 @@ public class ChatWritePanel chatPanel.getChatConversationPanel() .appendMessageToEnd(contactList, - ChatConversationPanel.HTML_CONTENT_TYPE); + ChatHtmlUtils.HTML_CONTENT_TYPE); } else if(contacts.size() == 1) { @@ -963,7 +962,7 @@ public class ChatWritePanel 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 0000000..e6e5b4e --- /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 0000000..b64f287 --- /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 2c2b216..78dd4f7 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 @@ public class HistoryWindow 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 @@ public class HistoryWindow { MessageReceivedEvent evt = (MessageReceivedEvent) o; + protocolProvider + = evt.getSourceContact().getProtocolProvider(); + chatMessage = new ChatMessage( evt.getSourceContact().getAddress(), evt.getSourceContact().getDisplayName(), @@ -304,6 +308,9 @@ public class HistoryWindow ChatRoomMessageReceivedEvent evt = (ChatRoomMessageReceivedEvent) o; + protocolProvider + = evt.getSourceChatRoom().getParentProvider(); + chatMessage = new ChatMessage( evt.getSourceChatRoomMember().getName(), evt.getTimestamp(), Chat.INCOMING_MESSAGE, @@ -315,6 +322,9 @@ public class HistoryWindow ChatRoomMessageDeliveredEvent evt = (ChatRoomMessageDeliveredEvent) o; + protocolProvider + = evt.getSourceChatRoom().getParentProvider(); + chatMessage = new ChatMessage( evt.getSourceChatRoom().getParentProvider() .getAccountID().getUserID(), @@ -326,6 +336,9 @@ public class HistoryWindow { FileRecord fileRecord = (FileRecord) o; + protocolProvider + = fileRecord.getContact().getProtocolProvider(); + FileHistoryConversationComponent component = new FileHistoryConversationComponent( this, fileRecord); @@ -336,10 +349,13 @@ public class HistoryWindow 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 @@ public class HistoryWindow 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 c619a34..9393909 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 @@ public class ChatRightButtonMenu 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 class ChatRightButtonMenu 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 df0a7f5..f188fc0 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 @@ import net.java.sip.communicator.util.swing.*; /** * 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 14faa61..1c63daf 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.*; 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.gui.Container; 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.*; @@ -109,6 +106,13 @@ public class MainToolBar ImageLoader.getImage(ImageLoader.CHAT_CALL)); /** + * The call button. + */ + private final ChatToolbarButton callVideoButton + = new ChatToolbarButton( + ImageLoader.getImage(ImageLoader.CHAT_VIDEO_CALL)); + + /** * The options button. */ private final ChatToolbarButton optionsButton @@ -181,6 +185,7 @@ public class MainToolBar this.add(leaveChatRoomButton); this.add(callButton); +// this.add(callVideoButton); this.add(desktopSharingButton); this.add(sendFileButton); @@ -235,6 +240,11 @@ public class MainToolBar 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 @@ public class MainToolBar 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 class MainToolBar } } } - + callButton.setEnabled(hasTelephony || hasPhone); desktopSharingButton.setEnabled(!getOperationSetForCapabilities( chatPanel.chatSession.getTransportsForOperationSet( @@ -550,84 +561,13 @@ public class MainToolBar 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 class MainToolBar 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 09ad46f..d856041 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 class ContactListCellRenderer = 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 b6a5f75..ad6b3da 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.*; 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.*; @@ -74,6 +76,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. */ private static final int LEFT_BORDER = 5; @@ -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>. @@ -209,6 +228,11 @@ public class ContactListTreeCellRenderer private List<JButton> customActionButtons; /** + * The last added button. + */ + private SIPCommButton lastAddedButton; + + /** * Initializes the panel containing the node. */ public ContactListTreeCellRenderer() @@ -222,11 +246,11 @@ public class 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 class 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 class ContactListTreeCellRenderer 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 @@ public class ContactListTreeCellRenderer if (preferredHeight > 0) preferredSize.height = preferredHeight; else - preferredSize.height = 18; + preferredSize.height = 20; } return preferredSize; @@ -639,8 +667,6 @@ public class ContactListTreeCellRenderer 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 @@ public class ContactListTreeCellRenderer 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 @@ public class ContactListTreeCellRenderer 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 @@ public class ContactListTreeCellRenderer 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 @@ public class ContactListTreeCellRenderer || 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 @@ public class ContactListTreeCellRenderer 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 @@ public class ContactListTreeCellRenderer 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 @@ public class ContactListTreeCellRenderer 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 @@ public class ContactListTreeCellRenderer 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); } } @@ -1039,6 +972,15 @@ public class ContactListTreeCellRenderer * 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 + */ public JButton getCallButton() { return callButton; @@ -1365,7 +1307,9 @@ public class ContactListTreeCellRenderer else if (desktopContacts.size() > 1) { chooseAccountDialog - = new ChooseCallAccountPopupMenu(treeContactList, desktopContacts, + = new ChooseCallAccountPopupMenu( + treeContactList, + desktopContacts, OperationSetDesktopSharingServer.class); } @@ -1378,7 +1322,8 @@ public class ContactListTreeCellRenderer 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 class ContactListTreeCellRenderer 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 class ContactListTreeCellRenderer 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 class ContactListTreeCellRenderer 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 class ContactListTreeCellRenderer } } } + + 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 f703aaa..37d8c9a 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 @@ public class TreeContactList /** * 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 @@ public class TreeContactList 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 @@ public class TreeContactList 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 @@ public class TreeContactList 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 a49d02a..4aa50c8 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 class AccountStatusPanel */ public void registrationStateChanged(RegistrationStateChangeEvent evt) { - ProtocolProviderService protocolProvider = evt.getProvider(); + final ProtocolProviderService protocolProvider = evt.getProvider(); this.updateStatus(protocolProvider); @@ -379,16 +379,30 @@ public class AccountStatusPanel { 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 class AccountStatusPanel 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 e589bd4..63c21f7 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java +++ b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java @@ -196,12 +196,6 @@ public class ImageLoader = 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. */ public static final ImageID DOWN_ARROW_ICON @@ -276,6 +270,40 @@ public class ImageLoader = 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. */ public static final ImageID CALL_BUTTON_SMALL @@ -344,12 +372,24 @@ public class ImageLoader = 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. */ public static final ImageID CHAT_DESKTOP_SHARING @@ -368,6 +408,12 @@ public class ImageLoader = 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. */ public static final ImageID CHAT_BUTTON_SMALL_PRESSED @@ -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 class ImageLoader 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 0000000..37dcac1 --- /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 a106bde..aad1825 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 @@ public class GuiUtils 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 002dcde..dd5933d 100644 --- a/src/net/java/sip/communicator/util/ImageUtils.java +++ b/src/net/java/sip/communicator/util/ImageUtils.java @@ -168,7 +168,7 @@ public class ImageUtils 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 e4f523b..78d6c5e 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.netaddr.*; 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; /** @@ -239,6 +242,23 @@ public class UtilActivator } /** + * 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 9cc9367..ebc358e 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 @@ public class OrderedTransparentPanel 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 cbdea52..db40d4d 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 @@ public class SIPCommButton 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 14b130e..eb6fe7c 100644 --- a/src/net/java/sip/communicator/util/swing/SIPCommTextButton.java +++ b/src/net/java/sip/communicator/util/swing/SIPCommTextButton.java @@ -92,6 +92,16 @@ public class SIPCommTextButton extends JButton } /** + * 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 * configurable button. diff --git a/src/net/java/sip/communicator/util/swing/SIPCommToggleButton.java b/src/net/java/sip/communicator/util/swing/SIPCommToggleButton.java index 6a1ca46..a18e207 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 @@ public class SIPCommToggleButton } } + 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 92b65dd..4e81bc9 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 @@ public class SoundLevelIndicator 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 class SoundLevelIndicator } 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 class SoundLevelIndicator */ private int getSoundBarCount(int width) { - int soundBarWidth = soundLevelActiveImage.getIconWidth(); + int soundBarWidth = soundLevelActiveImageLeft.getIconWidth(); return width / soundBarWidth; } @@ -218,28 +302,43 @@ public class SoundLevelIndicator { 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 554119b..93f7c6c 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 @@ public class SIPCommTabbedPaneUI 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 @@ public class SIPCommTabbedPaneUI 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 @@ public class SIPCommTabbedPaneUI 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 5b68197..1b1a643 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 @@ public class SIPCommTextFieldUI if(isRounded) { g2.fillRoundRect(1, 1, c.getWidth() - 1, c.getHeight() - 1, - 20, 20); + 8, 8); } else { @@ -225,8 +225,8 @@ public class SIPCommTextFieldUI 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 64557f4..7e08cd4 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, |