summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers/Roster/GroupRosterItem.cpp')
-rw-r--r--Swift/Controllers/Roster/GroupRosterItem.cpp201
1 files changed, 201 insertions, 0 deletions
diff --git a/Swift/Controllers/Roster/GroupRosterItem.cpp b/Swift/Controllers/Roster/GroupRosterItem.cpp
new file mode 100644
index 0000000..c473ae7
--- /dev/null
+++ b/Swift/Controllers/Roster/GroupRosterItem.cpp
@@ -0,0 +1,201 @@
+/*
+ * 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 String& name, GroupRosterItem* parent, bool sortByStatus) : RosterItem(name, parent), sortByStatus_(sortByStatus) {
+ expanded_ = true;
+}
+
+GroupRosterItem::~GroupRosterItem() {
+
+}
+
+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;
+}
+
+/**
+ * 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()) {
+ onChildrenChanged();
+ onDataChanged();
+ }
+}
+
+
+}