/**
   * Creates a new AWT <tt>Container</tt> which can display a single <tt>Component</tt> at a time
   * (supposedly, one which represents video) and, in the absence of such a <tt>Component</tt>,
   * displays a predefined default <tt>Component</tt> (in accord with the previous supposition, one
   * which is the default when there is no video). The returned <tt>Container</tt> will track the
   * <tt>Components</tt>s added to and removed from it in order to make sure that
   * <tt>noVideoContainer</tt> is displayed as described.
   *
   * @param noVideoComponent the predefined default <tt>Component</tt> to be displayed in the
   *     returned <tt>Container</tt> when there is no other <tt>Component</tt> in it
   * @return a new <tt>Container</tt> which can display a single <tt>Component</tt> at a time and,
   *     in the absence of such a <tt>Component</tt>, displays <tt>noVideoComponent</tt>
   */
  private VideoContainer createVideoContainer(Component noVideoComponent) {
    Container oldParent = noVideoComponent.getParent();

    if (oldParent != null) oldParent.remove(noVideoComponent);

    return new VideoContainer(noVideoComponent, false);
  }
  /**
   * Releases the resources acquired by this instance which require explicit disposal (e.g. any
   * listeners added to the depicted <tt>CallPeer</tt>. Invoked by <tt>OneToOneCallPanel</tt> when
   * it determines that this <tt>OneToOneCallPeerPanel</tt> is no longer necessary.
   */
  public void dispose() {
    disposed = true;

    callPeerAdapter.dispose();
    uiVideoHandler.deleteObserver(uiVideoHandlerObserver);

    if (callRenderer instanceof Component) {
      ((Component) callRenderer).removePropertyChangeListener(CallContainer.PROP_FULL_SCREEN, this);
    }
  }
  /**
   * Re-dispatches glass pane mouse events only in case they occur on the security panel.
   *
   * @param glassPane the glass pane
   * @param e the mouse event in question
   */
  private void redispatchMouseEvent(Component glassPane, MouseEvent e) {
    Point glassPanePoint = e.getPoint();

    Point securityPanelPoint =
        SwingUtilities.convertPoint(glassPane, glassPanePoint, securityPanel);

    Component component;
    Point componentPoint;

    if (securityPanelPoint.y > 0) {
      component = securityPanel;
      componentPoint = securityPanelPoint;
    } else {
      Container contentPane =
          callRenderer.getCallContainer().getCallWindow().getFrame().getContentPane();

      Point containerPoint = SwingUtilities.convertPoint(glassPane, glassPanePoint, contentPane);

      component =
          SwingUtilities.getDeepestComponentAt(contentPane, containerPoint.x, containerPoint.y);

      componentPoint = SwingUtilities.convertPoint(contentPane, glassPanePoint, component);
    }

    if (component != null)
      component.dispatchEvent(
          new MouseEvent(
              component,
              e.getID(),
              e.getWhen(),
              e.getModifiers(),
              componentPoint.x,
              componentPoint.y,
              e.getClickCount(),
              e.isPopupTrigger()));

    e.consume();
  }
  /**
   * Creates a <tt>CallPeerPanel</tt> for the given call peer.
   *
   * @param callRenderer the renderer of the call
   * @param callPeer the <tt>CallPeer</tt> represented in this panel
   * @param uiVideoHandler the facility which is to aid the new instance in the dealing with the
   *     video-related information
   */
  public OneToOneCallPeerPanel(
      SwingCallRenderer callRenderer, CallPeer callPeer, UIVideoHandler2 uiVideoHandler) {
    this.callRenderer = callRenderer;
    this.callPeer = callPeer;
    // we need to obtain call as soon as possible
    // cause if it fails too quickly we may fail to show it
    this.call = callPeer.getCall();
    this.uiVideoHandler = uiVideoHandler;

    peerName = CallManager.getPeerDisplayName(callPeer);
    securityPanel = SecurityPanel.create(this, callPeer, null);

    photoLabel = new JLabel(getPhotoLabelIcon());
    center = createCenter();
    statusBar = createStatusBar();

    setPeerImage(CallManager.getPeerImage(callPeer));

    /* Lay out the main Components of the UI. */
    setLayout(new GridBagLayout());

    GridBagConstraints cnstrnts = new GridBagConstraints();

    if (center != null) {
      cnstrnts.fill = GridBagConstraints.BOTH;
      cnstrnts.gridx = 0;
      cnstrnts.gridy = 1;
      cnstrnts.weightx = 1;
      cnstrnts.weighty = 1;
      add(center, cnstrnts);
    }
    if (statusBar != null) {
      cnstrnts.fill = GridBagConstraints.NONE;
      cnstrnts.gridx = 0;
      cnstrnts.gridy = 3;
      cnstrnts.weightx = 0;
      cnstrnts.weighty = 0;
      cnstrnts.insets = new Insets(5, 0, 0, 0);
      add(statusBar, cnstrnts);
    }

    createSoundLevelIndicators();
    initSecuritySettings();

    /*
     * Add the listeners which will be notified about changes in the model
     * and which will update this view.
     */
    callPeerAdapter = new CallPeerAdapter(callPeer, this);
    uiVideoHandler.addObserver(uiVideoHandlerObserver);

    /*
     * This view adapts to whether it is displayed in full-screen or
     * windowed mode.
     */
    if (callRenderer instanceof Component) {
      ((Component) callRenderer).addPropertyChangeListener(CallContainer.PROP_FULL_SCREEN, this);
    }

    OperationSetDesktopSharingClient desktopSharingClient =
        callPeer.getProtocolProvider().getOperationSet(OperationSetDesktopSharingClient.class);
    if (desktopSharingClient != null) {
      desktopSharingMouseAndKeyboardListener =
          new DesktopSharingMouseAndKeyboardListener(callPeer, desktopSharingClient);
    } else desktopSharingMouseAndKeyboardListener = null;

    updateViewFromModel();
  }