예제 #1
0
  /**
   * When a message is received determines whether to open a new chat window or chat window tab, or
   * to indicate that a message is received from a contact which already has an open chat. When the
   * chat is found checks if in mode "Auto popup enabled" and if this is the case shows the message
   * in the appropriate chat panel.
   *
   * @param evt the event containing details on the received message
   */
  public void messageReceived(MessageReceivedEvent evt) {
    if (logger.isTraceEnabled())
      logger.trace("MESSAGE RECEIVED from contact: " + evt.getSourceContact().getAddress());

    Contact protocolContact = evt.getSourceContact();
    ContactResource contactResource = evt.getContactResource();
    Message message = evt.getSourceMessage();
    int eventType = evt.getEventType();
    MetaContact metaContact =
        GuiActivator.getContactListService().findMetaContactByContact(protocolContact);

    if (metaContact != null) {
      messageReceived(
          protocolContact,
          contactResource,
          metaContact,
          message,
          eventType,
          evt.getTimestamp(),
          evt.getCorrectedMessageUID(),
          evt.isPrivateMessaging(),
          evt.getPrivateMessagingContactRoom());
    } else {
      if (logger.isTraceEnabled())
        logger.trace("MetaContact not found for protocol contact: " + protocolContact + ".");
    }
  }
예제 #2
0
  /**
   * Returns existing chat rooms for the given <tt>chatRoomProvider</tt>.
   *
   * @param chatRoomProvider the <tt>ChatRoomProviderWrapper</tt>, which chat rooms we're looking
   *     for
   * @return existing chat rooms for the given <tt>chatRoomProvider</tt>
   */
  public List<String> getExistingChatRooms(ChatRoomProviderWrapper chatRoomProvider) {
    if (chatRoomProvider == null) return null;

    ProtocolProviderService protocolProvider = chatRoomProvider.getProtocolProvider();

    if (protocolProvider == null) return null;

    OperationSetMultiUserChat groupChatOpSet =
        protocolProvider.getOperationSet(OperationSetMultiUserChat.class);

    if (groupChatOpSet == null) return null;

    List<String> chatRooms = null;
    try {
      chatRooms = groupChatOpSet.getExistingChatRooms();
    } catch (OperationFailedException e) {
      if (logger.isTraceEnabled())
        logger.trace(
            "Failed to obtain existing chat rooms for server: "
                + protocolProvider.getAccountID().getService(),
            e);
    } catch (OperationNotSupportedException e) {
      if (logger.isTraceEnabled())
        logger.trace(
            "Failed to obtain existing chat rooms for server: "
                + protocolProvider.getAccountID().getService(),
            e);
    }

    return chatRooms;
  }
예제 #3
0
  public void setCurrentContact(Contact contact, String resourceName) {
    if (contact == null) {
      this.otrContact = null;
      this.setPolicy(null);
      this.setStatus(ScSessionStatus.PLAINTEXT);
      return;
    }

    if (resourceName == null) {
      OtrContact otrContact = OtrContactManager.getOtrContact(contact, null);
      if (this.otrContact == otrContact) return;
      this.otrContact = otrContact;
      this.setStatus(OtrActivator.scOtrEngine.getSessionStatus(otrContact));
      this.setPolicy(OtrActivator.scOtrEngine.getContactPolicy(contact));
      return;
    }
    for (ContactResource resource : contact.getResources()) {
      if (resource.getResourceName().equals(resourceName)) {
        OtrContact otrContact = OtrContactManager.getOtrContact(contact, resource);
        if (this.otrContact == otrContact) return;
        this.otrContact = otrContact;
        this.setStatus(OtrActivator.scOtrEngine.getSessionStatus(otrContact));
        this.setPolicy(OtrActivator.scOtrEngine.getContactPolicy(contact));
        return;
      }
    }
    logger.debug("Could not find resource for contact " + contact);
  }
예제 #4
0
  /**
   * Sends a typing notification state.
   *
   * @param typingState the typing notification state to send
   * @return the result of this operation. One of the TYPING_NOTIFICATION_XXX constants defined in
   *     this class
   */
  public int sendTypingNotification(int typingState) {
    // If this chat transport does not support sms messaging we do
    // nothing here.
    if (!allowsTypingNotifications()) return -1;

    ProtocolProviderService protocolProvider = contact.getProtocolProvider();
    OperationSetTypingNotifications tnOperationSet =
        protocolProvider.getOperationSet(OperationSetTypingNotifications.class);

    // if protocol is not registered or contact is offline don't
    // try to send typing notifications
    if (protocolProvider.isRegistered()
        && contact.getPresenceStatus().getStatus() >= PresenceStatus.ONLINE_THRESHOLD) {
      try {
        tnOperationSet.sendTypingNotification(contact, typingState);

        return ChatPanel.TYPING_NOTIFICATION_SUCCESSFULLY_SENT;
      } catch (Exception ex) {
        logger.error("Failed to send typing notifications.", ex);

        return ChatPanel.TYPING_NOTIFICATION_SEND_FAILED;
      }
    }

    return ChatPanel.TYPING_NOTIFICATION_SEND_FAILED;
  }
예제 #5
0
  /**
   * Sets the icon for the given file.
   *
   * @param file the file to set an icon for
   * @return the byte array containing the thumbnail
   */
  private byte[] getFileThumbnail(File file) {
    byte[] bytes = null;
    if (FileUtils.isImage(file.getName())) {
      try {
        ImageIcon image = new ImageIcon(file.toURI().toURL());
        int width = image.getIconWidth();
        int height = image.getIconHeight();

        if (width > THUMBNAIL_WIDTH) width = THUMBNAIL_WIDTH;
        if (height > THUMBNAIL_HEIGHT) height = THUMBNAIL_HEIGHT;

        bytes = ImageUtils.getScaledInstanceInBytes(image.getImage(), width, height);
      } catch (MalformedURLException e) {
        if (logger.isDebugEnabled()) logger.debug("Could not locate image.", e);
      }
    }
    return bytes;
  }
예제 #6
0
  /**
   * When a sent message is delivered shows it in the chat conversation panel.
   *
   * @param evt the event containing details on the message delivery
   */
  public void messageDelivered(MessageDeliveredEvent evt) {
    Contact contact = evt.getDestinationContact();
    MetaContact metaContact =
        GuiActivator.getContactListService().findMetaContactByContact(contact);

    if (logger.isTraceEnabled())
      logger.trace("MESSAGE DELIVERED to contact: " + contact.getAddress());

    ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, false);

    if (chatPanel != null) {
      Message msg = evt.getSourceMessage();
      ProtocolProviderService protocolProvider = contact.getProtocolProvider();

      if (logger.isTraceEnabled())
        logger.trace(
            "MESSAGE DELIVERED: process message to chat for contact: "
                + contact.getAddress()
                + " MESSAGE: "
                + msg.getContent());

      chatPanel.addMessage(
          this.mainFrame.getAccountAddress(protocolProvider),
          this.mainFrame.getAccountDisplayName(protocolProvider),
          evt.getTimestamp(),
          Chat.OUTGOING_MESSAGE,
          msg.getContent(),
          msg.getContentType(),
          msg.getMessageUID(),
          evt.getCorrectedMessageUID());

      if (evt.isSmsMessage() && !ConfigurationUtils.isSmsNotifyTextDisabled()) {
        chatPanel.addMessage(
            contact.getDisplayName(),
            new Date(),
            Chat.ACTION_MESSAGE,
            GuiActivator.getResources().getI18NString("service.gui.SMS_SUCCESSFULLY_SENT"),
            "text");
      }
    }
  }
예제 #7
0
  /**
   * Shows a warning message to the user when message delivery has failed.
   *
   * @param evt the event containing details on the message delivery failure
   */
  public void messageDeliveryFailed(MessageDeliveryFailedEvent evt) {
    logger.error(evt.getReason());

    String errorMsg = null;

    Message sourceMessage = (Message) evt.getSource();

    Contact sourceContact = evt.getDestinationContact();

    MetaContact metaContact =
        GuiActivator.getContactListService().findMetaContactByContact(sourceContact);

    if (evt.getErrorCode() == MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED) {
      errorMsg =
          GuiActivator.getResources()
              .getI18NString(
                  "service.gui.MSG_DELIVERY_NOT_SUPPORTED",
                  new String[] {sourceContact.getDisplayName()});
    } else if (evt.getErrorCode() == MessageDeliveryFailedEvent.NETWORK_FAILURE) {
      errorMsg = GuiActivator.getResources().getI18NString("service.gui.MSG_NOT_DELIVERED");
    } else if (evt.getErrorCode() == MessageDeliveryFailedEvent.PROVIDER_NOT_REGISTERED) {
      errorMsg =
          GuiActivator.getResources().getI18NString("service.gui.MSG_SEND_CONNECTION_PROBLEM");
    } else if (evt.getErrorCode() == MessageDeliveryFailedEvent.INTERNAL_ERROR) {
      errorMsg =
          GuiActivator.getResources().getI18NString("service.gui.MSG_DELIVERY_INTERNAL_ERROR");
    } else {
      errorMsg = GuiActivator.getResources().getI18NString("service.gui.MSG_DELIVERY_ERROR");
    }

    String reason = evt.getReason();
    if (reason != null)
      errorMsg +=
          " "
              + GuiActivator.getResources()
                  .getI18NString("service.gui.ERROR_WAS", new String[] {reason});

    ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, sourceContact);

    chatPanel.addMessage(
        sourceContact.getAddress(),
        metaContact.getDisplayName(),
        new Date(),
        Chat.OUTGOING_MESSAGE,
        sourceMessage.getContent(),
        sourceMessage.getContentType(),
        sourceMessage.getMessageUID(),
        evt.getCorrectedMessageUID());

    chatPanel.addErrorMessage(metaContact.getDisplayName(), errorMsg);

    chatWindowManager.openChat(chatPanel, false);
  }
  /**
   * Parses the given http response.
   *
   * @param response the http response to parse
   * @return the new account
   */
  private NewAccount parseHttpResponse(String response) {
    NewAccount newAccount = null;
    try {
      JSONObject jsonObject = (JSONObject) JSONValue.parseWithException(response);
      boolean isSuccess = (Boolean) jsonObject.get("success");

      if (isSuccess) {
        newAccount =
            new NewAccount(
                (String) jsonObject.get("sip_address"),
                passField.getPassword(),
                null,
                (String) jsonObject.get("outbound_proxy"));

        String xcapRoot = (String) jsonObject.get("xcap_root");

        // as sip2sip adds @sip2sip.info at the end of the
        // xcap_uri but doesn't report it in resullt after
        // creating account, we add it
        String domain = null;
        int delimIndex = newAccount.getUserName().indexOf("@");
        if (delimIndex != -1) {
          domain = newAccount.getUserName().substring(delimIndex);
        }
        if (domain != null) {
          if (xcapRoot.endsWith("/"))
            xcapRoot = xcapRoot.substring(0, xcapRoot.length() - 1) + domain;
          else xcapRoot += domain;
        }

        newAccount.setXcapRoot(xcapRoot);
      } else {
        showErrorMessage((String) jsonObject.get("error_message"));
      }
    } catch (Throwable e1) {
      if (logger.isInfoEnabled()) logger.info("Failed Json parsing.", e1);
    }

    return newAccount;
  }
예제 #9
0
  /**
   * Joins the room with the given name though the given chat room provider.
   *
   * @param chatRoomName the name of the room to join.
   * @param chatRoomProvider the chat room provider to join through.
   */
  public void joinChatRoom(String chatRoomName, ChatRoomProviderWrapper chatRoomProvider) {
    OperationSetMultiUserChat groupChatOpSet =
        chatRoomProvider.getProtocolProvider().getOperationSet(OperationSetMultiUserChat.class);

    ChatRoom chatRoom = null;
    try {
      chatRoom = groupChatOpSet.findRoom(chatRoomName);
    } catch (Exception e) {
      if (logger.isTraceEnabled())
        logger.trace("Un exception occurred while searching for room:" + chatRoomName, e);
    }

    if (chatRoom != null) {
      ChatRoomWrapper chatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);

      if (chatRoomWrapper == null) {
        ChatRoomProviderWrapper parentProvider =
            chatRoomList.findServerWrapperFromProvider(chatRoom.getParentProvider());

        chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom);

        chatRoomList.addChatRoom(chatRoomWrapper);

        fireChatRoomListChangedEvent(chatRoomWrapper, ChatRoomListChangeEvent.CHAT_ROOM_ADDED);
      }
      joinChatRoom(chatRoomWrapper);
    } else
      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.ERROR"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CHAT_ROOM_NOT_EXIST",
                      new String[] {
                        chatRoomName,
                        chatRoomProvider.getProtocolProvider().getAccountID().getService()
                      }));
  }
예제 #10
0
  private void initPluginComponents() {
    // Search for plugin components registered through the OSGI bundle
    // context.
    ServiceReference[] serRefs = null;

    String osgiFilter =
        "(" + Container.CONTAINER_ID + "=" + Container.CONTAINER_CONTACT_LIST.getID() + ")";

    try {
      serRefs =
          GuiActivator.bundleContext.getServiceReferences(
              PluginComponentFactory.class.getName(), osgiFilter);
    } catch (InvalidSyntaxException exc) {
      logger.error("Could not obtain plugin reference.", exc);
    }

    if (serRefs != null) {
      for (ServiceReference serRef : serRefs) {
        PluginComponentFactory factory =
            (PluginComponentFactory) GuiActivator.bundleContext.getService(serRef);
        PluginComponent component = factory.getPluginComponentInstance(this);

        Object selectedValue = getContactList().getSelectedValue();

        if (selectedValue instanceof MetaContact) {
          component.setCurrentContact((MetaContact) selectedValue);
        } else if (selectedValue instanceof MetaContactGroup) {
          component.setCurrentContactGroup((MetaContactGroup) selectedValue);
        }

        String pluginConstraints = factory.getConstraints();
        Object constraints;

        if (pluginConstraints != null)
          constraints = UIServiceImpl.getBorderLayoutConstraintsFromContainer(pluginConstraints);
        else constraints = BorderLayout.SOUTH;

        this.add((Component) component.getComponent(), constraints);

        this.repaint();
      }
    }

    GuiActivator.getUIService().addPluginComponentListener(this);
  }
예제 #11
0
/**
 * The <tt>MUCServiceImpl</tt> class implements the service for the chat rooms.
 *
 * @author Hristo Terezov
 */
public class MUCServiceImpl extends MUCService {

  /** The list of persistent chat rooms. */
  private final ChatRoomListImpl chatRoomList = new ChatRoomListImpl();

  /**
   * The <tt>Logger</tt> used by the <tt>MUCServiceImpl</tt> class and its instances for logging
   * output.
   */
  private static Logger logger = Logger.getLogger(MUCServiceImpl.class);

  /**
   * Called to accept an incoming invitation. Adds the invitation chat room to the list of chat
   * rooms and joins it.
   *
   * @param invitation the invitation to accept.
   */
  public void acceptInvitation(ChatRoomInvitation invitation) {
    ChatRoom chatRoom = invitation.getTargetChatRoom();
    byte[] password = invitation.getChatRoomPassword();

    String nickName = chatRoom.getParentProvider().getAccountID().getUserID();

    joinChatRoom(chatRoom, nickName, password);
  }

  /**
   * Adds a change listener to the <tt>ChatRoomList</tt>.
   *
   * @param l the listener.
   */
  public void addChatRoomListChangeListener(ChatRoomListChangeListener l) {
    chatRoomList.addChatRoomListChangeListener(l);
  }

  /**
   * Removes a change listener to the <tt>ChatRoomList</tt>.
   *
   * @param l the listener.
   */
  public void removeChatRoomListChangeListener(ChatRoomListChangeListener l) {
    chatRoomList.removeChatRoomListChangeListener(l);
  }

  /**
   * Fires a <tt>ChatRoomListChangedEvent</tt> event.
   *
   * @param chatRoomWrapper the chat room.
   * @param eventID the id of the event.
   */
  public void fireChatRoomListChangedEvent(ChatRoomWrapper chatRoomWrapper, int eventID) {
    chatRoomList.fireChatRoomListChangedEvent(chatRoomWrapper, eventID);
  }

