summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp22
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.h4
-rw-r--r--Swift/Controllers/EventNotifier.cpp7
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h2
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h2
-rw-r--r--Swift/Controllers/XMPPEvents/EventController.cpp4
-rw-r--r--Swift/Controllers/XMPPEvents/MUCInviteEvent.h31
-rw-r--r--Swift/QtUI/EventViewer/EventDelegate.cpp7
-rw-r--r--Swift/QtUI/EventViewer/EventDelegate.h3
-rw-r--r--Swift/QtUI/EventViewer/QtEvent.cpp10
-rw-r--r--Swift/QtUI/EventViewer/QtEventWindow.cpp7
-rw-r--r--Swift/QtUI/QtChatView.cpp21
-rw-r--r--Swift/QtUI/QtChatView.h1
-rw-r--r--Swift/QtUI/QtChatWindow.cpp190
-rw-r--r--Swift/QtUI/QtChatWindow.h37
-rw-r--r--Swift/QtUI/QtChatWindowJSBridge.cpp (renamed from Swift/QtUI/QtFileTransferJSBridge.cpp)8
-rw-r--r--Swift/QtUI/QtChatWindowJSBridge.h (renamed from Swift/QtUI/QtFileTransferJSBridge.h)12
-rw-r--r--Swift/QtUI/SConscript2
18 files changed, 244 insertions, 126 deletions
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index f590ffd..8523591 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -23,18 +23,19 @@
#include <Swiften/Elements/MUCInvitationPayload.h>
#include <Swiften/Elements/MUCUserPayload.h>
#include <Swiften/Base/foreach.h>
#include <Swift/Controllers/XMPPEvents/EventController.h>
#include <Swiften/Disco/EntityCapsProvider.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h>
#include <Swiften/Avatars/AvatarManager.h>
+#include <Swift/Controllers/XMPPEvents/MUCInviteEvent.h>
namespace Swift {
ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider) {
chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream);
chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2));
entityCapsProvider_->onCapsChanged.connect(boost::bind(&ChatControllerBase::handleCapsChanged, this, _1));
setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable());
@@ -85,20 +86,20 @@ void ChatControllerBase::setAvailableServerFeatures(boost::shared_ptr<DiscoInfo>
request->send();
} else {
chatWindow_->setSecurityLabelsEnabled(false);
labelsEnabled_ = false;
}
}
void ChatControllerBase::handleAllMessagesRead() {
if (!unreadMessages_.empty()) {
- foreach (boost::shared_ptr<MessageEvent> messageEvent, unreadMessages_) {
- messageEvent->read();
+ foreach (boost::shared_ptr<StanzaEvent> stanzaEvent, unreadMessages_) {
+ stanzaEvent->conclude();
}
unreadMessages_.clear();
chatWindow_->setUnreadMessageCount(0);
onUnreadCountChanged();
}
}
int ChatControllerBase::getUnreadCount() {
return unreadMessages_.size();
@@ -261,31 +262,44 @@ std::string ChatControllerBase::getErrorMessage(boost::shared_ptr<ErrorPayload>
case ErrorPayload::ServiceUnavailable: return QT_TRANSLATE_NOOP("", "The service is unavailable"); break;
case ErrorPayload::SubscriptionRequired: return QT_TRANSLATE_NOOP("", "A subscription is required"); break;
case ErrorPayload::UndefinedCondition: return QT_TRANSLATE_NOOP("", "Undefined condition"); break;
case ErrorPayload::UnexpectedRequest: return QT_TRANSLATE_NOOP("", "Unexpected request"); break;
}
}
return defaultMessage;
}
+void ChatControllerBase::handleGeneralMUCInvitation(MUCInviteEvent::ref event) {
+ unreadMessages_.push_back(event);
+ chatWindow_->show();
+ chatWindow_->setUnreadMessageCount(unreadMessages_.size());
+ onUnreadCountChanged();
+ chatWindow_->addMUCInvitation(senderDisplayNameFromMessage(event->getInviter()), event->getRoomJID(), event->getReason(), event->getPassword(), event->getDirect());
+ eventController_->handleIncomingEvent(event);
+}
+
void ChatControllerBase::handleMUCInvitation(Message::ref message) {
MUCInvitationPayload::ref invite = message->getPayload<MUCInvitationPayload>();
- chatWindow_->addMUCInvitation(invite->getJID(), invite->getReason(), invite->getPassword());
+
+ MUCInviteEvent::ref inviteEvent = boost::make_shared<MUCInviteEvent>(toJID_, invite->getJID(), invite->getReason(), invite->getPassword(), true);
+ handleGeneralMUCInvitation(inviteEvent);
}
void ChatControllerBase::handleMediatedMUCInvitation(Message::ref message) {
MUCUserPayload::Invite invite = *message->getPayload<MUCUserPayload>()->getInvite();
JID from = message->getFrom();
std::string reason;
if (!invite.reason.empty()) {
reason = invite.reason;
}
std::string password;
if (message->getPayload<MUCUserPayload>()->getPassword()) {
password = *message->getPayload<MUCUserPayload>()->getPassword();
}
- chatWindow_->addMUCInvitation(from, reason, password, false);
+
+ MUCInviteEvent::ref inviteEvent = boost::make_shared<MUCInviteEvent>(invite.from, from, reason, password, false);
+ handleGeneralMUCInvitation(inviteEvent);
}
}
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index e1034d6..a4d23c0 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -14,18 +14,19 @@
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "Swiften/Network/Timer.h"
#include "Swiften/Network/TimerFactory.h"
#include "Swiften/Elements/Stanza.h"
#include <string>
#include "Swiften/Elements/DiscoInfo.h"
#include "Swift/Controllers/XMPPEvents/MessageEvent.h"
+#include <Swift/Controllers/XMPPEvents/MUCInviteEvent.h>
#include "Swiften/JID/JID.h"
#include "Swiften/Elements/SecurityLabelsCatalog.h"
#include "Swiften/Elements/ErrorPayload.h"
#include "Swiften/Presence/PresenceOracle.h"
#include "Swiften/Queries/IQRouter.h"
#include "Swiften/Base/IDGenerator.h"
namespace Swift {
class IQRouter;
@@ -78,22 +79,23 @@ namespace Swift {
IDGenerator idGenerator_;
std::string lastSentMessageStanzaID_;
void createDayChangeTimer();
void handleSendMessageRequest(const std::string &body, bool isCorrectionMessage);
void handleAllMessagesRead();
void handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog>, ErrorPayload::ref error);
void handleDayChangeTick();
void handleMUCInvitation(Message::ref message);
void handleMediatedMUCInvitation(Message::ref message);
+ void handleGeneralMUCInvitation(MUCInviteEvent::ref event);
protected:
JID selfJID_;
- std::vector<boost::shared_ptr<MessageEvent> > unreadMessages_;
+ std::vector<boost::shared_ptr<StanzaEvent> > unreadMessages_;
StanzaChannel* stanzaChannel_;
IQRouter* iqRouter_;
ChatWindowFactory* chatWindowFactory_;
ChatWindow* chatWindow_;
JID toJID_;
bool labelsEnabled_;
std::map<JID, std::string> lastMessagesUIID_;
PresenceOracle* presenceOracle_;
AvatarManager* avatarManager_;
diff --git a/Swift/Controllers/EventNotifier.cpp b/Swift/Controllers/EventNotifier.cpp
index e643ab3..a4edabf 100644
--- a/Swift/Controllers/EventNotifier.cpp
+++ b/Swift/Controllers/EventNotifier.cpp
@@ -12,18 +12,19 @@
#include <Swiften/Base/format.h>
#include "Swift/Controllers/XMPPEvents/EventController.h"
#include "SwifTools/Notifier/Notifier.h"
#include "Swiften/Avatars/AvatarManager.h"
#include "Swiften/Client/NickResolver.h"
#include "Swiften/JID/JID.h"
#include "Swift/Controllers/XMPPEvents/MessageEvent.h"
#include "Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h"
#include "Swift/Controllers/XMPPEvents/ErrorEvent.h"
+#include "Swift/Controllers/XMPPEvents/MUCInviteEvent.h"
#include "Swift/Controllers/Settings/SettingsProvider.h"
namespace Swift {
EventNotifier::EventNotifier(EventController* eventController, Notifier* notifier, AvatarManager* avatarManager, NickResolver* nickResolver) : eventController(eventController), notifier(notifier), avatarManager(avatarManager), nickResolver(nickResolver) {
eventController->onEventQueueEventAdded.connect(boost::bind(&EventNotifier::handleEventAdded, this, _1));
}
EventNotifier::~EventNotifier() {
@@ -49,17 +50,23 @@ void EventNotifier::handleEventAdded(boost::shared_ptr<StanzaEvent> event) {
else if(boost::shared_ptr<SubscriptionRequestEvent> subscriptionEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(event)) {
JID jid = subscriptionEvent->getJID();
std::string title = jid;
std::string message = str(format(QT_TRANSLATE_NOOP("", "%1% wants to add you to his/her contact list")) % nickResolver->jidToNick(jid));
notifier->showMessage(Notifier::SystemMessage, title, message, boost::filesystem::path(), boost::function<void()>());
}
else if(boost::shared_ptr<ErrorEvent> errorEvent = boost::dynamic_pointer_cast<ErrorEvent>(event)) {
notifier->showMessage(Notifier::SystemMessage, QT_TRANSLATE_NOOP("", "Error"), errorEvent->getText(), boost::filesystem::path(), boost::function<void()>());
}
+ else if (boost::shared_ptr<MUCInviteEvent> mucInviteEvent = boost::dynamic_pointer_cast<MUCInviteEvent>(event)) {
+ std::string title = mucInviteEvent->getInviter();
+ std::string message = str(format(QT_TRANSLATE_NOOP("", "%1% has invited you to enter the %2% room")) % nickResolver->jidToNick(mucInviteEvent->getInviter()) % mucInviteEvent->getRoomJID());
+ // FIXME: not show avatar or greyed out avatar for mediated invites
+ notifier->showMessage(Notifier::SystemMessage, title, message, avatarManager->getAvatarPath(mucInviteEvent->getInviter()), boost::bind(&EventNotifier::handleNotificationActivated, this, mucInviteEvent->getInviter()));
+ }
}
void EventNotifier::handleNotificationActivated(JID jid) {
onNotificationActivated(jid);
}
}
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index e7246c6..9305314 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -51,19 +51,19 @@ namespace Swift {
virtual void addSystemMessage(const std::string& message) = 0;
virtual void addPresenceMessage(const std::string& message) = 0;
virtual void addErrorMessage(const std::string& message) = 0;
virtual void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) = 0;
// File transfer related stuff
virtual std::string addFileTransfer(const std::string& senderName, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes) = 0;
virtual void setFileTransferProgress(std::string, const int percentageDone) = 0;
virtual void setFileTransferStatus(std::string, const FileTransferState state, const std::string& msg = "") = 0;
- virtual void addMUCInvitation(const JID& jid, const std::string& reason, const std::string& password, bool direct = true) = 0;
+ virtual void addMUCInvitation(const std::string& senderName, const JID& jid, const std::string& reason, const std::string& password, bool direct = true) = 0;
// message receipts
virtual void setMessageReceiptState(const std::string& id, ChatWindow::ReceiptState state) = 0;
virtual void setContactChatState(ChatState::ChatStateType state) = 0;
virtual void setName(const std::string& name) = 0;
virtual void show() = 0;
virtual void activate() = 0;
virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) = 0;
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index dab1e90..f92bd8b 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -44,19 +44,19 @@ namespace Swift {
virtual void replaceMessage(const std::string&, const std::string&, const boost::posix_time::ptime&) {};
void setAckState(const std::string& /*id*/, AckState /*state*/) {};
virtual void flash() {};
virtual void setAlert(const std::string& /*alertText*/, const std::string& /*buttonText*/) {};
virtual void cancelAlert() {};
virtual void setCorrectionEnabled(Tristate /*enabled*/) {}
void setAvailableOccupantActions(const std::vector<OccupantAction>&/* actions*/) {}
void setSubject(const std::string& /*subject*/) {}
virtual void showRoomConfigurationForm(Form::ref) {}
- virtual void addMUCInvitation(const JID& /*jid*/, const std::string& /*reason*/, const std::string& /*password*/, bool = true) {};
+ virtual void addMUCInvitation(const std::string& /*senderName*/, const JID& /*jid*/, const std::string& /*reason*/, const std::string& /*password*/, bool = true) {};
virtual void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&) {}
virtual void setAvailableRoomActions(const std::vector<RoomAction> &) {};
std::string name_;
std::string lastMessageBody_;
std::vector<SecurityLabelsCatalog::Item> labels_;
bool labelsEnabled_;
SecurityLabelsCatalog::Item label_;
};
diff --git a/Swift/Controllers/XMPPEvents/EventController.cpp b/Swift/Controllers/XMPPEvents/EventController.cpp
index 98fd634..0808aa0 100644
--- a/Swift/Controllers/XMPPEvents/EventController.cpp
+++ b/Swift/Controllers/XMPPEvents/EventController.cpp
@@ -7,35 +7,37 @@
#include "Swift/Controllers/XMPPEvents/EventController.h"
#include <boost/bind.hpp>
#include <algorithm>
#include <Swiften/Base/foreach.h>
#include "Swift/Controllers/XMPPEvents/MessageEvent.h"
#include "Swift/Controllers/XMPPEvents/ErrorEvent.h"
#include "Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h"
+#include "Swift/Controllers/XMPPEvents/MUCInviteEvent.h"
namespace Swift {
EventController::EventController() {
}
EventController::~EventController() {
foreach(boost::shared_ptr<StanzaEvent> event, events_) {
event->onConclusion.disconnect(boost::bind(&EventController::handleEventConcluded, this, event));
}
}
void EventController::handleIncomingEvent(boost::shared_ptr<StanzaEvent> sourceEvent) {
boost::shared_ptr<MessageEvent> messageEvent = boost::dynamic_pointer_cast<MessageEvent>(sourceEvent);
boost::shared_ptr<SubscriptionRequestEvent> subscriptionEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(sourceEvent);
boost::shared_ptr<ErrorEvent> errorEvent = boost::dynamic_pointer_cast<ErrorEvent>(sourceEvent);
- if ((messageEvent && messageEvent->isReadable()) || subscriptionEvent || errorEvent) {
+ boost::shared_ptr<MUCInviteEvent> mucInviteEvent = boost::dynamic_pointer_cast<MUCInviteEvent>(sourceEvent);
+ if ((messageEvent && messageEvent->isReadable()) || subscriptionEvent || errorEvent || mucInviteEvent) {
events_.push_back(sourceEvent);
sourceEvent->onConclusion.connect(boost::bind(&EventController::handleEventConcluded, this, sourceEvent));
onEventQueueLengthChange(events_.size());
onEventQueueEventAdded(sourceEvent);
if (sourceEvent->getConcluded()) {
handleEventConcluded(sourceEvent);
}
}
}
diff --git a/Swift/Controllers/XMPPEvents/MUCInviteEvent.h b/Swift/Controllers/XMPPEvents/MUCInviteEvent.h
new file mode 100644
index 0000000..0b430cd
--- /dev/null
+++ b/Swift/Controllers/XMPPEvents/MUCInviteEvent.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+
+ class MUCInviteEvent : public StanzaEvent {
+ public:
+ typedef boost::shared_ptr<MUCInviteEvent> ref;
+
+ public:
+ MUCInviteEvent(const JID& inviter, const JID& roomJID, const std::string& reason, const std::string& password, bool direct) : inviter_(inviter), roomJID_(roomJID), reason_(reason), password_(password), direct_(direct) {}
+
+ const JID& getInviter() const { return inviter_; }
+ const JID& getRoomJID() const { return roomJID_; }
+ const std::string& getReason() const { return reason_; }
+ const std::string& getPassword() const { return password_; }
+ bool getDirect() const { return direct_; }
+
+ private:
+ JID inviter_;
+ JID roomJID_;
+ std::string reason_;
+ std::string password_;
+ bool direct_;
+ };
+}
diff --git a/Swift/QtUI/EventViewer/EventDelegate.cpp b/Swift/QtUI/EventViewer/EventDelegate.cpp
index 79b8854..9ecdd34 100644
--- a/Swift/QtUI/EventViewer/EventDelegate.cpp
+++ b/Swift/QtUI/EventViewer/EventDelegate.cpp
@@ -5,57 +5,62 @@
*/
#include "EventDelegate.h"
#include <QDebug>
#include "Swift/Controllers/XMPPEvents/MessageEvent.h"
#include "Swift/Controllers/XMPPEvents/ErrorEvent.h"
#include "Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h"
+#include "Swift/Controllers/XMPPEvents/MUCInviteEvent.h"
namespace Swift {
-EventDelegate::EventDelegate() : QStyledItemDelegate(), messageDelegate_(QtEvent::SenderRole, Qt::DisplayRole, false), subscriptionDelegate_(QtEvent::SenderRole, Qt::DisplayRole, true), errorDelegate_(QtEvent::SenderRole, Qt::DisplayRole, true) {
+EventDelegate::EventDelegate() : QStyledItemDelegate(), messageDelegate_(QtEvent::SenderRole, Qt::DisplayRole, false), subscriptionDelegate_(QtEvent::SenderRole, Qt::DisplayRole, true), errorDelegate_(QtEvent::SenderRole, Qt::DisplayRole, true), mucInviteDelegate_(QtEvent::SenderRole, Qt::DisplayRole, false) {
}
QSize EventDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index ) const {
QtEvent* item = static_cast<QtEvent*>(index.internalPointer());
if (!item) {
return QStyledItemDelegate::sizeHint(option, index);
}
switch (getEventType(item->getEvent())) {
case MessageEventType: return messageDelegate_.sizeHint(option, item);
case SubscriptionEventType: return subscriptionDelegate_.sizeHint(option, item);
case ErrorEventType: return errorDelegate_.sizeHint(option, item);
+ case MUCInviteEventType: return mucInviteDelegate_.sizeHint(option, item);
default: return QStyledItemDelegate::sizeHint(option, index);
}
}
void EventDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
QtEvent* item = static_cast<QtEvent*>(index.internalPointer());
if (!item) {
QStyledItemDelegate::paint(painter, option, index);
return;
}
switch (getEventType(item->getEvent())) {
case MessageEventType: messageDelegate_.paint(painter, option, item);break;
case SubscriptionEventType: subscriptionDelegate_.paint(painter, option, item);break;
case ErrorEventType: errorDelegate_.paint(painter, option, item);break;
+ case MUCInviteEventType: mucInviteDelegate_.paint(painter, option, item);break;
default: QStyledItemDelegate::paint(painter, option, index);
}
}
EventType EventDelegate::getEventType(boost::shared_ptr<StanzaEvent> event) const {
boost::shared_ptr<MessageEvent> messageEvent = boost::dynamic_pointer_cast<MessageEvent>(event);
if (messageEvent) return MessageEventType;
boost::shared_ptr<SubscriptionRequestEvent> subscriptionEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(event);
if (subscriptionEvent) return SubscriptionEventType;
boost::shared_ptr<ErrorEvent> errorEvent = boost::dynamic_pointer_cast<ErrorEvent>(event);
if (errorEvent) return ErrorEventType;
+ boost::shared_ptr<MUCInviteEvent> mucInviteEvent = boost::dynamic_pointer_cast<MUCInviteEvent>(event);
+ if (mucInviteEvent) return MUCInviteEventType;
//I don't know what this is.
assert(false);
return MessageEventType;
}
}
diff --git a/Swift/QtUI/EventViewer/EventDelegate.h b/Swift/QtUI/EventViewer/EventDelegate.h
index 2ad741c..1ebaff2 100644
--- a/Swift/QtUI/EventViewer/EventDelegate.h
+++ b/Swift/QtUI/EventViewer/EventDelegate.h
@@ -6,25 +6,26 @@
#pragma once
#include <QStyledItemDelegate>
#include "Swift/QtUI/Roster/DelegateCommons.h"
#include "Swift/QtUI/EventViewer/TwoLineDelegate.h"
namespace Swift {
- enum EventType {MessageEventType, SubscriptionEventType, ErrorEventType};
+ enum EventType {MessageEventType, SubscriptionEventType, ErrorEventType, MUCInviteEventType};
class EventDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
EventDelegate();
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
private:
EventType getEventType(boost::shared_ptr<StanzaEvent> event) const;
DelegateCommons common_;
TwoLineDelegate messageDelegate_;
TwoLineDelegate subscriptionDelegate_;
TwoLineDelegate errorDelegate_;
+ TwoLineDelegate mucInviteDelegate_;
};
}
diff --git a/Swift/QtUI/EventViewer/QtEvent.cpp b/Swift/QtUI/EventViewer/QtEvent.cpp
index e7ea473..3c6f16c 100644
--- a/Swift/QtUI/EventViewer/QtEvent.cpp
+++ b/Swift/QtUI/EventViewer/QtEvent.cpp
@@ -5,18 +5,19 @@
*/
#include "Swift/QtUI/EventViewer/QtEvent.h"
#include <QDateTime>
#include "Swift/Controllers/XMPPEvents/MessageEvent.h"
#include "Swift/Controllers/XMPPEvents/ErrorEvent.h"
#include "Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h"
+#include "Swift/Controllers/XMPPEvents/MUCInviteEvent.h"
#include "Swift/QtUI/QtSwiftUtil.h"
namespace Swift {
QtEvent::QtEvent(boost::shared_ptr<StanzaEvent> event, bool active) : event_(event) {
active_ = active;
}
@@ -41,18 +42,22 @@ QString QtEvent::sender() {
}
boost::shared_ptr<SubscriptionRequestEvent> subscriptionRequestEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(event_);
if (subscriptionRequestEvent) {
return P2QSTRING(subscriptionRequestEvent->getJID().toBare().toString());
}
boost::shared_ptr<ErrorEvent> errorEvent = boost::dynamic_pointer_cast<ErrorEvent>(event_);
if (errorEvent) {
return P2QSTRING(errorEvent->getJID().toBare().toString());
}
+ boost::shared_ptr<MUCInviteEvent> mucInviteEvent = boost::dynamic_pointer_cast<MUCInviteEvent>(event_);
+ if (mucInviteEvent) {
+ return P2QSTRING(mucInviteEvent->getInviter().toString());
+ }
return "";
}
QString QtEvent::text() {
boost::shared_ptr<MessageEvent> messageEvent = boost::dynamic_pointer_cast<MessageEvent>(event_);
if (messageEvent) {
return P2QSTRING(messageEvent->getStanza()->getBody());
}
boost::shared_ptr<SubscriptionRequestEvent> subscriptionRequestEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(event_);
@@ -65,13 +70,18 @@ QString QtEvent::text() {
else {
message = QString(QObject::tr("%1 would like to add you to their contact list, saying '%2'")).arg(subscriptionRequestEvent->getJID().toBare().toString().c_str()).arg(reason.c_str());
}
return message;
}
boost::shared_ptr<ErrorEvent> errorEvent = boost::dynamic_pointer_cast<ErrorEvent>(event_);
if (errorEvent) {
return P2QSTRING(errorEvent->getText());
}
+ boost::shared_ptr<MUCInviteEvent> mucInviteEvent = boost::dynamic_pointer_cast<MUCInviteEvent>(event_);
+ if (mucInviteEvent) {
+ QString message = QString(QObject::tr("%1 has invited you to enter the %2 room.")).arg(P2QSTRING(mucInviteEvent->getInviter().toBare().toString())).arg(P2QSTRING(mucInviteEvent->getRoomJID().toString()));
+ return message;
+ }
return "";
}
}
diff --git a/Swift/QtUI/EventViewer/QtEventWindow.cpp b/Swift/QtUI/EventViewer/QtEventWindow.cpp
index fdc0194..35473b6 100644
--- a/Swift/QtUI/EventViewer/QtEventWindow.cpp
+++ b/Swift/QtUI/EventViewer/QtEventWindow.cpp
@@ -10,18 +10,19 @@
#include <QtDebug>
#include <QBoxLayout>
#include <QPushButton>
#include <QMessageBox>
#include "Swift/Controllers/XMPPEvents/MessageEvent.h"
#include "Swift/Controllers/XMPPEvents/ErrorEvent.h"
#include "Swift/QtUI/QtSubscriptionRequestWindow.h"
#include "Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h"
+#include "Swift/Controllers/XMPPEvents/MUCInviteEvent.h"
#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
#include "Swiften/Base/Platform.h"
namespace Swift {
QtEventWindow::QtEventWindow(UIEventStream* eventStream) : EventWindow(false) {
@@ -69,29 +70,33 @@ void QtEventWindow::handleReadClicked() {
return;
}
handleItemActivated(index);
}
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());
+ boost::shared_ptr<MUCInviteEvent> mucInviteEvent = boost::dynamic_pointer_cast<MUCInviteEvent>(event->getEvent());
boost::shared_ptr<ErrorEvent> errorEvent = boost::dynamic_pointer_cast<ErrorEvent>(event->getEvent());
-
+
if (messageEvent) {
if (messageEvent->getStanza()->getType() == Message::Groupchat) {
eventStream_->send(boost::shared_ptr<UIEvent>(new JoinMUCUIEvent(messageEvent->getStanza()->getFrom().toBare(), messageEvent->getStanza()->getTo().getResource())));
} else {
eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(messageEvent->getStanza()->getFrom())));
}
} else if (subscriptionEvent) {
QtSubscriptionRequestWindow* window = QtSubscriptionRequestWindow::getWindow(subscriptionEvent, this);
window->show();
+ } else if (mucInviteEvent) {
+ eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(mucInviteEvent->getInviter())));
+ mucInviteEvent->conclude();
} else {
if (errorEvent) {
errorEvent->conclude();
}
QMessageBox msgBox;
msgBox.setText(model_->data(item, Qt::DisplayRole).toString());
msgBox.exec();
}
diff --git a/Swift/QtUI/QtChatView.cpp b/Swift/QtUI/QtChatView.cpp
index db00ba0..b0c4e09 100644
--- a/Swift/QtUI/QtChatView.cpp
+++ b/Swift/QtUI/QtChatView.cpp
@@ -16,18 +16,19 @@
#include <QStackedWidget>
#include <QTimer>
#include <QMessageBox>
#include <QApplication>
#include <Swiften/Base/Log.h>
#include "QtWebView.h"
#include "QtChatTheme.h"
+#include "QtChatWindow.h"
#include "QtSwiftUtil.h"
namespace Swift {
QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent) : QWidget(parent), fontSizeSteps_(0) {
theme_ = theme;
QVBoxLayout* mainLayout = new QVBoxLayout(this);
@@ -320,43 +321,51 @@ void QtChatView::setFileTransferProgress(QString id, const int percentageDone) {
void QtChatView::setFileTransferStatus(QString id, const ChatWindow::FileTransferState state, const QString& /* msg */) {
QWebElement ftElement = findDivElementWithID(document_, id);
if (ftElement.isNull()) {
SWIFT_LOG(debug) << "Tried to access FT UI via invalid id! id = " << Q2PSTRING(id) << std::endl;
return;
}
QString newInnerHTML = "";
if (state == ChatWindow::WaitingForAccept) {
- newInnerHTML = "Waiting for other side to accept the transfer.<br/>"
- "<input id=\"discard\" type=\"submit\" value=\"Cancel\" onclick=\"filetransfer.cancel(\'" + id + "\');\">";
+ newInnerHTML = "Waiting for other side to accept the transfer.<br/>" +
+ QtChatWindow::buildChatWindowButton(tr("Cancel"), QtChatWindow::ButtonFileTransferCancel, id);
}
if (state == ChatWindow::Negotiating) {
// replace with text "Negotiaging" + Cancel button
- newInnerHTML = "Negotiating...<br/>"
- "<input id=\"discard\" type=\"submit\" value=\"Cancel\" onclick=\"filetransfer.cancel(\'" + id + "\');\">";
+ newInnerHTML = "Negotiating...<br/>" +
+ QtChatWindow::buildChatWindowButton(tr("Cancel"), QtChatWindow::ButtonFileTransferCancel, id);
}
else if (state == ChatWindow::Transferring) {
// progress bar + Cancel Button
newInnerHTML = "<div style=\"position: relative; width: 90%; height: 20px; border: 2px solid grey; -webkit-border-radius: 10px;\">"
"<div class=\"progressbar\" style=\"width: 0%; height: 100%; background: #AAA; -webkit-border-radius: 6px;\">"
"<div class=\"progressbar-value\" style=\"position: absolute; top: 0px; left: 0px; width: 100%; text-align: center; padding-top: 2px;\">"
"0%"
"</div>"
"</div>"
- "</div>"
- "<input id=\"discard\" type=\"submit\" value=\"Cancel\" onclick=\"filetransfer.cancel(\'" + id + "\');\">";
+ "</div>" +
+ QtChatWindow::buildChatWindowButton(tr("Cancel"), QtChatWindow::ButtonFileTransferCancel, id);
}
else if (state == ChatWindow::Canceled) {
newInnerHTML = "Transfer has been canceled!";
}
else if (state == ChatWindow::Finished) {
// text "Successful transfer"
newInnerHTML = "Transfer completed successfully.";
}
else if (state == ChatWindow::FTFailed) {
newInnerHTML = "Transfer failed.";
}
ftElement.setInnerXml(newInnerHTML);
}
+void QtChatView::setMUCInvitationJoined(QString id) {
+ QWebElement divElement = findDivElementWithID(document_, id);
+ QWebElement buttonElement = divElement.findFirst("input#mucinvite");
+ if (!buttonElement.isNull()) {
+ buttonElement.setAttribute("value", tr("Return to room"));
+ }
+}
+
}
diff --git a/Swift/QtUI/QtChatView.h b/Swift/QtUI/QtChatView.h
index 0cc521a..6b40c05 100644
--- a/Swift/QtUI/QtChatView.h
+++ b/Swift/QtUI/QtChatView.h
@@ -36,18 +36,19 @@ namespace Swift {
void rememberScrolledToBottom();
void setAckXML(const QString& id, const QString& xml);
void setReceiptXML(const QString& id, const QString& xml);
void displayReceiptInfo(const QString& id, bool showIt);
QString getLastSentMessage();
void addToJSEnvironment(const QString&, QObject*);
void setFileTransferProgress(QString id, const int percentageDone);
void setFileTransferStatus(QString id, const ChatWindow::FileTransferState state, const QString& msg);
+ void setMUCInvitationJoined(QString id);
signals:
void gotFocus();
void fontResized(int);
public slots:
void copySelectionToClipboard();
void scrollToBottom();
void handleLinkClicked(const QUrl&);
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index c6519ba..cf520ee 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -16,19 +16,19 @@
#include "SystemMessageSnippet.h"
#include "QtTextEdit.h"
#include "QtSettingsProvider.h"
#include "QtScaledAvatarCache.h"
#include "SwifTools/TabComplete.h"
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
-#include "QtFileTransferJSBridge.h"
+#include "QtChatWindowJSBridge.h"
#include <boost/cstdint.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <QLabel>
#include <QMessageBox>
#include <QInputDialog>
#include <QApplication>
@@ -44,19 +44,26 @@
#include <QUrl>
#include <QPushButton>
#include <QFileDialog>
#include <QMenu>
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <QDebug>
namespace Swift {
-QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageWasSystem_(false), previousMessageWasPresence_(false), previousMessageWasFileTransfer_(false), eventStream_(eventStream) {
+
+const QString QtChatWindow::ButtonFileTransferCancel = QString("filetransfer-cancel");
+const QString QtChatWindow::ButtonFileTransferSetDescription = QString("filetransfer-setdescription");
+const QString QtChatWindow::ButtonFileTransferSendRequest = QString("filetransfer-sendrequest");
+const QString QtChatWindow::ButtonFileTransferAcceptRequest = QString("filetransfer-acceptrequest");
+const QString QtChatWindow::ButtonMUCInvite = QString("mucinvite");
+
+QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageKind_(PreviosuMessageWasNone), eventStream_(eventStream) {
settings_ = settings;
unreadCount_ = 0;
idCounter_ = 0;
inputEnabled_ = true;
completer_ = NULL;
affiliationEditor_ = NULL;
theme_ = theme;
isCorrection_ = false;
correctionEnabled_ = Maybe;
@@ -152,38 +159,39 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
messageLog_->setFocusProxy(input_);
connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(qAppFocusChanged(QWidget*, QWidget*)));
connect(messageLog_, SIGNAL(gotFocus()), input_, SLOT(setFocus()));
resize(400,300);
connect(messageLog_, SIGNAL(fontResized(int)), this, SIGNAL(fontResized(int)));
treeWidget_->onSomethingSelectedChanged.connect(boost::bind(&QtChatWindow::handleOccupantSelectionChanged, this, _1));
treeWidget_->onOccupantActionSelected.connect(boost::bind(boost::ref(onOccupantActionSelected), _1, _2));
- fileTransferJS = new QtFileTransferJSBridge();
- messageLog_->addToJSEnvironment("filetransfer", fileTransferJS);
- connect(fileTransferJS, SIGNAL(setDescription(QString)), this, SLOT(handleFileTransferSetDescription(QString)));
- connect(fileTransferJS, SIGNAL(sendRequest(QString)), this, SLOT(handleFileTransferStart(QString)));
- connect(fileTransferJS, SIGNAL(acceptRequest(QString, QString)), this, SLOT(handleFileTransferAccept(QString, QString)));
- connect(fileTransferJS, SIGNAL(cancel(QString)), this, SLOT(handleFileTransferCancel(QString)));
+ jsBridge = new QtChatWindowJSBridge();
+ messageLog_->addToJSEnvironment("chatwindow", jsBridge);
+ connect(jsBridge, SIGNAL(buttonClicked(QString,QString,QString,QString)), this, SLOT(handleHTMLButtonClicked(QString,QString,QString,QString)));
}
QtChatWindow::~QtChatWindow() {
- delete fileTransferJS;
+ delete jsBridge;
if (mucConfigurationWindow_) {
delete mucConfigurationWindow_.data();
}
}
void QtChatWindow::handleOccupantSelectionChanged(RosterItem* item) {
onOccupantSelectionChanged(dynamic_cast<ContactRosterItem*>(item));
}
+bool QtChatWindow::appendToPreviousCheck(QtChatWindow::PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf) const {
+ return previousMessageKind_ == messageKind && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_&& previousSenderName_ == P2QSTRING(senderName)));
+}
+
void QtChatWindow::handleFontResized(int fontSizeSteps) {
messageLog_->resizeFont(fontSizeSteps);
}
void QtChatWindow::handleAlertButtonClicked() {
onAlertButtonClicked();
}
void QtChatWindow::setAlert(const std::string& alertText, const std::string& buttonText) {
@@ -442,34 +450,32 @@ std::string QtChatWindow::addMessage(const std::string &message, const std::stri
htmlString += QString("%3</span> ").arg(Qt::escape(P2QSTRING(label->getDisplayMarking())));
}
QString messageHTML(Qt::escape(P2QSTRING(message)));
messageHTML = P2QSTRING(Linkify::linkify(Q2PSTRING(messageHTML)));
messageHTML.replace("\n","<br/>");
QString styleSpanStart = style == "" ? "" : "<span style=\"" + style + "\">";
QString styleSpanEnd = style == "" ? "" : "</span>";
htmlString += styleSpanStart + messageHTML + styleSpanEnd;
- bool appendToPrevious = !previousMessageWasFileTransfer_ && !previousMessageWasSystem_ && !previousMessageWasPresence_ && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_ && previousSenderName_ == P2QSTRING(senderName)));
+ bool appendToPrevious = appendToPreviousCheck(PreviousMessageWasMessage, senderName, senderIsSelf);
if (lastLineTracker_.getShouldMoveLastLine()) {
/* should this be queued? */
messageLog_->addLastSeenLine();
/* if the line is added we should break the snippet */
appendToPrevious = false;
}
QString qAvatarPath = scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.png" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded();
std::string id = "id" + boost::lexical_cast<std::string>(idCounter_++);
messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id))));
previousMessageWasSelf_ = senderIsSelf;
previousSenderName_ = P2QSTRING(senderName);
- previousMessageWasSystem_ = false;
- previousMessageWasPresence_ = false;
- previousMessageWasFileTransfer_ = false;
+ previousMessageKind_ = PreviousMessageWasMessage;
return id;
}
void QtChatWindow::flash() {
emit requestFlash();
}
void QtChatWindow::setAckState(std::string const& id, ChatWindow::AckState state) {
QString xml;
@@ -513,124 +519,140 @@ std::string formatSize(const boost::uintmax_t bytes) {
int power = 0;
double engBytes = bytes;
while (engBytes >= 1000) {
++power;
engBytes = engBytes / 1000.0;
}
return str( boost::format("%.1lf %sB") % engBytes % (power > 0 ? siPrefix[power-1] : "") );
}
+QString QtChatWindow::buildChatWindowButton(const QString& name, const QString& id, const QString& arg1, const QString& arg2, const QString& arg3) {
+ QRegExp regex("[A-Za-z][A-Za-z0-9\\-\\_]+");
+ Q_ASSERT(regex.exactMatch(id));
+ QString html = QString("<input id='%2' type='submit' value='%1' onclick='chatwindow.buttonClicked(\"%2\", \"%3\", \"%4\", \"%5\");' />").arg(name).arg(id).arg(arg1).arg(arg2).arg(arg3);
+ return html;
+}
+
std::string QtChatWindow::addFileTransfer(const std::string& senderName, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes) {
qDebug() << "addFileTransfer";
- std::string ft_id = "ft" + boost::lexical_cast<std::string>(idCounter_++);
+ QString ft_id = QString("ft%1").arg(P2QSTRING(boost::lexical_cast<std::string>(idCounter_++)));
- std::string htmlString;
+ QString htmlString;
+ QString formattedFileSize = P2QSTRING(formatSize(sizeInBytes));
if (senderIsSelf) {
// outgoing
- htmlString = "Send file: " + filename + " ( " + formatSize(sizeInBytes) + ") </br>" +
+ htmlString = tr("Send file)") + ": " + P2QSTRING(filename) + " ( " + formattedFileSize + ") </br>" +
"<div id='" + ft_id + "'>" +
- "<input id='discard' type='submit' value='Cancel' onclick='filetransfer.cancel(\"" + ft_id + "\");' />" +
- "<input id='description' type='submit' value='Set Description' onclick='filetransfer.setDescription(\"" + ft_id + "\");' />" +
- "<input id='send' type='submit' value='Send' onclick='filetransfer.sendRequest(\"" + ft_id + "\");' />" +
+ buildChatWindowButton(tr("Cancel"), ButtonFileTransferCancel, ft_id) +
+ buildChatWindowButton(tr("Set Description"), ButtonFileTransferSetDescription, ft_id) +
+ buildChatWindowButton(tr("Send"), ButtonFileTransferSendRequest, ft_id) +
"</div>";
} else {
// incoming
- htmlString = "Receiving file: " + filename + " ( " + formatSize(sizeInBytes) + ") </br>" +
+ htmlString = "Receiving file: " + P2QSTRING(filename) + " ( " + formattedFileSize + ") </br>" +
"<div id='" + ft_id + "'>" +
- "<input id='discard' type='submit' value='Cancel' onclick='filetransfer.cancel(\"" + ft_id + "\");' />" +
- "<input id='accept' type='submit' value='Accept' onclick='filetransfer.acceptRequest(\"" + ft_id + "\", \"" + filename + "\");' />" +
+ buildChatWindowButton(tr("Cancel"), ButtonFileTransferCancel, ft_id) +
+ buildChatWindowButton(tr("Accept"), ButtonFileTransferAcceptRequest, ft_id, P2QSTRING(filename)) +
"</div>";
}
//addMessage(message, senderName, senderIsSelf, boost::shared_ptr<SecurityLabel>(), "", boost::posix_time::second_clock::local_time());
- bool appendToPrevious = !previousMessageWasFileTransfer_ && !previousMessageWasSystem_ && !previousMessageWasPresence_ && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_ && previousSenderName_ == P2QSTRING(senderName)));
+ bool appendToPrevious = appendToPreviousCheck(PreviousMessageWasFileTransfer, senderName, senderIsSelf);
if (lastLineTracker_.getShouldMoveLastLine()) {
/* should this be queued? */
messageLog_->addLastSeenLine();
/* if the line is added we should break the snippet */
appendToPrevious = false;
}
QString qAvatarPath = "qrc:/icons/avatar.png";
std::string id = "ftmessage" + boost::lexical_cast<std::string>(idCounter_++);
- messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(QString::fromStdString(htmlString), Qt::escape(P2QSTRING(senderName)), B2QDATE(boost::posix_time::second_clock::local_time()), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id))));
-
+ messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(boost::posix_time::second_clock::local_time()), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id))));
- return ft_id;
+ previousMessageWasSelf_ = senderIsSelf;
+ previousSenderName_ = P2QSTRING(senderName);
+ previousMessageKind_ = PreviousMessageWasFileTransfer;
+ return Q2PSTRING(ft_id);
}
void QtChatWindow::setFileTransferProgress(std::string id, const int percentageDone) {
messageLog_->setFileTransferProgress(QString::fromStdString(id), percentageDone);
}
void QtChatWindow::setFileTransferStatus(std::string id, const FileTransferState state, const std::string& msg) {
messageLog_->setFileTransferStatus(QString::fromStdString(id), state, QString::fromStdString(msg));
}
-void QtChatWindow::handleFileTransferCancel(QString id) {
- qDebug() << "QtChatWindow::handleFileTransferCancel(" << id << ")";
- onFileTransferCancel(Q2PSTRING(id));
-}
-
-void QtChatWindow::handleFileTransferSetDescription(QString id) {
- bool ok = false;
- QString text = QInputDialog::getText(this, tr("File transfer description"),
- tr("Description:"), QLineEdit::Normal, "", &ok);
- if (ok) {
- descriptions[id] = text;
+void QtChatWindow::handleHTMLButtonClicked(QString id, QString arg1, QString arg2, QString arg3) {
+ if (id.startsWith(ButtonFileTransferCancel)) {
+ QString ft_id = arg1;
+ onFileTransferCancel(Q2PSTRING(ft_id));
}
-}
-
-void QtChatWindow::handleFileTransferStart(QString id) {
- qDebug() << "QtChatWindow::handleFileTransferStart(" << id << ")";
-
- QString text = descriptions.find(id) == descriptions.end() ? QString() : descriptions[id];
- onFileTransferStart(Q2PSTRING(id), Q2PSTRING(text));
-}
+ else if (id.startsWith(ButtonFileTransferSetDescription)) {
+ QString ft_id = arg1;
+ bool ok = false;
+ QString text = QInputDialog::getText(this, tr("File transfer description"),
+ tr("Description:"), QLineEdit::Normal, "", &ok);
+ if (ok) {
+ descriptions[ft_id] = text;
+ }
+ }
+ else if (id.startsWith(ButtonFileTransferSendRequest)) {
+ QString ft_id = arg1;
+ QString text = descriptions.find(ft_id) == descriptions.end() ? QString() : descriptions[ft_id];
+ onFileTransferStart(Q2PSTRING(ft_id), Q2PSTRING(text));
+ }
+ else if (id.startsWith(ButtonFileTransferAcceptRequest)) {
+ QString ft_id = arg1;
+ QString filename = arg2;
-void QtChatWindow::handleFileTransferAccept(QString id, QString filename) {
- qDebug() << "QtChatWindow::handleFileTransferAccept(" << id << ", " << filename << ")";
+ QString path = QFileDialog::getSaveFileName(this, tr("Save File"), filename);
+ if (!path.isEmpty()) {
+ onFileTransferAccept(Q2PSTRING(ft_id), Q2PSTRING(path));
+ }
+ }
+ else if (id.startsWith(ButtonMUCInvite)) {
+ QString roomJID = arg1;
+ QString password = arg2;
+ QString elementID = arg3;
- QString path = QFileDialog::getSaveFileName(this, tr("Save File"), filename);
- if (!path.isEmpty()) {
- onFileTransferAccept(Q2PSTRING(id), Q2PSTRING(path));
+ eventStream_->send(boost::make_shared<JoinMUCUIEvent>(Q2PSTRING(roomJID), Q2PSTRING(password)));
+ messageLog_->setMUCInvitationJoined(elementID);
+ }
+ else {
+ qDebug() << "Unknown HTML button! ( " << id << " )";
}
}
void QtChatWindow::addErrorMessage(const std::string& errorMessage) {
if (isWidgetSelected()) {
onAllMessagesRead();
}
QString errorMessageHTML(Qt::escape(P2QSTRING(errorMessage)));
errorMessageHTML.replace("\n","<br/>");
messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet("<span class=\"error\">" + errorMessageHTML + "</span>", QDateTime::currentDateTime(), false, theme_)));
previousMessageWasSelf_ = false;
- previousMessageWasSystem_ = true;
- previousMessageWasPresence_ = false;
- previousMessageWasFileTransfer_ = false;
+ previousMessageKind_ = PreviousMessageWasSystem;
}
void QtChatWindow::addSystemMessage(const std::string& message) {
if (isWidgetSelected()) {
onAllMessagesRead();
}
QString messageHTML(Qt::escape(P2QSTRING(message)));
messageHTML = P2QSTRING(Linkify::linkify(Q2PSTRING(messageHTML)));
messageHTML.replace("\n","<br/>");
messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet(messageHTML, QDateTime::currentDateTime(), false, theme_)));
- previousMessageWasSelf_ = false;
- previousMessageWasSystem_ = true;
- previousMessageWasPresence_ = false;
- previousMessageWasFileTransfer_ = false;
+ previousMessageKind_ = PreviousMessageWasSystem;
}
void QtChatWindow::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) {
if (!id.empty()) {
QString messageHTML(Qt::escape(P2QSTRING(message)));
messageHTML = P2QSTRING(Linkify::linkify(Q2PSTRING(messageHTML)));
messageHTML.replace("\n","<br/>");
messageLog_->replaceMessage(messageHTML, P2QSTRING(id), B2QDATE(time));
}
@@ -643,21 +665,19 @@ void QtChatWindow::addPresenceMessage(const std::string& message) {
if (isWidgetSelected()) {
onAllMessagesRead();
}
QString messageHTML(Qt::escape(P2QSTRING(message)));
messageHTML = P2QSTRING(Linkify::linkify(Q2PSTRING(messageHTML)));
messageHTML.replace("\n","<br/>");
messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet(messageHTML, QDateTime::currentDateTime(), false, theme_)));
- previousMessageWasSelf_ = false;
- previousMessageWasSystem_ = false;
- previousMessageWasPresence_ = true;
+ previousMessageKind_ = PreviousMessageWasPresence;
}
void QtChatWindow::returnPressed() {
if (!inputEnabled_) {
return;
}
messageLog_->scrollToBottom();
lastSentMessage_ = QString(input_->toPlainText());
@@ -806,41 +826,41 @@ void QtChatWindow::setAvailableRoomActions(const std::vector<RoomAction> &action
void QtChatWindow::showRoomConfigurationForm(Form::ref form) {
if (mucConfigurationWindow_) {
delete mucConfigurationWindow_.data();
}
mucConfigurationWindow_ = new QtMUCConfigurationWindow(form);
mucConfigurationWindow_->onFormComplete.connect(boost::bind(boost::ref(onConfigureRequest), _1));
mucConfigurationWindow_->onFormCancelled.connect(boost::bind(boost::ref(onConfigurationFormCancelled)));
}
-void QtChatWindow::addMUCInvitation(const JID& jid, const std::string& reason, const std::string& /*password*/, bool direct) {
- bool accepted = false;
- QMessageBox msgBox;
- //FIXME: horrid modal untranslated popup. Fix before release.
- msgBox.setText(QString("You have been invited to the room %1 by %2.").arg(P2QSTRING(jid.toString())).arg(contact_));
- QString reasonString;
+void QtChatWindow::addMUCInvitation(const std::string& senderName, const JID& jid, const std::string& reason, const std::string& password, bool direct) {
+ if (isWidgetSelected()) {
+ onAllMessagesRead();
+ }
+
+ QString htmlString = QObject::tr("You've been invited to enter the %1 room.").arg(P2QSTRING(jid.toString())) + " </br>";
if (!reason.empty()) {
- reasonString = QString("\"%1\"").arg(P2QSTRING(reason));
+ htmlString += QObject::tr("Reason: %1").arg(P2QSTRING(reason)) + "</br>";
}
if (!direct) {
- if (!reasonString.isEmpty()) {
- reasonString += " ";
- }
- reasonString += QString(" (%1 may not have really sent this invitation)").arg(contact_);
- }
- msgBox.setInformativeText(QString("Accept invitation from %1 to enter %2?\n%3").arg(contact_).arg(P2QSTRING(jid.toString())).arg(reasonString));
- msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
- msgBox.setDefaultButton(QMessageBox::Yes);
- int ret = msgBox.exec();
- switch (ret) {
- case QMessageBox::Yes:
- accepted = true;
- break;
- default:
- break;
- }
- if (accepted) {
- eventStream_->send(boost::make_shared<JoinMUCUIEvent>(jid));
+ htmlString += QObject::tr("This person may not have really sent this invitation!") + "</br>";
}
+
+ QString id = QString(ButtonMUCInvite + "%1").arg(P2QSTRING(boost::lexical_cast<std::string>(idCounter_++)));
+
+ htmlString += "<div id='" + id + "'>" +
+ buildChatWindowButton(tr("Accept Invite"), ButtonMUCInvite, Qt::escape(P2QSTRING(jid.toString())), Qt::escape(P2QSTRING(password)), id) +
+ "</div>";
+
+ bool appendToPrevious = appendToPreviousCheck(PreviousMessageWasMUCInvite, senderName, false);
+ if (lastLineTracker_.getShouldMoveLastLine()) {
+ /* should this be queued? */
+ messageLog_->addLastSeenLine();
+ /* if the line is added we should break the snippet */
+ appendToPrevious = false;
+ }
+ QString qAvatarPath = "qrc:/icons/avatar.png";
+
+ messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(boost::posix_time::second_clock::local_time()), qAvatarPath, false, appendToPrevious, theme_, id)));
}
}
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index 189a12a..18eb092 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -25,23 +25,31 @@ class QSplitter;
class QPushButton;
namespace Swift {
class QtChatView;
class QtOccupantListWidget;
class QtChatTheme;
class TreeWidget;
class QtTextEdit;
class UIEventStream;
- class QtFileTransferJSBridge;
+ class QtChatWindowJSBridge;
class SettingsProvider;
class QtChatWindow : public QtTabbable, public ChatWindow {
Q_OBJECT
+
+ public:
+ static const QString ButtonFileTransferCancel;
+ static const QString ButtonFileTransferSetDescription;
+ static const QString ButtonFileTransferSendRequest;
+ static const QString ButtonFileTransferAcceptRequest;
+ static const QString ButtonMUCInvite;
+
public:
QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings);
~QtChatWindow();
std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
std::string addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
void addSystemMessage(const std::string& message);
void addPresenceMessage(const std::string& message);
void addErrorMessage(const std::string& errorMessage);
void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time);
@@ -71,22 +79,24 @@ namespace Swift {
// message receipts
void setMessageReceiptState(const std::string& id, ChatWindow::ReceiptState state);
void flash();
QByteArray getSplitterState();
virtual void setAvailableOccupantActions(const std::vector<OccupantAction>& actions);
void setSubject(const std::string& subject);
void showRoomConfigurationForm(Form::ref);
- void addMUCInvitation(const JID& jid, const std::string& reason, const std::string& password, bool direct = true);
+ void addMUCInvitation(const std::string& senderName, const JID& jid, const std::string& reason, const std::string& password, bool direct = true);
void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&);
void setAvailableRoomActions(const std::vector<RoomAction> &actions);
+ static QString buildChatWindowButton(const QString& name, const QString& id, const QString& arg1 = QString(), const QString& arg2 = QString(), const QString& arg3 = QString());
+
public slots:
void handleChangeSplitterState(QByteArray state);
void handleFontResized(int fontSizeSteps);
void setAlert(const std::string& alertText, const std::string& buttonText = "");
void cancelAlert();
void setCorrectionEnabled(Tristate enabled);
signals:
void geometryChanged();
@@ -107,32 +117,39 @@ namespace Swift {
private slots:
void returnPressed();
void handleInputChanged();
void handleKeyPressEvent(QKeyEvent* event);
void handleSplitterMoved(int pos, int index);
void handleAlertButtonClicked();
void handleActionButtonClicked();
-
- void handleFileTransferCancel(QString id);
- void handleFileTransferSetDescription(QString id);
- void handleFileTransferStart(QString id);
- void handleFileTransferAccept(QString id, QString filename);
+ void handleHTMLButtonClicked(QString id, QString arg1, QString arg2, QString arg3);
void handleAffiliationEditorAccepted();
private:
+ enum PreviousMessageKind {
+ PreviosuMessageWasNone,
+ PreviousMessageWasMessage,
+ PreviousMessageWasSystem,
+ PreviousMessageWasPresence,
+ PreviousMessageWasFileTransfer,
+ PreviousMessageWasMUCInvite
+ };
+
+ private:
void updateTitleWithUnreadCount();
void tabComplete();
void beginCorrection();
void cancelCorrection();
std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time);
void handleOccupantSelectionChanged(RosterItem* item);
+ bool appendToPreviousCheck(PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf) const;
int unreadCount_;
bool contactIsTyping_;
LastLineTracker lastLineTracker_;
QString contact_;
QString lastSentMessage_;
QtChatView* messageLog_;
QtChatTheme* theme_;
QtTextEdit* input_;
@@ -142,28 +159,26 @@ namespace Swift {
QLabel* alertLabel_;
QWidget* alertWidget_;
QPushButton* alertButton_;
TabComplete* completer_;
QLineEdit* subject_;
QPushButton* actionButton_;
std::vector<SecurityLabelsCatalog::Item> availableLabels_;
bool isCorrection_;
bool previousMessageWasSelf_;
- bool previousMessageWasSystem_;
- bool previousMessageWasPresence_;
- bool previousMessageWasFileTransfer_;
+ PreviousMessageKind previousMessageKind_;
QString previousSenderName_;
bool inputClearing_;
UIEventStream* eventStream_;
bool inputEnabled_;
QSplitter *logRosterSplitter_;
Tristate correctionEnabled_;
QString alertStyleSheet_;
std::map<QString, QString> descriptions;
- QtFileTransferJSBridge* fileTransferJS;
+ QtChatWindowJSBridge* jsBridge;
QPointer<QtMUCConfigurationWindow> mucConfigurationWindow_;
QPointer<QtAffiliationEditor> affiliationEditor_;
int idCounter_;
SettingsProvider* settings_;
std::vector<ChatWindow::RoomAction> availableRoomActions_;
};
}
diff --git a/Swift/QtUI/QtFileTransferJSBridge.cpp b/Swift/QtUI/QtChatWindowJSBridge.cpp
index 76c1509..db67d79 100644
--- a/Swift/QtUI/QtFileTransferJSBridge.cpp
+++ b/Swift/QtUI/QtChatWindowJSBridge.cpp
@@ -1,19 +1,19 @@
/*
* Copyright (c) 2011 Tobias Markmann
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
-#include "QtFileTransferJSBridge.h"
+#include "QtChatWindowJSBridge.h"
namespace Swift {
-QtFileTransferJSBridge::QtFileTransferJSBridge() {
+QtChatWindowJSBridge::QtChatWindowJSBridge() {
}
-QtFileTransferJSBridge::~QtFileTransferJSBridge() {
+QtChatWindowJSBridge::~QtChatWindowJSBridge() {
}
-} \ No newline at end of file
+}
diff --git a/Swift/QtUI/QtFileTransferJSBridge.h b/Swift/QtUI/QtChatWindowJSBridge.h
index bd884e5..8e6f0c2 100644
--- a/Swift/QtUI/QtFileTransferJSBridge.h
+++ b/Swift/QtUI/QtChatWindowJSBridge.h
@@ -8,23 +8,19 @@
#include <QObject>
#include <map>
namespace Swift {
class FileTransferController;
-class QtFileTransferJSBridge : public QObject {
+class QtChatWindowJSBridge : public QObject {
Q_OBJECT
public:
- QtFileTransferJSBridge();
- virtual ~QtFileTransferJSBridge();
+ QtChatWindowJSBridge();
+ virtual ~QtChatWindowJSBridge();
signals:
- void discard(QString id);
- void sendRequest(QString id);
- void setDescription(QString id);
- void acceptRequest(QString id, QString filename);
- void cancel(QString id);
+ void buttonClicked(QString id, QString arg1, QString arg2, QString arg3);
};
}
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 0971577..06c5bc4 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -138,19 +138,19 @@ sources = [
"UserSearch/QtUserSearchDetailsPage.cpp",
"UserSearch/QtUserSearchWindow.cpp",
"UserSearch/UserSearchModel.cpp",
"UserSearch/UserSearchDelegate.cpp",
"QtSubscriptionRequestWindow.cpp",
"QtRosterHeader.cpp",
"QtWebView.cpp",
"qrc_DefaultTheme.cc",
"qrc_Swift.cc",
- "QtFileTransferJSBridge.cpp",
+ "QtChatWindowJSBridge.cpp",
"QtMUCConfigurationWindow.cpp",
"QtAffiliationEditor.cpp",
"QtUISettingConstants.cpp"
]
myenv["SWIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift")
if env["PLATFORM"] == "win32" :
res = myenv.RES("#/Swift/resources/Windows/Swift.rc")