summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/Chat/MUCSearchController.cpp156
-rw-r--r--Swift/Controllers/Chat/MUCSearchController.h108
-rw-r--r--Swift/Controllers/MainController.cpp16
-rw-r--r--Swift/Controllers/MainController.h6
-rw-r--r--Swift/Controllers/SConscript3
-rw-r--r--Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h15
-rw-r--r--Swift/Controllers/UIInterfaces/MUCSearchWindow.h31
-rw-r--r--Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h19
-rw-r--r--Swift/QtUI/MUCSearch/MUCSearchDelegate.cpp86
-rw-r--r--Swift/QtUI/MUCSearch/MUCSearchDelegate.h28
-rw-r--r--Swift/QtUI/MUCSearch/MUCSearchItem.h17
-rw-r--r--Swift/QtUI/MUCSearch/MUCSearchModel.cpp77
-rw-r--r--Swift/QtUI/MUCSearch/MUCSearchModel.h35
-rw-r--r--Swift/QtUI/MUCSearch/MUCSearchRoomItem.cpp26
-rw-r--r--Swift/QtUI/MUCSearch/MUCSearchRoomItem.h23
-rw-r--r--Swift/QtUI/MUCSearch/MUCSearchServiceItem.h32
-rw-r--r--Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp112
-rw-r--r--Swift/QtUI/MUCSearch/QtMUCSearchWindow.h39
-rw-r--r--Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui185
-rw-r--r--Swift/QtUI/MUCSearch/QtMUCSearchWindowFactory.h22
-rw-r--r--Swift/QtUI/QtMainWindow.cpp2
-rw-r--r--Swift/QtUI/QtSwift.cpp5
-rw-r--r--Swift/QtUI/QtSwift.h2
-rw-r--r--Swift/QtUI/SConscript5
-rw-r--r--Swiften/Elements/DiscoItems.h65
-rw-r--r--Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp30
-rw-r--r--Swiften/Parser/PayloadParsers/DiscoItemsParser.h29
-rw-r--r--Swiften/Parser/PayloadParsers/DiscoItemsParserFactory.h18
-rw-r--r--Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp2
-rw-r--r--Swiften/Parser/SConscript1
-rw-r--r--Swiften/Queries/Requests/GetDiscoItemsRequest.h19
-rw-r--r--Swiften/SConscript1
-rw-r--r--Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.cpp36
-rw-r--r--Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h20
-rw-r--r--Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp2
35 files changed, 1265 insertions, 8 deletions
diff --git a/Swift/Controllers/Chat/MUCSearchController.cpp b/Swift/Controllers/Chat/MUCSearchController.cpp
new file mode 100644
index 0000000..93d2087
--- /dev/null
+++ b/Swift/Controllers/Chat/MUCSearchController.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swift/Controllers/Chat/MUCSearchController.h"
+
+#include <iostream>
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Queries/Requests/GetDiscoInfoRequest.h"
+#include "Swiften/Queries/Requests/GetDiscoItemsRequest.h"
+
+#include "Swift/Controllers/UIEvents/UIEventStream.h"
+#include "Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h"
+#include "Swift/Controllers/UIInterfaces/MUCSearchWindow.h"
+#include "Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h"
+
+namespace Swift {
+
+MUCSearchController::MUCSearchController(const JID& jid, UIEventStream* uiEventStream, MUCSearchWindowFactory* factory, IQRouter* iqRouter) : jid_(jid) {
+ iqRouter_ = iqRouter;
+ uiEventStream_ = uiEventStream;
+ uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&MUCSearchController::handleUIEvent, this, _1));
+ window_ = NULL;
+ factory_ = factory;
+}
+
+MUCSearchController::~MUCSearchController() {
+ delete window_;
+}
+
+void MUCSearchController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
+ boost::shared_ptr<RequestMUCSearchUIEvent> searchEvent = boost::dynamic_pointer_cast<RequestMUCSearchUIEvent>(event);
+ if (searchEvent) {
+ if (!window_) {
+ window_ = factory_->createMUCSearchWindow(uiEventStream_);
+ window_->onAddService.connect(boost::bind(&MUCSearchController::handleAddService, this, _1, true));
+ handleAddService(JID(jid_.getDomain()), true);
+ }
+ window_->setMUC("");
+ window_->setNick(jid_.getNode());
+ window_->show();
+ return;
+ }
+}
+
+void MUCSearchController::handleAddService(const JID& jid, bool userTriggered) {
+ if (std::find(services_.begin(), services_.end(), jid) != services_.end()) {
+ if (!userTriggered) {
+ /* No infinite recursion. (Some buggy servers do infinitely deep disco of themselves)*/
+ return;
+ }
+ } else if (userTriggered) {
+ services_.push_back(jid);
+ serviceDetails_[jid].setComplete(false);
+ refreshView();
+ }
+ if (!jid.isValid()) {
+ //Set Window to say error this isn't valid
+ return;
+ }
+ boost::shared_ptr<GetDiscoInfoRequest> discoInfoRequest(new GetDiscoInfoRequest(jid, iqRouter_));
+ discoInfoRequest->onResponse.connect(boost::bind(&MUCSearchController::handleDiscoInfoResponse, this, _1, _2, jid));
+ discoInfoRequest->send();
+}
+
+void MUCSearchController::removeService(const JID& jid) {
+ serviceDetails_.erase(jid);
+ services_.erase(std::remove(services_.begin(), services_.end(), jid), services_.end());
+ refreshView();
+}
+
+void MUCSearchController::handleDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, const boost::optional<ErrorPayload>& error, const JID& jid) {
+ if (error) {
+ handleDiscoError(jid, error.get());
+ return;
+ }
+ boost::shared_ptr<GetDiscoItemsRequest> discoItemsRequest(new GetDiscoItemsRequest(jid, iqRouter_));
+ bool mucService = false;
+ bool couldContainServices = false;
+ String name;
+ foreach (DiscoInfo::Identity identity, info->getIdentities()) {
+ if ((identity.getCategory() == "directory"
+ && identity.getType() == "chatroom")
+ || (identity.getCategory() == "conference"
+ && identity.getType() == "text")) {
+ mucService = true;
+ name = identity.getName();
+ }
+ if (identity.getCategory() == "server") {
+ couldContainServices = true;
+ name = identity.getName();
+ }
+ }
+ services_.erase(std::remove(services_.begin(), services_.end(), jid), services_.end()); /* Bring it back to the end on a refresh */
+ services_.push_back(jid);
+ serviceDetails_[jid].setName(name);
+ serviceDetails_[jid].setJID(jid);
+ serviceDetails_[jid].setComplete(false);
+
+ if (mucService) {
+ discoItemsRequest->onResponse.connect(boost::bind(&MUCSearchController::handleRoomsItemsResponse, this, _1, _2, jid));
+ } else if (couldContainServices) {
+ discoItemsRequest->onResponse.connect(boost::bind(&MUCSearchController::handleServerItemsResponse, this, _1, _2, jid));
+ } else {
+ removeService(jid);
+ return;
+ }
+ discoItemsRequest->send();
+ refreshView();
+}
+
+void MUCSearchController::handleRoomsItemsResponse(boost::shared_ptr<DiscoItems> items, const boost::optional<ErrorPayload>& error, const JID& jid) {
+ if (error) {
+ handleDiscoError(jid, error.get());
+ return;
+ }
+ serviceDetails_[jid].clearRooms();
+ foreach (DiscoItems::Item item, items->getItems()) {
+ serviceDetails_[jid].addRoom(MUCService::MUCRoom(item.getJID().getNode(), item.getName(), -1));
+ }
+ serviceDetails_[jid].setComplete(true);
+ refreshView();
+}
+
+void MUCSearchController::handleServerItemsResponse(boost::shared_ptr<DiscoItems> items, const boost::optional<ErrorPayload>& error, const JID& jid) {
+ if (error) {
+ handleDiscoError(jid, error.get());
+ return;
+ }
+ if (jid.isValid()) {
+ removeService(jid);
+ }
+ foreach (DiscoItems::Item item, items->getItems()) {
+ handleAddService(item.getJID());
+ }
+ refreshView();
+}
+
+void MUCSearchController::handleDiscoError(const JID& jid, const ErrorPayload& error) {
+ serviceDetails_[jid].setComplete(true);
+ serviceDetails_[jid].setError(error.getText());
+}
+
+void MUCSearchController::refreshView() {
+ window_->clearList();
+ foreach (JID jid, services_) {
+ window_->addService(serviceDetails_[jid]);
+ }
+}
+
+}
diff --git a/Swift/Controllers/Chat/MUCSearchController.h b/Swift/Controllers/Chat/MUCSearchController.h
new file mode 100644
index 0000000..6eba2a5
--- /dev/null
+++ b/Swift/Controllers/Chat/MUCSearchController.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+#include <map>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/signals.hpp>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/JID/JID.h"
+
+#include "Swift/Controllers/UIEvents/UIEvent.h"
+#include "Swift/Controllers/Chat/MUCSearchController.h"
+#include "Swiften/Elements/DiscoInfo.h"
+#include "Swiften/Elements/DiscoItems.h"
+#include "Swiften/Elements/ErrorPayload.h"
+
+namespace Swift {
+ class UIEventStream;
+ class MUCSearchWindow;
+ class MUCSearchWindowFactory;
+ class IQRouter;
+
+ class MUCService {
+ public:
+ class MUCRoom {
+ public:
+ MUCRoom(const String& node, const String& name, int occupants) : node_(node), name_(name), occupants_(occupants) {}
+ String getNode() {return node_;}
+ String getName() {return name_;}
+ int getOccupantCount() {return occupants_;}
+ private:
+ String node_;
+ String name_;
+ int occupants_;
+ };
+
+ MUCService() {error_ = false; complete_ = false;}
+
+ void setComplete(bool complete) {
+ complete_ = complete;
+ }
+
+ void setName(const String& name) {
+ name_ = name;
+ }
+
+ void setJID(const JID& jid) {
+ jid_ = jid;
+ }
+
+ bool getComplete() const {
+ return complete_;
+ }
+
+ JID getJID() const {
+ return jid_;
+ }
+
+ String getName() const {
+ return name_;
+ }
+
+ void setError(const String& errorText) {error_ = true; errorText_ = errorText;}
+
+ void clearRooms() {rooms_.clear();}
+
+ void addRoom(const MUCRoom& room) {rooms_.push_back(room);}
+
+ std::vector<MUCRoom> getRooms() const {return rooms_;}
+ private:
+ String name_;
+ JID jid_;
+ std::vector<MUCRoom> rooms_;
+ bool complete_;
+ bool error_;
+ String errorText_;
+ };
+
+ class MUCSearchController {
+ public:
+ MUCSearchController(const JID& jid, UIEventStream* uiEventStream, MUCSearchWindowFactory* mucSearchWindowFactory, IQRouter* iqRouter);
+ ~MUCSearchController();
+ private:
+ void handleUIEvent(boost::shared_ptr<UIEvent> event);
+ void handleAddService(const JID& jid, bool userTriggered=false);
+ void handleDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, const boost::optional<ErrorPayload>& error, const JID& jid);
+ void handleRoomsItemsResponse(boost::shared_ptr<DiscoItems> items, const boost::optional<ErrorPayload>& error, const JID& jid);
+ void handleServerItemsResponse(boost::shared_ptr<DiscoItems> items, const boost::optional<ErrorPayload>& error, const JID& jid);
+ void handleDiscoError(const JID& jid, const ErrorPayload& error);
+ void removeService(const JID& jid);
+ void refreshView();
+ UIEventStream* uiEventStream_;
+ MUCSearchWindow* window_;
+ MUCSearchWindowFactory* factory_;
+ boost::bsignals::scoped_connection uiEventConnection_;
+ std::vector<JID> services_;
+ std::map<JID, MUCService> serviceDetails_;
+ IQRouter* iqRouter_;
+ JID jid_;
+ };
+}
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index e6dfe47..5be8e46 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -14,15 +14,16 @@
#include "Swiften/Application/Application.h"
#include "Swiften/Application/ApplicationMessageDisplay.h"
#include "Swift/Controllers/Chat/ChatController.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h"
+#include "Swift/Controllers/Chat/MUCSearchController.h"
+//#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h"
#include "Swift/Controllers/Chat/ChatsManager.h"
#include "Swift/Controllers/EventController.h"
#include "Swift/Controllers/EventWindowController.h"
#include "Swift/Controllers/UIInterfaces/LoginWindow.h"
#include "Swift/Controllers/UIInterfaces/LoginWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/EventWindowFactory.h"
+//#include "Swift/Controllers/UIInterfaces/EventWindowFactory.h"
#include "Swift/Controllers/UIInterfaces/MainWindow.h"
-#include "Swift/Controllers/UIInterfaces/MainWindowFactory.h"
+//#include "Swift/Controllers/UIInterfaces/MainWindowFactory.h"
#include "Swift/Controllers/Chat/MUCController.h"
#include "Swift/Controllers/NickResolver.h"
#include "Swift/Controllers/ProfileSettingsProvider.h"
@@ -33,7 +34,7 @@
#include "Swift/Controllers/SystemTrayController.h"
#include "Swift/Controllers/XMLConsoleController.h"
#include "Swift/Controllers/XMPPRosterController.h"
-#include "Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h"
+//#include "Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h"
#include "Swift/Controllers/UIEvents/UIEventStream.h"
#include "Swiften/Base/foreach.h"
#include "Swiften/Base/String.h"
@@ -60,7 +61,7 @@ static const String CLIENT_VERSION = "0.3";
static const String CLIENT_NODE = "http://swift.im";
-MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, EventWindowFactory* eventWindowFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer, XMLConsoleWidgetFactory* xmlConsoleWidgetFactory, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency)
+MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, EventWindowFactory* eventWindowFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer, XMLConsoleWidgetFactory* xmlConsoleWidgetFactory, ChatListWindowFactory* chatListWindowFactory, MUCSearchWindowFactory* mucSearchWindowFactory, bool useDelayForLatency)
: timerFactory_(&boostIOServiceThread_.getIOService()), idleDetector_(&idleQuerier_, &timerFactory_, 100), chatWindowFactory_(chatWindowFactory), mainWindowFactory_(mainWindowFactory), loginWindowFactory_(loginWindowFactory), settings_(settings), loginWindow_(NULL), useDelayForLatency_(useDelayForLatency) {
application_ = application;
presenceOracle_ = NULL;
@@ -77,6 +78,7 @@ MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowF
presenceSender_ = NULL;
client_ = NULL;
+ mucSearchWindowFactory_ = mucSearchWindowFactory;
eventWindowFactory_ = eventWindowFactory;
chatListWindowFactory_ = chatListWindowFactory;
uiEventStream_ = new UIEventStream();
@@ -155,6 +157,8 @@ void MainController::resetClient() {
presenceSender_ = NULL;
delete client_;
client_ = NULL;
+ delete mucSearchController_;
+ mucSearchController_ = NULL;
}
@@ -203,6 +207,8 @@ void MainController::handleConnected() {
discoResponder_->setDiscoInfo(discoInfo);
discoResponder_->setDiscoInfo(capsInfo_->getNode() + "#" + capsInfo_->getVersion(), discoInfo);
serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>(new DiscoInfo());
+
+ mucSearchController_ = new MUCSearchController(jid_, uiEventStream_, mucSearchWindowFactory_, client_);
}
boost::shared_ptr<GetDiscoInfoRequest> discoInfoRequest(new GetDiscoInfoRequest(JID(), client_));
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index 5d3f998..63e77f2 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -58,10 +58,12 @@ namespace Swift {
class XMLConsoleWidgetFactory;
class EventWindowFactory;
class EventWindowController;
+ class MUCSearchController;
+ class MUCSearchWindowFactory;
class MainController {
public:
- MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, EventWindowFactory* eventWindowFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer, XMLConsoleWidgetFactory* xmlConsoleWidgetFactory, ChatListWindowFactory* chatListWindowFactory_, bool useDelayForLatency);
+ MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, EventWindowFactory* eventWindowFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer, XMLConsoleWidgetFactory* xmlConsoleWidgetFactory, ChatListWindowFactory* chatListWindowFactory_, MUCSearchWindowFactory* mucSearchWindowFactory, bool useDelayForLatency);
~MainController();
@@ -126,5 +128,7 @@ namespace Swift {
ChatListWindowFactory* chatListWindowFactory_;
boost::shared_ptr<ErrorEvent> lastDisconnectError_;
bool useDelayForLatency_;
+ MUCSearchController* mucSearchController_;
+ MUCSearchWindowFactory* mucSearchWindowFactory_;
};
}
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index a7ddc79..eb63bed 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -21,11 +21,12 @@ if env["SCONS_STAGE"] == "build" :
"Chat/ChatController.cpp",
"Chat/ChatControllerBase.cpp",
"Chat/ChatsManager.cpp",
+ "Chat/MUCController.cpp",
+ "Chat/MUCSearchController.cpp",
"MainController.cpp",
"NickResolver.cpp",
"RosterController.cpp",
"XMPPRosterController.cpp",
- "Chat/MUCController.cpp",
"EventController.cpp",
"EventWindowController.cpp",
"SoundEventController.cpp",
diff --git a/Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h b/Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h
new file mode 100644
index 0000000..623cd00
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swift/Controllers/UIEvents/UIEvent.h"
+
+namespace Swift {
+ class RequestMUCSearchUIEvent : public UIEvent {
+
+ };
+}
diff --git a/Swift/Controllers/UIInterfaces/MUCSearchWindow.h b/Swift/Controllers/UIInterfaces/MUCSearchWindow.h
new file mode 100644
index 0000000..3114a5a
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/MUCSearchWindow.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/signals.hpp>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/JID/JID.h"
+
+#include "Swift/Controllers/Chat/MUCSearchController.h"
+
+namespace Swift {
+
+ class MUCSearchWindow {
+ public:
+ virtual ~MUCSearchWindow() {};
+
+ virtual void setNick(const String& nick) = 0;
+ virtual void setMUC(const String& nick) = 0;
+ virtual void clearList() = 0;
+ virtual void addService(const MUCService& service) = 0;
+
+ virtual void show() = 0;
+
+ boost::signal<void (const JID&)> onAddService;
+ };
+}
diff --git a/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h b/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h
new file mode 100644
index 0000000..1f0bf90
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swift/Controllers/UIInterfaces/MUCSearchWindow.h"
+
+namespace Swift {
+ class UIEventStream;
+ class MUCSearchWindowFactory {
+ public:
+ virtual ~MUCSearchWindowFactory() {};
+
+ virtual MUCSearchWindow* createMUCSearchWindow(UIEventStream* eventStream) = 0;
+ };
+}
diff --git a/Swift/QtUI/MUCSearch/MUCSearchDelegate.cpp b/Swift/QtUI/MUCSearch/MUCSearchDelegate.cpp
new file mode 100644
index 0000000..be92efe
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/MUCSearchDelegate.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <QPen>
+#include <QPainter>
+
+#include "Swift/QtUI/MUCSearch/MUCSearchDelegate.h"
+#include "Swift/QtUI/Roster/GroupItemDelegate.h"
+#include "Swift/QtUI/MUCSearch/MUCSearchItem.h"
+#include "Swift/QtUI/MUCSearch/MUCSearchRoomItem.h"
+#include "Swift/QtUI/MUCSearch/MUCSearchServiceItem.h"
+
+namespace Swift {
+
+MUCSearchDelegate::MUCSearchDelegate() {
+
+}
+
+MUCSearchDelegate::~MUCSearchDelegate() {
+
+}
+
+// QSize MUCSearchDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index ) const {
+// // MUCSearchItem* item = static_cast<MUCSearchItem*>(index.internalPointer());
+// // if (item && dynamic_cast<MUCSearchMUCItem*>(item)) {
+// // return mucSizeHint(option, index);
+// // } else if (item && dynamic_cast<MUCSearchGroupItem*>(item)) {
+// // return groupDelegate_->sizeHint(option, index);
+// // }
+// return QStyledItemDelegate::sizeHint(option, index);
+// }
+
+// QSize MUCSearchDelegate::mucSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const {
+// QFontMetrics nameMetrics(common_.nameFont);
+// QFontMetrics statusMetrics(common_.detailFont);
+// int sizeByText = 2 * common_.verticalMargin + nameMetrics.height() + statusMetrics.height();
+// return QSize(150, sizeByText);
+// }
+
+// void MUCSearchDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
+// MUCSearchItem* item = static_cast<MUCSearchItem*>(index.internalPointer());
+// if (item && dynamic_cast<MUCSearchMUCItem*>(item)) {
+// paintMUC(painter, option, dynamic_cast<MUCSearchMUCItem*>(item));
+// } else if (item && dynamic_cast<MUCSearchGroupItem*>(item)) {
+// MUCSearchGroupItem* group = dynamic_cast<MUCSearchGroupItem*>(item);
+// groupDelegate_->paint(painter, option, group->data(Qt::DisplayRole).toString(), group->rowCount(), option.state & QStyle::State_Open);
+// } else {
+// QStyledItemDelegate::paint(painter, option, index);
+// }
+// }
+
+// void MUCSearchDelegate::paintMUC(QPainter* painter, const QStyleOptionViewItem& option, MUCSearchMUCItem* item) const {
+// painter->save();
+// QRect fullRegion(option.rect);
+// if ( option.state & QStyle::State_Selected ) {
+// painter->fillRect(fullRegion, option.palette.highlight());
+// painter->setPen(option.palette.highlightedText().color());
+// } else {
+// QColor nameColor = item->data(Qt::TextColorRole).value<QColor>();
+// painter->setPen(QPen(nameColor));
+// }
+
+// QFontMetrics nameMetrics(common_.nameFont);
+// painter->setFont(common_.nameFont);
+// int extraFontWidth = nameMetrics.width("H");
+// int leftOffset = common_.horizontalMargin * 2 + extraFontWidth / 2;
+// QRect textRegion(fullRegion.adjusted(leftOffset, 0, 0, 0));
+
+// int nameHeight = nameMetrics.height() + common_.verticalMargin;
+// QRect nameRegion(textRegion.adjusted(0, common_.verticalMargin, 0, 0));
+
+// painter->drawText(nameRegion, Qt::AlignTop, item->data(Qt::DisplayRole).toString());
+
+// painter->setFont(common_.detailFont);
+// painter->setPen(QPen(QColor(160,160,160)));
+
+// QRect detailRegion(textRegion.adjusted(0, nameHeight, 0, 0));
+// painter->drawText(detailRegion, Qt::AlignTop, item->data(DetailTextRole).toString());
+
+// painter->restore();
+// }
+
+}
diff --git a/Swift/QtUI/MUCSearch/MUCSearchDelegate.h b/Swift/QtUI/MUCSearch/MUCSearchDelegate.h
new file mode 100644
index 0000000..2662bb9
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/MUCSearchDelegate.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QStyledItemDelegate>
+
+#include "Swift/QtUI/Roster/DelegateCommons.h"
+
+namespace Swift {
+ class MUCSearchDelegate : public QStyledItemDelegate {
+ public:
+ MUCSearchDelegate();
+ ~MUCSearchDelegate();
+ /* QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; */
+ /* void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; */
+ private:
+// void paintMUC(QPainter* painter, const QStyleOptionViewItem& option, MUCSearchMUCItem* item) const;
+// QSize mucSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const;
+
+ DelegateCommons common_;
+ };
+
+}
+
diff --git a/Swift/QtUI/MUCSearch/MUCSearchItem.h b/Swift/QtUI/MUCSearch/MUCSearchItem.h
new file mode 100644
index 0000000..7bac25d
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/MUCSearchItem.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QVariant>
+
+namespace Swift {
+ class MUCSearchItem {
+ public:
+ virtual ~MUCSearchItem() {}
+ virtual QVariant data(int role) = 0;
+ };
+}
diff --git a/Swift/QtUI/MUCSearch/MUCSearchModel.cpp b/Swift/QtUI/MUCSearch/MUCSearchModel.cpp
new file mode 100644
index 0000000..eb7fe20
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/MUCSearchModel.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swift/QtUI/MUCSearch/MUCSearchModel.h"
+
+namespace Swift {
+
+MUCSearchModel::MUCSearchModel() {
+}
+
+void MUCSearchModel::clear() {
+ emit layoutAboutToBeChanged();
+ services_.clear();
+ emit layoutChanged();
+}
+
+void MUCSearchModel::addService(MUCSearchServiceItem* service) {
+ emit layoutAboutToBeChanged();
+ services_.push_back(service);
+ emit layoutChanged();
+}
+
+int MUCSearchModel::columnCount(const QModelIndex& /*parent*/) const {
+ return 1;
+}
+
+QVariant MUCSearchModel::data(const QModelIndex& index, int role) const {
+ return index.isValid() ? static_cast<MUCSearchItem*>(index.internalPointer())->data(role) : QVariant();
+}
+
+QModelIndex MUCSearchModel::index(int row, int column, const QModelIndex & parent) const {
+ if (!hasIndex(row, column, parent)) {
+ return QModelIndex();
+ }
+
+ if (parent.isValid()) {
+ MUCSearchServiceItem* parentItem = static_cast<MUCSearchServiceItem*>(parent.internalPointer());
+ return row < parentItem->rowCount() ? createIndex(row, column, parentItem->getItem(row)) : QModelIndex();
+
+ } else {
+ return row < services_.size() ? createIndex(row, column, services_[row]) : QModelIndex();
+ }
+
+
+}
+
+QModelIndex MUCSearchModel::parent(const QModelIndex& index) const {
+ if (!index.isValid()) {
+ return QModelIndex();
+ }
+ MUCSearchItem* item = static_cast<MUCSearchItem*>(index.internalPointer());
+ if (!item) {
+ return QModelIndex();
+ }
+ if (dynamic_cast<MUCSearchServiceItem*>(item)) {
+ return QModelIndex();
+ }
+ MUCSearchServiceItem* parent = dynamic_cast<MUCSearchRoomItem*>(item)->getParent();
+ int row = services_.indexOf(parent);
+ return parent ? createIndex(row, 1, parent) : QModelIndex();
+}
+
+int MUCSearchModel::rowCount(const QModelIndex& parentIndex) const {
+ if (!parentIndex.isValid()) {
+ return services_.size();
+ }
+ if (dynamic_cast<MUCSearchServiceItem*>(static_cast<MUCSearchItem*>(parentIndex.internalPointer()))) {
+ return services_[parentIndex.row()]->rowCount();
+ } else {
+ return 0;
+ }
+}
+
+}
diff --git a/Swift/QtUI/MUCSearch/MUCSearchModel.h b/Swift/QtUI/MUCSearch/MUCSearchModel.h
new file mode 100644
index 0000000..0c02c72
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/MUCSearchModel.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <QAbstractItemModel>
+#include <QList>
+
+#include "Swift/QtUI/MUCSearch/MUCSearchServiceItem.h"
+
+namespace Swift {
+ class MUCSearchModel : public QAbstractItemModel {
+ Q_OBJECT
+ public:
+ MUCSearchModel();
+ void clear();
+ void addService(MUCSearchServiceItem* service);
+ int columnCount(const QModelIndex& parent = QModelIndex()) const;
+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
+ QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex& index) const;
+ int rowCount(const QModelIndex& parent = QModelIndex()) const;
+// ChatListItem* getItemForIndex(const QModelIndex& index) const;
+ private:
+// ChatListGroupItem* mucBookmarks_;
+// ChatListGroupItem* root_;
+ QList<MUCSearchServiceItem*> services_;
+ };
+
+}
diff --git a/Swift/QtUI/MUCSearch/MUCSearchRoomItem.cpp b/Swift/QtUI/MUCSearch/MUCSearchRoomItem.cpp
new file mode 100644
index 0000000..a53a577
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/MUCSearchRoomItem.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swift/QtUI/MUCSearch/MUCSearchRoomItem.h"
+
+#include "Swift/QtUI/MUCSearch/MUCSearchServiceItem.h"
+
+namespace Swift {
+MUCSearchRoomItem::MUCSearchRoomItem(const QString& node, MUCSearchServiceItem* parent) : parent_(parent), node_(node) {
+ parent_->addRoom(this);
+}
+
+MUCSearchServiceItem* MUCSearchRoomItem::getParent() {
+ return parent_;
+}
+QVariant MUCSearchRoomItem::data(int role) {
+ switch (role) {
+ case Qt::DisplayRole: return QVariant(node_);
+ default: return QVariant();
+ }
+}
+
+}
diff --git a/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h b/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h
new file mode 100644
index 0000000..920aaae
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swift/QtUI/MUCSearch/MUCSearchItem.h"
+
+namespace Swift {
+ class MUCSearchServiceItem;
+ class MUCSearchRoomItem : public MUCSearchItem {
+ public:
+ MUCSearchRoomItem(const QString& node, MUCSearchServiceItem* parent);
+ MUCSearchServiceItem* getParent();
+ QVariant data(int role);
+ QString getNode() {return node_;}
+ private:
+ MUCSearchServiceItem* parent_;
+ QString node_;
+ };
+}
diff --git a/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h b/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h
new file mode 100644
index 0000000..860792f
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QList>
+#include <QString>
+
+#include "Swift/QtUI/MUCSearch/MUCSearchRoomItem.h"
+
+namespace Swift {
+ class MUCSearchServiceItem : public MUCSearchItem {
+ public:
+ MUCSearchServiceItem(const QString& jidString) : jidString_(jidString) {}
+ void addRoom(MUCSearchRoomItem* room) {rooms_.push_back(room);}
+ int rowCount() {return rooms_.count();}
+ MUCSearchRoomItem* getItem(int i) {return rooms_[i];}
+ QVariant data(int role) {
+ switch (role) {
+ case Qt::DisplayRole: return QVariant(jidString_);
+ default: return QVariant();
+ }
+ }
+ QString getHost() {return jidString_;}
+ private:
+ QList<MUCSearchRoomItem*> rooms_;
+ QString jidString_;
+ };
+}
diff --git a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp
new file mode 100644
index 0000000..78e4fa5
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swift/QtUI/MUCSearch/QtMUCSearchWindow.h"
+
+#include <qdebug.h>
+
+#include "Swift/Controllers/UIEvents/UIEventStream.h"
+#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
+#include "Swift/QtUI/MUCSearch/MUCSearchModel.h"
+#include "Swift/QtUI/MUCSearch/MUCSearchDelegate.h"
+#include "Swift/QtUI/QtSwiftUtil.h"
+
+namespace Swift {
+
+QtMUCSearchWindow::QtMUCSearchWindow(UIEventStream* eventStream) {
+ eventStream_ = eventStream;
+ setupUi(this);
+ showEmptyRooms_->hide();
+ filterLabel_->hide();
+ filter_->hide();
+ model_ = new MUCSearchModel();
+ delegate_ = new MUCSearchDelegate();
+ results_->setModel(model_);
+ results_->setItemDelegate(delegate_);
+ results_->setHeaderHidden(true);
+#ifdef SWIFT_PLATFORM_MACOSX
+ results_->setAlternatingRowColors(true);
+#endif
+ connect(searchButton_, SIGNAL(clicked()), this, SLOT(handleSearch()));
+ connect(joinButton_, SIGNAL(clicked()), this, SLOT(handleJoin()));
+ connect(results_, SIGNAL(clicked(const QModelIndex&)), this, SLOT(handleSelected(const QModelIndex&)));
+ connect(results_, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleActivated(const QModelIndex&)));
+}
+
+QtMUCSearchWindow::~QtMUCSearchWindow() {
+
+}
+
+void QtMUCSearchWindow::handleActivated(const QModelIndex& index) {
+ if (!index.isValid()) {
+ return;
+ }
+ MUCSearchRoomItem* roomItem = dynamic_cast<MUCSearchRoomItem*>(static_cast<MUCSearchItem*>(index.internalPointer()));
+ if (roomItem) {
+ handleSelected(index);
+ handleJoin();
+ }
+}
+
+void QtMUCSearchWindow::handleSelected(const QModelIndex& current) {
+ if (!current.isValid()) {
+ return;
+ }
+ MUCSearchRoomItem* roomItem = dynamic_cast<MUCSearchRoomItem*>(static_cast<MUCSearchItem*>(current.internalPointer()));
+ if (roomItem) {
+ room_->setText(roomItem->getNode() + "@" + roomItem->getParent()->getHost());
+ }
+
+}
+
+void QtMUCSearchWindow::handleSearch() {
+ if (service_->text().isEmpty()) {
+ return;
+ }
+ onAddService(JID(Q2PSTRING(service_->text())));
+}
+
+void QtMUCSearchWindow::handleJoin() {
+ if (room_->text().isEmpty()) {
+ handleSelected(results_->currentIndex());
+ }
+ if (room_->text().isEmpty()) {
+ return;
+ }
+ boost::optional<String> maybeNick;
+ if (!nickName_->text().isEmpty()) {
+ maybeNick = Q2PSTRING(nickName_->text());
+ }
+ eventStream_->send(boost::shared_ptr<UIEvent>(new JoinMUCUIEvent(JID(Q2PSTRING(room_->text())), maybeNick)));
+ hide();
+}
+
+void QtMUCSearchWindow::setNick(const String& nick) {
+ nickName_->setText(P2QSTRING(nick));
+}
+
+void QtMUCSearchWindow::setMUC(const String& nick) {
+ room_->setText(P2QSTRING(nick));
+}
+
+void QtMUCSearchWindow::show() {
+ QWidget::show();
+ QWidget::activateWindow();
+}
+
+void QtMUCSearchWindow::clearList() {
+ model_->clear();
+}
+
+void QtMUCSearchWindow::addService(const MUCService& service) {
+ MUCSearchServiceItem* serviceItem = new MUCSearchServiceItem(P2QSTRING(service.getJID().toString()));
+ foreach (MUCService::MUCRoom room, service.getRooms()) {
+ new MUCSearchRoomItem(P2QSTRING(room.getNode()), serviceItem);
+ }
+ model_->addService(serviceItem);
+}
+
+}
diff --git a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h
new file mode 100644
index 0000000..7b556b0
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swift/QtUI/MUCSearch/ui_QtMUCSearchWindow.h"
+
+#include "Swift/Controllers/UIInterfaces/MUCSearchWindow.h"
+
+namespace Swift {
+ class MUCSearchModel;
+ class MUCSearchDelegate;
+ class UIEventStream;
+ class QtMUCSearchWindow : public QWidget, public MUCSearchWindow, private Ui::QtMUCSearchWindow {
+ Q_OBJECT
+ public:
+ QtMUCSearchWindow(UIEventStream* eventStream);
+ virtual ~QtMUCSearchWindow();
+
+ virtual void setNick(const String& nick);
+ virtual void setMUC(const String& nick);
+ virtual void clearList();
+ virtual void addService(const MUCService& service);
+
+ virtual void show();
+ private slots:
+ void handleSearch();
+ void handleJoin();
+ void handleSelected(const QModelIndex& current);
+ void handleActivated(const QModelIndex& index);
+ private:
+ MUCSearchModel* model_;
+ MUCSearchDelegate* delegate_;
+ UIEventStream* eventStream_;
+ };
+}
diff --git a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui
new file mode 100644
index 0000000..d3d327e
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtMUCSearchWindow</class>
+ <widget class="QWidget" name="QtMUCSearchWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>502</width>
+ <height>526</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Find Room</string>
+ </property>
+ <widget class="QTreeView" name="results_">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>30</y>
+ <width>256</width>
+ <height>441</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>251</width>
+ <height>18</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Available Rooms</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="service_">
+ <property name="geometry">
+ <rect>
+ <x>280</x>
+ <y>140</y>
+ <width>211</width>
+ <height>26</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_2">
+ <property name="geometry">
+ <rect>
+ <x>280</x>
+ <y>120</y>
+ <width>201</width>
+ <height>18</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Search another service:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="filterLabel_">
+ <property name="geometry">
+ <rect>
+ <x>280</x>
+ <y>260</y>
+ <width>211</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Only show rooms matching:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="filter_">
+ <property name="geometry">
+ <rect>
+ <x>280</x>
+ <y>280</y>
+ <width>211</width>
+ <height>26</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_4">
+ <property name="geometry">
+ <rect>
+ <x>280</x>
+ <y>410</y>
+ <width>211</width>
+ <height>18</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Join Room Directly:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_5">
+ <property name="geometry">
+ <rect>
+ <x>280</x>
+ <y>10</y>
+ <width>211</width>
+ <height>18</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Your nickname:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="nickName_">
+ <property name="geometry">
+ <rect>
+ <x>280</x>
+ <y>30</y>
+ <width>211</width>
+ <height>26</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="room_">
+ <property name="geometry">
+ <rect>
+ <x>280</x>
+ <y>430</y>
+ <width>201</width>
+ <height>26</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="joinButton_">
+ <property name="geometry">
+ <rect>
+ <x>210</x>
+ <y>480</y>
+ <width>92</width>
+ <height>28</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Join Room</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="showEmptyRooms_">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>280</x>
+ <y>310</y>
+ <width>201</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Show Empty Rooms</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="searchButton_">
+ <property name="geometry">
+ <rect>
+ <x>410</x>
+ <y>170</y>
+ <width>80</width>
+ <height>26</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Search</string>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Swift/QtUI/MUCSearch/QtMUCSearchWindowFactory.h b/Swift/QtUI/MUCSearch/QtMUCSearchWindowFactory.h
new file mode 100644
index 0000000..9bcb53f
--- /dev/null
+++ b/Swift/QtUI/MUCSearch/QtMUCSearchWindowFactory.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h"
+#include "Swift/QtUI/MUCSearch/QtMUCSearchWindow.h"
+
+namespace Swift {
+ class UIEventStream;
+ class QtMUCSearchWindowFactory : public MUCSearchWindowFactory {
+ public:
+ virtual ~QtMUCSearchWindowFactory() {};
+
+ MUCSearchWindow* createMUCSearchWindow(UIEventStream* eventStream) {
+ return new QtMUCSearchWindow(eventStream);
+ };
+ };
+}
diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp
index fcfb693..7d987c6 100644
--- a/Swift/QtUI/QtMainWindow.cpp
+++ b/Swift/QtUI/QtMainWindow.cpp
@@ -25,6 +25,7 @@
#include "QtTabWidget.h"
#include "Roster/QtTreeWidget.h"
#include "Swift/Controllers/UIEvents/AddContactUIEvent.h"
+#include "Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h"
#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
namespace Swift {
@@ -138,6 +139,7 @@ void QtMainWindow::handleJoinMUCAction() {
QtJoinMUCDialog* joinMUC = new QtJoinMUCDialog("jabber@conference.jabber.org", "SwiftUser", this);
connect(joinMUC, SIGNAL(onJoinCommand(const JID&, const QString&)), SLOT(handleJoinMUCDialogComplete(const JID&, const QString&)));
joinMUC->show();
+ uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestMUCSearchUIEvent()));
}
void QtMainWindow::handleJoinMUCDialogComplete(const JID& muc, const QString& nick) {
diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp
index 534697b..3b286b4 100644
--- a/Swift/QtUI/QtSwift.cpp
+++ b/Swift/QtUI/QtSwift.cpp
@@ -16,6 +16,7 @@
#include "QtXMLConsoleWidgetFactory.h"
#include "ChatList/QtChatListWindowFactory.h"
#include "EventViewer/QtEventWindowFactory.h"
+#include "MUCSearch/QtMUCSearchWindowFactory.h"
#include <boost/bind.hpp>
#include <QSplitter>
@@ -71,11 +72,12 @@ QtSwift::QtSwift(po::variables_map options) : autoUpdater_(NULL) {
eventWindowFactory_ = new QtEventWindowFactory(rosterWindowFactory_);
xmlConsoleWidgetFactory_ = new QtXMLConsoleWidgetFactory(tabs_);
chatListWindowFactory_ = new QtChatListWindowFactory(rosterWindowFactory_);
+ mucSearchWindowFactory_ = new QtMUCSearchWindowFactory();
soundPlayer_ = new QtSoundPlayer();
if (splitter_) {
splitter_->show();
}
- mainController_ = new MainController(chatWindowFactory_, rosterWindowFactory_, loginWindowFactory_, eventWindowFactory_, settings_, application_, systemTray_, soundPlayer_, xmlConsoleWidgetFactory_, chatListWindowFactory_, options.count("latency-debug") > 0);
+ mainController_ = new MainController(chatWindowFactory_, rosterWindowFactory_, loginWindowFactory_, eventWindowFactory_, settings_, application_, systemTray_, soundPlayer_, xmlConsoleWidgetFactory_, chatListWindowFactory_, mucSearchWindowFactory_, options.count("latency-debug") > 0);
PlatformAutoUpdaterFactory autoUpdaterFactory;
if (autoUpdaterFactory.isSupported()) {
@@ -89,6 +91,7 @@ QtSwift::~QtSwift() {
delete chatWindowFactory_;
delete rosterWindowFactory_;
delete loginWindowFactory_;
+ delete mucSearchWindowFactory_;
delete mainController_;
delete settings_;
delete application_;
diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h
index d0141b2..37dd4ce 100644
--- a/Swift/QtUI/QtSwift.h
+++ b/Swift/QtUI/QtSwift.h
@@ -33,6 +33,7 @@ namespace Swift {
class QtSoundPlayer;
class QtEventWindowFactory;
class QtChatListWindowFactory;
+ class QtMUCSearchWindowFactory;
class QtSwift : public QObject {
Q_OBJECT
@@ -56,6 +57,7 @@ namespace Swift {
QtEventWindowFactory* eventWindowFactory_;
Application* application_;
AutoUpdater* autoUpdater_;
+ QtMUCSearchWindowFactory* mucSearchWindowFactory_;
};
}
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 4311623..4ccb301 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -95,6 +95,10 @@ sources = [
"ChatList/ChatListModel.cpp",
"ChatList/ChatListDelegate.cpp",
"ChatList/ChatListMUCItem.cpp",
+ "MUCSearch/QtMUCSearchWindow.cpp",
+ "MUCSearch/MUCSearchModel.cpp",
+ "MUCSearch/MUCSearchRoomItem.cpp",
+ "MUCSearch/MUCSearchDelegate.cpp",
"ContextMenus/QtRosterContextMenu.cpp",
"ContextMenus/QtContextMenu.cpp",
"QtSubscriptionRequestWindow.cpp",
@@ -116,6 +120,7 @@ else :
swiftProgram = myenv.Program("swift", sources)
myenv.Uic4("QtJoinMUCDialog.ui")
+myenv.Uic4("MUCSearch/QtMUCSearchWindow.ui")
myenv.Uic4("QtAddContactDialog.ui")
myenv.Uic4("QtBookmarkDetailWindow.ui")
myenv.Qrc("DefaultTheme.qrc")
diff --git a/Swiften/Elements/DiscoItems.h b/Swiften/Elements/DiscoItems.h
new file mode 100644
index 0000000..400947a
--- /dev/null
+++ b/Swiften/Elements/DiscoItems.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+#include <algorithm>
+
+#include "Swiften/Elements/Payload.h"
+#include "Swiften/Base/String.h"
+#include "Swiften/JID/JID.h"
+
+namespace Swift {
+ class DiscoItems : public Payload {
+ public:
+ class Item {
+ public:
+ Item(const String& name, const JID& jid, const String& node="") : name_(name), jid_(jid), node_(node) {
+ }
+
+ const String& getName() const {
+ return name_;
+ }
+
+ const String& getNode() const {
+ return node_;
+ }
+
+ const JID& getJID() const {
+ return jid_;
+ }
+
+ private:
+ String name_;
+ JID jid_;
+ String node_;
+ };
+
+ DiscoItems() {
+ }
+
+ const String& getNode() const {
+ return node_;
+ }
+
+ void setNode(const String& node) {
+ node_ = node;
+ }
+
+ const std::vector<Item>& getItems() const {
+ return items_;
+ }
+
+ void addItem(const Item& item) {
+ items_.push_back(item);
+ }
+
+ private:
+ String node_;
+ std::vector<Item> items_;
+ };
+}
diff --git a/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp b/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp
new file mode 100644
index 0000000..0900354
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swiften/Parser/PayloadParsers/DiscoItemsParser.h"
+
+namespace Swift {
+
+DiscoItemsParser::DiscoItemsParser() : level_(TopLevel) {
+}
+
+void DiscoItemsParser::handleStartElement(const String& element, const String&, const AttributeMap& attributes) {
+ if (level_ == PayloadLevel) {
+ if (element == "item") {
+ getPayloadInternal()->addItem(DiscoItems::Item(attributes.getAttribute("name"), JID(attributes.getAttribute("jid")), attributes.getAttribute("node")));
+ }
+ }
+ ++level_;
+}
+
+void DiscoItemsParser::handleEndElement(const String&, const String&) {
+ --level_;
+}
+
+void DiscoItemsParser::handleCharacterData(const String&) {
+}
+
+}
diff --git a/Swiften/Parser/PayloadParsers/DiscoItemsParser.h b/Swiften/Parser/PayloadParsers/DiscoItemsParser.h
new file mode 100644
index 0000000..e3da34e
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/DiscoItemsParser.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swiften/Elements/DiscoItems.h"
+#include "Swiften/Parser/GenericPayloadParser.h"
+
+namespace Swift {
+ class DiscoItemsParser : public GenericPayloadParser<DiscoItems> {
+ public:
+ DiscoItemsParser();
+
+ virtual void handleStartElement(const String& element, const String&, const AttributeMap& attributes);
+ virtual void handleEndElement(const String& element, const String&);
+ virtual void handleCharacterData(const String& data);
+
+ private:
+ enum Level {
+ TopLevel = 0,
+ PayloadLevel = 1
+ };
+ int level_;
+ };
+}
+
diff --git a/Swiften/Parser/PayloadParsers/DiscoItemsParserFactory.h b/Swiften/Parser/PayloadParsers/DiscoItemsParserFactory.h
new file mode 100644
index 0000000..5b53031
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/DiscoItemsParserFactory.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swiften/Parser/GenericPayloadParserFactory.h"
+#include "Swiften/Parser/PayloadParsers/DiscoItemsParser.h"
+
+namespace Swift {
+ class DiscoItemsParserFactory : public GenericPayloadParserFactory<DiscoItemsParser> {
+ public:
+ DiscoItemsParserFactory() : GenericPayloadParserFactory<DiscoItemsParser>("query", "http://jabber.org/protocol/disco#items") {}
+ };
+}
+
diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
index b0e4eb2..8c570cb 100644
--- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
+++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
@@ -20,6 +20,7 @@
#include "Swiften/Parser/PayloadParsers/SoftwareVersionParserFactory.h"
#include "Swiften/Parser/PayloadParsers/StorageParserFactory.h"
#include "Swiften/Parser/PayloadParsers/DiscoInfoParserFactory.h"
+#include "Swiften/Parser/PayloadParsers/DiscoItemsParserFactory.h"
#include "Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h"
#include "Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h"
#include "Swiften/Parser/PayloadParsers/VCardUpdateParserFactory.h"
@@ -42,6 +43,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() {
factories_.push_back(shared_ptr<PayloadParserFactory>(new StorageParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new RosterParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new DiscoInfoParserFactory()));
+ factories_.push_back(shared_ptr<PayloadParserFactory>(new DiscoItemsParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new ResourceBindParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new StartSessionParserFactory()));
factories_.push_back(shared_ptr<PayloadParserFactory>(new SecurityLabelParserFactory()));
diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript
index 0d3aad2..77f50be 100644
--- a/Swiften/Parser/SConscript
+++ b/Swiften/Parser/SConscript
@@ -20,6 +20,7 @@ sources = [
"PayloadParsers/BodyParser.cpp",
"PayloadParsers/ChatStateParser.cpp",
"PayloadParsers/DiscoInfoParser.cpp",
+ "PayloadParsers/DiscoItemsParser.cpp",
"PayloadParsers/ErrorParser.cpp",
"PayloadParsers/FullPayloadParserFactoryCollection.cpp",
"PayloadParsers/PriorityParser.cpp",
diff --git a/Swiften/Queries/Requests/GetDiscoItemsRequest.h b/Swiften/Queries/Requests/GetDiscoItemsRequest.h
new file mode 100644
index 0000000..453eab4
--- /dev/null
+++ b/Swiften/Queries/Requests/GetDiscoItemsRequest.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swiften/Queries/GenericRequest.h"
+#include "Swiften/Elements/DiscoItems.h"
+
+namespace Swift {
+ class GetDiscoItemsRequest : public GenericRequest<DiscoItems> {
+ public:
+ GetDiscoItemsRequest(const JID& jid, IQRouter* router) :
+ GenericRequest<DiscoItems>(IQ::Get, jid, boost::shared_ptr<DiscoItems>(new DiscoItems()), router) {
+ }
+ };
+}
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 257f056..4d25dc5 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -70,6 +70,7 @@ if env["SCONS_STAGE"] == "build" :
"Serializer/PayloadSerializers/CapsInfoSerializer.cpp",
"Serializer/PayloadSerializers/ChatStateSerializer.cpp",
"Serializer/PayloadSerializers/DiscoInfoSerializer.cpp",
+ "Serializer/PayloadSerializers/DiscoItemsSerializer.cpp",
"Serializer/PayloadSerializers/ErrorSerializer.cpp",
"Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp",
"Serializer/PayloadSerializers/MUCPayloadSerializer.cpp",
diff --git a/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.cpp
new file mode 100644
index 0000000..056c515
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Base/foreach.h"
+#include "Swiften/Serializer/XML/XMLElement.h"
+
+namespace Swift {
+
+DiscoItemsSerializer::DiscoItemsSerializer() : GenericPayloadSerializer<DiscoItems>() {
+}
+
+String DiscoItemsSerializer::serializePayload(boost::shared_ptr<DiscoItems> discoItems) const {
+ XMLElement queryElement("query", "http://jabber.org/protocol/disco#items");
+ if (!discoItems->getNode().isEmpty()) {
+ queryElement.setAttribute("node", discoItems->getNode());
+ }
+ foreach(const DiscoItems::Item& item, discoItems->getItems()) {
+ boost::shared_ptr<XMLElement> itemElement(new XMLElement("item"));
+ itemElement->setAttribute("name", item.getName());
+ itemElement->setAttribute("jid", item.getJID());
+ if (!item.getNode().isEmpty()) {
+ itemElement->setAttribute("node", item.getNode());
+ }
+ queryElement.addNode(itemElement);
+ }
+ return queryElement.serialize();
+}
+
+}
diff --git a/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h b/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h
new file mode 100644
index 0000000..8116e9b
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swiften/Serializer/GenericPayloadSerializer.h"
+#include "Swiften/Elements/DiscoItems.h"
+
+namespace Swift {
+ class DiscoItemsSerializer : public GenericPayloadSerializer<DiscoItems> {
+ public:
+ DiscoItemsSerializer();
+
+ virtual String serializePayload(boost::shared_ptr<DiscoItems>) const;
+ };
+}
+
diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
index 8dc9d86..caf1d9c 100644
--- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
+++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
@@ -17,6 +17,7 @@
#include "Swiften/Serializer/PayloadSerializers/StatusSerializer.h"
#include "Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h"
#include "Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h"
+#include "Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h"
#include "Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h"
#include "Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h"
#include "Swiften/Serializer/PayloadSerializers/StartSessionSerializer.h"
@@ -42,6 +43,7 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() {
serializers_.push_back(new StatusSerializer());
serializers_.push_back(new StatusShowSerializer());
serializers_.push_back(new DiscoInfoSerializer());
+ serializers_.push_back(new DiscoItemsSerializer());
serializers_.push_back(new CapsInfoSerializer());
serializers_.push_back(new ResourceBindSerializer());
serializers_.push_back(new StartSessionSerializer());