  /**
   * Joins the given chat room with the given password and manages all the exceptions that could
   * occur during the join process.
   *
   * @param chatRoomWrapper the chat room to join.
   * @param nickName the nickname we choose for the given chat room.
   * @param password the password.
   * @param rememberPassword if true the password should be saved.
   * @param isFirstAttempt is this the first attempt to join room, used to check whether to show
   *     some error messages
   * @param subject the subject which will be set to the room after the user join successful.
   */
  private void joinChatRoom(
      ChatRoomWrapper chatRoomWrapper,
      String nickName,
      byte[] password,
      boolean rememberPassword,
      boolean isFirstAttempt,
      String subject) {
    ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

    if (chatRoom == null) {
      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.WARNING"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CHAT_ROOM_NOT_CONNECTED",
                      new String[] {chatRoomWrapper.getChatRoomName()}));
      return;
    }

    new JoinChatRoomTask(
            (ChatRoomWrapperImpl) chatRoomWrapper,
            nickName,
            password,
            rememberPassword,
            isFirstAttempt,
            subject)
        .start();
  }

  /**
   * Joins the given chat room with the given password and manages all the exceptions that could
   * occur during the join process.
   *
   * @param chatRoomWrapper the chat room to join.
   * @param nickName the nickname we choose for the given chat room.
   * @param password the password.
   */
  public void joinChatRoom(ChatRoomWrapper chatRoomWrapper, String nickName, byte[] password) {
    ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

    if (chatRoom == null) {
      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.WARNING"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CHAT_ROOM_NOT_CONNECTED",
                      new String[] {chatRoomWrapper.getChatRoomName()}));
      return;
    }

    new JoinChatRoomTask((ChatRoomWrapperImpl) chatRoomWrapper, nickName, password).start();
  }

  /**
   * Joins the given chat room with the given password and manages all the exceptions that could
   * occur during the join process.
   *
   * @param chatRoomWrapper the chat room to join.
   * @param nickName the nickname we choose for the given chat room.
   * @param password the password.
   * @param subject the subject which will be set to the room after the user join successful.
   */
  public void joinChatRoom(
      ChatRoomWrapper chatRoomWrapper, String nickName, byte[] password, String subject) {
    ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

    if (chatRoom == null) {
      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.WARNING"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CHAT_ROOM_NOT_CONNECTED",
                      new String[] {chatRoomWrapper.getChatRoomName()}));

      return;
    }

    // join from add chat room dialog

    new JoinChatRoomTask((ChatRoomWrapperImpl) chatRoomWrapper, nickName, password, subject)
        .start();
  }

  /**
   * Join chat room.
   *
   * @param chatRoomWrapper
   */
  public void joinChatRoom(ChatRoomWrapper chatRoomWrapper) {
    ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

    if (chatRoom == null) {
      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.WARNING"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CHAT_ROOM_NOT_CONNECTED",
                      new String[] {chatRoomWrapper.getChatRoomName()}));

      return;
    }

    new JoinChatRoomTask((ChatRoomWrapperImpl) chatRoomWrapper, null, null).start();
  }

  /**
   * Joins the given chat room and manages all the exceptions that could occur during the join
   * process.
   *
   * @param chatRoom the chat room to join
   * @param nickname the nickname we're using to join
   * @param password the password we're using to join
   */
  public void joinChatRoom(ChatRoom chatRoom, String nickname, byte[] password) {
    ChatRoomWrapper chatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);

    if (chatRoomWrapper == null) {
      ChatRoomProviderWrapper parentProvider =
          chatRoomList.findServerWrapperFromProvider(chatRoom.getParentProvider());

      chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom);

      chatRoomList.addChatRoom(chatRoomWrapper);

      fireChatRoomListChangedEvent(chatRoomWrapper, ChatRoomListChangeEvent.CHAT_ROOM_ADDED);
    }

    this.joinChatRoom(chatRoomWrapper, nickname, password);
  }

  /**
   * Joins the room with the given name though the given chat room provider.
   *
   * @param chatRoomName the name of the room to join.
   * @param chatRoomProvider the chat room provider to join through.
   */
  public void joinChatRoom(String chatRoomName, ChatRoomProviderWrapper chatRoomProvider) {
    OperationSetMultiUserChat groupChatOpSet =
        chatRoomProvider.getProtocolProvider().getOperationSet(OperationSetMultiUserChat.class);

    ChatRoom chatRoom = null;
    try {
      chatRoom = groupChatOpSet.findRoom(chatRoomName);
    } catch (Exception e) {
      if (logger.isTraceEnabled())
        logger.trace("Un exception occurred while searching for room:" + chatRoomName, e);
    }

    if (chatRoom != null) {
      ChatRoomWrapper chatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);

      if (chatRoomWrapper == null) {
        ChatRoomProviderWrapper parentProvider =
            chatRoomList.findServerWrapperFromProvider(chatRoom.getParentProvider());

        chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom);

        chatRoomList.addChatRoom(chatRoomWrapper);

        fireChatRoomListChangedEvent(chatRoomWrapper, ChatRoomListChangeEvent.CHAT_ROOM_ADDED);
      }
      joinChatRoom(chatRoomWrapper);
    } else
      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.ERROR"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CHAT_ROOM_NOT_EXIST",
                      new String[] {
                        chatRoomName,
                        chatRoomProvider.getProtocolProvider().getAccountID().getService()
                      }));
  }

  /**
   * Creates a chat room, by specifying the chat room name, the parent protocol provider and
   * eventually, the contacts invited to participate in this chat room.
   *
   * @param roomName the name of the room
   * @param protocolProvider the parent protocol provider.
   * @param contacts the contacts invited when creating the chat room.
   * @param reason
   * @param persistent is the room persistent
   * @param isPrivate whether the room will be private or public.
   * @return the <tt>ChatRoomWrapper</tt> corresponding to the created room
   */
  public ChatRoomWrapper createChatRoom(
      String roomName,
      ProtocolProviderService protocolProvider,
      Collection<String> contacts,
      String reason,
      boolean persistent,
      boolean isPrivate) {
    return createChatRoom(
        roomName, protocolProvider, contacts, reason, true, persistent, isPrivate);
  }

  /**
   * Creates a chat room, by specifying the chat room name, the parent protocol provider and
   * eventually, the contacts invited to participate in this chat room.
   *
   * @param roomName the name of the room
   * @param protocolProvider the parent protocol provider.
   * @param contacts the contacts invited when creating the chat room.
   * @param reason
   * @param persistent is the room persistent
   * @return the <tt>ChatRoomWrapper</tt> corresponding to the created room
   */
  public ChatRoomWrapper createChatRoom(
      String roomName,
      ProtocolProviderService protocolProvider,
      Collection<String> contacts,
      String reason,
      boolean persistent) {
    return createChatRoom(roomName, protocolProvider, contacts, reason, true, persistent, false);
  }

  /**
   * Creates a chat room, by specifying the chat room name, the parent protocol provider and
   * eventually, the contacts invited to participate in this chat room.
   *
   * @param roomName the name of the room
   * @param protocolProvider the parent protocol provider.
   * @param contacts the contacts invited when creating the chat room.
   * @param reason
   * @param join whether we should join the room after creating it.
   * @param persistent whether the newly created room will be persistent.
   * @param isPrivate whether the room will be private or public.
   * @return the <tt>ChatRoomWrapper</tt> corresponding to the created room
   */
  public ChatRoomWrapper createChatRoom(
      String roomName,
      ProtocolProviderService protocolProvider,
      Collection<String> contacts,
      String reason,
      boolean join,
      boolean persistent,
      boolean isPrivate) {
    ChatRoomWrapper chatRoomWrapper = null;
    OperationSetMultiUserChat groupChatOpSet =
        protocolProvider.getOperationSet(OperationSetMultiUserChat.class);

    // If there's no group chat operation set we have nothing to do here.
    if (groupChatOpSet == null) return null;

    ChatRoom chatRoom = null;
    try {

      HashMap<String, Object> roomProperties = new HashMap<String, Object>();
      roomProperties.put("isPrivate", isPrivate);
      chatRoom = groupChatOpSet.createChatRoom(roomName, roomProperties);

      if (join) {
        chatRoom.join();

        for (String contact : contacts) chatRoom.invite(contact, reason);
      }
    } catch (OperationFailedException ex) {
      logger.error("Failed to create chat room.", ex);

      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.ERROR"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CREATE_CHAT_ROOM_ERROR",
                      new String[] {protocolProvider.getProtocolDisplayName()}),
              ex);
    } catch (OperationNotSupportedException ex) {
      logger.error("Failed to create chat room.", ex);

      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.ERROR"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CREATE_CHAT_ROOM_ERROR",
                      new String[] {protocolProvider.getProtocolDisplayName()}),
              ex);
    }

    if (chatRoom != null) {
      ChatRoomProviderWrapper parentProvider =
          chatRoomList.findServerWrapperFromProvider(protocolProvider);

      // if there is the same room ids don't add new wrapper as old one
      // maybe already created
      chatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);

      if (chatRoomWrapper == null) {
        chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom);
        chatRoomWrapper.setPersistent(persistent);
        chatRoomList.addChatRoom(chatRoomWrapper);
      }
    }

    return chatRoomWrapper;
  }

  /**
   * Creates a private chat room, by specifying the parent protocol provider and eventually, the
   * contacts invited to participate in this chat room.
   *
   * @param protocolProvider the parent protocol provider.
   * @param contacts the contacts invited when creating the chat room.
   * @param reason
   * @param persistent is the room persistent
   * @return the <tt>ChatRoomWrapper</tt> corresponding to the created room
   */
  public ChatRoomWrapper createPrivateChatRoom(
      ProtocolProviderService protocolProvider,
      Collection<String> contacts,
      String reason,
      boolean persistent) {
    return this.createChatRoom(null, protocolProvider, contacts, reason, persistent, true);
  }

  /**
   * Returns existing chat rooms for the given <tt>chatRoomProvider</tt>.
   *
   * @param chatRoomProvider the <tt>ChatRoomProviderWrapper</tt>, which chat rooms we're looking
   *     for
   * @return existing chat rooms for the given <tt>chatRoomProvider</tt>
   */
  public List<String> getExistingChatRooms(ChatRoomProviderWrapper chatRoomProvider) {
    if (chatRoomProvider == null) return null;

    ProtocolProviderService protocolProvider = chatRoomProvider.getProtocolProvider();

    if (protocolProvider == null) return null;

    OperationSetMultiUserChat groupChatOpSet =
        protocolProvider.getOperationSet(OperationSetMultiUserChat.class);

    if (groupChatOpSet == null) return null;

    List<String> chatRooms = null;
    try {
      chatRooms = groupChatOpSet.getExistingChatRooms();
    } catch (OperationFailedException e) {
      if (logger.isTraceEnabled())
        logger.trace(
            "Failed to obtain existing chat rooms for server: "
                + protocolProvider.getAccountID().getService(),
            e);
    } catch (OperationNotSupportedException e) {
      if (logger.isTraceEnabled())
        logger.trace(
            "Failed to obtain existing chat rooms for server: "
                + protocolProvider.getAccountID().getService(),
            e);
    }

    return chatRooms;
  }

  /**
   * Rejects the given invitation with the specified reason.
   *
   * @param multiUserChatOpSet the operation set to use for rejecting the invitation
   * @param invitation the invitation to reject
   * @param reason the reason for the rejection
   */
  public void rejectInvitation(
      OperationSetMultiUserChat multiUserChatOpSet, ChatRoomInvitation invitation, String reason) {
    multiUserChatOpSet.rejectInvitation(invitation, reason);
  }

  /**
   * Leaves the given chat room.
   *
   * @param chatRoomWrapper the chat room to leave.
   * @return <tt>ChatRoomWrapper</tt> instance associated with the chat room.
   */
  public ChatRoomWrapper leaveChatRoom(ChatRoomWrapper chatRoomWrapper) {
    ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

    if (chatRoom == null) {
      ResourceManagementService resources = MUCActivator.getResources();

      MUCActivator.getAlertUIService()
          .showAlertDialog(
              resources.getI18NString("service.gui.WARNING"),
              resources.getI18NString("service.gui.CHAT_ROOM_LEAVE_NOT_CONNECTED"));

      return null;
    }

    if (chatRoom.isJoined()) chatRoom.leave();

    ChatRoomWrapper existChatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);

    if (existChatRoomWrapper == null) return null;

    // We save the choice of the user, before the chat room is really
    // joined, because even the join fails we want the next time when
    // we login to join this chat room automatically.
    ConfigurationUtils.updateChatRoomStatus(
        chatRoomWrapper.getParentProvider().getProtocolProvider(),
        chatRoomWrapper.getChatRoomID(),
        GlobalStatusEnum.OFFLINE_STATUS);

    return existChatRoomWrapper;
  }

  /** Joins a chat room in an asynchronous way. */
  private class JoinChatRoomTask extends Thread {
    private final ChatRoomWrapperImpl chatRoomWrapper;

    private final String nickName;

    private final byte[] password;

    private final boolean rememberPassword;

    private final boolean isFirstAttempt;

    private final String subject;

    private ResourceManagementService resources = MUCActivator.getResources();

    JoinChatRoomTask(
        ChatRoomWrapperImpl chatRoomWrapper,
        String nickName,
        byte[] password,
        boolean rememberPassword,
        boolean isFirstAttempt,
        String subject) {
      this.chatRoomWrapper = chatRoomWrapper;
      this.nickName = nickName;
      this.isFirstAttempt = isFirstAttempt;
      this.subject = subject;

      if (password == null) {
        String passString = chatRoomWrapper.loadPassword();
        if (passString != null) {
          this.password = passString.getBytes();
        } else {
          this.password = null;
        }
      } else {
        this.password = password;
      }
      this.rememberPassword = rememberPassword;
    }

    JoinChatRoomTask(ChatRoomWrapperImpl chatRoomWrapper, String nickName, byte[] password) {
      this(chatRoomWrapper, nickName, password, false, true, null);
    }

    JoinChatRoomTask(
        ChatRoomWrapperImpl chatRoomWrapper, String nickName, byte[] password, String subject) {
      this(chatRoomWrapper, nickName, password, false, true, subject);
    }

    /** @override {@link Thread}{@link #run()} to perform all asynchronous tasks. */
    @Override
    public void run() {
      ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

      try {
        if (password != null && password.length > 0) chatRoom.joinAs(nickName, password);
        else if (nickName != null) chatRoom.joinAs(nickName);
        else chatRoom.join();

        done(JOIN_SUCCESS_PROP);
      } catch (OperationFailedException e) {
        if (logger.isTraceEnabled())
          logger.trace("Failed to join chat room: " + chatRoom.getName(), e);

        switch (e.getErrorCode()) {
          case OperationFailedException.AUTHENTICATION_FAILED:
            done(JOIN_AUTHENTICATION_FAILED_PROP);
            break;
          case OperationFailedException.REGISTRATION_REQUIRED:
            done(JOIN_REGISTRATION_REQUIRED_PROP);
            break;
          case OperationFailedException.PROVIDER_NOT_REGISTERED:
            done(JOIN_PROVIDER_NOT_REGISTERED_PROP);
            break;
          case OperationFailedException.SUBSCRIPTION_ALREADY_EXISTS:
            done(JOIN_SUBSCRIPTION_ALREADY_EXISTS_PROP);
            break;
          default:
            done(JOIN_UNKNOWN_ERROR_PROP);
        }
      }
    }

    /**
     * Performs UI changes after the chat room join task has finished.
     *
     * @param returnCode the result code from the chat room join task.
     */
    private void done(String returnCode) {
      ConfigurationUtils.updateChatRoomStatus(
          chatRoomWrapper.getParentProvider().getProtocolProvider(),
          chatRoomWrapper.getChatRoomID(),
          GlobalStatusEnum.ONLINE_STATUS);

      String errorMessage = null;
      if (JOIN_AUTHENTICATION_FAILED_PROP.equals(returnCode)) {
        chatRoomWrapper.removePassword();

        AuthenticationWindowService authWindowsService =
            ServiceUtils.getService(MUCActivator.bundleContext, AuthenticationWindowService.class);

        AuthenticationWindowService.AuthenticationWindow authWindow =
            authWindowsService.create(
                null,
                null,
                null,
                false,
                chatRoomWrapper.isPersistent(),
                AuthenticationWindow.getAuthenticationWindowIcon(
                    chatRoomWrapper.getParentProvider().getProtocolProvider()),
                resources.getI18NString(
                    "service.gui.AUTHENTICATION_WINDOW_TITLE",
                    new String[] {chatRoomWrapper.getParentProvider().getName()}),
                resources.getI18NString(
                    "service.gui.CHAT_ROOM_REQUIRES_PASSWORD",
                    new String[] {chatRoomWrapper.getChatRoomName()}),
                "",
                null,
                isFirstAttempt
                    ? null
                    : resources.getI18NString(
                        "service.gui.AUTHENTICATION_FAILED",
                        new String[] {chatRoomWrapper.getChatRoomName()}),
                null);

        authWindow.setVisible(true);

        if (!authWindow.isCanceled()) {
          joinChatRoom(
              chatRoomWrapper,
              nickName,
              new String(authWindow.getPassword()).getBytes(),
              authWindow.isRememberPassword(),
              false,
              subject);
        }
      } else if (JOIN_REGISTRATION_REQUIRED_PROP.equals(returnCode)) {
        errorMessage =
            resources.getI18NString(
                "service.gui.CHAT_ROOM_REGISTRATION_REQUIRED",
                new String[] {chatRoomWrapper.getChatRoomName()});
      } else if (JOIN_PROVIDER_NOT_REGISTERED_PROP.equals(returnCode)) {
        errorMessage =
            resources.getI18NString(
                "service.gui.CHAT_ROOM_NOT_CONNECTED",
                new String[] {chatRoomWrapper.getChatRoomName()});
      } else if (JOIN_SUBSCRIPTION_ALREADY_EXISTS_PROP.equals(returnCode)) {
        errorMessage =
            resources.getI18NString(
                "service.gui.CHAT_ROOM_ALREADY_JOINED",
                new String[] {chatRoomWrapper.getChatRoomName()});
      } else {
        errorMessage =
            resources.getI18NString(
                "service.gui.FAILED_TO_JOIN_CHAT_ROOM",
                new String[] {chatRoomWrapper.getChatRoomName()});
      }

      if (!JOIN_SUCCESS_PROP.equals(returnCode)
          && !JOIN_AUTHENTICATION_FAILED_PROP.equals(returnCode)) {
        MUCActivator.getAlertUIService()
            .showAlertPopup(resources.getI18NString("service.gui.ERROR"), errorMessage);
      }

      if (JOIN_SUCCESS_PROP.equals(returnCode)) {
        if (rememberPassword) {
          chatRoomWrapper.savePassword(new String(password));
        }

        if (subject != null) {
          try {
            chatRoomWrapper.getChatRoom().setSubject(subject);
          } catch (OperationFailedException ex) {
            logger.warn("Failed to set subject.");
          }
        }
      }

      chatRoomWrapper.firePropertyChange(returnCode);
    }
  }

  /**
   * Finds the <tt>ChatRoomWrapper</tt> instance associated with the source contact.
   *
   * @param contact the source contact.
   * @return the <tt>ChatRoomWrapper</tt> instance.
   */
  public ChatRoomWrapper findChatRoomWrapperFromSourceContact(SourceContact contact) {
    if (!(contact instanceof ChatRoomSourceContact)) return null;
    ChatRoomSourceContact chatRoomContact = (ChatRoomSourceContact) contact;
    return chatRoomList.findChatRoomWrapperFromChatRoomID(
        chatRoomContact.getChatRoomID(), chatRoomContact.getProvider());
  }

  /**
   * Finds the <tt>ChatRoomWrapper</tt> instance associated with the chat room.
   *
   * @param chatRoomID the id of the chat room.
   * @param pps the provider of the chat room.
   * @return the <tt>ChatRoomWrapper</tt> instance.
   */
  public ChatRoomWrapper findChatRoomWrapperFromChatRoomID(
      String chatRoomID, ProtocolProviderService pps) {
    return chatRoomList.findChatRoomWrapperFromChatRoomID(chatRoomID, pps);
  }

  /**
   * Searches for chat room wrapper in chat room list by chat room.
   *
   * @param chatRoom the chat room.
   * @param create if <tt>true</tt> and the chat room wrapper is not found new chatRoomWrapper is
   *     created.
   * @return found chat room wrapper or the created chat room wrapper.
   */
  @Override
  public ChatRoomWrapper getChatRoomWrapperByChatRoom(ChatRoom chatRoom, boolean create) {
    ChatRoomWrapper chatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);

    if ((chatRoomWrapper == null) && create) {
      ChatRoomProviderWrapper parentProvider =
          chatRoomList.findServerWrapperFromProvider(chatRoom.getParentProvider());

      chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom);

      chatRoomList.addChatRoom(chatRoomWrapper);
    }
    return chatRoomWrapper;
  }

  /**
   * Goes through the locally stored chat rooms list and for each {@link ChatRoomWrapper} tries to
   * find the corresponding server stored {@link ChatRoom} in the specified operation set. Joins
   * automatically all found chat rooms.
   *
   * @param protocolProvider the protocol provider for the account to synchronize
   * @param opSet the multi user chat operation set, which give us access to chat room server
   */
  public void synchronizeOpSetWithLocalContactList(
      ProtocolProviderService protocolProvider, final OperationSetMultiUserChat opSet) {
    ChatRoomProviderWrapper chatRoomProvider = findServerWrapperFromProvider(protocolProvider);

    if (chatRoomProvider == null) {
      chatRoomProvider = chatRoomList.addRegisteredChatProvider(protocolProvider);
    }

    if (chatRoomProvider != null) {
      chatRoomProvider.synchronizeProvider();
    }
  }

  /**
   * Returns an iterator to the list of chat room providers.
   *
   * @return an iterator to the list of chat room providers.
   */
  public Iterator<ChatRoomProviderWrapper> getChatRoomProviders() {
    return chatRoomList.getChatRoomProviders();
  }

  /**
   * Removes the given <tt>ChatRoom</tt> from the list of all chat rooms.
   *
   * @param chatRoomWrapper the <tt>ChatRoomWrapper</tt> to remove
   */
  public void removeChatRoom(ChatRoomWrapper chatRoomWrapper) {
    chatRoomList.removeChatRoom(chatRoomWrapper);
  }

  /**
   * Destroys the given <tt>ChatRoom</tt> from the list of all chat rooms.
   *
   * @param chatRoomWrapper the <tt>ChatRoomWrapper</tt> to be destroyed.
   * @param reason the reason for destroying.
   * @param alternateAddress the alternate address.
   */
  public void destroyChatRoom(
      ChatRoomWrapper chatRoomWrapper, String reason, String alternateAddress) {
    if (chatRoomWrapper.getChatRoom().destroy(reason, alternateAddress)) {
      MUCActivator.getUIService().closeChatRoomWindow(chatRoomWrapper);
      chatRoomList.removeChatRoom(chatRoomWrapper);
    } else {
      // if we leave a chat room which is not persistent
      // the room can be destroyed on the server, and error is returned
      // when we try to destroy it not-authorized(401)
      if (!chatRoomWrapper.getChatRoom().isPersistent()
          && !chatRoomWrapper.getChatRoom().isJoined()) {
        chatRoomList.removeChatRoom(chatRoomWrapper);
      }
    }
  }

  /**
   * Adds a ChatRoomProviderWrapperListener to the listener list.
   *
   * @param listener the ChatRoomProviderWrapperListener to be added
   */
  public void addChatRoomProviderWrapperListener(ChatRoomProviderWrapperListener listener) {
    chatRoomList.addChatRoomProviderWrapperListener(listener);
  }

  /**
   * Removes the ChatRoomProviderWrapperListener to the listener list.
   *
   * @param listener the ChatRoomProviderWrapperListener to be removed
   */
  public void removeChatRoomProviderWrapperListener(ChatRoomProviderWrapperListener listener) {
    chatRoomList.removeChatRoomProviderWrapperListener(listener);
  }

  /**
   * Returns the <tt>ChatRoomProviderWrapper</tt> that correspond to the given
   * <tt>ProtocolProviderService</tt>. If the list doesn't contain a corresponding wrapper - returns
   * null.
   *
   * @param protocolProvider the protocol provider that we're looking for
   * @return the <tt>ChatRoomProvider</tt> object corresponding to the given
   *     <tt>ProtocolProviderService</tt>
   */
  public ChatRoomProviderWrapper findServerWrapperFromProvider(
      ProtocolProviderService protocolProvider) {
    return chatRoomList.findServerWrapperFromProvider(protocolProvider);
  }

  /**
   * Returns the <tt>ChatRoomWrapper</tt> that correspond to the given <tt>ChatRoom</tt>. If the
   * list of chat rooms doesn't contain a corresponding wrapper - returns null.
   *
   * @param chatRoom the <tt>ChatRoom</tt> that we're looking for
   * @return the <tt>ChatRoomWrapper</tt> object corresponding to the given <tt>ChatRoom</tt>
   */
  public ChatRoomWrapper findChatRoomWrapperFromChatRoom(ChatRoom chatRoom) {
    return chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);
  }

  /**
   * Opens a chat window for the chat room.
   *
   * @param room the chat room.
   */
  public void openChatRoom(ChatRoomWrapper room) {
    if (room.getChatRoom() == null) {
      room =
          createChatRoom(
              room.getChatRoomName(),
              room.getParentProvider().getProtocolProvider(),
              new ArrayList<String>(),
              "",
              false,
              false,
              true);

      // leave the chatroom because getChatRoom().isJoined() returns true
      // otherwise
      if (room.getChatRoom().isJoined()) room.getChatRoom().leave();
    }

    if (!room.getChatRoom().isJoined()) {
      String savedNick =
          ConfigurationUtils.getChatRoomProperty(
              room.getParentProvider().getProtocolProvider(), room.getChatRoomID(), "userNickName");
      String subject = null;

      if (savedNick == null) {
        String[] joinOptions =
            ChatRoomJoinOptionsDialog.getJoinOptions(
                room.getParentProvider().getProtocolProvider(),
                room.getChatRoomID(),
                getDefaultNickname(room.getParentProvider().getProtocolProvider()));
        savedNick = joinOptions[0];
        subject = joinOptions[1];
      }

      if (savedNick != null) {
        joinChatRoom(room, savedNick, null, subject);
      } else return;
    }

    MUCActivator.getUIService().openChatRoomWindow(room);
  }

  /**
   * Returns default nickname for chat room based on the given provider.
   *
   * @param pps the given protocol provider service
   * @return default nickname for chat room based on the given provider.
   */
  public String getDefaultNickname(ProtocolProviderService pps) {
    final OperationSetServerStoredAccountInfo accountInfoOpSet =
        pps.getOperationSet(OperationSetServerStoredAccountInfo.class);

    String displayName = "";
    if (accountInfoOpSet != null) {
      displayName = AccountInfoUtils.getDisplayName(accountInfoOpSet);
    }

    if (displayName == null || displayName.length() == 0) {
      displayName = MUCActivator.getGlobalDisplayDetailsService().getGlobalDisplayName();
      if (displayName == null || displayName.length() == 0) {
        displayName = pps.getAccountID().getUserID();
        if (displayName != null) {
          int atIndex = displayName.lastIndexOf("@");
          if (atIndex > 0) displayName = displayName.substring(0, atIndex);
        }
      }
    }

    return displayName;
  }

  /**
   * Returns instance of the <tt>ServerChatRoomContactSourceService</tt> contact source.
   *
   * @return instance of the <tt>ServerChatRoomContactSourceService</tt> contact source.
   */
  public ContactSourceService getServerChatRoomsContactSourceForProvider(
      ChatRoomProviderWrapper pps) {
    return new ServerChatRoomContactSourceService(pps);
  }

  /**
   * Returns <tt>true</tt> if the contact is <tt>ChatRoomSourceContact</tt>
   *
   * @param contact the contact
   * @return <tt>true</tt> if the contact is <tt>ChatRoomSourceContact</tt>
   */
  public boolean isMUCSourceContact(SourceContact contact) {
    return (contact instanceof ChatRoomSourceContact);
  }
}
예제 #12
0
/**
 * The <tt>OneToOneCallPeerPanel</tt> is the panel containing data for a call peer in a given call.
 * It contains information like call peer name, photo, call duration, etc.
 *
 * @author Yana Stamcheva
 * @author Lyubomir Marinov
 * @author Sebastien Vincent
 * @author Adam Netocny
 */
