diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactInfoPanel.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactInfoPanel.java new file mode 100644 index 000000000..8dd158eca --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactInfoPanel.java @@ -0,0 +1,104 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +package net.java.sip.communicator.impl.gui.main.contactlist; + +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Point; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JWindow; +import javax.swing.SwingUtilities; + +import net.java.sip.communicator.impl.gui.main.ContactItem; +import net.java.sip.communicator.impl.gui.main.customcontrols.TransparentBackground; +import net.java.sip.communicator.impl.gui.main.customcontrols.TransparentWindow; +import net.java.sip.communicator.impl.gui.main.utils.AntialiasingManager; +import net.java.sip.communicator.impl.gui.main.utils.Constants; + +/** + * @author Yana Stamcheva + * + * The ContactListPanel contains the contact list. + */ + +public class ContactInfoPanel extends JWindow + implements WindowFocusListener { + + private JPanel protocolsPanel = new JPanel(new GridLayout(0, 1)); + + private ContactItem contactItem; + + TransparentBackground bg; + + public ContactInfoPanel(ContactItem contactItem){ + + this.contactItem = contactItem; + + this.protocolsPanel.setOpaque(false); + + //Create the transparent background component + this.bg = new TransparentBackground(this); + + this.bg.setLayout(new BorderLayout()); + + this.bg.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + this.getContentPane().setLayout(new BorderLayout()); + + this.init(); + + this.getContentPane().add(bg, BorderLayout.CENTER); + + this.pack(); + + this.setSize(140, 50); + + this.addWindowFocusListener(this); + } + + private void init() { + + String[] protocolList = this.contactItem.getProtocolList(); + + if(protocolsPanel.getComponentCount() == 0){ + for(int i = 0; i < protocolList.length; i ++){ + + JLabel protocolLabel = new JLabel(protocolList[i], + new ImageIcon(Constants.getProtocolIcon(protocolList[i])), + JLabel.LEFT); + + this.protocolsPanel.add(protocolLabel); + } + } + + this.bg.add(protocolsPanel, BorderLayout.CENTER); + } + + + public void windowGainedFocus(WindowEvent e) { + System.out.println("focus gained"); + } + + public void windowLostFocus(WindowEvent e) { + System.out.println("focus lost"); + this.setVisible(false); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListCellRenderer.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListCellRenderer.java new file mode 100644 index 000000000..f7f3c0269 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListCellRenderer.java @@ -0,0 +1,184 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +package net.java.sip.communicator.impl.gui.main.contactlist; + +import gov.nist.javax.sip.parser.ContactParser; + +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Stroke; +import java.awt.Transparency; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTree; +import javax.swing.JWindow; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeCellRenderer; + +import net.java.sip.communicator.impl.gui.main.ContactItem; +import net.java.sip.communicator.impl.gui.main.GroupItem; +import net.java.sip.communicator.impl.gui.main.customcontrols.SIPCommButton; +import net.java.sip.communicator.impl.gui.main.customcontrols.TransparentBackground; +import net.java.sip.communicator.impl.gui.main.utils.AntialiasingManager; +import net.java.sip.communicator.impl.gui.main.utils.Constants; +import net.java.sip.communicator.impl.gui.main.utils.ImageLoader; + +public class ContactListCellRenderer extends JPanel + implements TreeCellRenderer, ActionListener { + + private ContactItem contactItem; + + private JTree tree; + + private JLabel nameLabel = new JLabel(); + + private SIPCommButton extendPanelButton + = new SIPCommButton(ImageLoader.getImage(ImageLoader.MORE_INFO_ICON), + ImageLoader.getImage(ImageLoader.MORE_INFO_ICON)); + + private boolean isSelected = false; + + private boolean isLeaf = true; + + /** + * Initialize the panel containing the node. + */ + public ContactListCellRenderer() { + + super(new BorderLayout()); + + this.setBackground(Color.WHITE); + + this.setOpaque(true); + + this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + + this.nameLabel.setIconTextGap(2); + + this.extendPanelButton.addActionListener(this); + + this.add(nameLabel, BorderLayout.CENTER); + + this.add(extendPanelButton, BorderLayout.EAST); + } + + + public Component getTreeCellRendererComponent(JTree tree, Object value, + boolean selected, boolean expanded, boolean leaf, int row, + boolean hasFocus) { + + this.tree = tree; + + // Find out which node we are rendering and get its text + ContactNode node = (ContactNode) value; + + if(leaf){ + + if (node.getUserObject() instanceof ContactItem) { + + ContactItem contactItem = (ContactItem) node.getUserObject(); + + this.contactItem = contactItem; + + this.nameLabel.setText(contactItem.getNickName()); + + this.nameLabel.setIcon(contactItem.getUserIcon()); + + this.nameLabel.setFont(this.getFont().deriveFont(Font.PLAIN)); + + this.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + + this.setPreferredSize(new Dimension(Constants.MAINFRAME_WIDTH + 20, 17)); + + this.setBounds(0, 0, Constants.MAINFRAME_WIDTH + 20, 17); + } + } + else{ + if (node.getUserObject() instanceof GroupItem) { + + GroupItem groupItem = (GroupItem) node.getUserObject(); + + this.nameLabel.setText(groupItem.getGroupName()); + + this.nameLabel.setIcon(new ImageIcon( + ImageLoader.getImage(ImageLoader.GROUPS_16x16_ICON))); + + this.nameLabel.setFont(this.getFont().deriveFont(Font.BOLD)); + + this.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); + + this.setPreferredSize(new Dimension(Constants.MAINFRAME_WIDTH + 20, 20)); + + this.setBounds(0, 0, Constants.MAINFRAME_WIDTH + 20, 20); + } + } + + this.isSelected = selected; + + this.isLeaf = leaf; + + return this; + } + + public void paintComponent(Graphics g) { + super.paintComponent(g); + + Graphics2D g2 = (Graphics2D) g; + + AntialiasingManager.activateAntialiasing(g2); + + if(!this.isLeaf){ + + g2.setColor(Constants.CONTACTPANEL_MOVER_START_COLOR); + g2.fillRoundRect(0, 0, this.getWidth(), this.getHeight(), 7, 7); + } + + if (this.isSelected) { + + g2.setColor(Constants.CONTACTPANEL_SELECTED_END_COLOR); + g2.fillRoundRect(0, 0, this.getWidth(), this.getHeight(), 7, 7); + + g2.setColor(Constants.CONTACTPANEL_BORDER_COLOR); + g2.setStroke(new BasicStroke(1.5f)); + g2.drawRoundRect(0, 0, this.getWidth() - 1, this.getHeight() - 1, 7, 7); + + } + } + + public SIPCommButton getExtendPanelButton() { + return extendPanelButton; + } + + public void actionPerformed(ActionEvent e) { + + ContactInfoPanel contactInfoPanel = new ContactInfoPanel(this.contactItem); + +// TODO: To calculate accurately the position of the contact info popup. + contactInfoPanel.setLocation(800, 200); + + contactInfoPanel.setVisible(true); + + } + +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPanel.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPanel.java new file mode 100755 index 000000000..3a9abca87 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPanel.java @@ -0,0 +1,203 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +package net.java.sip.communicator.impl.gui.main.contactlist; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Point; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; + +import net.java.sip.communicator.impl.gui.main.ContactItem; +import net.java.sip.communicator.impl.gui.main.ContactList; +import net.java.sip.communicator.impl.gui.main.ContactRightButtonMenu; +import net.java.sip.communicator.impl.gui.main.GroupItem; +import net.java.sip.communicator.impl.gui.main.MainFrame; +import net.java.sip.communicator.impl.gui.main.message.MessageWindow; +import net.java.sip.communicator.service.contactlist.MetaContactListService; + +/** + * @author Yana Stamcheva + * + * The ContactListPanel contains the contact list. + */ +public class ContactListPanel extends JScrollPane implements MouseListener { + + private MetaContactListService contactList; + + private MainFrame parent; + + private ContactListTree contactListTree; + + private JPanel treePanel = new JPanel(new BorderLayout()); + + public ContactListPanel(MainFrame parent) { + + this.parent = parent; + + this.contactList = parent.getContactList(); + + this.contactListTree = new ContactListTree(new ContactNode(new GroupItem("root"))); + + this.contactListTree.addMouseListener(this); + + this.initTree(); + + this.treePanel.add(contactListTree, BorderLayout.NORTH); + + this.getViewport().add(treePanel); + + this.treePanel.setBackground(Color.WHITE); + } + + private void initTree() { + /* + // TODO: To be removed!!!! + ContactNode generalGroup = (ContactNode)this.contactListTree + .addChild(new GroupItem("General")); + + for (int i = 0; i < this.contactList.getAllContacts().size(); i++) { + + this.contactListTree.addChild(generalGroup, (ContactItem) this.clist + .getAllContacts().get(i), true); + } + */ + } + + public void mouseClicked(MouseEvent e) { + // TODO Auto-generated method stub + + } + + public void mouseEntered(MouseEvent e) { + // TODO Auto-generated method stub + + } + + public void mouseExited(MouseEvent e) { + // TODO Auto-generated method stub + + } + + public void mousePressed(MouseEvent e) { + + int selRow = this.contactListTree.getRowForLocation(e.getX(), e.getY()); + + TreePath selPath = this.contactListTree.getPathForLocation(e.getX(), e.getY()); + + if (selRow != -1) { + + if (e.getClickCount() == 1) { + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) contactListTree + .getLastSelectedPathComponent(); + + if (node == null) return; + + if (node.isLeaf()) { + + ContactListCellRenderer renderer = + (ContactListCellRenderer) this.contactListTree.getCellRenderer() + .getTreeCellRendererComponent( this.contactListTree, + selPath.getLastPathComponent(), + false, false, + true, selRow, true); + + //Translate coordinates into cell cordinates. + + int translatedX = (int)e.getX() - (int)this.contactListTree.getPathBounds(selPath).getX(); + + int translatedY = (int)e.getY() - (int)this.contactListTree.getPathBounds(selPath).getY(); + + Component component = renderer.findComponentAt(translatedX, translatedY); + + ContactItem contactItem = (ContactItem) node.getUserObject(); + + if(component instanceof JLabel){ + + if((e.getModifiers() & InputEvent.BUTTON1_MASK) == + InputEvent.BUTTON1_MASK){ + + SwingUtilities.invokeLater(new RunMessageWindow(contactItem)); + } + else if((e.getModifiers() & InputEvent.BUTTON3_MASK) == + InputEvent.BUTTON3_MASK){ + + ContactRightButtonMenu popupMenu + = new ContactRightButtonMenu(parent, contactItem); + + popupMenu.setInvoker(this.contactListTree); + + popupMenu.setLocation(popupMenu.getPopupLocation()); + + popupMenu.setVisible(true); + } + } + else if(component instanceof JButton){ + + ContactInfoPanel contactInfoPanel = new ContactInfoPanel(contactItem); + + Point p = new Point(); + + p.x = (int)this.contactListTree.getPathBounds(selPath).getX(); + + p.y = (int)this.contactListTree.getPathBounds(selPath).getY(); + + SwingUtilities.convertPointToScreen(p, this.contactListTree); + + //TODO: to calculate popup window posititon properly. + contactInfoPanel.setLocation(p.x - 140, p.y - 15); + + contactInfoPanel.setVisible(true); + + contactInfoPanel.requestFocus(); + } + } + + } + else if (e.getClickCount() == 2){ + + } + } + } + + public void mouseReleased(MouseEvent e) { + // TODO Auto-generated method stub + } + + private class RunMessageWindow implements Runnable{ + + private ContactItem contactItem; + + private RunMessageWindow(ContactItem contactItem){ + this.contactItem = contactItem; + } + + public void run() { + + MessageWindow msgWindow = new MessageWindow(parent); + + msgWindow.addContactToChat(this.contactItem); + + msgWindow.setVisible(true); + + msgWindow.getWriteMessagePanel().getEditorPane().requestFocus(); + } + } +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTree.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTree.java new file mode 100644 index 000000000..5cb703ca2 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTree.java @@ -0,0 +1,108 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +package net.java.sip.communicator.impl.gui.main.contactlist; + +import java.awt.Cursor; + +import javax.swing.BorderFactory; +import javax.swing.JTree; +import javax.swing.plaf.basic.BasicTreeUI; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; + +import net.java.sip.communicator.impl.gui.main.ui.SIPCommTreeUI; + +public class ContactListTree extends JTree { + + private ContactListTreeModel treeModel; + + private ContactNode rootNode; + + public ContactListTree(ContactNode rootNode){ + + this.rootNode = rootNode; + + this.treeModel = new ContactListTreeModel(rootNode); + + this.setModel(this.treeModel); + + this.setRootVisible(false); + + this.setEditable(true); + + this.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); + + this.getSelectionModel().setSelectionMode + (TreeSelectionModel .SINGLE_TREE_SELECTION); + + this.setCellRenderer(new ContactListCellRenderer()); + + this.putClientProperty("JTree.lineStyle", "None"); + + this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + + this.setUI(new SIPCommTreeUI()); + + ((BasicTreeUI)this.getUI()).setLeftChildIndent(0); + + ((BasicTreeUI)this.getUI()).setRightChildIndent(0); + } + + /** + * Adds a child directly to the root node. + * + * @param child The child object to be added. + * @return The added node. + */ + public ContactNode addChild(Object child) { + + ContactNode parentNode = null; + + TreePath parentPath = this.getSelectionPath(); + + if (parentPath == null) { + + //There's no selection. Default to the root node. + parentNode = this.rootNode; + + } else { + + parentNode = (ContactNode) + (parentPath.getLastPathComponent()); + } + + return addChild(parentNode, child, true); + } + + + /** + * Adds a child to a given parent. + * + * @param parent The parent node. + * @param child The child object. + * @param shouldBeVisible + * @return The added node. + */ + public ContactNode addChild(ContactNode parent, + Object child, + boolean shouldBeVisible) { + + ContactNode childNode = + new ContactNode(child); + + treeModel.insertNodeInto(childNode, parent, + parent.getChildCount()); + + //Make sure the user can see the new node. + if (shouldBeVisible) { + this.scrollPathToVisible(new TreePath(childNode.getPath())); + } + + return childNode; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeModel.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeModel.java new file mode 100644 index 000000000..019c5f31a --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeModel.java @@ -0,0 +1,66 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +package net.java.sip.communicator.impl.gui.main.contactlist; + +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; + +public class ContactListTreeModel extends DefaultTreeModel + implements TreeModelListener { + + public ContactListTreeModel(TreeNode root) { + super(root); + + this.addTreeModelListener(this); + } + + public void treeNodesChanged(TreeModelEvent e) { + + ContactNode node; + + node = (ContactNode) + (e.getTreePath().getLastPathComponent()); + + /* + * If the event lists children, then the changed + * node is the child of the node we've already + * gotten. Otherwise, the changed node and the + * specified node are the same. + */ + try { + int index = e.getChildIndices()[0]; + + node = (ContactNode) + (node.getChildAt(index)); + + + } catch (NullPointerException exc) {} + + System.out.println("The user has finished editing the node."); + System.out.println("New value: " + node.getUserObject()); + } + + public void treeNodesInserted(TreeModelEvent e) { + // TODO Auto-generated method stub + + } + + public void treeNodesRemoved(TreeModelEvent e) { + // TODO Auto-generated method stub + + } + + public void treeStructureChanged(TreeModelEvent e) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactNode.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactNode.java new file mode 100644 index 000000000..2121f7c5f --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactNode.java @@ -0,0 +1,55 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +package net.java.sip.communicator.impl.gui.main.contactlist; + +import java.awt.Cursor; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeNode; + +import net.java.sip.communicator.impl.gui.main.ContactItem; +import net.java.sip.communicator.impl.gui.main.GroupItem; + +public class ContactNode extends DefaultMutableTreeNode { + + private boolean leafExpanded = false; + + public ContactNode(){ + + } + + public ContactNode(Object userObject){ + super(userObject); + } + + public String toString() { + + String result = ""; + + if (userObject == null) { + return null; + } else { + //TODO: to replace ContactItem with MetaContact and GroupItem with MetaGroup + if (userObject instanceof ContactItem) + result = ((ContactItem)userObject).getNickName(); + else if (userObject instanceof GroupItem) + result = ((GroupItem)userObject).getGroupName(); + } + + return result; + } + + public boolean isLeafExpanded() { + return leafExpanded; + } + + public void setLeafExpanded(boolean leafExpanded) { + this.leafExpanded = leafExpanded; + } + +}