/* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "Swift/Controllers/Roster/GroupRosterItem.h" #include <boost/bind.hpp> //#include <boost/algorithm.hpp> #include <iostream> namespace Swift { GroupRosterItem::GroupRosterItem(const std::string& name, GroupRosterItem* parent, bool sortByStatus) : RosterItem(name, parent), sortByStatus_(sortByStatus), manualSort_(false) { expanded_ = true; } GroupRosterItem::~GroupRosterItem() { } void GroupRosterItem::setManualSort(const std::string& manualSortValue) { manualSort_ = true; bool changed = manualSortValue_ != manualSortValue; manualSortValue_ = manualSortValue; if (changed) { onChildrenChanged(); onDataChanged(); } } const std::string& GroupRosterItem::getSortableDisplayName() const { return manualSort_ ? manualSortValue_ : RosterItem::getSortableDisplayName(); } bool GroupRosterItem::isExpanded() const { return expanded_; } /** This has no effect, and is only used by the UI. If reTransmit is specified, dataChanged will be emitted on a change - This may be undesireable if called from the UI, so you can use reTransmit=false to avoid a loop in this case. */ void GroupRosterItem::setExpanded(bool expanded) { bool old = expanded_; expanded_ = expanded; if (expanded != old) { onExpandedChanged(expanded); } } const std::vector<RosterItem*>& GroupRosterItem::getChildren() const { return children_; } const std::vector<RosterItem*>& GroupRosterItem::getDisplayedChildren() const { return displayedChildren_; } void GroupRosterItem::addChild(RosterItem* item) { children_.push_back(item); GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item); if (group) { group->onChildrenChanged.connect(boost::bind(&GroupRosterItem::handleChildrenChanged, this, group)); } else { item->onDataChanged.connect(boost::bind(&GroupRosterItem::handleDataChanged, this, item)); } onChildrenChanged(); onDataChanged(); } /** * Does not emit a changed signal. */ void GroupRosterItem::removeAll() { std::vector<RosterItem*>::iterator it = children_.begin(); displayedChildren_.clear(); while (it != children_.end()) { ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(*it); if (contact) { delete contact; } else { GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(*it); if (group) { group->removeAll(); delete group; } } ++it; } children_.clear(); } /** * Returns the removed item - but only if it's the only one, otherwise * the return result is undefined. */ ContactRosterItem* GroupRosterItem::removeChild(const JID& jid) { std::vector<RosterItem*>::iterator it = children_.begin(); ContactRosterItem* removed = NULL; while (it != children_.end()) { ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(*it); if (contact && contact->getJID() == jid) { displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), contact), displayedChildren_.end()); removed = contact; delete contact; it = children_.erase(it); continue; } GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(*it); if (group) { ContactRosterItem* groupRemoved = group->removeChild(jid); if (groupRemoved) { removed = groupRemoved; } } ++it; } onChildrenChanged(); onDataChanged(); return removed; } GroupRosterItem* GroupRosterItem::removeGroupChild(const std::string& groupName) { std::vector<RosterItem*>::iterator it = children_.begin(); GroupRosterItem* removed = NULL; while (it != children_.end()) { GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(*it); if (group && group->getDisplayName() == groupName) { displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), group), displayedChildren_.end()); removed = group; delete group; it = children_.erase(it); continue; } ++it; } onChildrenChanged(); onDataChanged(); return removed; } /** * Returns false if the list didn't need a resort */ bool GroupRosterItem::sortDisplayed() { /* Not doing this until we import boost::algorithm*/ // if (boost::is_sorted(displayedChildren_begin(), displayedChildren_.end(), itemLessThan)) { // return false; // } //Sholudn't need stable_sort here std::sort(displayedChildren_.begin(), displayedChildren_.end(), sortByStatus_? itemLessThanWithStatus : itemLessThanWithoutStatus); return true; } bool GroupRosterItem::itemLessThanWithoutStatus(const RosterItem* left, const RosterItem* right) { return left->getSortableDisplayName() < right->getSortableDisplayName(); } bool GroupRosterItem::itemLessThanWithStatus(const RosterItem* left, const RosterItem* right) { const ContactRosterItem* leftContact = dynamic_cast<const ContactRosterItem*>(left); const ContactRosterItem* rightContact = dynamic_cast<const ContactRosterItem*>(right); if (leftContact) { if (!rightContact) { return false; } StatusShow::Type leftType = leftContact->getSimplifiedStatusShow(); StatusShow::Type rightType = rightContact->getSimplifiedStatusShow(); if (leftType == rightType) { return left->getSortableDisplayName() < right->getSortableDisplayName(); } else { return leftType < rightType; } } else { if (rightContact) { return true; } return left->getSortableDisplayName() < right->getSortableDisplayName(); } } void GroupRosterItem::setDisplayed(RosterItem* item, bool displayed) { bool found = false; for (size_t i = 0; i < displayedChildren_.size(); i++) { if (displayedChildren_[i] == item) { found = true; } } if (found == displayed) { return; } if (displayed) { displayedChildren_.push_back(item); sortDisplayed(); } else { displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), item), displayedChildren_.end()); } onChildrenChanged(); onDataChanged(); } void GroupRosterItem::handleDataChanged(RosterItem* /*item*/) { if (sortDisplayed()) { onChildrenChanged(); } } void GroupRosterItem::handleChildrenChanged(GroupRosterItem* group) { size_t oldSize = getDisplayedChildren().size(); if (group->getDisplayedChildren().size() > 0) { bool found = false; for (size_t i = 0; i < displayedChildren_.size(); i++) { if (displayedChildren_[i] == group) { found = true; } } if (!found) { displayedChildren_.push_back(group); sortDisplayed(); } } else { displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), group), displayedChildren_.end()); } if (oldSize != getDisplayedChildren().size() || sortDisplayed()) { onChildrenChanged(); onDataChanged(); } } }