public class OneToOneCallPeerPanel extends TransparentPanel
    implements SwingCallPeerRenderer, PropertyChangeListener, Skinnable {
  /**
   * The <tt>Logger</tt> used by the <tt>OneToOneCallPeerPanel</tt> class and its instances for
   * logging output.
   */
  private static final Logger logger = Logger.getLogger(OneToOneCallPeerPanel.class);

  /** Serial version UID. */
  private static final long serialVersionUID = 0L;

  /** The <tt>CallPeer</tt>, which is rendered in this panel. */
  private final CallPeer callPeer;

  /** The <tt>Call</tt>, which is rendered in this panel. */
  private final Call call;

  /**
   * The <tt>CallPeerAdapter</tt> which implements common <tt>CallPeer</tt>-related listeners on
   * behalf of this instance.
   */
  private final CallPeerAdapter callPeerAdapter;

  /** The renderer of the call. */
  private final SwingCallRenderer callRenderer;

  /** The component showing the status of the underlying call peer. */
  private final JLabel callStatusLabel = new JLabel();

  /** The center component. */
  private final VideoContainer center;

  /**
   * The AWT <tt>Component</tt> which implements a button which allows closing/hiding the visual
   * <tt>Component</tt> which depicts the video streaming from the local peer/user to the remote
   * peer(s).
   */
  private Component closeLocalVisualComponentButton;

  /**
   * A listener to desktop sharing granted/revoked events and to mouse and keyboard interaction with
   * the remote video displaying the remote desktop.
   */
  private final DesktopSharingMouseAndKeyboardListener desktopSharingMouseAndKeyboardListener;

  /**
   * The indicator which determines whether {@link #dispose()} has already been invoked on this
   * instance. If <tt>true</tt>, this instance is considered non-functional and is to be left to the
   * garbage collector.
   */
  private boolean disposed = false;

  /** The DTMF label. */
  private final JLabel dtmfLabel = new JLabel();

  /** The component responsible for displaying an error message. */
  private JTextComponent errorMessageComponent;

  /** The label showing whether the call is on or off hold. */
  private final JLabel holdStatusLabel = new JLabel();

  /** Sound local level label. */
  private InputVolumeControlButton localLevel;

  /**
   * The <tt>Component</tt> which {@link #updateViewFromModelInEventDispatchThread()} last added to
   * {@link #center} as the visual <tt>Component</tt> displaying the video streaming from the local
   * peer/user to the remote peer(s).
   *
   * <p><b>Warning</b>: It is not to be used for any other purposes because it may not represent the
   * current state of the model of this view.
   */
  private Component localVideo;

  /** The label showing whether the voice has been set to mute. */
  private final JLabel muteStatusLabel = new JLabel();

  /** The <tt>Icon</tt> which represents the avatar of the associated call peer. */
  private ImageIcon peerImage;

  /** The name of the peer. */
  private String peerName;

  /** The label containing the user photo. */
  private final JLabel photoLabel;

  /** Sound remote level label. */
  private Component remoteLevel;

  /**
   * The <tt>Component</tt> which {@link #updateViewFromModelInEventDispatchThread()} last added to
   * {@link #center} as the visual <tt>Component</tt> displaying the video streaming from the remote
   * peer(s) to the local peer/user.
   *
   * <p><b>Warning</b>: It is not to be used for any other purposes because it may not represent the
   * current state of the model of this view.
   */
  private Component remoteVideo;

  /** Current id for security image. */
  private ImageID securityImageID = ImageLoader.SECURE_BUTTON_OFF;

  /** The panel containing security related components. */
  private SecurityPanel<?> securityPanel;

  /** The security status of the peer */
  private final SecurityStatusLabel securityStatusLabel = new SecurityStatusLabel();

  /** The status bar component. */
  private final Component statusBar;

  /** The facility which aids this instance in the dealing with the video-related information. */
  private final UIVideoHandler2 uiVideoHandler;

  /**
   * The <tt>Observer</tt> which listens to changes in the video-related information detected and
   * reported by {@link #uiVideoHandler}.
   */
  private final Observer uiVideoHandlerObserver =
      new Observer() {
        public void update(Observable o, Object arg) {
          updateViewFromModel();
        }
      };

  /**
   * The <tt>Runnable</tt> which is scheduled by {@link #updateViewFromModel()} for execution in the
   * AWT event dispatching thread in order to invoke {@link
   * #updateViewFromModelInEventDispatchThread()}.
   */
  private final Runnable updateViewFromModelInEventDispatchThread =
      new Runnable() {
        public void run() {
          /*
           * We receive events/notifications from various threads and we
           * respond to them in the AWT event dispatching thread. It is
           * possible to first schedule an event to be brought to the AWT
           * event dispatching thread, then to have #dispose() invoked on
           * this instance and, finally, to receive the scheduled event in
           * the AWT event dispatching thread. In such a case, this
           * disposed instance should not respond to the event.
           */
          if (!disposed) updateViewFromModelInEventDispatchThread();
        }
      };

  /**
   * 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();
  }

  /**
   * Creates the <tt>Component</tt> hierarchy of the central area of this <tt>CallPeerPanel</tt>
   * which displays the photo of the <tt>CallPeer</tt> or the video if any.
   */
  private VideoContainer createCenter() {
    photoLabel.setPreferredSize(new Dimension(90, 90));

    return createVideoContainer(photoLabel);
  }

  /** Creates sound level related components. */
  private void createSoundLevelIndicators() {
    TransparentPanel localLevelPanel = new TransparentPanel(new BorderLayout(5, 0));
    TransparentPanel remoteLevelPanel = new TransparentPanel(new BorderLayout(5, 0));

    localLevel =
        new InputVolumeControlButton(
            call, ImageLoader.MICROPHONE, ImageLoader.MUTE_BUTTON, false, false);
    remoteLevel =
        new OutputVolumeControlButton(call.getConference(), ImageLoader.HEADPHONE, false, false)
            .getComponent();

    final SoundLevelIndicator localLevelIndicator =
        new SoundLevelIndicator(SoundLevelChangeEvent.MIN_LEVEL, SoundLevelChangeEvent.MAX_LEVEL);
    final SoundLevelIndicator remoteLevelIndicator =
        new SoundLevelIndicator(SoundLevelChangeEvent.MIN_LEVEL, SoundLevelChangeEvent.MAX_LEVEL);

    localLevelPanel.add(localLevel, BorderLayout.WEST);
    localLevelPanel.add(localLevelIndicator, BorderLayout.CENTER);
    remoteLevelPanel.add(remoteLevel, BorderLayout.WEST);
    remoteLevelPanel.add(remoteLevelIndicator, BorderLayout.CENTER);

    GridBagConstraints constraints = new GridBagConstraints();
    constraints.fill = GridBagConstraints.NONE;
    constraints.gridx = 0;
    constraints.gridy = 5;
    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.insets = new Insets(10, 0, 0, 0);

    add(localLevelPanel, constraints);

    constraints.fill = GridBagConstraints.NONE;
    constraints.gridx = 0;
    constraints.gridy = 6;
    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.insets = new Insets(5, 0, 10, 0);

    add(remoteLevelPanel, constraints);

    if (!GuiActivator.getConfigurationService()
        .getBoolean(
            "net.java.sip.communicator.impl.gui.main.call." + "DISABLE_SOUND_LEVEL_INDICATORS",
            false)) {
      callPeer.addStreamSoundLevelListener(
          new SoundLevelListener() {
            public void soundLevelChanged(Object source, int level) {
              remoteLevelIndicator.updateSoundLevel(level);
            }
          });
      /*
       * By the time the UI gets to be initialized, the callPeer may have
       * been removed from its Call. As far as the UI is concerned, the
       * callPeer will never have a Call again and there will be no audio
       * levels to display anyway so there is no point in throwing a
       * NullPointerException here.
       */
      if (call != null) {
        call.addLocalUserSoundLevelListener(
            new SoundLevelListener() {
              public void soundLevelChanged(Object source, int level) {
                localLevelIndicator.updateSoundLevel(level);
              }
            });
      }
    }
  }

  /**
   * Creates the <tt>Component</tt> hierarchy of the area of status-related information such as
   * <tt>CallPeer</tt> display name, call duration, security status.
   *
   * @return the root of the <tt>Component</tt> hierarchy of the area of status-related information
   *     such as <tt>CallPeer</tt> display name, call duration, security status
   */
  private Component createStatusBar() {
    // stateLabel
    callStatusLabel.setForeground(Color.WHITE);
    dtmfLabel.setForeground(Color.WHITE);
    callStatusLabel.setText(callPeer.getState().getLocalizedStateString());

    PeerStatusPanel statusPanel = new PeerStatusPanel(new GridBagLayout());

    GridBagConstraints constraints = new GridBagConstraints();

    constraints.gridx = 0;
    constraints.gridy = 0;
    statusPanel.add(securityStatusLabel, constraints);
    initSecurityStatusLabel();

    constraints.gridx++;
    statusPanel.add(holdStatusLabel, constraints);

    constraints.gridx++;
    statusPanel.add(muteStatusLabel, constraints);

    constraints.gridx++;
    callStatusLabel.setBorder(BorderFactory.createEmptyBorder(2, 3, 2, 12));
    statusPanel.add(callStatusLabel, constraints);

    constraints.gridx++;
    constraints.weightx = 1f;
    statusPanel.add(dtmfLabel, constraints);

    return statusPanel;
  }

  /**
   * 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);
    }
  }

  /**
   * Returns the parent <tt>CallPanel</tt> containing this renderer.
   *
   * @return the parent <tt>CallPanel</tt> containing this renderer
   */
  public CallPanel getCallPanel() {
    return callRenderer.getCallContainer();
  }

  /**
   * Returns the parent call renderer.
   *
   * @return the parent call renderer
   */
  public CallRenderer getCallRenderer() {
    return callRenderer;
  }

  /**
   * Returns the component associated with this renderer.
   *
   * @return the component associated with this renderer
   */
  public Component getComponent() {
    return this;
  }

  /**
   * Returns the name of the peer, contained in this panel.
   *
   * @return the name of the peer, contained in this panel
   */
  public String getPeerName() {
    return peerName;
  }

  /**
   * Gets the <tt>Icon</tt> to be displayed in {@link #photoLabel}.
   *
   * @return the <tt>Icon</tt> to be displayed in {@link #photoLabel}
   */
  private ImageIcon getPhotoLabelIcon() {
    return (peerImage == null)
        ? new ImageIcon(ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO))
        : peerImage;
  }

  /** Initializes the security settings for this call peer. */
  private void initSecuritySettings() {
    CallPeerSecurityStatusEvent securityEvent = callPeer.getCurrentSecuritySettings();

    if (securityEvent instanceof CallPeerSecurityOnEvent)
      securityOn((CallPeerSecurityOnEvent) securityEvent);
  }

  /** Initializes the security status label, shown in the call status bar. */
  private void initSecurityStatusLabel() {
    securityStatusLabel.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));

    securityStatusLabel.addMouseListener(
        new MouseAdapter() {
          /** Invoked when a mouse button has been pressed on a component. */
          @Override
          public void mousePressed(MouseEvent e) {
            // Only show the security details if the security is on.
            SrtpControl ctrl = securityPanel.getSecurityControl();
            if (ctrl instanceof ZrtpControl && ctrl.getSecureCommunicationStatus()) {
              setSecurityPanelVisible(
                  !callRenderer
                      .getCallContainer()
                      .getCallWindow()
                      .getFrame()
                      .getGlassPane()
                      .isVisible());
            }
          }
        });
  }

  /**
   * Determines whether the visual <tt>Component</tt> depicting the video streaming from the local
   * peer/user to the remote peer(s) is currently visible.
   *
   * @return <tt>true</tt> if the visual <tt>Component</tt> depicting the video streaming from the
   *     local peer/user to the remote peer(s) is currently visible; otherwise, <tt>false</tt>
   */
  public boolean isLocalVideoVisible() {
    return uiVideoHandler.isLocalVideoVisible();
  }

  /** Reloads all icons. */
  public void loadSkin() {
    if (localLevel != null)
      localLevel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.MICROPHONE)));

    if (remoteLevel != null && remoteLevel instanceof Skinnable)
      ((Skinnable) remoteLevel).loadSkin();

    if (muteStatusLabel.getIcon() != null)
      muteStatusLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.MUTE_STATUS_ICON)));

    if (holdStatusLabel.getIcon() != null)
      holdStatusLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.HOLD_STATUS_ICON)));

    securityStatusLabel.setIcon(new ImageIcon(ImageLoader.getImage(securityImageID)));

    if (peerImage == null) {
      photoLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO)));
    }
  }

  /**
   * Prints the given DTMG character through this <tt>CallPeerRenderer</tt>.
   *
   * @param dtmfChar the DTMF char to print
   */
  public void printDTMFTone(char dtmfChar) {
    dtmfLabel.setText(dtmfLabel.getText() + dtmfChar);
    if (dtmfLabel.getBorder() == null)
      dtmfLabel.setBorder(BorderFactory.createEmptyBorder(2, 1, 2, 5));
  }

  /**
   * Notifies this instance about a change in the value of a property of a source which of interest
   * to this instance. For example, <tt>OneToOneCallPeerPanel</tt> updates its user
   * interface-related properties upon changes in the value of the {@link
   * CallContainer#PROP_FULL_SCREEN} property of its associated {@link #callRenderer}.
   *
   * @param ev a <tt>PropertyChangeEvent</tt> which identifies the source, the name of the property
   *     and the old and new values
   */
  public void propertyChange(PropertyChangeEvent ev) {
    if (CallContainer.PROP_FULL_SCREEN.equals(ev.getPropertyName())) updateViewFromModel();
  }

  /**
   * 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();
  }

  /**
   * The handler for the security event received. The security event for starting establish a secure
   * connection.
   *
   * @param evt the security started event received
   */
  public void securityNegotiationStarted(CallPeerSecurityNegotiationStartedEvent evt) {
    if (Boolean.parseBoolean(
        GuiActivator.getResources().getSettingsString("impl.gui.PARANOIA_UI"))) {
      SrtpControl srtpControl = null;
      if (callPeer instanceof MediaAwareCallPeer) srtpControl = evt.getSecurityController();

      securityPanel = new ParanoiaTimerSecurityPanel<SrtpControl>(srtpControl);

      setSecurityPanelVisible(true);
    }
  }

  /**
   * Indicates that the security has gone off.
   *
   * @param evt the <tt>CallPeerSecurityOffEvent</tt> that notified us
   */
  public void securityOff(final CallPeerSecurityOffEvent evt) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              securityOff(evt);
            }
          });
      return;
    }

    if (evt.getSessionType() == CallPeerSecurityOffEvent.AUDIO_SESSION) {
      securityStatusLabel.setText("");
      securityStatusLabel.setSecurityOff();
      if (securityStatusLabel.getBorder() == null)
        securityStatusLabel.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 3));
    }

    securityPanel.securityOff(evt);
  }

  /**
   * Indicates that the security is turned on.
   *
   * <p>Sets the secured status icon to the status panel and initializes/updates the corresponding
   * security details.
   *
   * @param evt Details about the event that caused this message.
   */
  public void securityOn(final CallPeerSecurityOnEvent evt) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              securityOn(evt);
            }
          });
      return;
    }

    // If the securityOn is called without a specific event, we'll just set
    // the security label status to on.
    if (evt == null) {
      securityStatusLabel.setSecurityOn();
      return;
    }

    SrtpControl srtpControl = evt.getSecurityController();

    if (!srtpControl.requiresSecureSignalingTransport()
        || callPeer.getProtocolProvider().isSignalingTransportSecure()) {
      if (srtpControl instanceof ZrtpControl) {
        securityStatusLabel.setText("zrtp");

        if (!((ZrtpControl) srtpControl).isSecurityVerified())
          securityStatusLabel.setSecurityPending();
        else securityStatusLabel.setSecurityOn();
      } else securityStatusLabel.setSecurityOn();
    }

    // if we have some other panel, using other control
    if (!srtpControl.getClass().isInstance(securityPanel.getSecurityControl())
        || (securityPanel instanceof ParanoiaTimerSecurityPanel)) {
      setSecurityPanelVisible(false);

      securityPanel = SecurityPanel.create(this, callPeer, srtpControl);

      if (srtpControl instanceof ZrtpControl)
        ((ZrtpSecurityPanel) securityPanel).setSecurityStatusLabel(securityStatusLabel);
    }

    securityPanel.securityOn(evt);

    boolean isSecurityLowPriority =
        Boolean.parseBoolean(
            GuiActivator.getResources()
                .getSettingsString("impl.gui.I_DONT_CARE_THAT_MUCH_ABOUT_SECURITY"));

    // Display ZRTP panel in case SAS was not verified or a AOR mismtach
    // was detected during creation of ZrtpSecurityPanel.
    // Don't show panel if user does not care about security at all.
    if (srtpControl instanceof ZrtpControl
        && !isSecurityLowPriority
        && (!((ZrtpControl) srtpControl).isSecurityVerified()
            || ((ZrtpSecurityPanel) securityPanel).isZidAorMismatch())) {
      setSecurityPanelVisible(true);
    }

    this.revalidate();
  }

  /** Indicates that the security status is pending confirmation. */
  public void securityPending() {
    securityStatusLabel.setSecurityPending();
  }

  /**
   * Indicates that the security is timeouted, is not supported by the other end.
   *
   * @param evt Details about the event that caused this message.
   */
  public void securityTimeout(final CallPeerSecurityTimeoutEvent evt) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              securityTimeout(evt);
            }
          });
      return;
    }

    if (securityPanel != null) securityPanel.securityTimeout(evt);
  }

  /**
   * Sets the reason of a call failure if one occurs. The renderer should display this reason to the
   * user.
   *
   * @param reason the reason to display
   */
  public void setErrorReason(final String reason) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              setErrorReason(reason);
            }
          });
      return;
    }

    if (errorMessageComponent == null) {
      errorMessageComponent = new JTextPane();

      JTextPane textPane = (JTextPane) errorMessageComponent;
      textPane.setEditable(false);
      textPane.setOpaque(false);

      StyledDocument doc = textPane.getStyledDocument();

      MutableAttributeSet standard = new SimpleAttributeSet();
      StyleConstants.setAlignment(standard, StyleConstants.ALIGN_CENTER);
      StyleConstants.setFontFamily(standard, textPane.getFont().getFamily());
      StyleConstants.setFontSize(standard, 12);
      doc.setParagraphAttributes(0, 0, standard, true);

      GridBagConstraints constraints = new GridBagConstraints();
      constraints.fill = GridBagConstraints.HORIZONTAL;
      constraints.gridx = 0;
      constraints.gridy = 4;
      constraints.weightx = 1;
      constraints.weighty = 0;
      constraints.insets = new Insets(5, 0, 0, 0);

      add(errorMessageComponent, constraints);
      this.revalidate();
    }

    errorMessageComponent.setText(reason);

    if (isVisible()) errorMessageComponent.repaint();
  }

  /**
   * Shows/hides the visual <tt>Component</tt> depicting the video streaming from the local
   * peer/user to the remote peer(s).
   *
   * @param visible <tt>true</tt> to show the visual <tt>Component</tt> depicting the video
   *     streaming from the local peer/user to the remote peer(s); <tt>false</tt>, otherwise
   */
  public void setLocalVideoVisible(boolean visible) {
    uiVideoHandler.setLocalVideoVisible(visible);
  }

  /**
   * Sets the mute status icon to the status panel.
   *
   * @param isMute indicates if the call with this peer is muted
   */
  public void setMute(final boolean isMute) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              setMute(isMute);
            }
          });
      return;
    }

    if (isMute) {
      muteStatusLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.MUTE_STATUS_ICON)));
      muteStatusLabel.setBorder(BorderFactory.createEmptyBorder(2, 3, 2, 3));
    } else {
      muteStatusLabel.setIcon(null);
      muteStatusLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
    }

    // Update input volume control button state to reflect the current
    // mute status.
    if (localLevel.isSelected() != isMute) localLevel.setSelected(isMute);

    this.revalidate();
    this.repaint();
  }

  /**
   * Sets the "on hold" property value.
   *
   * @param isOnHold indicates if the call with this peer is put on hold
   */
  public void setOnHold(final boolean isOnHold) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              setOnHold(isOnHold);
            }
          });
      return;
    }

    if (isOnHold) {
      holdStatusLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.HOLD_STATUS_ICON)));
      holdStatusLabel.setBorder(BorderFactory.createEmptyBorder(2, 3, 2, 3));
    } else {
      holdStatusLabel.setIcon(null);
      holdStatusLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
    }

    this.revalidate();
    this.repaint();
  }

  /**
   * Set the image of the peer
   *
   * @param image new image
   */
  public void setPeerImage(byte[] image) {
    // If the image is still null we try to obtain it from one of the
    // available contact sources.
    if (image == null || image.length <= 0) {
      GuiActivator.getContactList().setSourceContactImage(peerName, photoLabel, 100, 100);
    } else {
      peerImage = ImageUtils.getScaledRoundedIcon(image, 100, 100);
      if (peerImage == null) peerImage = getPhotoLabelIcon();

      if (!SwingUtilities.isEventDispatchThread()) {
        SwingUtilities.invokeLater(
            new Runnable() {
              public void run() {
                photoLabel.setIcon(peerImage);
                photoLabel.repaint();
              }
            });
      } else {
        photoLabel.setIcon(peerImage);
        photoLabel.repaint();
      }
    }
  }

  /**
   * Sets the name of the peer.
   *
   * @param name the name of the peer
   */
  public void setPeerName(final String name) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              setPeerName(name);
            }
          });
      return;
    }

    peerName = name;

    ((OneToOneCallPanel) callRenderer).setPeerName(name);
  }

  /**
   * Sets the state of the contained call peer by specifying the state name.
   *
   * @param oldState the previous state of the peer
   * @param newState the new state of the peer
   * @param stateString the state of the contained call peer
   */
  public void setPeerState(
      final CallPeerState oldState, final CallPeerState newState, final String stateString) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              setPeerState(oldState, newState, stateString);
            }
          });
      return;
    }

    this.callStatusLabel.setText(stateString);

    if (newState == CallPeerState.CONNECTED
        && !CallPeerState.isOnHold(oldState)
        && !securityStatusLabel.isSecurityStatusSet()) {
      securityStatusLabel.setSecurityOff();
    }
  }

  /**
   * Shows/hides the security panel.
   *
   * @param isVisible <tt>true</tt> to show the security panel, <tt>false</tt> to hide it
   */
  public void setSecurityPanelVisible(final boolean isVisible) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              setSecurityPanelVisible(isVisible);
            }
          });
      return;
    }

    final JFrame callFrame = callRenderer.getCallContainer().getCallWindow().getFrame();

    final JPanel glassPane = (JPanel) callFrame.getGlassPane();

    if (!isVisible) {
      // Need to hide the security panel explicitly in order to keep the
      // fade effect.
      securityPanel.setVisible(false);
      glassPane.setVisible(false);
      glassPane.removeAll();
    } else {
      glassPane.setLayout(null);
      glassPane.addMouseListener(
          new MouseListener() {
            public void mouseClicked(MouseEvent e) {
              redispatchMouseEvent(glassPane, e);
            }

            public void mouseEntered(MouseEvent e) {
              redispatchMouseEvent(glassPane, e);
            }

            public void mouseExited(MouseEvent e) {
              redispatchMouseEvent(glassPane, e);
            }

            public void mousePressed(MouseEvent e) {
              redispatchMouseEvent(glassPane, e);
            }

            public void mouseReleased(MouseEvent e) {
              redispatchMouseEvent(glassPane, e);
            }
          });

      Point securityLabelPoint = securityStatusLabel.getLocation();

      Point newPoint =
          SwingUtilities.convertPoint(
              securityStatusLabel.getParent(),
              securityLabelPoint.x,
              securityLabelPoint.y,
              callFrame);

      securityPanel.setBeginPoint(new Point((int) newPoint.getX() + 15, 0));
      securityPanel.setBounds(0, (int) newPoint.getY() - 5, this.getWidth(), 130);

      glassPane.add(securityPanel);
      // Need to show the security panel explicitly in order to keep the
      // fade effect.
      securityPanel.setVisible(true);
      glassPane.setVisible(true);

      glassPane.addComponentListener(
          new ComponentAdapter() {
            /** Invoked when the component's size changes. */
            @Override
            public void componentResized(ComponentEvent e) {
              if (glassPane.isVisible()) {
                glassPane.setVisible(false);
                callFrame.removeComponentListener(this);
              }
            }
          });
    }
  }

  /**
   * Updates this view i.e. <tt>OneToOneCallPeerPanel</tt> so that it depicts the current state of
   * its model i.e. <tt>callPeer</tt>.
   */
  private void updateViewFromModel() {
    /*
     * We receive events/notifications from various threads and we respond
     * to them in the AWT event dispatching thread. It is possible to first
     * schedule an event to be brought to the AWT event dispatching thread,
     * then to have #dispose() invoked on this instance and, finally, to
     * receive the scheduled event in the AWT event dispatching thread. In
     * such a case, this disposed instance should not respond to the event
     * because it may, for example, steal a visual Components depicting
     * video (which cannot belong to more than one parent at a time) from
     * another non-disposed OneToOneCallPeerPanel.
     */
    if (!disposed) {
      if (SwingUtilities.isEventDispatchThread()) updateViewFromModelInEventDispatchThread();
      else {
        SwingUtilities.invokeLater(updateViewFromModelInEventDispatchThread);
      }
    }
  }

  /**
   * Updates this view i.e. <tt>OneToOneCallPeerPanel</tt> so that it depicts the current state of
   * its model i.e. <tt>callPeer</tt>. The update is performed in the AWT event dispatching thread.
   */
  private void updateViewFromModelInEventDispatchThread() {
    /*
     * We receive events/notifications from various threads and we respond
     * to them in the AWT event dispatching thread. It is possible to first
     * schedule an event to be brought to the AWT event dispatching thread,
     * then to have #dispose() invoked on this instance and, finally, to
     * receive the scheduled event in the AWT event dispatching thread. In
     * such a case, this disposed instance should not respond to the event
     * because it may, for example, steal a visual Components depicting
     * video (which cannot belong to more than one parent at a time) from
     * another non-disposed OneToOneCallPeerPanel.
     */
    if (disposed) return;

    /*
     * Update the display of visual <tt>Component</tt>s depicting video
     * streaming between the local peer/user and the remote peer(s).
     */

    OperationSetVideoTelephony videoTelephony =
        callPeer.getProtocolProvider().getOperationSet(OperationSetVideoTelephony.class);
    Component remoteVideo = null;
    Component localVideo = null;

    if (videoTelephony != null) {
      List<Component> remoteVideos = videoTelephony.getVisualComponents(callPeer);

      if ((remoteVideos != null) && !remoteVideos.isEmpty()) {
        /*
         * TODO OneToOneCallPeerPanel displays a one-to-one conversation
         * between the local peer/user and a specific remote peer. If
         * the remote peer is the focus of a telephony conference of its
         * own, it may be sending multiple videos to the local peer.
         * Switching to a user interface which displays multiple videos
         * is the responsibility of whoever decided that this
         * OneToOneCallPeerPanel is to be used to depict the current
         * state of the CallConference associated with the CallPeer
         * depicted by this instance. If that switching decides that
         * this instance is to continue being the user interface, then
         * we should probably pick up the remote video which is
         * generated by the remote peer and not one of its
         * ConferenceMembers.
         */
        remoteVideo = remoteVideos.get(0);
      }

      if (uiVideoHandler.isLocalVideoVisible()) {
        try {
          localVideo = videoTelephony.getLocalVisualComponent(callPeer);
        } catch (OperationFailedException ofe) {
          /*
           * Well, we cannot do much about the exception. We'll just
           * not display the local video.
           */
          logger.warn("Failed to retrieve local video to be displayed.", ofe);
        }
      }

      /*
       * Determine whether there is actually a change in the local and
       * remote videos which requires an update.
       */
      boolean localVideoChanged =
          ((localVideo != this.localVideo)
              || ((localVideo != null) && !UIVideoHandler2.isAncestor(center, localVideo)));
      boolean remoteVideoChanged =
          ((remoteVideo != this.remoteVideo)
              || ((remoteVideo != null) && !UIVideoHandler2.isAncestor(center, remoteVideo)));

      // If the remote video has changed, maybe the CallPanel can display
      // the LO/SD/HD button.
      if (remoteVideoChanged) {
        // Updates video component which may listen the mouse and key
        // events.
        if (desktopSharingMouseAndKeyboardListener != null) {
          desktopSharingMouseAndKeyboardListener.setVideoComponent(remoteVideo);
        }

        CallPanel callPanel = callRenderer.getCallContainer();
        // The remote video has been added, then tries to display the
        // LO/SD/HD button.
        if (remoteVideo != null) {
          callPanel.addRemoteVideoSpecificComponents(callPeer);
        }
        // The remote video has been removed, then hide the LO/SD/HD
        // button if it is currently displayed.
        else {
          callPanel.removeRemoteVideoSpecificComponents();
        }
      }

      if (localVideoChanged || remoteVideoChanged) {
        /*
         * VideoContainer and JAWTRenderer cannot handle random
         * additions of Components. Removing the localVideo when the
         * user has requests its hiding though, should work without
         * removing all Components from the VideoCotainer and adding
         * them again.
         */
        if (localVideoChanged && !remoteVideoChanged && (localVideo == null)) {
          if (this.localVideo != null) {
            center.remove(this.localVideo);
            this.localVideo = null;

            if (closeLocalVisualComponentButton != null)
              center.remove(closeLocalVisualComponentButton);
          }
        } else {
          center.removeAll();
          this.localVideo = null;
          this.remoteVideo = null;

          /*
           * AWT does not make a guarantee about the Z order even
           * within an operating system i.e. the order of adding the
           * Components to their Container does not mean that they
           * will be determinedly painted in that or reverse order.
           * Anyway, there appears to be an expectation among the
           * developers less acquainted with AWT that AWT paints the
           * Components of a Container in an order that is the reverse
           * of the order of their adding. In order to satisfy that
           * expectation and thus give at least some idea to the
           * developers reading the code bellow, do add the Components
           * according to that expectation.
           */

          if (localVideo != null) {
            if (closeLocalVisualComponentButton == null) {
              closeLocalVisualComponentButton = new CloseLocalVisualComponentButton(uiVideoHandler);
            }
            center.add(closeLocalVisualComponentButton, VideoLayout.CLOSE_LOCAL_BUTTON, -1);

            center.add(localVideo, VideoLayout.LOCAL, -1);
            this.localVideo = localVideo;
          }

          if (remoteVideo != null) {
            center.add(remoteVideo, VideoLayout.CENTER_REMOTE, -1);
            this.remoteVideo = remoteVideo;
          }
        }
      }
    }
  }

  /** The <tt>TransparentPanel</tt> that will display the peer status. */
  private static class PeerStatusPanel extends TransparentPanel {
    /**
     * Silence the serial warning. Though there isn't a plan to serialize the instances of the
     * class, there're no fields so the default serialization routine will work.
     */
    private static final long serialVersionUID = 0L;

    /**
     * Constructs a new <tt>PeerStatusPanel</tt>.
     *
     * @param layout the <tt>LayoutManager</tt> to use
     */
    public PeerStatusPanel(LayoutManager layout) {
      super(layout);
    }

    /** @{inheritDoc} */
    @Override
    public void paintComponent(Graphics g) {
      super.paintComponent(g);

      g = g.create();

      try {
        AntialiasingManager.activateAntialiasing(g);

        g.setColor(Color.DARK_GRAY);
        g.fillRoundRect(0, 0, this.getWidth(), this.getHeight(), 10, 10);
      } finally {
        g.dispose();
      }
    }
  }
}
예제 #13
0
  /**
   * Updates this view i.e. <tt>OneToOneCallPeerPanel</tt> so that it depicts the current state of
   * its model i.e. <tt>callPeer</tt>. The update is performed in the AWT event dispatching thread.
   */
  private void updateViewFromModelInEventDispatchThread() {
    /*
     * We receive events/notifications from various threads and we respond
     * to them in the AWT event dispatching thread. It is possible to first
     * schedule an event to be brought to the AWT event dispatching thread,
     * then to have #dispose() invoked on this instance and, finally, to
     * receive the scheduled event in the AWT event dispatching thread. In
     * such a case, this disposed instance should not respond to the event
     * because it may, for example, steal a visual Components depicting
     * video (which cannot belong to more than one parent at a time) from
     * another non-disposed OneToOneCallPeerPanel.
     */
    if (disposed) return;

    /*
     * Update the display of visual <tt>Component</tt>s depicting video
     * streaming between the local peer/user and the remote peer(s).
     */

    OperationSetVideoTelephony videoTelephony =
        callPeer.getProtocolProvider().getOperationSet(OperationSetVideoTelephony.class);
    Component remoteVideo = null;
    Component localVideo = null;

    if (videoTelephony != null) {
      List<Component> remoteVideos = videoTelephony.getVisualComponents(callPeer);

      if ((remoteVideos != null) && !remoteVideos.isEmpty()) {
        /*
         * TODO OneToOneCallPeerPanel displays a one-to-one conversation
         * between the local peer/user and a specific remote peer. If
         * the remote peer is the focus of a telephony conference of its
         * own, it may be sending multiple videos to the local peer.
         * Switching to a user interface which displays multiple videos
         * is the responsibility of whoever decided that this
         * OneToOneCallPeerPanel is to be used to depict the current
         * state of the CallConference associated with the CallPeer
         * depicted by this instance. If that switching decides that
         * this instance is to continue being the user interface, then
         * we should probably pick up the remote video which is
         * generated by the remote peer and not one of its
         * ConferenceMembers.
         */
        remoteVideo = remoteVideos.get(0);
      }

      if (uiVideoHandler.isLocalVideoVisible()) {
        try {
          localVideo = videoTelephony.getLocalVisualComponent(callPeer);
        } catch (OperationFailedException ofe) {
          /*
           * Well, we cannot do much about the exception. We'll just
           * not display the local video.
           */
          logger.warn("Failed to retrieve local video to be displayed.", ofe);
        }
      }

      /*
       * Determine whether there is actually a change in the local and
       * remote videos which requires an update.
       */
      boolean localVideoChanged =
          ((localVideo != this.localVideo)
              || ((localVideo != null) && !UIVideoHandler2.isAncestor(center, localVideo)));
      boolean remoteVideoChanged =
          ((remoteVideo != this.remoteVideo)
              || ((remoteVideo != null) && !UIVideoHandler2.isAncestor(center, remoteVideo)));

      // If the remote video has changed, maybe the CallPanel can display
      // the LO/SD/HD button.
      if (remoteVideoChanged) {
        // Updates video component which may listen the mouse and key
        // events.
        if (desktopSharingMouseAndKeyboardListener != null) {
          desktopSharingMouseAndKeyboardListener.setVideoComponent(remoteVideo);
        }

        CallPanel callPanel = callRenderer.getCallContainer();
        // The remote video has been added, then tries to display the
        // LO/SD/HD button.
        if (remoteVideo != null) {
          callPanel.addRemoteVideoSpecificComponents(callPeer);
        }
        // The remote video has been removed, then hide the LO/SD/HD
        // button if it is currently displayed.
        else {
          callPanel.removeRemoteVideoSpecificComponents();
        }
      }

      if (localVideoChanged || remoteVideoChanged) {
        /*
         * VideoContainer and JAWTRenderer cannot handle random
         * additions of Components. Removing the localVideo when the
         * user has requests its hiding though, should work without
         * removing all Components from the VideoCotainer and adding
         * them again.
         */
        if (localVideoChanged && !remoteVideoChanged && (localVideo == null)) {
          if (this.localVideo != null) {
            center.remove(this.localVideo);
            this.localVideo = null;

            if (closeLocalVisualComponentButton != null)
              center.remove(closeLocalVisualComponentButton);
          }
        } else {
          center.removeAll();
          this.localVideo = null;
          this.remoteVideo = null;

          /*
           * AWT does not make a guarantee about the Z order even
           * within an operating system i.e. the order of adding the
           * Components to their Container does not mean that they
           * will be determinedly painted in that or reverse order.
           * Anyway, there appears to be an expectation among the
           * developers less acquainted with AWT that AWT paints the
           * Components of a Container in an order that is the reverse
           * of the order of their adding. In order to satisfy that
           * expectation and thus give at least some idea to the
           * developers reading the code bellow, do add the Components
           * according to that expectation.
           */

          if (localVideo != null) {
            if (closeLocalVisualComponentButton == null) {
              closeLocalVisualComponentButton = new CloseLocalVisualComponentButton(uiVideoHandler);
            }
            center.add(closeLocalVisualComponentButton, VideoLayout.CLOSE_LOCAL_BUTTON, -1);

            center.add(localVideo, VideoLayout.LOCAL, -1);
            this.localVideo = localVideo;
          }

          if (remoteVideo != null) {
            center.add(remoteVideo, VideoLayout.CENTER_REMOTE, -1);
            this.remoteVideo = remoteVideo;
          }
        }
      }
    }
  }
  /**
   * Handles buttons action events.
   *
   * @param evt the <tt>ActionEvent</tt> that notified us
   */
  public void actionPerformed(ActionEvent evt) {
    JButton sourceButton = (JButton) evt.getSource();

    if (sourceButton.equals(openFileButton)) {
      this.openFile(downloadFile);
    } else if (sourceButton.equals(openFolderButton)) {
      try {
        File downloadDir = GuiActivator.getFileAccessService().getDefaultDownloadDirectory();

        GuiActivator.getDesktopService().open(downloadDir);
      } catch (IllegalArgumentException e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_DOES_NOT_EXIST"));
      } catch (NullPointerException e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_DOES_NOT_EXIST"));
      } catch (UnsupportedOperationException e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FILE_OPEN_NOT_SUPPORTED"));
      } catch (SecurityException e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_OPEN_NO_PERMISSION"));
      } catch (IOException e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_OPEN_NO_APPLICATION"));
      } catch (Exception e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open file.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_OPEN_FAILED"));
      }
    } else if (sourceButton.equals(cancelButton)) {
      if (fileTransfer != null) fileTransfer.cancel();
    }
  }
