diff options
author | Kevin Smith <git@kismith.co.uk> | 2010-03-21 22:33:09 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2010-03-22 14:54:54 (GMT) |
commit | f5c2750f56c78d115bb9e8a7c5d50316da98b6d5 (patch) | |
tree | 661c761e7ebb526e1d71848c127046605e036729 | |
parent | 37a3ff6afe96c39bbf075d05da72e5f2c684dfa4 (diff) | |
download | swift-f5c2750f56c78d115bb9e8a7c5d50316da98b6d5.zip swift-f5c2750f56c78d115bb9e8a7c5d50316da98b6d5.tar.bz2 |
Lots of plumbing for event view.
This isn't ready yet, but clicking on a message in the event view will now cause the chat to pop up, and the plumbing is there for doing something with subscription requests - I just don't, yet.
30 files changed, 267 insertions, 101 deletions
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index 5009588..250f02d 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -7,6 +7,7 @@ #include "Swift/Controllers/Chat/ChatController.h" #include "Swift/Controllers/EventController.h" #include "Swift/Controllers/Chat/MUCController.h" +#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" #include "Swiften/Presence/PresenceSender.h" #include "Swiften/Elements/ChatState.h" @@ -15,7 +16,7 @@ namespace Swift { typedef std::pair<JID, ChatController*> JIDChatControllerPair; typedef std::pair<JID, MUCController*> JIDMUCControllerPair; -ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr<DiscoInfo> serverDiscoInfo, PresenceSender* presenceSender) : jid_(jid) { +ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr<DiscoInfo> serverDiscoInfo, PresenceSender* presenceSender, UIEventStream* uiEventStream) : jid_(jid) { eventController_ = eventController; stanzaChannel_ = stanzaChannel; iqRouter_ = iqRouter; @@ -26,7 +27,9 @@ ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRo avatarManager_ = NULL; serverDiscoInfo_ = serverDiscoInfo; presenceSender_ = presenceSender; + uiEventStream_ = uiEventStream; presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1, _2)); + uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1)); } ChatsManager::~ChatsManager() { @@ -39,6 +42,13 @@ ChatsManager::~ChatsManager() { } +void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) { + boost::shared_ptr<RequestChatUIEvent> chatEvent = boost::dynamic_pointer_cast<RequestChatUIEvent>(event); + if (chatEvent) { + handleChatRequest(chatEvent->getContact()); + } +} + /** * If a resource goes offline, release bound chatdialog to that resource. */ diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index dd80d95..04d9330 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -10,6 +10,7 @@ #include "Swiften/Elements/Presence.h" #include "Swiften/JID/JID.h" #include "Swiften/MUC/MUCRegistry.h" +#include "Swift/Controllers/UIEvents/UIEventStream.h" namespace Swift { class EventController; @@ -23,9 +24,10 @@ namespace Swift { class StanzaChannel; class IQRouter; class PresenceSender; + class ChatsManager : public MUCRegistry { public: - ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr<DiscoInfo> serverDiscoInfo, PresenceSender* presenceSender); + ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr<DiscoInfo> serverDiscoInfo, PresenceSender* presenceSender, UIEventStream* uiEventStream); ~ChatsManager(); void setAvatarManager(AvatarManager* avatarManager); void setEnabled(bool enabled); @@ -36,6 +38,7 @@ namespace Swift { private: void rebindControllerJID(const JID& from, const JID& to); void handlePresenceChange(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> lastPresence); + void handleUIEvent(boost::shared_ptr<UIEvent> event); ChatController* getChatController(const JID &contact); virtual bool isMUC(const JID& muc) const; @@ -51,6 +54,7 @@ namespace Swift { PresenceOracle* presenceOracle_; AvatarManager* avatarManager_; PresenceSender* presenceSender_; + UIEventStream* uiEventStream_; boost::shared_ptr<DiscoInfo> serverDiscoInfo_; }; } diff --git a/Swift/Controllers/EventController.cpp b/Swift/Controllers/EventController.cpp index 3849aa7..71ccaeb 100644 --- a/Swift/Controllers/EventController.cpp +++ b/Swift/Controllers/EventController.cpp @@ -3,23 +3,26 @@ #include <boost/bind.hpp> #include <algorithm> +#include "Swiften/Events/MessageEvent.h" +#include "Swiften/Events/SubscriptionRequestEvent.h" namespace Swift { EventController::EventController() { } -void EventController::handleIncomingEvent(boost::shared_ptr<Event> sourceEvent) { +void EventController::handleIncomingEvent(boost::shared_ptr<StanzaEvent> sourceEvent) { boost::shared_ptr<MessageEvent> messageEvent = boost::dynamic_pointer_cast<MessageEvent>(sourceEvent); - if (messageEvent && messageEvent->isReadable()) { + boost::shared_ptr<SubscriptionRequestEvent> subscriptionEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(sourceEvent); + if ((messageEvent && messageEvent->isReadable()) || subscriptionEvent) { events_.push_back(sourceEvent); - messageEvent->onConclusion.connect(boost::bind(&EventController::handleEventConcluded, this, messageEvent)); + sourceEvent->onConclusion.connect(boost::bind(&EventController::handleEventConcluded, this, sourceEvent)); onEventQueueLengthChange(events_.size()); onEventQueueEventAdded(sourceEvent); } } -void EventController::handleEventConcluded(boost::shared_ptr<Event> event) { +void EventController::handleEventConcluded(boost::shared_ptr<StanzaEvent> event) { events_.erase(std::remove(events_.begin(), events_.end(), event), events_.end()); onEventQueueLengthChange(events_.size()); } diff --git a/Swift/Controllers/EventController.h b/Swift/Controllers/EventController.h index 482be58..1f4051c 100644 --- a/Swift/Controllers/EventController.h +++ b/Swift/Controllers/EventController.h @@ -6,20 +6,20 @@ #include <boost/shared_ptr.hpp> #include <vector> -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h" #include "Swiften/Events/MessageEvent.h" namespace Swift { class EventController { public: EventController(); - void handleIncomingEvent(boost::shared_ptr<Event> sourceEvent); + void handleIncomingEvent(boost::shared_ptr<StanzaEvent> sourceEvent); boost::signal<void (int)> onEventQueueLengthChange; - boost::signal<void (boost::shared_ptr<Event>)> onEventQueueEventAdded; + boost::signal<void (boost::shared_ptr<StanzaEvent>)> onEventQueueEventAdded; private: - void handleEventConcluded(boost::shared_ptr<Event> event); - std::vector<boost::shared_ptr<Event> > events_; + void handleEventConcluded(boost::shared_ptr<StanzaEvent> event); + std::vector<boost::shared_ptr<StanzaEvent> > events_; }; } #endif diff --git a/Swift/Controllers/EventWindowController.cpp b/Swift/Controllers/EventWindowController.cpp index a6611fc..0f91db7 100644 --- a/Swift/Controllers/EventWindowController.cpp +++ b/Swift/Controllers/EventWindowController.cpp @@ -15,12 +15,13 @@ EventWindowController::~EventWindowController() { delete window_; } -void EventWindowController::handleEventQueueEventAdded(boost::shared_ptr<Event> event) { +void EventWindowController::handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event) { event->onConclusion.connect(boost::bind(&EventWindowController::handleEventConcluded, this, event)); + fprintf(stderr, "Adding to ewc\n"); window_->addEvent(event, true); } -void EventWindowController::handleEventConcluded(boost::shared_ptr<Event> event) { +void EventWindowController::handleEventConcluded(boost::shared_ptr<StanzaEvent> event) { window_->removeEvent(event); window_->addEvent(event, false); } diff --git a/Swift/Controllers/EventWindowController.h b/Swift/Controllers/EventWindowController.h index c612265..7c58be1 100644 --- a/Swift/Controllers/EventWindowController.h +++ b/Swift/Controllers/EventWindowController.h @@ -12,8 +12,8 @@ namespace Swift { EventWindowController(EventController* eventController, EventWindowFactory* windowFactory); ~EventWindowController(); private: - void handleEventQueueEventAdded(boost::shared_ptr<Event> event); - void handleEventConcluded(boost::shared_ptr<Event> event); + void handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event); + void handleEventConcluded(boost::shared_ptr<StanzaEvent> event); EventController* eventController_; EventWindowFactory* windowFactory_; diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index d013f5f..310d28f 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -134,10 +134,8 @@ void MainController::handleConnected() { presenceOracle_ = new PresenceOracle(client_); nickResolver_ = new NickResolver(xmppRoster_); lastSentPresence_ = boost::shared_ptr<Presence>(); - - client_->onPresenceReceived.connect(boost::bind(&MainController::handleIncomingPresence, this, _1)); - - chatsManager_ = new ChatsManager(jid_, client_, client_, eventController_, chatWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_); + + chatsManager_ = new ChatsManager(jid_, client_, client_, eventController_, chatWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_, uiEventStream_); client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1)); avatarManager_ = new AvatarManager(client_, client_, avatarStorage_, chatsManager_); @@ -145,7 +143,7 @@ void MainController::handleConnected() { chatsManager_->setAvatarManager(avatarManager_); - rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_); + rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, eventController_, uiEventStream_); rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2)); rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this)); rosterController_->onStartChatRequest.connect(boost::bind(&ChatsManager::handleChatRequest, chatsManager_, _1)); @@ -254,11 +252,6 @@ void MainController::handleInputIdleChanged(bool idle) { } } -void MainController::handleIncomingPresence(boost::shared_ptr<Presence> presence) { - //FIXME: subscribe, subscribed - rosterController_->handleIncomingPresence(presence); -} - void MainController::handleLoginRequest(const String &username, const String &password, const String& certificateFile, bool remember) { loginWindow_->setMessage(""); ProfileSettingsProvider* profileSettings = new ProfileSettingsProvider(username, settings_); diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index 63be284..387fcb6 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -63,7 +63,6 @@ namespace Swift { void handleConnected(); void handleLoginRequest(const String& username, const String& password, const String& certificateFile, bool remember); void handleCancelLoginRequest(); - void handleIncomingPresence(boost::shared_ptr<Presence> presence); void handleChangeStatusRequest(StatusShow::Type show, const String &statusText); void handleError(const ClientError& error); void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>, const boost::optional<ErrorPayload>&); diff --git a/Swift/Controllers/MainWindowFactory.h b/Swift/Controllers/MainWindowFactory.h index cf5a061..ce612b3 100644 --- a/Swift/Controllers/MainWindowFactory.h +++ b/Swift/Controllers/MainWindowFactory.h @@ -2,6 +2,7 @@ #define SWIFTEN_MainWindowFactory_H #include "Swiften/JID/JID.h" +#include "Swift/Controllers/UIEvents/UIEventStream.h" namespace Swift { class MainWindow; @@ -12,7 +13,7 @@ namespace Swift { /** * Transfers ownership of result. */ - virtual MainWindow* createMainWindow() = 0; + virtual MainWindow* createMainWindow(UIEventStream* eventStream) = 0; }; } diff --git a/Swift/Controllers/RosterController.cpp b/Swift/Controllers/RosterController.cpp index df3453d..4c55ea8 100644 --- a/Swift/Controllers/RosterController.cpp +++ b/Swift/Controllers/RosterController.cpp @@ -7,7 +7,9 @@ #include "Swift/Controllers/MainWindowFactory.h" #include "Swift/Controllers/NickResolver.h" #include "Swiften/Queries/Requests/GetRosterRequest.h" -#include "Swiften/EventLoop/MainEventLoop.h" +#include "Swiften/Events/SubscriptionRequestEvent.h" +#include "Swiften/Presence/PresenceOracle.h" +#include "Swift/Controllers/EventController.h" #include "Swiften/Roster/Roster.h" #include "Swiften/Roster/SetPresence.h" #include "Swiften/Roster/AppearOffline.h" @@ -23,9 +25,10 @@ namespace Swift { /** * The controller does not gain ownership of these parameters. */ -RosterController::RosterController(const JID& jid, boost::shared_ptr<XMPPRoster> xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver) - : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), treeWidgetFactory_(treeWidgetFactory), mainWindow_(mainWindowFactory_->createMainWindow()), roster_(new Roster(mainWindow_->getTreeWidget(), treeWidgetFactory_)), offlineFilter_(new OfflineRosterFilter()) { - +RosterController::RosterController(const JID& jid, boost::shared_ptr<XMPPRoster> xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, EventController* eventController, UIEventStream* uiEventStream) + : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), treeWidgetFactory_(treeWidgetFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster(mainWindow_->getTreeWidget(), treeWidgetFactory_)), offlineFilter_(new OfflineRosterFilter()) { + presenceOracle_ = presenceOracle; + eventController_ = eventController; roster_->addFilter(offlineFilter_); mainWindow_->onJoinMUCRequest.connect(boost::bind(&RosterController::handleJoinMUCRequest, this, _1, _2)); @@ -36,6 +39,8 @@ RosterController::RosterController(const JID& jid, boost::shared_ptr<XMPPRoster> xmppRoster_->onJIDAdded.connect(boost::bind(&RosterController::handleOnJIDAdded, this, _1)); xmppRoster_->onJIDUpdated.connect(boost::bind(&RosterController::handleOnJIDUpdated, this, _1, _2, _3)); xmppRoster_->onJIDRemoved.connect(boost::bind(&RosterController::handleOnJIDRemoved, this, _1)); + presenceOracle_->onPresenceSubscriptionRequest.connect(boost::bind(&RosterController::handleSubscriptionRequest, this, _1, _2)); + presenceOracle_->onPresenceChange.connect(boost::bind(&RosterController::handleIncomingPresence, this, _1, _2)); avatarManager_ = NULL; setAvatarManager(avatarManager); setNickResolver(nickResolver); @@ -132,8 +137,24 @@ void RosterController::handleOnJIDUpdated(const JID& jid, const String& oldName, } -void RosterController::handleIncomingPresence(boost::shared_ptr<Presence> presence) { - roster_->applyOnItems(SetPresence(presence)); +void RosterController::handleIncomingPresence(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> /*oldPresence*/) { + roster_->applyOnItems(SetPresence(newPresence)); +} + +void RosterController::handleSubscriptionRequest(const JID& jid, const String& message) { + SubscriptionRequestEvent* eventPointer = new SubscriptionRequestEvent(jid, message); + eventPointer->onAccept.connect(boost::bind(&RosterController::handleSubscriptionRequestAccepted, this, eventPointer)); + eventPointer->onDecline.connect(boost::bind(&RosterController::handleSubscriptionRequestDeclined, this, eventPointer)); + boost::shared_ptr<StanzaEvent> event(eventPointer); + eventController_->handleIncomingEvent(event); +} + +void RosterController::handleSubscriptionRequestAccepted(SubscriptionRequestEvent* event) { + //FIXME: do something +} + +void RosterController::handleSubscriptionRequestDeclined(SubscriptionRequestEvent* event) { + //FIXME: do something } void RosterController::handleAvatarChanged(const JID& jid, const String&) { diff --git a/Swift/Controllers/RosterController.h b/Swift/Controllers/RosterController.h index f3d96e1..cef0e48 100644 --- a/Swift/Controllers/RosterController.h +++ b/Swift/Controllers/RosterController.h @@ -19,10 +19,14 @@ namespace Swift { class TreeWidgetFactory; class OfflineRosterFilter; class NickResolver; + class PresenceOracle; + class EventController; + class SubscriptionRequestEvent; + class UIEventStream; class RosterController { public: - RosterController(const JID& jid, boost::shared_ptr<XMPPRoster> xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver); + RosterController(const JID& jid, boost::shared_ptr<XMPPRoster> xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, EventController* eventController, UIEventStream* uiEventStream); ~RosterController(); void showRosterWindow(); MainWindow* getWindow() {return mainWindow_;}; @@ -32,7 +36,6 @@ namespace Swift { boost::signal<void (const JID&, const String&)> onJoinMUCRequest; boost::signal<void (StatusShow::Type, const String&)> onChangeStatusRequest; boost::signal<void ()> onSignOutRequest; - void handleIncomingPresence(boost::shared_ptr<Presence> presence); void handleAvatarChanged(const JID& jid, const String& hash); void setEnabled(bool enabled); private: @@ -44,6 +47,10 @@ namespace Swift { void handleUserAction(boost::shared_ptr<UserRosterAction> action); void handleChangeStatusRequest(StatusShow::Type show, const String &statusText); void handleShowOfflineToggled(bool state); + void handleIncomingPresence(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> oldPresence); + void handleSubscriptionRequest(const JID& jid, const String& message); + void handleSubscriptionRequestAccepted(SubscriptionRequestEvent* event); + void handleSubscriptionRequestDeclined(SubscriptionRequestEvent* event); JID myJID_; boost::shared_ptr<XMPPRoster> xmppRoster_; MainWindowFactory* mainWindowFactory_; @@ -53,6 +60,8 @@ namespace Swift { OfflineRosterFilter* offlineFilter_; AvatarManager* avatarManager_; NickResolver* nickResolver_; + PresenceOracle* presenceOracle_; + EventController* eventController_; }; } #endif diff --git a/Swift/Controllers/SoundEventController.cpp b/Swift/Controllers/SoundEventController.cpp index 392b4e9..456de44 100644 --- a/Swift/Controllers/SoundEventController.cpp +++ b/Swift/Controllers/SoundEventController.cpp @@ -14,7 +14,7 @@ SoundEventController::SoundEventController(EventController* eventController, Sou playSounds_ = playSounds; } -void SoundEventController::handleEventQueueEventAdded(boost::shared_ptr<Event>) { +void SoundEventController::handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent>) { if (playSounds_) soundPlayer_->playSound(SoundPlayer::MessageReceived); } diff --git a/Swift/Controllers/SoundEventController.h b/Swift/Controllers/SoundEventController.h index 777e55f..07ac667 100644 --- a/Swift/Controllers/SoundEventController.h +++ b/Swift/Controllers/SoundEventController.h @@ -2,7 +2,7 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h" namespace Swift { class EventController; @@ -12,7 +12,7 @@ namespace Swift { SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, bool playSounds); void setPlaySounds(bool playSounds); private: - void handleEventQueueEventAdded(boost::shared_ptr<Event> event); + void handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event); EventController* eventController_; SoundPlayer* soundPlayer_; bool playSounds_; diff --git a/Swift/Controllers/UIInterfaces/EventWindow.h b/Swift/Controllers/UIInterfaces/EventWindow.h index 95bd7dd..b85840b 100644 --- a/Swift/Controllers/UIInterfaces/EventWindow.h +++ b/Swift/Controllers/UIInterfaces/EventWindow.h @@ -1,13 +1,13 @@ #pragma once #include "boost/shared_ptr.hpp" -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h" namespace Swift { class EventWindow { public: virtual ~EventWindow() {}; - virtual void addEvent(boost::shared_ptr<Event> event, bool active) = 0; - virtual void removeEvent(boost::shared_ptr<Event> event) = 0; + virtual void addEvent(boost::shared_ptr<StanzaEvent> event, bool active) = 0; + virtual void removeEvent(boost::shared_ptr<StanzaEvent> event) = 0; }; } diff --git a/Swift/Controllers/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/UnitTest/RosterControllerTest.cpp index 0296cdc..67884d0 100644 --- a/Swift/Controllers/UnitTest/RosterControllerTest.cpp +++ b/Swift/Controllers/UnitTest/RosterControllerTest.cpp @@ -8,8 +8,11 @@ // #include "Swiften/Elements/RosterItemPayload.h" // #include "Swiften/Elements/RosterPayload.h" #include "Swiften/Queries/DummyIQChannel.h" +#include "Swiften/Client/DummyStanzaChannel.h" #include "Swiften/Queries/IQRouter.h" #include "Swiften/Roster/XMPPRoster.h" +#include "Swift/Controllers/EventController.h" +#include "Swiften/Presence/PresenceOracle.h" #include "Swift/Controllers/NickResolver.h" using namespace Swift; @@ -30,10 +33,13 @@ class RosterControllerTest : public CppUnit::TestFixture treeWidgetFactory_ = new MockTreeWidgetFactory(); mainWindowFactory_ = new MockMainWindowFactory(treeWidgetFactory_); nickResolver_ = new NickResolver(xmppRoster_); - rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_); - channel_ = new DummyIQChannel(); router_ = new IQRouter(channel_); + stanzaChannel_ = new DummyStanzaChannel(); + presenceOracle_ = new PresenceOracle(stanzaChannel_); + eventController_ = new EventController(); + rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, eventController_); + }; @@ -45,6 +51,9 @@ class RosterControllerTest : public CppUnit::TestFixture delete avatarManager_; delete channel_; delete router_; + delete eventController_; + delete presenceOracle_; + delete stanzaChannel_; }; void testAdd() { @@ -66,6 +75,9 @@ class RosterControllerTest : public CppUnit::TestFixture NickResolver* nickResolver_; RosterController* rosterController_; DummyIQChannel* channel_; + DummyStanzaChannel* stanzaChannel_; IQRouter* router_; + PresenceOracle* presenceOracle_; + EventController* eventController_; }; diff --git a/Swift/QtUI/EventViewer/EventModel.cpp b/Swift/QtUI/EventViewer/EventModel.cpp index f75fe74..902004b 100644 --- a/Swift/QtUI/EventViewer/EventModel.cpp +++ b/Swift/QtUI/EventViewer/EventModel.cpp @@ -16,14 +16,16 @@ EventModel::~EventModel() { } } +QtEvent* EventModel::getItem(int row) const { + return row < activeEvents_.size() ? activeEvents_[row] : inactiveEvents_[row - activeEvents_.size()]; +} + QVariant EventModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } - int row = index.row(); - QtEvent* item = index.row() < activeEvents_.size() ? activeEvents_[row] : inactiveEvents_[row - activeEvents_.size()]; + QtEvent* item = getItem(index.row()); QVariant result = item ? item->data(role) : QVariant(); - qDebug() << "Asked for data of " << index << ", " << role << " returning " << result; return result; } @@ -33,8 +35,7 @@ int EventModel::rowCount(const QModelIndex& parent) const { return count; } -void EventModel::addEvent(boost::shared_ptr<Event> event, bool active) { - qDebug() << " Adding Event"; +void EventModel::addEvent(boost::shared_ptr<StanzaEvent> event, bool active) { if (active) { activeEvents_.push_front(new QtEvent(event, active)); emit dataChanged(createIndex(0, 0), createIndex(1, 0)); @@ -48,7 +49,7 @@ void EventModel::addEvent(boost::shared_ptr<Event> event, bool active) { emit layoutChanged(); } -void EventModel::removeEvent(boost::shared_ptr<Event> event) { +void EventModel::removeEvent(boost::shared_ptr<StanzaEvent> event) { for (int i = inactiveEvents_.size() - 1; i >= 0; i--) { if (event == inactiveEvents_[i]->getEvent()) { inactiveEvents_.removeAt(i); diff --git a/Swift/QtUI/EventViewer/EventModel.h b/Swift/QtUI/EventViewer/EventModel.h index bc54cf4..7882c6b 100644 --- a/Swift/QtUI/EventViewer/EventModel.h +++ b/Swift/QtUI/EventViewer/EventModel.h @@ -5,7 +5,7 @@ #include <QAbstractListModel> #include <QList> -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h" #include "Swift/QtUI/EventViewer/QtEvent.h" @@ -15,10 +15,11 @@ Q_OBJECT public: EventModel(); ~EventModel(); - void addEvent(boost::shared_ptr<Event> event, bool active); - void removeEvent(boost::shared_ptr<Event> event); + void addEvent(boost::shared_ptr<StanzaEvent> event, bool active); + void removeEvent(boost::shared_ptr<StanzaEvent> event); QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; int rowCount(const QModelIndex& parent = QModelIndex()) const; + QtEvent* getItem(int row) const; private: QList<QtEvent*> activeEvents_; QList<QtEvent*> inactiveEvents_; diff --git a/Swift/QtUI/EventViewer/QtEvent.cpp b/Swift/QtUI/EventViewer/QtEvent.cpp index 2dc1fb0..3aae213 100644 --- a/Swift/QtUI/EventViewer/QtEvent.cpp +++ b/Swift/QtUI/EventViewer/QtEvent.cpp @@ -1,22 +1,23 @@ #include "Swift/QtUI/EventViewer/QtEvent.h" #include "Swiften/Events/MessageEvent.h" +#include "Swiften/Events/SubscriptionRequestEvent.h" #include "Swift/QtUI/QtSwiftUtil.h" namespace Swift { -QtEvent::QtEvent(boost::shared_ptr<Event> event, bool active) : event_(event) { +QtEvent::QtEvent(boost::shared_ptr<StanzaEvent> event, bool active) : event_(event) { active_ = active; } QVariant QtEvent::data(int role) { switch (role) { + case Qt::ToolTipRole: case Qt::DisplayRole: return QVariant(text()); case Qt::TextColorRole: return active_ ? Qt::black : Qt::darkGray; case Qt::BackgroundColorRole: return active_ ? Qt::white : Qt::lightGray; - /*case Qt::ToolTipRole: return isContact() ? toolTipString() : QVariant(); - case StatusTextRole: return statusText_; + /*case StatusTextRole: return statusText_; case AvatarRole: return avatar_; case PresenceIconRole: return getPresenceIcon();*/ default: return QVariant(); @@ -25,7 +26,16 @@ QVariant QtEvent::data(int role) { QString QtEvent::text() { boost::shared_ptr<MessageEvent> messageEvent = boost::dynamic_pointer_cast<MessageEvent>(event_); - return messageEvent ? P2QSTRING(messageEvent->getStanza()->getBody()) : "Bob: "; + if (messageEvent) { + return P2QSTRING(messageEvent->getStanza()->getBody()); + } + boost::shared_ptr<SubscriptionRequestEvent> subscriptionRequestEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(event_); + if (subscriptionRequestEvent) { + String reason = subscriptionRequestEvent->getReason(); + String message = subscriptionRequestEvent->getJID().toBare().toString() + " would like to add you to their roster" + (reason.isEmpty() ? "." : ", saying '" + reason + "'."); + return P2QSTRING(message); + } + return ""; } } diff --git a/Swift/QtUI/EventViewer/QtEvent.h b/Swift/QtUI/EventViewer/QtEvent.h index 7083c6e..6dec858 100644 --- a/Swift/QtUI/EventViewer/QtEvent.h +++ b/Swift/QtUI/EventViewer/QtEvent.h @@ -4,17 +4,17 @@ #include <QVariant> -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h" namespace Swift { class QtEvent { public: - QtEvent(boost::shared_ptr<Event> event, bool active); + QtEvent(boost::shared_ptr<StanzaEvent> event, bool active); QVariant data(int role); - boost::shared_ptr<Event> getEvent() { return event_; }; + boost::shared_ptr<StanzaEvent> getEvent() { return event_; }; private: QString text(); - boost::shared_ptr<Event> event_; + boost::shared_ptr<StanzaEvent> event_; bool active_; }; } diff --git a/Swift/QtUI/EventViewer/QtEventWindow.cpp b/Swift/QtUI/EventViewer/QtEventWindow.cpp index fda957d..91eb2c1 100644 --- a/Swift/QtUI/EventViewer/QtEventWindow.cpp +++ b/Swift/QtUI/EventViewer/QtEventWindow.cpp @@ -1,10 +1,17 @@ #include "Swift/QtUI/EventViewer/QtEventWindow.h" +#include <qdebug> + +#include "Swiften/Events/MessageEvent.h" +#include "Swiften/Events/SubscriptionRequestEvent.h" +#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" + #include "Swiften/Base/Platform.h" namespace Swift { -QtEventWindow::QtEventWindow(QWidget* parent) : QTreeView(parent) { +QtEventWindow::QtEventWindow(UIEventStream* eventStream, QWidget* parent) : QTreeView(parent) { + eventStream_ = eventStream; model_ = new EventModel(); setModel(model_); delegate_ = new EventDelegate(); @@ -16,6 +23,7 @@ QtEventWindow::QtEventWindow(QWidget* parent) : QTreeView(parent) { setAnimated(true); setIndentation(0); setRootIsDecorated(true); + connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleItemActivated(const QModelIndex&))); } QtEventWindow::~QtEventWindow() { @@ -23,11 +31,27 @@ QtEventWindow::~QtEventWindow() { delete delegate_; } -void QtEventWindow::addEvent(boost::shared_ptr<Event> event, bool active) { +void QtEventWindow::handleItemActivated(const QModelIndex& item) { + QtEvent* event = model_->getItem(item.row()); + boost::shared_ptr<MessageEvent> messageEvent = boost::dynamic_pointer_cast<MessageEvent>(event->getEvent()); + boost::shared_ptr<SubscriptionRequestEvent> subscriptionEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(event->getEvent()); + + if (messageEvent) { + eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(messageEvent->getStanza()->getFrom()))); + } else if (subscriptionEvent) { + printf("Subscription activated\n"); + //FIXME: do something + } else { + qWarning() << "Trying to activate an unexpected event"; + } + +} + +void QtEventWindow::addEvent(boost::shared_ptr<StanzaEvent> event, bool active) { model_->addEvent(event, active); } -void QtEventWindow::removeEvent(boost::shared_ptr<Event> event) { +void QtEventWindow::removeEvent(boost::shared_ptr<StanzaEvent> event) { model_->removeEvent(event); } diff --git a/Swift/QtUI/EventViewer/QtEventWindow.h b/Swift/QtUI/EventViewer/QtEventWindow.h index cab50ef..283ba52 100644 --- a/Swift/QtUI/EventViewer/QtEventWindow.h +++ b/Swift/QtUI/EventViewer/QtEventWindow.h @@ -5,6 +5,7 @@ #include <QTreeView> #include "Swift/Controllers/UIInterfaces/EventWindow.h" +#include "Swift/Controllers/UIEvents/UIEventStream.h" #include "Swift/QtUI/EventViewer/EventView.h" #include "Swift/QtUI/EventViewer/EventModel.h" #include "Swift/QtUI/EventViewer/EventDelegate.h" @@ -13,13 +14,16 @@ namespace Swift { class QtEventWindow : public QTreeView, public EventWindow { Q_OBJECT public: - QtEventWindow(QWidget* parent = 0); + QtEventWindow(UIEventStream* eventStream, QWidget* parent = 0); ~QtEventWindow(); - void addEvent(boost::shared_ptr<Event> event, bool active); - void removeEvent(boost::shared_ptr<Event> event); + void addEvent(boost::shared_ptr<StanzaEvent> event, bool active); + void removeEvent(boost::shared_ptr<StanzaEvent> event); + private slots: + void handleItemActivated(const QModelIndex& item); private: EventModel* model_; EventDelegate* delegate_; + UIEventStream* eventStream_; }; } diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp index 10dcfa6..ebafaff 100644 --- a/Swift/QtUI/QtMainWindow.cpp +++ b/Swift/QtUI/QtMainWindow.cpp @@ -19,7 +19,8 @@ namespace Swift { -QtMainWindow::QtMainWindow(QtTreeWidgetFactory *treeWidgetFactory) : QWidget() { +QtMainWindow::QtMainWindow(UIEventStream* uiEventStream, QtTreeWidgetFactory *treeWidgetFactory) : QWidget() { + uiEventStream_ = uiEventStream; setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this); mainLayout->setContentsMargins(0,0,0,0); @@ -45,7 +46,7 @@ QtMainWindow::QtMainWindow(QtTreeWidgetFactory *treeWidgetFactory) : QWidget() { tabs_->addTab(contactsTabWidget_, "Contacts"); - eventWindow_ = new QtEventWindow(); + eventWindow_ = new QtEventWindow(uiEventStream_); tabs_->addTab(eventWindow_, "Events"); diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h index ce3272a..1c862e6 100644 --- a/Swift/QtUI/QtMainWindow.h +++ b/Swift/QtUI/QtMainWindow.h @@ -21,11 +21,12 @@ namespace Swift { class QtTreeWidget; class QtTreeWidgetFactory; class TreeWidget; + class UIEventStream; class QtMainWindow : public QWidget, public MainWindow { Q_OBJECT public: - QtMainWindow(QtTreeWidgetFactory *treeWidgetFactory); + QtMainWindow(UIEventStream* eventStream, QtTreeWidgetFactory *treeWidgetFactory); TreeWidget* getTreeWidget(); std::vector<QMenu*> getMenus() {return menus_;} void setMyName(const String& name); @@ -53,6 +54,7 @@ namespace Swift { QWidget* contactsTabWidget_; QWidget* eventsTabWidget_; QtEventWindow* eventWindow_; + UIEventStream* uiEventStream_; }; } diff --git a/Swift/QtUI/QtMainWindowFactory.cpp b/Swift/QtUI/QtMainWindowFactory.cpp index 0794780..dc1949e 100644 --- a/Swift/QtUI/QtMainWindowFactory.cpp +++ b/Swift/QtUI/QtMainWindowFactory.cpp @@ -8,8 +8,8 @@ QtMainWindowFactory::QtMainWindowFactory(QtTreeWidgetFactory *treeWidgetFactory) lastWindow_ = NULL; } -MainWindow* QtMainWindowFactory::createMainWindow() { - QtMainWindow* window = new QtMainWindow(treeWidgetFactory_); +MainWindow* QtMainWindowFactory::createMainWindow(UIEventStream* eventStream) { + QtMainWindow* window = new QtMainWindow(eventStream, treeWidgetFactory_); lastWindow_ = window; return window; } diff --git a/Swift/QtUI/QtMainWindowFactory.h b/Swift/QtUI/QtMainWindowFactory.h index bd8342c..8567efd 100644 --- a/Swift/QtUI/QtMainWindowFactory.h +++ b/Swift/QtUI/QtMainWindowFactory.h @@ -8,7 +8,7 @@ namespace Swift { class QtMainWindowFactory : public MainWindowFactory{ public: QtMainWindowFactory(QtTreeWidgetFactory *treeWidgetFactory); - MainWindow* createMainWindow(); + MainWindow* createMainWindow(UIEventStream* eventStream); MainWindow* getLastCreatedWindow(); private: QtTreeWidgetFactory *treeWidgetFactory_; diff --git a/Swiften/Events/MessageEvent.h b/Swiften/Events/MessageEvent.h index 0adfa82..1f71493 100644 --- a/Swiften/Events/MessageEvent.h +++ b/Swiften/Events/MessageEvent.h @@ -6,11 +6,11 @@ #include <boost/signals.hpp> #include <boost/shared_ptr.hpp> -#include "Swiften/Events/Event.h" +#include "Swiften/Events/StanzaEvent.h" #include "Swiften/Elements/Message.h" namespace Swift { - class MessageEvent : public Event { + class MessageEvent : public StanzaEvent { public: MessageEvent(boost::shared_ptr<Message> stanza) : stanza_(stanza){}; virtual ~MessageEvent(){}; diff --git a/Swiften/Events/Event.h b/Swiften/Events/StanzaEvent.h index b4a71f6..adef112 100644 --- a/Swiften/Events/Event.h +++ b/Swiften/Events/StanzaEvent.h @@ -4,10 +4,10 @@ #include <boost/shared_ptr.hpp> namespace Swift { - class Event { + class StanzaEvent { public: - Event(){}; - virtual ~Event() {}; + StanzaEvent(){}; + virtual ~StanzaEvent() {}; boost::signal<void()> onConclusion; }; } diff --git a/Swiften/Events/SubscriptionRequestEvent.h b/Swiften/Events/SubscriptionRequestEvent.h new file mode 100644 index 0000000..fe41df7 --- /dev/null +++ b/Swiften/Events/SubscriptionRequestEvent.h @@ -0,0 +1,36 @@ +#pragma once + +#include <cassert> + +#include <boost/signals.hpp> +#include <boost/shared_ptr.hpp> + +#include "Swiften/Events/StanzaEvent.h" +#include "Swiften/Base/String.h" +#include "Swiften/JID/JID.h" + +namespace Swift { + class SubscriptionRequestEvent : public StanzaEvent { + public: + SubscriptionRequestEvent(const JID& jid, const String& reason) : jid_(jid), reason_(reason){}; + virtual ~SubscriptionRequestEvent(){}; + const JID& getJID() const {return jid_;}; + const String& getReason() const {return reason_;}; + boost::signal<void()> onAccept; + boost::signal<void()> onDecline; + void accept() { + onAccept(); + onConclusion(); + } + + void decline() { + onDecline(); + onConclusion(); + } + + private: + JID jid_; + String reason_; + }; +} + diff --git a/Swiften/Presence/PresenceOracle.cpp b/Swiften/Presence/PresenceOracle.cpp index af98510..f1e6adb 100644 --- a/Swiften/Presence/PresenceOracle.cpp +++ b/Swiften/Presence/PresenceOracle.cpp @@ -13,17 +13,23 @@ PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel) { void PresenceOracle::handleIncomingPresence(boost::shared_ptr<Presence> presence) { JID bareJID = JID(presence->getFrom().toBare()); - std::map<JID, boost::shared_ptr<Presence> > jidMap = entries_[bareJID]; - boost::shared_ptr<Presence> last; - foreach(JIDPresencePair pair, jidMap) { - if (pair.first == presence->getFrom()) { - last = pair.second; - break; + + if (presence->getType() == Presence::Subscribe) { + fprintf(stderr, "rarr, sub\n"); + onPresenceSubscriptionRequest(bareJID, presence->getStatus()); + } else { + std::map<JID, boost::shared_ptr<Presence> > jidMap = entries_[bareJID]; + boost::shared_ptr<Presence> last; + foreach(JIDPresencePair pair, jidMap) { + if (pair.first == presence->getFrom()) { + last = pair.second; + break; + } } + jidMap[presence->getFrom()] = presence; + entries_[bareJID] = jidMap; + onPresenceChange(presence, last); } - jidMap[presence->getFrom()] = presence; - entries_[bareJID] = jidMap; - onPresenceChange(presence, last); } } diff --git a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp index e6f56b2..2c9c526 100644 --- a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp +++ b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp @@ -15,11 +15,18 @@ class PresencePointerPair { boost::shared_ptr<Presence> two; }; +class SubscriptionRequestInfo { + public: + boost::optional<JID> jid; + boost::optional<String> reason; +}; + class PresenceOracleTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(PresenceOracleTest); CPPUNIT_TEST(testFirstPresence); CPPUNIT_TEST(testSecondPresence); + CPPUNIT_TEST(testSubscriptionRequest); CPPUNIT_TEST_SUITE_END(); private: @@ -37,11 +44,11 @@ class PresenceOracleTest : public CppUnit::TestFixture CPPUNIT_ASSERT_EQUAL(newPresence, out->one); } - void handlePresenceSubscriptionRequest(const JID& jid, const String& reason, boost::optional<JID>& outJID, boost::optional<String>& outReason) { - CPPUNIT_ASSERT(!outJID); - CPPUNIT_ASSERT(!outReason); - outJID = jid; - outReason = reason; + void handlePresenceSubscriptionRequest(const JID& jid, const String& reason, SubscriptionRequestInfo* info) { + CPPUNIT_ASSERT(!info->jid); + CPPUNIT_ASSERT(!info->reason); + info->jid = jid; + info->reason = reason; } void setUp() { @@ -58,15 +65,14 @@ class PresenceOracleTest : public CppUnit::TestFixture PresencePointerPair out; oracle_->onPresenceChange.connect(boost::bind(&PresenceOracleTest::handlePresenceChange, this, _1, _2, &out)); - boost::optional<JID> jid; - boost::optional<String> reason; - oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2, jid, reason)); + SubscriptionRequestInfo info; + oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2, &info)); boost::shared_ptr<Presence> sentPresence(new Presence("blarb")); stanzaChannel_->onPresenceReceived(sentPresence); - CPPUNIT_ASSERT(!jid); - CPPUNIT_ASSERT(!reason); + CPPUNIT_ASSERT(!info.jid); + CPPUNIT_ASSERT(!info.reason); CPPUNIT_ASSERT(out.two.get() == NULL); CPPUNIT_ASSERT_EQUAL(sentPresence, out.one); } @@ -80,19 +86,41 @@ class PresenceOracleTest : public CppUnit::TestFixture CPPUNIT_ASSERT_EQUAL(sentPresence1, out.one); out.one = boost::shared_ptr<Presence>(); - boost::optional<JID> jid; - boost::optional<String> reason; - oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2, jid, reason)); + SubscriptionRequestInfo info; + oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2, &info)); boost::shared_ptr<Presence> sentPresence2(new Presence("test2")); stanzaChannel_->onPresenceReceived(sentPresence2); - CPPUNIT_ASSERT(!jid); - CPPUNIT_ASSERT(!reason); + CPPUNIT_ASSERT(!info.jid); + CPPUNIT_ASSERT(!info.reason); CPPUNIT_ASSERT_EQUAL(sentPresence1, out.two); CPPUNIT_ASSERT_EQUAL(sentPresence2, out.one); } + void testSubscriptionRequest() { + PresencePointerPair out; + oracle_->onPresenceChange.connect(boost::bind(&PresenceOracleTest::handlePresenceChange, this, _1, _2, &out)); + SubscriptionRequestInfo info; + oracle_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2, &info)); + + String reasonText = "Because I want to"; + JID sentJID = JID("me@example.com"); + + boost::shared_ptr<Presence> sentPresence(new Presence()); + sentPresence->setType(Presence::Subscribe); + sentPresence->setFrom(sentJID); + sentPresence->setStatus(reasonText); + stanzaChannel_->onPresenceReceived(sentPresence); + + CPPUNIT_ASSERT(info.jid); + CPPUNIT_ASSERT(info.reason); + CPPUNIT_ASSERT_EQUAL(sentJID, info.jid.get()); + CPPUNIT_ASSERT_EQUAL(reasonText, info.reason.get()); + + CPPUNIT_ASSERT(!out.two); + CPPUNIT_ASSERT(!out.one); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(PresenceOracleTest); |