package cz.cuni.mff.inetpaint;
import com.sun.java.swing.plaf.windows.WindowsBorders.DashedBorder;
import cz.cuni.mff.inetpaint.communications.CommunicationFrame;
import java.awt.Color;
import java.awt.Insets;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.border.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.util.*;
import org.jivesoftware.smack.packet.*;
/**
* Třída reprezentující skupinu kontaktů v rosteru. Každá skupina lze rozbalovat a
* sbalovat, lze měnit její jméno a kontakty.
*
* @author Jindřich Helcl
*/
public class Group extends JPanel implements RosterListener {
private static final Color focusedHeaderBorderColor = new Color(184, 179, 217);
private static final Insets headerBorderInsets = new Insets(1,1,1,1);
private boolean offlineContactsVisible;
private boolean expanded;
private String name;
private GroupHeader header;
private ArrayList<Contact> contacts;
@Override
public void entriesAdded(Collection<String> addresses) { /*tady nic nebude*/ }
@Override
public void entriesDeleted(Collection<String> addresses) { /*tady nic nebude*/ }
@Override
public void entriesUpdated(Collection<String> addresses) { /*tady nic nebude*/ }
@Override
public void presenceChanged(Presence presence) {
String JIDFrom = StringUtils.parseBareAddress(presence.getFrom());
for(Contact c : contacts) {
if(c.getJID().equalsIgnoreCase(JIDFrom)) {
setUpStats();
return;
}
}
}
private void initComponents() {
GroupLayout layout = new GroupLayout(this);
setLayout(layout);
GroupLayout.SequentialGroup vertical;
GroupLayout.ParallelGroup horizontal;
if(header == null) {
vertical = layout.createSequentialGroup();
horizontal = layout.createParallelGroup(GroupLayout.Alignment.CENTER);
}
else {
header.setIcon(getStateIcon());
vertical = layout.createSequentialGroup().addComponent(header);
horizontal = layout.createParallelGroup(GroupLayout.Alignment.CENTER).addComponent(header);
}
for( Contact c : contacts ) {
GroupLayout.SequentialGroup new_vertical = vertical.addComponent(c);//, ContactList.ROSTER_ITEM_HEIGHT, GroupLayout.PREFERRED_SIZE, ContactList.ROSTER_ITEM_HEIGHT);
vertical = new_vertical;
GroupLayout.ParallelGroup new_horizontal = horizontal.addComponent(c, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE);
horizontal = new_horizontal;
}
layout.setVerticalGroup(vertical);
layout.setHorizontalGroup(horizontal);
}
private void initContacts(Collection<RosterEntry> entries) {
contacts = new ArrayList<Contact>(50);
for(RosterEntry ent : entries) {
Contact c = new Contact(ent.getUser());
// "oživit" kontakt
CommunicationFrame.addCommunicationListener(c);
contacts.add(c);
}
}
private Icon getStateIcon() {
return expanded ? new ImageIcon(Program.getImage("expanded.png")) : new ImageIcon(Program.getImage("collapsed.png"));
}
private void updateContactVisibility() {
for(Contact c : contacts) {
boolean visible;
if(!offlineContactsVisible)
visible = expanded && c.getPresence().isAvailable();
else visible = expanded;
c.setVisible(visible);
}
}
private void setUpStats() {
int pocet = contacts.size();
int online = getOnlineCount();
if(header != null) {
header.setPocet(pocet);
header.setOnline(online);
}
}
/**
* Vrátí počet kontaktů v této skupině, které jsou online
* @return Počet online uživatelů
*/
public int getOnlineCount() {
int online = 0;
for(Contact c : contacts) {
if(c.getPresence().isAvailable())
++online;
}
return online;
}
/**
* Nastaví viditelnost offline kontaktů uvnitř skupiny
* @param visible Viditelnost ({@literal true} => viditelné, {@literal false} => neviditelné)
*/
final public void setOfflineContactsVisible(boolean visible) {
offlineContactsVisible = visible;
updateContactVisibility();
}
/**
* Rozbalí/sbalí skupinu
* @param isExpanded Nový stav skupiny ({@literal true} => rozbalená, {@literal false} => sbalená)
*/
final public void setExpansionState(boolean isExpanded) {
expanded = isExpanded;
updateContactVisibility();
if(header != null)
header.setIcon(getStateIcon());
}
/**
* Vytvoří novou skupinu podle skupiny z rosteru s daným názvem.
* @param name Název skupiny kontaktů
* @param defaultExpanded Implicitní stav skupiny ({@literal true} => rozalená, {@literal false} => sbalená)
*/
public Group(String name, boolean defaultExpanded) {
this.name = name;
expanded = defaultExpanded;
header = new GroupHeader(name);
header.addMouseListener(new MouseAdapter() {
@Override public void mousePressed(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1) {
setExpansionState(!expanded);
header.requestFocusInWindow();
}
}
});
header.setBorder(new EmptyBorder(headerBorderInsets));
header.setFocusable(true);
header.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
header.setBorder(new DashedBorder(focusedHeaderBorderColor, 1));
}
@Override
public void focusLost(FocusEvent e) {
header.setBorder(new EmptyBorder(headerBorderInsets));
}
});
header.getInputMap().put(KeyStroke.getKeyStroke("DOWN"), "downPressed");
header.getInputMap().put(KeyStroke.getKeyStroke("UP"), "upPressed");
header.getActionMap().put("downPressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
header.transferFocus();
}
});
header.getActionMap().put("upPressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
header.transferFocusBackward();
}
});
header.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "stateChange");
header.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "stateChange");
header.getActionMap().put("stateChange", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
setExpansionState(!expanded);
}
});
final ConnectionManager manager = ConnectionManager.getInstance();
RosterGroup gr = manager.getRosterGroup(name);
initContacts(gr.getEntries());
setUpStats();
initComponents();
setExpansionState(defaultExpanded);
}
/**
* Vytvoří novou skupinu pro kontakty z rosteru bez určené skupiny
*/
public Group() {
final ConnectionManager manager = ConnectionManager.getInstance();
expanded = true;
initContacts(manager.getUnfiledRosterEntries());
initComponents();
setExpansionState(true);
}
}
/**
* Reprezentuje hlavičku skupiny. Hlavička zobrazuje název skupiny, počet online/všech členů.
*
* @author Jindřich Helcl
*/
class GroupHeader extends JPanel {
private static final int LEFT_GAP_SIZE = 8;
private static final int RIGHT_GAP_MIN_SIZE = 2;
private static final int CONTAINER_GAP_SIZE = 5;
private JLabel iconLabel;
private JLabel nameLabel;
private JLabel statsLabel;
private Integer pocet = 0;
private Integer online = 0;
private void updateStatsLabel() {
statsLabel.setText("(" + online.toString() + "/" + pocet.toString() + ")");
}
/**
* Nastaví počet online členů
* @param online Počet online členů
*/
public void setOnline(int online) {
this.online = online;
updateStatsLabel();
}
/**
* Nastaví počet všech členů
* @param pocet Počet členů
*/
public void setPocet(int pocet) {
this.pocet = pocet;
updateStatsLabel();
}
/**
* Nastaví jméno skupiny
* @param name Jméno
*/
public void setGroupName(String name) {
nameLabel.setText(name);
}
/**
* Nastaví ikonku (sbalovací)
* @param icon Ikona
*/
public void setIcon(Icon icon) {
iconLabel.setIcon(icon);
}
/**
* Vytvoří novou hlavičku skupiny
* @param name
*/
GroupHeader(String name) {
// dodelat stats label
iconLabel = new JLabel();
nameLabel = new JLabel(name);
statsLabel = new JLabel("N/A");
GroupLayout layout = new GroupLayout(this);
setLayout(layout);
layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(iconLabel)
.addComponent(nameLabel)
.addComponent(statsLabel)
);
layout.setHorizontalGroup(layout.createSequentialGroup()
.addGap(CONTAINER_GAP_SIZE)
.addComponent(iconLabel)
.addGap(LEFT_GAP_SIZE)
.addComponent(nameLabel)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, RIGHT_GAP_MIN_SIZE, Short.MAX_VALUE)
.addComponent(statsLabel)
.addGap(CONTAINER_GAP_SIZE)
);
}
}