/**
 * The <tt>FileTransferConversationComponent</tt> is the parent of all file conversation components
 * - for incoming, outgoing and history file transfers.
 *
 * @author Yana Stamcheva
 * @author Adam Netocny
 */
public abstract class FileTransferConversationComponent extends ChatConversationComponent
    implements ActionListener, FileTransferProgressListener, Skinnable {
  /** The logger for this class. */
  private final Logger logger = Logger.getLogger(FileTransferConversationComponent.class);

  /** Image default width. */
  protected static final int IMAGE_WIDTH = 64;

  /** Image default height. */
  protected static final int IMAGE_HEIGHT = 64;

  /** The image label. */
  protected final FileImageLabel imageLabel;

  /** The title label. */
  protected final JLabel titleLabel = new JLabel();

  /** The file label. */
  protected final JLabel fileLabel = new JLabel();

  /** The error area. */
  private final JTextArea errorArea = new JTextArea();

  /** The error icon label. */
  private final JLabel errorIconLabel =
      new JLabel(new ImageIcon(ImageLoader.getImage(ImageLoader.EXCLAMATION_MARK)));

  /** The cancel button. */
  protected final ChatConversationButton cancelButton = new ChatConversationButton();

  /** The retry button. */
  protected final ChatConversationButton retryButton = new ChatConversationButton();

  /** The accept button. */
  protected final ChatConversationButton acceptButton = new ChatConversationButton();

  /** The reject button. */
  protected final ChatConversationButton rejectButton = new ChatConversationButton();

  /** The open file button. */
  protected final ChatConversationButton openFileButton = new ChatConversationButton();

  /** The open folder button. */
  protected final ChatConversationButton openFolderButton = new ChatConversationButton();

  /** The progress bar. */
  protected final JProgressBar progressBar = new JProgressBar();

  /** The progress properties panel. */
  private final TransparentPanel progressPropertiesPanel =
      new TransparentPanel(new FlowLayout(FlowLayout.RIGHT));

  /** The progress speed label. */
  private final JLabel progressSpeedLabel = new JLabel();

  /** The estimated time label. */
  private final JLabel estimatedTimeLabel = new JLabel();

  /** The download file. */
  private File downloadFile;

  /** The file transfer. */
  private FileTransfer fileTransfer;

  /** The speed calculated delay. */
  private static final int SPEED_CALCULATE_DELAY = 5000;

  /** The transferred file size. */
  private long transferredFileSize = 0;

  /** The time of the last calculated transfer speed. */
  private long lastSpeedTimestamp = 0;

  /** The last estimated time for the transfer. */
  private long lastEstimatedTimeTimestamp = 0;

  /** The number of bytes last transferred. */
  private long lastTransferredBytes = 0;

  /** The last calculated progress speed. */
  private long lastProgressSpeed;

  /** The last estimated time. */
  private long lastEstimatedTime;

  /** Creates a file conversation component. */
  public FileTransferConversationComponent() {
    imageLabel = new FileImageLabel();

    constraints.gridx = 0;
    constraints.gridy = 0;
    constraints.gridwidth = 1;
    constraints.gridheight = 4;
    constraints.anchor = GridBagConstraints.NORTHWEST;
    constraints.insets = new Insets(5, 5, 5, 5);

    add(imageLabel, constraints);
    imageLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON)));

    constraints.gridx = 1;
    constraints.gridy = 0;
    constraints.gridwidth = 3;
    constraints.gridheight = 1;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.weightx = 1.0;
    constraints.anchor = GridBagConstraints.NORTHWEST;
    constraints.insets = new Insets(5, 5, 5, 5);

    add(titleLabel, constraints);
    titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 11f));

    constraints.gridx = 1;
    constraints.gridy = 1;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(0, 5, 5, 5);

    add(fileLabel, constraints);

    constraints.gridx = 1;
    constraints.gridy = 2;
    constraints.gridwidth = 1;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(0, 5, 0, 5);
    constraints.fill = GridBagConstraints.NONE;

    add(errorIconLabel, constraints);
    errorIconLabel.setVisible(false);

    constraints.gridx = 2;
    constraints.gridy = 2;
    constraints.gridwidth = 2;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(0, 5, 0, 5);
    constraints.fill = GridBagConstraints.HORIZONTAL;

    add(errorArea, constraints);
    errorArea.setForeground(new Color(resources.getColor("service.gui.ERROR_FOREGROUND")));
    setTextAreaStyle(errorArea);
    errorArea.setVisible(false);

    constraints.gridx = 1;
    constraints.gridy = 3;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0.0;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(0, 5, 0, 5);

    add(retryButton, constraints);
    retryButton.setText(GuiActivator.getResources().getI18NString("service.gui.RETRY"));
    retryButton.setVisible(false);

    constraints.gridx = 1;
    constraints.gridy = 3;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0.0;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(0, 5, 0, 5);

    add(cancelButton, constraints);
    cancelButton.setText(GuiActivator.getResources().getI18NString("service.gui.CANCEL"));
    cancelButton.addActionListener(this);
    cancelButton.setVisible(false);

    constraints.gridx = 2;
    constraints.gridy = 3;
    constraints.gridwidth = GridBagConstraints.RELATIVE;
    constraints.gridheight = 1;
    constraints.weightx = 0.0;
    constraints.fill = GridBagConstraints.NONE;
    constraints.anchor = GridBagConstraints.EAST;
    constraints.insets = new Insets(0, 5, 0, 5);

    constraints.gridx = 3;
    constraints.gridy = 3;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0.0;
    constraints.fill = GridBagConstraints.NONE;
    constraints.anchor = GridBagConstraints.LINE_END;
    constraints.insets = new Insets(0, 5, 0, 5);

    add(progressPropertiesPanel, constraints);

    estimatedTimeLabel.setFont(estimatedTimeLabel.getFont().deriveFont(11f));
    estimatedTimeLabel.setVisible(false);
    progressSpeedLabel.setFont(progressSpeedLabel.getFont().deriveFont(11f));
    progressSpeedLabel.setVisible(false);

    progressPropertiesPanel.add(progressSpeedLabel);
    progressPropertiesPanel.add(estimatedTimeLabel);

    constraints.gridx = 1;
    constraints.gridy = 3;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0.0;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(0, 5, 0, 5);
    constraints.fill = GridBagConstraints.NONE;

    add(acceptButton, constraints);
    acceptButton.setText(GuiActivator.getResources().getI18NString("service.gui.ACCEPT"));
    acceptButton.setVisible(false);

    constraints.gridx = 2;
    constraints.gridy = 3;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0.0;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(0, 5, 0, 5);
    constraints.fill = GridBagConstraints.NONE;

    add(rejectButton, constraints);
    rejectButton.setText(GuiActivator.getResources().getI18NString("service.gui.REJECT"));
    rejectButton.setVisible(false);

    constraints.gridx = 1;
    constraints.gridy = 3;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0.0;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(0, 5, 0, 5);
    constraints.fill = GridBagConstraints.NONE;

    add(openFileButton, constraints);
    openFileButton.setText(GuiActivator.getResources().getI18NString("service.gui.OPEN"));
    openFileButton.setVisible(false);
    openFileButton.addActionListener(this);

    constraints.gridx = 2;
    constraints.gridy = 3;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0.0;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(0, 5, 0, 5);
    constraints.fill = GridBagConstraints.NONE;

    add(openFolderButton, constraints);
    openFolderButton.setText(GuiActivator.getResources().getI18NString("service.gui.OPEN_FOLDER"));
    openFolderButton.setVisible(false);
    openFolderButton.addActionListener(this);

    constraints.gridx = 1;
    constraints.gridy = 2;
    constraints.gridwidth = 3;
    constraints.gridheight = 1;
    constraints.weightx = 1.0;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(0, 5, 0, 5);
    constraints.ipadx = 150;
    constraints.fill = GridBagConstraints.HORIZONTAL;

    add(progressBar, constraints);
    progressBar.setVisible(false);
    progressBar.setStringPainted(true);
  }

  /**
   * Sets a custom style for the given text area.
   *
   * @param textArea the text area to style
   */
  private void setTextAreaStyle(JTextArea textArea) {
    textArea.setOpaque(false);
    textArea.setLineWrap(true);
    textArea.setWrapStyleWord(true);
  }

  /**
   * Shows the given error message in the error area of this component.
   *
   * @param message the message to show
   */
  protected void showErrorMessage(String message) {
    errorArea.setText(message);
    errorIconLabel.setVisible(true);
    errorArea.setVisible(true);
  }

  /**
   * Sets the download file.
   *
   * @param file the file that has been downloaded or sent
   */
  protected void setCompletedDownloadFile(File file) {
    this.downloadFile = file;

    imageLabel.setFile(downloadFile);

    imageLabel.setToolTipText(resources.getI18NString("service.gui.OPEN_FILE_FROM_IMAGE"));

    imageLabel.addMouseListener(
        new MouseAdapter() {
          public void mouseClicked(MouseEvent e) {
            if (e.getClickCount() > 1) {
              openFile(downloadFile);
            }
          }
        });
  }

  /**
   * Sets the file transfer.
   *
   * @param fileTransfer the file transfer
   * @param transferredFileSize the size of the transferred file
   */
  protected void setFileTransfer(FileTransfer fileTransfer, long transferredFileSize) {
    this.fileTransfer = fileTransfer;
    this.transferredFileSize = transferredFileSize;

    fileTransfer.addProgressListener(this);
  }

  /**
   * Handles buttons action events.
   *
   * @param evt the <tt>ActionEvent</tt> that notified us
   */
  public void actionPerformed(ActionEvent evt) {
    JButton sourceButton = (JButton) evt.getSource();

    if (sourceButton.equals(openFileButton)) {
      this.openFile(downloadFile);
    } else if (sourceButton.equals(openFolderButton)) {
      try {
        File downloadDir = GuiActivator.getFileAccessService().getDefaultDownloadDirectory();

        GuiActivator.getDesktopService().open(downloadDir);
      } catch (IllegalArgumentException e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_DOES_NOT_EXIST"));
      } catch (NullPointerException e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_DOES_NOT_EXIST"));
      } catch (UnsupportedOperationException e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FILE_OPEN_NOT_SUPPORTED"));
      } catch (SecurityException e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_OPEN_NO_PERMISSION"));
      } catch (IOException e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open folder.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_OPEN_NO_APPLICATION"));
      } catch (Exception e) {
        if (logger.isDebugEnabled()) logger.debug("Unable to open file.", e);

        this.showErrorMessage(resources.getI18NString("service.gui.FOLDER_OPEN_FAILED"));
      }
    } else if (sourceButton.equals(cancelButton)) {
      if (fileTransfer != null) fileTransfer.cancel();
    }
  }

  /**
   * Updates progress bar progress line every time a progress event has been received.
   *
   * @param event the <tt>FileTransferProgressEvent</tt> that notified us
   */
  public void progressChanged(FileTransferProgressEvent event) {
    progressBar.setValue((int) event.getProgress());

    long transferredBytes = event.getFileTransfer().getTransferedBytes();
    long progressTimestamp = event.getTimestamp();

    ByteFormat format = new ByteFormat();
    String bytesString = format.format(transferredBytes);

    if ((progressTimestamp - lastSpeedTimestamp) >= SPEED_CALCULATE_DELAY) {
      lastProgressSpeed = Math.round(calculateProgressSpeed(transferredBytes));

      this.lastSpeedTimestamp = progressTimestamp;
      this.lastTransferredBytes = transferredBytes;
    }

    if ((progressTimestamp - lastEstimatedTimeTimestamp) >= SPEED_CALCULATE_DELAY
        && lastProgressSpeed > 0) {
      lastEstimatedTime =
          Math.round(
              calculateEstimatedTransferTime(
                  lastProgressSpeed, transferredFileSize - transferredBytes));

      lastEstimatedTimeTimestamp = progressTimestamp;
    }

    progressBar.setString(getProgressLabel(bytesString));

    if (lastProgressSpeed > 0) {
      progressSpeedLabel.setText(
          resources.getI18NString("service.gui.SPEED") + format.format(lastProgressSpeed) + "/sec");
      progressSpeedLabel.setVisible(true);
    }

    if (lastEstimatedTime > 0) {
      estimatedTimeLabel.setText(
          resources.getI18NString("service.gui.ESTIMATED_TIME")
              + GuiUtils.formatSeconds(lastEstimatedTime * 1000));
      estimatedTimeLabel.setVisible(true);
    }
  }

  /**
   * Returns the string, showing information for the given file.
   *
   * @param file the file
   * @return the name of the given file
   */
  protected String getFileLabel(File file) {
    String fileName = file.getName();
    long fileSize = file.length();

    ByteFormat format = new ByteFormat();
    String text = format.format(fileSize);

    return fileName + " (" + text + ")";
  }

  /**
   * Returns the string, showing information for the given file.
   *
   * @param fileName the name of the file
   * @param fileSize the size of the file
   * @return the name of the given file
   */
  protected String getFileLabel(String fileName, long fileSize) {
    ByteFormat format = new ByteFormat();
    String text = format.format(fileSize);

    return fileName + " (" + text + ")";
  }

  /** Hides all progress related components. */
  protected void hideProgressRelatedComponents() {
    progressBar.setVisible(false);
    progressSpeedLabel.setVisible(false);
    estimatedTimeLabel.setVisible(false);
  }

  /**
   * Returns the label to show on the progress bar.
   *
   * @param bytesString the bytes that have been transfered
   * @return the label to show on the progress bar
   */
  protected abstract String getProgressLabel(String bytesString);

  /**
   * Returns the speed of the transfer.
   *
   * @param transferredBytes the number of bytes that have been transferred
   * @return the speed of the transfer
   */
  private double calculateProgressSpeed(long transferredBytes) {
    // Bytes per second = bytes / SPEED_CALCULATE_DELAY miliseconds * 1000.
    return (transferredBytes - lastTransferredBytes) / SPEED_CALCULATE_DELAY * 1000;
  }

  /**
   * Returns the estimated transfer time left.
   *
   * @param speed the speed of the transfer
   * @param bytesLeft the size of the file
   * @return the estimated transfer time left
   */
  private double calculateEstimatedTransferTime(double speed, long bytesLeft) {
    return bytesLeft / speed;
  }

  /** Reload images and colors. */
  public void loadSkin() {
    errorIconLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.EXCLAMATION_MARK)));

    if (downloadFile != null)
      imageLabel.setIcon(new ImageIcon(ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON)));

    errorArea.setForeground(new Color(resources.getColor("service.gui.ERROR_FOREGROUND")));
  }
}
/** @author Yana Stamcheva */
public class CreateSip2SipAccountForm extends TransparentPanel
    implements SIPAccountCreationFormService {
  /** Serial version UID. */
  private static final long serialVersionUID = 0L;

  /** The logger. */
  private static final Logger logger = Logger.getLogger(CreateSip2SipAccountForm.class);

  /** The user name text field. */
  private final JTextField usernameField = new TrimTextField();

  /** The display name text field. */
  private final JTextField displayNameField = new JTextField();

  /** The password field. */
  private final JPasswordField passField = new JPasswordField();

  /** The retype password field. */
  private final JPasswordField retypePassField = new JPasswordField();

  /** The email field. */
  private final JTextField emailField = new JTextField();

  /** The error text pane. */
  private final JTextPane errorPane = new JTextPane();

  /** The register link. */
  private static String registerLink = "https://enrollment.sipthor.net/enrollment.phtml?";

  /** Creates an instance of <tt>RegisterSip2SipAccountForm</tt>. */
  public CreateSip2SipAccountForm() {
    super(new BorderLayout());

    this.init();
  }

  /** Initializes this panel. */
  private void init() {
    JPanel mainPanel = new TransparentPanel(new BorderLayout());

    mainPanel.setBorder(
        BorderFactory.createTitledBorder(
            Sip2SipAccRegWizzActivator.getResources()
                .getI18NString("plugin.sipaccregwizz.CREATE_ACCOUNT_TITLE")));

    JPanel labelsPanel = new TransparentPanel(new GridLayout(0, 1));

    JPanel valuesPanel = new TransparentPanel(new GridLayout(0, 1));

    JLabel usernameLabel =
        new JLabel(
            Sip2SipAccRegWizzActivator.getResources()
                .getI18NString("plugin.sip2sipaccregwizz.USERNAME"));

    JLabel displayNameLabel =
        new JLabel(
            Sip2SipAccRegWizzActivator.getResources()
                .getI18NString("plugin.sipaccregwizz.DISPLAY_NAME"));

    JLabel passLabel =
        new JLabel(Sip2SipAccRegWizzActivator.getResources().getI18NString("service.gui.PASSWORD"));

    JLabel retypePasswordLabel =
        new JLabel(
            Sip2SipAccRegWizzActivator.getResources()
                .getI18NString("plugin.sip2sipaccregwizz.RETYPE_PASSWORD"));

    JLabel emailLabel =
        new JLabel(
            Sip2SipAccRegWizzActivator.getResources()
                .getI18NString("plugin.sip2sipaccregwizz.EMAIL"));

    labelsPanel.add(displayNameLabel);
    labelsPanel.add(usernameLabel);
    labelsPanel.add(passLabel);
    labelsPanel.add(retypePasswordLabel);
    labelsPanel.add(emailLabel);

    valuesPanel.add(displayNameField);
    valuesPanel.add(usernameField);
    valuesPanel.add(passField);
    valuesPanel.add(retypePassField);
    valuesPanel.add(emailField);

    JLabel emailDescriptionLabel =
        new JLabel(
            Sip2SipAccRegWizzActivator.getResources()
                .getI18NString("plugin.sip2sipaccregwizz.EMAIL_NOTE"),
            SwingConstants.CENTER);
    emailDescriptionLabel.setForeground(Color.GRAY);
    emailDescriptionLabel.setFont(emailDescriptionLabel.getFont().deriveFont(8));
    emailDescriptionLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 8, 10));

    initErrorArea();

    mainPanel.add(labelsPanel, BorderLayout.WEST);
    mainPanel.add(valuesPanel, BorderLayout.CENTER);
    mainPanel.add(emailDescriptionLabel, BorderLayout.SOUTH);

    this.add(mainPanel, BorderLayout.CENTER);

    JLabel infoLabel =
        new JLabel(
            Sip2SipAccRegWizzActivator.getResources()
                .getI18NString("plugin.sip2sipaccregwizz.INFO_NOTE"),
            SwingConstants.RIGHT);
    infoLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
    infoLabel.setForeground(Color.GRAY);
    infoLabel.setFont(emailDescriptionLabel.getFont().deriveFont(8));
    infoLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 8, 0));
    infoLabel.addMouseListener(
        new MouseAdapter() {
          @Override
          public void mousePressed(MouseEvent e) {
            Sip2SipAccRegWizzActivator.getBrowserLauncher().openURL("http://wiki.sip2sip.info");
          }
        });

    this.add(infoLabel, BorderLayout.SOUTH);
  }

  /** Creates the error area component. */
  private void initErrorArea() {
    SimpleAttributeSet attribs = new SimpleAttributeSet();
    StyleConstants.setAlignment(attribs, StyleConstants.ALIGN_RIGHT);
    StyleConstants.setFontFamily(attribs, errorPane.getFont().getFamily());
    StyleConstants.setForeground(attribs, Color.RED);
    errorPane.setParagraphAttributes(attribs, true);
    errorPane.setPreferredSize(new Dimension(100, 50));
    errorPane.setMinimumSize(new Dimension(100, 50));
    errorPane.setOpaque(false);
  }

  /**
   * Creates this account on the server.
   *
   * @return the created account
   */
  public NewAccount createAccount() {
    // Check if the two passwords match.
    String pass1 = new String(passField.getPassword());
    String pass2 = new String(retypePassField.getPassword());
    if (!pass1.equals(pass2)) {
      showErrorMessage(
          IppiAccRegWizzActivator.getResources()
              .getI18NString("plugin.sipaccregwizz.NOT_SAME_PASSWORD"));

      return null;
    }

    NewAccount newAccount = null;
    try {
      StringBuilder registerLinkBuilder = new StringBuilder(registerLink);
      registerLinkBuilder
          .append(URLEncoder.encode("email", "UTF-8"))
          .append("=")
          .append(URLEncoder.encode(emailField.getText(), "UTF-8"))
          .append("&")
          .append(URLEncoder.encode("password", "UTF-8"))
          .append("=")
          .append(URLEncoder.encode(new String(passField.getPassword()), "UTF-8"))
          .append("&")
          .append(URLEncoder.encode("display_name", "UTF-8"))
          .append("=")
          .append(URLEncoder.encode(displayNameField.getText(), "UTF-8"))
          .append("&")
          .append(URLEncoder.encode("username", "UTF-8"))
          .append("=")
          .append(URLEncoder.encode(usernameField.getText(), "UTF-8"))
          .append("&")
          .append(URLEncoder.encode("user_agent", "UTF-8"))
          .append("=")
          .append(URLEncoder.encode("sip-communicator.org", "UTF-8"));

      URL url = new URL(registerLinkBuilder.toString());
      URLConnection conn = url.openConnection();

      // If this is not an http connection we have nothing to do here.
      if (!(conn instanceof HttpURLConnection)) {
        return null;
      }

      HttpURLConnection httpConn = (HttpURLConnection) conn;

      int responseCode = httpConn.getResponseCode();

      if (responseCode == HttpURLConnection.HTTP_OK) {
        // Read all the text returned by the server
        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String str;

        StringBuffer stringBuffer = new StringBuffer();
        while ((str = in.readLine()) != null) {
          stringBuffer.append(str);
        }

        if (logger.isInfoEnabled())
          logger.info("JSON response to create account request: " + stringBuffer.toString());

        newAccount = parseHttpResponse(stringBuffer.toString());
      }
    } catch (MalformedURLException e1) {
      if (logger.isInfoEnabled())
        logger.info("Failed to create URL with string: " + registerLink, e1);
    } catch (IOException e1) {
      if (logger.isInfoEnabled()) logger.info("Failed to open connection.", e1);
    }
    return newAccount;
  }

  /**
   * Returns the form, which would be used by the user to create a new account.
   *
   * @return the component of the form
   */
  public Component getForm() {
    return this;
  }

  /** Clears all the data previously entered in the form. */
  public void clear() {
    usernameField.setText("");
    displayNameField.setText("");
    passField.setText("");
    retypePassField.setText("");
    emailField.setText("");
    errorPane.setText("");

    remove(errorPane);
  }

  /**
   * Parses the given http response.
   *
   * @param response the http response to parse
   * @return the new account
   */
  private NewAccount parseHttpResponse(String response) {
    NewAccount newAccount = null;
    try {
      JSONObject jsonObject = (JSONObject) JSONValue.parseWithException(response);
      boolean isSuccess = (Boolean) jsonObject.get("success");

      if (isSuccess) {
        newAccount =
            new NewAccount(
                (String) jsonObject.get("sip_address"),
                passField.getPassword(),
                null,
                (String) jsonObject.get("outbound_proxy"));

        String xcapRoot = (String) jsonObject.get("xcap_root");

        // as sip2sip adds @sip2sip.info at the end of the
        // xcap_uri but doesn't report it in resullt after
        // creating account, we add it
        String domain = null;
        int delimIndex = newAccount.getUserName().indexOf("@");
        if (delimIndex != -1) {
          domain = newAccount.getUserName().substring(delimIndex);
        }
        if (domain != null) {
          if (xcapRoot.endsWith("/"))
            xcapRoot = xcapRoot.substring(0, xcapRoot.length() - 1) + domain;
          else xcapRoot += domain;
        }

        newAccount.setXcapRoot(xcapRoot);
      } else {
        showErrorMessage((String) jsonObject.get("error_message"));
      }
    } catch (Throwable e1) {
      if (logger.isInfoEnabled()) logger.info("Failed Json parsing.", e1);
    }

    return newAccount;
  }

  /**
   * Shows the given error message.
   *
   * @param text the text of the error
   */
  private void showErrorMessage(String text) {
    errorPane.setText(text);

    if (errorPane.getParent() == null) add(errorPane, BorderLayout.NORTH);

    SwingUtilities.getWindowAncestor(CreateSip2SipAccountForm.this).pack();
  }
}
예제 #17
0
/**
 * A {@link AbstractPluginComponent} that registers the Off-the-Record button in the main chat
 * toolbar.
 *
 * @author George Politis
 * @author Marin Dzhigarov
 */
