diff options
Diffstat (limited to 'src/net/java/sip/communicator/impl/gui/main/call')
10 files changed, 3306 insertions, 3290 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java index 697a3fc..de63f79 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java @@ -1,4 +1,4 @@ -/*
+/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd @@ -15,619 +15,619 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.java.sip.communicator.impl.gui.main.call;
-
-import java.awt.*;
-import java.awt.event.*;
-
-import javax.swing.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-
-/**
- * The dialog created for a given call.
- *
- * @author Yana Stamcheva
- * @author Adam Netocny
- * @author Lyubomir Marinov
- */
-public class CallDialog
- extends SIPCommFrame
- implements CallContainer,
- CallTitleListener
-{
- /**
- * Serial version UID.
- */
- private static final long serialVersionUID = 0L;
-
- /**
- * Enabling force minimized mode will always open call dialog minimized.
- * The call dialog still can be shown, but by default it will be minimized.
- */
- private static final String FORCE_MINIMIZED_MODE
- = "net.java.sip.communicator.impl.gui.main.call.FORCE_MINIMIZED_MODE";
-
- /**
- * Finds a <tt>Container</tt> which is an ancestor of a specific
- * <tt>Component</tt>, has a set <tt>preferredSize</tt> and is closest to
- * the specified <tt>Component</tt> up the ancestor hierarchy.
- *
- * @param component the <tt>Component</tt> whose ancestor hierarchy is to be
- * searched upwards
- * @return a <tt>Container</tt>, if any, which is an ancestor of the
- * specified <tt>component</tt>, has a set <tt>preferredSize</tt> and is
- * closest to the specified <tt>component</tt> up the ancestor hierarchy
- */
- private static Container findClosestAncestorWithSetPreferredSize(
- Component component)
- {
- if ((component instanceof Container) && component.isPreferredSizeSet())
- return (Container) component;
- else
- {
- Container parent;
-
- while ((parent = component.getParent()) != null)
- {
- if (parent.isPreferredSizeSet())
- return parent;
- else
- component = parent;
- }
- return null;
- }
- }
-
- /**
- * The panel, where all call components are added.
- */
- private CallPanel callPanel;
-
- private final WindowStateListener windowStateListener
- = new WindowStateListener()
- {
- public void windowStateChanged(WindowEvent ev)
- {
- switch (ev.getID())
- {
- case WindowEvent.WINDOW_DEACTIVATED:
- case WindowEvent.WINDOW_ICONIFIED:
- case WindowEvent.WINDOW_LOST_FOCUS:
- setFullScreen(false);
- break;
- }
- }
- };
-
- /**
- * Creates a <tt>CallDialog</tt> by specifying the underlying call panel.
- */
- public CallDialog()
- {
- super(true, false);
-
- setMinimumSize(new Dimension(360, 300));
- }
-
- /**
- * Adds a call panel.
- *
- * @param callPanel the call panel to add to this dialog
- */
- public void addCallPanel(CallPanel callPanel)
- {
- this.callPanel = callPanel;
-
- getContentPane().add(callPanel);
-
- callPanel.addCallTitleListener(this);
- setTitle(callPanel.getCallTitle());
-
- if (!isVisible())
- {
- pack();
-
- // checks whether we need to open the call dialog in minimized mode
- if(GuiActivator.getConfigurationService()
- .getBoolean(FORCE_MINIMIZED_MODE, false))
- {
- setState(ICONIFIED);
- }
- setVisible(true);
- }
- }
-
- /**
- * Called when the title of the given <tt>CallPanel</tt> changes.
- *
- * @param callPanel the <tt>CallPanel</tt>, which title has changed
- */
- public void callTitleChanged(CallPanel callPanel)
- {
- if (this.callPanel.equals(callPanel))
- setTitle(callPanel.getCallTitle());
- }
-
- /**
- * {@inheritDoc}
- *
- * Hang ups the call/telephony conference depicted by this
- * <tt>CallDialog</tt> on close.
- */
- @Override
- protected void close(boolean escape)
- {
- if (escape)
- {
- /*
- * In full-screen mode, ESC does not close this CallDialog but exits
- * from full-screen to windowed mode.
- */
- if (isFullScreen())
- {
- setFullScreen(false);
- return;
- }
- }
- else
- {
- /*
- * If the window has been closed by clicking the X button or
- * pressing the key combination corresponding to the same button we
- * close the window first and then perform all hang up operations.
- */
-
- callPanel.disposeCallInfoFrame();
- // We hide the window here. It will be disposed when the call has
- // been ended.
- setVisible(false);
- }
-
- // Then perform hang up operations.
- callPanel.actionPerformedOnHangupButton(escape);
- }
-
- /**
- * {@inheritDoc}
- *
- * The delay implemented by <tt>CallDialog</tt> is 5 seconds.
- */
- public void close(final CallPanel callPanel, boolean delay)
- {
- if (this.callPanel.equals(callPanel))
- {
- if (delay)
- {
- Timer timer
- = new Timer(
- 5000,
- new ActionListener()
- {
- public void actionPerformed(ActionEvent ev)
- {
- dispose();
- }
- });
-
- timer.setRepeats(false);
- timer.start();
- }
- else
- {
- dispose();
- }
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * <tt>CallDialog</tt> prepares the <tt>CallPanel</tt> it contains for
- * garbage collection.
- */
- @Override
- public void dispose()
- {
- super.dispose();
-
- /*
- * Technically, CallManager adds/removes the callPanel to/from this
- * instance. It may want to just move it to another CallContainer so it
- * does not sound right that we are disposing of it. But we do not have
- * such a case at this time so try to reduce the risk of memory leaks.
- */
- if (this.callPanel != null)
- {
- callPanel.disposeCallInfoFrame();
- callPanel.dispose();
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * Attempts to adjust the size of this <tt>Frame</tt> as requested in the
- * AWT event dispatching thread.
- * <p>
- * The method may be executed on the AWT event dispatching thread only
- * because whoever is making the decision to request an adjustment of the
- * Frame size in relation to a AWT Component should be analyzing that same
- * Component in the AWT event dispatching thread only.
- * </p>
- *
- * @throws RuntimeException if the method is not called on the AWT event
- * dispatching thread
- */
- public void ensureSize(Component component, int width, int height)
- {
- CallManager.assertIsEventDispatchingThread();
-
- Frame frame = CallPeerRendererUtils.getFrame(component);
-
- if (frame == null)
- return;
- else if ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH)
- == Frame.MAXIMIZED_BOTH)
- {
- /*
- * Forcing the size of a Component which is displayed in a maximized
- * window does not sound like anything we want to do.
- */
- return;
- }
- else if (frame.equals(
- frame.getGraphicsConfiguration().getDevice()
- .getFullScreenWindow()))
- {
- /*
- * Forcing the size of a Component which is displayed in a
- * full-screen window does not sound like anything we want to do.
- */
- return;
- }
- else if (!frame.equals(this))
- {
- /* This Frame will try to adjust only its own size. */
- return;
- }
- else if ((component.getHeight() >= height)
- && (component.getWidth() >= width))
- {
- /*
- * We will only enlarge the frame size. If the component has already
- * been given at least what it is requesting, do not enlarge the
- * frame size because the whole calculation is prone to inaccuracy.
- */
- return;
- }
- else
- {
- /*
- * If there is no callPanel, it is unlikely that this CallDialog
- * will be asked to ensureSize. Anyway, support the scenario just in
- * case. In light of the absence of a callPanel to guide this
- * CallDialog about the preferred size, we do not have much of a
- * choice but to trust the method arguments.
- */
- if (callPanel != null)
- {
- /*
- * If there is a callPanel, we are likely to get a much better
- * estimation about the preferred size by asking the callPanel
- * rather than by trusting the method arguments. For example,
- * the visual Component displaying the video streaming from the
- * local user/peer to the remote peer(s) will think that its
- * preferred size is the one to base this Frame's size on but
- * that may be misleading because the local video may not be
- * displayed with its preferred size even if this Frame's size
- * will accommodate it.
- */
- /*
- * Just asking the callPanel about its preferredSize would've
- * been terrificly great. Unfortunately, that is presently
- * futile because the callPanel may have a preferredSize while
- * we are still required to display visual Components displaying
- * video in their non-scaled size. The same goes for any
- * Container which is an ancestor of the specified component.
- */
- Container ancestor
- = findClosestAncestorWithSetPreferredSize(component);
-
- if (ancestor == null)
- ancestor = callPanel;
- /*
- * If the ancestor has a forced preferredSize, its LayoutManager
- * may be able to give a good enough estimation.
- */
- if (ancestor.isPreferredSizeSet())
- {
- LayoutManager ancestorLayout = ancestor.getLayout();
-
- if (ancestorLayout != null)
- {
- Dimension preferredLayoutSize
- = ancestorLayout.preferredLayoutSize(ancestor);
-
- if (preferredLayoutSize != null)
- {
- component = ancestor;
- width = preferredLayoutSize.width;
- height = preferredLayoutSize.height;
- }
- }
- }
- else
- {
- /*
- * If the ancestor doesn't have a preferredSize forced, then
- * we may think that it will calculate an appropriate
- * preferredSize itself.
- */
- Dimension prefSize = ancestor.getPreferredSize();
-
- if (prefSize != null)
- {
- component = ancestor;
- width = prefSize.width;
- height = prefSize.height;
- }
- }
- }
-
- /*
- * If the component (which may be an ancestor of the Component
- * specified as an argument to the ensureSize method at this point)
- * has not been given a size, we will make a mistake if we try to
- * use it for the purposes of determining how much this Frame is to
- * be enlarged.
- */
- Dimension componentSize = component.getSize();
-
- if ((componentSize.width < 1) || (componentSize.height < 1))
- return;
-
- Dimension frameSize = frame.getSize();
- int newFrameWidth = frameSize.width + width - componentSize.width;
- int newFrameHeight
- = frameSize.height + height - componentSize.height;
-
- // Respect the minimum size.
- Dimension minSize = frame.getMinimumSize();
-
- if (newFrameWidth < minSize.width)
- newFrameWidth = minSize.width;
- if (newFrameHeight < minSize.height)
- newFrameHeight = minSize.height;
-
- // Don't get bigger than the screen.
- Rectangle screenBounds
- = frame.getGraphicsConfiguration().getBounds();
-
- if (newFrameWidth > screenBounds.width)
- newFrameWidth = screenBounds.width;
- if (newFrameHeight > screenBounds.height)
- newFrameHeight = screenBounds.height;
-
- /*
- * If we're going to make too small a change, don't even bother.
- * Besides, we don't want some weird recursive resizing.
- * Additionally, do not reduce the Frame size.
- */
- boolean changeWidth = ((newFrameWidth - frameSize.width) > 1);
- boolean changeHeight = ((newFrameHeight - frameSize.height) > 1);
-
- if (changeWidth || changeHeight)
- {
- if (!changeWidth)
- newFrameWidth = frameSize.width;
- else if (!changeHeight)
- newFrameHeight = frameSize.height;
-
- /*
- * The latest requirement with respect to the behavior upon
- * resizing is to center the Frame.
- */
- int newFrameX
- = screenBounds.x
- + (screenBounds.width - newFrameWidth) / 2;
- int newFrameY
- = screenBounds.y
- + (screenBounds.height - newFrameHeight) / 2;
-
- // Do not let the top left go out of the screen.
- if (newFrameX < screenBounds.x)
- newFrameX = screenBounds.x;
- if (newFrameY < screenBounds.y)
- newFrameY = screenBounds.y;
-
- frame.setBounds(
- newFrameX, newFrameY,
- newFrameWidth, newFrameHeight);
-
- /*
- * Make sure that the component which originally requested the
- * update to the size of the frame realizes the change as soon
- * as possible; otherwise, it may request yet another update.
- */
- if (frame.isDisplayable())
- {
- if (frame.isValid())
- frame.doLayout();
- else
- frame.validate();
- frame.repaint();
- }
- else
- frame.doLayout();
- }
- }
- }
-
- /**
- * Returns the frame of the call window.
- *
- * @return the frame of the call window
- */
- public JFrame getFrame()
- {
- return this;
- }
-
- /**
- * Overrides getMinimumSize and checks the minimum size that
- * is needed to display buttons and use it for minimum size if
- * needed.
- * @return minimum size.
- */
- @Override
- public Dimension getMinimumSize()
- {
- Dimension minSize = super.getMinimumSize();
-
- if(callPanel != null)
- {
- int minButtonWidth = callPanel.getMinimumButtonWidth();
-
- if(minButtonWidth > minSize.getWidth())
- minSize = new Dimension(minButtonWidth, 300);
- }
-
- return minSize;
- }
-
- /**
- * Indicates if the given <tt>callPanel</tt> is currently visible.
- *
- * @param callPanel the <tt>CallPanel</tt>, for which we verify
- * @return <tt>true</tt> if the given call container is visible in this
- * call window, otherwise - <tt>false</tt>
- */
- public boolean isCallVisible(CallPanel callPanel)
- {
- return this.callPanel.equals(callPanel) ? isVisible() : false;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isFullScreen()
- {
- return isFullScreen(getFrame());
- }
-
- /**
- * Determines whether a specific <tt>Window</tt> is displayed in full-screen
- * mode.
- *
- * @param window the <tt>Window</tt> to be checked whether it is displayed
- * in full-screen mode
- * @return <tt>true</tt> if the specified <tt>window</tt> is displayed in
- * full-screen mode; otherwise, <tt>false</tt>
- */
- public static boolean isFullScreen(Window window)
- {
- GraphicsConfiguration graphicsConfiguration
- = window.getGraphicsConfiguration();
-
- if (graphicsConfiguration != null)
- {
- GraphicsDevice device = graphicsConfiguration.getDevice();
-
- if (device != null)
- return window.equals(device.getFullScreenWindow());
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public void setFullScreen(boolean fullScreen)
- {
- GraphicsConfiguration graphicsConfiguration
- = getGraphicsConfiguration();
-
- if (graphicsConfiguration != null)
- {
- GraphicsDevice device = graphicsConfiguration.getDevice();
-
- if (device != null)
- {
- boolean thisIsFullScreen = equals(device.getFullScreenWindow());
- boolean firePropertyChange = false;
- boolean setVisible = isVisible();
-
- try
- {
- if (fullScreen)
- {
- if (!thisIsFullScreen)
- {
- /*
- * XXX The setUndecorated method will only work if
- * this Window is not displayable.
- */
- windowDispose();
- setUndecorated(true);
-
- device.setFullScreenWindow(this);
- firePropertyChange = true;
- }
- }
- else if (thisIsFullScreen)
- {
- /*
- * XXX The setUndecorated method will only work if this
- * Window is not displayable.
- */
- windowDispose();
- setUndecorated(false);
-
- device.setFullScreenWindow(null);
- firePropertyChange = true;
- }
-
- if (firePropertyChange)
- {
- if (fullScreen)
- {
- addWindowStateListener(windowStateListener);
-
- /*
- * If full-screen mode, a black background is the
- * most common.
- */
- getContentPane().setBackground(Color.BLACK);
- }
- else
- {
- removeWindowStateListener(windowStateListener);
-
- /*
- * In windowed mode, a system-defined background is
- * the most common.
- */
- getContentPane().setBackground(null);
- }
-
- firePropertyChange(
- PROP_FULL_SCREEN,
- thisIsFullScreen,
- fullScreen);
- }
- }
- finally
- {
- /*
- * Regardless of whether this Window successfully entered or
- * exited full-screen mode, make sure that remains visible.
- */
- if (setVisible)
- setVisible(true);
- }
- }
- }
- }
-}
+package net.java.sip.communicator.impl.gui.main.call; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.plugin.desktoputil.*; + +/** + * The dialog created for a given call. + * + * @author Yana Stamcheva + * @author Adam Netocny + * @author Lyubomir Marinov + */ +public class CallDialog + extends SIPCommFrame + implements CallContainer, + CallTitleListener +{ + /** + * Serial version UID. + */ + private static final long serialVersionUID = 0L; + + /** + * Enabling force minimized mode will always open call dialog minimized. + * The call dialog still can be shown, but by default it will be minimized. + */ + private static final String FORCE_MINIMIZED_MODE + = "net.java.sip.communicator.impl.gui.main.call.FORCE_MINIMIZED_MODE"; + + /** + * Finds a <tt>Container</tt> which is an ancestor of a specific + * <tt>Component</tt>, has a set <tt>preferredSize</tt> and is closest to + * the specified <tt>Component</tt> up the ancestor hierarchy. + * + * @param component the <tt>Component</tt> whose ancestor hierarchy is to be + * searched upwards + * @return a <tt>Container</tt>, if any, which is an ancestor of the + * specified <tt>component</tt>, has a set <tt>preferredSize</tt> and is + * closest to the specified <tt>component</tt> up the ancestor hierarchy + */ + private static Container findClosestAncestorWithSetPreferredSize( + Component component) + { + if ((component instanceof Container) && component.isPreferredSizeSet()) + return (Container) component; + else + { + Container parent; + + while ((parent = component.getParent()) != null) + { + if (parent.isPreferredSizeSet()) + return parent; + else + component = parent; + } + return null; + } + } + + /** + * The panel, where all call components are added. + */ + private CallPanel callPanel; + + private final WindowStateListener windowStateListener + = new WindowStateListener() + { + public void windowStateChanged(WindowEvent ev) + { + switch (ev.getID()) + { + case WindowEvent.WINDOW_DEACTIVATED: + case WindowEvent.WINDOW_ICONIFIED: + case WindowEvent.WINDOW_LOST_FOCUS: + setFullScreen(false); + break; + } + } + }; + + /** + * Creates a <tt>CallDialog</tt> by specifying the underlying call panel. + */ + public CallDialog() + { + super(true, false); + + setMinimumSize(new Dimension(360, 300)); + } + + /** + * Adds a call panel. + * + * @param callPanel the call panel to add to this dialog + */ + public void addCallPanel(CallPanel callPanel) + { + this.callPanel = callPanel; + + getContentPane().add(callPanel); + + callPanel.addCallTitleListener(this); + setTitle(callPanel.getCallTitle()); + + if (!isVisible()) + { + pack(); + + // checks whether we need to open the call dialog in minimized mode + if(GuiActivator.getConfigurationService() + .getBoolean(FORCE_MINIMIZED_MODE, false)) + { + setState(ICONIFIED); + } + setVisible(true); + } + } + + /** + * Called when the title of the given <tt>CallPanel</tt> changes. + * + * @param callPanel the <tt>CallPanel</tt>, which title has changed + */ + public void callTitleChanged(CallPanel callPanel) + { + if (this.callPanel.equals(callPanel)) + setTitle(callPanel.getCallTitle()); + } + + /** + * {@inheritDoc} + * + * Hang ups the call/telephony conference depicted by this + * <tt>CallDialog</tt> on close. + */ + @Override + protected void close(boolean escape) + { + if (escape) + { + /* + * In full-screen mode, ESC does not close this CallDialog but exits + * from full-screen to windowed mode. + */ + if (isFullScreen()) + { + setFullScreen(false); + return; + } + } + else + { + /* + * If the window has been closed by clicking the X button or + * pressing the key combination corresponding to the same button we + * close the window first and then perform all hang up operations. + */ + + callPanel.disposeCallInfoFrame(); + // We hide the window here. It will be disposed when the call has + // been ended. + setVisible(false); + } + + // Then perform hang up operations. + callPanel.actionPerformedOnHangupButton(escape); + } + + /** + * {@inheritDoc} + * + * The delay implemented by <tt>CallDialog</tt> is 5 seconds. + */ + public void close(final CallPanel callPanel, boolean delay) + { + if (this.callPanel.equals(callPanel)) + { + if (delay) + { + Timer timer + = new Timer( + 5000, + new ActionListener() + { + public void actionPerformed(ActionEvent ev) + { + dispose(); + } + }); + + timer.setRepeats(false); + timer.start(); + } + else + { + dispose(); + } + } + } + + /** + * {@inheritDoc} + * + * <tt>CallDialog</tt> prepares the <tt>CallPanel</tt> it contains for + * garbage collection. + */ + @Override + public void dispose() + { + super.dispose(); + + /* + * Technically, CallManager adds/removes the callPanel to/from this + * instance. It may want to just move it to another CallContainer so it + * does not sound right that we are disposing of it. But we do not have + * such a case at this time so try to reduce the risk of memory leaks. + */ + if (this.callPanel != null) + { + callPanel.disposeCallInfoFrame(); + callPanel.dispose(); + } + } + + /** + * {@inheritDoc} + * + * Attempts to adjust the size of this <tt>Frame</tt> as requested in the + * AWT event dispatching thread. + * <p> + * The method may be executed on the AWT event dispatching thread only + * because whoever is making the decision to request an adjustment of the + * Frame size in relation to a AWT Component should be analyzing that same + * Component in the AWT event dispatching thread only. + * </p> + * + * @throws RuntimeException if the method is not called on the AWT event + * dispatching thread + */ + public void ensureSize(Component component, int width, int height) + { + CallManager.assertIsEventDispatchingThread(); + + Frame frame = CallPeerRendererUtils.getFrame(component); + + if (frame == null) + return; + else if ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) + == Frame.MAXIMIZED_BOTH) + { + /* + * Forcing the size of a Component which is displayed in a maximized + * window does not sound like anything we want to do. + */ + return; + } + else if (frame.equals( + frame.getGraphicsConfiguration().getDevice() + .getFullScreenWindow())) + { + /* + * Forcing the size of a Component which is displayed in a + * full-screen window does not sound like anything we want to do. + */ + return; + } + else if (!frame.equals(this)) + { + /* This Frame will try to adjust only its own size. */ + return; + } + else if ((component.getHeight() >= height) + && (component.getWidth() >= width)) + { + /* + * We will only enlarge the frame size. If the component has already + * been given at least what it is requesting, do not enlarge the + * frame size because the whole calculation is prone to inaccuracy. + */ + return; + } + else + { + /* + * If there is no callPanel, it is unlikely that this CallDialog + * will be asked to ensureSize. Anyway, support the scenario just in + * case. In light of the absence of a callPanel to guide this + * CallDialog about the preferred size, we do not have much of a + * choice but to trust the method arguments. + */ + if (callPanel != null) + { + /* + * If there is a callPanel, we are likely to get a much better + * estimation about the preferred size by asking the callPanel + * rather than by trusting the method arguments. For example, + * the visual Component displaying the video streaming from the + * local user/peer to the remote peer(s) will think that its + * preferred size is the one to base this Frame's size on but + * that may be misleading because the local video may not be + * displayed with its preferred size even if this Frame's size + * will accommodate it. + */ + /* + * Just asking the callPanel about its preferredSize would've + * been terrificly great. Unfortunately, that is presently + * futile because the callPanel may have a preferredSize while + * we are still required to display visual Components displaying + * video in their non-scaled size. The same goes for any + * Container which is an ancestor of the specified component. + */ + Container ancestor + = findClosestAncestorWithSetPreferredSize(component); + + if (ancestor == null) + ancestor = callPanel; + /* + * If the ancestor has a forced preferredSize, its LayoutManager + * may be able to give a good enough estimation. + */ + if (ancestor.isPreferredSizeSet()) + { + LayoutManager ancestorLayout = ancestor.getLayout(); + + if (ancestorLayout != null) + { + Dimension preferredLayoutSize + = ancestorLayout.preferredLayoutSize(ancestor); + + if (preferredLayoutSize != null) + { + component = ancestor; + width = preferredLayoutSize.width; + height = preferredLayoutSize.height; + } + } + } + else + { + /* + * If the ancestor doesn't have a preferredSize forced, then + * we may think that it will calculate an appropriate + * preferredSize itself. + */ + Dimension prefSize = ancestor.getPreferredSize(); + + if (prefSize != null) + { + component = ancestor; + width = prefSize.width; + height = prefSize.height; + } + } + } + + /* + * If the component (which may be an ancestor of the Component + * specified as an argument to the ensureSize method at this point) + * has not been given a size, we will make a mistake if we try to + * use it for the purposes of determining how much this Frame is to + * be enlarged. + */ + Dimension componentSize = component.getSize(); + + if ((componentSize.width < 1) || (componentSize.height < 1)) + return; + + Dimension frameSize = frame.getSize(); + int newFrameWidth = frameSize.width + width - componentSize.width; + int newFrameHeight + = frameSize.height + height - componentSize.height; + + // Respect the minimum size. + Dimension minSize = frame.getMinimumSize(); + + if (newFrameWidth < minSize.width) + newFrameWidth = minSize.width; + if (newFrameHeight < minSize.height) + newFrameHeight = minSize.height; + + // Don't get bigger than the screen. + Rectangle screenBounds + = frame.getGraphicsConfiguration().getBounds(); + + if (newFrameWidth > screenBounds.width) + newFrameWidth = screenBounds.width; + if (newFrameHeight > screenBounds.height) + newFrameHeight = screenBounds.height; + + /* + * If we're going to make too small a change, don't even bother. + * Besides, we don't want some weird recursive resizing. + * Additionally, do not reduce the Frame size. + */ + boolean changeWidth = ((newFrameWidth - frameSize.width) > 1); + boolean changeHeight = ((newFrameHeight - frameSize.height) > 1); + + if (changeWidth || changeHeight) + { + if (!changeWidth) + newFrameWidth = frameSize.width; + else if (!changeHeight) + newFrameHeight = frameSize.height; + + /* + * The latest requirement with respect to the behavior upon + * resizing is to center the Frame. + */ + int newFrameX + = screenBounds.x + + (screenBounds.width - newFrameWidth) / 2; + int newFrameY + = screenBounds.y + + (screenBounds.height - newFrameHeight) / 2; + + // Do not let the top left go out of the screen. + if (newFrameX < screenBounds.x) + newFrameX = screenBounds.x; + if (newFrameY < screenBounds.y) + newFrameY = screenBounds.y; + + frame.setBounds( + newFrameX, newFrameY, + newFrameWidth, newFrameHeight); + + /* + * Make sure that the component which originally requested the + * update to the size of the frame realizes the change as soon + * as possible; otherwise, it may request yet another update. + */ + if (frame.isDisplayable()) + { + if (frame.isValid()) + frame.doLayout(); + else + frame.validate(); + frame.repaint(); + } + else + frame.doLayout(); + } + } + } + + /** + * Returns the frame of the call window. + * + * @return the frame of the call window + */ + public JFrame getFrame() + { + return this; + } + + /** + * Overrides getMinimumSize and checks the minimum size that + * is needed to display buttons and use it for minimum size if + * needed. + * @return minimum size. + */ + @Override + public Dimension getMinimumSize() + { + Dimension minSize = super.getMinimumSize(); + + if(callPanel != null) + { + int minButtonWidth = callPanel.getMinimumButtonWidth(); + + if(minButtonWidth > minSize.getWidth()) + minSize = new Dimension(minButtonWidth, 300); + } + + return minSize; + } + + /** + * Indicates if the given <tt>callPanel</tt> is currently visible. + * + * @param callPanel the <tt>CallPanel</tt>, for which we verify + * @return <tt>true</tt> if the given call container is visible in this + * call window, otherwise - <tt>false</tt> + */ + public boolean isCallVisible(CallPanel callPanel) + { + return this.callPanel.equals(callPanel) ? isVisible() : false; + } + + /** + * {@inheritDoc} + */ + public boolean isFullScreen() + { + return isFullScreen(getFrame()); + } + + /** + * Determines whether a specific <tt>Window</tt> is displayed in full-screen + * mode. + * + * @param window the <tt>Window</tt> to be checked whether it is displayed + * in full-screen mode + * @return <tt>true</tt> if the specified <tt>window</tt> is displayed in + * full-screen mode; otherwise, <tt>false</tt> + */ + public static boolean isFullScreen(Window window) + { + GraphicsConfiguration graphicsConfiguration + = window.getGraphicsConfiguration(); + + if (graphicsConfiguration != null) + { + GraphicsDevice device = graphicsConfiguration.getDevice(); + + if (device != null) + return window.equals(device.getFullScreenWindow()); + } + return false; + } + + /** + * {@inheritDoc} + */ + public void setFullScreen(boolean fullScreen) + { + GraphicsConfiguration graphicsConfiguration + = getGraphicsConfiguration(); + + if (graphicsConfiguration != null) + { + GraphicsDevice device = graphicsConfiguration.getDevice(); + + if (device != null) + { + boolean thisIsFullScreen = equals(device.getFullScreenWindow()); + boolean firePropertyChange = false; + boolean setVisible = isVisible(); + + try + { + if (fullScreen) + { + if (!thisIsFullScreen) + { + /* + * XXX The setUndecorated method will only work if + * this Window is not displayable. + */ + windowDispose(); + setUndecorated(true); + + device.setFullScreenWindow(this); + firePropertyChange = true; + } + } + else if (thisIsFullScreen) + { + /* + * XXX The setUndecorated method will only work if this + * Window is not displayable. + */ + windowDispose(); + setUndecorated(false); + + device.setFullScreenWindow(null); + firePropertyChange = true; + } + + if (firePropertyChange) + { + if (fullScreen) + { + addWindowStateListener(windowStateListener); + + /* + * If full-screen mode, a black background is the + * most common. + */ + getContentPane().setBackground(Color.BLACK); + } + else + { + removeWindowStateListener(windowStateListener); + + /* + * In windowed mode, a system-defined background is + * the most common. + */ + getContentPane().setBackground(null); + } + + firePropertyChange( + PROP_FULL_SCREEN, + thisIsFullScreen, + fullScreen); + } + } + finally + { + /* + * Regardless of whether this Window successfully entered or + * exited full-screen mode, make sure that remains visible. + */ + if (setVisible) + setVisible(true); + } + } + } + } +} 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 095b3dd..d1c0a42 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 @@ -130,6 +130,14 @@ public class CallHistoryButton } /** + * Does nothing because this class causes the clearing. + */ + @Override + public void notificationCleared(UINotification notification) + { + } + + /** * Sets the history view. */ private void setHistoryView() diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java b/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java index ad8f6fd..872e861 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java @@ -34,6 +34,7 @@ import net.java.sip.communicator.util.*; import org.ice4j.ice.*; import org.jitsi.service.neomedia.*; +import org.jitsi.service.neomedia.stats.*; import org.jitsi.service.resources.*; import org.jitsi.util.*; @@ -469,7 +470,7 @@ public class CallInfoFrame StringBuffer stringBuffer, MediaType mediaType) { - MediaStreamStats mediaStreamStats + MediaStreamStats2 mediaStreamStats = mediaStream.getMediaStreamStats(); if(mediaStreamStats == null) @@ -624,18 +625,19 @@ public class CallInfoFrame resources.getI18NString( "service.gui.callinfo.BANDWITH"), "↓ " - + (int) mediaStreamStats.getDownloadRateKiloBitPerSec() + + (int) mediaStreamStats.getReceiveStats().getBitrate()/1024 + " Kbps " + " ↑ " - + (int) mediaStreamStats.getUploadRateKiloBitPerSec() + + (int) mediaStreamStats.getSendStats().getBitrate()/1024 + " Kbps")); stringBuffer.append( getLineString( resources.getI18NString("service.gui.callinfo.LOSS_RATE"), - "↓ " + (int) mediaStreamStats.getDownloadPercentLoss() + "↓" + + (int) (mediaStreamStats.getReceiveStats().getLossRate() * 100) + "% ↑ " - + (int) mediaStreamStats.getUploadPercentLoss() + + (int) (mediaStreamStats.getSendStats().getLossRate() * 100) + "%")); stringBuffer.append( getLineString( @@ -668,21 +670,23 @@ public class CallInfoFrame + mediaStreamStats.getPacketQueueCountPackets() + "/" + mediaStreamStats.getPacketQueueSize() + " packets")); - long rttMs = mediaStreamStats.getRttMs(); - if(rttMs != -1) + long sendRttMs = mediaStreamStats.getSendStats().getRtt(); + long recvRttMs = mediaStreamStats.getReceiveStats().getRtt(); + if(recvRttMs != -1 || sendRttMs != -1) { stringBuffer.append( getLineString(resources.getI18NString( "service.gui.callinfo.RTT"), - rttMs + " ms")); + (recvRttMs != -1 ? "↓ " + recvRttMs + " ms" : "") + + (sendRttMs != -1 ? "↑ " + sendRttMs + " ms" : ""))); } stringBuffer.append( getLineString(resources.getI18NString( "service.gui.callinfo.JITTER"), - "↓ " + (int) mediaStreamStats.getDownloadJitterMs() + "↓ " + (int) mediaStreamStats.getReceiveStats().getJitter() + " ms ↑ " - + (int) mediaStreamStats.getUploadJitterMs() + " ms")); + + (int) mediaStreamStats.getSendStats().getJitter() + " ms")); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java b/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java index 54f48ee..6235e1c 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java @@ -1,4 +1,4 @@ -/*
+/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd @@ -15,276 +15,276 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.java.sip.communicator.impl.gui.main.call;
-
-import java.awt.datatransfer.*;
-import java.awt.im.*;
-import java.io.*;
-import java.util.*;
-
-import javax.swing.*;
-
-import org.jitsi.service.resources.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.impl.gui.main.contactlist.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * A <tt>TransferHandler</tt> that handles dropping of <tt>UIContact</tt>s or
- * <tt>String</tt> addresses on a <tt>CallConference</tt>. Dropping such data on
- * the <tt>CallDialog</tt> will turn a one-to-one <tt>Call</tt> into a telephony
- * conference.
- *
- * @author Yana Stamcheva
- */
-public class CallTransferHandler
- extends ExtendedTransferHandler
-{
- /**
- * Serial version UID.
- */
- private static final long serialVersionUID = 0L;
-
- /**
- * The data flavor used when transferring <tt>UIContact</tt>s.
- */
- protected static final DataFlavor uiContactDataFlavor
- = new DataFlavor(UIContact.class, "UIContact");
-
- /**
- * The logger.
- */
- private static final Logger logger
- = Logger.getLogger(CallTransferHandler.class);
-
- /**
- * The <tt>CallConference</tt> into which the dropped callees are to be
- * invited.
- */
- private final CallConference callConference;
-
- /**
- * Initializes a new <tt>CallTransferHandler</tt> instance which is to
- * invite dropped callees to a telephony conference specified by a specific
- * <tt>Call</tt> which participates in it.
- *
- * @param call the <tt>Call</tt> which specifies the telephony conference to
- * which dropped callees are to be invited
- */
- public CallTransferHandler(Call call)
- {
- this(call.getConference());
- }
-
- /**
- * Initializes a new <tt>CallTransferHandler</tt> instance which is to
- * invite dropped callees to a specific <tt>CallConference</tt>.
- *
- * @param callConference the <tt>CallConference</tt> to which dropped
- * callees are to be invited
- */
- public CallTransferHandler(CallConference callConference)
- {
- this.callConference = callConference;
- }
-
- /**
- * Indicates whether a component will accept an import of the given
- * set of data flavors prior to actually attempting to import it. We return
- * <tt>true</tt> to indicate that the transfer with at least one of the
- * given flavors would work and <tt>false</tt> to reject the transfer.
- * <p>
- * @param comp component
- * @param flavor the data formats available
- * @return true if the data can be inserted into the component, false
- * otherwise
- * @throws NullPointerException if <code>support</code> is {@code null}
- */
- @Override
- public boolean canImport(JComponent comp, DataFlavor[] flavor)
- {
- for (DataFlavor f : flavor)
- {
- if (f.equals(DataFlavor.stringFlavor)
- || f.equals(uiContactDataFlavor))
- {
- return (comp instanceof JPanel);
- }
- }
- return false;
- }
-
- /**
- * Handles transfers to the chat panel from the clip board or a
- * DND drop operation. The <tt>Transferable</tt> parameter contains the
- * data that needs to be imported.
- * <p>
- * @param comp the component to receive the transfer;
- * @param t the data to import
- * @return true if the data was inserted into the component and false
- * otherwise
- */
- @Override
- public boolean importData(JComponent comp, Transferable t)
- {
- String callee = null;
- ProtocolProviderService provider = null;
-
- if (t.isDataFlavorSupported(uiContactDataFlavor))
- {
- Object o = null;
-
- try
- {
- o = t.getTransferData(uiContactDataFlavor);
- }
- catch (UnsupportedFlavorException e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to drop meta contact.", e);
- }
- catch (IOException e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to drop meta contact.", e);
- }
-
- if (o instanceof ContactNode)
- {
- UIContact uiContact = ((ContactNode) o).getContactDescriptor();
- Iterator<UIContactDetail> contactDetails
- = uiContact
- .getContactDetailsForOperationSet(
- OperationSetBasicTelephony.class)
- .iterator();
-
- while (contactDetails.hasNext())
- {
- UIContactDetail detail = contactDetails.next();
- ProtocolProviderService detailProvider
- = detail.getPreferredProtocolProvider(
- OperationSetBasicTelephony.class);
-
- if (detailProvider != null)
- {
- /*
- * Currently for videobridge conferences we only support
- * adding contacts via the account with the videobridge
- */
- if (callConference.isJitsiVideobridge())
- {
- for (Call call : callConference.getCalls())
- {
- if (detailProvider == call.getProtocolProvider())
- {
- callee = detail.getAddress();
- provider = detailProvider;
- break;
- }
- }
- }
- else
- {
- callee = detail.getAddress();
- provider = detailProvider;
- break;
- }
- }
- }
-
- if (callee == null)
- {
- /*
- * It turns out that the error message to be reported would
- * like to display information about the account which could
- * not add the dropped callee to the telephony conference.
- * Unfortunately, a telephony conference may have multiple
- * accounts involved. Anyway, choose the first account
- * involved in the telephony conference.
- */
- ProtocolProviderService callProvider
- = callConference.getCalls().get(0)
- .getProtocolProvider();
-
- ResourceManagementService resources
- = GuiActivator.getResources();
- AccountID accountID = callProvider.getAccountID();
-
- new ErrorDialog(null,
- resources.getI18NString("service.gui.ERROR"),
- resources.getI18NString(
- "service.gui.CALL_NOT_SUPPORTING_PARTICIPANT",
- new String[]
- {
- accountID.getService(),
- accountID.getUserID(),
- uiContact.getDisplayName()
- }))
- .showDialog();
- }
- }
- }
- else if (t.isDataFlavorSupported(DataFlavor.stringFlavor))
- {
- InputContext inputContext = comp.getInputContext();
-
- if (inputContext != null)
- inputContext.endComposition();
-
- try
- {
- BufferedReader reader
- = new BufferedReader(
- DataFlavor.stringFlavor.getReaderForText(t));
-
- try
- {
- String line;
- StringBuilder calleeBuilder = new StringBuilder();
-
- while ((line = reader.readLine()) != null)
- calleeBuilder.append(line);
-
- callee = calleeBuilder.toString();
- /*
- * The value of the local variable provider will be null
- * because we have a String only and hence we have no
- * associated ProtocolProviderService.
- * CallManager.inviteToConferenceCall will accept it.
- */
- }
- finally
- {
- reader.close();
- }
- }
- catch (UnsupportedFlavorException e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to drop string.", e);
- }
- catch (IOException e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to drop string.", e);
- }
- }
-
- if (callee == null)
- return false;
- else
- {
- Map<ProtocolProviderService, List<String>> callees
- = new HashMap<ProtocolProviderService, List<String>>();
-
- callees.put(provider, Arrays.asList(callee));
- CallManager.inviteToConferenceCall(callees, callConference);
-
- return true;
- }
- }
-}
+package net.java.sip.communicator.impl.gui.main.call; + +import java.awt.datatransfer.*; +import java.awt.im.*; +import java.io.*; +import java.util.*; + +import javax.swing.*; + +import org.jitsi.service.resources.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.impl.gui.main.contactlist.*; +import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + +/** + * A <tt>TransferHandler</tt> that handles dropping of <tt>UIContact</tt>s or + * <tt>String</tt> addresses on a <tt>CallConference</tt>. Dropping such data on + * the <tt>CallDialog</tt> will turn a one-to-one <tt>Call</tt> into a telephony + * conference. + * + * @author Yana Stamcheva + */ +public class CallTransferHandler + extends ExtendedTransferHandler +{ + /** + * Serial version UID. + */ + private static final long serialVersionUID = 0L; + + /** + * The data flavor used when transferring <tt>UIContact</tt>s. + */ + protected static final DataFlavor uiContactDataFlavor + = new DataFlavor(UIContact.class, "UIContact"); + + /** + * The logger. + */ + private static final Logger logger + = Logger.getLogger(CallTransferHandler.class); + + /** + * The <tt>CallConference</tt> into which the dropped callees are to be + * invited. + */ + private final CallConference callConference; + + /** + * Initializes a new <tt>CallTransferHandler</tt> instance which is to + * invite dropped callees to a telephony conference specified by a specific + * <tt>Call</tt> which participates in it. + * + * @param call the <tt>Call</tt> which specifies the telephony conference to + * which dropped callees are to be invited + */ + public CallTransferHandler(Call call) + { + this(call.getConference()); + } + + /** + * Initializes a new <tt>CallTransferHandler</tt> instance which is to + * invite dropped callees to a specific <tt>CallConference</tt>. + * + * @param callConference the <tt>CallConference</tt> to which dropped + * callees are to be invited + */ + public CallTransferHandler(CallConference callConference) + { + this.callConference = callConference; + } + + /** + * Indicates whether a component will accept an import of the given + * set of data flavors prior to actually attempting to import it. We return + * <tt>true</tt> to indicate that the transfer with at least one of the + * given flavors would work and <tt>false</tt> to reject the transfer. + * <p> + * @param comp component + * @param flavor the data formats available + * @return true if the data can be inserted into the component, false + * otherwise + * @throws NullPointerException if <code>support</code> is {@code null} + */ + @Override + public boolean canImport(JComponent comp, DataFlavor[] flavor) + { + for (DataFlavor f : flavor) + { + if (f.equals(DataFlavor.stringFlavor) + || f.equals(uiContactDataFlavor)) + { + return (comp instanceof JPanel); + } + } + return false; + } + + /** + * Handles transfers to the chat panel from the clip board or a + * DND drop operation. The <tt>Transferable</tt> parameter contains the + * data that needs to be imported. + * <p> + * @param comp the component to receive the transfer; + * @param t the data to import + * @return true if the data was inserted into the component and false + * otherwise + */ + @Override + public boolean importData(JComponent comp, Transferable t) + { + String callee = null; + ProtocolProviderService provider = null; + + if (t.isDataFlavorSupported(uiContactDataFlavor)) + { + Object o = null; + + try + { + o = t.getTransferData(uiContactDataFlavor); + } + catch (UnsupportedFlavorException e) + { + if (logger.isDebugEnabled()) + logger.debug("Failed to drop meta contact.", e); + } + catch (IOException e) + { + if (logger.isDebugEnabled()) + logger.debug("Failed to drop meta contact.", e); + } + + if (o instanceof ContactNode) + { + UIContact uiContact = ((ContactNode) o).getContactDescriptor(); + Iterator<UIContactDetail> contactDetails + = uiContact + .getContactDetailsForOperationSet( + OperationSetBasicTelephony.class) + .iterator(); + + while (contactDetails.hasNext()) + { + UIContactDetail detail = contactDetails.next(); + ProtocolProviderService detailProvider + = detail.getPreferredProtocolProvider( + OperationSetBasicTelephony.class); + + if (detailProvider != null) + { + /* + * Currently for videobridge conferences we only support + * adding contacts via the account with the videobridge + */ + if (callConference.isJitsiVideobridge()) + { + for (Call call : callConference.getCalls()) + { + if (detailProvider == call.getProtocolProvider()) + { + callee = detail.getAddress(); + provider = detailProvider; + break; + } + } + } + else + { + callee = detail.getAddress(); + provider = detailProvider; + break; + } + } + } + + if (callee == null) + { + /* + * It turns out that the error message to be reported would + * like to display information about the account which could + * not add the dropped callee to the telephony conference. + * Unfortunately, a telephony conference may have multiple + * accounts involved. Anyway, choose the first account + * involved in the telephony conference. + */ + ProtocolProviderService callProvider + = callConference.getCalls().get(0) + .getProtocolProvider(); + + ResourceManagementService resources + = GuiActivator.getResources(); + AccountID accountID = callProvider.getAccountID(); + + new ErrorDialog(null, + resources.getI18NString("service.gui.ERROR"), + resources.getI18NString( + "service.gui.CALL_NOT_SUPPORTING_PARTICIPANT", + new String[] + { + accountID.getService(), + accountID.getUserID(), + uiContact.getDisplayName() + })) + .showDialog(); + } + } + } + else if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) + { + InputContext inputContext = comp.getInputContext(); + + if (inputContext != null) + inputContext.endComposition(); + + try + { + BufferedReader reader + = new BufferedReader( + DataFlavor.stringFlavor.getReaderForText(t)); + + try + { + String line; + StringBuilder calleeBuilder = new StringBuilder(); + + while ((line = reader.readLine()) != null) + calleeBuilder.append(line); + + callee = calleeBuilder.toString(); + /* + * The value of the local variable provider will be null + * because we have a String only and hence we have no + * associated ProtocolProviderService. + * CallManager.inviteToConferenceCall will accept it. + */ + } + finally + { + reader.close(); + } + } + catch (UnsupportedFlavorException e) + { + if (logger.isDebugEnabled()) + logger.debug("Failed to drop string.", e); + } + catch (IOException e) + { + if (logger.isDebugEnabled()) + logger.debug("Failed to drop string.", e); + } + } + + if (callee == null) + return false; + else + { + Map<ProtocolProviderService, List<String>> callees + = new HashMap<ProtocolProviderService, List<String>>(); + + callees.put(provider, Arrays.asList(callee)); + CallManager.inviteToConferenceCall(callees, callConference); + + return true; + } + } +} 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 3e823ba..c56a415 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 @@ -1,4 +1,4 @@ -/*
+/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd @@ -15,176 +15,176 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.java.sip.communicator.impl.gui.main.call;
-
-import java.awt.*;
-import java.util.*;
-import java.util.List;
-
-/**
- * Implements a <tt>LayoutManager</tt> for the full-screen <tt>Call</tt>
- * display.
- *
- * @author Lyubomir Marinov
- */
-public class FullScreenLayout
- implements LayoutManager
-{
- public static final String CENTER = "CENTER";
-
- public static final String SOUTH = "SOUTH";
-
- private Component center;
-
- /**
- * The indicator which determines whether {@link #south} is to be laid out
- * on top of {@link #center} i.e. as an overlay.
- */
- private final boolean overlay;
-
- 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, 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))
- center = comp;
- else if (SOUTH.equals(name))
- south = comp;
- }
-
- /**
- * Gets a <tt>List</tt> of the <tt>Component</tt>s to be laid out by this
- * <tt>LayoutManager</tt> i.e. the non-<tt>null</tt> of {@link #center}
- * and {@link #south}.
- *
- * @return a <tt>List</tt> of the <tt>Component</tt>s to be laid out by this
- * <tt>LayoutManager</tt>
- */
- private List<Component> getLayoutComponents()
- {
- List<Component> layoutComponents = new ArrayList<Component>(2);
-
- if (center != null)
- layoutComponents.add(center);
- if (south != null)
- layoutComponents.add(south);
- 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;
- int southHeight;
-
- if (south == null)
- {
- southWidth = southHeight = 0;
- }
- else
- {
- Dimension southSize = south.getPreferredSize();
-
- southWidth = southSize.width;
- southHeight = southSize.height;
- }
-
- Dimension parentSize = parent.getSize();
-
- if (center != null)
- {
- /*
- * 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 + yGap;
-
- center.setBounds(
- 0,
- 0,
- parentSize.width,
- parentSize.height - yOffset);
- }
- if (south != null)
- {
- south.setBounds(
- (parentSize.width - southWidth) / 2,
- parentSize.height - southHeight,
- southWidth,
- southHeight);
- }
- }
-
- public Dimension minimumLayoutSize(Container parent)
- {
- List<Component> components = getLayoutComponents();
- Dimension size = new Dimension(0, 0);
-
- for (Component component : components)
- {
- Dimension componentSize = component.getMinimumSize();
-
- size.width = Math.max(size.width, componentSize.width);
- if (overlay)
- size.height = Math.max(size.height, componentSize.height);
- else
- size.height += componentSize.height;
- }
- return size;
- }
-
- public Dimension preferredLayoutSize(Container parent)
- {
- List<Component> components = getLayoutComponents();
- Dimension size = new Dimension(0, 0);
-
- for (Component component : components)
- {
- Dimension componentSize = component.getPreferredSize();
-
- size.width = Math.max(size.width, componentSize.width);
- if (overlay)
- size.height = Math.max(size.height, componentSize.height);
- else
- size.height += componentSize.height;
- }
- return size;
- }
-
- public void removeLayoutComponent(Component comp)
- {
- if (comp.equals(center))
- center = null;
- else if (comp.equals(south))
- south = null;
- }
-}
+package net.java.sip.communicator.impl.gui.main.call; + +import java.awt.*; +import java.util.*; +import java.util.List; + +/** + * Implements a <tt>LayoutManager</tt> for the full-screen <tt>Call</tt> + * display. + * + * @author Lyubomir Marinov + */ +public class FullScreenLayout + implements LayoutManager +{ + public static final String CENTER = "CENTER"; + + public static final String SOUTH = "SOUTH"; + + private Component center; + + /** + * The indicator which determines whether {@link #south} is to be laid out + * on top of {@link #center} i.e. as an overlay. + */ + private final boolean overlay; + + 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, 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)) + center = comp; + else if (SOUTH.equals(name)) + south = comp; + } + + /** + * Gets a <tt>List</tt> of the <tt>Component</tt>s to be laid out by this + * <tt>LayoutManager</tt> i.e. the non-<tt>null</tt> of {@link #center} + * and {@link #south}. + * + * @return a <tt>List</tt> of the <tt>Component</tt>s to be laid out by this + * <tt>LayoutManager</tt> + */ + private List<Component> getLayoutComponents() + { + List<Component> layoutComponents = new ArrayList<Component>(2); + + if (center != null) + layoutComponents.add(center); + if (south != null) + layoutComponents.add(south); + 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; + int southHeight; + + if (south == null) + { + southWidth = southHeight = 0; + } + else + { + Dimension southSize = south.getPreferredSize(); + + southWidth = southSize.width; + southHeight = southSize.height; + } + + Dimension parentSize = parent.getSize(); + + if (center != null) + { + /* + * 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 + yGap; + + center.setBounds( + 0, + 0, + parentSize.width, + parentSize.height - yOffset); + } + if (south != null) + { + south.setBounds( + (parentSize.width - southWidth) / 2, + parentSize.height - southHeight, + southWidth, + southHeight); + } + } + + public Dimension minimumLayoutSize(Container parent) + { + List<Component> components = getLayoutComponents(); + Dimension size = new Dimension(0, 0); + + for (Component component : components) + { + Dimension componentSize = component.getMinimumSize(); + + size.width = Math.max(size.width, componentSize.width); + if (overlay) + size.height = Math.max(size.height, componentSize.height); + else + size.height += componentSize.height; + } + return size; + } + + public Dimension preferredLayoutSize(Container parent) + { + List<Component> components = getLayoutComponents(); + Dimension size = new Dimension(0, 0); + + for (Component component : components) + { + Dimension componentSize = component.getPreferredSize(); + + size.width = Math.max(size.width, componentSize.width); + if (overlay) + size.height = Math.max(size.height, componentSize.height); + else + size.height += componentSize.height; + } + return size; + } + + public void removeLayoutComponent(Component comp) + { + if (comp.equals(center)) + center = null; + else if (comp.equals(south)) + south = null; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/PreCallDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/PreCallDialog.java index 76c4139..0d6206a 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/PreCallDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/PreCallDialog.java @@ -256,8 +256,12 @@ public abstract class PreCallDialog receivedCallWindow.setAlwaysOnTop(true); + // Register the JFrame so the dialog window is able to get dragged + // across the screen + ComponentMover.registerComponent(receivedCallWindow); + // prevents dialog window to get unwanted key events and when going - // on top on linux, it steals focus and if we are accidently + // on top on linux, it steals focus and if we are accidentally // writing something and pressing enter a call get answered receivedCallWindow.setFocusableWindowState(false); 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 2e2ed5b..b49e0a3 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 @@ -1,4 +1,4 @@ -/*
+/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd @@ -15,117 +15,117 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.java.sip.communicator.impl.gui.main.call;
-
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.skin.*;
-
-import org.jitsi.service.neomedia.*;
-
-/**
- * Base class for security panels that show encryption specific UI controls.
- *
- * @author Ingo Bauersachs
- */
-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.
- *
- * @param srtpControl the security controller that provides the information
- * to be shown on the UI
- * @return An instance of a {@link SecurityPanel} for the security
- * controller or an {@link TransparentPanel} if the controller is
- * unknown or does not have any controls to show.
- */
- public static SecurityPanel<?> create(
- SwingCallPeerRenderer peerRenderer,
- CallPeer callPeer,
- SrtpControl srtpControl)
- {
- if(srtpControl instanceof ZrtpControl)
- {
- return
- new ZrtpSecurityPanel(
- peerRenderer,
- callPeer,
- (ZrtpControl) srtpControl);
- }
- else
- {
- return
- new SecurityPanel<SrtpControl>(srtpControl)
- {
- public void loadSkin() {}
-
- @Override
- public void securityOn(CallPeerSecurityOnEvent evt) {}
-
- @Override
- public void securityOff(CallPeerSecurityOffEvent evt) {}
-
- @Override
- public void securityTimeout(
- CallPeerSecurityTimeoutEvent evt) {}
- };
- }
- }
-
- /**
- * 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 securityTimeout(CallPeerSecurityTimeoutEvent evt);
-}
+package net.java.sip.communicator.impl.gui.main.call; + +import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.skin.*; + +import org.jitsi.service.neomedia.*; + +/** + * Base class for security panels that show encryption specific UI controls. + * + * @author Ingo Bauersachs + */ +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. + * + * @param srtpControl the security controller that provides the information + * to be shown on the UI + * @return An instance of a {@link SecurityPanel} for the security + * controller or an {@link TransparentPanel} if the controller is + * unknown or does not have any controls to show. + */ + public static SecurityPanel<?> create( + SwingCallPeerRenderer peerRenderer, + CallPeer callPeer, + SrtpControl srtpControl) + { + if(srtpControl instanceof ZrtpControl) + { + return + new ZrtpSecurityPanel( + peerRenderer, + callPeer, + (ZrtpControl) srtpControl); + } + else + { + return + new SecurityPanel<SrtpControl>(srtpControl) + { + public void loadSkin() {} + + @Override + public void securityOn(CallPeerSecurityOnEvent evt) {} + + @Override + public void securityOff(CallPeerSecurityOffEvent evt) {} + + @Override + public void securityTimeout( + CallPeerSecurityTimeoutEvent evt) {} + }; + } + } + + /** + * 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 securityTimeout(CallPeerSecurityTimeoutEvent evt); +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java index f2f2bd2..982738b 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java @@ -1,4 +1,4 @@ -/*
+/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd @@ -15,140 +15,140 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.java.sip.communicator.impl.gui.main.call;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.util.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*;
-import net.java.sip.communicator.impl.gui.utils.*;
-import net.java.sip.communicator.service.contactsource.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * Represents a <tt>Dialog</tt> which allows specifying the target contact
- * address of a transfer-call operation.
- *
- * @author Yana Stamcheva
- */
-public class TransferCallDialog
- extends OneChoiceInviteDialog
-{
- /**
- * The peer to transfer.
- */
- private final CallPeer transferPeer;
-
- /**
- * Creates a <tt>TransferCallDialog</tt> by specifying the peer to transfer
- * @param peer the peer to transfer
- */
- public TransferCallDialog(final CallPeer peer)
- {
- super(GuiActivator.getResources()
- .getI18NString("service.gui.TRANSFER_CALL_TITLE"));
-
- this.transferPeer = peer;
-
- this.initContactListData(peer.getProtocolProvider());
-
- this.setInfoText(GuiActivator.getResources()
- .getI18NString("service.gui.TRANSFER_CALL_MSG"));
- this.setOkButtonText(GuiActivator.getResources()
- .getI18NString("service.gui.TRANSFER"));
-
- this.setMinimumSize(new Dimension(300, 300));
-
- addOkButtonListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- UIContact uiContact = getSelectedContact();
-
- if (uiContact != null)
- {
- transferToContact(uiContact);
- }
-
- setVisible(false);
- dispose();
- }
- });
- addCancelButtonListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- setVisible(false);
- dispose();
- }
- });
- }
-
- /**
- * Initializes contact list sources.
- */
- private void initContactSources()
- {
- DemuxContactSourceService demuxCSService
- = GuiActivator.getDemuxContactSourceService();
-
- // If the DemuxContactSourceService isn't registered we use the default
- // contact source set.
- if (demuxCSService == null)
- return;
-
- Iterator<UIContactSource> sourcesIter
- = new ArrayList<UIContactSource>(
- contactList.getContactSources()).iterator();
-
- contactList.removeAllContactSources();
-
- while (sourcesIter.hasNext())
- {
- ContactSourceService contactSource
- = sourcesIter.next().getContactSourceService();
-
- contactList.addContactSource(
- demuxCSService.createDemuxContactSource(contactSource));
- }
- }
-
- /**
- * Initializes the left contact list with the contacts that could be added
- * to the current chat session.
- *
- * @param protocolProvider the protocol provider from which to initialize
- * the contact list data
- */
- private void initContactListData(ProtocolProviderService protocolProvider)
- {
- initContactSources();
-
- contactList.addContactSource(
- new ProtocolContactSourceServiceImpl(
- protocolProvider, OperationSetBasicTelephony.class));
- contactList.addContactSource(
- new StringContactSourceServiceImpl(
- protocolProvider, OperationSetBasicTelephony.class));
-
- contactList.applyDefaultFilter();
- }
-
- /**
- * Transfer the transfer peer to the given <tt>UIContact</tt>.
- *
- * @param uiContact the contact to transfer to
- */
- private void transferToContact(UIContact uiContact)
- {
- UIContactDetail contactDetail = uiContact
- .getDefaultContactDetail(
- OperationSetBasicTelephony.class);
-
- CallManager.transferCall( transferPeer,
- contactDetail.getAddress());
- }
-}
+package net.java.sip.communicator.impl.gui.main.call; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*; +import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; + +/** + * Represents a <tt>Dialog</tt> which allows specifying the target contact + * address of a transfer-call operation. + * + * @author Yana Stamcheva + */ +public class TransferCallDialog + extends OneChoiceInviteDialog +{ + /** + * The peer to transfer. + */ + private final CallPeer transferPeer; + + /** + * Creates a <tt>TransferCallDialog</tt> by specifying the peer to transfer + * @param peer the peer to transfer + */ + public TransferCallDialog(final CallPeer peer) + { + super(GuiActivator.getResources() + .getI18NString("service.gui.TRANSFER_CALL_TITLE")); + + this.transferPeer = peer; + + this.initContactListData(peer.getProtocolProvider()); + + this.setInfoText(GuiActivator.getResources() + .getI18NString("service.gui.TRANSFER_CALL_MSG")); + this.setOkButtonText(GuiActivator.getResources() + .getI18NString("service.gui.TRANSFER")); + + this.setMinimumSize(new Dimension(300, 300)); + + addOkButtonListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + UIContact uiContact = getSelectedContact(); + + if (uiContact != null) + { + transferToContact(uiContact); + } + + setVisible(false); + dispose(); + } + }); + addCancelButtonListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + setVisible(false); + dispose(); + } + }); + } + + /** + * Initializes contact list sources. + */ + private void initContactSources() + { + DemuxContactSourceService demuxCSService + = GuiActivator.getDemuxContactSourceService(); + + // If the DemuxContactSourceService isn't registered we use the default + // contact source set. + if (demuxCSService == null) + return; + + Iterator<UIContactSource> sourcesIter + = new ArrayList<UIContactSource>( + contactList.getContactSources()).iterator(); + + contactList.removeAllContactSources(); + + while (sourcesIter.hasNext()) + { + ContactSourceService contactSource + = sourcesIter.next().getContactSourceService(); + + contactList.addContactSource( + demuxCSService.createDemuxContactSource(contactSource)); + } + } + + /** + * Initializes the left contact list with the contacts that could be added + * to the current chat session. + * + * @param protocolProvider the protocol provider from which to initialize + * the contact list data + */ + private void initContactListData(ProtocolProviderService protocolProvider) + { + initContactSources(); + + contactList.addContactSource( + new ProtocolContactSourceServiceImpl( + protocolProvider, OperationSetBasicTelephony.class)); + contactList.addContactSource( + new StringContactSourceServiceImpl( + protocolProvider, OperationSetBasicTelephony.class)); + + contactList.applyDefaultFilter(); + } + + /** + * Transfer the transfer peer to the given <tt>UIContact</tt>. + * + * @param uiContact the contact to transfer to + */ + private void transferToContact(UIContact uiContact) + { + UIContactDetail contactDetail = uiContact + .getDefaultContactDetail( + OperationSetBasicTelephony.class); + + CallManager.transferCall( transferPeer, + contactDetail.getAddress()); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java index 80eedc6..bb32858 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java @@ -1,4 +1,4 @@ -/*
+/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd @@ -15,570 +15,570 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.java.sip.communicator.impl.gui.main.call.conference;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.util.*;
-import java.util.List;
-
-import javax.swing.*;
-
-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.*;
-import net.java.sip.communicator.impl.gui.utils.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.service.contactsource.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * The invite dialog is the one shown when the user clicks on the conference
- * button in the chat toolbar.
- *
- * @author Yana Stamcheva
- * @author Lyubomir Marinov
- */
-public class ConferenceInviteDialog
- extends InviteDialog
-{
- /**
- * Serial version UID.
- */
- private static final long serialVersionUID = 0L;
-
- /**
- * The account selector box.
- */
- private final JComboBox accountSelectorBox = new JComboBox();
-
- /**
- * The last selected account.
- */
- private Object lastSelectedAccount;
-
- /**
- * The telephony conference into which this instance is to invite
- * participants.
- */
- private final CallConference conference;
-
- /**
- * The current provider contact source.
- */
- private ContactSourceService currentProviderContactSource;
-
- /**
- * The current string contact source.
- */
- private ContactSourceService currentStringContactSource;
-
- /**
- * The previously selected protocol provider, with which this dialog has
- * been instantiated.
- */
- private ProtocolProviderService preselectedProtocolProvider;
-
- /**
- * Indicates whether this conference invite dialog is associated with a
- * Jitsi Videobridge invite.
- */
- private final boolean isJitsiVideobridge;
-
- /**
- * Initializes a new <tt>ConferenceInviteDialog</tt> instance which is to
- * invite contacts/participants in a specific telephony conference.
- *
- * @param conference the telephony conference in which the new instance is
- * to invite contacts/participants
- */
- public ConferenceInviteDialog(
- CallConference conference,
- ProtocolProviderService preselectedProvider,
- List<ProtocolProviderService> protocolProviders,
- final boolean isJitsiVideobridge)
- {
- // Set the correct dialog title depending if we're going to create a
- // video bridge conference call
- super((isJitsiVideobridge
- ? GuiActivator.getResources()
- .getI18NString("service.gui.INVITE_CONTACT_TO_VIDEO_BRIDGE")
- : GuiActivator.getResources()
- .getI18NString("service.gui.INVITE_CONTACT_TO_CALL")),
- false);
-
- this.conference = conference;
- this.preselectedProtocolProvider = preselectedProvider;
- this.isJitsiVideobridge = isJitsiVideobridge;
-
- if (preselectedProtocolProvider == null)
- initAccountSelectorPanel(protocolProviders);
-
- // init the list, as we check whether features are supported
- // it may take some time if we have too much contacts
- SwingUtilities.invokeLater(new Runnable()
- {
- public void run()
- {
- initContactSources();
-
- // Initialize the list of contacts to select from.
- if (preselectedProtocolProvider != null)
- initContactListData(preselectedProtocolProvider);
- else
- initContactListData(
- (ProtocolProviderService) accountSelectorBox
- .getSelectedItem());
- }
- });
-
- this.addInviteButtonListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- Collection<UIContact> selectedContacts
- = destContactList.getContacts(null);
-
- if (selectedContacts != null && selectedContacts.size() > 0)
- {
- if (preselectedProtocolProvider == null)
- preselectedProtocolProvider
- = (ProtocolProviderService) accountSelectorBox
- .getSelectedItem();
-
- if (isJitsiVideobridge)
- inviteJitsiVideobridgeContacts( preselectedProtocolProvider,
- selectedContacts);
- else
- inviteContacts(selectedContacts);
-
- // Store the last used account in order to pre-select it
- // next time.
- ConfigurationUtils.setLastCallConferenceProvider(
- preselectedProtocolProvider);
-
- dispose();
- }
- else
- {
- // TODO: The underlying invite dialog should show a message
- // to the user that she should select at least two contacts
- // in order to create a conference.
- }
- }
- });
-
- this.addCancelButtonListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- dispose();
- }
- });
- }
-
- /**
- * Constructs the <tt>ConferenceInviteDialog</tt>.
- */
- public ConferenceInviteDialog()
- {
- this(null, null, null, false);
- }
-
- /**
- * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying an
- * already created conference. To use when inviting contacts to an existing
- * conference is needed.
- *
- * @param conference the existing <tt>CallConference</tt>
- */
- public ConferenceInviteDialog(CallConference conference)
- {
- this(conference, null, null, false);
- }
-
- /**
- * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying an
- * already created conference. To use when inviting contacts to an existing
- * conference is needed.
- *
- * @param conference the existing <tt>CallConference</tt>
- */
- public ConferenceInviteDialog(
- CallConference conference,
- ProtocolProviderService preselectedProtocolProvider,
- boolean isJitsiVideobridge)
- {
- this(conference, preselectedProtocolProvider, null, isJitsiVideobridge);
- }
-
- /**
- * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying a
- * preselected protocol provider to be used and if this is an invite for
- * a video bridge conference.
- *
- * @param protocolProviders the protocol providers list
- * @param isJitsiVideobridge <tt>true</tt> if this dialog should create a
- * conference through a Jitsi Videobridge; otherwise, <tt>false</tt>
- */
- public ConferenceInviteDialog(
- List<ProtocolProviderService> protocolProviders,
- boolean isJitsiVideobridge)
- {
- this(null, null, protocolProviders, isJitsiVideobridge);
- }
-
- /**
- * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying a
- * preselected protocol provider to be used and if this is an invite for
- * a video bridge conference.
- *
- * @param selectedConfProvider the preselected protocol provider
- * @param isJitsiVideobridge <tt>true</tt> if this dialog should create a
- * conference through a Jitsi Videobridge; otherwise, <tt>false</tt>
- */
- public ConferenceInviteDialog(
- ProtocolProviderService selectedConfProvider,
- boolean isJitsiVideobridge)
- {
- this(null, selectedConfProvider, null, isJitsiVideobridge);
- }
-
- /**
- * Initializes the account selector panel.
- *
- * @param protocolProviders the list of protocol providers we'd like to
- * show in the account selector box
- */
- private void initAccountSelectorPanel(
- List<ProtocolProviderService> protocolProviders)
- {
- JLabel accountSelectorLabel = new JLabel(
- GuiActivator.getResources().getI18NString("service.gui.CALL_VIA"));
-
- TransparentPanel accountSelectorPanel
- = new TransparentPanel(new BorderLayout());
-
- accountSelectorPanel.setBorder(
- BorderFactory.createEmptyBorder(5, 5, 5, 5));
- accountSelectorPanel.add(accountSelectorLabel, BorderLayout.WEST);
- accountSelectorPanel.add(accountSelectorBox, BorderLayout.CENTER);
-
- // Initialize the account selector box.
- if (protocolProviders != null && protocolProviders.size() > 0)
- this.initAccountListData(protocolProviders);
- else
- this.initAccountListData();
-
- this.accountSelectorBox.setRenderer(new DefaultListCellRenderer()
- {
- private static final long serialVersionUID = 0L;
-
- @Override
- public Component getListCellRendererComponent(JList list,
- Object value, int index, boolean isSelected,
- boolean cellHasFocus)
- {
- ProtocolProviderService protocolProvider
- = (ProtocolProviderService) value;
-
- if (protocolProvider != null)
- {
- this.setText(
- protocolProvider.getAccountID().getDisplayName());
- this.setIcon(
- ImageLoader.getAccountStatusImage(protocolProvider));
- }
-
- return this;
- }
- });
-
- this.accountSelectorBox.addActionListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- Object accountSelectorBoxSelectedItem
- = accountSelectorBox.getSelectedItem();
-
- if (lastSelectedAccount == null
- || !lastSelectedAccount
- .equals(accountSelectorBoxSelectedItem))
- {
- lastSelectedAccount = accountSelectorBoxSelectedItem;
-
- initContactListData(
- (ProtocolProviderService) accountSelectorBox
- .getSelectedItem());
-
- if (isJitsiVideobridge)
- destContactList.removeAll();
- }
- }
- });
-
- this.getContentPane().add(accountSelectorPanel, BorderLayout.NORTH);
- }
-
- /**
- * Initializes the account selector box with the given list of
- * <tt>ProtocolProviderService</tt>-s.
- *
- * @param protocolProviders the list of <tt>ProtocolProviderService</tt>-s
- * we'd like to show in the account selector box
- */
- private void initAccountListData(
- List<ProtocolProviderService> protocolProviders)
- {
- Iterator<ProtocolProviderService> providersIter
- = protocolProviders.iterator();
-
- while (providersIter.hasNext())
- {
- ProtocolProviderService protocolProvider
- = providersIter.next();
-
- accountSelectorBox.addItem(protocolProvider);
- }
-
- if (accountSelectorBox.getItemCount() > 0)
- accountSelectorBox.setSelectedIndex(0);
- }
-
- /**
- * Initializes the account list.
- */
- private void initAccountListData()
- {
- Iterator<ProtocolProviderService> protocolProviders
- = GuiActivator.getUIService().getMainFrame().getProtocolProviders();
-
- while(protocolProviders.hasNext())
- {
- ProtocolProviderService protocolProvider
- = protocolProviders.next();
- OperationSet opSet
- = protocolProvider.getOperationSet(
- OperationSetTelephonyConferencing.class);
-
- if ((opSet != null) && protocolProvider.isRegistered())
- accountSelectorBox.addItem(protocolProvider);
- }
-
- // Try to select the last used account if available.
- ProtocolProviderService pps
- = ConfigurationUtils.getLastCallConferenceProvider();
-
- if (pps == null && conference != null)
- {
- /*
- * Pick up the first account from the ones participating in the
- * associated telephony conference which supports
- * OperationSetTelephonyConferencing.
- */
- for (Call call : conference.getCalls())
- {
- ProtocolProviderService callPps = call.getProtocolProvider();
-
- if (callPps.getOperationSet(
- OperationSetTelephonyConferencing.class)
- != null)
- {
- pps = callPps;
- break;
- }
- }
- }
-
- if (pps != null)
- accountSelectorBox.setSelectedItem(pps);
- else if (accountSelectorBox.getItemCount() > 0)
- accountSelectorBox.setSelectedIndex(0);
- }
-
- /**
- * Initializes contact list sources.
- */
- private void initContactSources()
- {
- DemuxContactSourceService demuxCSService
- = GuiActivator.getDemuxContactSourceService();
-
- // If the DemuxContactSourceService isn't registered we use the default
- // contact source set.
- if (demuxCSService == null)
- return;
-
- Iterator<UIContactSource> sourcesIter
- = new ArrayList<UIContactSource>(
- srcContactList.getContactSources()).iterator();
-
- srcContactList.removeAllContactSources();
-
- while (sourcesIter.hasNext())
- {
- ContactSourceService contactSource
- = sourcesIter.next().getContactSourceService();
-
- srcContactList.addContactSource(
- demuxCSService.createDemuxContactSource(contactSource));
- }
- }
-
- /**
- * Initializes the left contact list with the contacts that could be added
- * to the current chat session.
- * @param protocolProvider the protocol provider from which to initialize
- * the contact list data
- */
- private void initContactListData(ProtocolProviderService protocolProvider)
- {
- this.setCurrentProvider(protocolProvider);
-
- Iterator<UIContactSource> sourcesIter
- = new ArrayList<UIContactSource>(
- srcContactList.getContactSources()).iterator();
-
- while (sourcesIter.hasNext())
- {
- ContactSourceService contactSource
- = sourcesIter.next().getContactSourceService();
-
- if (contactSource instanceof ProtocolAwareContactSourceService)
- {
- ((ProtocolAwareContactSourceService) contactSource)
- .setPreferredProtocolProvider(
- OperationSetBasicTelephony.class, protocolProvider);
- }
- }
-
- srcContactList.removeContactSource(currentProviderContactSource);
- srcContactList.removeContactSource(currentStringContactSource);
-
- currentProviderContactSource
- = new ProtocolContactSourceServiceImpl(
- protocolProvider,
- OperationSetBasicTelephony.class);
- currentStringContactSource
- = new StringContactSourceServiceImpl(
- protocolProvider,
- OperationSetBasicTelephony.class);
-
- srcContactList.addContactSource(currentProviderContactSource);
- srcContactList.addContactSource(currentStringContactSource);
-
- srcContactList.applyDefaultFilter();
- }
-
- /**
- * Invites the contacts to the chat conference.
- *
- * @param contacts the list of contacts to invite
- */
- private void inviteContacts(Collection<UIContact> contacts)
- {
- ProtocolProviderService selectedProvider;
- Map<ProtocolProviderService, List<String>> selectedProviderCallees
- = new HashMap<ProtocolProviderService, List<String>>();
- List<String> callees;
-
- Iterator<UIContact> contactsIter = contacts.iterator();
-
- while (contactsIter.hasNext())
- {
- UIContact uiContact = contactsIter.next();
-
- Iterator<UIContactDetail> contactDetailsIter = uiContact
- .getContactDetailsForOperationSet(
- OperationSetBasicTelephony.class).iterator();
-
- // We invite the first protocol contact that corresponds to the
- // invite provider.
- if (contactDetailsIter.hasNext())
- {
- UIContactDetail inviteDetail = contactDetailsIter.next();
- selectedProvider = inviteDetail
- .getPreferredProtocolProvider(
- OperationSetBasicTelephony.class);
-
- if (selectedProvider == null)
- {
- selectedProvider
- = (ProtocolProviderService)
- accountSelectorBox.getSelectedItem();
- }
-
- if(selectedProvider != null
- && selectedProviderCallees.get(selectedProvider) != null)
- {
- callees = selectedProviderCallees.get(selectedProvider);
- }
- else
- {
- callees = new ArrayList<String>();
- }
-
- callees.add(inviteDetail.getAddress());
- selectedProviderCallees.put(selectedProvider, callees);
- }
- }
-
- if(conference != null)
- {
- CallManager.inviteToConferenceCall(
- selectedProviderCallees,
- conference);
- }
- else
- {
- CallManager.createConferenceCall(selectedProviderCallees);
- }
- }
-
- /**
- * Invites the contacts to the chat conference.
- *
- * @param contacts the list of contacts to invite
- */
- private void inviteJitsiVideobridgeContacts(
- ProtocolProviderService preselectedProvider,
- Collection<UIContact> contacts)
- {
- List<String> callees = new ArrayList<String>();
-
- Iterator<UIContact> contactsIter = contacts.iterator();
-
- while (contactsIter.hasNext())
- {
- UIContact uiContact = contactsIter.next();
-
- Iterator<UIContactDetail> contactDetailsIter = uiContact
- .getContactDetailsForOperationSet(
- OperationSetBasicTelephony.class).iterator();
-
- // We invite the first protocol contact that corresponds to the
- // invite provider.
- if (contactDetailsIter.hasNext())
- {
- UIContactDetail inviteDetail = contactDetailsIter.next();
-
- callees.add(inviteDetail.getAddress());
- }
- }
-
- if(conference != null)
- {
- CallManager.inviteToJitsiVideobridgeConfCall(
- callees.toArray(new String[callees.size()]),
- conference.getCalls().get(0));
- }
- else
- {
- CallManager.createJitsiVideobridgeConfCall(
- preselectedProvider,
- callees.toArray(new String[callees.size()]));
- }
- }
-}
+package net.java.sip.communicator.impl.gui.main.call.conference; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import java.util.List; + +import javax.swing.*; + +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.*; +import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + +/** + * The invite dialog is the one shown when the user clicks on the conference + * button in the chat toolbar. + * + * @author Yana Stamcheva + * @author Lyubomir Marinov + */ +public class ConferenceInviteDialog + extends InviteDialog +{ + /** + * Serial version UID. + */ + private static final long serialVersionUID = 0L; + + /** + * The account selector box. + */ + private final JComboBox accountSelectorBox = new JComboBox(); + + /** + * The last selected account. + */ + private Object lastSelectedAccount; + + /** + * The telephony conference into which this instance is to invite + * participants. + */ + private final CallConference conference; + + /** + * The current provider contact source. + */ + private ContactSourceService currentProviderContactSource; + + /** + * The current string contact source. + */ + private ContactSourceService currentStringContactSource; + + /** + * The previously selected protocol provider, with which this dialog has + * been instantiated. + */ + private ProtocolProviderService preselectedProtocolProvider; + + /** + * Indicates whether this conference invite dialog is associated with a + * Jitsi Videobridge invite. + */ + private final boolean isJitsiVideobridge; + + /** + * Initializes a new <tt>ConferenceInviteDialog</tt> instance which is to + * invite contacts/participants in a specific telephony conference. + * + * @param conference the telephony conference in which the new instance is + * to invite contacts/participants + */ + public ConferenceInviteDialog( + CallConference conference, + ProtocolProviderService preselectedProvider, + List<ProtocolProviderService> protocolProviders, + final boolean isJitsiVideobridge) + { + // Set the correct dialog title depending if we're going to create a + // video bridge conference call + super((isJitsiVideobridge + ? GuiActivator.getResources() + .getI18NString("service.gui.INVITE_CONTACT_TO_VIDEO_BRIDGE") + : GuiActivator.getResources() + .getI18NString("service.gui.INVITE_CONTACT_TO_CALL")), + false); + + this.conference = conference; + this.preselectedProtocolProvider = preselectedProvider; + this.isJitsiVideobridge = isJitsiVideobridge; + + if (preselectedProtocolProvider == null) + initAccountSelectorPanel(protocolProviders); + + // init the list, as we check whether features are supported + // it may take some time if we have too much contacts + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + initContactSources(); + + // Initialize the list of contacts to select from. + if (preselectedProtocolProvider != null) + initContactListData(preselectedProtocolProvider); + else + initContactListData( + (ProtocolProviderService) accountSelectorBox + .getSelectedItem()); + } + }); + + this.addInviteButtonListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + Collection<UIContact> selectedContacts + = destContactList.getContacts(null); + + if (selectedContacts != null && selectedContacts.size() > 0) + { + if (preselectedProtocolProvider == null) + preselectedProtocolProvider + = (ProtocolProviderService) accountSelectorBox + .getSelectedItem(); + + if (isJitsiVideobridge) + inviteJitsiVideobridgeContacts( preselectedProtocolProvider, + selectedContacts); + else + inviteContacts(selectedContacts); + + // Store the last used account in order to pre-select it + // next time. + ConfigurationUtils.setLastCallConferenceProvider( + preselectedProtocolProvider); + + dispose(); + } + else + { + // TODO: The underlying invite dialog should show a message + // to the user that she should select at least two contacts + // in order to create a conference. + } + } + }); + + this.addCancelButtonListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + dispose(); + } + }); + } + + /** + * Constructs the <tt>ConferenceInviteDialog</tt>. + */ + public ConferenceInviteDialog() + { + this(null, null, null, false); + } + + /** + * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying an + * already created conference. To use when inviting contacts to an existing + * conference is needed. + * + * @param conference the existing <tt>CallConference</tt> + */ + public ConferenceInviteDialog(CallConference conference) + { + this(conference, null, null, false); + } + + /** + * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying an + * already created conference. To use when inviting contacts to an existing + * conference is needed. + * + * @param conference the existing <tt>CallConference</tt> + */ + public ConferenceInviteDialog( + CallConference conference, + ProtocolProviderService preselectedProtocolProvider, + boolean isJitsiVideobridge) + { + this(conference, preselectedProtocolProvider, null, isJitsiVideobridge); + } + + /** + * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying a + * preselected protocol provider to be used and if this is an invite for + * a video bridge conference. + * + * @param protocolProviders the protocol providers list + * @param isJitsiVideobridge <tt>true</tt> if this dialog should create a + * conference through a Jitsi Videobridge; otherwise, <tt>false</tt> + */ + public ConferenceInviteDialog( + List<ProtocolProviderService> protocolProviders, + boolean isJitsiVideobridge) + { + this(null, null, protocolProviders, isJitsiVideobridge); + } + + /** + * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying a + * preselected protocol provider to be used and if this is an invite for + * a video bridge conference. + * + * @param selectedConfProvider the preselected protocol provider + * @param isJitsiVideobridge <tt>true</tt> if this dialog should create a + * conference through a Jitsi Videobridge; otherwise, <tt>false</tt> + */ + public ConferenceInviteDialog( + ProtocolProviderService selectedConfProvider, + boolean isJitsiVideobridge) + { + this(null, selectedConfProvider, null, isJitsiVideobridge); + } + + /** + * Initializes the account selector panel. + * + * @param protocolProviders the list of protocol providers we'd like to + * show in the account selector box + */ + private void initAccountSelectorPanel( + List<ProtocolProviderService> protocolProviders) + { + JLabel accountSelectorLabel = new JLabel( + GuiActivator.getResources().getI18NString("service.gui.CALL_VIA")); + + TransparentPanel accountSelectorPanel + = new TransparentPanel(new BorderLayout()); + + accountSelectorPanel.setBorder( + BorderFactory.createEmptyBorder(5, 5, 5, 5)); + accountSelectorPanel.add(accountSelectorLabel, BorderLayout.WEST); + accountSelectorPanel.add(accountSelectorBox, BorderLayout.CENTER); + + // Initialize the account selector box. + if (protocolProviders != null && protocolProviders.size() > 0) + this.initAccountListData(protocolProviders); + else + this.initAccountListData(); + + this.accountSelectorBox.setRenderer(new DefaultListCellRenderer() + { + private static final long serialVersionUID = 0L; + + @Override + public Component getListCellRendererComponent(JList list, + Object value, int index, boolean isSelected, + boolean cellHasFocus) + { + ProtocolProviderService protocolProvider + = (ProtocolProviderService) value; + + if (protocolProvider != null) + { + this.setText( + protocolProvider.getAccountID().getDisplayName()); + this.setIcon( + ImageLoader.getAccountStatusImage(protocolProvider)); + } + + return this; + } + }); + + this.accountSelectorBox.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + Object accountSelectorBoxSelectedItem + = accountSelectorBox.getSelectedItem(); + + if (lastSelectedAccount == null + || !lastSelectedAccount + .equals(accountSelectorBoxSelectedItem)) + { + lastSelectedAccount = accountSelectorBoxSelectedItem; + + initContactListData( + (ProtocolProviderService) accountSelectorBox + .getSelectedItem()); + + if (isJitsiVideobridge) + destContactList.removeAll(); + } + } + }); + + this.getContentPane().add(accountSelectorPanel, BorderLayout.NORTH); + } + + /** + * Initializes the account selector box with the given list of + * <tt>ProtocolProviderService</tt>-s. + * + * @param protocolProviders the list of <tt>ProtocolProviderService</tt>-s + * we'd like to show in the account selector box + */ + private void initAccountListData( + List<ProtocolProviderService> protocolProviders) + { + Iterator<ProtocolProviderService> providersIter + = protocolProviders.iterator(); + + while (providersIter.hasNext()) + { + ProtocolProviderService protocolProvider + = providersIter.next(); + + accountSelectorBox.addItem(protocolProvider); + } + + if (accountSelectorBox.getItemCount() > 0) + accountSelectorBox.setSelectedIndex(0); + } + + /** + * Initializes the account list. + */ + private void initAccountListData() + { + Iterator<ProtocolProviderService> protocolProviders + = GuiActivator.getUIService().getMainFrame().getProtocolProviders(); + + while(protocolProviders.hasNext()) + { + ProtocolProviderService protocolProvider + = protocolProviders.next(); + OperationSet opSet + = protocolProvider.getOperationSet( + OperationSetTelephonyConferencing.class); + + if ((opSet != null) && protocolProvider.isRegistered()) + accountSelectorBox.addItem(protocolProvider); + } + + // Try to select the last used account if available. + ProtocolProviderService pps + = ConfigurationUtils.getLastCallConferenceProvider(); + + if (pps == null && conference != null) + { + /* + * Pick up the first account from the ones participating in the + * associated telephony conference which supports + * OperationSetTelephonyConferencing. + */ + for (Call call : conference.getCalls()) + { + ProtocolProviderService callPps = call.getProtocolProvider(); + + if (callPps.getOperationSet( + OperationSetTelephonyConferencing.class) + != null) + { + pps = callPps; + break; + } + } + } + + if (pps != null) + accountSelectorBox.setSelectedItem(pps); + else if (accountSelectorBox.getItemCount() > 0) + accountSelectorBox.setSelectedIndex(0); + } + + /** + * Initializes contact list sources. + */ + private void initContactSources() + { + DemuxContactSourceService demuxCSService + = GuiActivator.getDemuxContactSourceService(); + + // If the DemuxContactSourceService isn't registered we use the default + // contact source set. + if (demuxCSService == null) + return; + + Iterator<UIContactSource> sourcesIter + = new ArrayList<UIContactSource>( + srcContactList.getContactSources()).iterator(); + + srcContactList.removeAllContactSources(); + + while (sourcesIter.hasNext()) + { + ContactSourceService contactSource + = sourcesIter.next().getContactSourceService(); + + srcContactList.addContactSource( + demuxCSService.createDemuxContactSource(contactSource)); + } + } + + /** + * Initializes the left contact list with the contacts that could be added + * to the current chat session. + * @param protocolProvider the protocol provider from which to initialize + * the contact list data + */ + private void initContactListData(ProtocolProviderService protocolProvider) + { + this.setCurrentProvider(protocolProvider); + + Iterator<UIContactSource> sourcesIter + = new ArrayList<UIContactSource>( + srcContactList.getContactSources()).iterator(); + + while (sourcesIter.hasNext()) + { + ContactSourceService contactSource + = sourcesIter.next().getContactSourceService(); + + if (contactSource instanceof ProtocolAwareContactSourceService) + { + ((ProtocolAwareContactSourceService) contactSource) + .setPreferredProtocolProvider( + OperationSetBasicTelephony.class, protocolProvider); + } + } + + srcContactList.removeContactSource(currentProviderContactSource); + srcContactList.removeContactSource(currentStringContactSource); + + currentProviderContactSource + = new ProtocolContactSourceServiceImpl( + protocolProvider, + OperationSetBasicTelephony.class); + currentStringContactSource + = new StringContactSourceServiceImpl( + protocolProvider, + OperationSetBasicTelephony.class); + + srcContactList.addContactSource(currentProviderContactSource); + srcContactList.addContactSource(currentStringContactSource); + + srcContactList.applyDefaultFilter(); + } + + /** + * Invites the contacts to the chat conference. + * + * @param contacts the list of contacts to invite + */ + private void inviteContacts(Collection<UIContact> contacts) + { + ProtocolProviderService selectedProvider; + Map<ProtocolProviderService, List<String>> selectedProviderCallees + = new HashMap<ProtocolProviderService, List<String>>(); + List<String> callees; + + Iterator<UIContact> contactsIter = contacts.iterator(); + + while (contactsIter.hasNext()) + { + UIContact uiContact = contactsIter.next(); + + Iterator<UIContactDetail> contactDetailsIter = uiContact + .getContactDetailsForOperationSet( + OperationSetBasicTelephony.class).iterator(); + + // We invite the first protocol contact that corresponds to the + // invite provider. + if (contactDetailsIter.hasNext()) + { + UIContactDetail inviteDetail = contactDetailsIter.next(); + selectedProvider = inviteDetail + .getPreferredProtocolProvider( + OperationSetBasicTelephony.class); + + if (selectedProvider == null) + { + selectedProvider + = (ProtocolProviderService) + accountSelectorBox.getSelectedItem(); + } + + if(selectedProvider != null + && selectedProviderCallees.get(selectedProvider) != null) + { + callees = selectedProviderCallees.get(selectedProvider); + } + else + { + callees = new ArrayList<String>(); + } + + callees.add(inviteDetail.getAddress()); + selectedProviderCallees.put(selectedProvider, callees); + } + } + + if(conference != null) + { + CallManager.inviteToConferenceCall( + selectedProviderCallees, + conference); + } + else + { + CallManager.createConferenceCall(selectedProviderCallees); + } + } + + /** + * Invites the contacts to the chat conference. + * + * @param contacts the list of contacts to invite + */ + private void inviteJitsiVideobridgeContacts( + ProtocolProviderService preselectedProvider, + Collection<UIContact> contacts) + { + List<String> callees = new ArrayList<String>(); + + Iterator<UIContact> contactsIter = contacts.iterator(); + + while (contactsIter.hasNext()) + { + UIContact uiContact = contactsIter.next(); + + Iterator<UIContactDetail> contactDetailsIter = uiContact + .getContactDetailsForOperationSet( + OperationSetBasicTelephony.class).iterator(); + + // We invite the first protocol contact that corresponds to the + // invite provider. + if (contactDetailsIter.hasNext()) + { + UIContactDetail inviteDetail = contactDetailsIter.next(); + + callees.add(inviteDetail.getAddress()); + } + } + + if(conference != null) + { + CallManager.inviteToJitsiVideobridgeConfCall( + callees.toArray(new String[callees.size()]), + conference.getCalls().get(0)); + } + else + { + CallManager.createJitsiVideobridgeConfCall( + preselectedProvider, + callees.toArray(new String[callees.size()])); + } + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java index 0dd6ef5..07c653d 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java @@ -1,4 +1,4 @@ -/*
+/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd @@ -15,1395 +15,1395 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.java.sip.communicator.impl.gui.main.call.conference;
-
-import java.awt.*;
-import java.util.*;
-import java.util.List;
-
-import javax.swing.*;
-
-import net.java.sip.communicator.impl.gui.main.call.*;
-import net.java.sip.communicator.impl.gui.utils.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.plugin.desktoputil.TransparentPanel;
-
-import org.jitsi.util.swing.*;
-
-/**
- * Extends <tt>BasicConferenceCallPanel</tt> to implement a user interface
- * <tt>Component</tt> which depicts a <tt>CallConference</tt> with audio and
- * video and is contained in a <tt>CallPanel</tt>.
- *
- * @author Yana Stamcheva
- * @author Lyubomir Marinov
- */
-public class VideoConferenceCallPanel
- extends BasicConferenceCallPanel
-{
- /**
- * The <tt>Logger</tt> used by the <tt>VideoConferenceCallPanel</tt> class
- * and its instances for logging output.
- */
- private static final Logger logger
- = Logger.getLogger(VideoConferenceCallPanel.class);
-
- /**
- * The compile-time flag which indicates whether each video displayed by
- * <tt>VideoConferenceCallPanel</tt> is to be depicted with an associated
- * tool bar showing information and controls related to the (local or
- * remote) peer sending the respective video.
- */
- private static final boolean SHOW_TOOLBARS = true;
-
- /**
- * The facility which aids this instance with the video-related information.
- */
- private final UIVideoHandler2 uiVideoHandler;
-
- /**
- * The <tt>Observer</tt> which listens to {@link #uiVideoHandler} about
- * changes in the video-related information.
- */
- private final Observer uiVideoHandlerObserver
- = new Observer()
- {
- public void update(Observable o, Object arg)
- {
- updateViewFromModel();
- }
- };
-
- /**
- * The <tt>VideoContainer</tt> which occupies this whole <tt>Component</tt>
- * and arranges the visual <tt>Component</tt>s displaying the video
- * streaming between the local peer/user and the remote peer(s).
- */
- private final VideoContainer videoContainer;
-
- /**
- * The set of visual <tt>Component</tt>s displaying video streaming between
- * the local peer/user and the remote peers which are depicted by this
- * instance.
- */
- private final Set<Component> videos = new HashSet<Component>();
-
- /**
- * The thumbnail container.
- */
- private final ThumbnailConferenceCallPanel thumbnailContainer;
-
- private final JPanel thumbnailPanel;
-
- /**
- * Initializes a new <tt>VideoConferenceCallPanel</tt> instance which is to
- * be used by a specific <tt>CallPanel</tt> to depict a specific
- * <tt>CallConference</tt>. The new instance will depict both the
- * audio-related and the video-related information.
- *
- * @param callPanel the <tt>CallPanel</tt> which will use the new instance
- * to depict the specified <tt>CallConference</tt>.
- * @param callConference the <tt>CallConference</tt> to be depicted by the
- * new instance
- * @param uiVideoHandler the utility which is to aid the new instance in
- * dealing with the video-related information
- */
- public VideoConferenceCallPanel(
- CallPanel callPanel,
- CallConference callConference,
- UIVideoHandler2 uiVideoHandler)
- {
- super(callPanel, callConference);
-
- this.uiVideoHandler = uiVideoHandler;
-
- thumbnailPanel = new JPanel(new BorderLayout());
- thumbnailContainer
- = new ThumbnailConferenceCallPanel( callPanel,
- callConference,
- uiVideoHandler);
-
- videoContainer = createVideoContainer();
-
- /*
- * Our user interface hierarchy has been initialized so we are ready to
- * begin receiving events warranting updates of this view from its
- * model.
- */
- uiVideoHandler.addObserver(uiVideoHandlerObserver);
-
- /*
- * Notify the super that this instance has completed its initialization
- * and the view that it implements is ready to be updated from the
- * model.
- */
- initializeComplete();
- }
-
- private void addConferenceMemberContainers(
- ConferenceParticipantContainer cpc)
- {
- List<ConferenceParticipantContainer> cmcs
- = cpc.conferenceMemberContainers;
-
- if ((cmcs != null) && !cmcs.isEmpty())
- {
- for (ConferenceParticipantContainer cmc : cmcs)
- {
- if (!cmc.toBeRemoved)
- {
- videoContainer.add(
- cmc.getComponent(),
- VideoLayout.CENTER_REMOTE);
- }
- }
- }
- }
-
- private Component createDefaultPhotoPanel(Call call)
- {
- OperationSetServerStoredAccountInfo accountInfo
- = call.getProtocolProvider().getOperationSet(
- OperationSetServerStoredAccountInfo.class);
- ImageIcon photoLabelIcon = null;
-
- if (accountInfo != null)
- {
- byte[] accountImage = AccountInfoUtils.getImage(accountInfo);
-
- // do not set empty images
- if ((accountImage != null) && (accountImage.length > 0))
- photoLabelIcon = new ImageIcon(accountImage);
- }
- if (photoLabelIcon == null)
- {
- photoLabelIcon
- = new ImageIcon(
- ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO));
- }
-
- return createDefaultPhotoPanel(photoLabelIcon);
- }
-
- private Component createDefaultPhotoPanel(CallPeer callPeer)
- {
- byte[] peerImage = CallManager.getPeerImage(callPeer);
- ImageIcon photoLabelIcon
- = (peerImage == null)
- ? new ImageIcon(
- ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO))
- : new ImageIcon(peerImage);
-
- return createDefaultPhotoPanel(photoLabelIcon);
- }
-
- private Component createDefaultPhotoPanel(ConferenceMember conferenceMember)
- {
- return
- createDefaultPhotoPanel(
- new ImageIcon(
- ImageLoader.getImage(
- ImageLoader.DEFAULT_USER_PHOTO)));
- }
-
- /**
- * Creates a new <tt>Component</tt> which is to display a specific
- * <tt>ImageIcon</tt> representing the photo of a participant in a call.
- *
- * @param photoLabelIcon the <tt>ImageIcon</tt> which represents the photo
- * of a participant in a call and which is to be displayed by the new
- * <tt>Component</tt>
- * @return a new <tt>Component</tt> which displays the specified
- * <tt>photoLabelIcon</tt>
- */
- private Component createDefaultPhotoPanel(ImageIcon photoLabelIcon)
- {
- JLabel photoLabel = new JLabel();
-
- photoLabel.setIcon(photoLabelIcon);
-
- @SuppressWarnings("serial")
- JPanel photoPanel
- = new TransparentPanel(new GridBagLayout())
- {
- /**
- * @{inheritDoc}
- */
- @Override
- public void paintComponent(Graphics g)
- {
- super.paintComponent(g);
-
- g = g.create();
- try
- {
- AntialiasingManager.activateAntialiasing(g);
-
- g.setColor(Color.GRAY);
- g.fillRoundRect(
- 0, 0, this.getWidth(), this.getHeight(),
- 6, 6);
- }
- finally
- {
- g.dispose();
- }
- }
- };
-
- photoPanel.setPreferredSize(new Dimension(320, 240));
-
- GridBagConstraints photoPanelConstraints = new GridBagConstraints();
-
- photoPanelConstraints.anchor = GridBagConstraints.CENTER;
- photoPanelConstraints.fill = GridBagConstraints.NONE;
- photoPanel.add(photoLabel, photoPanelConstraints);
-
- return photoPanel;
- }
-
- /**
- * Initializes a new <tt>VideoContainer</tt> instance which is to contain
- * the visual/video <tt>Component</tt>s of the telephony conference depicted
- * by this instance.
- */
- private VideoContainer createVideoContainer()
- {
- VideoContainer videoContainer = new VideoContainer(null, true);
-
- thumbnailPanel.setBackground(Color.DARK_GRAY);
- thumbnailPanel.add(thumbnailContainer, BorderLayout.NORTH);
-
- add(thumbnailPanel, BorderLayout.EAST);
- add(videoContainer, BorderLayout.CENTER);
-
- return videoContainer;
- }
-
- /**
- * Shows/hides the participants thumbnails list.
- *
- * @param show <tt>true</tt> to show the participants list, <tt>false</tt>
- * to hide it
- */
- public void showThumbnailsList(boolean show)
- {
- thumbnailPanel.setVisible(show);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void dispose()
- {
- try
- {
- uiVideoHandler.deleteObserver(uiVideoHandlerObserver);
- }
- finally
- {
- super.dispose();
- }
- }
-
- /**
- * Determines whether a specific <tt>ConferenceMember</tt> represents the
- * same conference participant as a specific <tt>CallPeer</tt>. If the
- * specified <tt>conferenceMember</tt> is <tt>null</tt>, returns
- * <tt>true</tt>. Otherwise, determines whether the addresses of the
- * specified <tt>conferenceMember</tt> and the specified <tt>callPeer</tt>
- * identify one and the same entity.
- *
- * @param conferenceMember the <tt>ConferenceMember</tt> to be checked
- * whether is represents the same conference participant as the specified
- * <tt>callPeer</tt>. If it is <tt>null</tt>, <tt>true</tt> is returned.
- * @param callPeer the <tt>CallPeer</tt> to be checked whether it represents
- * the same conference participant as the specified
- * <tt>conferenceMember</tt>
- * @return <tt>true</tt> if the specified <tt>conferenceMember</tt> and the
- * specified <tt>callPeer</tt> represent the same conference participant or
- * the specified <tt>conferenceMember</tt> is <tt>null</tt>; otherwise,
- * <tt>false</tt>
- */
- private boolean isConferenceMemberCallPeer(
- ConferenceMember conferenceMember,
- CallPeer callPeer)
- {
- return
- (conferenceMember == null)
- ? true
- : CallManager.addressesAreEqual(
- conferenceMember.getAddress(),
- callPeer.getAddress());
- }
-
- /**
- * Determines whether a specific <tt>ConferenceMember</tt> represents the
- * local peer/user. Since this instance depicts a whole telephony
- * conference, the local peer/user may be participating with multiple
- * <tt>Call</tt>s in it. The <tt>Call</tt>s may be through different
- * (local) accounts. That's why the implementation determines whether the
- * address of the specified <tt>conferenceMember</tt> identifies the address
- * of a (local) accounts involved in the telephony conference depicted by
- * this instance.
- *
- * @param conferenceMember the <tt>ConferenceMember</tt> to be checked
- * whether it represents the local peer/user
- * @return <tt>true</tt> if the specified <tt>conferenceMember</tt>
- * represents the local peer/user; otherwise, <tt>false</tt>
- */
- private boolean isConferenceMemberLocalUser(
- ConferenceMember conferenceMember)
- {
- String address = conferenceMember.getAddress();
-
- for (Call call : callConference.getCalls())
- {
- if (CallManager.addressesAreEqual(
- address,
- call.getProtocolProvider().getAccountID()
- .getAccountAddress()))
- {
- return true;
- }
- }
- return false;
- }
-
- private void removeConferenceMemberContainers(
- ConferenceParticipantContainer cpc,
- boolean all)
- {
- List<ConferenceParticipantContainer> cmcs
- = cpc.conferenceMemberContainers;
-
- if ((cmcs != null) && !cmcs.isEmpty())
- {
- Iterator<ConferenceParticipantContainer> i = cmcs.iterator();
-
- while (i.hasNext())
- {
- ConferenceParticipantContainer cmc = i.next();
-
- if (all || cmc.toBeRemoved)
- {
- i.remove();
-
- videoContainer.remove(cmc.getComponent());
- cmc.dispose();
- }
- }
- }
- }
-
- /**
- * Updates the <tt>ConferenceParticipantContainer</tt>s which depict the
- * <tt>ConferenceMember</tt>s of the <tt>CallPeer</tt> depicted by a
- * specific <tt>ConferenceParticipantContainer</tt>.
- *
- * @param cpc the <tt>ConferenceParticipantContainer</tt> which depicts the
- * <tt>CallPeer</tt> whose <tt>ConferenceMember</tt>s are to be depicted
- * @param videos the visual <tt>Component</tt>s displaying video streaming
- * from the remote peer (represented by <tt>cpc</tt>) to the local peer/user
- * @param videoTelephony the <tt>OperationSetVideoTelephony</tt> which
- * retrieved the specified <tt>videos</tt> from the <tt>CallPeer</tt>
- * depicted by <tt>cpc</tt>. While the <tt>CallPeer</tt> could be queried
- * for it, such a query would waste more resources at run time given that
- * the invoker has it already.
- */
- private void updateConferenceMemberContainers(
- ConferenceParticipantContainer cpc,
- List<Component> videos,
- OperationSetVideoTelephony videoTelephony)
- {
- CallPeer callPeer = (CallPeer) cpc.getParticipant();
- List<ConferenceParticipantContainer> cmcs
- = cpc.conferenceMemberContainers;
-
- /*
- * Invalidate all conferenceMemberContainers. Then validate which of
- * them are to remain and which of them are to really be removed
- * later on.
- */
- if (cmcs != null)
- {
- for (ConferenceParticipantContainer cmc : cmcs)
- cmc.toBeRemoved = true;
- }
-
- /*
- * Depict the remote videos. They may or may not be associated with
- * ConferenceMembers so the ConferenceMembers which have no
- * associated videos will be depicted afterwards.
- */
- if (videos != null)
- {
- Component video = cpc.getVideo();
-
- for (Component conferenceMemberVideo : videos)
- {
- /*
- * One of the remote videos is already used to depict the
- * callPeer.
- */
- if (conferenceMemberVideo == video)
- continue;
-
- boolean addNewConferenceParticipantContainer = true;
- ConferenceMember conferenceMember
- = videoTelephony.getConferenceMember(
- callPeer,
- conferenceMemberVideo);
-
- if (cmcs == null)
- {
- cmcs = new LinkedList<ConferenceParticipantContainer>();
- cpc.conferenceMemberContainers = cmcs;
- }
- else
- {
- for (ConferenceParticipantContainer cmc : cmcs)
- {
- Object cmcParticipant = cmc.getParticipant();
-
- if (conferenceMember == null)
- {
- if (cmcParticipant == callPeer)
- {
- Component cmcVideo = cmc.getVideo();
-
- if (cmcVideo == null)
- {
- cmc.setVideo(conferenceMemberVideo);
- cmc.toBeRemoved = false;
- addNewConferenceParticipantContainer
- = false;
- break;
- }
- else if (cmcVideo == conferenceMemberVideo)
- {
- cmc.toBeRemoved = false;
- addNewConferenceParticipantContainer
- = false;
- break;
- }
- }
- }
- else if (cmcParticipant == conferenceMember)
- {
- cmc.setVideo(conferenceMemberVideo);
- cmc.toBeRemoved = false;
- addNewConferenceParticipantContainer = false;
- break;
- }
- }
- }
-
- if (addNewConferenceParticipantContainer)
- {
- ConferenceParticipantContainer cmc
- = (conferenceMember == null)
- ? new ConferenceParticipantContainer(
- callPeer,
- conferenceMemberVideo)
- : new ConferenceParticipantContainer(
- conferenceMember,
- conferenceMemberVideo);
-
- cmcs.add(cmc);
- }
- }
- }
-
- /*
- * Depict the ConferenceMembers which have not been depicted yet.
- * They have no associated videos.
- */
- List<ConferenceMember> conferenceMembers
- = callPeer.getConferenceMembers();
-
- if (!conferenceMembers.isEmpty())
- {
- if (cmcs == null)
- {
- cmcs = new LinkedList<ConferenceParticipantContainer>();
- cpc.conferenceMemberContainers = cmcs;
- }
- for (ConferenceMember conferenceMember : conferenceMembers)
- {
- /*
- * If the callPeer reports itself as a ConferenceMember, then
- * we've already depicted it with cpc.
- */
- if (isConferenceMemberCallPeer(conferenceMember, callPeer))
- continue;
- /*
- * If the callPeer reports the local peer/user as a
- * ConferenceMember, then we've already depicted it.
- */
- if (isConferenceMemberLocalUser(conferenceMember))
- continue;
-
- boolean addNewConferenceParticipantContainer = true;
-
- for (ConferenceParticipantContainer cmc : cmcs)
- {
- if (cmc.getParticipant() == conferenceMember)
- {
- /*
- * It is possible to have a ConferenceMember who is
- * sending video but we just do not have the SSRC of
- * that video to associate the video with the
- * ConferenceMember. In such a case, we may be depicting
- * the ConferenceMember twice: once with video without a
- * ConferenceMember and once with a ConferenceMember
- * without video. This will surely be the case at the
- * time of this writing with non-focus participants in a
- * telephony conference hosted on a Jitsi Videobridge.
- * Such a display is undesirable. If the
- * conferenceMember is known to send video, we will not
- * display it until we associated it with a video. This
- * way, if a ConferenceMember is not sending video, we
- * will depict it and we can be sure that no video
- * without a ConferenceMember association will be
- * depicting it a second time.
- */
- if (cmc.toBeRemoved
- && !conferenceMember
- .getVideoStatus()
- .allowsSending())
- {
- cmc.setVideo(null);
- cmc.toBeRemoved = false;
- }
- addNewConferenceParticipantContainer = false;
- break;
- }
- }
-
- if (addNewConferenceParticipantContainer)
- {
- ConferenceParticipantContainer cmc
- = new ConferenceParticipantContainer(
- conferenceMember,
- null);
-
- cmcs.add(cmc);
- }
- }
- }
-
- if ((cmcs != null) && !cmcs.isEmpty())
- {
- removeConferenceMemberContainers(cpc, false);
- /*
- * If cpc is already added to the user interface hierarchy of this
- * instance, then it was there before the update procedure and it
- * was determined to be appropriate to continue to depict its model.
- * Consequently, its Component will be neither added to (because it
- * was already added) nor removed from the user interface hierarchy
- * of this instance. That's why we have make sure that the
- * Components of its conferenceMemberContainers are also added to
- * the user interface.
- */
- if (UIVideoHandler2.isAncestor(this, cpc.getComponent()))
- addConferenceMemberContainers(cpc);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected ConferenceCallPeerRenderer updateViewFromModel(
- ConferenceCallPeerRenderer callPeerPanel,
- CallPeer callPeer)
- {
- if (callPeer == null)
- {
- /*
- * The local peer/user will be represented by a Call which has a
- * CallPeer who provides local video. However, if the user has
- * selected to hide the local video, the local peer/user will not be
- * represented at all.
- */
- Component video = null;
-
- if (uiVideoHandler.isLocalVideoVisible())
- {
- for (Call aCall : callConference.getCalls())
- {
- Iterator<? extends CallPeer> callPeerIter
- = aCall.getCallPeers();
- OperationSetVideoTelephony videoTelephony
- = aCall.getProtocolProvider().getOperationSet(
- OperationSetVideoTelephony.class);
-
- while (callPeerIter.hasNext())
- {
- callPeer = callPeerIter.next();
-
- if (videoTelephony != null)
- {
- try
- {
- video
- = videoTelephony.getLocalVisualComponent(
- callPeer);
- }
- catch (OperationFailedException ofe)
- {
- logger.error(
- "Failed to retrieve the local video"
- + " for display",
- ofe);
- }
- if (video != null)
- break;
- }
- }
- if (video != null)
- break;
- }
- }
-
- if (callPeer == null)
- callPeerPanel = null;
- else
- {
- Call call = callPeer.getCall();
-
- if (callPeerPanel instanceof ConferenceParticipantContainer)
- {
- ConferenceParticipantContainer cpc
- = (ConferenceParticipantContainer) callPeerPanel;
-
- if (cpc.getParticipant() == call)
- cpc.setVideo(video);
- else
- callPeerPanel = null;
- }
- else
- callPeerPanel = null;
- if (callPeerPanel == null)
- {
- callPeerPanel
- = new ConferenceParticipantContainer(call, video);
- }
- }
- }
- else
- {
- /*
- * The specified callPeer will be represented by one of its remote
- * videos which is not associated with a ConferenceMember or is
- * associated with a ConferenceMember representing the callPeer
- * itself.
- */
- OperationSetVideoTelephony videoTelephony
- = callPeer.getProtocolProvider().getOperationSet(
- OperationSetVideoTelephony.class);
- List<Component> videos = null;
- Component video = null;
-
- if (videoTelephony != null)
- {
- videos = videoTelephony.getVisualComponents(callPeer);
- if ((videos != null) && !videos.isEmpty())
- {
- for (Component aVideo : videos)
- {
- ConferenceMember conferenceMember
- = videoTelephony.getConferenceMember(
- callPeer,
- aVideo);
-
- if (isConferenceMemberCallPeer(
- conferenceMember,
- callPeer))
- {
- video = aVideo;
- break;
- }
- }
- }
- }
-
- ConferenceParticipantContainer cpc = null;
-
- if (callPeerPanel instanceof ConferenceParticipantContainer)
- {
- cpc = (ConferenceParticipantContainer) callPeerPanel;
- if (cpc.getParticipant() == callPeer)
- cpc.setVideo(video);
- else
- cpc = null;
- }
- if (cpc == null)
- cpc = new ConferenceParticipantContainer(callPeer, video);
- callPeerPanel = cpc;
-
- // Update the conferenceMemberContainers of the cpc.
- updateConferenceMemberContainers(cpc, videos, videoTelephony);
- }
- return callPeerPanel;
- }
-
- /**
- * {@inheritDoc}
- *
- * If {@link #SHOW_TOOLBARS} is <tt>false</tt>, disables the use of
- * <tt>ConferenceParticipantContainer</tt>. A reason for such a value of
- * <tt>SHOW_TOOLBARS</tt> may be that the functionality implemented in the
- * model may not fully support mapping of visual <tt>Component</tt>s
- * displaying video to telephony conference participants (e.g. in telephony
- * conferences utilizing the Jitsi Videobridge server-side technology). In
- * such a case displays the videos only, does not map videos to participants
- * and does not display participants who do not have videos.
- */
- @Override
- protected void updateViewFromModelInEventDispatchThread()
- {
- if (SHOW_TOOLBARS)
- {
- super.updateViewFromModelInEventDispatchThread();
- return;
- }
-
- /*
- * Determine the set of visual Components displaying video streaming
- * between the local peer/user and the remote peers which are to be
- * depicted by this instance.
- */
- Component localVideo = null;
- Set<Component> videos = new HashSet<Component>();
-
- for (Call call : callConference.getCalls())
- {
- OperationSetVideoTelephony videoTelephony
- = call.getProtocolProvider().getOperationSet(
- OperationSetVideoTelephony.class);
-
- if (videoTelephony == null)
- continue;
-
- Iterator<? extends CallPeer> callPeerIter = call.getCallPeers();
-
- while (callPeerIter.hasNext())
- {
- CallPeer callPeer = callPeerIter.next();
-
- /*
- * TODO VideoConferenceCallPanel respects
- * UIVideoHandler2.isLocalVideoVisible() in order to react to
- * the associated button at the bottom of the CallPanel.
- * However, it does not add a close button on top of the local
- * video in contrast to OneToOneCallPeerPanel. Overall, the
- * result is questionable.
- */
- if (uiVideoHandler.isLocalVideoVisible()
- && (localVideo == null))
- {
- try
- {
- localVideo
- = videoTelephony.getLocalVisualComponent(callPeer);
- }
- catch (OperationFailedException ofe)
- {
- /*
- * We'll just try to get the local video through another
- * CallPeer then.
- */
- }
- if (localVideo != null)
- videos.add(localVideo);
- }
-
- List<Component> callPeerRemoteVideos
- = videoTelephony.getVisualComponents(callPeer);
-
- videos.addAll(callPeerRemoteVideos);
- }
- }
-
- /*
- * Remove the Components of this view which are no longer present in the
- * model.
- */
- Iterator<Component> thisVideoIter = this.videos.iterator();
-
- while (thisVideoIter.hasNext())
- {
- Component thisVideo = thisVideoIter.next();
-
- if (!videos.contains(thisVideo))
- {
- thisVideoIter.remove();
- videoContainer.remove(thisVideo);
- }
-
- /*
- * If a video is known to be depicted by this view and is still
- * present in the model, then we could remove it from the set of
- * videos present in the model in order to prevent going through the
- * procedure of adding it to this view. However, we choose to play
- * on the safe side.
- */
- }
-
- /*
- * Add the Components of the model which are not depicted by this view.
- */
- for (Component video : videos)
- {
- if (!UIVideoHandler2.isAncestor(videoContainer, video))
- {
- this.videos.add(video);
- videoContainer.add(
- video,
- (video == localVideo)
- ? VideoLayout.LOCAL
- : VideoLayout.CENTER_REMOTE);
- }
- }
- }
-
- @Override
- protected void viewForModelAdded(
- ConferenceCallPeerRenderer callPeerPanel,
- CallPeer callPeer)
- {
- videoContainer.add(
- callPeerPanel.getComponent(),
- VideoLayout.CENTER_REMOTE);
- if ((callPeer != null)
- && (callPeerPanel instanceof ConferenceParticipantContainer))
- {
- addConferenceMemberContainers(
- (ConferenceParticipantContainer) callPeerPanel);
- }
- }
-
- @Override
- protected void viewForModelRemoved(
- ConferenceCallPeerRenderer callPeerPanel,
- CallPeer callPeer)
- {
- videoContainer.remove(callPeerPanel.getComponent());
- if ((callPeer != null)
- && (callPeerPanel instanceof ConferenceParticipantContainer))
- {
- removeConferenceMemberContainers(
- (ConferenceParticipantContainer) callPeerPanel,
- true);
- }
- }
-
- /**
- * Implements an AWT <tt>Component</tt> which contains the user interface
- * elements depicting a specific participant in the telephony conference
- * depicted by a <tt>VideoConferenceCallPanel</tt>.
- */
- private class ConferenceParticipantContainer
- extends TransparentPanel
- implements ConferenceCallPeerRenderer
- {
- /**
- * The list of <tt>ConferenceParticipantContainer</tt>s which represent
- * the <tt>ConferenceMember</tt>s of the participant represented by this
- * instance. Since a <tt>CallPeer</tt> may send the local peer/user
- * multiple videos without providing a way to associate a
- * ConferenceMember with each one of them, the list may contain
- * <tt>ConferenceParticipantContainer</tt>s which do not represent a
- * specific <tt>ConferenceMember</tt> instance but rather a video sent
- * by a <tt>CallPeer</tt> to the local peer/user which looks like (in
- * the terms of <tt>VideoConferenceCallPanel) a member of a conference
- * organized by the <tt>CallPeer</tt> in question.
- * <p>
- * Implements a state which is private to
- * <tt>VideoConferenceCallPanel</tt> and is of no concern to
- * <tt>ConferenceParticipantContainer</tt>.
- * </p>
- */
- List<ConferenceParticipantContainer> conferenceMemberContainers;
-
- /**
- * The indicator which determines whether this instance is to be removed
- * because it has become out-of-date, obsolete, unnecessary.
- * <p>
- * Implements a state which is private to
- * <tt>VideoConferenceCallPanel</tt> and is of no concern to
- * <tt>ConferenceParticipantContainer</tt>.
- * </p>
- */
- boolean toBeRemoved;
-
- /**
- * The <tt>BasicConferenceParticipantPanel</tt> which is displayed at
- * the bottom of this instance, bellow the {@link #video} (i.e.
- * {@link #videoContainer}) and is referred to as the tool bar.
- */
- private final BasicConferenceParticipantPanel<?> toolBar;
-
- /**
- * The visual <tt>Component</tt>, if any, displaying video which is
- * depicted by this instance.
- */
- private Component video;
-
- /**
- * The <tt>VideoContainer</tt> which lays out the video depicted by this
- * instance i.e. {@link #video}.
- */
- private final VideoContainer videoContainer;
-
- /**
- * The <tt>CallPeer</tt> associated with this container, if it has been
- * created to represent a <tt>CallPeer</tt>.
- */
- private CallPeer callPeer;
-
- /**
- * The <tt>conferenceMember</tt> associated with this container, if it
- * has been created to represent a <tt>conferenceMember</tt>.
- */
- private ConferenceMember conferenceMember;
-
- /**
- * Indicates that this container contains information for the local
- * user.
- */
- private boolean isLocalUser;
-
- /**
- * Initializes a new <tt>ConferenceParticipantContainer</tt> instance
- * which is to depict the local peer/user.
- *
- * @param call a <tt>Call</tt> which is to provide information about the
- * local peer/user
- * @param video the visual <tt>Component</tt>, if any, displaying the
- * video streaming from the local peer/user to the remote peer(s)
- */
- public ConferenceParticipantContainer(Call call, Component video)
- {
- this(
- createDefaultPhotoPanel(call),
- video,
- new ConferencePeerPanel(
- VideoConferenceCallPanel.this,
- call,
- true),
- null, null, true);
- }
-
- public ConferenceParticipantContainer(
- CallPeer callPeer,
- Component video)
- {
- this( createDefaultPhotoPanel(callPeer),
- video,
- new ConferencePeerPanel(
- VideoConferenceCallPanel.this,
- callPeer,
- true),
- callPeer, null, false);
- }
-
- private ConferenceParticipantContainer(
- Component noVideo,
- Component video,
- BasicConferenceParticipantPanel<?> toolBar,
- CallPeer callPeer,
- ConferenceMember conferenceMember,
- boolean isLocalUser)
- {
- super(new BorderLayout());
-
- this.callPeer = callPeer;
- this.conferenceMember = conferenceMember;
- this.isLocalUser = isLocalUser;
-
- videoContainer = new VideoContainer(noVideo, false);
- add(videoContainer, BorderLayout.CENTER);
-
- this.toolBar = toolBar;
- if (this.toolBar != null)
- add(this.toolBar, BorderLayout.SOUTH);
-
- if (video != null)
- {
- setVideo(video);
- }
- else
- setVisible(false);
- }
-
- public ConferenceParticipantContainer(
- ConferenceMember conferenceMember,
- Component video)
- {
- this(
- createDefaultPhotoPanel(conferenceMember),
- video,
- new ConferenceMemberPanel(
- VideoConferenceCallPanel.this,
- conferenceMember,
- true),
- null, conferenceMember, false);
- }
-
- public void dispose()
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.dispose();
-
- // Dispose of the conferenceMemberContainers if any.
- /*
- * XXX The field conferenceMemberContainers implements a state
- * private to VideoConferenceCallPanel which the latter makes sure
- * to access on the AWT event dispatching thread only. Since we are
- * going out of our way here to help VideoConferenceCallPanel,
- * ensure that the mentioned synchronization rule is not violated.
- */
- CallManager.assertIsEventDispatchingThread();
- if (conferenceMemberContainers != null)
- {
- for (ConferenceParticipantContainer cmc
- : conferenceMemberContainers)
- {
- cmc.dispose();
- }
- }
- }
-
- public CallPanel getCallPanel()
- {
- return getCallRenderer().getCallContainer();
- }
-
- public SwingCallRenderer getCallRenderer()
- {
- return VideoConferenceCallPanel.this;
- }
-
- public Component getComponent()
- {
- return this;
- }
-
- private ConferenceCallPeerRenderer
- getConferenceCallPeerRendererDelegate()
- {
- return
- (toolBar instanceof ConferenceCallPeerRenderer)
- ? (ConferenceCallPeerRenderer) toolBar
- : null;
- }
-
- /**
- * Gets the conference participant depicted by this instance.
- *
- * @return the conference participant depicted by this instance
- */
- public Object getParticipant()
- {
- return (toolBar == null) ? null : toolBar.getParticipant();
- }
-
- public Component getVideo()
- {
- return video;
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only. Otherwise, returns <tt>false</tt>.
- */
- public boolean isLocalVideoVisible()
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- return (delegate == null) ? false : delegate.isLocalVideoVisible();
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void printDTMFTone(char dtmfChar)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.printDTMFTone(dtmfChar);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void securityNegotiationStarted(
- CallPeerSecurityNegotiationStartedEvent ev)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.securityNegotiationStarted(ev);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void securityOff(CallPeerSecurityOffEvent ev)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.securityOff(ev);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void securityOn(CallPeerSecurityOnEvent ev)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.securityOn(ev);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void securityPending()
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.securityPending();
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void securityTimeout(CallPeerSecurityTimeoutEvent ev)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.securityTimeout(ev);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setErrorReason(String reason)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setErrorReason(reason);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setLocalVideoVisible(boolean visible)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setLocalVideoVisible(visible);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setMute(boolean mute)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setMute(mute);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setOnHold(boolean onHold)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setOnHold(onHold);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setPeerImage(byte[] image)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setPeerImage(image);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setPeerName(String name)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setPeerName(name);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setPeerState(
- CallPeerState oldState,
- CallPeerState newState,
- String stateString)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setPeerState(oldState, newState, stateString);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setSecurityPanelVisible(boolean visible)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setSecurityPanelVisible(visible);
- }
-
- /**
- * Sets the visual <tt>Component</tt> displaying the video associated
- * with the participant depicted by this instance.
- *
- * @param video the visual <tt>Component</tt> displaying video which is
- * to be associated with the participant depicted by this instance
- */
- void setVideo(Component video)
- {
- if (this.video != video)
- {
- if (this.video != null)
- videoContainer.remove(this.video);
-
- this.video = video;
-
- if (this.video != null)
- {
- setVisible(true);
- videoContainer.add(this.video, VideoLayout.CENTER_REMOTE);
- }
- else
- setVisible(false);
-
- // Update thumbnails container according to video status.
- if (thumbnailContainer != null)
- {
- if (conferenceMember != null)
- thumbnailContainer
- .updateThumbnail(conferenceMember, (video != null));
- else if (callPeer != null)
- thumbnailContainer
- .updateThumbnail(callPeer, (video != null));
- else if (isLocalUser)
- thumbnailContainer
- .updateThumbnail((video != null));
- }
- }
- }
- }
-}
+package net.java.sip.communicator.impl.gui.main.call.conference; + +import java.awt.*; +import java.util.*; +import java.util.List; + +import javax.swing.*; + +import net.java.sip.communicator.impl.gui.main.call.*; +import net.java.sip.communicator.impl.gui.utils.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; +import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.plugin.desktoputil.TransparentPanel; + +import org.jitsi.util.swing.*; + +/** + * Extends <tt>BasicConferenceCallPanel</tt> to implement a user interface + * <tt>Component</tt> which depicts a <tt>CallConference</tt> with audio and + * video and is contained in a <tt>CallPanel</tt>. + * + * @author Yana Stamcheva + * @author Lyubomir Marinov + */ +public class VideoConferenceCallPanel + extends BasicConferenceCallPanel +{ + /** + * The <tt>Logger</tt> used by the <tt>VideoConferenceCallPanel</tt> class + * and its instances for logging output. + */ + private static final Logger logger + = Logger.getLogger(VideoConferenceCallPanel.class); + + /** + * The compile-time flag which indicates whether each video displayed by + * <tt>VideoConferenceCallPanel</tt> is to be depicted with an associated + * tool bar showing information and controls related to the (local or + * remote) peer sending the respective video. + */ + private static final boolean SHOW_TOOLBARS = true; + + /** + * The facility which aids this instance with the video-related information. + */ + private final UIVideoHandler2 uiVideoHandler; + + /** + * The <tt>Observer</tt> which listens to {@link #uiVideoHandler} about + * changes in the video-related information. + */ + private final Observer uiVideoHandlerObserver + = new Observer() + { + public void update(Observable o, Object arg) + { + updateViewFromModel(); + } + }; + + /** + * The <tt>VideoContainer</tt> which occupies this whole <tt>Component</tt> + * and arranges the visual <tt>Component</tt>s displaying the video + * streaming between the local peer/user and the remote peer(s). + */ + private final VideoContainer videoContainer; + + /** + * The set of visual <tt>Component</tt>s displaying video streaming between + * the local peer/user and the remote peers which are depicted by this + * instance. + */ + private final Set<Component> videos = new HashSet<Component>(); + + /** + * The thumbnail container. + */ + private final ThumbnailConferenceCallPanel thumbnailContainer; + + private final JPanel thumbnailPanel; + + /** + * Initializes a new <tt>VideoConferenceCallPanel</tt> instance which is to + * be used by a specific <tt>CallPanel</tt> to depict a specific + * <tt>CallConference</tt>. The new instance will depict both the + * audio-related and the video-related information. + * + * @param callPanel the <tt>CallPanel</tt> which will use the new instance + * to depict the specified <tt>CallConference</tt>. + * @param callConference the <tt>CallConference</tt> to be depicted by the + * new instance + * @param uiVideoHandler the utility which is to aid the new instance in + * dealing with the video-related information + */ + public VideoConferenceCallPanel( + CallPanel callPanel, + CallConference callConference, + UIVideoHandler2 uiVideoHandler) + { + super(callPanel, callConference); + + this.uiVideoHandler = uiVideoHandler; + + thumbnailPanel = new JPanel(new BorderLayout()); + thumbnailContainer + = new ThumbnailConferenceCallPanel( callPanel, + callConference, + uiVideoHandler); + + videoContainer = createVideoContainer(); + + /* + * Our user interface hierarchy has been initialized so we are ready to + * begin receiving events warranting updates of this view from its + * model. + */ + uiVideoHandler.addObserver(uiVideoHandlerObserver); + + /* + * Notify the super that this instance has completed its initialization + * and the view that it implements is ready to be updated from the + * model. + */ + initializeComplete(); + } + + private void addConferenceMemberContainers( + ConferenceParticipantContainer cpc) + { + List<ConferenceParticipantContainer> cmcs + = cpc.conferenceMemberContainers; + + if ((cmcs != null) && !cmcs.isEmpty()) + { + for (ConferenceParticipantContainer cmc : cmcs) + { + if (!cmc.toBeRemoved) + { + videoContainer.add( + cmc.getComponent(), + VideoLayout.CENTER_REMOTE); + } + } + } + } + + private Component createDefaultPhotoPanel(Call call) + { + OperationSetServerStoredAccountInfo accountInfo + = call.getProtocolProvider().getOperationSet( + OperationSetServerStoredAccountInfo.class); + ImageIcon photoLabelIcon = null; + + if (accountInfo != null) + { + byte[] accountImage = AccountInfoUtils.getImage(accountInfo); + + // do not set empty images + if ((accountImage != null) && (accountImage.length > 0)) + photoLabelIcon = new ImageIcon(accountImage); + } + if (photoLabelIcon == null) + { + photoLabelIcon + = new ImageIcon( + ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO)); + } + + return createDefaultPhotoPanel(photoLabelIcon); + } + + private Component createDefaultPhotoPanel(CallPeer callPeer) + { + byte[] peerImage = CallManager.getPeerImage(callPeer); + ImageIcon photoLabelIcon + = (peerImage == null) + ? new ImageIcon( + ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO)) + : new ImageIcon(peerImage); + + return createDefaultPhotoPanel(photoLabelIcon); + } + + private Component createDefaultPhotoPanel(ConferenceMember conferenceMember) + { + return + createDefaultPhotoPanel( + new ImageIcon( + ImageLoader.getImage( + ImageLoader.DEFAULT_USER_PHOTO))); + } + + /** + * Creates a new <tt>Component</tt> which is to display a specific + * <tt>ImageIcon</tt> representing the photo of a participant in a call. + * + * @param photoLabelIcon the <tt>ImageIcon</tt> which represents the photo + * of a participant in a call and which is to be displayed by the new + * <tt>Component</tt> + * @return a new <tt>Component</tt> which displays the specified + * <tt>photoLabelIcon</tt> + */ + private Component createDefaultPhotoPanel(ImageIcon photoLabelIcon) + { + JLabel photoLabel = new JLabel(); + + photoLabel.setIcon(photoLabelIcon); + + @SuppressWarnings("serial") + JPanel photoPanel + = new TransparentPanel(new GridBagLayout()) + { + /** + * @{inheritDoc} + */ + @Override + public void paintComponent(Graphics g) + { + super.paintComponent(g); + + g = g.create(); + try + { + AntialiasingManager.activateAntialiasing(g); + + g.setColor(Color.GRAY); + g.fillRoundRect( + 0, 0, this.getWidth(), this.getHeight(), + 6, 6); + } + finally + { + g.dispose(); + } + } + }; + + photoPanel.setPreferredSize(new Dimension(320, 240)); + + GridBagConstraints photoPanelConstraints = new GridBagConstraints(); + + photoPanelConstraints.anchor = GridBagConstraints.CENTER; + photoPanelConstraints.fill = GridBagConstraints.NONE; + photoPanel.add(photoLabel, photoPanelConstraints); + + return photoPanel; + } + + /** + * Initializes a new <tt>VideoContainer</tt> instance which is to contain + * the visual/video <tt>Component</tt>s of the telephony conference depicted + * by this instance. + */ + private VideoContainer createVideoContainer() + { + VideoContainer videoContainer = new VideoContainer(null, true); + + thumbnailPanel.setBackground(Color.DARK_GRAY); + thumbnailPanel.add(thumbnailContainer, BorderLayout.NORTH); + + add(thumbnailPanel, BorderLayout.EAST); + add(videoContainer, BorderLayout.CENTER); + + return videoContainer; + } + + /** + * Shows/hides the participants thumbnails list. + * + * @param show <tt>true</tt> to show the participants list, <tt>false</tt> + * to hide it + */ + public void showThumbnailsList(boolean show) + { + thumbnailPanel.setVisible(show); + } + + /** + * {@inheritDoc} + */ + @Override + public void dispose() + { + try + { + uiVideoHandler.deleteObserver(uiVideoHandlerObserver); + } + finally + { + super.dispose(); + } + } + + /** + * Determines whether a specific <tt>ConferenceMember</tt> represents the + * same conference participant as a specific <tt>CallPeer</tt>. If the + * specified <tt>conferenceMember</tt> is <tt>null</tt>, returns + * <tt>true</tt>. Otherwise, determines whether the addresses of the + * specified <tt>conferenceMember</tt> and the specified <tt>callPeer</tt> + * identify one and the same entity. + * + * @param conferenceMember the <tt>ConferenceMember</tt> to be checked + * whether is represents the same conference participant as the specified + * <tt>callPeer</tt>. If it is <tt>null</tt>, <tt>true</tt> is returned. + * @param callPeer the <tt>CallPeer</tt> to be checked whether it represents + * the same conference participant as the specified + * <tt>conferenceMember</tt> + * @return <tt>true</tt> if the specified <tt>conferenceMember</tt> and the + * specified <tt>callPeer</tt> represent the same conference participant or + * the specified <tt>conferenceMember</tt> is <tt>null</tt>; otherwise, + * <tt>false</tt> + */ + private boolean isConferenceMemberCallPeer( + ConferenceMember conferenceMember, + CallPeer callPeer) + { + return + (conferenceMember == null) + ? true + : CallManager.addressesAreEqual( + conferenceMember.getAddress(), + callPeer.getAddress()); + } + + /** + * Determines whether a specific <tt>ConferenceMember</tt> represents the + * local peer/user. Since this instance depicts a whole telephony + * conference, the local peer/user may be participating with multiple + * <tt>Call</tt>s in it. The <tt>Call</tt>s may be through different + * (local) accounts. That's why the implementation determines whether the + * address of the specified <tt>conferenceMember</tt> identifies the address + * of a (local) accounts involved in the telephony conference depicted by + * this instance. + * + * @param conferenceMember the <tt>ConferenceMember</tt> to be checked + * whether it represents the local peer/user + * @return <tt>true</tt> if the specified <tt>conferenceMember</tt> + * represents the local peer/user; otherwise, <tt>false</tt> + */ + private boolean isConferenceMemberLocalUser( + ConferenceMember conferenceMember) + { + String address = conferenceMember.getAddress(); + + for (Call call : callConference.getCalls()) + { + if (CallManager.addressesAreEqual( + address, + call.getProtocolProvider().getAccountID() + .getAccountAddress())) + { + return true; + } + } + return false; + } + + private void removeConferenceMemberContainers( + ConferenceParticipantContainer cpc, + boolean all) + { + List<ConferenceParticipantContainer> cmcs + = cpc.conferenceMemberContainers; + + if ((cmcs != null) && !cmcs.isEmpty()) + { + Iterator<ConferenceParticipantContainer> i = cmcs.iterator(); + + while (i.hasNext()) + { + ConferenceParticipantContainer cmc = i.next(); + + if (all || cmc.toBeRemoved) + { + i.remove(); + + videoContainer.remove(cmc.getComponent()); + cmc.dispose(); + } + } + } + } + + /** + * Updates the <tt>ConferenceParticipantContainer</tt>s which depict the + * <tt>ConferenceMember</tt>s of the <tt>CallPeer</tt> depicted by a + * specific <tt>ConferenceParticipantContainer</tt>. + * + * @param cpc the <tt>ConferenceParticipantContainer</tt> which depicts the + * <tt>CallPeer</tt> whose <tt>ConferenceMember</tt>s are to be depicted + * @param videos the visual <tt>Component</tt>s displaying video streaming + * from the remote peer (represented by <tt>cpc</tt>) to the local peer/user + * @param videoTelephony the <tt>OperationSetVideoTelephony</tt> which + * retrieved the specified <tt>videos</tt> from the <tt>CallPeer</tt> + * depicted by <tt>cpc</tt>. While the <tt>CallPeer</tt> could be queried + * for it, such a query would waste more resources at run time given that + * the invoker has it already. + */ + private void updateConferenceMemberContainers( + ConferenceParticipantContainer cpc, + List<Component> videos, + OperationSetVideoTelephony videoTelephony) + { + CallPeer callPeer = (CallPeer) cpc.getParticipant(); + List<ConferenceParticipantContainer> cmcs + = cpc.conferenceMemberContainers; + + /* + * Invalidate all conferenceMemberContainers. Then validate which of + * them are to remain and which of them are to really be removed + * later on. + */ + if (cmcs != null) + { + for (ConferenceParticipantContainer cmc : cmcs) + cmc.toBeRemoved = true; + } + + /* + * Depict the remote videos. They may or may not be associated with + * ConferenceMembers so the ConferenceMembers which have no + * associated videos will be depicted afterwards. + */ + if (videos != null) + { + Component video = cpc.getVideo(); + + for (Component conferenceMemberVideo : videos) + { + /* + * One of the remote videos is already used to depict the + * callPeer. + */ + if (conferenceMemberVideo == video) + continue; + + boolean addNewConferenceParticipantContainer = true; + ConferenceMember conferenceMember + = videoTelephony.getConferenceMember( + callPeer, + conferenceMemberVideo); + + if (cmcs == null) + { + cmcs = new LinkedList<ConferenceParticipantContainer>(); + cpc.conferenceMemberContainers = cmcs; + } + else + { + for (ConferenceParticipantContainer cmc : cmcs) + { + Object cmcParticipant = cmc.getParticipant(); + + if (conferenceMember == null) + { + if (cmcParticipant == callPeer) + { + Component cmcVideo = cmc.getVideo(); + + if (cmcVideo == null) + { + cmc.setVideo(conferenceMemberVideo); + cmc.toBeRemoved = false; + addNewConferenceParticipantContainer + = false; + break; + } + else if (cmcVideo == conferenceMemberVideo) + { + cmc.toBeRemoved = false; + addNewConferenceParticipantContainer + = false; + break; + } + } + } + else if (cmcParticipant == conferenceMember) + { + cmc.setVideo(conferenceMemberVideo); + cmc.toBeRemoved = false; + addNewConferenceParticipantContainer = false; + break; + } + } + } + + if (addNewConferenceParticipantContainer) + { + ConferenceParticipantContainer cmc + = (conferenceMember == null) + ? new ConferenceParticipantContainer( + callPeer, + conferenceMemberVideo) + : new ConferenceParticipantContainer( + conferenceMember, + conferenceMemberVideo); + + cmcs.add(cmc); + } + } + } + + /* + * Depict the ConferenceMembers which have not been depicted yet. + * They have no associated videos. + */ + List<ConferenceMember> conferenceMembers + = callPeer.getConferenceMembers(); + + if (!conferenceMembers.isEmpty()) + { + if (cmcs == null) + { + cmcs = new LinkedList<ConferenceParticipantContainer>(); + cpc.conferenceMemberContainers = cmcs; + } + for (ConferenceMember conferenceMember : conferenceMembers) + { + /* + * If the callPeer reports itself as a ConferenceMember, then + * we've already depicted it with cpc. + */ + if (isConferenceMemberCallPeer(conferenceMember, callPeer)) + continue; + /* + * If the callPeer reports the local peer/user as a + * ConferenceMember, then we've already depicted it. + */ + if (isConferenceMemberLocalUser(conferenceMember)) + continue; + + boolean addNewConferenceParticipantContainer = true; + + for (ConferenceParticipantContainer cmc : cmcs) + { + if (cmc.getParticipant() == conferenceMember) + { + /* + * It is possible to have a ConferenceMember who is + * sending video but we just do not have the SSRC of + * that video to associate the video with the + * ConferenceMember. In such a case, we may be depicting + * the ConferenceMember twice: once with video without a + * ConferenceMember and once with a ConferenceMember + * without video. This will surely be the case at the + * time of this writing with non-focus participants in a + * telephony conference hosted on a Jitsi Videobridge. + * Such a display is undesirable. If the + * conferenceMember is known to send video, we will not + * display it until we associated it with a video. This + * way, if a ConferenceMember is not sending video, we + * will depict it and we can be sure that no video + * without a ConferenceMember association will be + * depicting it a second time. + */ + if (cmc.toBeRemoved + && !conferenceMember + .getVideoStatus() + .allowsSending()) + { + cmc.setVideo(null); + cmc.toBeRemoved = false; + } + addNewConferenceParticipantContainer = false; + break; + } + } + + if (addNewConferenceParticipantContainer) + { + ConferenceParticipantContainer cmc + = new ConferenceParticipantContainer( + conferenceMember, + null); + + cmcs.add(cmc); + } + } + } + + if ((cmcs != null) && !cmcs.isEmpty()) + { + removeConferenceMemberContainers(cpc, false); + /* + * If cpc is already added to the user interface hierarchy of this + * instance, then it was there before the update procedure and it + * was determined to be appropriate to continue to depict its model. + * Consequently, its Component will be neither added to (because it + * was already added) nor removed from the user interface hierarchy + * of this instance. That's why we have make sure that the + * Components of its conferenceMemberContainers are also added to + * the user interface. + */ + if (UIVideoHandler2.isAncestor(this, cpc.getComponent())) + addConferenceMemberContainers(cpc); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected ConferenceCallPeerRenderer updateViewFromModel( + ConferenceCallPeerRenderer callPeerPanel, + CallPeer callPeer) + { + if (callPeer == null) + { + /* + * The local peer/user will be represented by a Call which has a + * CallPeer who provides local video. However, if the user has + * selected to hide the local video, the local peer/user will not be + * represented at all. + */ + Component video = null; + + if (uiVideoHandler.isLocalVideoVisible()) + { + for (Call aCall : callConference.getCalls()) + { + Iterator<? extends CallPeer> callPeerIter + = aCall.getCallPeers(); + OperationSetVideoTelephony videoTelephony + = aCall.getProtocolProvider().getOperationSet( + OperationSetVideoTelephony.class); + + while (callPeerIter.hasNext()) + { + callPeer = callPeerIter.next(); + + if (videoTelephony != null) + { + try + { + video + = videoTelephony.getLocalVisualComponent( + callPeer); + } + catch (OperationFailedException ofe) + { + logger.error( + "Failed to retrieve the local video" + + " for display", + ofe); + } + if (video != null) + break; + } + } + if (video != null) + break; + } + } + + if (callPeer == null) + callPeerPanel = null; + else + { + Call call = callPeer.getCall(); + + if (callPeerPanel instanceof ConferenceParticipantContainer) + { + ConferenceParticipantContainer cpc + = (ConferenceParticipantContainer) callPeerPanel; + + if (cpc.getParticipant() == call) + cpc.setVideo(video); + else + callPeerPanel = null; + } + else + callPeerPanel = null; + if (callPeerPanel == null) + { + callPeerPanel + = new ConferenceParticipantContainer(call, video); + } + } + } + else + { + /* + * The specified callPeer will be represented by one of its remote + * videos which is not associated with a ConferenceMember or is + * associated with a ConferenceMember representing the callPeer + * itself. + */ + OperationSetVideoTelephony videoTelephony + = callPeer.getProtocolProvider().getOperationSet( + OperationSetVideoTelephony.class); + List<Component> videos = null; + Component video = null; + + if (videoTelephony != null) + { + videos = videoTelephony.getVisualComponents(callPeer); + if ((videos != null) && !videos.isEmpty()) + { + for (Component aVideo : videos) + { + ConferenceMember conferenceMember + = videoTelephony.getConferenceMember( + callPeer, + aVideo); + + if (isConferenceMemberCallPeer( + conferenceMember, + callPeer)) + { + video = aVideo; + break; + } + } + } + } + + ConferenceParticipantContainer cpc = null; + + if (callPeerPanel instanceof ConferenceParticipantContainer) + { + cpc = (ConferenceParticipantContainer) callPeerPanel; + if (cpc.getParticipant() == callPeer) + cpc.setVideo(video); + else + cpc = null; + } + if (cpc == null) + cpc = new ConferenceParticipantContainer(callPeer, video); + callPeerPanel = cpc; + + // Update the conferenceMemberContainers of the cpc. + updateConferenceMemberContainers(cpc, videos, videoTelephony); + } + return callPeerPanel; + } + + /** + * {@inheritDoc} + * + * If {@link #SHOW_TOOLBARS} is <tt>false</tt>, disables the use of + * <tt>ConferenceParticipantContainer</tt>. A reason for such a value of + * <tt>SHOW_TOOLBARS</tt> may be that the functionality implemented in the + * model may not fully support mapping of visual <tt>Component</tt>s + * displaying video to telephony conference participants (e.g. in telephony + * conferences utilizing the Jitsi Videobridge server-side technology). In + * such a case displays the videos only, does not map videos to participants + * and does not display participants who do not have videos. + */ + @Override + protected void updateViewFromModelInEventDispatchThread() + { + if (SHOW_TOOLBARS) + { + super.updateViewFromModelInEventDispatchThread(); + return; + } + + /* + * Determine the set of visual Components displaying video streaming + * between the local peer/user and the remote peers which are to be + * depicted by this instance. + */ + Component localVideo = null; + Set<Component> videos = new HashSet<Component>(); + + for (Call call : callConference.getCalls()) + { + OperationSetVideoTelephony videoTelephony + = call.getProtocolProvider().getOperationSet( + OperationSetVideoTelephony.class); + + if (videoTelephony == null) + continue; + + Iterator<? extends CallPeer> callPeerIter = call.getCallPeers(); + + while (callPeerIter.hasNext()) + { + CallPeer callPeer = callPeerIter.next(); + + /* + * TODO VideoConferenceCallPanel respects + * UIVideoHandler2.isLocalVideoVisible() in order to react to + * the associated button at the bottom of the CallPanel. + * However, it does not add a close button on top of the local + * video in contrast to OneToOneCallPeerPanel. Overall, the + * result is questionable. + */ + if (uiVideoHandler.isLocalVideoVisible() + && (localVideo == null)) + { + try + { + localVideo + = videoTelephony.getLocalVisualComponent(callPeer); + } + catch (OperationFailedException ofe) + { + /* + * We'll just try to get the local video through another + * CallPeer then. + */ + } + if (localVideo != null) + videos.add(localVideo); + } + + List<Component> callPeerRemoteVideos + = videoTelephony.getVisualComponents(callPeer); + + videos.addAll(callPeerRemoteVideos); + } + } + + /* + * Remove the Components of this view which are no longer present in the + * model. + */ + Iterator<Component> thisVideoIter = this.videos.iterator(); + + while (thisVideoIter.hasNext()) + { + Component thisVideo = thisVideoIter.next(); + + if (!videos.contains(thisVideo)) + { + thisVideoIter.remove(); + videoContainer.remove(thisVideo); + } + + /* + * If a video is known to be depicted by this view and is still + * present in the model, then we could remove it from the set of + * videos present in the model in order to prevent going through the + * procedure of adding it to this view. However, we choose to play + * on the safe side. + */ + } + + /* + * Add the Components of the model which are not depicted by this view. + */ + for (Component video : videos) + { + if (!UIVideoHandler2.isAncestor(videoContainer, video)) + { + this.videos.add(video); + videoContainer.add( + video, + (video == localVideo) + ? VideoLayout.LOCAL + : VideoLayout.CENTER_REMOTE); + } + } + } + + @Override + protected void viewForModelAdded( + ConferenceCallPeerRenderer callPeerPanel, + CallPeer callPeer) + { + videoContainer.add( + callPeerPanel.getComponent(), + VideoLayout.CENTER_REMOTE); + if ((callPeer != null) + && (callPeerPanel instanceof ConferenceParticipantContainer)) + { + addConferenceMemberContainers( + (ConferenceParticipantContainer) callPeerPanel); + } + } + + @Override + protected void viewForModelRemoved( + ConferenceCallPeerRenderer callPeerPanel, + CallPeer callPeer) + { + videoContainer.remove(callPeerPanel.getComponent()); + if ((callPeer != null) + && (callPeerPanel instanceof ConferenceParticipantContainer)) + { + removeConferenceMemberContainers( + (ConferenceParticipantContainer) callPeerPanel, + true); + } + } + + /** + * Implements an AWT <tt>Component</tt> which contains the user interface + * elements depicting a specific participant in the telephony conference + * depicted by a <tt>VideoConferenceCallPanel</tt>. + */ + private class ConferenceParticipantContainer + extends TransparentPanel + implements ConferenceCallPeerRenderer + { + /** + * The list of <tt>ConferenceParticipantContainer</tt>s which represent + * the <tt>ConferenceMember</tt>s of the participant represented by this + * instance. Since a <tt>CallPeer</tt> may send the local peer/user + * multiple videos without providing a way to associate a + * ConferenceMember with each one of them, the list may contain + * <tt>ConferenceParticipantContainer</tt>s which do not represent a + * specific <tt>ConferenceMember</tt> instance but rather a video sent + * by a <tt>CallPeer</tt> to the local peer/user which looks like (in + * the terms of <tt>VideoConferenceCallPanel) a member of a conference + * organized by the <tt>CallPeer</tt> in question. + * <p> + * Implements a state which is private to + * <tt>VideoConferenceCallPanel</tt> and is of no concern to + * <tt>ConferenceParticipantContainer</tt>. + * </p> + */ + List<ConferenceParticipantContainer> conferenceMemberContainers; + + /** + * The indicator which determines whether this instance is to be removed + * because it has become out-of-date, obsolete, unnecessary. + * <p> + * Implements a state which is private to + * <tt>VideoConferenceCallPanel</tt> and is of no concern to + * <tt>ConferenceParticipantContainer</tt>. + * </p> + */ + boolean toBeRemoved; + + /** + * The <tt>BasicConferenceParticipantPanel</tt> which is displayed at + * the bottom of this instance, bellow the {@link #video} (i.e. + * {@link #videoContainer}) and is referred to as the tool bar. + */ + private final BasicConferenceParticipantPanel<?> toolBar; + + /** + * The visual <tt>Component</tt>, if any, displaying video which is + * depicted by this instance. + */ + private Component video; + + /** + * The <tt>VideoContainer</tt> which lays out the video depicted by this + * instance i.e. {@link #video}. + */ + private final VideoContainer videoContainer; + + /** + * The <tt>CallPeer</tt> associated with this container, if it has been + * created to represent a <tt>CallPeer</tt>. + */ + private CallPeer callPeer; + + /** + * The <tt>conferenceMember</tt> associated with this container, if it + * has been created to represent a <tt>conferenceMember</tt>. + */ + private ConferenceMember conferenceMember; + + /** + * Indicates that this container contains information for the local + * user. + */ + private boolean isLocalUser; + + /** + * Initializes a new <tt>ConferenceParticipantContainer</tt> instance + * which is to depict the local peer/user. + * + * @param call a <tt>Call</tt> which is to provide information about the + * local peer/user + * @param video the visual <tt>Component</tt>, if any, displaying the + * video streaming from the local peer/user to the remote peer(s) + */ + public ConferenceParticipantContainer(Call call, Component video) + { + this( + createDefaultPhotoPanel(call), + video, + new ConferencePeerPanel( + VideoConferenceCallPanel.this, + call, + true), + null, null, true); + } + + public ConferenceParticipantContainer( + CallPeer callPeer, + Component video) + { + this( createDefaultPhotoPanel(callPeer), + video, + new ConferencePeerPanel( + VideoConferenceCallPanel.this, + callPeer, + true), + callPeer, null, false); + } + + private ConferenceParticipantContainer( + Component noVideo, + Component video, + BasicConferenceParticipantPanel<?> toolBar, + CallPeer callPeer, + ConferenceMember conferenceMember, + boolean isLocalUser) + { + super(new BorderLayout()); + + this.callPeer = callPeer; + this.conferenceMember = conferenceMember; + this.isLocalUser = isLocalUser; + + videoContainer = new VideoContainer(noVideo, false); + add(videoContainer, BorderLayout.CENTER); + + this.toolBar = toolBar; + if (this.toolBar != null) + add(this.toolBar, BorderLayout.SOUTH); + + if (video != null) + { + setVideo(video); + } + else + setVisible(false); + } + + public ConferenceParticipantContainer( + ConferenceMember conferenceMember, + Component video) + { + this( + createDefaultPhotoPanel(conferenceMember), + video, + new ConferenceMemberPanel( + VideoConferenceCallPanel.this, + conferenceMember, + true), + null, conferenceMember, false); + } + + public void dispose() + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.dispose(); + + // Dispose of the conferenceMemberContainers if any. + /* + * XXX The field conferenceMemberContainers implements a state + * private to VideoConferenceCallPanel which the latter makes sure + * to access on the AWT event dispatching thread only. Since we are + * going out of our way here to help VideoConferenceCallPanel, + * ensure that the mentioned synchronization rule is not violated. + */ + CallManager.assertIsEventDispatchingThread(); + if (conferenceMemberContainers != null) + { + for (ConferenceParticipantContainer cmc + : conferenceMemberContainers) + { + cmc.dispose(); + } + } + } + + public CallPanel getCallPanel() + { + return getCallRenderer().getCallContainer(); + } + + public SwingCallRenderer getCallRenderer() + { + return VideoConferenceCallPanel.this; + } + + public Component getComponent() + { + return this; + } + + private ConferenceCallPeerRenderer + getConferenceCallPeerRendererDelegate() + { + return + (toolBar instanceof ConferenceCallPeerRenderer) + ? (ConferenceCallPeerRenderer) toolBar + : null; + } + + /** + * Gets the conference participant depicted by this instance. + * + * @return the conference participant depicted by this instance + */ + public Object getParticipant() + { + return (toolBar == null) ? null : toolBar.getParticipant(); + } + + public Component getVideo() + { + return video; + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. Otherwise, returns <tt>false</tt>. + */ + public boolean isLocalVideoVisible() + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + return (delegate == null) ? false : delegate.isLocalVideoVisible(); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void printDTMFTone(char dtmfChar) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.printDTMFTone(dtmfChar); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void securityNegotiationStarted( + CallPeerSecurityNegotiationStartedEvent ev) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.securityNegotiationStarted(ev); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void securityOff(CallPeerSecurityOffEvent ev) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.securityOff(ev); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void securityOn(CallPeerSecurityOnEvent ev) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.securityOn(ev); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void securityPending() + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.securityPending(); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void securityTimeout(CallPeerSecurityTimeoutEvent ev) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.securityTimeout(ev); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void setErrorReason(String reason) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.setErrorReason(reason); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void setLocalVideoVisible(boolean visible) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.setLocalVideoVisible(visible); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void setMute(boolean mute) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.setMute(mute); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void setOnHold(boolean onHold) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.setOnHold(onHold); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void setPeerImage(byte[] image) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.setPeerImage(image); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void setPeerName(String name) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.setPeerName(name); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void setPeerState( + CallPeerState oldState, + CallPeerState newState, + String stateString) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.setPeerState(oldState, newState, stateString); + } + + /** + * {@inheritDoc} + * + * Delegates to the <tt>toolBar</tt>, if the latter implements + * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a + * container only. + */ + public void setSecurityPanelVisible(boolean visible) + { + ConferenceCallPeerRenderer delegate + = getConferenceCallPeerRendererDelegate(); + + if (delegate != null) + delegate.setSecurityPanelVisible(visible); + } + + /** + * Sets the visual <tt>Component</tt> displaying the video associated + * with the participant depicted by this instance. + * + * @param video the visual <tt>Component</tt> displaying video which is + * to be associated with the participant depicted by this instance + */ + void setVideo(Component video) + { + if (this.video != video) + { + if (this.video != null) + videoContainer.remove(this.video); + + this.video = video; + + if (this.video != null) + { + setVisible(true); + videoContainer.add(this.video, VideoLayout.CENTER_REMOTE); + } + else + setVisible(false); + + // Update thumbnails container according to video status. + if (thumbnailContainer != null) + { + if (conferenceMember != null) + thumbnailContainer + .updateThumbnail(conferenceMember, (video != null)); + else if (callPeer != null) + thumbnailContainer + .updateThumbnail(callPeer, (video != null)); + else if (isLocalUser) + thumbnailContainer + .updateThumbnail((video != null)); + } + } + } + } +} |