private int addButton(SIPCommButton button, int gridX, int xBounds, boolean isLast) {
    lastAddedButton = button;

    constraints.insets = new Insets(0, 0, V_GAP, 0);
    constraints.anchor = GridBagConstraints.WEST;
    constraints.fill = GridBagConstraints.NONE;
    constraints.gridx = gridX;
    constraints.gridy = 2;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;
    constraints.weightx = 0f;
    constraints.weighty = 0f;
    this.add(button, constraints);

    int yBounds =
        TOP_BORDER
            + BOTTOM_BORDER
            + 2 * V_GAP
            + ComponentUtils.getStringSize(nameLabel, nameLabel.getText()).height
            + ComponentUtils.getStringSize(displayDetailsLabel, displayDetailsLabel.getText())
                .height;

    button.setBounds(xBounds, yBounds, BUTTON_WIDTH, BUTTON_HEIGHT);

    button.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));

    setButtonBg(button, gridX, isLast);

    return button.getWidth();
  }
  /**
   * Shows the appropriate user interface that would allow the user to add the given
   * <tt>SourceUIContact</tt> to their contact list.
   *
   * @param contact the contact to add
   */
  private void addContact(SourceUIContact contact) {
    SourceContact sourceContact = (SourceContact) contact.getDescriptor();

    List<ContactDetail> details =
        sourceContact.getContactDetails(OperationSetPersistentPresence.class);
    int detailsCount = details.size();

    if (detailsCount > 1) {
      JMenuItem addContactMenu =
          TreeContactList.createAddContactMenu((SourceContact) contact.getDescriptor());

      JPopupMenu popupMenu = ((JMenu) addContactMenu).getPopupMenu();

      // Add a title label.
      JLabel infoLabel = new JLabel();
      infoLabel.setText(
          "<html><b>"
              + GuiActivator.getResources().getI18NString("service.gui.ADD_CONTACT")
              + "</b></html>");

      popupMenu.insert(infoLabel, 0);
      popupMenu.insert(new Separator(), 1);

      popupMenu.setFocusable(true);
      popupMenu.setInvoker(treeContactList);

      Point location =
          new Point(
              addContactButton.getX(), addContactButton.getY() + addContactButton.getHeight());

      SwingUtilities.convertPointToScreen(location, treeContactList);

      location.y = location.y + treeContactList.getPathBounds(treeContactList.getSelectionPath()).y;

      popupMenu.setLocation(location.x + 8, location.y - 8);
      popupMenu.setVisible(true);
    } else if (details.size() == 1) {
      TreeContactList.showAddContactDialog(details.get(0), sourceContact.getDisplayName());
    }
  }
  /**
   * Initializes the display details component for the given <tt>UIContact</tt>.
   *
   * @param displayDetails the display details to show
   */
  private void initDisplayDetails(String displayDetails) {
    remove(displayDetailsLabel);
    displayDetailsLabel.setText("");

    if (displayDetails != null && displayDetails.length() > 0) {
      // Replace all occurrences of new line with slash.
      displayDetails = Html2Text.extractText(displayDetails);
      displayDetails = displayDetails.replaceAll("\n|<br>|<br/>", " / ");

      displayDetailsLabel.setText(displayDetails);
    }

    constraints.anchor = GridBagConstraints.WEST;
    constraints.fill = GridBagConstraints.NONE;
    constraints.gridx = 1;
    constraints.gridy = 1;
    constraints.weightx = 1f;
    constraints.weighty = 0f;
    constraints.gridwidth = 1;
    constraints.gridheight = 1;

    this.add(displayDetailsLabel, constraints);
  }
  /**
   * Returns the drag icon used to represent a cell in all drag operations.
   *
   * @param tree the parent tree object
   * @param dragObject the dragged object
   * @param index the index of the dragged object in the tree
   * @return the drag icon
   */
  public Icon getDragIcon(JTree tree, Object dragObject, int index) {
    ContactListTreeCellRenderer dragC =
        (ContactListTreeCellRenderer)
            getTreeCellRendererComponent(
                tree,
                dragObject,
                false, // is selected
                false, // is expanded
                true, // is leaf
                index,
                true // has focus
                );

    // We should explicitly set the bounds of all components in order that
    // they're correctly painted by paintIcon afterwards. This fixes empty
    // drag component in contact list!
    dragC.setBounds(0, 0, dragC.getIconWidth(), dragC.getIconHeight());

    Icon rightLabelIcon = rightLabel.getIcon();
    int imageHeight = 0;
    int imageWidth = 0;
    if (rightLabelIcon != null) {
      imageWidth = rightLabelIcon.getIconWidth();
      imageHeight = rightLabelIcon.getIconHeight();
      dragC.rightLabel.setBounds(tree.getWidth() - imageWidth, 0, imageWidth, imageHeight);
    }

    dragC.statusLabel.setBounds(0, 0, statusLabel.getWidth(), statusLabel.getHeight());

    dragC.nameLabel.setBounds(
        statusLabel.getWidth(), 0, tree.getWidth() - imageWidth - 5, nameLabel.getHeight());

    dragC.displayDetailsLabel.setBounds(
        displayDetailsLabel.getX(),
        nameLabel.getHeight(),
        displayDetailsLabel.getWidth(),
        displayDetailsLabel.getHeight());

    return dragC;
  }
  /**
   * Returns this panel that has been configured to display the meta contact and meta contact group
   * cells.
   *
   * @param tree the source tree
   * @param value the tree node
   * @param selected indicates if the node is selected
   * @param expanded indicates if the node is expanded
   * @param leaf indicates if the node is a leaf
   * @param row indicates the row number of the node
   * @param hasFocus indicates if the node has the focus
   * @return this panel
   */
  public Component getTreeCellRendererComponent(
      JTree tree,
      Object value,
      boolean selected,
      boolean expanded,
      boolean leaf,
      int row,
      boolean hasFocus) {
    this.treeContactList = (TreeContactList) tree;
    this.row = row;
    this.isSelected = selected;
    this.treeNode = (TreeNode) value;

    this.rightLabel.setIcon(null);

    DefaultTreeContactList contactList = (DefaultTreeContactList) tree;

    setBorder();
    addLabels(1);

    // Set background color.
    if (contactList instanceof TreeContactList) {
      ContactListFilter filter = ((TreeContactList) contactList).getCurrentFilter();

      if (filter != null
          && filter.equals(TreeContactList.historyFilter)
          && value instanceof ContactNode
          && row % 2 == 0) {
        setBackground(Constants.CALL_HISTORY_EVEN_ROW_COLOR);
      } else {
        setBackground(Color.WHITE);
      }
    }

    // Make appropriate adjustments for contact nodes and group nodes.
    if (value instanceof ContactNode) {
      UIContactImpl contact = ((ContactNode) value).getContactDescriptor();

      String displayName = contact.getDisplayName();

      if ((displayName == null || displayName.trim().length() < 1)
          && !(contact instanceof ShowMoreContact)) {
        displayName = GuiActivator.getResources().getI18NString("service.gui.UNKNOWN");
      }

      this.nameLabel.setText(displayName);

      if (statusIcon != null
          && contactList.isContactActive(contact)
          && statusIcon instanceof ImageIcon) ((ImageIcon) statusIcon).setImage(msgReceivedImage);
      else statusIcon = contact.getStatusIcon();

      this.statusLabel.setIcon(statusIcon);

      this.nameLabel.setFont(this.getFont().deriveFont(Font.PLAIN));

      if (contactForegroundColor != null) nameLabel.setForeground(contactForegroundColor);

      // Initializes status message components if the given meta contact
      // contains a status message.
      this.initDisplayDetails(contact.getDisplayDetails());

      if (this.treeContactList.isContactButtonsVisible()) this.initButtonsPanel(contact);

      int avatarWidth, avatarHeight;

      if (isSelected && treeContactList.isContactButtonsVisible()) {
        avatarWidth = EXTENDED_AVATAR_WIDTH;
        avatarHeight = EXTENDED_AVATAR_HEIGHT;
      } else {
        avatarWidth = AVATAR_WIDTH;
        avatarHeight = AVATAR_HEIGHT;
      }

      Icon avatar = contact.getAvatar(isSelected, avatarWidth, avatarHeight);

      if (avatar != null) {
        this.rightLabel.setIcon(avatar);
      }

      if (contact instanceof ShowMoreContact) {
        rightLabel.setFont(rightLabel.getFont().deriveFont(12f));
        rightLabel.setForeground(Color.GRAY);
        rightLabel.setText((String) contact.getDescriptor());
      } else {
        rightLabel.setFont(rightLabel.getFont().deriveFont(9f));
        rightLabel.setText("");
      }

      this.setToolTipText(contact.getDescriptor().toString());
    } else if (value instanceof GroupNode) {
      UIGroupImpl groupItem = ((GroupNode) value).getGroupDescriptor();

      this.nameLabel.setText(groupItem.getDisplayName());

      this.nameLabel.setFont(this.getFont().deriveFont(Font.BOLD));

      if (groupForegroundColor != null) this.nameLabel.setForeground(groupForegroundColor);

      this.remove(displayDetailsLabel);
      this.remove(callButton);
      this.remove(callVideoButton);
      this.remove(desktopSharingButton);
      this.remove(chatButton);
      this.remove(addContactButton);

      clearCustomActionButtons();

      statusIcon = expanded ? openedGroupIcon : closedGroupIcon;
      this.statusLabel.setIcon(expanded ? openedGroupIcon : closedGroupIcon);

      // We have no photo icon for groups.
      this.rightLabel.setIcon(null);
      this.rightLabel.setText("");

      if (groupItem.countChildContacts() >= 0) {
        rightLabel.setFont(rightLabel.getFont().deriveFont(9f));
        this.rightLabel.setForeground(Color.BLACK);
        this.rightLabel.setText(
            groupItem.countOnlineChildContacts() + "/" + groupItem.countChildContacts());
      }

      this.initDisplayDetails(groupItem.getDisplayDetails());
      this.initButtonsPanel(groupItem);
      this.setToolTipText(groupItem.getDescriptor().toString());
    }

    return this;
  }