public class OtrMetaContactButton extends AbstractPluginComponent
    implements ScOtrEngineListener, ScOtrKeyManagerListener {
  /** The logger */
  private final Logger logger = Logger.getLogger(OtrMetaContactButton.class);

  private SIPCommButton button;

  private OtrContact otrContact;

  private AnimatedImage animatedPadlockImage;

  private Image finishedPadlockImage;

  private Image verifiedLockedPadlockImage;

  private Image unverifiedLockedPadlockImage;

  private Image unlockedPadlockImage;

  private Image timedoutPadlockImage;

  public void sessionStatusChanged(OtrContact otrContact) {
    // OtrMetaContactButton.this.contact can be null.
    if (otrContact.equals(OtrMetaContactButton.this.otrContact)) {
      setStatus(OtrActivator.scOtrEngine.getSessionStatus(otrContact));
    }
  }

  public void contactPolicyChanged(Contact contact) {
    // OtrMetaContactButton.this.contact can be null.
    if (OtrMetaContactButton.this.otrContact != null
        && contact.equals(OtrMetaContactButton.this.otrContact.contact)) {
      setPolicy(OtrActivator.scOtrEngine.getContactPolicy(contact));
    }
  }

  public void globalPolicyChanged() {
    if (OtrMetaContactButton.this.otrContact != null)
      setPolicy(OtrActivator.scOtrEngine.getContactPolicy(otrContact.contact));
  }

  public void contactVerificationStatusChanged(OtrContact otrContact) {
    // OtrMetaContactButton.this.contact can be null.
    if (otrContact.equals(OtrMetaContactButton.this.otrContact)) {
      setStatus(OtrActivator.scOtrEngine.getSessionStatus(otrContact));
    }
  }

  public OtrMetaContactButton(Container container, PluginComponentFactory parentFactory) {
    super(container, parentFactory);

    /*
     * XXX This OtrMetaContactButton instance cannot be added as a listener
     * to scOtrEngine and scOtrKeyManager without being removed later on
     * because the latter live forever. Unfortunately, the dispose() method
     * of this instance is never executed. OtrWeakListener will keep this
     * instance as a listener of scOtrEngine and scOtrKeyManager for as long
     * as this instance is necessary. And this instance will be strongly
     * referenced by the JMenuItems which depict it. So when the JMenuItems
     * are gone, this instance will become obsolete and OtrWeakListener will
     * remove it as a listener of scOtrEngine and scOtrKeyManager.
     */
    new OtrWeakListener<OtrMetaContactButton>(
        this, OtrActivator.scOtrEngine, OtrActivator.scOtrKeyManager);
  }

  /**
   * Gets the <code>SIPCommButton</code> which is the component of this plugin. If the button
   * doesn't exist, it's created.
   *
   * @return the <code>SIPCommButton</code> which is the component of this plugin
   */
  @SuppressWarnings("fallthrough")
  private SIPCommButton getButton() {
    if (button == null) {
      button = new SIPCommButton(null, null);
      button.setEnabled(false);
      button.setPreferredSize(new Dimension(25, 25));

      button.setToolTipText(
          OtrActivator.resourceService.getI18NString("plugin.otr.menu.OTR_TOOLTIP"));

      Image i1 = null, i2 = null, i3 = null;
      try {
        i1 =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.LOADING_ICON1_22x22"));
        i2 =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.LOADING_ICON2_22x22"));
        i3 =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.LOADING_ICON3_22x22"));
        finishedPadlockImage =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.FINISHED_ICON_22x22"));
        verifiedLockedPadlockImage =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.ENCRYPTED_ICON_22x22"));
        unverifiedLockedPadlockImage =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL(
                    "plugin.otr.ENCRYPTED_UNVERIFIED_ICON_22x22"));
        unlockedPadlockImage =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.PLAINTEXT_ICON_22x22"));
        timedoutPadlockImage =
            ImageIO.read(OtrActivator.resourceService.getImageURL("plugin.otr.BROKEN_ICON_22x22"));
      } catch (IOException e) {
        logger.debug("Failed to load padlock image");
      }

      animatedPadlockImage = new AnimatedImage(button, i1, i2, i3);

      button.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              if (otrContact == null) return;

              switch (OtrActivator.scOtrEngine.getSessionStatus(otrContact)) {
                case ENCRYPTED:
                  OtrPolicy policy = OtrActivator.scOtrEngine.getContactPolicy(otrContact.contact);
                  policy.setSendWhitespaceTag(false);
                  OtrActivator.scOtrEngine.setContactPolicy(otrContact.contact, policy);
                case FINISHED:
                case LOADING:
                  // Default action for finished, encrypted and loading
                  // sessions is end session.
                  OtrActivator.scOtrEngine.endSession(otrContact);
                  break;
                case TIMED_OUT:
                case PLAINTEXT:
                  policy = OtrActivator.scOtrEngine.getContactPolicy(otrContact.contact);
                  OtrPolicy globalPolicy = OtrActivator.scOtrEngine.getGlobalPolicy();
                  policy.setSendWhitespaceTag(globalPolicy.getSendWhitespaceTag());
                  OtrActivator.scOtrEngine.setContactPolicy(otrContact.contact, policy);
                  // Default action for timed_out and plaintext sessions
                  // is start session.
                  OtrActivator.scOtrEngine.startSession(otrContact);
                  break;
              }
            }
          });
    }
    return button;
  }

  /*
   * Implements PluginComponent#getComponent(). Returns the SIPCommButton
   * which is the component of this plugin creating it first if it doesn't
   * exist.
   */
  public Object getComponent() {
    return getButton();
  }

  /*
   * Implements PluginComponent#getName().
   */
  public String getName() {
    return "";
  }

  /*
   * Implements PluginComponent#setCurrentContact(Contact).
   */
  @Override
  public void setCurrentContact(Contact contact) {
    setCurrentContact(contact, null);
  }

  public void setCurrentContact(Contact contact, String resourceName) {
    if (contact == null) {
      this.otrContact = null;
      this.setPolicy(null);
      this.setStatus(ScSessionStatus.PLAINTEXT);
      return;
    }

    if (resourceName == null) {
      OtrContact otrContact = OtrContactManager.getOtrContact(contact, null);
      if (this.otrContact == otrContact) return;
      this.otrContact = otrContact;
      this.setStatus(OtrActivator.scOtrEngine.getSessionStatus(otrContact));
      this.setPolicy(OtrActivator.scOtrEngine.getContactPolicy(contact));
      return;
    }
    for (ContactResource resource : contact.getResources()) {
      if (resource.getResourceName().equals(resourceName)) {
        OtrContact otrContact = OtrContactManager.getOtrContact(contact, resource);
        if (this.otrContact == otrContact) return;
        this.otrContact = otrContact;
        this.setStatus(OtrActivator.scOtrEngine.getSessionStatus(otrContact));
        this.setPolicy(OtrActivator.scOtrEngine.getContactPolicy(contact));
        return;
      }
    }
    logger.debug("Could not find resource for contact " + contact);
  }

  /*
   * Implements PluginComponent#setCurrentContact(MetaContact).
   */
  @Override
  public void setCurrentContact(MetaContact metaContact) {
    setCurrentContact((metaContact == null) ? null : metaContact.getDefaultContact());
  }

  /**
   * Sets the button enabled status according to the passed in {@link OtrPolicy}.
   *
   * @param contactPolicy the {@link OtrPolicy}.
   */
  private void setPolicy(OtrPolicy contactPolicy) {
    getButton().setEnabled(contactPolicy != null && contactPolicy.getEnableManual());
  }

  /**
   * Sets the button icon according to the passed in {@link SessionStatus}.
   *
   * @param status the {@link SessionStatus}.
   */
  private void setStatus(ScSessionStatus status) {
    animatedPadlockImage.pause();
    Image image;
    String tipKey;
    switch (status) {
      case ENCRYPTED:
        PublicKey pubKey = OtrActivator.scOtrEngine.getRemotePublicKey(otrContact);
        String fingerprint = OtrActivator.scOtrKeyManager.getFingerprintFromPublicKey(pubKey);
        image =
            OtrActivator.scOtrKeyManager.isVerified(otrContact.contact, fingerprint)
                ? verifiedLockedPadlockImage
                : unverifiedLockedPadlockImage;
        tipKey =
            OtrActivator.scOtrKeyManager.isVerified(otrContact.contact, fingerprint)
                ? "plugin.otr.menu.VERIFIED"
                : "plugin.otr.menu.UNVERIFIED";
        break;
      case FINISHED:
        image = finishedPadlockImage;
        tipKey = "plugin.otr.menu.FINISHED";
        break;
      case PLAINTEXT:
        image = unlockedPadlockImage;
        tipKey = "plugin.otr.menu.START_OTR";
        break;
      case LOADING:
        image = animatedPadlockImage;
        animatedPadlockImage.start();
        tipKey = "plugin.otr.menu.LOADING_OTR";
        break;
      case TIMED_OUT:
        image = timedoutPadlockImage;
        tipKey = "plugin.otr.menu.TIMED_OUT";
        break;
      default:
        return;
    }

    SIPCommButton button = getButton();
    button.setIconImage(image);
    button.setToolTipText(OtrActivator.resourceService.getI18NString(tipKey));
    button.repaint();
  }

  @Override
  public void multipleInstancesDetected(OtrContact contact) {}

  @Override
  public void outgoingSessionChanged(OtrContact otrContact) {
    // OtrMetaContactButton.this.contact can be null.
    if (otrContact.equals(OtrMetaContactButton.this.otrContact)) {
      setStatus(OtrActivator.scOtrEngine.getSessionStatus(otrContact));
    }
  }
}
예제 #18
0
public class ShowPreviewDialog extends SIPCommDialog
    implements ActionListener, ChatLinkClickedListener {
  /** Serial version UID. */
  private static final long serialVersionUID = 1L;

  /**
   * The <tt>Logger</tt> used by the <tt>ShowPreviewDialog</tt> class and its instances for logging
   * output.
   */
  private static final Logger logger = Logger.getLogger(ShowPreviewDialog.class);

  ConfigurationService cfg = GuiActivator.getConfigurationService();

  /** The Ok button. */
  private final JButton okButton;

  /** The cancel button. */
  private final JButton cancelButton;

  /** Checkbox that indicates whether or not to show this dialog next time. */
  private final JCheckBox enableReplacementProposal;

  /** Checkbox that indicates whether or not to show previews automatically */
  private final JCheckBox enableReplacement;

  /** The <tt>ChatConversationPanel</tt> that this dialog is associated with. */
  private final ChatConversationPanel chatPanel;

  /** Mapping between messageID and the string representation of the chat message. */
  private Map<String, String> msgIDToChatString = new ConcurrentHashMap<String, String>();

  /**
   * Mapping between the pair (messageID, link position) and the actual link in the string
   * representation of the chat message.
   */
  private Map<String, String> msgIDandPositionToLink = new ConcurrentHashMap<String, String>();

  /**
   * Mapping between link and replacement for this link that is acquired from it's corresponding
   * <tt>ReplacementService</tt>.
   */
  private Map<String, String> linkToReplacement = new ConcurrentHashMap<String, String>();

  /** The id of the message that is currently associated with this dialog. */
  private String currentMessageID = "";

  /** The position of the link in the current message. */
  private String currentLinkPosition = "";

  /**
   * Creates an instance of <tt>ShowPreviewDialog</tt>
   *
   * @param chatPanel The <tt>ChatConversationPanel</tt> that is associated with this dialog.
   */
  ShowPreviewDialog(final ChatConversationPanel chatPanel) {
    this.chatPanel = chatPanel;

    this.setTitle(
        GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW_DIALOG_TITLE"));
    okButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.OK"));
    cancelButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.CANCEL"));

    JPanel mainPanel = new TransparentPanel();
    mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
    mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    // mainPanel.setPreferredSize(new Dimension(200, 150));
    this.getContentPane().add(mainPanel);

    JTextPane descriptionMsg = new JTextPane();
    descriptionMsg.setEditable(false);
    descriptionMsg.setOpaque(false);
    descriptionMsg.setText(
        GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW_WARNING_DESCRIPTION"));

    Icon warningIcon = null;
    try {
      warningIcon =
          new ImageIcon(
              ImageIO.read(
                  GuiActivator.getResources().getImageURL("service.gui.icons.WARNING_ICON")));
    } catch (IOException e) {
      logger.debug("failed to load the warning icon");
    }
    JLabel warningSign = new JLabel(warningIcon);

    JPanel warningPanel = new TransparentPanel();
    warningPanel.setLayout(new BoxLayout(warningPanel, BoxLayout.X_AXIS));
    warningPanel.add(warningSign);
    warningPanel.add(Box.createHorizontalStrut(10));
    warningPanel.add(descriptionMsg);

    enableReplacement =
        new JCheckBox(
            GuiActivator.getResources()
                .getI18NString("plugin.chatconfig.replacement.ENABLE_REPLACEMENT_STATUS"));
    enableReplacement.setOpaque(false);
    enableReplacement.setSelected(cfg.getBoolean(ReplacementProperty.REPLACEMENT_ENABLE, true));
    enableReplacementProposal =
        new JCheckBox(
            GuiActivator.getResources()
                .getI18NString("plugin.chatconfig.replacement.ENABLE_REPLACEMENT_PROPOSAL"));
    enableReplacementProposal.setOpaque(false);

    JPanel checkBoxPanel = new TransparentPanel();
    checkBoxPanel.setLayout(new BoxLayout(checkBoxPanel, BoxLayout.Y_AXIS));
    checkBoxPanel.add(enableReplacement);
    checkBoxPanel.add(enableReplacementProposal);

    JPanel buttonsPanel = new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
    buttonsPanel.add(okButton);
    buttonsPanel.add(cancelButton);

    mainPanel.add(warningPanel);
    mainPanel.add(Box.createVerticalStrut(10));
    mainPanel.add(checkBoxPanel);
    mainPanel.add(buttonsPanel);

    okButton.addActionListener(this);
    cancelButton.addActionListener(this);

    this.setPreferredSize(new Dimension(390, 230));
  }

  @Override
  public void actionPerformed(ActionEvent arg0) {
    if (arg0.getSource().equals(okButton)) {
      cfg.setProperty(ReplacementProperty.REPLACEMENT_ENABLE, enableReplacement.isSelected());
      cfg.setProperty(
          ReplacementProperty.REPLACEMENT_PROPOSAL, enableReplacementProposal.isSelected());
      SwingWorker worker =
          new SwingWorker() {
            /**
             * Called on the event dispatching thread (not on the worker thread) after the <code>
             * construct</code> method has returned.
             */
            @Override
            public void finished() {
              String newChatString = (String) get();

              if (newChatString != null) {
                try {
                  Element elem = chatPanel.document.getElement(currentMessageID);
                  chatPanel.document.setOuterHTML(elem, newChatString);
                  msgIDToChatString.put(currentMessageID, newChatString);
                } catch (BadLocationException ex) {
                  logger.error("Could not replace chat message", ex);
                } catch (IOException ex) {
                  logger.error("Could not replace chat message", ex);
                }
              }
            }

            @Override
            protected Object construct() throws Exception {
              String newChatString = msgIDToChatString.get(currentMessageID);
              try {
                String originalLink =
                    msgIDandPositionToLink.get(currentMessageID + "#" + currentLinkPosition);
                String replacementLink = linkToReplacement.get(originalLink);
                String replacement;
                DirectImageReplacementService source =
                    GuiActivator.getDirectImageReplacementSource();
                if (originalLink.equals(replacementLink)
                    && (!source.isDirectImage(originalLink)
                        || source.getImageSize(originalLink) == -1)) {
                  replacement = originalLink;
                } else {
                  replacement =
                      "<IMG HEIGHT=\"90\" WIDTH=\"120\" SRC=\""
                          + replacementLink
                          + "\" BORDER=\"0\" ALT=\""
                          + originalLink
                          + "\"></IMG>";
                }

                String old =
                    originalLink
                        + "</A> <A href=\"jitsi://"
                        + ShowPreviewDialog.this.getClass().getName()
                        + "/SHOWPREVIEW?"
                        + currentMessageID
                        + "#"
                        + currentLinkPosition
                        + "\">"
                        + GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW");

                newChatString = newChatString.replace(old, replacement);
              } catch (Exception ex) {
                logger.error("Could not replace chat message", ex);
              }
              return newChatString;
            }
          };
      worker.start();
      this.setVisible(false);
    } else if (arg0.getSource().equals(cancelButton)) {
      this.setVisible(false);
    }
  }

  @Override
  public void chatLinkClicked(URI url) {
    String action = url.getPath();
    if (action.equals("/SHOWPREVIEW")) {
      enableReplacement.setSelected(cfg.getBoolean(ReplacementProperty.REPLACEMENT_ENABLE, true));
      enableReplacementProposal.setSelected(
          cfg.getBoolean(ReplacementProperty.REPLACEMENT_PROPOSAL, true));

      currentMessageID = url.getQuery();
      currentLinkPosition = url.getFragment();

      this.setVisible(true);
      this.setLocationRelativeTo(chatPanel);
    }
  }

  /**
   * Returns mapping between messageID and the string representation of the chat message.
   *
   * @return mapping between messageID and chat string.
   */
  Map<String, String> getMsgIDToChatString() {
    return msgIDToChatString;
  }

  /**
   * Returns mapping between the pair (messageID, link position) and the actual link in the string
   * representation of the chat message.
   *
   * @return mapping between (messageID, linkPosition) and link.
   */
  Map<String, String> getMsgIDandPositionToLink() {
    return msgIDandPositionToLink;
  }

  /**
   * Returns mapping between link and replacement for this link that was acquired from it's
   * corresponding <tt>ReplacementService</tt>.
   *
   * @return mapping between link and it's corresponding replacement.
   */
  Map<String, String> getLinkToReplacement() {
    return linkToReplacement;
  }
}
예제 #19
0
  /**
   * Creates a chat room, by specifying the chat room name, the parent protocol provider and
   * eventually, the contacts invited to participate in this chat room.
   *
   * @param roomName the name of the room
   * @param protocolProvider the parent protocol provider.
   * @param contacts the contacts invited when creating the chat room.
   * @param reason
   * @param join whether we should join the room after creating it.
   * @param persistent whether the newly created room will be persistent.
   * @param isPrivate whether the room will be private or public.
   * @return the <tt>ChatRoomWrapper</tt> corresponding to the created room
   */
  public ChatRoomWrapper createChatRoom(
      String roomName,
      ProtocolProviderService protocolProvider,
      Collection<String> contacts,
      String reason,
      boolean join,
      boolean persistent,
      boolean isPrivate) {
    ChatRoomWrapper chatRoomWrapper = null;
    OperationSetMultiUserChat groupChatOpSet =
        protocolProvider.getOperationSet(OperationSetMultiUserChat.class);

    // If there's no group chat operation set we have nothing to do here.
    if (groupChatOpSet == null) return null;

    ChatRoom chatRoom = null;
    try {

      HashMap<String, Object> roomProperties = new HashMap<String, Object>();
      roomProperties.put("isPrivate", isPrivate);
      chatRoom = groupChatOpSet.createChatRoom(roomName, roomProperties);

      if (join) {
        chatRoom.join();

        for (String contact : contacts) chatRoom.invite(contact, reason);
      }
    } catch (OperationFailedException ex) {
      logger.error("Failed to create chat room.", ex);

      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.ERROR"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CREATE_CHAT_ROOM_ERROR",
                      new String[] {protocolProvider.getProtocolDisplayName()}),
              ex);
    } catch (OperationNotSupportedException ex) {
      logger.error("Failed to create chat room.", ex);

      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.ERROR"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CREATE_CHAT_ROOM_ERROR",
                      new String[] {protocolProvider.getProtocolDisplayName()}),
              ex);
    }

    if (chatRoom != null) {
      ChatRoomProviderWrapper parentProvider =
          chatRoomList.findServerWrapperFromProvider(protocolProvider);

      // if there is the same room ids don't add new wrapper as old one
      // maybe already created
      chatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);

      if (chatRoomWrapper == null) {
        chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom);
        chatRoomWrapper.setPersistent(persistent);
        chatRoomList.addChatRoom(chatRoomWrapper);
      }
    }

    return chatRoomWrapper;
  }
