diff options
author | Yana Stamcheva <yana@jitsi.org> | 2012-04-04 12:13:03 +0000 |
---|---|---|
committer | Yana Stamcheva <yana@jitsi.org> | 2012-04-04 12:13:03 +0000 |
commit | f9a8da4458d7f9d10a415d0605bc809860dc20ad (patch) | |
tree | 5b9f0ede3f5af9eb1672a6d9f71e00e29677cc38 | |
parent | f26b85ff9ed73e950c454fb855e9a2b1f4201333 (diff) | |
download | jitsi-f9a8da4458d7f9d10a415d0605bc809860dc20ad.zip jitsi-f9a8da4458d7f9d10a415d0605bc809860dc20ad.tar.gz jitsi-f9a8da4458d7f9d10a415d0605bc809860dc20ad.tar.bz2 |
Adds new improved security interface.
22 files changed, 1579 insertions, 484 deletions
diff --git a/resources/colors/colors.properties b/resources/colors/colors.properties index c8b6f44..54e6e9c 100644 --- a/resources/colors/colors.properties +++ b/resources/colors/colors.properties @@ -203,4 +203,13 @@ service.gui.SEARCH_BORDER_GRADIENT=ACACAC service.gui.SEARCH_FOREGROUND=000000 # The default text foreground of the search field -service.gui.SEARCH_DEFAULT_FOREGROUND=ACACAC
\ No newline at end of file +service.gui.SEARCH_DEFAULT_FOREGROUND=ACACAC + +# The security on status color. +service.gui.SECURITY_ON=6FC93C + +# The security off status color. +service.gui.SECURITY_OFF=ED0000 + +# Going secure status color. +service.gui.GOING_SECURE=FFC01B
\ No newline at end of file diff --git a/resources/config/defaults.properties b/resources/config/defaults.properties index 8b285b5..51ea8c0 100644 --- a/resources/config/defaults.properties +++ b/resources/config/defaults.properties @@ -89,3 +89,5 @@ net.java.sip.communicator.util.dns.DS_ROOT.1=. IN DS 19036 8 2 49AAC11D7B6F64467 plugin.jabberaccregwizz.NEW_ACCOUNT_DEFAULT_SERVER=jit.si net.java.sip.communicator.service.neomedia.SDES_CIPHER_SUITES=AES_CM_128_HMAC_SHA1_80,AES_CM_128_HMAC_SHA1_32 + +impl.gui.PARANOIA_UI=false
\ No newline at end of file diff --git a/resources/images/impl/gui/buttons/encrypted_verified.png b/resources/images/impl/gui/buttons/encrypted_verified.png Binary files differindex d5ba163..c9fd25f 100755 --- a/resources/images/impl/gui/buttons/encrypted_verified.png +++ b/resources/images/impl/gui/buttons/encrypted_verified.png diff --git a/resources/images/impl/gui/buttons/goingSecureAudio.png b/resources/images/impl/gui/buttons/goingSecureAudio.png Binary files differnew file mode 100644 index 0000000..6e019bb --- /dev/null +++ b/resources/images/impl/gui/buttons/goingSecureAudio.png diff --git a/resources/images/impl/gui/buttons/goingSecureVideo.png b/resources/images/impl/gui/buttons/goingSecureVideo.png Binary files differnew file mode 100644 index 0000000..9e610a6 --- /dev/null +++ b/resources/images/impl/gui/buttons/goingSecureVideo.png diff --git a/resources/images/impl/gui/buttons/secureAudioOff.png b/resources/images/impl/gui/buttons/secureAudioOff.png Binary files differindex 201e782..d32800c 100644 --- a/resources/images/impl/gui/buttons/secureAudioOff.png +++ b/resources/images/impl/gui/buttons/secureAudioOff.png diff --git a/resources/images/impl/gui/buttons/secureAudioOn.png b/resources/images/impl/gui/buttons/secureAudioOn.png Binary files differindex 7bbbb51..c408c4f 100644 --- a/resources/images/impl/gui/buttons/secureAudioOn.png +++ b/resources/images/impl/gui/buttons/secureAudioOn.png diff --git a/resources/images/impl/gui/buttons/secureVideoOff.png b/resources/images/impl/gui/buttons/secureVideoOff.png Binary files differindex 546aaad..d4d144b 100644 --- a/resources/images/impl/gui/buttons/secureVideoOff.png +++ b/resources/images/impl/gui/buttons/secureVideoOff.png diff --git a/resources/images/impl/gui/buttons/secureVideoOn.png b/resources/images/impl/gui/buttons/secureVideoOn.png Binary files differindex 489784b..4f020a6 100644 --- a/resources/images/impl/gui/buttons/secureVideoOn.png +++ b/resources/images/impl/gui/buttons/secureVideoOn.png diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties index 80f467c..934f590 100644 --- a/resources/languages/resources.properties +++ b/resources/languages/resources.properties @@ -120,12 +120,11 @@ service.gui.CHAT_ROOM_SUBJECT_CHANGED={0} has changed the subject to {1} service.gui.CHOOSE_CONTACT=Choose contact
service.gui.CHOOSE_ACCOUNT=Please select one of the listed accounts.
service.gui.SHOW_MORE_TOOLTIP=Click to show more results
+servoce.gui.CLEAR=Clear
service.gui.CLOSE=Cl&ose
service.gui.CLOSE_CHAT_AFTER_NEW_MESSAGE=You have received a new message less than 2 seconds ago. Are you sure you want to close this chat?
service.gui.CLOSE_CHAT_ACTIVE_FILE_TRANSFER=You have active file transfers. Are you sure you want to cancel them?
-service.gui.COMPARE_WITH_PARTNER=Compare with partner and click the padlock to confirm.
-# keep the following string short
-service.gui.COMPARE_WITH_PARTNER_SHORT=Compare with partner: {0}
+servoce.gui.CONFIRM=Confirm
service.gui.CONNECTED_STATUS=Connected
service.gui.CONNECTING=Connecting...
service.gui.CONNECTING_STATUS=Connecting
@@ -611,6 +610,29 @@ service.gui.AUTO_ANSWER_DESCR_VLUE=leave empty for any service.gui.AUTO_ANSWER_FWD_CALLS=Forward Calls
service.gui.AUTO_ANSWER_FWD_CALLS_TO=Forward all calls to the following number or URI:
+service.gui.security.SECURE_AUDIO=Secure audio
+service.gui.security.AUDIO_NOT_SECURED=Audio not secured
+service.gui.security.SECURE_VIDEO=Secure video
+service.gui.security.VIDEO_NOT_SECURED=Video not secured
+service.gui.security.NO_VIDEO=No video
+service.gui.security.CIPHER=Cipher: {0}
+service.gui.security.CALL_SECURED_TOOLTIP=Call secured. Fore more information press here.
+service.gui.security.CALL_NOT_SECURED_TOOLTIP=Call not secured. Fore more information press here.
+service.gui.security.CALL_SECURED_COMPARE_TOOLTIP=Press here to compare security secret with your partner.
+service.gui.security.COMPARE_WITH_PARTNER=Compare with partner and click the padlock to confirm.
+# keep the following string short
+service.gui.security.COMPARE_WITH_PARTNER_SHORT=Compare with partner:
+service.gui.security.STRING_COMPARED=String compared!
+service.gui.security.SAS_INFO_TOOLTIP=\
+<html>In order to be completely secured you<br/>\
+need to verbally <b>compare</b> the short<br/>\
+authentication string here left with your<br/>\
+partner and press the confirm button when the <br/>\
+string is verified.<br/><br/\
+If you clear the confirmation, you'll be asked to verify<br/>\
+next time when you call this partner.</html>
+service.gui.security.SECURITY_ALERT=Trying to secure call. Will disconnect in
+
service.gui.avatar.CHOOSE_ICON=Choose picture
service.gui.avatar.REMOVE_ICON=Remove current picture
service.gui.avatar.CLEAR_RECENT=Clear recent pictures
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallPeerAdapter.java b/src/net/java/sip/communicator/impl/gui/main/call/CallPeerAdapter.java index 6be7282..537e4ed 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallPeerAdapter.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallPeerAdapter.java @@ -104,7 +104,7 @@ public class CallPeerAdapter renderer.getCallPanel().updateHoldButtonState(); } - renderer.setPeerState(newStateString); + renderer.setPeerState(newState, newStateString); String reasonString = evt.getReasonString(); if (reasonString != null) diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRenderer.java b/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRenderer.java index d915536..ee2afd6 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRenderer.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallPeerRenderer.java @@ -8,6 +8,7 @@ package net.java.sip.communicator.impl.gui.main.call; import java.awt.*; +import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; /** @@ -37,9 +38,10 @@ public interface CallPeerRenderer * Sets the state of the contained call peer by specifying the * state name. * + * @param peerState the peer state * @param state the state of the contained call peer */ - public void setPeerState(String state); + public void setPeerState(CallPeerState peerState, String state); /** * Sets the reason of a call failure if one occurs. The renderer should @@ -78,6 +80,11 @@ public interface CallPeerRenderer public void securityOff(CallPeerSecurityOffEvent evt); /** + * Indicates that the security status is pending confirmation. + */ + public void securityPending(); + + /** * Indicates that the security is timeouted, is not supported by the * other end. * @param evt Details about the event that caused this message. @@ -148,4 +155,12 @@ public interface CallPeerRenderer * @return the video handler associated with this call peer renderer */ public UIVideoHandler getVideoHandler(); + + /** + * Shows/hides the security panel. + * + * @param isVisible <tt>true</tt> to show the security panel, <tt>false</tt> + * to hide it + */ + public void setSecurityPanelVisible(boolean isVisible); } 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 3082178..2fb7267 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 @@ -14,9 +14,11 @@ import java.util.List; // disambiguation import javax.swing.*; import javax.swing.text.*; +import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.main.call.conference.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.service.resources.*; @@ -65,7 +67,7 @@ public class OneToOneCallPeerPanel /** * The security status of the peer */ - private SecurityStatusLabel securityStatusLabel; + private SecurityStatusLabel securityStatusLabel = new SecurityStatusLabel(); /** * The label showing whether the voice has been set to mute. @@ -199,6 +201,7 @@ public class OneToOneCallPeerPanel this.callPeer = callPeer; this.peerName = callPeer.getDisplayName(); this.videoContainers = videoContainers; + this.securityPanel = SecurityPanel.create(this, callPeer, null); if (vHandler == null) videoHandler @@ -212,11 +215,6 @@ public class OneToOneCallPeerPanel videoHandler.addVideoListener(); videoHandler.addRemoteControlListener(); - securityStatusLabel = new SecurityStatusLabel( - callRenderer.getCallContainer().getCallWindow().getFrame(), - new ImageIcon( - ImageLoader.getImage(ImageLoader.SECURE_BUTTON_OFF))); - photoLabel = new JLabel(getPhotoLabelIcon()); center = createCenter(videoContainers); statusBar = createStatusBar(); @@ -382,6 +380,8 @@ public class OneToOneCallPeerPanel statusPanel.add(muteStatusLabel, constraints); constraints.gridx++; + callStatusLabel.setBorder( + BorderFactory.createEmptyBorder(2, 3, 2, 5)); statusPanel.add(callStatusLabel, constraints); constraints.gridx++; @@ -509,7 +509,6 @@ public class OneToOneCallPeerPanel public PeerStatusPanel(LayoutManager layout) { super(layout); - this.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5)); } /** @@ -600,11 +599,25 @@ public class OneToOneCallPeerPanel * Sets the state of the contained call peer by specifying the * state name and icon. * + * @param peerState the peer state * @param state the state of the contained call peer */ - public void setPeerState(String state) + public void setPeerState(CallPeerState peerState, String state) { this.callStatusLabel.setText(state); + + if (peerState == CallPeerState.CONNECTED) + { + initSecurityStatusLabel(); + + if(Boolean.parseBoolean(GuiActivator.getResources() + .getSettingsString("impl.gui.PARANOIA_UI"))) + { + securityPanel = new ParanoiaTimerSecurityPanel(); + + setSecurityPanelVisible(true); + } + } } /** @@ -616,10 +629,18 @@ public class OneToOneCallPeerPanel public void setMute(boolean isMute) { if(isMute) + { muteStatusLabel.setIcon(new ImageIcon( ImageLoader.getImage(ImageLoader.MUTE_STATUS_ICON))); + muteStatusLabel.setBorder( + BorderFactory.createEmptyBorder(2, 3, 2, 3)); + } else + { muteStatusLabel.setIcon(null); + muteStatusLabel.setBorder( + BorderFactory.createEmptyBorder(0, 0, 0, 0)); + } this.revalidate(); this.repaint(); @@ -632,10 +653,18 @@ public class OneToOneCallPeerPanel public void setOnHold(boolean isOnHold) { if(isOnHold) + { holdStatusLabel.setIcon(new ImageIcon( ImageLoader.getImage(ImageLoader.HOLD_STATUS_ICON))); + holdStatusLabel.setBorder( + BorderFactory.createEmptyBorder(2, 3, 2, 3)); + } else + { holdStatusLabel.setIcon(null); + holdStatusLabel.setBorder( + BorderFactory.createEmptyBorder(0, 0, 0, 0)); + } this.revalidate(); this.repaint(); @@ -650,43 +679,48 @@ public class OneToOneCallPeerPanel */ public void securityOn(CallPeerSecurityOnEvent evt) { - if((evt.getSecurityController().requiresSecureSignalingTransport() - && callPeer.getProtocolProvider().isSignalingTransportSecure()) - || !evt.getSecurityController().requiresSecureSignalingTransport()) + // If the securityOn is called without a specific event, we'll just set + // the security label status to on. + if (evt == null) { - securityImageID = ImageLoader.SECURE_BUTTON_ON; - securityStatusLabel.setIcon(new ImageIcon(ImageLoader - .getImage(securityImageID))); + securityStatusLabel.setSecurityOn(); + return; } - //set common encryption properties - securityStatusLabel.setEncryptionCipher(evt.getCipher()); - switch (evt.getSessionType()) + SrtpControl srtpControl = evt.getSecurityController(); + + if ((srtpControl.requiresSecureSignalingTransport() + && callPeer.getProtocolProvider().isSignalingTransportSecure()) + || !srtpControl.requiresSecureSignalingTransport()) { - case CallPeerSecurityStatusEvent.AUDIO_SESSION: - securityStatusLabel.setAudioSecurityOn(true); - break; - case CallPeerSecurityStatusEvent.VIDEO_SESSION: - securityStatusLabel.setVideoSecurityOn(true); - break; + if (srtpControl instanceof ZrtpControl) + { + securityStatusLabel.setText("zrtp"); + + if (!((ZrtpControl) srtpControl).isSecurityVerified()) + securityStatusLabel.setSecurityPending(); + else + securityStatusLabel.setSecurityOn(); + } + else + securityStatusLabel.setSecurityOn(); } - //set encryption specific options - if (securityPanel == null) + // if we have some other panel, using other control + if(!srtpControl.getClass().isInstance( + securityPanel.getSecurityControl())) { - securityPanel = SecurityPanel.create(evt.getSecurityController()); - - GridBagConstraints constraints = new GridBagConstraints(); + setSecurityPanelVisible(false); - constraints.fill = GridBagConstraints.NONE; - constraints.gridx = 0; - constraints.gridy = 2; - constraints.weightx = 0; - constraints.weighty = 0; - constraints.insets = new Insets(5, 0, 0, 0); - this.add(securityPanel, constraints); + securityPanel + = SecurityPanel.create(this, callPeer, srtpControl); } - securityPanel.refreshStates(); + + securityPanel.securityOn(evt); + + if (srtpControl instanceof ZrtpControl + && !((ZrtpControl) srtpControl).isSecurityVerified()) + setSecurityPanelVisible(true); this.revalidate(); } @@ -696,27 +730,21 @@ public class OneToOneCallPeerPanel */ public void securityOff(CallPeerSecurityOffEvent evt) { - securityImageID = ImageLoader.SECURE_BUTTON_OFF; - securityStatusLabel.setIcon(new ImageIcon(ImageLoader - .getImage(securityImageID))); + securityStatusLabel.setText(""); + securityStatusLabel.setSecurityOff(); + if (securityStatusLabel.getBorder() == null) + securityStatusLabel.setBorder( + BorderFactory.createEmptyBorder(2, 5, 2, 3)); - switch (evt.getSessionType()) - { - case CallPeerSecurityStatusEvent.AUDIO_SESSION: - securityStatusLabel.setAudioSecurityOn(false); - break; - case CallPeerSecurityStatusEvent.VIDEO_SESSION: - securityStatusLabel.setVideoSecurityOn(false); - break; - } + securityPanel.securityOff(evt); + } - if (securityPanel != null - && !securityStatusLabel.isAudioSecurityOn() - && !securityStatusLabel.isVideoSecurityOn()) - { - securityPanel.getParent().remove(securityPanel); - securityPanel = null; - } + /** + * Indicates that the security status is pending confirmation. + */ + public void securityPending() + { + securityStatusLabel.setSecurityPending(); } /** @@ -726,7 +754,8 @@ public class OneToOneCallPeerPanel */ public void securityTimeout(CallPeerSecurityTimeoutEvent evt) { - + if (securityPanel != null) + securityPanel.securityTimeout(evt); } /** @@ -763,6 +792,9 @@ public class OneToOneCallPeerPanel public void printDTMFTone(char dtmfChar) { dtmfLabel.setText(dtmfLabel.getText() + dtmfChar); + if (dtmfLabel.getBorder() == null) + dtmfLabel.setBorder( + BorderFactory.createEmptyBorder(2, 1, 2, 5)); } /** @@ -1042,175 +1074,6 @@ public class OneToOneCallPeerPanel } /** - * The Mouse listener for local video. It is responsible for dragging local - * video. - */ -// private class LocalVideoMouseListener -// implements MouseListener, -// MouseMotionListener -// { -// /** -// * Indicates if we're currently during a drag operation. -// */ -// private boolean inDrag = false; -// -// /** -// * The previous x coordinate of the drag. -// */ -// private int previousX = 0; -// -// /** -// * The previous y coordinate of the drag. -// */ -// private int previousY = 0; -// -// /** -// * Indicates that the mouse has been dragged. -// * -// * @param event the <tt>MouseEvent</tt> that notified us -// */ -// public void mouseDragged(MouseEvent event) -// { -// Point p = event.getPoint(); -// -// if (inDrag) -// { -// Component c = (Component) event.getSource(); -// -// int newX = c.getX() + p.x - previousX; -// int newY = c.getY() + p.y - previousY; -// -// Component remoteContainer; -// if (remoteVideo != null) -// remoteContainer = remoteVideo; -// else -// synchronized (videoContainers) -// { -// // If there's no remote video we limit the drag to the -// // parent video container. -// if (videoContainers != null -// && videoContainers.size() > 0) -// remoteContainer = videoContainers.get( -// videoContainers.size() - 1); -// else -// // In the case no video container is available -// // we just limit the drag to this panel. -// remoteContainer = OneToOneCallPeerPanel.this; -// } -// -// int minX = remoteContainer.getX(); -// int maxX = remoteContainer.getX() + remoteContainer.getWidth(); -// int minY = remoteContainer.getY(); -// int maxY = remoteContainer.getY() + remoteContainer.getHeight(); -// -// if (newX < minX) -// newX = minX; -// -// if (newX + c.getWidth() > maxX) -// newX = maxX - c.getWidth(); -// -// if (newY < minY) -// newY = minY; -// -// if (newY + c.getHeight() > maxY) -// newY = maxY - c.getHeight(); -// -// c.setLocation(newX, newY); -// if (closeButton.isVisible()) -// closeButton.setVisible(false); -// } -// } -// -// public void mouseMoved(MouseEvent event) {} -// -// public void mouseClicked(MouseEvent event) {} -// -// public void mouseEntered(MouseEvent event) {} -// -// public void mouseExited(MouseEvent event) {} -// -// /** -// * Indicates that the mouse has been pressed. -// * -// * @param event the <tt>MouseEvent</tt> that notified us -// */ -// public void mousePressed(MouseEvent event) -// { -// Point p = event.getPoint(); -// -// previousX = p.x; -// previousY = p.y; -// inDrag = true; -// } -// -// /** -// * Indicates that the mouse has been released. -// * -// * @param event the <tt>MouseEvent</tt> that notified us -// */ -// public void mouseReleased(MouseEvent event) -// { -// inDrag = false; -// previousX = 0; -// previousY = 0; -// -// if (!closeButton.isVisible()) -// { -// Component c = (Component) event.getSource(); -// closeButton.setLocation( -// c.getX() + c.getWidth() - closeButton.getWidth() - 3, -// c.getY() + 3); -// closeButton.setVisible(true); -// } -// } -// } - -// private class CloseButton -// extends Label -// implements MouseListener -// { -// private static final long serialVersionUID = 0L; -// -// Image image = ImageLoader.getImage(ImageLoader.CLOSE_VIDEO); -// -// public CloseButton() -// { -// int buttonWidth = image.getWidth(this) + 5; -// int buttonHeight = image.getHeight(this) + 5; -// -// setPreferredSize(new Dimension(buttonWidth, buttonHeight)); -// setSize(new Dimension(buttonWidth, buttonHeight)); -// -// this.addMouseListener(this); -// } -// -// public void paint(Graphics g) -// { -// g.setColor(Color.GRAY); -// g.fillRect(0, 0, getWidth(), getHeight()); -// g.drawImage(image, -// getWidth()/2 - image.getWidth(this)/2, -// getHeight()/2 - image.getHeight(this)/2, this); -// } -// -// public void mouseClicked(MouseEvent event) -// { -// setLocalVideoVisible(false); -// -// callRenderer.getCallContainer() -// .setShowHideVideoButtonSelected(false); -// } -// -// public void mouseEntered(MouseEvent event) {} -// -// public void mouseExited(MouseEvent event) {} -// -// public void mousePressed(MouseEvent event) {} -// -// public void mouseReleased(MouseEvent event) {} -// } - - /** * Reloads all icons. */ public void loadSkin() @@ -1254,63 +1117,6 @@ public class OneToOneCallPeerPanel public void setLocalVideoVisible(boolean isVisible) { videoHandler.setLocalVideoVisible(isVisible); -// synchronized (videoContainers) -// { -// this.localVideoVisible = isVisible; -// -// if (isVisible -// != callRenderer.getCallContainer() -// .isShowHideVideoButtonSelected()) -// { -// callRenderer.getCallContainer() -// .setShowHideVideoButtonSelected(isVisible); -// } -// -// int videoContainerCount; -// -// if ((videoTelephony != null) -// && ((videoContainerCount = videoContainers.size()) > 0)) -// { -// Container videoContainer -// = videoContainers.get(videoContainerCount - 1); -// -// if (localVideo != null) -// { -// if (isVisible) -// { -// Container localVideoParent = localVideo.getParent(); -// -// if (localVideoParent != null) -// localVideoParent.remove(localVideo); -// -// Container closeButtonParent -// = closeButton.getParent(); -// -// if (closeButtonParent != null) -// closeButtonParent.remove(closeButton); -// -// videoContainer.add(localVideo, VideoLayout.LOCAL, 0); -// videoContainer.add( -// closeButton, -// VideoLayout.CLOSE_LOCAL_BUTTON, -// 0); -// } -// else -// { -// videoContainer.remove(localVideo); -// videoContainer.remove(closeButton); -// } -// -// /* -// * Just like #handleVideoEvent(VideoEvent, Container) says, -// * we have to be explicit in order to achieve a proper -// * layout and an up-to-date painting. -// */ -// videoContainer.validate(); -// videoContainer.repaint(); -// } -// } -// } } /** @@ -1353,4 +1159,174 @@ public class OneToOneCallPeerPanel { return videoHandler; } + + /** + * Initializes the security status label, shown in the call status bar. + */ + private void initSecurityStatusLabel() + { + securityStatusLabel.setBorder( + BorderFactory.createEmptyBorder(2, 5, 2, 5)); + + securityStatusLabel.setSecurityOff(); + + securityStatusLabel.addMouseListener(new MouseAdapter() + { + /** + * Invoked when a mouse button has been pressed on a component. + */ + public void mousePressed(MouseEvent e) + { + // Only show the security details if the security is on. + if (callPeer.getCurrentSecuritySettings() + instanceof CallPeerSecurityOnEvent) + { + setSecurityPanelVisible(!callRenderer.getCallContainer() + .getCallWindow().getFrame().getGlassPane().isVisible()); + } + } + }); + } + + /** + * Shows/hides the security panel. + * + * @param isVisible <tt>true</tt> to show the security panel, <tt>false</tt> + * to hide it + */ + public void setSecurityPanelVisible(boolean isVisible) + { + final JFrame callFrame = callRenderer.getCallContainer() + .getCallWindow().getFrame(); + + final JPanel glassPane = (JPanel) callFrame.getGlassPane(); + + if (!isVisible) + { + // Need to hide the security panel explicitly in order to keep the + // fade effect. + securityPanel.setVisible(false); + glassPane.setVisible(false); + glassPane.removeAll(); + } + else + { + glassPane.setLayout(null); + glassPane.addMouseListener(new MouseListener() + { + public void mouseReleased(MouseEvent e) + { + redispatchMouseEvent(glassPane, e); + } + + public void mousePressed(MouseEvent e) + { + redispatchMouseEvent(glassPane, e); + } + + public void mouseExited(MouseEvent e) + { + redispatchMouseEvent(glassPane, e); + } + + public void mouseEntered(MouseEvent e) + { + redispatchMouseEvent(glassPane, e); + } + + public void mouseClicked(MouseEvent e) + { + redispatchMouseEvent(glassPane, e); + } + }); + + Point securityLabelPoint = securityStatusLabel.getLocation(); + + Point newPoint + = SwingUtilities.convertPoint(securityStatusLabel.getParent(), + securityLabelPoint.x, securityLabelPoint.y, + callFrame); + + securityPanel.setBeginPoint( + new Point((int) newPoint.getX() + 15, 0)); + securityPanel.setBounds( + 0, (int) newPoint.getY() - 5, callFrame.getWidth(), 110); + + glassPane.add(securityPanel); + // Need to show the security panel explicitly in order to keep the + // fade effect. + securityPanel.setVisible(true); + glassPane.setVisible(true); + + glassPane.addComponentListener(new ComponentAdapter() + { + /** + * Invoked when the component's size changes. + */ + public void componentResized(ComponentEvent e) + { + if (glassPane.isVisible()) + { + glassPane.setVisible(false); + callFrame.removeComponentListener(this); + } + } + }); + } + } + + /** + * Re-dispatches glass pane mouse events only in case they occur on the + * security panel. + * + * @param glassPane the glass pane + * @param e the mouse event in question + */ + private void redispatchMouseEvent(Component glassPane, MouseEvent e) + { + Point glassPanePoint = e.getPoint(); + + Point securityPanelPoint = SwingUtilities.convertPoint( + glassPane, + glassPanePoint, + securityPanel); + + Component component; + Point componentPoint; + + if (securityPanelPoint.y > 0) + { + component = securityPanel; + componentPoint = securityPanelPoint; + } + else + { + Container contentPane + = callRenderer.getCallContainer().getCallWindow() + .getFrame().getContentPane(); + + Point containerPoint = SwingUtilities.convertPoint( + glassPane, + glassPanePoint, + contentPane); + + component = SwingUtilities.getDeepestComponentAt(contentPane, + containerPoint.x, containerPoint.y); + + componentPoint = SwingUtilities.convertPoint(contentPane, + glassPanePoint, component); + } + + if (component != null) + component.dispatchEvent(new MouseEvent( component, + e.getID(), + e.getWhen(), + e.getModifiers(), + componentPoint.x, + componentPoint.y, + e.getClickCount(), + e.isPopupTrigger())); + + e.consume(); + } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/ParanoiaTimerSecurityPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/ParanoiaTimerSecurityPanel.java new file mode 100644 index 0000000..3efee42 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/call/ParanoiaTimerSecurityPanel.java @@ -0,0 +1,142 @@ +/* + * 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 net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.service.neomedia.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; + +import javax.swing.*; +import java.awt.*; +import java.text.*; +import java.util.*; +import java.util.Timer; + +/** + * @author Damian Minkov + * @author Yana Stamcheva + */ +public class ParanoiaTimerSecurityPanel + extends SecurityPanel<SrtpControl> +{ + /** + * The security timer. + */ + private Timer timer = new Timer(true); + + /** + * Creates an instance of this <tt>ParanoiaTimerSecurityPanel</tt>. + */ + ParanoiaTimerSecurityPanel() + { + super(null); + + initComponents(); + } + + /** + * Initializes contained components. + */ + private void initComponents() + { + final SimpleDateFormat format = new SimpleDateFormat("mm:ss"); + final Calendar c = Calendar.getInstance(); + final JLabel counter = new JLabel(); + + counter.setForeground(Color.red); + counter.setFont(counter.getFont().deriveFont( + (float)(counter.getFont().getSize() + 5))); + + setLayout(new GridBagLayout()); + setBorder( + BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + GridBagConstraints constraints = new GridBagConstraints(); + + JLabel messageLabel = new JLabel(GuiActivator.getResources() + .getI18NString("service.gui.security.SECURITY_ALERT")); + + messageLabel.setForeground(Color.WHITE); + + constraints.anchor = GridBagConstraints.CENTER; + constraints.fill = GridBagConstraints.NONE; + constraints.gridx = 0; + constraints.gridy = 0; + add(messageLabel, constraints); + + constraints.anchor = GridBagConstraints.CENTER; + constraints.fill = GridBagConstraints.NONE; + constraints.gridx = 0; + constraints.gridy = 1; + add(counter, constraints); + + ZrtpControl zrtpControl = null; + if (securityControl instanceof ZrtpControl) + zrtpControl = (ZrtpControl) securityControl; + + int initialSeconds = 0; + + if (zrtpControl != null) + initialSeconds = (int) zrtpControl.getTimeoutValue()/1000; + + c.set(Calendar.HOUR, 0); + c.set(Calendar.MINUTE, 0); + c.set(Calendar.SECOND, initialSeconds); + + counter.setText(format.format(c.getTime())); + + if (initialSeconds > 0) + timer.schedule(new TimerTask() + { + @Override + public void run() + { + c.add(Calendar.SECOND, -1); + counter.setText(format.format(c.getTime())); + } + }, 0, 1000); + } + + /** + * Cancels the security timer. + * + * @param evt the security event of which we're notified + */ + public void securityOn(CallPeerSecurityOnEvent evt) + { + timer.cancel(); + } + + /** + * Nothing to do here. + * + * @param evt the security event of which we're notified + */ + public void securityOff(CallPeerSecurityOffEvent evt) {} + + /** + * Indicates that the security is time-outed, is not supported by the + * other end. + * @param evt Details about the event that caused this message. + */ + public void securityTimeout(CallPeerSecurityTimeoutEvent evt) + { + timer.cancel(); + + // fail peer, call + if(evt.getSource() instanceof AbstractCallPeer) + { + AbstractCallPeer peer = (AbstractCallPeer)evt.getSource(); + peer.setState(CallPeerState.FAILED, "Encryption Required!"); + } + } + + public void loadSkin() + { + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/SecurityPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/SecurityPanel.java index 32ca281..202c150 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/SecurityPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/SecurityPanel.java @@ -7,6 +7,8 @@ package net.java.sip.communicator.impl.gui.main.call;
import net.java.sip.communicator.service.neomedia.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.skin.*;
import net.java.sip.communicator.util.swing.*;
@@ -15,11 +17,43 @@ import net.java.sip.communicator.util.swing.*; *
* @author Ingo Bauersachs
*/
-public abstract class SecurityPanel
- extends TransparentPanel
+public abstract class SecurityPanel<T extends SrtpControl>
+ extends FadeInBalloonPanel
implements Skinnable
{
/**
+ * The currently used security control.
+ */
+ protected T securityControl;
+
+ /**
+ * Create security panel using the security control.
+ * @param securityControl
+ */
+ public SecurityPanel(T securityControl)
+ {
+ this.securityControl = securityControl;
+ }
+
+ /**
+ * The currently used security control.
+ * @return
+ */
+ public T getSecurityControl()
+ {
+ return securityControl;
+ }
+
+ /**
+ * The currently used security control.
+ * @return
+ */
+ public void setSecurityControl(T securityControl)
+ {
+ this.securityControl = securityControl;
+ }
+
+ /**
* Creates the security panel depending on the concrete implementation of
* the passed security controller.
*
@@ -29,23 +63,49 @@ public abstract class SecurityPanel * controller or an {@link TransparentPanel} if the controller is
* unknown or does not have any controls to show.
*/
- public static SecurityPanel create(SrtpControl srtpControl)
+ public static SecurityPanel create( CallPeerRenderer peerRenderer,
+ CallPeer callPeer,
+ SrtpControl srtpControl)
{
if(srtpControl instanceof ZrtpControl)
- return new ZrtpSecurityPanel((ZrtpControl)srtpControl);
+ return new ZrtpSecurityPanel( peerRenderer,
+ callPeer,
+ (ZrtpControl)srtpControl);
- return new SecurityPanel()
+ return new SecurityPanel<SrtpControl>(srtpControl)
{
public void loadSkin()
{}
- public void refreshStates()
+
+ public void securityOn(CallPeerSecurityOnEvent evt)
+ {}
+
+ public void securityOff(CallPeerSecurityOffEvent evt)
+ {}
+
+ public void securityTimeout(CallPeerSecurityTimeoutEvent evt)
{}
};
}
/**
- * Forces the panel to update the security information presented to the
- * user.
+ * Indicates that the security is turned on.
+ *
+ * @param evt details about the event that caused this message.
+ */
+ public abstract void securityOn(CallPeerSecurityOnEvent evt);
+
+ /**
+ * Indicates that the security is turned off.
+ *
+ * @param evt details about the event that caused this message.
+ */
+ public abstract void securityOff(CallPeerSecurityOffEvent evt);
+
+ /**
+ * Indicates that the security is timeouted, is not supported by the
+ * other end.
+ * @param evt Details about the event that caused this message.
*/
- public abstract void refreshStates();
+ public abstract void securityTimeout(CallPeerSecurityTimeoutEvent evt);
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/SecurityStatusLabel.java b/src/net/java/sip/communicator/impl/gui/main/call/SecurityStatusLabel.java index bfe2ada..994808f 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/SecurityStatusLabel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/SecurityStatusLabel.java @@ -10,8 +10,10 @@ import java.awt.*; 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.*; /** * The <tt>SecurityStatusLabel</tt> is meant to be used to visualize the audio @@ -22,7 +24,7 @@ import net.java.sip.communicator.util.skin.*; */ public class SecurityStatusLabel extends JLabel - implements Skinnable + implements Skinnable { /** * Serial version UID. @@ -30,157 +32,135 @@ public class SecurityStatusLabel private static final long serialVersionUID = 0L; /** - * Indicates the state of the audio security (on or off). + * The icon used for the not secured state. */ - private boolean isAudioSecurityOn = false; + private static Icon securityOffIcon; /** - * Indicates the state of the video security (on or off). + * The icon used for the secured state. */ - private boolean isVideoSecurityOn = false; + private static Icon securityOnIcon; /** - * The encryption cipher. + * The background used to indicate that the call is secured. */ - private String encryptionCipher; + private final static Color securityOnBackground + = new Color(GuiActivator.getResources() + .getColor("service.gui.SECURITY_ON")); /** - * The default security status icon. + * The background used to indicate that the call is not secured. */ - private final Icon defaultIcon; + private final static Color securityOffBackground + = new Color(GuiActivator.getResources() + .getColor("service.gui.SECURITY_OFF")); /** - * The parent window, where this component will be contained. + * The background used to indicate that the call is not secured. */ - private final Window parentWindow; + private final static Color goingSecureBackground + = new Color(GuiActivator.getResources() + .getColor("service.gui.GOING_SECURE")); + + /** + * Indicates security status. + */ + private boolean isSecure = false; /** * Creates an instance of <tt>SecurityStatusLabel</tt> by specifying the * <tt>GuiCallPeer</tt>, the icon and the alignment to use for the label. */ - public SecurityStatusLabel(Window parentWindow, Icon securityIcon) + public SecurityStatusLabel() { - this.parentWindow = parentWindow; - this.defaultIcon = securityIcon; - loadSkin(); - this.setHorizontalAlignment(JLabel.CENTER); + setBorder(BorderFactory.createEmptyBorder(2, 8, 2, 3)); + setForeground(Color.WHITE); - this.setToolTipText("Security status"); + setHorizontalAlignment(JLabel.CENTER); + setHorizontalTextPosition(JLabel.LEFT); } /** - * Create an extended tooltip showing some more security details. - * @return the created tooltip + * Paints a custom background to better indicate security state. + * + * @param g the <tt>Graphics</tt> object */ - public JToolTip createToolTip() + public void paintComponent(Graphics g) { - ExtendedTooltip tip = new ExtendedTooltip(parentWindow, true); + g = g.create(); - tip.setTitle("Security status"); - - ImageIcon audioStatusIcon; - String audioStatusString; - if (isAudioSecurityOn) - { - audioStatusIcon = new ImageIcon( - ImageLoader.getImage(ImageLoader.SECURE_AUDIO_ON)); - audioStatusString = "Audio security on."; - } - else + try { - audioStatusIcon = new ImageIcon( - ImageLoader.getImage(ImageLoader.SECURE_AUDIO_OFF)); - audioStatusString = "Audio security off."; + AntialiasingManager.activateAntialiasing(g); + g.setColor(getBackground()); + + if (getIcon() != null) + { + if (isSecure) + g.fillRoundRect( + 0, 0, this.getWidth(), this.getHeight(), 20, 20); + else + g.fillRoundRect( + 0, 0, this.getWidth(), this.getHeight(), 20, 20); + } + + g.setColor(getForeground()); + + super.paintComponent(g); } - - ImageIcon videoStatusIcon; - String videoStatusString; - if (isVideoSecurityOn) + finally { - videoStatusIcon = new ImageIcon( - ImageLoader.getImage(ImageLoader.SECURE_VIDEO_ON)); - videoStatusString = "Video security on."; + g.dispose(); } - else - { - videoStatusIcon = new ImageIcon( - ImageLoader.getImage(ImageLoader.SECURE_VIDEO_OFF)); - videoStatusString = "Video security off."; - } - - String cipher = "Cipher: " + encryptionCipher; - - tip.addLine(audioStatusIcon, - audioStatusString); - - tip.addLine(videoStatusIcon, - videoStatusString); - - tip.addLine(null, cipher); - - tip.setComponent(this); - - return tip; - } - - /** - * Gets the audio security status. - * @return the audio security status. - */ - public boolean isAudioSecurityOn() - { - return isAudioSecurityOn; } /** * Sets the audio security on or off. - * - * @param isAudioSecurityOn indicates if the audio security is turned on or - * off. - */ - public void setAudioSecurityOn(boolean isAudioSecurityOn) - { - this.isAudioSecurityOn = isAudioSecurityOn; - } - - /** - * Gets the video security status. - * @return the video security status. */ - public boolean isVideoSecurityOn() + public void setSecurityOn() { - return isVideoSecurityOn; + isSecure = true; + setIcon(securityOnIcon); + setBackground(securityOnBackground); + setToolTipText(GuiActivator.getResources().getI18NString( + "service.gui.security.CALL_SECURED_TOOLTIP")); } /** - * Sets the video security on or off. - * - * @param isVideoSecurityOn indicates if the video security is turned on or - * off. + * Sets the audio security on or off. */ - public void setVideoSecurityOn(boolean isVideoSecurityOn) + public void setSecurityOff() { - this.isVideoSecurityOn = isVideoSecurityOn; + isSecure = false; + setIcon(securityOffIcon); + setBackground(securityOffBackground); + this.setToolTipText(GuiActivator.getResources().getI18NString( + "service.gui.security.CALL_NOT_SECURED_TOOLTIP")); } /** - * Sets the cipher used for the encryption of the current call. - * - * @param encryptionCipher the cipher used for the encryption of the - * current call. + * Sets the audio security on or off. */ - public void setEncryptionCipher(String encryptionCipher) + public void setSecurityPending() { - this.encryptionCipher = encryptionCipher; + isSecure = false; + setIcon(securityOnIcon); + setBackground(goingSecureBackground); + this.setToolTipText(GuiActivator.getResources().getI18NString( + "service.gui.security.CALL_SECURED_COMPARE_TOOLTIP")); } /** - * Reloads icon. + * Reloads icons. */ public void loadSkin() { - this.setIcon(defaultIcon); + securityOffIcon = new ImageIcon(ImageLoader + .getImage(ImageLoader.SECURE_BUTTON_OFF)); + + securityOnIcon = new ImageIcon(ImageLoader + .getImage(ImageLoader.SECURE_BUTTON_ON)); } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/ZrtpSecurityPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/ZrtpSecurityPanel.java index 547e796..73cfa37 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/ZrtpSecurityPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/ZrtpSecurityPanel.java @@ -8,12 +8,17 @@ package net.java.sip.communicator.impl.gui.main.call; import java.awt.*; import java.awt.event.*; +import java.beans.*; import javax.swing.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.neomedia.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.service.protocol.media.*; +import net.java.sip.communicator.util.event.*; import net.java.sip.communicator.util.swing.*; /** @@ -24,102 +29,580 @@ import net.java.sip.communicator.util.swing.*; * @author Yana Stamcheva */ public class ZrtpSecurityPanel - extends SecurityPanel + extends SecurityPanel<ZrtpControl> + implements VideoListener, + PropertyChangeListener { - private SIPCommButton sasVerificationButton; - private Image iconEncr; - private Image iconEncrVerified; - private final JLabel securityStringLabel = new JLabel(); + /** + * The icon indicating that the short authentication string has been + * verified. + */ + private static Icon encryptionVerifiedIcon; + + /** + * The icon indicating that the audio is secure. + */ + private static Icon audioSecuredIcon; + + /** + * The icon indicating that the audio is not secure. + */ + private static Icon audioNotSecuredIcon; + + /** + * The icon indicating that the video is secure. + */ + private static Icon videoSecuredIcon; + + /** + * The icon indicating that the video is not secure. + */ + private static Icon videoNotSecuredIcon; + + /** + * The label showing the security authentication string. + */ + private final JLabel securityStringLabel = createSecurityLabel("", null); + + /** + * The label showing audio security status. + */ + private final JLabel audioSecurityLabel; + + /** + * The label showing video security status. + */ + private final JLabel videoSecurityLabel; + + /** + * The button, which closes this panel. + */ + private final JButton closeButton + = new SIPCommButton(ImageLoader.getImage(ImageLoader.CLOSE_VIDEO)); + + /** + * The label containing information about the security authentication + * string. + */ + private final JLabel compareLabel = createSecurityLabel("", null); + + /** + * The button confirming the security authentication string. + */ + private final JButton confirmButton = new JButton(""); + + /** + * The label showing the cipher. + */ + private JLabel cipherLabel; + + /** + * Indicates if the security authentication string has been verified. + */ private boolean sasVerified = false; - private final ZrtpControl zrtpControl; + /** + * Indicates the state of the audio security (on or off). + */ + private boolean isAudioSecurityOn = false; + + /** + * Indicates the state of the video security (on or off). + */ + private boolean isVideoSecurityOn = false; + + /** + * The encryption cipher. + */ + private String encryptionCipher; + + /** + * The corresponding call peer. + */ + private final CallPeer callPeer; + /** + * The renderer of the corresponding call peer. + */ + private final CallPeerRenderer peerRenderer; /** * Creates an instance of <tt>SecurityPanel</tt> by specifying the * corresponding <tt>peer</tt>. - * + * + * @param peerRenderer the parent renderer + * @param callPeer the peer, which security this panel is about * @param zrtpControl the ZRTP security controller that provides information * for this panel and receives the user input */ - public ZrtpSecurityPanel(ZrtpControl zrtpControl) + public ZrtpSecurityPanel( CallPeerRenderer peerRenderer, + CallPeer callPeer, + ZrtpControl zrtpControl) { - this.zrtpControl = zrtpControl; + super(zrtpControl); - this.setBorder(null); - this.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 0)); + this.peerRenderer = peerRenderer; + this.callPeer = callPeer; - this.setToolTipText(GuiActivator.getResources().getI18NString( - "service.gui.COMPARE_WITH_PARTNER")); + OperationSetVideoTelephony telephony + = callPeer.getProtocolProvider() + .getOperationSet(OperationSetVideoTelephony.class); + + telephony.addVideoListener(callPeer, this); + telephony.addPropertyChangeListener(callPeer.getCall(), this); + + audioSecurityLabel = createSecurityLabel("", null); + + videoSecurityLabel = createSecurityLabel("", null); loadSkin(); } /** - * Adds security related components to this panel. + * Adds all components. */ - private void addComponentsToPane() + private void addComponents() { - this.add(sasVerificationButton); - this.add(securityStringLabel); + setAudioSecurityOn(isAudioSecurityOn); + setVideoSecurityOn(isVideoSecurityOn); - securityStringLabel - .setFont(securityStringLabel.getFont().deriveFont(14f)); + closeButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + peerRenderer.setSecurityPanelVisible(false); + } + }); + + setLayout(new GridBagLayout()); + GridBagConstraints constraints = new GridBagConstraints(); - // Action to trigger SAS verification - sasVerificationButton.addActionListener(new ActionListener() + constraints.anchor = GridBagConstraints.NORTHEAST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridx = 0; + constraints.gridy = 0; + constraints.gridheight = 1; + constraints.weightx = 0f; + constraints.weighty = 0f; + this.add(audioSecurityLabel, constraints); + + constraints.anchor = GridBagConstraints.NORTHEAST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridx = 0; + constraints.gridy = 1; + constraints.gridheight = 1; + constraints.weightx = 0f; + constraints.weighty = 0f; + constraints.insets = new Insets(5, 0, 0, 0); + this.add(videoSecurityLabel, constraints); + + String cipher = ""; + if (encryptionCipher != null && encryptionCipher.length() > 0) + { + cipher = GuiActivator.getResources().getI18NString( + "service.gui.CIPHER", new String[]{encryptionCipher}); + } + + cipherLabel = createSecurityLabel(cipher, null); + + constraints.anchor = GridBagConstraints.NORTHEAST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridx = 0; + constraints.gridy = 2; + constraints.gridheight = 1; + constraints.weightx = 0f; + constraints.weighty = 0f; + constraints.insets = new Insets(5, 0, 0, 0); + this.add(cipherLabel, constraints); + + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridx = 1; + constraints.gridy = 0; + constraints.gridheight = 3; + constraints.weightx = 1f; + constraints.weighty = 0f; + constraints.insets = new Insets(0, 5, 0, 5); + this.add(createSasPanel(), constraints); + + constraints.anchor = GridBagConstraints.NORTHEAST; + constraints.fill = GridBagConstraints.NONE; + constraints.gridx = 2; + constraints.gridy = 0; + constraints.gridheight = 1; + constraints.weightx = 0f; + constraints.weighty = 0f; + constraints.insets = new Insets(0, 0, 0, 5); + this.add(closeButton, constraints); + } + + /** + * Creates a security panel label. + * + * @param text the text of the label + * @param icon the label icon + * @return the created JLabel + */ + private JLabel createSecurityLabel(String text, Icon icon) + { + JLabel label = new JLabel(text, icon, JLabel.LEFT); + label.setForeground(Color.WHITE); + + return label; + } + + /** + * Creates the ZRTP sas panel. + * + * @return the created ZRTP SAS panel + */ + private JPanel createSasPanel() + { + sasVerified = getSecurityControl().isSecurityVerified(); + + TransparentPanel sasPanel = new TransparentPanel() + { + public void paintComponent(Graphics g) + { + g = g.create(); + try + { + AntialiasingManager.activateAntialiasing(g); + g.setColor(new Color(1f, 1f, 1f, 0.1f)); + g.fillRoundRect( + 0, 0, this.getWidth(), this.getHeight(), 10, 10); + g.setColor(Color.WHITE); + g.drawRoundRect( + 0, 0, + this.getWidth() - 1, this.getHeight() - 1, + 10, 10); + } + finally + { + g.dispose(); + } + } + }; + + sasPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + sasPanel.setPreferredSize(new Dimension(200, 80)); + sasPanel.setMinimumSize(new Dimension(200, 80)); + sasPanel.setMaximumSize(new Dimension(200, 80)); + sasPanel.setLayout(new BoxLayout(sasPanel, BoxLayout.Y_AXIS)); + + initSasLabels(); + + SIPCommButton infoButton = new SIPCommButton( + ImageLoader.getImage(ImageLoader.CALL_INFO)); + infoButton.setToolTipText(GuiActivator.getResources() + .getI18NString("service.gui.security.SAS_INFO_TOOLTIP")); + + compareLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + JPanel stringPanel = new TransparentPanel( + new FlowLayout(FlowLayout.CENTER, 5, 0)); + stringPanel.add(compareLabel); + stringPanel.add(infoButton); + + sasPanel.add(stringPanel); + + securityStringLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + sasPanel.add(securityStringLabel); + + confirmButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - sasVerified = !sasVerified; - zrtpControl.setSASVerification(sasVerified); + if (getSecurityControl() != null) + { + getSecurityControl().setSASVerification(!sasVerified); + + sasVerified = !sasVerified; + securityStringLabel + .setIcon(sasVerified ? encryptionVerifiedIcon : null); + + if (sasVerified) + peerRenderer.securityOn(null); + else + peerRenderer.securityPending(); - if (sasVerified) - sasVerificationButton.setImage(iconEncrVerified); - else - sasVerificationButton.setImage(iconEncr); + initSasLabels(); + } } }); + confirmButton.setAlignmentX(Component.CENTER_ALIGNMENT); + sasPanel.add(confirmButton); + + return sasPanel; + } + + /** + * Initializes security authentication string labels depending on the + * security verification status. + */ + private void initSasLabels() + { + if (!sasVerified) + { + compareLabel.setText(GuiActivator.getResources().getI18NString( + "service.gui.security.COMPARE_WITH_PARTNER_SHORT")); + confirmButton.setText(GuiActivator.getResources() + .getI18NString("servoce.gui.CONFIRM")); + } + else + { + compareLabel.setText(GuiActivator.getResources().getI18NString( + "service.gui.security.STRING_COMPARED")); + confirmButton.setText(GuiActivator.getResources() + .getI18NString("servoce.gui.CLEAR")); + } + + if (compareLabel.isVisible()) + { + compareLabel.revalidate(); + compareLabel.repaint(); + + confirmButton.revalidate(); + confirmButton.repaint(); + } } /** * Refreshes the state of the SAS and the SAS verified padlock. + * + * @param evt the security event of which we're notified */ - public void refreshStates() + public void securityOn(CallPeerSecurityOnEvent evt) { - String securityString = zrtpControl.getSecurityString(); + encryptionCipher = evt.getCipher(); + + if (encryptionCipher != null) + cipherLabel.setText(GuiActivator.getResources().getI18NString( + "service.gui.security.CIPHER", new String[]{encryptionCipher})); + + switch (evt.getSessionType()) + { + case CallPeerSecurityStatusEvent.AUDIO_SESSION: + setAudioSecurityOn(true); + break; + case CallPeerSecurityStatusEvent.VIDEO_SESSION: + setVideoSecurityOn(true); + break; + } + + String securityString = getSecurityControl().getSecurityString(); if (securityString != null) { - securityStringLabel.setText( - GuiActivator.getResources().getI18NString( - "service.gui.COMPARE_WITH_PARTNER_SHORT", - new String[] {securityString} - ) - ); + securityStringLabel.setText(securityString); } else { securityStringLabel.setText(null); } - sasVerified = zrtpControl.isSecurityVerified(); - sasVerificationButton - .setImage(sasVerified ? iconEncrVerified : iconEncr); + sasVerified = getSecurityControl().isSecurityVerified(); + securityStringLabel + .setIcon(sasVerified ? encryptionVerifiedIcon : null); + + revalidate(); + repaint(); + } + + /** + * Indicates that the security has gone off. + */ + public void securityOff(CallPeerSecurityOffEvent evt) + { + switch (evt.getSessionType()) + { + case CallPeerSecurityStatusEvent.AUDIO_SESSION: + setAudioSecurityOn(false); + break; + case CallPeerSecurityStatusEvent.VIDEO_SESSION: + setVideoSecurityOn(false); + break; + } revalidate(); repaint(); } + public void securityTimeout(CallPeerSecurityTimeoutEvent evt) + { + + } + /** * Reloads icons and components. */ public void loadSkin() { - this.removeAll(); - iconEncrVerified = ImageLoader.getImage(ImageLoader.ENCR_VERIFIED); - iconEncr = ImageLoader.getImage(ImageLoader.ENCR); - sasVerificationButton = new SIPCommButton(iconEncr); + removeAll(); + + encryptionVerifiedIcon = new ImageIcon( + ImageLoader.getImage(ImageLoader.ENCR_VERIFIED)); + + audioSecuredIcon = new ImageIcon( + ImageLoader.getImage(ImageLoader.SECURE_AUDIO_ON)); + + audioNotSecuredIcon = new ImageIcon( + ImageLoader.getImage(ImageLoader.SECURE_AUDIO_OFF)); + + videoSecuredIcon = new ImageIcon( + ImageLoader.getImage(ImageLoader.SECURE_VIDEO_ON)); + + videoNotSecuredIcon = new ImageIcon( + ImageLoader.getImage(ImageLoader.SECURE_VIDEO_OFF)); + + addComponents(); + + if (isVisible()) + { + revalidate(); + repaint(); + } + } + + /** + * Updates audio security related components, depending on the given audio + * security state. + * + * @param isAudioSecurityOn indicates if the audio is secured or not + */ + private void setAudioSecurityOn(final boolean isAudioSecurityOn) + { + if (!SwingUtilities.isEventDispatchThread()) + { + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + setAudioSecurityOn(isAudioSecurityOn); + } + }); + return; + } + + Icon statusIcon; + String statusText; + + this.isAudioSecurityOn = isAudioSecurityOn; + + if (isAudioSecurityOn) + { + statusIcon = audioSecuredIcon; + statusText = GuiActivator.getResources() + .getI18NString("service.gui.security.SECURE_AUDIO"); + } + else + { + statusIcon = audioNotSecuredIcon; + statusText = GuiActivator.getResources() + .getI18NString("service.gui.security.AUDIO_NOT_SECURED"); + } - this.addComponentsToPane(); + audioSecurityLabel.setIcon(statusIcon); + audioSecurityLabel.setText(statusText); + } + + /** + * Updates video security related components, depending on the given video + * security state. + * + * @param isVideoSecurityOn indicates if the video is secured or not + */ + private void setVideoSecurityOn(final boolean isVideoSecurityOn) + { + if (!SwingUtilities.isEventDispatchThread()) + { + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + setVideoSecurityOn(isVideoSecurityOn); + } + }); + return; + } + + this.isVideoSecurityOn = isVideoSecurityOn; + + Icon statusIcon = null; + String statusText = null; + + final OperationSetVideoTelephony telephony + = callPeer.getProtocolProvider() + .getOperationSet(OperationSetVideoTelephony.class); + + if (telephony != null + && ((telephony.getVisualComponents(callPeer) != null + && telephony.getVisualComponents(callPeer).size() > 0) + || ((MediaAwareCallPeer<?, ?, ?>) callPeer) + .isLocalVideoStreaming())) + { + if (isVideoSecurityOn) + { + statusIcon = videoSecuredIcon; + statusText = GuiActivator.getResources() + .getI18NString("service.gui.security.SECURE_VIDEO"); + } + else + { + statusIcon = videoNotSecuredIcon; + statusText = GuiActivator.getResources() + .getI18NString("service.gui.security.VIDEO_NOT_SECURED"); + } + } + else + { + videoSecurityLabel.setVisible(false); + } + + if (statusIcon != null && statusText != null) + { + videoSecurityLabel.setIcon(statusIcon); + videoSecurityLabel.setText(statusText); + + if (!videoSecurityLabel.isVisible()) + videoSecurityLabel.setVisible(true); + } + + revalidate(); + repaint(); + } + + /** + * {@inheritDoc} + */ + public void propertyChange(final PropertyChangeEvent event) + { + if (OperationSetVideoTelephony.LOCAL_VIDEO_STREAMING + .equals(event.getPropertyName())) + { + setVideoSecurityOn(isAudioSecurityOn); + } + } + + /** + * {@inheritDoc} + */ + public void videoAdded(VideoEvent event) + { + setVideoSecurityOn(isAudioSecurityOn); + } + + /** + * {@inheritDoc} + */ + public void videoRemoved(VideoEvent event) + { + setVideoSecurityOn(isAudioSecurityOn); + } + + /** + * {@inheritDoc} + */ + public void videoUpdate(VideoEvent event) + { + setVideoSecurityOn(isAudioSecurityOn); } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java index 00692b1..5e0568d 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java @@ -13,6 +13,7 @@ import javax.swing.text.*; import net.java.sip.communicator.impl.gui.main.call.*; import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.service.resources.*; import net.java.sip.communicator.util.*; @@ -161,10 +162,8 @@ public abstract class BasicConferenceParticipantPanel SoundLevelChangeEvent.MIN_LEVEL, SoundLevelChangeEvent.MAX_LEVEL); - securityStatusLabel = new SecurityStatusLabel( - renderer.getCallContainer().getCallWindow().getFrame(), - new ImageIcon( - ImageLoader.getImage(ImageLoader.SECURE_OFF_CONF_CALL))); + securityStatusLabel = new SecurityStatusLabel(); + securityStatusLabel.setSecurityOff(); this.setLayout(new GridBagLayout()); this.setBorder(BorderFactory.createEmptyBorder(7, 7, 7, 7)); @@ -270,6 +269,8 @@ public abstract class BasicConferenceParticipantPanel { statusBarConstraints.gridx = statusBarConstraints.gridx + 1; statusBarConstraints.weightx = 0f; + statusBarConstraints.insets = new Insets(0, 5, 0, 5); + this.statusBar.add(component, statusBarConstraints); } @@ -439,25 +440,32 @@ public abstract class BasicConferenceParticipantPanel */ public void securityOn(CallPeerSecurityOnEvent evt) { - if ((evt.getSecurityController().requiresSecureSignalingTransport() - && renderer.getCall().getProtocolProvider() - .isSignalingTransportSecure()) - || !evt.getSecurityController().requiresSecureSignalingTransport()) + // If the securityOn is called without a specific event, we'll just set + // the security label status to on. + if (evt == null) { - securityImageID = ImageLoader.SECURE_ON_CONF_CALL; - securityStatusLabel.setIcon(new ImageIcon(ImageLoader - .getImage(securityImageID))); + securityStatusLabel.setSecurityOn(); + return; } - securityStatusLabel.setEncryptionCipher(evt.getCipher()); - switch (evt.getSessionType()) + SrtpControl srtpControl = evt.getSecurityController(); + + if ((srtpControl.requiresSecureSignalingTransport() + && renderer.getCall().getProtocolProvider() + .isSignalingTransportSecure()) + || !srtpControl.requiresSecureSignalingTransport()) { - case CallPeerSecurityStatusEvent.AUDIO_SESSION: - securityStatusLabel.setAudioSecurityOn(true); - break; - case CallPeerSecurityStatusEvent.VIDEO_SESSION: - securityStatusLabel.setVideoSecurityOn(true); - break; + if (srtpControl instanceof ZrtpControl) + { + securityStatusLabel.setText("zrtp"); + + if (!((ZrtpControl) srtpControl).isSecurityVerified()) + securityStatusLabel.setSecurityPending(); + else + securityStatusLabel.setSecurityOn(); + } + else + securityStatusLabel.setSecurityOn(); } } @@ -468,19 +476,18 @@ public abstract class BasicConferenceParticipantPanel */ public void securityOff(CallPeerSecurityOffEvent evt) { - securityImageID = ImageLoader.SECURE_OFF_CONF_CALL; - securityStatusLabel.setIcon(new ImageIcon(ImageLoader - .getImage(securityImageID))); + securityStatusLabel.setText(""); + securityStatusLabel.setSecurityOff(); + if (securityStatusLabel.getBorder() == null) + securityStatusLabel.setBorder( + BorderFactory.createEmptyBorder(2, 5, 2, 3)); + } - securityStatusLabel.setEncryptionCipher(null); - switch (evt.getSessionType()) - { - case CallPeerSecurityStatusEvent.AUDIO_SESSION: - securityStatusLabel.setAudioSecurityOn(false); - break; - case CallPeerSecurityStatusEvent.VIDEO_SESSION: - securityStatusLabel.setVideoSecurityOn(false); - break; - } + /** + * Indicates that the security status is pending confirmation. + */ + public void securityPending() + { + securityStatusLabel.setSecurityPending(); } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceFocusPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceFocusPanel.java index 951df44..f45eb58 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceFocusPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceFocusPanel.java @@ -276,9 +276,9 @@ public class ConferenceFocusPanel * * @param state the state of the contained call peer */ - public void setPeerState(String state) + public void setPeerState(CallPeerState peerState, String state) { - focusPeerPanel.setPeerState(state); + focusPeerPanel.setPeerState(peerState, state); } /** @@ -321,6 +321,7 @@ public class ConferenceFocusPanel public void securityOn(CallPeerSecurityOnEvent evt) { focusPeerPanel.securityOn(evt); + for (ConferenceMemberPanel member : conferenceMembersPanels.values()) { member.securityOn(evt); @@ -342,6 +343,14 @@ public class ConferenceFocusPanel } /** + * Indicates that the security status is pending confirmation. + */ + public void securityPending() + { + focusPeerPanel.securityPending(); + } + + /** * Indicates that the security is timeouted, is not supported by the * other end. * @param evt Details about the event that caused this message. @@ -646,4 +655,15 @@ public class ConferenceFocusPanel } } } + + /** + * Shows/hides the security panel. + * + * @param isVisible <tt>true</tt> to show the security panel, <tt>false</tt> + * to hide it + */ + public void setSecurityPanelVisible(boolean isVisible) + { + + } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java index 3e8adc1..d942385 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferencePeerPanel.java @@ -7,6 +7,7 @@ package net.java.sip.communicator.impl.gui.main.call.conference; import java.awt.*; +import java.awt.event.*; import javax.swing.*; @@ -15,6 +16,7 @@ import net.java.sip.communicator.impl.gui.main.call.*; import net.java.sip.communicator.impl.gui.main.call.CallPeerAdapter; // disambiguation import net.java.sip.communicator.impl.gui.main.presence.*; import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.skin.*; @@ -153,6 +155,8 @@ public class ConferencePeerPanel this.callPeer = callPeer; this.videoHandler = videoHandler; + this.securityPanel = SecurityPanel.create(this, callPeer, null); + this.setMute(callPeer.isMute()); this.setPeerImage(CallManager.getPeerImage(callPeer)); @@ -192,6 +196,23 @@ public class ConferencePeerPanel securityOn(securityOnEvt); } + + securityStatusLabel.setBorder( + BorderFactory.createEmptyBorder(2, 5, 2, 5)); + + securityStatusLabel.setSecurityOff(); + + securityStatusLabel.addMouseListener(new MouseAdapter() + { + /** + * Invoked when a mouse button has been pressed on a component. + */ + public void mousePressed(MouseEvent e) + { + setSecurityPanelVisible(!callRenderer.getCallContainer() + .getCallWindow().getFrame().getGlassPane().isVisible()); + } + }); } /** @@ -207,13 +228,33 @@ public class ConferencePeerPanel { super.securityOn(evt); + // If the securityOn is called without a specific event, we'll just call + // the super and we'll return. + if (evt == null) + return; + + SrtpControl srtpControl = evt.getSecurityController(); + + // In case this is the local peer. if (securityPanel == null) + return; + + // if we have some other panel, using other control + if (securityPanel.getSecurityControl() == null + || !srtpControl.getClass().isInstance( + securityPanel.getSecurityControl())) { - securityPanel = SecurityPanel.create(evt.getSecurityController()); - securityPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); - this.addToCenter(securityPanel); + setSecurityPanelVisible(false); + + securityPanel + = SecurityPanel.create(this, callPeer, srtpControl); } - securityPanel.refreshStates(); + + securityPanel.securityOn(evt); + + if (srtpControl instanceof ZrtpControl + && !((ZrtpControl) srtpControl).isSecurityVerified()) + setSecurityPanelVisible(true); callPanel.refreshContainer(); } @@ -227,16 +268,22 @@ public class ConferencePeerPanel public void securityOff(CallPeerSecurityOffEvent evt) { super.securityOff(evt); - if(securityPanel != null - && !securityStatusLabel.isAudioSecurityOn() - && !securityStatusLabel.isVideoSecurityOn()) + + if(securityPanel != null) { - securityPanel.getParent().remove(securityPanel); - securityPanel = null; + securityPanel.securityOff(evt); } } /** + * Indicates that the security status is pending confirmation. + */ + public void securityPending() + { + super.securityPending(); + } + + /** * Indicates that the security is timeouted, is not supported by the * other end. * @param evt Details about the event that caused this message. @@ -306,7 +353,7 @@ public class ConferencePeerPanel * * @param state the state of the contained call peer */ - public void setPeerState(String state) + public void setPeerState(CallPeerState peerState, String state) { this.setParticipantState(state); } @@ -497,4 +544,146 @@ public class ConferencePeerPanel { return callPeer.getURI(); } + + /** + * Shows/hides the security panel. + * + * @param isVisible <tt>true</tt> to show the security panel, <tt>false</tt> + * to hide it + */ + public void setSecurityPanelVisible(boolean isVisible) + { + final JFrame callFrame = callRenderer.getCallContainer() + .getCallWindow().getFrame(); + + final JPanel glassPane = (JPanel) callFrame.getGlassPane(); + + if (!isVisible) + { + // Need to hide the security panel explicitly in order to keep the + // fade effect. + securityPanel.setVisible(false); + glassPane.setVisible(false); + glassPane.removeAll(); + } + else + { + glassPane.setLayout(null); + glassPane.addMouseListener(new MouseListener() + { + public void mouseReleased(MouseEvent e) + { + redispatchMouseEvent(glassPane, e); + } + + public void mousePressed(MouseEvent e) + { + redispatchMouseEvent(glassPane, e); + } + + public void mouseExited(MouseEvent e) + { + redispatchMouseEvent(glassPane, e); + } + + public void mouseEntered(MouseEvent e) + { + redispatchMouseEvent(glassPane, e); + } + + public void mouseClicked(MouseEvent e) + { + redispatchMouseEvent(glassPane, e); + } + }); + + Point securityLabelPoint = securityStatusLabel.getLocation(); + + Point newPoint + = SwingUtilities.convertPoint(securityStatusLabel.getParent(), + securityLabelPoint.x, securityLabelPoint.y, + callFrame); + + securityPanel.setBeginPoint( + new Point((int) newPoint.getX() + 15, 0)); + securityPanel.setBounds( + 0, (int) newPoint.getY() - 5, callFrame.getWidth(), 110); + + glassPane.add(securityPanel); + // Need to show the security panel explicitly in order to keep the + // fade effect. + securityPanel.setVisible(true); + glassPane.setVisible(true); + + glassPane.addComponentListener(new ComponentAdapter() + { + /** + * Invoked when the component's size changes. + */ + public void componentResized(ComponentEvent e) + { + if (glassPane.isVisible()) + { + glassPane.setVisible(false); + callFrame.removeComponentListener(this); + } + } + }); + } + } + + /** + * Re-dispatches glass pane mouse events only in case they occur on the + * security panel. + * + * @param glassPane the glass pane + * @param e the mouse event in question + */ + private void redispatchMouseEvent(Component glassPane, MouseEvent e) + { + Point glassPanePoint = e.getPoint(); + + Point securityPanelPoint = SwingUtilities.convertPoint( + glassPane, + glassPanePoint, + securityPanel); + + Component component; + Point componentPoint; + + if (securityPanelPoint.y > 0) + { + component = securityPanel; + componentPoint = securityPanelPoint; + } + else + { + Container contentPane + = callRenderer.getCallContainer().getCallWindow() + .getFrame().getContentPane(); + + Point containerPoint = SwingUtilities.convertPoint( + glassPane, + glassPanePoint, + contentPane); + + component = SwingUtilities.getDeepestComponentAt(contentPane, + containerPoint.x, containerPoint.y); + + componentPoint = SwingUtilities.convertPoint(contentPane, + glassPanePoint, component); + } + + if (component != null) + component.dispatchEvent(new MouseEvent( component, + e.getID(), + e.getWhen(), + e.getModifiers(), + componentPoint.x, + componentPoint.y, + e.getClickCount(), + e.isPopupTrigger())); + + e.consume(); + } } diff --git a/src/net/java/sip/communicator/util/swing/FadeInBalloonPanel.java b/src/net/java/sip/communicator/util/swing/FadeInBalloonPanel.java new file mode 100644 index 0000000..2d62c56 --- /dev/null +++ b/src/net/java/sip/communicator/util/swing/FadeInBalloonPanel.java @@ -0,0 +1,190 @@ +/* + * 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.swing; + +import java.awt.*; +import java.awt.geom.*; + +import javax.swing.*; + +import org.jvnet.lafwidget.animation.*; + +/** + * The <tt>FadeInBaloonPanel</tt> is a semi-transparent "balloon" panel, which + * could be shown in a glass pane for example. You can define a begin point, + * where the balloon triangle would show. + * + * @author Yana Stamcheva + */ +public class FadeInBalloonPanel + extends TransparentPanel +{ + /** + * The begin point, where the balloon triangle will be shown. + */ + private Point beginPoint; + + /** + * The begin point shift, which defines the rectangle point shift. + */ + private final static int beginPointShift = 6; + + /** + * Sets the begin point. + * + * @param beginPoint the begin point + */ + public void setBeginPoint(Point beginPoint) + { + this.beginPoint = beginPoint; + } + + /** + * 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. + * + * @param g The Graphics object. + */ + protected void paintComponent(Graphics g) + { + g = g.create(); + try + { + internalPaintComponent((Graphics2D) g); + } + finally + { + g.dispose(); + } + } + + /** + * Paints this button. + * @param g the <tt>Graphics</tt> object used for painting + */ + private void internalPaintComponent(Graphics2D g) + { + AntialiasingManager.activateAntialiasing(g); + /* + * As JComponent#paintComponent says, if you do not invoke super's + * implementation you must honor the opaque property, that is if this + * component is opaque, you must completely fill in the background in a + * non-opaque color. If you do not honor the opaque property you will + * likely see visual artifacts. + */ + if (isOpaque()) + { + g.setColor(getBackground()); + g.fillRect(0, 0, getWidth(), getHeight()); + } + + // Paint a roll over fade out. + FadeTracker fadeTracker = FadeTracker.getInstance(); + + float visibility = isVisible() ? 0.8f : 0.0f; + if (fadeTracker.isTracked(this, FadeKind.ROLLOVER)) + { + visibility = fadeTracker.getFade(this, FadeKind.ROLLOVER); + } + + g.setColor(new Color(0f, 0f, 0f, visibility)); + + int y = 0; + + // draw triangle (polygon) + if (beginPoint != null) + { + y = beginPointShift; + + int x1Points[] = { beginPoint.x, + beginPoint.x + beginPointShift, + beginPoint.x - beginPointShift}; + + int y1Points[] = { beginPoint.y, + beginPoint.y + beginPointShift, + beginPoint.y + beginPointShift}; + + GeneralPath polygon = + new GeneralPath(GeneralPath.WIND_EVEN_ODD, + x1Points.length); + + polygon.moveTo(x1Points[0], y1Points[0]); + + for (int index = 1; index < x1Points.length; index++) { + polygon.lineTo(x1Points[index], y1Points[index]); + }; + + polygon.closePath(); + g.fill(polygon); + } + + if (visibility != 0.0f) + { + g.fillRoundRect( + 0, y, this.getWidth(), this.getHeight(), 10, 10); + } + } + + /** + * The <tt>ButtonRepaintCallback</tt> is charged to repaint this button + * when the fade animation is performed. + */ + private class PanelRepaintCallback implements FadeTrackerCallback + { + public void fadeEnded(FadeKind arg0) + { + repaintLater(); + } + + public void fadePerformed(FadeKind arg0, float arg1) + { + repaintLater(); + } + + private void repaintLater() + { + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + FadeInBalloonPanel.this.repaint(); + } + }); + } + + public void fadeReversed(FadeKind arg0, boolean arg1, float arg2) + { + } + } + + /** + * Shows/hides this panel. + * + * @param isVisible <tt>true</tt> to show this panel, <tt>false</tt> to + * hide it + */ + public void setVisible(boolean isVisible) + { + FadeTracker fadeTracker = FadeTracker.getInstance(); + + if (isVisible) + { + fadeTracker.trackFadeIn(FadeKind.ROLLOVER, + FadeInBalloonPanel.this, + true, + new PanelRepaintCallback()); + } + else + { + fadeTracker.trackFadeOut(FadeKind.ROLLOVER, + FadeInBalloonPanel.this, + true, + new PanelRepaintCallback()); + } + } +} 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 fc5030c..e9d6775 100644 --- a/src/net/java/sip/communicator/util/swing/plaf/SIPCommTextFieldUI.java +++ b/src/net/java/sip/communicator/util/swing/plaf/SIPCommTextFieldUI.java @@ -300,7 +300,7 @@ public class SIPCommTextFieldUI } JTextComponent c = getComponent(); - + if(c == null) return null; |