summaryrefslogtreecommitdiffstats
path: root/Swift
diff options
context:
space:
mode:
authorRichard Maudsley <richard.maudsley@isode.com>2014-03-14 14:15:34 (GMT)
committerKevin Smith <git@kismith.co.uk>2014-04-02 11:14:52 (GMT)
commitc9275affd040ee1ca7c1d599b28df3b363bef888 (patch)
tree04afffe1e766f897f2208cf097a307a5fe530032 /Swift
parentb92fe0b47d519da5fd55ba55ad0838e1ff69195c (diff)
downloadswift-c9275affd040ee1ca7c1d599b28df3b363bef888.zip
swift-c9275affd040ee1ca7c1d599b28df3b363bef888.tar.bz2
Make the impromptu MUCs behave more like a regular chat.
This hides occupant types in the participant list and initiates a direct 1-to-1 on occupant double-click instead of MUC-proxied 1-to-1. Change-Id: I76c57fe52beb3e4236524c1d8cfbd583d3dc3f62
Diffstat (limited to 'Swift')
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp31
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h3
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h2
-rw-r--r--Swift/QtUI/QtChatWindow.cpp7
-rw-r--r--Swift/QtUI/QtChatWindow.h2
-rw-r--r--Swift/QtUI/QtHistoryWindow.cpp2
-rw-r--r--Swift/QtUI/Roster/QtOccupantListWidget.cpp15
-rw-r--r--Swift/QtUI/Roster/QtOccupantListWidget.h11
-rw-r--r--Swift/QtUI/Roster/QtRosterWidget.cpp2
-rw-r--r--Swift/QtUI/Roster/QtTreeWidget.cpp30
-rw-r--r--Swift/QtUI/Roster/QtTreeWidget.h22
-rw-r--r--Swift/QtUI/Roster/RosterModel.cpp12
-rw-r--r--Swift/QtUI/Roster/RosterModel.h6
13 files changed, 98 insertions, 47 deletions
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index 14d1767..f83a772 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -104,8 +104,6 @@ MUCController::MUCController (
muc_->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1));
muc_->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));
muc_->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
- muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
- muc_->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
muc_->onRoleChangeFailed.connect(boost::bind(&MUCController::handleOccupantRoleChangeFailed, this, _1, _2, _3));
muc_->onAffiliationListReceived.connect(boost::bind(&MUCController::handleAffiliationListReceived, this, _1, _2));
muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1));
@@ -119,9 +117,11 @@ MUCController::MUCController (
}
if (isImpromptu) {
muc_->onUnlocked.connect(boost::bind(&MUCController::handleRoomUnlocked, this));
- chatWindow_->convertToMUC(true);
+ chatWindow_->convertToMUC(ChatWindow::ImpromptuMUC);
} else {
- chatWindow_->convertToMUC();
+ muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
+ muc_->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
+ chatWindow_->convertToMUC(ChatWindow::StandardMUC);
chatWindow_->setName(muc->getJID().getNode());
}
setOnline(true);
@@ -154,7 +154,7 @@ void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item
if (item) {
MUCOccupant::Affiliation affiliation = muc_->getOccupant(getNick()).getAffiliation();
MUCOccupant::Role role = muc_->getOccupant(getNick()).getRole();
- if (role == MUCOccupant::Moderator)
+ if (role == MUCOccupant::Moderator && !isImpromptu_)
{
if (affiliation == MUCOccupant::Admin || affiliation == MUCOccupant::Owner) {
actions.push_back(ChatWindow::Ban);
@@ -348,8 +348,12 @@ void MUCController::handleJoinComplete(const std::string& nick) {
clearPresenceQueue();
shouldJoinOnReconnect_ = true;
setEnabled(true);
- MUCOccupant occupant = muc_->getOccupant(nick);
- setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
+ if (isImpromptu_) {
+ setAvailableRoomActions(MUCOccupant::NoAffiliation, MUCOccupant::Participant);
+ } else {
+ MUCOccupant occupant = muc_->getOccupant(nick);
+ setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
+ }
onUserJoined();
if (isImpromptu_) {
@@ -384,13 +388,18 @@ void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {
currentOccupants_.insert(occupant.getNick());
NickJoinPart event(occupant.getNick(), Join);
appendToJoinParts(joinParts_, event);
- std::string groupName(roleToGroupName(occupant.getRole()));
+ MUCOccupant::Role role = MUCOccupant::Participant;
+ MUCOccupant::Affiliation affiliation = MUCOccupant::NoAffiliation;
+ if (!isImpromptu_) {
+ role = occupant.getRole();
+ affiliation = occupant.getAffiliation();
+ }
+ std::string groupName(roleToGroupName(role));
roster_->addContact(jid, realJID, occupant.getNick(), groupName, avatarManager_->getAvatarPath(jid));
- roster_->applyOnItems(SetMUC(jid, occupant.getRole(), occupant.getAffiliation()));
- roster_->getGroup(groupName)->setManualSort(roleToSortName(occupant.getRole()));
+ roster_->applyOnItems(SetMUC(jid, role, affiliation));
+ roster_->getGroup(groupName)->setManualSort(roleToSortName(role));
if (joined_) {
std::string joinString;
- MUCOccupant::Role role = occupant.getRole();
if (role != MUCOccupant::NoRole && role != MUCOccupant::Participant) {
joinString = str(format(QT_TRANSLATE_NOOP("", "%1% has entered the %3% as a %2%.")) % occupant.getNick() % roleToFriendlyName(role) % (isImpromptu_ ? QT_TRANSLATE_NOOP("", "chat") : QT_TRANSLATE_NOOP("", "room")));
}
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 0f0062d..771872a 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -92,6 +92,7 @@ namespace Swift {
enum WhiteboardSessionState {WhiteboardAccepted, WhiteboardTerminated, WhiteboardRejected};
enum BlockingState {BlockingUnsupported, IsBlocked, IsUnblocked};
enum Direction { UnknownDirection, DefaultDirection };
+ enum MUCType { StandardMUC, ImpromptuMUC };
ChatWindow() {}
virtual ~ChatWindow() {}
@@ -132,7 +133,7 @@ namespace Swift {
virtual void setSecurityLabelsEnabled(bool enabled) = 0;
virtual void setCorrectionEnabled(Tristate enabled) = 0;
virtual void setUnreadMessageCount(int count) = 0;
- virtual void convertToMUC(bool impromptuMUC = false) = 0;
+ virtual void convertToMUC(MUCType mucType) = 0;
// virtual TreeWidget *getTreeWidget() = 0;
virtual void setSecurityLabelsError() = 0;
virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() = 0;
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 59ed0f1..8aa645d 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -45,7 +45,7 @@ namespace Swift {
virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) {labels_ = labels;}
virtual void setSecurityLabelsEnabled(bool enabled) {labelsEnabled_ = enabled;}
virtual void setUnreadMessageCount(int /*count*/) {}
- virtual void convertToMUC(bool /*impromptuMUC*/) {}
+ virtual void convertToMUC(MUCType /*mucType*/) {}
virtual void setSecurityLabelsError() {}
virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() {return label_;}
virtual void setInputEnabled(bool /*enabled*/) {}
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 826ec9e..bd7c817 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -116,7 +116,7 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
}
logRosterSplitter_->addWidget(messageLog_);
- treeWidget_ = new QtOccupantListWidget(eventStream_, settings_, this);
+ treeWidget_ = new QtOccupantListWidget(eventStream_, settings_, QtTreeWidget::MessageDefaultJID, this);
treeWidget_->hide();
logRosterSplitter_->addWidget(treeWidget_);
logRosterSplitter_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -396,8 +396,9 @@ void QtChatWindow::closeEvent(QCloseEvent* event) {
onClosed();
}
-void QtChatWindow::convertToMUC(bool impromptuMUC) {
- impromptu_ = impromptuMUC;
+void QtChatWindow::convertToMUC(MUCType mucType) {
+ impromptu_ = (mucType == ImpromptuMUC);
+ treeWidget_->setMessageTarget(impromptu_ ? QtTreeWidget::MessageDisplayJID : QtTreeWidget::MessageDefaultJID);
isMUC_ = true;
treeWidget_->show();
subject_->setVisible(!impromptu_);
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index eeb8093..5a4fe95 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -99,7 +99,7 @@ namespace Swift {
void show();
void activate();
void setUnreadMessageCount(int count);
- void convertToMUC(bool impromptuMUC = false);
+ void convertToMUC(MUCType mucType);
// TreeWidget *getTreeWidget();
void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels);
void setSecurityLabelsEnabled(bool enabled);
diff --git a/Swift/QtUI/QtHistoryWindow.cpp b/Swift/QtUI/QtHistoryWindow.cpp
index 9f88258..75eeaad 100644
--- a/Swift/QtUI/QtHistoryWindow.cpp
+++ b/Swift/QtUI/QtHistoryWindow.cpp
@@ -60,7 +60,7 @@ QtHistoryWindow::QtHistoryWindow(SettingsProvider* settings, UIEventStream* even
ui_.bottomLayout_->addWidget(conversation_);
delete ui_.conversationRoster_;
- conversationRoster_ = new QtTreeWidget(eventStream, settings, this);
+ conversationRoster_ = new QtTreeWidget(eventStream, settings, QtTreeWidget::MessageDefaultJID, this);
QSizePolicy sizePolicy2(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy2.setVerticalStretch(80);
conversationRoster_->setSizePolicy(sizePolicy2);
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.cpp b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
index 12dc1e4..4f1baf3 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.cpp
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
@@ -1,25 +1,26 @@
/*
- * Copyright (c) 2011-2012 Kevin Smith
+ * Copyright (c) 2011-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Roster/QtOccupantListWidget.h"
+#include <Swift/QtUI/Roster/QtOccupantListWidget.h>
#include <QContextMenuEvent>
#include <QMenu>
#include <QAction>
#include <QInputDialog>
-#include "Swift/Controllers/Roster/ContactRosterItem.h"
-#include "Swift/Controllers/Roster/GroupRosterItem.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "QtSwiftUtil.h"
+#include <Swift/Controllers/Roster/ContactRosterItem.h>
+#include <Swift/Controllers/Roster/GroupRosterItem.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
namespace Swift {
-QtOccupantListWidget::QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, parent) {
+QtOccupantListWidget::QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget privateMessageTarget, QWidget* parent) : QtTreeWidget(eventStream, settings, privateMessageTarget, parent) {
}
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.h b/Swift/QtUI/Roster/QtOccupantListWidget.h
index 729115a..c944658 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.h
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.h
@@ -1,15 +1,16 @@
/*
- * Copyright (c) 2011-2012 Kevin Smith
+ * Copyright (c) 2011-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
-#include "Swift/QtUI/Roster/QtTreeWidget.h"
+#include <Swift/QtUI/Roster/QtTreeWidget.h>
-#include "Swiften/Base/boost_bsignals.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
+#include <Swiften/Base/boost_bsignals.h>
+
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
namespace Swift {
class SettingsProvider;
@@ -17,7 +18,7 @@ class SettingsProvider;
class QtOccupantListWidget : public QtTreeWidget {
Q_OBJECT
public:
- QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = 0);
+ QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget privateMessageTarget, QWidget* parent = NULL);
virtual ~QtOccupantListWidget();
void setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions);
boost::signal<void (ChatWindow::OccupantAction, ContactRosterItem*)> onOccupantActionSelected;
diff --git a/Swift/QtUI/Roster/QtRosterWidget.cpp b/Swift/QtUI/Roster/QtRosterWidget.cpp
index 1436c7c..fff0ccd 100644
--- a/Swift/QtUI/Roster/QtRosterWidget.cpp
+++ b/Swift/QtUI/Roster/QtRosterWidget.cpp
@@ -28,7 +28,7 @@
namespace Swift {
-QtRosterWidget::QtRosterWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, parent) {
+QtRosterWidget::QtRosterWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, MessageDefaultJID, parent) {
}
diff --git a/Swift/QtUI/Roster/QtTreeWidget.cpp b/Swift/QtUI/Roster/QtTreeWidget.cpp
index 91e9a33..ed76a6f 100644
--- a/Swift/QtUI/Roster/QtTreeWidget.cpp
+++ b/Swift/QtUI/Roster/QtTreeWidget.cpp
@@ -26,12 +26,12 @@
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/QtUI/QtUISettingConstants.h>
-
+#include <Swift/QtUI/Roster/RosterModel.h>
#include <QtSwiftUtil.h>
namespace Swift {
-QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QTreeView(parent), tooltipShown_(false) {
+QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget messageTarget, QWidget* parent) : QTreeView(parent), messageTarget_(messageTarget), tooltipShown_(false) {
eventStream_ = eventStream;
settings_ = settings;
model_ = new RosterModel(this, settings_->getSetting(QtUISettingConstants::USE_SCREENREADER));
@@ -137,12 +137,24 @@ void QtTreeWidget::currentChanged(const QModelIndex& current, const QModelIndex&
QTreeView::currentChanged(current, previous);
}
-
void QtTreeWidget::handleItemActivated(const QModelIndex& index) {
- RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
- ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
- if (contact) {
- eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(contact->getJID())));
+ switch (messageTarget_) {
+ case MessageDisplayJID: {
+ QString indexJID = index.data(DisplayJIDRole).toString();
+ if (!indexJID.isEmpty()) {
+ JID target = JID(Q2PSTRING(indexJID)).toBare();
+ eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(target)));
+ break;
+ }
+ }
+ case MessageDefaultJID: {
+ QString indexJID = index.data(JIDRole).toString();
+ if (!indexJID.isEmpty()) {
+ JID target = JID(Q2PSTRING(indexJID));
+ eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(target)));
+ }
+ break;
+ }
}
}
@@ -230,4 +242,8 @@ void QtTreeWidget::show() {
QWidget::show();
}
+void QtTreeWidget::setMessageTarget(MessageTarget messageTarget) {
+ messageTarget_ = messageTarget;
+}
+
}
diff --git a/Swift/QtUI/Roster/QtTreeWidget.h b/Swift/QtUI/Roster/QtTreeWidget.h
index 8884a40..29e985d 100644
--- a/Swift/QtUI/Roster/QtTreeWidget.h
+++ b/Swift/QtUI/Roster/QtTreeWidget.h
@@ -1,34 +1,40 @@
/*
- * Copyright (c) 2010-2012 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
-#include <QTreeView>
-#include <QModelIndex>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QDragMoveEvent>
+#include <QModelIndex>
+#include <QTreeView>
-#include <Swift/QtUI/Roster/RosterModel.h>
#include <Swift/QtUI/Roster/RosterDelegate.h>
+#include <Swift/QtUI/Roster/RosterModel.h>
+
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
namespace Swift {
class UIEventStream;
class SettingsProvider;
-class QtTreeWidget : public QTreeView{
+class QtTreeWidget : public QTreeView {
Q_OBJECT
public:
- QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = 0);
+ enum MessageTarget {MessageDefaultJID, MessageDisplayJID};
+
+ QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget messageTarget, QWidget* parent = 0);
~QtTreeWidget();
void show();
QtTreeWidgetItem* getRoot();
void setRosterModel(Roster* roster);
Roster* getRoster() {return roster_;}
void refreshTooltip();
+ void setMessageTarget(MessageTarget messageTarget);
+ public:
boost::signal<void (RosterItem*)> onSomethingSelectedChanged;
private slots:
@@ -45,9 +51,8 @@ class QtTreeWidget : public QTreeView{
void dropEvent(QDropEvent* event);
void dragMoveEvent(QDragMoveEvent* event);
bool event(QEvent* event);
-
- protected:
QModelIndexList getSelectedIndexes() const;
+
private:
void drawBranches(QPainter*, const QRect&, const QModelIndex&) const;
@@ -63,6 +68,7 @@ class QtTreeWidget : public QTreeView{
QtTreeWidgetItem* treeRoot_;
SettingsProvider* settings_;
bool tooltipShown_;
+ MessageTarget messageTarget_;
};
}
diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp
index fa8c393..2bd0d09 100644
--- a/Swift/QtUI/Roster/RosterModel.cpp
+++ b/Swift/QtUI/Roster/RosterModel.cpp
@@ -102,6 +102,8 @@ QVariant RosterModel::data(const QModelIndex& index, int role) const {
case PresenceIconRole: return getPresenceIcon(item);
case ChildCountRole: return getChildCount(item);
case IdleRole: return getIsIdle(item);
+ case JIDRole: return getJID(item);
+ case DisplayJIDRole: return getDisplayJID(item);
default: return QVariant();
}
}
@@ -181,6 +183,16 @@ QString RosterModel::getStatusText(RosterItem* item) const {
return P2QSTRING(contact->getStatusText());
}
+QString RosterModel::getJID(RosterItem* item) const {
+ ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
+ return contact ? P2QSTRING(contact->getJID().toString()) : QString();
+}
+
+QString RosterModel::getDisplayJID(RosterItem* item) const {
+ ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
+ return contact ? P2QSTRING(contact->getDisplayJID().toString()) : QString();
+}
+
QIcon RosterModel::getPresenceIcon(RosterItem* item) const {
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
if (!contact) return QIcon();
diff --git a/Swift/QtUI/Roster/RosterModel.h b/Swift/QtUI/Roster/RosterModel.h
index 7f6cdd2..2b05044 100644
--- a/Swift/QtUI/Roster/RosterModel.h
+++ b/Swift/QtUI/Roster/RosterModel.h
@@ -20,7 +20,9 @@ namespace Swift {
PresenceIconRole = Qt::UserRole + 2,
StatusShowTypeRole = Qt::UserRole + 3,
ChildCountRole = Qt::UserRole + 4,
- IdleRole = Qt::UserRole + 5
+ IdleRole = Qt::UserRole + 5,
+ JIDRole = Qt::UserRole + 6,
+ DisplayJIDRole = Qt::UserRole + 7
};
class QtTreeWidget;
@@ -52,6 +54,8 @@ namespace Swift {
QString getToolTip(RosterItem* item) const;
QString getAvatar(RosterItem* item) const;
QString getStatusText(RosterItem* item) const;
+ QString getJID(RosterItem* item) const;
+ QString getDisplayJID(RosterItem* item) const;
QIcon getPresenceIcon(RosterItem* item) const;
int getChildCount(RosterItem* item) const;
bool getIsIdle(RosterItem* item) const;