예제 #20
0
/**
 * The single chat implementation of the <tt>ChatTransport</tt> interface that provides abstraction
 * to protocol provider access.
 *
 * @author Yana Stamcheva
 */
public class MetaContactChatTransport implements ChatTransport, ContactPresenceStatusListener {
  /** The logger. */
  private static final Logger logger = Logger.getLogger(MetaContactChatTransport.class);

  /** The parent <tt>ChatSession</tt>, where this transport is available. */
  private final MetaContactChatSession parentChatSession;

  /** The associated protocol <tt>Contact</tt>. */
  private final Contact contact;

  /** The resource associated with this contact. */
  private ContactResource contactResource;

  /** The protocol presence operation set associated with this transport. */
  private final OperationSetPresence presenceOpSet;

  /** The thumbnail default width. */
  private static final int THUMBNAIL_WIDTH = 64;

  /** The thumbnail default height. */
  private static final int THUMBNAIL_HEIGHT = 64;

  /** Indicates if only the resource name should be displayed. */
  private boolean isDisplayResourceOnly = false;

  /**
   * Creates an instance of <tt>MetaContactChatTransport</tt> by specifying the parent
   * <tt>chatSession</tt> and the <tt>contact</tt> associated with the transport.
   *
   * @param chatSession the parent <tt>ChatSession</tt>
   * @param contact the <tt>Contact</tt> associated with this transport
   */
  public MetaContactChatTransport(MetaContactChatSession chatSession, Contact contact) {
    this(chatSession, contact, null, false);
  }

  /**
   * Creates an instance of <tt>MetaContactChatTransport</tt> by specifying the parent
   * <tt>chatSession</tt> and the <tt>contact</tt> associated with the transport.
   *
   * @param chatSession the parent <tt>ChatSession</tt>
   * @param contact the <tt>Contact</tt> associated with this transport
   * @param contactResource the <tt>ContactResource</tt> associated with the contact
   * @param isDisplayResourceOnly indicates if only the resource name should be displayed
   */
  public MetaContactChatTransport(
      MetaContactChatSession chatSession,
      Contact contact,
      ContactResource contactResource,
      boolean isDisplayResourceOnly) {
    this.parentChatSession = chatSession;
    this.contact = contact;
    this.contactResource = contactResource;
    this.isDisplayResourceOnly = isDisplayResourceOnly;

    presenceOpSet = contact.getProtocolProvider().getOperationSet(OperationSetPresence.class);

    if (presenceOpSet != null) presenceOpSet.addContactPresenceStatusListener(this);

    // checking this can be slow so make
    // sure its out of our way
    new Thread(
            new Runnable() {
              public void run() {
                checkImCaps();
              }
            })
        .start();
  }

  /**
   * If sending im is supported check it for supporting html messages if a font is set. As it can be
   * slow make sure its not on our way
   */
  private void checkImCaps() {
    if (ConfigurationUtils.getChatDefaultFontFamily() != null
        && ConfigurationUtils.getChatDefaultFontSize() > 0) {
      OperationSetBasicInstantMessaging imOpSet =
          contact.getProtocolProvider().getOperationSet(OperationSetBasicInstantMessaging.class);

      if (imOpSet != null)
        imOpSet.isContentTypeSupported(OperationSetBasicInstantMessaging.HTML_MIME_TYPE, contact);
    }
  }

  /**
   * Returns the contact associated with this transport.
   *
   * @return the contact associated with this transport
   */
  public Contact getContact() {
    return contact;
  }

  /**
   * Returns the contact address corresponding to this chat transport.
   *
   * @return The contact address corresponding to this chat transport.
   */
  public String getName() {
    return contact.getAddress();
  }

  /**
   * Returns the display name corresponding to this chat transport.
   *
   * @return The display name corresponding to this chat transport.
   */
  public String getDisplayName() {
    return contact.getDisplayName();
  }

  /**
   * Returns the resource name of this chat transport. This is for example the name of the user
   * agent from which the contact is logged.
   *
   * @return The display name of this chat transport resource.
   */
  public String getResourceName() {
    if (contactResource != null) return contactResource.getResourceName();

    return null;
  }

  public boolean isDisplayResourceOnly() {
    return isDisplayResourceOnly;
  }

  /**
   * Returns the presence status of this transport.
   *
   * @return the presence status of this transport.
   */
  public PresenceStatus getStatus() {
    if (contactResource != null) return contactResource.getPresenceStatus();
    else return contact.getPresenceStatus();
  }

  /**
   * Returns the <tt>ProtocolProviderService</tt>, corresponding to this chat transport.
   *
   * @return the <tt>ProtocolProviderService</tt>, corresponding to this chat transport.
   */
  public ProtocolProviderService getProtocolProvider() {
    return contact.getProtocolProvider();
  }

  /**
   * Returns <code>true</code> if this chat transport supports instant messaging, otherwise returns
   * <code>false</code>.
   *
   * @return <code>true</code> if this chat transport supports instant messaging, otherwise returns
   *     <code>false</code>.
   */
  public boolean allowsInstantMessage() {
    // First try to ask the capabilities operation set if such is
    // available.
    OperationSetContactCapabilities capOpSet =
        getProtocolProvider().getOperationSet(OperationSetContactCapabilities.class);

    if (capOpSet != null) {
      if (capOpSet.getOperationSet(contact, OperationSetBasicInstantMessaging.class) != null) {
        return true;
      }
    } else if (contact
            .getProtocolProvider()
            .getOperationSet(OperationSetBasicInstantMessaging.class)
        != null) return true;

    return false;
  }

  /**
   * Returns <code>true</code> if this chat transport supports message corrections and false
   * otherwise.
   *
   * @return <code>true</code> if this chat transport supports message corrections and false
   *     otherwise.
   */
  public boolean allowsMessageCorrections() {
    OperationSetContactCapabilities capOpSet =
        getProtocolProvider().getOperationSet(OperationSetContactCapabilities.class);

    if (capOpSet != null) {
      return capOpSet.getOperationSet(contact, OperationSetMessageCorrection.class) != null;
    } else {
      return contact.getProtocolProvider().getOperationSet(OperationSetMessageCorrection.class)
          != null;
    }
  }

  /**
   * Returns <code>true</code> if this chat transport supports sms messaging, otherwise returns
   * <code>false</code>.
   *
   * @return <code>true</code> if this chat transport supports sms messaging, otherwise returns
   *     <code>false</code>.
   */
  public boolean allowsSmsMessage() {
    // First try to ask the capabilities operation set if such is
    // available.
    OperationSetContactCapabilities capOpSet =
        getProtocolProvider().getOperationSet(OperationSetContactCapabilities.class);

    if (capOpSet != null) {
      if (capOpSet.getOperationSet(contact, OperationSetSmsMessaging.class) != null) {
        return true;
      }
    } else if (contact.getProtocolProvider().getOperationSet(OperationSetSmsMessaging.class)
        != null) return true;

    return false;
  }

  /**
   * Returns <code>true</code> if this chat transport supports typing notifications, otherwise
   * returns <code>false</code>.
   *
   * @return <code>true</code> if this chat transport supports typing notifications, otherwise
   *     returns <code>false</code>.
   */
  public boolean allowsTypingNotifications() {
    Object tnOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetTypingNotifications.class);

