/** * */ package net.frontlinesms.ui.handler.contacts; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import org.apache.log4j.Logger; import thinlet.Thinlet; import net.frontlinesms.FrontlineSMS; import net.frontlinesms.data.domain.Group; import net.frontlinesms.data.repository.unmodifiable.UnmodifiableGroupDao; import net.frontlinesms.ui.Icon; import net.frontlinesms.ui.ThinletUiEventHandler; import net.frontlinesms.ui.UiGeneratorController; import net.frontlinesms.ui.handler.BasePanelHandler; /** * @author aga */ public class GroupSelecterPanel extends BasePanelHandler { private Logger LOG = Logger.getLogger(this.getClass()); private static final String XML_LAYOUT_GROUP_PANEL = "/ui/core/contacts/pnGroupSelecter.xml"; private static final String COMPONENT_GROUP_TREE = "trGroups"; /** Thinlet UI component: the group tree */ private Object groupTreeComponent; private GroupSelecterPanelOwner owner; private UnmodifiableGroupDao groupDao; private boolean allowMultipleSelections; private Group rootGroup; /** A list of groups which should be disabled/hidden */ private final HashSet<Group> hiddenGroups = new HashSet<Group>(); //> CONSTRUCTORS public GroupSelecterPanel(UiGeneratorController ui, GroupSelecterPanelOwner owner) { super(ui); this.owner = owner; allowMultipleSelections = owner instanceof MultiGroupSelecterPanelOwner; } /** Initialise the selecter. */ public void init(Group rootGroup) { Collection<Group> noHiddenGroups = Collections.emptySet(); init(rootGroup, noHiddenGroups ); } /** Initialise the selecter. */ public void init(Group rootGroup, Collection<Group> hiddenGroups) { super.loadPanel(XML_LAYOUT_GROUP_PANEL); // TODO update selection of group tree appropriate to allowMultipleSelections // Cache the group tree groupTreeComponent = super.find(COMPONENT_GROUP_TREE); // add nodes for group tree this.setRootGroup(rootGroup); this.setHiddenGroups(hiddenGroups); } /** * Refresh the list of groups * This method will reload the view of groups. */ public void refresh(boolean showRoot) { Object groupTree = getGroupTreeComponent(); FrontlineSMS frontlineController = ((UiGeneratorController) super.ui).getFrontlineController(); this.groupDao = new UnmodifiableGroupDao(frontlineController.getGroupDao()); ui.removeAll(groupTree); Object node = createNode(getRootGroup(), showRoot); // If we want to show the root group, we add it to the tree component // Otherwise, the main nodes are added to the tree component in the createNode() function if (showRoot) ui.add(groupTree, node); } /** * Sets a list of groups which should be disabled/hidden * @param hiddenGroups */ public void setHiddenGroups(Collection<Group> hiddenGroups) { this.hiddenGroups.clear(); this.hiddenGroups.addAll(hiddenGroups); } public boolean isHidden(Group group) { return this.hiddenGroups.contains(group); } //> ACCESSORS /** @return a single group selected in the tree, or <code>null</code> if none is selected */ public Group getSelectedGroup() { assert(!this.allowMultipleSelections) : "Cannot get a single selection if multiple groups are selectable."; return ui.getAttachedObject(ui.getSelectedItem(this.getGroupTreeComponent()), Group.class); } /** @return groups selected in the tree */ public Collection<Group> getSelectedGroups() { assert(this.allowMultipleSelections) : "Cannot get multiple groups if multiple selection is not enabled."; Object[] selectedItems = ui.getSelectedItems(this.getGroupTreeComponent()); HashSet<Group> groups = new HashSet<Group>(); for(Object selected : selectedItems) { groups.add(ui.getAttachedObject(selected, Group.class)); } return groups; } /** @return Recursively search for the group in the tree */ public void selectGroup(Group g) { if (g == null) return; this.ui.setSelectedItem(getGroupTreeComponent(), getNodeForGroup(getGroupTreeComponent(), g)); this.selectionChanged(); } /** FIXME this is only here for debug purposes. */ @Override public Object getPanelComponent() { return super.getPanelComponent(); } /** Adds a new group to the tree */ public void addGroup(Group group) { Object groupTree = this.getGroupTreeComponent(); Group parent = group.getParent(); Object parentGroupNode; if(parent != null && !parent.isRoot()) { parentGroupNode = getNodeForGroup(groupTree, parent); } else { // There is no parent for the group, so we need to get the node for the root group parentGroupNode = ui.getItem(groupTree, 0); } ui.add(parentGroupNode, createNode(group, true)); } //> UI EVENT METHODS public void selectionChanged() { if(owner instanceof SingleGroupSelecterPanelOwner) { ((SingleGroupSelecterPanelOwner) owner).groupSelectionChanged(getSelectedGroup()); } else { ((MultiGroupSelecterPanelOwner) owner).groupSelectionChanged(getSelectedGroups()); } } //> UI HELPER METHODS /** * Gets the node we are currently displaying for a group. * @param component * @param group * @return */ private Object getNodeForGroup(Object component, Group group) { assert(group!=null) : "Cannot get a node for a null group."; Object ret = null; for (Object o : this.ui.getItems(component)) { Group g = ui.getAttachedObject(o, Group.class); if (g.equals(group)) { ret = o; break; } else { ret = getNodeForGroup(o, group); if (ret != null) break; } } return ret; } /** @return the group tree TODO cache this - it's not going to change, and we use it a lot */ public Object getGroupTreeComponent() { return this.groupTreeComponent; } /** * Creates a node for the supplied group, creating nodes for its sub-groups and contacts as well. * @param group The group to be put into a node. * @return a Thinlet tree node for displaying a group */ private Object createNode(Group group, boolean showRootGroup) { LOG.trace("ENTER"); LOG.debug("Group [" + group.getName() + "]"); String toSet = group.getName(); Object node; if (group.equals(getRootGroup()) && !showRootGroup) { node = groupTreeComponent; } else { node = ui.createNode(toSet, group); if(ui.getBoolean(node, Thinlet.EXPANDED)) { ui.setIcon(node, Icon.FOLDER_OPEN); } else { ui.setIcon(node, Icon.FOLDER_CLOSED); } } // Add subgroup components to this node for (Group subGroup : groupDao.getChildGroups(group)) { Object groupNode = createNode(subGroup, showRootGroup); if (groupNode != null) { ui.add(node, groupNode); if (hiddenGroups != null && hiddenGroups.contains(subGroup)) { ui.setEnabled(groupNode, false); } } } LOG.trace("EXIT"); return node; } public void setRootGroup(Group rootGroup) { this.rootGroup = rootGroup; } public void setPerform(ThinletUiEventHandler groupSelecterDialog, String methodCall) { ui.setPerform(this.groupTreeComponent, methodCall, this.groupTreeComponent, groupSelecterDialog); } public Group getRootGroup() { return rootGroup; } }