    if (tnOpSet != null) return true;
    else return false;
  }

  /**
   * Returns <code>true</code> if this chat transport supports file transfer, otherwise returns
   * <code>false</code>.
   *
   * @return <code>true</code> if this chat transport supports file transfer, otherwise returns
   *     <code>false</code>.
   */
  public boolean allowsFileTransfer() {
    Object ftOpSet = contact.getProtocolProvider().getOperationSet(OperationSetFileTransfer.class);

    if (ftOpSet != null) return true;
    else return false;
  }

  /**
   * Sends the given instant message through this chat transport, by specifying the mime type (html
   * or plain text).
   *
   * @param message The message to send.
   * @param mimeType The mime type of the message to send: text/html or text/plain.
   * @throws Exception if the send operation is interrupted
   */
  public void sendInstantMessage(String message, String mimeType) throws Exception {
    // If this chat transport does not support instant messaging we do
    // nothing here.
    if (!allowsInstantMessage()) return;

    OperationSetBasicInstantMessaging imOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetBasicInstantMessaging.class);

    Message msg;
    if (mimeType.equals(OperationSetBasicInstantMessaging.HTML_MIME_TYPE)
        && imOpSet.isContentTypeSupported(OperationSetBasicInstantMessaging.HTML_MIME_TYPE)) {
      msg =
          imOpSet.createMessage(
              message, OperationSetBasicInstantMessaging.HTML_MIME_TYPE, "utf-8", "");
    } else {
      msg = imOpSet.createMessage(message);
    }

    if (contactResource != null) imOpSet.sendInstantMessage(contact, contactResource, msg);
    else imOpSet.sendInstantMessage(contact, ContactResource.BASE_RESOURCE, msg);
  }

  /**
   * Sends <tt>message</tt> as a message correction through this transport, specifying the mime type
   * (html or plain text) and the id of the message to replace.
   *
   * @param message The message to send.
   * @param mimeType The mime type of the message to send: text/html or text/plain.
   * @param correctedMessageUID The ID of the message being corrected by this message.
   */
  public void correctInstantMessage(String message, String mimeType, String correctedMessageUID) {
    if (!allowsMessageCorrections()) {
      return;
    }

    OperationSetMessageCorrection mcOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetMessageCorrection.class);

    Message msg;
    if (mimeType.equals(OperationSetBasicInstantMessaging.HTML_MIME_TYPE)
        && mcOpSet.isContentTypeSupported(OperationSetBasicInstantMessaging.HTML_MIME_TYPE)) {
      msg =
          mcOpSet.createMessage(
              message, OperationSetBasicInstantMessaging.HTML_MIME_TYPE, "utf-8", "");
    } else {
      msg = mcOpSet.createMessage(message);
    }

    mcOpSet.correctMessage(contact, contactResource, msg, correctedMessageUID);
  }

  /**
   * Determines whether this chat transport supports the supplied content type
   *
   * @param contentType the type we want to check
   * @return <tt>true</tt> if the chat transport supports it and <tt>false</tt> otherwise.
   */
  public boolean isContentTypeSupported(String contentType) {
    OperationSetBasicInstantMessaging imOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetBasicInstantMessaging.class);

    if (imOpSet != null) return imOpSet.isContentTypeSupported(contentType);
    else return false;
  }

  /**
   * Sends the given sms message trough this chat transport.
   *
   * @param phoneNumber phone number of the destination
   * @param messageText The message to send.
   * @throws Exception if the send operation is interrupted
   */
  public void sendSmsMessage(String phoneNumber, String messageText) throws Exception {
    // If this chat transport does not support sms messaging we do
    // nothing here.
    if (!allowsSmsMessage()) return;

    SMSManager.sendSMS(contact.getProtocolProvider(), phoneNumber, messageText);
  }

  /**
   * Whether a dialog need to be opened so the user can enter the destination number.
   *
   * @return <tt>true</tt> if dialog needs to be open.
   */
  public boolean askForSMSNumber() {
    // If this chat transport does not support sms messaging we do
    // nothing here.
    if (!allowsSmsMessage()) return false;

    OperationSetSmsMessaging smsOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetSmsMessaging.class);

    return smsOpSet.askForNumber(contact);
  }

  /**
   * Sends the given sms message trough this chat transport.
   *
   * @param message the message to send
   * @throws Exception if the send operation is interrupted
   */
  public void sendSmsMessage(String message) throws Exception {
    // If this chat transport does not support sms messaging we do
    // nothing here.
    if (!allowsSmsMessage()) return;

    SMSManager.sendSMS(contact, message);
  }

  /**
   * Sends a typing notification state.
   *
   * @param typingState the typing notification state to send
   * @return the result of this operation. One of the TYPING_NOTIFICATION_XXX constants defined in
   *     this class
   */
  public int sendTypingNotification(int typingState) {
    // If this chat transport does not support sms messaging we do
    // nothing here.
    if (!allowsTypingNotifications()) return -1;

    ProtocolProviderService protocolProvider = contact.getProtocolProvider();
    OperationSetTypingNotifications tnOperationSet =
        protocolProvider.getOperationSet(OperationSetTypingNotifications.class);

    // if protocol is not registered or contact is offline don't
    // try to send typing notifications
    if (protocolProvider.isRegistered()
        && contact.getPresenceStatus().getStatus() >= PresenceStatus.ONLINE_THRESHOLD) {
      try {
        tnOperationSet.sendTypingNotification(contact, typingState);

        return ChatPanel.TYPING_NOTIFICATION_SUCCESSFULLY_SENT;
      } catch (Exception ex) {
        logger.error("Failed to send typing notifications.", ex);

        return ChatPanel.TYPING_NOTIFICATION_SEND_FAILED;
      }
    }

    return ChatPanel.TYPING_NOTIFICATION_SEND_FAILED;
  }

  /**
   * Sends the given file through this chat transport file transfer operation set.
   *
   * @param file the file to send
   * @return the <tt>FileTransfer</tt> object charged to transfer the file
   * @throws Exception if anything goes wrong
   */
  public FileTransfer sendFile(File file) throws Exception {
    // If this chat transport does not support instant messaging we do
    // nothing here.
    if (!allowsFileTransfer()) return null;

    OperationSetFileTransfer ftOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetFileTransfer.class);

    if (FileUtils.isImage(file.getName())) {
      // Create a thumbnailed file if possible.
      OperationSetThumbnailedFileFactory tfOpSet =
          contact.getProtocolProvider().getOperationSet(OperationSetThumbnailedFileFactory.class);

      if (tfOpSet != null) {
        byte[] thumbnail = getFileThumbnail(file);

        if (thumbnail != null && thumbnail.length > 0) {
          file =
              tfOpSet.createFileWithThumbnail(
                  file, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, "image/png", thumbnail);
        }
      }
    }
    return ftOpSet.sendFile(contact, file);
  }

  /**
   * Returns the maximum file length supported by the protocol in bytes.
   *
   * @return the file length that is supported.
   */
  public long getMaximumFileLength() {
    OperationSetFileTransfer ftOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetFileTransfer.class);

    return ftOpSet.getMaximumFileLength();
  }

  public void inviteChatContact(String contactAddress, String reason) {}

  /**
   * Returns the parent session of this chat transport. A <tt>ChatSession</tt> could contain more
   * than one transports.
   *
   * @return the parent session of this chat transport
   */
  public ChatSession getParentChatSession() {
    return parentChatSession;
  }

  /**
   * Adds an SMS message listener to this chat transport.
   *
   * @param l The message listener to add.
   */
  public void addSmsMessageListener(MessageListener l) {
    // If this chat transport does not support sms messaging we do
    // nothing here.
    if (!allowsSmsMessage()) return;

    OperationSetSmsMessaging smsOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetSmsMessaging.class);

    smsOpSet.addMessageListener(l);
  }

  /**
   * Adds an instant message listener to this chat transport.
   *
   * @param l The message listener to add.
   */
  public void addInstantMessageListener(MessageListener l) {
    // If this chat transport does not support instant messaging we do
    // nothing here.
    if (!allowsInstantMessage()) return;

    OperationSetBasicInstantMessaging imOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetBasicInstantMessaging.class);

    imOpSet.addMessageListener(l);
  }

  /**
   * Removes the given sms message listener from this chat transport.
   *
   * @param l The message listener to remove.
   */
  public void removeSmsMessageListener(MessageListener l) {
    // If this chat transport does not support sms messaging we do
    // nothing here.
    if (!allowsSmsMessage()) return;

    OperationSetSmsMessaging smsOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetSmsMessaging.class);

    smsOpSet.removeMessageListener(l);
  }

  /**
   * Removes the instant message listener from this chat transport.
   *
   * @param l The message listener to remove.
   */
  public void removeInstantMessageListener(MessageListener l) {
    // If this chat transport does not support instant messaging we do
    // nothing here.
    if (!allowsInstantMessage()) return;

    OperationSetBasicInstantMessaging imOpSet =
        contact.getProtocolProvider().getOperationSet(OperationSetBasicInstantMessaging.class);

    imOpSet.removeMessageListener(l);
  }

  /**
   * Indicates that a contact has changed its status.
   *
   * @param evt The presence event containing information about the contact status change.
   */
  public void contactPresenceStatusChanged(ContactPresenceStatusChangeEvent evt) {
    if (evt.getSourceContact().equals(contact)
        && !evt.getOldStatus().equals(evt.getNewStatus())
        && contactResource == null) // If the contact source is set then the
    // status will be updated from the
    // MetaContactChatSession.
    {
      this.updateContactStatus();
    }
  }

  /** Updates the status of this contact with the new given status. */
  private void updateContactStatus() {
    // Update the status of the given contact in the "send via" selector
    // box.
    parentChatSession.getChatSessionRenderer().updateChatTransportStatus(this);
  }

  /** Removes all previously added listeners. */
  public void dispose() {
    if (presenceOpSet != null) presenceOpSet.removeContactPresenceStatusListener(this);
  }

  /**
   * Returns the descriptor of this chat transport.
   *
   * @return the descriptor of this chat transport
   */
  public Object getDescriptor() {
    return contact;
  }

  /**
   * Sets the icon for the given file.
   *
   * @param file the file to set an icon for
   * @return the byte array containing the thumbnail
   */
  private byte[] getFileThumbnail(File file) {
    byte[] bytes = null;
    if (FileUtils.isImage(file.getName())) {
      try {
        ImageIcon image = new ImageIcon(file.toURI().toURL());
        int width = image.getIconWidth();
        int height = image.getIconHeight();

        if (width > THUMBNAIL_WIDTH) width = THUMBNAIL_WIDTH;
        if (height > THUMBNAIL_HEIGHT) height = THUMBNAIL_HEIGHT;

        bytes = ImageUtils.getScaledInstanceInBytes(image.getImage(), width, height);
      } catch (MalformedURLException e) {
        if (logger.isDebugEnabled()) logger.debug("Could not locate image.", e);
      }
    }
    return bytes;
  }
}
예제 #21
0
/**
 * The contactlist panel not only contains the contact list but it has the role of a message
 * dispatcher. It process all sent and received messages as well as all typing notifications. Here
 * are managed all contact list mouse events.
 *
 * @author Yana Stamcheva
 * @author Hristo Terezov
 */
public class ContactListPane extends SIPCommScrollPane
    implements MessageListener,
        TypingNotificationsListener,
        FileTransferListener,
        ContactListListener,
        PluginComponentListener {
  /** Serial version UID. */
  private static final long serialVersionUID = 0L;

  private final MainFrame mainFrame;

  private TreeContactList contactList;

  private final TypingTimer typingTimer = new TypingTimer();

  private CommonRightButtonMenu commonRightButtonMenu;

  private final Logger logger = Logger.getLogger(ContactListPane.class);

  private final ChatWindowManager chatWindowManager;

  /**
   * Creates the contactlist scroll panel defining the parent frame.
   *
   * @param mainFrame The parent frame.
   */
  public ContactListPane(MainFrame mainFrame) {
    this.mainFrame = mainFrame;

    this.chatWindowManager = GuiActivator.getUIService().getChatWindowManager();

    this.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

    this.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY));

    this.initPluginComponents();
  }

  /**
   * Initializes the contact list.
   *
   * @param contactListService The MetaContactListService which will be used for a contact list data
   *     model.
   */
  public void initList(MetaContactListService contactListService) {
    this.contactList = new TreeContactList(mainFrame);
    // We should first set the contact list to the GuiActivator, so that
    // anybody could get it from there.
    GuiActivator.setContactList(contactList);

    // By default we set the current filter to be the presence filter.
    contactList.applyFilter(TreeContactList.presenceFilter);

    TransparentPanel transparentPanel = new TransparentPanel(new BorderLayout());

    transparentPanel.add(contactList, BorderLayout.NORTH);

    this.setViewportView(transparentPanel);

    transparentPanel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
    this.contactList.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));

    this.contactList.addContactListListener(this);
    this.addMouseListener(
        new MouseAdapter() {
          @Override
          public void mousePressed(MouseEvent e) {
            if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) {
              commonRightButtonMenu = new CommonRightButtonMenu(mainFrame);

              commonRightButtonMenu.setInvoker(ContactListPane.this);

              commonRightButtonMenu.setLocation(
                  e.getX() + mainFrame.getX() + 5, e.getY() + mainFrame.getY() + 105);

              commonRightButtonMenu.setVisible(true);
            }
          }
        });
  }

  /**
   * Returns the contact list.
   *
   * @return the contact list
   */
  public TreeContactList getContactList() {
    return this.contactList;
  }

  /**
   * Implements the ContactListListener.contactSelected method.
   *
   * @param evt the <tt>ContactListEvent</tt> that notified us
   */
  public void contactClicked(ContactListEvent evt) {
    // We're interested only in two click events.
    if (evt.getClickCount() < 2) return;

    UIContact descriptor = evt.getSourceContact();

    // We're currently only interested in MetaContacts.
    if (descriptor.getDescriptor() instanceof MetaContact) {
      MetaContact metaContact = (MetaContact) descriptor.getDescriptor();

      // Searching for the right proto contact to use as default for the
      // chat conversation.
      Contact defaultContact =
          metaContact.getDefaultContact(OperationSetBasicInstantMessaging.class);

      // do nothing
      if (defaultContact == null) {
        defaultContact = metaContact.getDefaultContact(OperationSetSmsMessaging.class);

        if (defaultContact == null) return;
      }

      ProtocolProviderService defaultProvider = defaultContact.getProtocolProvider();

      OperationSetBasicInstantMessaging defaultIM =
          defaultProvider.getOperationSet(OperationSetBasicInstantMessaging.class);

      ProtocolProviderService protoContactProvider;
      OperationSetBasicInstantMessaging protoContactIM;

      boolean isOfflineMessagingSupported =
          defaultIM != null && !defaultIM.isOfflineMessagingSupported();

      if (defaultContact.getPresenceStatus().getStatus() < 1
          && (!isOfflineMessagingSupported || !defaultProvider.isRegistered())) {
        Iterator<Contact> protoContacts = metaContact.getContacts();

        while (protoContacts.hasNext()) {
          Contact contact = protoContacts.next();

          protoContactProvider = contact.getProtocolProvider();

          protoContactIM =
              protoContactProvider.getOperationSet(OperationSetBasicInstantMessaging.class);

          if (protoContactIM != null
              && protoContactIM.isOfflineMessagingSupported()
              && protoContactProvider.isRegistered()) {
            defaultContact = contact;
          }
        }
      }

      ContactEventHandler contactHandler =
          mainFrame.getContactHandler(defaultContact.getProtocolProvider());

      contactHandler.contactClicked(defaultContact, evt.getClickCount());
    } else if (descriptor.getDescriptor() instanceof SourceContact) {
      SourceContact contact = (SourceContact) descriptor.getDescriptor();

      List<ContactDetail> imDetails =
          contact.getContactDetails(OperationSetBasicInstantMessaging.class);
      List<ContactDetail> mucDetails = contact.getContactDetails(OperationSetMultiUserChat.class);

      if (imDetails != null && imDetails.size() > 0) {
        ProtocolProviderService pps =
            imDetails.get(0).getPreferredProtocolProvider(OperationSetBasicInstantMessaging.class);

        GuiActivator.getUIService()
            .getChatWindowManager()
            .startChat(contact.getContactAddress(), pps);
      } else if (mucDetails != null && mucDetails.size() > 0) {
        ChatRoomWrapper room =
            GuiActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);

        if (room == null) {
          // lets check by id
          ProtocolProviderService pps =
              mucDetails.get(0).getPreferredProtocolProvider(OperationSetMultiUserChat.class);

          room =
              GuiActivator.getMUCService()
                  .findChatRoomWrapperFromChatRoomID(contact.getContactAddress(), pps);

          if (room == null) {
            GuiActivator.getMUCService()
                .createChatRoom(
                    contact.getContactAddress(),
                    pps,
                    new ArrayList<String>(),
                    "",
                    false,
                    false,
                    false);
          }
        }

        if (room != null) GuiActivator.getMUCService().openChatRoom(room);
      } else {
        List<ContactDetail> smsDetails = contact.getContactDetails(OperationSetSmsMessaging.class);

        if (smsDetails != null && smsDetails.size() > 0) {
          GuiActivator.getUIService()
              .getChatWindowManager()
              .startChat(contact.getContactAddress(), true);
        }
      }
    }
  }

  /**
   * Implements the ContactListListener.groupSelected method.
   *
   * @param evt the <tt>ContactListEvent</tt> that notified us
   */
  public void groupClicked(ContactListEvent evt) {}

  /** We're not interested in group selection events here. */
  public void groupSelected(ContactListEvent evt) {}

  /** We're not interested in contact selection events here. */
  public void contactSelected(ContactListEvent evt) {}

  /**
   * When a message is received determines whether to open a new chat window or chat window tab, or
   * to indicate that a message is received from a contact which already has an open chat. When the
   * chat is found checks if in mode "Auto popup enabled" and if this is the case shows the message
   * in the appropriate chat panel.
   *
   * @param evt the event containing details on the received message
   */
  public void messageReceived(MessageReceivedEvent evt) {
    if (logger.isTraceEnabled())
      logger.trace("MESSAGE RECEIVED from contact: " + evt.getSourceContact().getAddress());

    Contact protocolContact = evt.getSourceContact();
    ContactResource contactResource = evt.getContactResource();
    Message message = evt.getSourceMessage();
    int eventType = evt.getEventType();
    MetaContact metaContact =
        GuiActivator.getContactListService().findMetaContactByContact(protocolContact);

    if (metaContact != null) {
      messageReceived(
          protocolContact,
          contactResource,
          metaContact,
          message,
          eventType,
          evt.getTimestamp(),
          evt.getCorrectedMessageUID(),
          evt.isPrivateMessaging(),
          evt.getPrivateMessagingContactRoom());
    } else {
      if (logger.isTraceEnabled())
        logger.trace("MetaContact not found for protocol contact: " + protocolContact + ".");
    }
  }

  /**
   * When a message is received determines whether to open a new chat window or chat window tab, or
   * to indicate that a message is received from a contact which already has an open chat. When the
   * chat is found checks if in mode "Auto popup enabled" and if this is the case shows the message
   * in the appropriate chat panel.
   *
   * @param protocolContact the source contact of the event
   * @param contactResource the resource from which the contact is writing
   * @param metaContact the metacontact containing <tt>protocolContact</tt>
   * @param message the message to deliver
   * @param eventType the event type
   * @param timestamp the timestamp of the event
   * @param correctedMessageUID the identifier of the corrected message
   * @param isPrivateMessaging if <tt>true</tt> the message is received from private messaging
   *     contact.
   * @param privateContactRoom the chat room associated with the private messaging contact.
   */
  private void messageReceived(
      final Contact protocolContact,
      final ContactResource contactResource,
      final MetaContact metaContact,
      final Message message,
      final int eventType,
      final Date timestamp,
      final String correctedMessageUID,
      final boolean isPrivateMessaging,
      final ChatRoom privateContactRoom) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              messageReceived(
                  protocolContact,
                  contactResource,
                  metaContact,
                  message,
                  eventType,
                  timestamp,
                  correctedMessageUID,
                  isPrivateMessaging,
                  privateContactRoom);
            }
          });
      return;
    }

    // Obtain the corresponding chat panel.
    final ChatPanel chatPanel =
        chatWindowManager.getContactChat(
            metaContact, protocolContact, contactResource, message.getMessageUID());

    // Show an envelope on the sender contact in the contact list and
    // in the systray.
    if (!chatPanel.isChatFocused()) contactList.setActiveContact(metaContact, true);

    // Distinguish the message type, depending on the type of event that
    // we have received.
    String messageType = null;

    if (eventType == MessageReceivedEvent.CONVERSATION_MESSAGE_RECEIVED) {
      messageType = Chat.INCOMING_MESSAGE;
    } else if (eventType == MessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED) {
      messageType = Chat.SYSTEM_MESSAGE;
    } else if (eventType == MessageReceivedEvent.SMS_MESSAGE_RECEIVED) {
      messageType = Chat.SMS_MESSAGE;
    }

    String contactAddress =
        (contactResource != null)
            ? protocolContact.getAddress() + " (" + contactResource.getResourceName() + ")"
            : protocolContact.getAddress();

    chatPanel.addMessage(
        contactAddress,
        protocolContact.getDisplayName(),
        timestamp,
        messageType,
        message.getContent(),
        message.getContentType(),
        message.getMessageUID(),
        correctedMessageUID);

    String resourceName = (contactResource != null) ? contactResource.getResourceName() : null;

    if (isPrivateMessaging) {
      chatWindowManager.openPrivateChatForChatRoomMember(privateContactRoom, protocolContact);
    } else {
      chatWindowManager.openChat(chatPanel, false);
    }

    ChatTransport chatTransport =
        chatPanel.getChatSession().findChatTransportForDescriptor(protocolContact, resourceName);

    chatPanel.setSelectedChatTransport(chatTransport, true);
  }

  /**
   * When a sent message is delivered shows it in the chat conversation panel.
   *
   * @param evt the event containing details on the message delivery
   */
  public void messageDelivered(MessageDeliveredEvent evt) {
    Contact contact = evt.getDestinationContact();
    MetaContact metaContact =
        GuiActivator.getContactListService().findMetaContactByContact(contact);

    if (logger.isTraceEnabled())
      logger.trace("MESSAGE DELIVERED to contact: " + contact.getAddress());

    ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, false);

    if (chatPanel != null) {
      Message msg = evt.getSourceMessage();
      ProtocolProviderService protocolProvider = contact.getProtocolProvider();

      if (logger.isTraceEnabled())
        logger.trace(
            "MESSAGE DELIVERED: process message to chat for contact: "
                + contact.getAddress()
                + " MESSAGE: "
                + msg.getContent());

      chatPanel.addMessage(
          this.mainFrame.getAccountAddress(protocolProvider),
          this.mainFrame.getAccountDisplayName(protocolProvider),
          evt.getTimestamp(),
          Chat.OUTGOING_MESSAGE,
          msg.getContent(),
          msg.getContentType(),
          msg.getMessageUID(),
          evt.getCorrectedMessageUID());

      if (evt.isSmsMessage() && !ConfigurationUtils.isSmsNotifyTextDisabled()) {
        chatPanel.addMessage(
            contact.getDisplayName(),
            new Date(),
            Chat.ACTION_MESSAGE,
            GuiActivator.getResources().getI18NString("service.gui.SMS_SUCCESSFULLY_SENT"),
            "text");
      }
    }
  }

  /**
   * Shows a warning message to the user when message delivery has failed.
   *
   * @param evt the event containing details on the message delivery failure
   */
  public void messageDeliveryFailed(MessageDeliveryFailedEvent evt) {
    logger.error(evt.getReason());

    String errorMsg = null;

    Message sourceMessage = (Message) evt.getSource();

    Contact sourceContact = evt.getDestinationContact();

    MetaContact metaContact =
        GuiActivator.getContactListService().findMetaContactByContact(sourceContact);

    if (evt.getErrorCode() == MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED) {
      errorMsg =
          GuiActivator.getResources()
              .getI18NString(
                  "service.gui.MSG_DELIVERY_NOT_SUPPORTED",
                  new String[] {sourceContact.getDisplayName()});
    } else if (evt.getErrorCode() == MessageDeliveryFailedEvent.NETWORK_FAILURE) {
      errorMsg = GuiActivator.getResources().getI18NString("service.gui.MSG_NOT_DELIVERED");
    } else if (evt.getErrorCode() == MessageDeliveryFailedEvent.PROVIDER_NOT_REGISTERED) {
      errorMsg =
          GuiActivator.getResources().getI18NString("service.gui.MSG_SEND_CONNECTION_PROBLEM");
    } else if (evt.getErrorCode() == MessageDeliveryFailedEvent.INTERNAL_ERROR) {
      errorMsg =
          GuiActivator.getResources().getI18NString("service.gui.MSG_DELIVERY_INTERNAL_ERROR");
    } else {
      errorMsg = GuiActivator.getResources().getI18NString("service.gui.MSG_DELIVERY_ERROR");
    }

    String reason = evt.getReason();
    if (reason != null)
      errorMsg +=
          " "
              + GuiActivator.getResources()
                  .getI18NString("service.gui.ERROR_WAS", new String[] {reason});

    ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, sourceContact);

    chatPanel.addMessage(
        sourceContact.getAddress(),
        metaContact.getDisplayName(),
        new Date(),
        Chat.OUTGOING_MESSAGE,
        sourceMessage.getContent(),
        sourceMessage.getContentType(),
        sourceMessage.getMessageUID(),
        evt.getCorrectedMessageUID());

    chatPanel.addErrorMessage(metaContact.getDisplayName(), errorMsg);

    chatWindowManager.openChat(chatPanel, false);
  }

  /**
   * Informs the user what is the typing state of his chat contacts.
   *
   * @param evt the event containing details on the typing notification
   */
  public void typingNotificationReceived(TypingNotificationEvent evt) {
    if (typingTimer.isRunning()) typingTimer.stop();

    String notificationMsg = "";

    MetaContact metaContact =
        GuiActivator.getContactListService().findMetaContactByContact(evt.getSourceContact());
    String contactName = metaContact.getDisplayName() + " ";

    if (contactName.equals("")) {
      contactName = GuiActivator.getResources().getI18NString("service.gui.UNKNOWN") + " ";
    }

    int typingState = evt.getTypingState();

    ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, false);

    if (typingState == OperationSetTypingNotifications.STATE_TYPING) {
      notificationMsg =
          GuiActivator.getResources()
              .getI18NString("service.gui.CONTACT_TYPING", new String[] {contactName});

      // Proactive typing notification
      if (!chatWindowManager.isChatOpenedFor(metaContact)) {
        return;
      }

      if (chatPanel != null) chatPanel.addTypingNotification(notificationMsg);

      typingTimer.setMetaContact(metaContact);
      typingTimer.start();
    } else if (typingState == OperationSetTypingNotifications.STATE_PAUSED) {
      notificationMsg =
          GuiActivator.getResources()
              .getI18NString("service.gui.CONTACT_PAUSED_TYPING", new String[] {contactName});

      if (chatPanel != null) chatPanel.addTypingNotification(notificationMsg);

      typingTimer.setMetaContact(metaContact);
      typingTimer.start();
    } else {
      if (chatPanel != null) chatPanel.removeTypingNotification();
    }
  }

  /**
   * Called to indicate that sending typing notification has failed.
   *
   * @param evt a <tt>TypingNotificationEvent</tt> containing the sender of the notification and its
   *     type.
   */
  public void typingNotificationDeliveryFailed(TypingNotificationEvent evt) {
    if (typingTimer.isRunning()) typingTimer.stop();

    String notificationMsg = "";

    MetaContact metaContact =
        GuiActivator.getContactListService().findMetaContactByContact(evt.getSourceContact());
    String contactName = metaContact.getDisplayName();

    if (contactName.equals("")) {
      contactName = GuiActivator.getResources().getI18NString("service.gui.UNKNOWN") + " ";
    }

    ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, false);

    notificationMsg =
        GuiActivator.getResources()
            .getI18NString("service.gui.CONTACT_TYPING_SEND_FAILED", new String[] {contactName});

    // Proactive typing notification
    if (!chatWindowManager.isChatOpenedFor(metaContact)) {
      return;
    }

    if (chatPanel != null) chatPanel.addErrorSendingTypingNotification(notificationMsg);

    typingTimer.setMetaContact(metaContact);
    typingTimer.start();
  }

  /**
   * When a request has been received we show it to the user through the chat session renderer.
   *
   * @param event <tt>FileTransferRequestEvent</tt>
   * @see FileTransferListener#fileTransferRequestReceived(FileTransferRequestEvent)
   */
  public void fileTransferRequestReceived(FileTransferRequestEvent event) {
    IncomingFileTransferRequest request = event.getRequest();

    Contact sourceContact = request.getSender();

    MetaContact metaContact =
        GuiActivator.getContactListService().findMetaContactByContact(sourceContact);

    final ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, sourceContact);

    chatPanel.addIncomingFileTransferRequest(
        event.getFileTransferOperationSet(), request, event.getTimestamp());

    ChatTransport chatTransport =
        chatPanel.getChatSession().findChatTransportForDescriptor(sourceContact, null);

    chatPanel.setSelectedChatTransport(chatTransport, true);

    // Opens the chat panel with the new message in the UI thread.
    chatWindowManager.openChat(chatPanel, false);
  }

  /**
   * Nothing to do here, because we already know when a file transfer is created.
   *
   * @param event the <tt>FileTransferCreatedEvent</tt> that notified us
   */
  public void fileTransferCreated(FileTransferCreatedEvent event) {}

  /**
   * Called when a new <tt>IncomingFileTransferRequest</tt> has been rejected. Nothing to do here,
   * because we are the one who rejects the request.
   *
   * @param event the <tt>FileTransferRequestEvent</tt> containing the received request which was
   *     rejected.
   */
  public void fileTransferRequestRejected(FileTransferRequestEvent event) {}

  /**
   * Called when an <tt>IncomingFileTransferRequest</tt> has been canceled from the contact who sent
   * it.
   *
   * @param event the <tt>FileTransferRequestEvent</tt> containing the request which was canceled.
   */
  public void fileTransferRequestCanceled(FileTransferRequestEvent event) {}

  /**
   * Returns the right button menu of the contact list.
   *
   * @return the right button menu of the contact list
   */
  public CommonRightButtonMenu getCommonRightButtonMenu() {
    return commonRightButtonMenu;
  }

  /**
   * The TypingTimer is started after a PAUSED typing notification is received. It waits 5 seconds
   * and if no other typing event occurs removes the PAUSED message from the chat status panel.
   */
  private class TypingTimer extends Timer {
    /** Serial version UID. */
    private static final long serialVersionUID = 0L;

    private MetaContact metaContact;

    public TypingTimer() {
      // Set delay
      super(5 * 1000, null);

      this.addActionListener(new TimerActionListener());
    }

    private class TimerActionListener implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        ChatPanel chatPanel = chatWindowManager.getContactChat(metaContact, false);

        if (chatPanel != null) chatPanel.removeTypingNotification();
      }
    }

    private void setMetaContact(MetaContact metaContact) {
      this.metaContact = metaContact;
    }
  }

  private void initPluginComponents() {
    // Search for plugin components registered through the OSGI bundle
    // context.
    ServiceReference[] serRefs = null;

    String osgiFilter =
        "(" + Container.CONTAINER_ID + "=" + Container.CONTAINER_CONTACT_LIST.getID() + ")";

    try {
      serRefs =
          GuiActivator.bundleContext.getServiceReferences(
              PluginComponentFactory.class.getName(), osgiFilter);
    } catch (InvalidSyntaxException exc) {
      logger.error("Could not obtain plugin reference.", exc);
    }

    if (serRefs != null) {
      for (ServiceReference serRef : serRefs) {
        PluginComponentFactory factory =
            (PluginComponentFactory) GuiActivator.bundleContext.getService(serRef);
        PluginComponent component = factory.getPluginComponentInstance(this);

        Object selectedValue = getContactList().getSelectedValue();

        if (selectedValue instanceof MetaContact) {
          component.setCurrentContact((MetaContact) selectedValue);
        } else if (selectedValue instanceof MetaContactGroup) {
          component.setCurrentContactGroup((MetaContactGroup) selectedValue);
        }

        String pluginConstraints = factory.getConstraints();
        Object constraints;

        if (pluginConstraints != null)
          constraints = UIServiceImpl.getBorderLayoutConstraintsFromContainer(pluginConstraints);
        else constraints = BorderLayout.SOUTH;

        this.add((Component) component.getComponent(), constraints);

        this.repaint();
      }
    }

    GuiActivator.getUIService().addPluginComponentListener(this);
  }

  /**
   * Adds the plugin component given by <tt>event</tt> to this panel if it's its container.
   *
   * @param event the <tt>PluginComponentEvent</tt> that notified us
   */
  public void pluginComponentAdded(PluginComponentEvent event) {
    PluginComponentFactory factory = event.getPluginComponentFactory();

    // If the container id doesn't correspond to the id of the plugin
    // container we're not interested.
    if (!factory.getContainer().equals(Container.CONTAINER_CONTACT_LIST)) return;

    Object constraints =
        UIServiceImpl.getBorderLayoutConstraintsFromContainer(factory.getConstraints());

    if (constraints == null) constraints = BorderLayout.SOUTH;

    PluginComponent pluginComponent = factory.getPluginComponentInstance(this);
    this.add((Component) pluginComponent.getComponent(), constraints);

    Object selectedValue = getContactList().getSelectedValue();

    if (selectedValue instanceof MetaContact) {
      pluginComponent.setCurrentContact((MetaContact) selectedValue);
    } else if (selectedValue instanceof MetaContactGroup) {
      pluginComponent.setCurrentContactGroup((MetaContactGroup) selectedValue);
    }

    this.revalidate();
    this.repaint();
  }

  /**
   * Removes the plugin component given by <tt>event</tt> if previously added in this panel.
   *
   * @param event the <tt>PluginComponentEvent</tt> that notified us
   */
  public void pluginComponentRemoved(PluginComponentEvent event) {
    PluginComponentFactory factory = event.getPluginComponentFactory();

    // If the container id doesn't correspond to the id of the plugin
    // container we're not interested.
    if (!factory.getContainer().equals(Container.CONTAINER_CONTACT_LIST)) return;

    this.remove((Component) factory.getPluginComponentInstance(this).getComponent());
  }
}
예제 #22
0
/**
 * A dialog dedicated to desktop streaming/sharing. Shows the possible screens to select from to use
 * for the streaming/sharing session.
 *
 * @author Yana Stamcheva
 */
public class SelectScreenDialog extends SIPCommDialog {
  /** Serial version UID. */
  private static final long serialVersionUID = 0L;

  /** The object used for logging. */
  private static final Logger logger = Logger.getLogger(SelectScreenDialog.class);

  /** The combo box containing screen choice. */
  private final JComboBox deviceComboBox;

  /** The cancel button of this dialog. */
  private final JButton cancelButton =
      new JButton(GuiActivator.getResources().getI18NString("service.gui.CANCEL"));

  /**
   * The video <code>CaptureDeviceInfo</code> this instance started to create the preview of.
   *
   * <p>Because the creation of the preview is asynchronous, it's possible to request the preview of
   * one and the same device multiple times. Which may lead to failures because of, for example,
   * busy devices and/or resources (as is the case with LTI-CIVIL and video4linux2).
   */
  private static MediaDevice videoDeviceInPreview;

  /** The selected media device. */
  private MediaDevice selectedDevice;

  /**
   * Creates an instance of <tt>SelectScreenDialog</tt> by specifying the list of possible desktop
   * devices to choose from.
   *
   * @param desktopDevices the list of possible desktop devices to choose from
   */
  public SelectScreenDialog(List<MediaDevice> desktopDevices) {
    setModal(true);

    setPreferredSize(new Dimension(400, 300));

    Container contentPane = getContentPane();
    contentPane.setLayout(new BorderLayout());

    deviceComboBox = new JComboBox(desktopDevices.toArray());
    contentPane.add(deviceComboBox, BorderLayout.NORTH);

    deviceComboBox.setRenderer(new ComboRenderer());

    contentPane.add(createPreview(deviceComboBox));

    contentPane.add(createButtonsPanel(), BorderLayout.SOUTH);
  }

  /**
   * Returns the selected device.
   *
   * @return the selected device
   */
  public MediaDevice getSelectedDevice() {
    return selectedDevice;
  }

  /**
   * Creates the buttons panel.
   *
   * @return the buttons panel
   */
  private Component createButtonsPanel() {
    JPanel buttonsPanel = new TransparentPanel(new FlowLayout(FlowLayout.RIGHT));

    JButton okButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.OK"));

    okButton.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            selectedDevice = (MediaDevice) deviceComboBox.getSelectedItem();

            dispose();
          }
        });

    buttonsPanel.add(okButton);

    cancelButton.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            selectedDevice = null;
            dispose();
          }
        });

    buttonsPanel.add(cancelButton);

    return buttonsPanel;
  }

  /**
   * Create preview component.
   *
   * @param comboBox the options.
   * @return the component.
   */
  private static Component createPreview(final JComboBox comboBox) {
    final JComponent preview;

    JLabel noPreview =
        new JLabel(GuiActivator.getResources().getI18NString("impl.media.configform.NO_PREVIEW"));
    noPreview.setHorizontalAlignment(SwingConstants.CENTER);
    noPreview.setVerticalAlignment(SwingConstants.CENTER);

    preview = createVideoContainer(noPreview);

    preview.setPreferredSize(new Dimension(WIDTH, 280));
    preview.setMaximumSize(new Dimension(WIDTH, 280));

    final ActionListener comboBoxListener =
        new ActionListener() {
          public void actionPerformed(ActionEvent event) {
            MediaDevice device = (MediaDevice) comboBox.getSelectedItem();

            if ((device != null) && device.equals(videoDeviceInPreview)) return;

            Exception exception;
            try {
              createPreview(device, preview);
              exception = null;
            } catch (IOException ex) {
              exception = ex;
            } catch (MediaException ex) {
              exception = ex;
            }
            if (exception != null) {
              logger.error("Failed to create preview for device " + device, exception);

              device = null;
            }

            videoDeviceInPreview = device;
          }
        };
    comboBox.addActionListener(comboBoxListener);

    /*
     * We have to initialize the controls to reflect the configuration
     * at the time of creating this instance. Additionally, because the
     * video preview will stop when it and its associated controls
     * become unnecessary, we have to restart it when the mentioned
     * controls become necessary again. We'll address the two goals
     * described by pretending there's a selection in the video combo
     * box when the combo box in question becomes displayable.
     */
    comboBox.addHierarchyListener(
        new HierarchyListener() {
          public void hierarchyChanged(HierarchyEvent event) {
            if (((event.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0)
                && comboBox.isDisplayable()) {
              // let current changes end their execution
              // and after that trigger action on combobox
              SwingUtilities.invokeLater(
                  new Runnable() {
                    public void run() {
                      comboBoxListener.actionPerformed(null);
                    }
                  });
            } else {
              if (!comboBox.isDisplayable()) videoDeviceInPreview = null;
            }
          }
        });

    return preview;
  }

  /**
   * Creates preview for the device(video) in the video container.
   *
   * @param device the device
   * @param videoContainer the container
   * @throws IOException a problem accessing the device.
   * @throws MediaException a problem getting preview.
   */
  private static void createPreview(MediaDevice device, final JComponent videoContainer)
      throws IOException, MediaException {
    videoContainer.removeAll();

    videoContainer.revalidate();
    videoContainer.repaint();

    if (device == null) return;

    Component c =
        (Component)
            GuiActivator.getMediaService()
                .getVideoPreviewComponent(
                    device, videoContainer.getSize().width, videoContainer.getSize().height);

    videoContainer.add(c);
  }

  /**
   * Creates the video container.
   *
   * @param noVideoComponent the container component.
   * @return the video container.
   */
  private static JComponent createVideoContainer(Component noVideoComponent) {
    return new VideoContainer(noVideoComponent, false);
  }

  /** Custom combo box renderer. */
  private static class ComboRenderer extends DefaultListCellRenderer {
    @Override
    public Component getListCellRendererComponent(
        JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
      super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);

      MediaDevice mediaDevice = (MediaDevice) value;

      Dimension screenSize = null;
      if (mediaDevice != null) screenSize = ((VideoMediaFormat) mediaDevice.getFormat()).getSize();

      this.setText(screenSize.width + "x" + screenSize.height);

      return this;
    }
  }

  /**
   * Automatically press the cancel button when this dialog has been escaped.
   *
   * @param escaped indicates if this dialog has been closed by pressing the ESC key
   */
  @Override
  protected void close(boolean escaped) {
    if (escaped) cancelButton.doClick();
  }
}
  /**
   * Creates this account on the server.
   *
   * @return the created account
   */
  public NewAccount createAccount() {
    // Check if the two passwords match.
    String pass1 = new String(passField.getPassword());
    String pass2 = new String(retypePassField.getPassword());
    if (!pass1.equals(pass2)) {
      showErrorMessage(
          IppiAccRegWizzActivator.getResources()
              .getI18NString("plugin.sipaccregwizz.NOT_SAME_PASSWORD"));

      return null;
    }

    NewAccount newAccount = null;
    try {
      StringBuilder registerLinkBuilder = new StringBuilder(registerLink);
      registerLinkBuilder
          .append(URLEncoder.encode("email", "UTF-8"))
          .append("=")
          .append(URLEncoder.encode(emailField.getText(), "UTF-8"))
          .append("&")
          .append(URLEncoder.encode("password", "UTF-8"))
          .append("=")
          .append(URLEncoder.encode(new String(passField.getPassword()), "UTF-8"))
          .append("&")
          .append(URLEncoder.encode("display_name", "UTF-8"))
          .append("=")
          .append(URLEncoder.encode(displayNameField.getText(), "UTF-8"))
          .append("&")
          .append(URLEncoder.encode("username", "UTF-8"))
          .append("=")
          .append(URLEncoder.encode(usernameField.getText(), "UTF-8"))
          .append("&")
          .append(URLEncoder.encode("user_agent", "UTF-8"))
          .append("=")
          .append(URLEncoder.encode("sip-communicator.org", "UTF-8"));

      URL url = new URL(registerLinkBuilder.toString());
      URLConnection conn = url.openConnection();

      // If this is not an http connection we have nothing to do here.
      if (!(conn instanceof HttpURLConnection)) {
        return null;
      }

      HttpURLConnection httpConn = (HttpURLConnection) conn;

      int responseCode = httpConn.getResponseCode();

      if (responseCode == HttpURLConnection.HTTP_OK) {
        // Read all the text returned by the server
        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String str;

        StringBuffer stringBuffer = new StringBuffer();
        while ((str = in.readLine()) != null) {
          stringBuffer.append(str);
        }

        if (logger.isInfoEnabled())
          logger.info("JSON response to create account request: " + stringBuffer.toString());

        newAccount = parseHttpResponse(stringBuffer.toString());
      }
    } catch (MalformedURLException e1) {
      if (logger.isInfoEnabled())
        logger.info("Failed to create URL with string: " + registerLink, e1);
    } catch (IOException e1) {
      if (logger.isInfoEnabled()) logger.info("Failed to open connection.", e1);
    }
    return newAccount;
  }
예제 #24
0
  /**
   * Creates an instance of <tt>ShowPreviewDialog</tt>
   *
   * @param chatPanel The <tt>ChatConversationPanel</tt> that is associated with this dialog.
   */
  ShowPreviewDialog(final ChatConversationPanel chatPanel) {
    this.chatPanel = chatPanel;

    this.setTitle(
        GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW_DIALOG_TITLE"));
    okButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.OK"));
    cancelButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.CANCEL"));

    JPanel mainPanel = new TransparentPanel();
    mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
    mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    // mainPanel.setPreferredSize(new Dimension(200, 150));
    this.getContentPane().add(mainPanel);

    JTextPane descriptionMsg = new JTextPane();
    descriptionMsg.setEditable(false);
    descriptionMsg.setOpaque(false);
    descriptionMsg.setText(
        GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW_WARNING_DESCRIPTION"));

    Icon warningIcon = null;
    try {
      warningIcon =
          new ImageIcon(
              ImageIO.read(
                  GuiActivator.getResources().getImageURL("service.gui.icons.WARNING_ICON")));
    } catch (IOException e) {
      logger.debug("failed to load the warning icon");
    }
    JLabel warningSign = new JLabel(warningIcon);

    JPanel warningPanel = new TransparentPanel();
    warningPanel.setLayout(new BoxLayout(warningPanel, BoxLayout.X_AXIS));
    warningPanel.add(warningSign);
    warningPanel.add(Box.createHorizontalStrut(10));
    warningPanel.add(descriptionMsg);

    enableReplacement =
        new JCheckBox(
            GuiActivator.getResources()
                .getI18NString("plugin.chatconfig.replacement.ENABLE_REPLACEMENT_STATUS"));
    enableReplacement.setOpaque(false);
    enableReplacement.setSelected(cfg.getBoolean(ReplacementProperty.REPLACEMENT_ENABLE, true));
    enableReplacementProposal =
        new JCheckBox(
            GuiActivator.getResources()
                .getI18NString("plugin.chatconfig.replacement.ENABLE_REPLACEMENT_PROPOSAL"));
    enableReplacementProposal.setOpaque(false);

    JPanel checkBoxPanel = new TransparentPanel();
    checkBoxPanel.setLayout(new BoxLayout(checkBoxPanel, BoxLayout.Y_AXIS));
    checkBoxPanel.add(enableReplacement);
    checkBoxPanel.add(enableReplacementProposal);

    JPanel buttonsPanel = new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
    buttonsPanel.add(okButton);
    buttonsPanel.add(cancelButton);

    mainPanel.add(warningPanel);
    mainPanel.add(Box.createVerticalStrut(10));
    mainPanel.add(checkBoxPanel);
    mainPanel.add(buttonsPanel);

    okButton.addActionListener(this);
    cancelButton.addActionListener(this);

    this.setPreferredSize(new Dimension(390, 230));
  }
예제 #25
0
  /**
   * Gets the <code>SIPCommButton</code> which is the component of this plugin. If the button
   * doesn't exist, it's created.
   *
   * @return the <code>SIPCommButton</code> which is the component of this plugin
   */
  @SuppressWarnings("fallthrough")
  private SIPCommButton getButton() {
    if (button == null) {
      button = new SIPCommButton(null, null);
      button.setEnabled(false);
      button.setPreferredSize(new Dimension(25, 25));

      button.setToolTipText(
          OtrActivator.resourceService.getI18NString("plugin.otr.menu.OTR_TOOLTIP"));

      Image i1 = null, i2 = null, i3 = null;
      try {
        i1 =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.LOADING_ICON1_22x22"));
        i2 =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.LOADING_ICON2_22x22"));
        i3 =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.LOADING_ICON3_22x22"));
        finishedPadlockImage =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.FINISHED_ICON_22x22"));
        verifiedLockedPadlockImage =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.ENCRYPTED_ICON_22x22"));
        unverifiedLockedPadlockImage =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL(
                    "plugin.otr.ENCRYPTED_UNVERIFIED_ICON_22x22"));
        unlockedPadlockImage =
            ImageIO.read(
                OtrActivator.resourceService.getImageURL("plugin.otr.PLAINTEXT_ICON_22x22"));
        timedoutPadlockImage =
            ImageIO.read(OtrActivator.resourceService.getImageURL("plugin.otr.BROKEN_ICON_22x22"));
      } catch (IOException e) {
        logger.debug("Failed to load padlock image");
      }

      animatedPadlockImage = new AnimatedImage(button, i1, i2, i3);

      button.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              if (otrContact == null) return;

              switch (OtrActivator.scOtrEngine.getSessionStatus(otrContact)) {
                case ENCRYPTED:
                  OtrPolicy policy = OtrActivator.scOtrEngine.getContactPolicy(otrContact.contact);
                  policy.setSendWhitespaceTag(false);
                  OtrActivator.scOtrEngine.setContactPolicy(otrContact.contact, policy);
                case FINISHED:
                case LOADING:
                  // Default action for finished, encrypted and loading
                  // sessions is end session.
                  OtrActivator.scOtrEngine.endSession(otrContact);
                  break;
                case TIMED_OUT:
                case PLAINTEXT:
                  policy = OtrActivator.scOtrEngine.getContactPolicy(otrContact.contact);
                  OtrPolicy globalPolicy = OtrActivator.scOtrEngine.getGlobalPolicy();
                  policy.setSendWhitespaceTag(globalPolicy.getSendWhitespaceTag());
                  OtrActivator.scOtrEngine.setContactPolicy(otrContact.contact, policy);
                  // Default action for timed_out and plaintext sessions
                  // is start session.
                  OtrActivator.scOtrEngine.startSession(otrContact);
                  break;
              }
            }
          });
    }
    return button;
  }