summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp31
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h3
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h2
-rw-r--r--Swift/QtUI/QtChatWindow.cpp7
-rw-r--r--Swift/QtUI/QtChatWindow.h2
-rw-r--r--Swift/QtUI/QtHistoryWindow.cpp2
-rw-r--r--Swift/QtUI/Roster/QtOccupantListWidget.cpp15
-rw-r--r--Swift/QtUI/Roster/QtOccupantListWidget.h11
-rw-r--r--Swift/QtUI/Roster/QtRosterWidget.cpp2
-rw-r--r--Swift/QtUI/Roster/QtTreeWidget.cpp30
-rw-r--r--Swift/QtUI/Roster/QtTreeWidget.h22
-rw-r--r--Swift/QtUI/Roster/RosterModel.cpp12
-rw-r--r--Swift/QtUI/Roster/RosterModel.h6
13 files changed, 98 insertions, 47 deletions
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index 14d1767..f83a772 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -72,121 +72,121 @@ MUCController::MUCController (
MUCRegistry* mucRegistry,
HighlightManager* highlightManager,
ChatMessageParser* chatMessageParser,
bool isImpromptu,
AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider,
VCardManager* vcardManager) :
ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false) {
parting_ = true;
joined_ = false;
lastWasPresence_ = false;
shouldJoinOnReconnect_ = true;
doneGettingHistory_ = false;
events_ = uiEventStream;
xmppRoster_ = roster;
roster_ = new Roster(false, true);
rosterVCardProvider_ = new RosterVCardProvider(roster_, vcardManager, JID::WithResource);
completer_ = new TabComplete();
chatWindow_->setRosterModel(roster_);
chatWindow_->setTabComplete(completer_);
chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this));
chatWindow_->onOccupantSelectionChanged.connect(boost::bind(&MUCController::handleWindowOccupantSelectionChanged, this, _1));
chatWindow_->onOccupantActionSelected.connect(boost::bind(&MUCController::handleActionRequestedOnOccupant, this, _1, _2));
chatWindow_->onChangeSubjectRequest.connect(boost::bind(&MUCController::handleChangeSubjectRequest, this, _1));
chatWindow_->onConfigureRequest.connect(boost::bind(&MUCController::handleConfigureRequest, this, _1));
chatWindow_->onConfigurationFormCancelled.connect(boost::bind(&MUCController::handleConfigurationCancelled, this));
chatWindow_->onDestroyRequest.connect(boost::bind(&MUCController::handleDestroyRoomRequest, this));
chatWindow_->onInviteToChat.connect(boost::bind(&MUCController::handleInvitePersonToThisMUCRequest, this, _1));
chatWindow_->onGetAffiliationsRequest.connect(boost::bind(&MUCController::handleGetAffiliationsRequest, this));
chatWindow_->onChangeAffiliationsRequest.connect(boost::bind(&MUCController::handleChangeAffiliationsRequest, this, _1));
muc_->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1));
muc_->onJoinFailed.connect(boost::bind(&MUCController::handleJoinFailed, this, _1));
muc_->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1));
muc_->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));
muc_->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
- muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
- muc_->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
muc_->onRoleChangeFailed.connect(boost::bind(&MUCController::handleOccupantRoleChangeFailed, this, _1, _2, _3));
muc_->onAffiliationListReceived.connect(boost::bind(&MUCController::handleAffiliationListReceived, this, _1, _2));
muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1));
muc_->onConfigurationFormReceived.connect(boost::bind(&MUCController::handleConfigurationFormReceived, this, _1));
highlighter_->setMode(Highlighter::MUCMode);
highlighter_->setNick(nick_);
if (timerFactory) {
loginCheckTimer_ = boost::shared_ptr<Timer>(timerFactory->createTimer(MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS));
loginCheckTimer_->onTick.connect(boost::bind(&MUCController::handleJoinTimeoutTick, this));
loginCheckTimer_->start();
}
if (isImpromptu) {
muc_->onUnlocked.connect(boost::bind(&MUCController::handleRoomUnlocked, this));
- chatWindow_->convertToMUC(true);
+ chatWindow_->convertToMUC(ChatWindow::ImpromptuMUC);
} else {
- chatWindow_->convertToMUC();
+ muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
+ muc_->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
+ chatWindow_->convertToMUC(ChatWindow::StandardMUC);
chatWindow_->setName(muc->getJID().getNode());
}
setOnline(true);
if (avatarManager_ != NULL) {
avatarChangedConnection_ = (avatarManager_->onAvatarChanged.connect(boost::bind(&MUCController::handleAvatarChanged, this, _1)));
}
handleBareJIDCapsChanged(muc->getJID());
eventStream_->onUIEvent.connect(boost::bind(&MUCController::handleUIEvent, this, _1));
}
MUCController::~MUCController() {
eventStream_->onUIEvent.disconnect(boost::bind(&MUCController::handleUIEvent, this, _1));
chatWindow_->setRosterModel(NULL);
delete rosterVCardProvider_;
delete roster_;
if (loginCheckTimer_) {
loginCheckTimer_->stop();
}
chatWindow_->setTabComplete(NULL);
delete completer_;
}
void MUCController::cancelReplaces() {
lastWasPresence_ = false;
}
void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item) {
std::vector<ChatWindow::OccupantAction> actions;
if (item) {
MUCOccupant::Affiliation affiliation = muc_->getOccupant(getNick()).getAffiliation();
MUCOccupant::Role role = muc_->getOccupant(getNick()).getRole();
- if (role == MUCOccupant::Moderator)
+ if (role == MUCOccupant::Moderator && !isImpromptu_)
{
if (affiliation == MUCOccupant::Admin || affiliation == MUCOccupant::Owner) {
actions.push_back(ChatWindow::Ban);
}
actions.push_back(ChatWindow::Kick);
actions.push_back(ChatWindow::MakeModerator);
actions.push_back(ChatWindow::MakeParticipant);
actions.push_back(ChatWindow::MakeVisitor);
}
// Add contact is available only if the real JID is also available
if (muc_->getOccupant(item->getJID().getResource()).getRealJID()) {
actions.push_back(ChatWindow::AddContact);
}
actions.push_back(ChatWindow::ShowProfile);
}
chatWindow_->setAvailableOccupantActions(actions);
}
void MUCController::handleActionRequestedOnOccupant(ChatWindow::OccupantAction action, ContactRosterItem* item) {
JID mucJID = item->getJID();
MUCOccupant occupant = muc_->getOccupant(mucJID.getResource());
JID realJID;
if (occupant.getRealJID()) {
realJID = occupant.getRealJID().get();
}
switch (action) {
case ChatWindow::Kick: muc_->kickOccupant(mucJID);break;
case ChatWindow::Ban: muc_->changeAffiliation(realJID, MUCOccupant::Outcast);break;
case ChatWindow::MakeModerator: muc_->changeOccupantRole(mucJID, MUCOccupant::Moderator);break;
case ChatWindow::MakeParticipant: muc_->changeOccupantRole(mucJID, MUCOccupant::Participant);break;
case ChatWindow::MakeVisitor: muc_->changeOccupantRole(mucJID, MUCOccupant::Visitor);break;
case ChatWindow::AddContact: if (occupant.getRealJID()) events_->send(boost::make_shared<RequestAddUserDialogUIEvent>(realJID, occupant.getNick()));break;
case ChatWindow::ShowProfile: events_->send(boost::make_shared<ShowProfileForRosterItemUIEvent>(mucJID));break;
}
@@ -316,113 +316,122 @@ void MUCController::handleJoinFailed(boost::shared_ptr<ErrorPayload> error) {
default: break;
}
}
errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't join room: %1%.")) % errorMessage);
chatWindow_->addErrorMessage(chatMessageParser_->parseMessageBody(errorMessage));
parting_ = true;
if (!rejoinNick.empty() && renameCounter_ < 10) {
renameCounter_++;
setNick(rejoinNick);
rejoin();
}
}
#pragma clang diagnostic pop
void MUCController::handleJoinComplete(const std::string& nick) {
receivedActivity();
renameCounter_ = 0;
joined_ = true;
std::string joinMessage;
if (isImpromptu_) {
joinMessage = str(format(QT_TRANSLATE_NOOP("", "You have entered chat as %1%.")) % nick);
} else {
joinMessage = str(format(QT_TRANSLATE_NOOP("", "You have entered room %1% as %2%.")) % toJID_.toString() % nick);
}
setNick(nick);
chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(joinMessage), ChatWindow::DefaultDirection);
#ifdef SWIFT_EXPERIMENTAL_HISTORY
addRecentLogs();
#endif
clearPresenceQueue();
shouldJoinOnReconnect_ = true;
setEnabled(true);
- MUCOccupant occupant = muc_->getOccupant(nick);
- setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
+ if (isImpromptu_) {
+ setAvailableRoomActions(MUCOccupant::NoAffiliation, MUCOccupant::Participant);
+ } else {
+ MUCOccupant occupant = muc_->getOccupant(nick);
+ setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
+ }
onUserJoined();
if (isImpromptu_) {
setImpromptuWindowTitle();
}
}
void MUCController::handleAvatarChanged(const JID& jid) {
if (parting_ || !jid.equals(toJID_, JID::WithoutResource)) {
return;
}
roster_->applyOnItems(SetAvatar(jid, avatarManager_->getAvatarPath(jid), JID::WithResource));
}
void MUCController::handleWindowClosed() {
parting_ = true;
shouldJoinOnReconnect_ = false;
muc_->part();
onUserLeft();
}
void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {
if (nick_ != occupant.getNick()) {
completer_->addWord(occupant.getNick());
}
receivedActivity();
JID jid(nickToJID(occupant.getNick()));
JID realJID;
if (occupant.getRealJID()) {
realJID = occupant.getRealJID().get();
}
currentOccupants_.insert(occupant.getNick());
NickJoinPart event(occupant.getNick(), Join);
appendToJoinParts(joinParts_, event);
- std::string groupName(roleToGroupName(occupant.getRole()));
+ MUCOccupant::Role role = MUCOccupant::Participant;
+ MUCOccupant::Affiliation affiliation = MUCOccupant::NoAffiliation;
+ if (!isImpromptu_) {
+ role = occupant.getRole();
+ affiliation = occupant.getAffiliation();
+ }
+ std::string groupName(roleToGroupName(role));
roster_->addContact(jid, realJID, occupant.getNick(), groupName, avatarManager_->getAvatarPath(jid));
- roster_->applyOnItems(SetMUC(jid, occupant.getRole(), occupant.getAffiliation()));
- roster_->getGroup(groupName)->setManualSort(roleToSortName(occupant.getRole()));
+ roster_->applyOnItems(SetMUC(jid, role, affiliation));
+ roster_->getGroup(groupName)->setManualSort(roleToSortName(role));
if (joined_) {
std::string joinString;
- MUCOccupant::Role role = occupant.getRole();
if (role != MUCOccupant::NoRole && role != MUCOccupant::Participant) {
joinString = str(format(QT_TRANSLATE_NOOP("", "%1% has entered the %3% as a %2%.")) % occupant.getNick() % roleToFriendlyName(role) % (isImpromptu_ ? QT_TRANSLATE_NOOP("", "chat") : QT_TRANSLATE_NOOP("", "room")));
}
else {
joinString = str(format(QT_TRANSLATE_NOOP("", "%1% has entered the %2%.")) % occupant.getNick() % (isImpromptu_ ? QT_TRANSLATE_NOOP("", "chat") : QT_TRANSLATE_NOOP("", "room")));
}
if (shouldUpdateJoinParts()) {
updateJoinParts();
} else {
addPresenceMessage(joinString);
}
if (isImpromptu_) {
setImpromptuWindowTitle();
onActivity("");
}
}
if (avatarManager_ != NULL) {
handleAvatarChanged(jid);
}
}
void MUCController::addPresenceMessage(const std::string& message) {
lastWasPresence_ = true;
chatWindow_->addPresenceMessage(chatMessageParser_->parseMessageBody(message), ChatWindow::DefaultDirection);
}
void MUCController::setAvailableRoomActions(const MUCOccupant::Affiliation& affiliation, const MUCOccupant::Role& role)
{
std::vector<ChatWindow::RoomAction> actions;
if (role <= MUCOccupant::Participant) {
actions.push_back(ChatWindow::ChangeSubject);
}
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 0f0062d..771872a 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -60,111 +60,112 @@ namespace Swift {
class ChatTextMessagePart : public ChatMessagePart {
public:
ChatTextMessagePart(const std::string& text) : text(text) {}
std::string text;
};
class ChatURIMessagePart : public ChatMessagePart {
public:
ChatURIMessagePart(const std::string& target) : target(target) {}
std::string target;
};
class ChatEmoticonMessagePart : public ChatMessagePart {
public:
std::string imagePath;
std::string alternativeText;
};
class ChatHighlightingMessagePart : public ChatMessagePart {
public:
std::string foregroundColor;
std::string backgroundColor;
std::string text;
};
enum AckState {Pending, Received, Failed};
enum ReceiptState {ReceiptRequested, ReceiptReceived, ReceiptFailed};
enum Tristate {Yes, No, Maybe};
enum OccupantAction {Kick, Ban, MakeModerator, MakeParticipant, MakeVisitor, AddContact, ShowProfile};
enum RoomAction {ChangeSubject, Configure, Affiliations, Destroy, Invite};
enum FileTransferState {WaitingForAccept, Negotiating, Transferring, Canceled, Finished, FTFailed};
enum WhiteboardSessionState {WhiteboardAccepted, WhiteboardTerminated, WhiteboardRejected};
enum BlockingState {BlockingUnsupported, IsBlocked, IsUnblocked};
enum Direction { UnknownDirection, DefaultDirection };
+ enum MUCType { StandardMUC, ImpromptuMUC };
ChatWindow() {}
virtual ~ChatWindow() {}
/** Add message to window.
* @return id of added message (for acks).
*/
virtual std::string addMessage(const ChatMessage& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) = 0;
/** Adds action to window.
* @return id of added message (for acks);
*/
virtual std::string addAction(const ChatMessage& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) = 0;
virtual void addSystemMessage(const ChatMessage& message, Direction direction) = 0;
virtual void addPresenceMessage(const ChatMessage& message, Direction direction) = 0;
virtual void addErrorMessage(const ChatMessage& message) = 0;
virtual void replaceMessage(const ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight) = 0;
virtual void replaceWithAction(const ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight) = 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 std::string& senderName, const JID& jid, const std::string& reason, const std::string& password, bool direct = true, bool isImpromptu = false, bool isContinuation = false) = 0;
virtual std::string addWhiteboardRequest(bool senderIsSelf) = 0;
virtual void setWhiteboardSessionStatus(std::string id, const ChatWindow::WhiteboardSessionState state) = 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;
virtual void setSecurityLabelsEnabled(bool enabled) = 0;
virtual void setCorrectionEnabled(Tristate enabled) = 0;
virtual void setUnreadMessageCount(int count) = 0;
- virtual void convertToMUC(bool impromptuMUC = false) = 0;
+ virtual void convertToMUC(MUCType mucType) = 0;
// virtual TreeWidget *getTreeWidget() = 0;
virtual void setSecurityLabelsError() = 0;
virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() = 0;
virtual void setInputEnabled(bool enabled) = 0;
virtual void setRosterModel(Roster* model) = 0;
virtual void setTabComplete(TabComplete* completer) = 0;
virtual void replaceLastMessage(const ChatMessage& message) = 0;
virtual void setAckState(const std::string& id, AckState state) = 0;
virtual void flash() = 0;
virtual void setSubject(const std::string& subject) = 0;
virtual void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&) = 0;
virtual void setAvailableRoomActions(const std::vector<RoomAction> &actions) = 0;
virtual void setBlockingState(BlockingState state) = 0;
virtual void setCanInitiateImpromptuChats(bool supportsImpromptu) = 0;
/**
* Set an alert on the window.
* @param alertText Description of alert (required).
* @param buttonText Button text to use (optional, no button is shown if empty).
*/
virtual void setAlert(const std::string& alertText, const std::string& buttonText = "") = 0;
/**
* Removes an alert.
*/
virtual void cancelAlert() = 0;
/**
* Actions that can be performed on the selected occupant.
*/
virtual void setAvailableOccupantActions(const std::vector<OccupantAction>& actions) = 0;
/**
* A room configuration has been requested, show the form.
* If the form is cancelled, must emit onConfigurationFormCancelled().
*/
virtual void showRoomConfigurationForm(Form::ref) = 0;
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 59ed0f1..8aa645d 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -13,71 +13,71 @@
namespace Swift {
class MockChatWindow : public ChatWindow {
public:
MockChatWindow() : labelsEnabled_(false) {}
virtual ~MockChatWindow();
virtual std::string addMessage(const ChatMessage& message, const std::string& /*senderName*/, bool /*senderIsSelf*/, boost::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime& /*time*/, const HighlightAction& /*highlight*/) {
lastMessageBody_ = bodyFromMessage(message); return "id";}
virtual std::string addAction(const ChatMessage& /*message*/, const std::string& /*senderName*/, bool /*senderIsSelf*/, boost::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime& /*time*/, const HighlightAction& /*highlight*/) {return "id";}
virtual void addSystemMessage(const ChatMessage& /*message*/, Direction /*direction*/) {}
virtual void addPresenceMessage(const ChatMessage& /*message*/, Direction /*direction*/) {}
virtual void addErrorMessage(const ChatMessage& /*message*/) {}
virtual void replaceMessage(const ChatMessage& /*message*/, const std::string& /*id*/, const boost::posix_time::ptime& /*time*/, const HighlightAction& /*highlight*/) {}
virtual void replaceWithAction(const ChatMessage& /*message*/, const std::string& /*id*/, const boost::posix_time::ptime& /*time*/, const HighlightAction& /*highlight*/) {}
virtual void replaceLastMessage(const ChatMessage& /*message*/) {}
// File transfer related stuff
virtual std::string addFileTransfer(const std::string& /*senderName*/, bool /*senderIsSelf*/,const std::string& /*filename*/, const boost::uintmax_t /*sizeInBytes*/) { return 0; }
virtual void setFileTransferProgress(std::string /*id*/, const int /*alreadyTransferedBytes*/) { }
virtual void setFileTransferStatus(std::string /*id*/, const FileTransferState /*state*/, const std::string& /*msg*/) { }
virtual void setMessageReceiptState(const std::string &/* id */, ReceiptState /* state */) { }
virtual void setContactChatState(ChatState::ChatStateType /*state*/) {}
virtual void setName(const std::string& name) {name_ = name;}
virtual void show() {}
virtual void activate() {}
virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) {labels_ = labels;}
virtual void setSecurityLabelsEnabled(bool enabled) {labelsEnabled_ = enabled;}
virtual void setUnreadMessageCount(int /*count*/) {}
- virtual void convertToMUC(bool /*impromptuMUC*/) {}
+ virtual void convertToMUC(MUCType /*mucType*/) {}
virtual void setSecurityLabelsError() {}
virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() {return label_;}
virtual void setInputEnabled(bool /*enabled*/) {}
virtual void setRosterModel(Roster* roster) { roster_ = roster; }
Roster* getRosterModel() { return roster_; }
virtual void setTabComplete(TabComplete*) {}
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 std::string& /*senderName*/, const JID& /*jid*/, const std::string& /*reason*/, const std::string& /*password*/, bool = true, bool = false, bool = false) {}
virtual std::string addWhiteboardRequest(bool) {return "";}
virtual void setWhiteboardSessionStatus(std::string, const ChatWindow::WhiteboardSessionState){}
virtual void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&) {}
virtual void setAvailableRoomActions(const std::vector<RoomAction> &) {}
virtual void setBlockingState(BlockingState) {}
virtual void setCanInitiateImpromptuChats(bool /*supportsImpromptu*/) {}
std::string bodyFromMessage(const ChatMessage& message) {
boost::shared_ptr<ChatTextMessagePart> text;
foreach (boost::shared_ptr<ChatMessagePart> part, message.getParts()) {
if ((text = boost::dynamic_pointer_cast<ChatTextMessagePart>(part))) {
return text->text;
}
}
return "";
}
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 826ec9e..bd7c817 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -84,71 +84,71 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
alertLayout->addWidget(alertLabel_);
alertButton_ = new QPushButton(this);
connect (alertButton_, SIGNAL(clicked()), this, SLOT(handleAlertButtonClicked()));
alertLayout->addWidget(alertButton_);
QPalette palette = alertWidget_->palette();
palette.setColor(QPalette::Window, QColor(Qt::yellow));
palette.setColor(QPalette::WindowText, QColor(Qt::black));
alertWidget_->setStyleSheet(alertStyleSheet_);
alertLabel_->setStyleSheet(alertStyleSheet_);
alertWidget_->hide();
subjectLayout_ = new QBoxLayout(QBoxLayout::LeftToRight);
subject_ = new QLineEdit(this);
subjectLayout_->addWidget(subject_);
setSubject("");
subject_->setReadOnly(true);
QPushButton* actionButton_ = new QPushButton(this);
actionButton_->setIcon(QIcon(":/icons/actions.png"));
connect(actionButton_, SIGNAL(clicked()), this, SLOT(handleActionButtonClicked()));
subject_->hide();
layout->addLayout(subjectLayout_);
logRosterSplitter_ = new QSplitter(this);
logRosterSplitter_->setAutoFillBackground(true);
layout->addWidget(logRosterSplitter_);
if (settings_->getSetting(QtUISettingConstants::USE_PLAIN_CHATS) || settings_->getSetting(QtUISettingConstants::USE_SCREENREADER)) {
messageLog_ = new QtPlainChatView(this, eventStream_);
}
else {
messageLog_ = new QtWebKitChatView(this, eventStream_, theme, this); // I accept that passing the ChatWindow in so that the view can call the signals is somewhat inelegant, but it saves a lot of boilerplate. This patch is unpleasant enough already. So let's fix this soon (it at least needs fixing by the time history is sorted), but not now.
}
logRosterSplitter_->addWidget(messageLog_);
- treeWidget_ = new QtOccupantListWidget(eventStream_, settings_, this);
+ treeWidget_ = new QtOccupantListWidget(eventStream_, settings_, QtTreeWidget::MessageDefaultJID, this);
treeWidget_->hide();
logRosterSplitter_->addWidget(treeWidget_);
logRosterSplitter_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(logRosterSplitter_, SIGNAL(splitterMoved(int, int)), this, SLOT(handleSplitterMoved(int, int)));
midBar_ = new QWidget(this);
//layout->addWidget(midBar);
midBar_->setAutoFillBackground(true);
QHBoxLayout *midBarLayout = new QHBoxLayout(midBar_);
midBarLayout->setContentsMargins(0,0,0,0);
midBarLayout->setSpacing(2);
//midBarLayout->addStretch();
labelsWidget_ = new QComboBox(this);
labelsWidget_->setFocusPolicy(Qt::NoFocus);
labelsWidget_->hide();
labelsWidget_->setSizeAdjustPolicy(QComboBox::AdjustToContents);
midBarLayout->addWidget(labelsWidget_,0);
connect(labelsWidget_, SIGNAL(currentIndexChanged(int)), this, SLOT(handleCurrentLabelChanged(int)));
defaultLabelsPalette_ = labelsWidget_->palette();
QHBoxLayout* inputBarLayout = new QHBoxLayout();
inputBarLayout->setContentsMargins(0,0,0,0);
inputBarLayout->setSpacing(2);
input_ = new QtTextEdit(settings_, this);
input_->setAcceptRichText(false);
inputBarLayout->addWidget(midBar_);
inputBarLayout->addWidget(input_);
correctingLabel_ = new QLabel(tr("Correcting"), this);
inputBarLayout->addWidget(correctingLabel_);
correctingLabel_->hide();
// using an extra layout to work around Qt margin glitches on OS X
QHBoxLayout* actionLayout = new QHBoxLayout();
actionLayout->addWidget(actionButton_);
@@ -364,72 +364,73 @@ void QtChatWindow::handleCurrentLabelChanged(int index) {
labelsWidget_->setAutoFillBackground(false);
labelsWidget_->setPalette(defaultLabelsPalette_);
midBar_->setPalette(defaultLabelsPalette_);
}
}
void QtChatWindow::setSecurityLabelsError() {
labelsWidget_->setEnabled(false);
}
void QtChatWindow::setSecurityLabelsEnabled(bool enabled) {
if (enabled) {
labelsWidget_->setEnabled(true);
labelsWidget_->show();
} else {
labelsWidget_->hide();
}
}
void QtChatWindow::setCorrectionEnabled(Tristate enabled) {
correctionEnabled_ = enabled;
}
SecurityLabelsCatalog::Item QtChatWindow::getSelectedSecurityLabel() {
assert(labelsWidget_->isEnabled());
assert(labelsWidget_->currentIndex() >= 0 && static_cast<size_t>(labelsWidget_->currentIndex()) < labelModel_->availableLabels_.size());
return labelModel_->availableLabels_[labelsWidget_->currentIndex()];
}
void QtChatWindow::closeEvent(QCloseEvent* event) {
event->accept();
emit windowClosing();
onClosed();
}
-void QtChatWindow::convertToMUC(bool impromptuMUC) {
- impromptu_ = impromptuMUC;
+void QtChatWindow::convertToMUC(MUCType mucType) {
+ impromptu_ = (mucType == ImpromptuMUC);
+ treeWidget_->setMessageTarget(impromptu_ ? QtTreeWidget::MessageDisplayJID : QtTreeWidget::MessageDefaultJID);
isMUC_ = true;
treeWidget_->show();
subject_->setVisible(!impromptu_);
}
void QtChatWindow::qAppFocusChanged(QWidget* /*old*/, QWidget* /*now*/) {
if (isWidgetSelected()) {
lastLineTracker_.setHasFocus(true);
input_->setFocus();
onAllMessagesRead();
}
else {
lastLineTracker_.setHasFocus(false);
}
}
void QtChatWindow::setInputEnabled(bool enabled) {
inputEnabled_ = enabled;
if (!enabled) {
if (mucConfigurationWindow_) {
delete mucConfigurationWindow_.data();
}
if (affiliationEditor_) {
delete affiliationEditor_.data();
}
}
}
void QtChatWindow::showEvent(QShowEvent* event) {
emit windowOpening();
QWidget::showEvent(event);
}
void QtChatWindow::setUnreadMessageCount(int count) {
if (unreadCount_ != count) {
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index eeb8093..5a4fe95 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -67,71 +67,71 @@ namespace Swift {
QString labelName = selector.empty() ? displayMarking.c_str() : selector.c_str();
return labelName;
}
return QVariant();
}
std::vector<SecurityLabelsCatalog::Item> availableLabels_;
};
class QtChatWindow : public QtTabbable, public ChatWindow {
Q_OBJECT
public:
QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings);
~QtChatWindow();
std::string addMessage(const ChatMessage& message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight);
std::string addAction(const ChatMessage& message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight);
void addSystemMessage(const ChatMessage& message, Direction direction);
void addPresenceMessage(const ChatMessage& message, Direction direction);
void addErrorMessage(const ChatMessage& message);
void replaceMessage(const ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight);
void replaceWithAction(const ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight);
// File transfer related stuff
std::string addFileTransfer(const std::string& senderName, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes);
void setFileTransferProgress(std::string id, const int percentageDone);
void setFileTransferStatus(std::string id, const FileTransferState state, const std::string& msg);
std::string addWhiteboardRequest(bool senderIsSelf);
void setWhiteboardSessionStatus(std::string id, const ChatWindow::WhiteboardSessionState state);
void show();
void activate();
void setUnreadMessageCount(int count);
- void convertToMUC(bool impromptuMUC = false);
+ void convertToMUC(MUCType mucType);
// TreeWidget *getTreeWidget();
void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels);
void setSecurityLabelsEnabled(bool enabled);
void setSecurityLabelsError();
SecurityLabelsCatalog::Item getSelectedSecurityLabel();
void setName(const std::string& name);
void setInputEnabled(bool enabled);
QtTabbable::AlertType getWidgetAlertState();
void setContactChatState(ChatState::ChatStateType state);
void setRosterModel(Roster* roster);
void setTabComplete(TabComplete* completer);
int getCount();
void replaceLastMessage(const ChatMessage& message);
void setAckState(const std::string& id, AckState state);
// 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 std::string& senderName, const JID& jid, const std::string& reason, const std::string& password, bool direct = true, bool isImpromptu = false, bool isContinuation = false);
void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&);
void setAvailableRoomActions(const std::vector<RoomAction>& actions);
void setBlockingState(BlockingState state);
virtual void setCanInitiateImpromptuChats(bool supportsImpromptu);
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);
diff --git a/Swift/QtUI/QtHistoryWindow.cpp b/Swift/QtUI/QtHistoryWindow.cpp
index 9f88258..75eeaad 100644
--- a/Swift/QtUI/QtHistoryWindow.cpp
+++ b/Swift/QtUI/QtHistoryWindow.cpp
@@ -28,71 +28,71 @@
#include <Swiften/History/HistoryMessage.h>
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/QtUI/QtSwiftUtil.h>
#include <Swift/QtUI/MessageSnippet.h>
#include <Swift/QtUI/QtScaledAvatarCache.h>
#include <Swift/QtUI/ChatSnippet.h>
#include <Swift/QtUI/QtUtilities.h>
#include <Swift/QtUI/Roster/QtTreeWidget.h>
#include <Swift/QtUI/QtWebKitChatView.h>
namespace Swift {
QtHistoryWindow::QtHistoryWindow(SettingsProvider* settings, UIEventStream* eventStream) :
previousTopMessageWasSelf_(false),
previousBottomMessageWasSelf_(false) {
ui_.setupUi(this);
theme_ = new QtChatTheme("");
idCounter_ = 0;
delete ui_.conversation_;
conversation_ = new QtWebKitChatView(NULL, NULL, theme_, this, true); // Horrible unsafe. Do not do this. FIXME
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
sizePolicy.setHorizontalStretch(80);
sizePolicy.setVerticalStretch(0);
conversation_->setSizePolicy(sizePolicy);
ui_.conversation_ = conversation_;
ui_.bottomLayout_->addWidget(conversation_);
delete ui_.conversationRoster_;
- conversationRoster_ = new QtTreeWidget(eventStream, settings, this);
+ conversationRoster_ = new QtTreeWidget(eventStream, settings, QtTreeWidget::MessageDefaultJID, this);
QSizePolicy sizePolicy2(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy2.setVerticalStretch(80);
conversationRoster_->setSizePolicy(sizePolicy2);
ui_.conversationRoster_ = conversationRoster_;
ui_.bottomLeftLayout_->setDirection(QBoxLayout::BottomToTop);
ui_.bottomLeftLayout_->addWidget(conversationRoster_);
setWindowTitle(tr("History"));
conversationRoster_->onSomethingSelectedChanged.connect(boost::bind(&QtHistoryWindow::handleSomethingSelectedChanged, this, _1));
connect(conversation_, SIGNAL(scrollRequested(int)), this, SLOT(handleScrollRequested(int)));
connect(conversation_, SIGNAL(scrollReachedTop()), this, SLOT(handleScrollReachedTop()));
connect(conversation_, SIGNAL(scrollReachedBottom()), this, SLOT(handleScrollReachedBottom()));
connect(conversation_, SIGNAL(fontResized(int)), this, SLOT(handleFontResized(int)));
connect(ui_.searchBox_->lineEdit(), SIGNAL(returnPressed()), this, SLOT(handleReturnPressed()));
connect(ui_.calendarWidget_, SIGNAL(clicked(const QDate&)), this, SLOT(handleCalendarClicked(const QDate&)));
connect(ui_.calendarWidget_, SIGNAL(activated(const QDate&)), this, SLOT(handleCalendarClicked(const QDate&)));
connect(ui_.previousButton_, SIGNAL(clicked(bool)), this, SLOT(handlePreviousButtonClicked()));
connect(ui_.nextButton_, SIGNAL(clicked(bool)), this, SLOT(handleNextButtonClicked()));
}
QtHistoryWindow::~QtHistoryWindow() {
disconnect(conversation_, SIGNAL(scrollRequested(int)), this, SLOT(handleScrollRequested(int)));
disconnect(conversation_, SIGNAL(scrollReachedTop()), this, SLOT(handleScrollReachedTop()));
disconnect(conversation_, SIGNAL(scrollReachedBottom()), this, SLOT(handleScrollReachedBottom()));
disconnect(conversation_, SIGNAL(fontResized(int)), this, SLOT(handleFontResized(int)));
disconnect(ui_.searchBox_->lineEdit(), SIGNAL(returnPressed()), this, SLOT(handleReturnPressed()));
disconnect(ui_.calendarWidget_, SIGNAL(clicked(const QDate&)), this, SLOT(handleCalendarClicked(const QDate&)));
disconnect(ui_.calendarWidget_, SIGNAL(activated(const QDate&)), this, SLOT(handleCalendarClicked(const QDate&)));
disconnect(ui_.previousButton_, SIGNAL(clicked(bool)), this, SLOT(handlePreviousButtonClicked()));
disconnect(ui_.nextButton_, SIGNAL(clicked(bool)), this, SLOT(handleNextButtonClicked()));
delete theme_;
delete conversation_;
// TODO: delete ui_
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.cpp b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
index 12dc1e4..4f1baf3 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.cpp
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
@@ -1,57 +1,58 @@
/*
- * Copyright (c) 2011-2012 Kevin Smith
+ * Copyright (c) 2011-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Roster/QtOccupantListWidget.h"
+#include <Swift/QtUI/Roster/QtOccupantListWidget.h>
#include <QContextMenuEvent>
#include <QMenu>
#include <QAction>
#include <QInputDialog>
-#include "Swift/Controllers/Roster/ContactRosterItem.h"
-#include "Swift/Controllers/Roster/GroupRosterItem.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "QtSwiftUtil.h"
+#include <Swift/Controllers/Roster/ContactRosterItem.h>
+#include <Swift/Controllers/Roster/GroupRosterItem.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
namespace Swift {
-QtOccupantListWidget::QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, parent) {
+QtOccupantListWidget::QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget privateMessageTarget, QWidget* parent) : QtTreeWidget(eventStream, settings, privateMessageTarget, parent) {
}
QtOccupantListWidget::~QtOccupantListWidget() {
}
void QtOccupantListWidget::setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions) {
availableOccupantActions_ = actions;
}
void QtOccupantListWidget::contextMenuEvent(QContextMenuEvent* event) {
QModelIndex index = indexAt(event->pos());
if (!index.isValid()) {
return;
}
RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
if (contact) {
onSomethingSelectedChanged(contact);
QMenu contextMenu;
if (availableOccupantActions_.empty()) {
QAction* noAction = contextMenu.addAction(tr("No actions for this user"));
noAction->setEnabled(false);
contextMenu.exec(event->globalPos());
}
else {
std::map<QAction*, ChatWindow::OccupantAction> actions;
foreach (ChatWindow::OccupantAction availableAction, availableOccupantActions_) {
QString text = "Error: missing string";
switch (availableAction) {
case ChatWindow::Kick: text = tr("Kick user"); break;
case ChatWindow::Ban: text = tr("Kick and ban user"); break;
case ChatWindow::MakeModerator: text = tr("Make moderator"); break;
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.h b/Swift/QtUI/Roster/QtOccupantListWidget.h
index 729115a..c944658 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.h
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.h
@@ -1,31 +1,32 @@
/*
- * Copyright (c) 2011-2012 Kevin Smith
+ * Copyright (c) 2011-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
-#include "Swift/QtUI/Roster/QtTreeWidget.h"
+#include <Swift/QtUI/Roster/QtTreeWidget.h>
-#include "Swiften/Base/boost_bsignals.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
+#include <Swiften/Base/boost_bsignals.h>
+
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
namespace Swift {
class SettingsProvider;
class QtOccupantListWidget : public QtTreeWidget {
Q_OBJECT
public:
- QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = 0);
+ QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget privateMessageTarget, QWidget* parent = NULL);
virtual ~QtOccupantListWidget();
void setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions);
boost::signal<void (ChatWindow::OccupantAction, ContactRosterItem*)> onOccupantActionSelected;
protected:
void contextMenuEvent(QContextMenuEvent* event);
private:
std::vector<ChatWindow::OccupantAction> availableOccupantActions_;
};
}
diff --git a/Swift/QtUI/Roster/QtRosterWidget.cpp b/Swift/QtUI/Roster/QtRosterWidget.cpp
index 1436c7c..fff0ccd 100644
--- a/Swift/QtUI/Roster/QtRosterWidget.cpp
+++ b/Swift/QtUI/Roster/QtRosterWidget.cpp
@@ -1,66 +1,66 @@
/*
* Copyright (c) 2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swift/QtUI/Roster/QtRosterWidget.h>
#include <QContextMenuEvent>
#include <QMenu>
#include <QMessageBox>
#include <QInputDialog>
#include <QFileDialog>
#include <QPushButton>
#include <Swift/Controllers/UIEvents/RequestContactEditorUIEvent.h>
#include <Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h>
#include <Swift/Controllers/UIEvents/RenameGroupUIEvent.h>
#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestWhiteboardUIEvent.h>
#include <Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h>
#include <Swift/QtUI/QtContactEditWindow.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/QtUI/QtSwiftUtil.h>
namespace Swift {
-QtRosterWidget::QtRosterWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, parent) {
+QtRosterWidget::QtRosterWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, MessageDefaultJID, parent) {
}
QtRosterWidget::~QtRosterWidget() {
}
void QtRosterWidget::handleEditUserActionTriggered(bool /*checked*/) {
QModelIndexList selectedIndexList = getSelectedIndexes();
if (selectedIndexList.empty()) {
return;
}
QModelIndex index = selectedIndexList[0];
if (!index.isValid()) {
return;
}
RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) {
eventStream_->send(boost::make_shared<RequestContactEditorUIEvent>(contact->getJID()));
}
}
void QtRosterWidget::contextMenuEvent(QContextMenuEvent* event) {
QModelIndex index = indexAt(event->pos());
if (!index.isValid()) {
return;
}
RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
QMenu contextMenu;
if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) {
QAction* editContact = contextMenu.addAction(tr("Edit…"));
QAction* removeContact = contextMenu.addAction(tr("Remove"));
QAction* showProfileForContact = contextMenu.addAction(tr("Show Profile"));
QAction* unblockContact = NULL;
diff --git a/Swift/QtUI/Roster/QtTreeWidget.cpp b/Swift/QtUI/Roster/QtTreeWidget.cpp
index 91e9a33..ed76a6f 100644
--- a/Swift/QtUI/Roster/QtTreeWidget.cpp
+++ b/Swift/QtUI/Roster/QtTreeWidget.cpp
@@ -1,69 +1,69 @@
/*
* Copyright (c) 2010-2012 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swift/QtUI/Roster/QtTreeWidget.h>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/bind.hpp>
#include <QUrl>
#include <QMimeData>
#include <QObject>
#include <QLabel>
#include <QTimer>
#include <QToolTip>
#include <Swiften/Base/Platform.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/QtUI/QtUISettingConstants.h>
-
+#include <Swift/QtUI/Roster/RosterModel.h>
#include <QtSwiftUtil.h>
namespace Swift {
-QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QTreeView(parent), tooltipShown_(false) {
+QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget messageTarget, QWidget* parent) : QTreeView(parent), messageTarget_(messageTarget), tooltipShown_(false) {
eventStream_ = eventStream;
settings_ = settings;
model_ = new RosterModel(this, settings_->getSetting(QtUISettingConstants::USE_SCREENREADER));
setModel(model_);
delegate_ = new RosterDelegate(this, settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER));
setItemDelegate(delegate_);
setHeaderHidden(true);
#ifdef SWIFT_PLATFORM_MACOSX
setAlternatingRowColors(true);
#endif
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
expandAll();
setAnimated(true);
setIndentation(0);
#ifdef SWIFT_EXPERIMENTAL_FT
setAcceptDrops(true);
#endif
setDragEnabled(true);
setRootIsDecorated(true);
connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleItemActivated(const QModelIndex&)));
connect(model_, SIGNAL(itemExpanded(const QModelIndex&, bool)), this, SLOT(handleModelItemExpanded(const QModelIndex&, bool)));
connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(handleExpanded(const QModelIndex&)));
connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(handleCollapsed(const QModelIndex&)));
connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(handleClicked(const QModelIndex&)));
settings_->onSettingChanged.connect(boost::bind(&QtTreeWidget::handleSettingChanged, this, _1));
}
QtTreeWidget::~QtTreeWidget() {
settings_->onSettingChanged.disconnect(boost::bind(&QtTreeWidget::handleSettingChanged, this, _1));
delete model_;
delete delegate_;
}
void QtTreeWidget::handleSettingChanged(const std::string& setting) {
@@ -105,76 +105,88 @@ void QtTreeWidget::handleClicked(const QModelIndex& index) {
}
QModelIndexList QtTreeWidget::getSelectedIndexes() const {
// Not using selectedIndexes(), because this seems to cause a crash in Qt (4.7.0) in the
// QModelIndexList destructor.
// This is a workaround posted in http://www.qtcentre.org/threads/16933 (although this case
// was resolved by linking against the debug libs, ours isn't, and we're not alone)
QItemSelection ranges = selectionModel()->selection();
QModelIndexList selectedIndexList;
for (int i = 0; i < ranges.count(); ++i) {
QModelIndex parent = ranges.at(i).parent();
int right = ranges.at(i).model()->columnCount(parent) - 1;
if (ranges.at(i).left() == 0 && ranges.at(i).right() == right) {
for (int r = ranges.at(i).top(); r <= ranges.at(i).bottom(); ++r) {
selectedIndexList.append(ranges.at(i).model()->index(r, 0, parent));
}
}
}
return selectedIndexList;
}
void QtTreeWidget::currentChanged(const QModelIndex& current, const QModelIndex& previous) {
RosterItem* item = NULL;
QModelIndexList selectedIndexList = getSelectedIndexes();
if (selectedIndexList.empty() || !selectedIndexList[0].isValid()) {
/* I didn't quite understand why using current didn't seem to work here.*/
}
else if (current.isValid()) {
item = static_cast<RosterItem*>(current.internalPointer());
item = dynamic_cast<ContactRosterItem*>(item);
}
onSomethingSelectedChanged(item);
QTreeView::currentChanged(current, previous);
}
-
void QtTreeWidget::handleItemActivated(const QModelIndex& index) {
- RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
- ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
- if (contact) {
- eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(contact->getJID())));
+ switch (messageTarget_) {
+ case MessageDisplayJID: {
+ QString indexJID = index.data(DisplayJIDRole).toString();
+ if (!indexJID.isEmpty()) {
+ JID target = JID(Q2PSTRING(indexJID)).toBare();
+ eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(target)));
+ break;
+ }
+ }
+ case MessageDefaultJID: {
+ QString indexJID = index.data(JIDRole).toString();
+ if (!indexJID.isEmpty()) {
+ JID target = JID(Q2PSTRING(indexJID));
+ eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(target)));
+ }
+ break;
+ }
}
}
void QtTreeWidget::dragEnterEvent(QDragEnterEvent *event) {
if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) {
event->acceptProposedAction();
}
}
void QtTreeWidget::dropEvent(QDropEvent *event) {
QModelIndex index = indexAt(event->pos());
if (index.isValid()) {
RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) {
if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) {
QString filename = event->mimeData()->urls().at(0).toLocalFile();
if (!filename.isEmpty()) {
eventStream_->send(boost::make_shared<SendFileUIEvent>(contact->getJID(), Q2PSTRING(filename)));
}
}
}
}
}
void QtTreeWidget::dragMoveEvent(QDragMoveEvent* event) {
QModelIndex index = indexAt(event->pos());
if (index.isValid()) {
RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) {
if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) {
event->accept();
return;
}
}
}
@@ -198,36 +210,40 @@ bool QtTreeWidget::event(QEvent* event) {
return QAbstractItemView::event(event);
}
void QtTreeWidget::handleExpanded(const QModelIndex& index) {
GroupRosterItem* item = dynamic_cast<GroupRosterItem*>(static_cast<RosterItem*>(index.internalPointer()));
if (item) {
item->setExpanded(true);
}
}
void QtTreeWidget::handleCollapsed(const QModelIndex& index) {
GroupRosterItem* item = dynamic_cast<GroupRosterItem*>(static_cast<RosterItem*>(index.internalPointer()));
if (item) {
item->setExpanded(false);
}
}
void QtTreeWidget::handleModelItemExpanded(const QModelIndex& index, bool shouldExpand) {
if (!index.isValid()) {
return;
}
bool alreadyRight = this->isExpanded(index) == shouldExpand;
if (alreadyRight) {
return;
}
setExpanded(index, shouldExpand);
}
void QtTreeWidget::drawBranches(QPainter*, const QRect&, const QModelIndex&) const {
}
void QtTreeWidget::show() {
QWidget::show();
}
+void QtTreeWidget::setMessageTarget(MessageTarget messageTarget) {
+ messageTarget_ = messageTarget;
+}
+
}
diff --git a/Swift/QtUI/Roster/QtTreeWidget.h b/Swift/QtUI/Roster/QtTreeWidget.h
index 8884a40..29e985d 100644
--- a/Swift/QtUI/Roster/QtTreeWidget.h
+++ b/Swift/QtUI/Roster/QtTreeWidget.h
@@ -1,68 +1,74 @@
/*
- * Copyright (c) 2010-2012 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
-#include <QTreeView>
-#include <QModelIndex>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QDragMoveEvent>
+#include <QModelIndex>
+#include <QTreeView>
-#include <Swift/QtUI/Roster/RosterModel.h>
#include <Swift/QtUI/Roster/RosterDelegate.h>
+#include <Swift/QtUI/Roster/RosterModel.h>
+
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
namespace Swift {
class UIEventStream;
class SettingsProvider;
-class QtTreeWidget : public QTreeView{
+class QtTreeWidget : public QTreeView {
Q_OBJECT
public:
- QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = 0);
+ enum MessageTarget {MessageDefaultJID, MessageDisplayJID};
+
+ QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget messageTarget, QWidget* parent = 0);
~QtTreeWidget();
void show();
QtTreeWidgetItem* getRoot();
void setRosterModel(Roster* roster);
Roster* getRoster() {return roster_;}
void refreshTooltip();
+ void setMessageTarget(MessageTarget messageTarget);
+ public:
boost::signal<void (RosterItem*)> onSomethingSelectedChanged;
private slots:
void handleItemActivated(const QModelIndex&);
void handleModelItemExpanded(const QModelIndex&, bool expanded);
void handleExpanded(const QModelIndex&);
void handleCollapsed(const QModelIndex&);
void handleClicked(const QModelIndex&);
void handleSettingChanged(const std::string& setting);
void handleRefreshTooltip();
protected:
void dragEnterEvent(QDragEnterEvent* event);
void dropEvent(QDropEvent* event);
void dragMoveEvent(QDragMoveEvent* event);
bool event(QEvent* event);
-
- protected:
QModelIndexList getSelectedIndexes() const;
+
private:
void drawBranches(QPainter*, const QRect&, const QModelIndex&) const;
protected slots:
virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous);
protected:
UIEventStream* eventStream_;
private:
RosterModel* model_;
Roster* roster_;
RosterDelegate* delegate_;
QtTreeWidgetItem* treeRoot_;
SettingsProvider* settings_;
bool tooltipShown_;
+ MessageTarget messageTarget_;
};
}
diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp
index fa8c393..2bd0d09 100644
--- a/Swift/QtUI/Roster/RosterModel.cpp
+++ b/Swift/QtUI/Roster/RosterModel.cpp
@@ -70,70 +70,72 @@ void RosterModel::handleDataChanged(RosterItem* item) {
emit dataChanged(modelIndex, modelIndex);
view_->refreshTooltip();
}
}
Qt::ItemFlags RosterModel::flags(const QModelIndex& index) const {
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
if (dynamic_cast<GroupRosterItem*>(getItem(index)) == NULL) {
flags |= Qt::ItemIsDragEnabled;
}
return flags;
}
int RosterModel::columnCount(const QModelIndex& /*parent*/) const {
return 1;
}
RosterItem* RosterModel::getItem(const QModelIndex& index) const {
return index.isValid() ? static_cast<RosterItem*>(index.internalPointer()) : NULL;
}
QVariant RosterModel::data(const QModelIndex& index, int role) const {
RosterItem* item = getItem(index);
if (!item) return QVariant();
switch (role) {
case Qt::DisplayRole: return getScreenReaderTextOr(item, P2QSTRING(item->getDisplayName()));
case Qt::TextColorRole: return getTextColor(item);
case Qt::BackgroundColorRole: return getBackgroundColor(item);
case Qt::ToolTipRole: return getToolTip(item);
case StatusTextRole: return getStatusText(item);
case AvatarRole: return getAvatar(item);
case PresenceIconRole: return getPresenceIcon(item);
case ChildCountRole: return getChildCount(item);
case IdleRole: return getIsIdle(item);
+ case JIDRole: return getJID(item);
+ case DisplayJIDRole: return getDisplayJID(item);
default: return QVariant();
}
}
QString RosterModel::getScreenReaderTextOr(RosterItem* item, const QString& alternative) const {
QString name = P2QSTRING(item->getDisplayName());
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
if (contact && screenReader_) {
name += ": " + P2QSTRING(statusShowTypeToFriendlyName(contact->getStatusShow()));
if (!contact->getStatusText().empty()) {
name += " (" + P2QSTRING(contact->getStatusText()) + ")";
}
return name;
}
else {
return alternative;
}
}
int RosterModel::getChildCount(RosterItem* item) const {
GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item);
return group ? group->getDisplayedChildren().size() : 0;
}
bool RosterModel::getIsIdle(RosterItem* item) const {
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
return contact ? !contact->getIdleText().empty() : false;
}
QColor RosterModel::intToColor(int color) const {
return QColor(
((color & 0xFF0000)>>16),
((color & 0xFF00)>>8),
(color & 0xFF));
}
@@ -149,70 +151,80 @@ QColor RosterModel::getTextColor(RosterItem* item) const {
case StatusShow::FFC: color = 0x000000; break;
case StatusShow::DND: color = 0x990000; break;
case StatusShow::None: color = 0x7F7F7F;break;
}
}
return intToColor(color);
}
QColor RosterModel::getBackgroundColor(RosterItem* item) const {
return dynamic_cast<ContactRosterItem*>(item) ? intToColor(0xFFFFFF) : intToColor(0x969696);
}
QString RosterModel::getToolTip(RosterItem* item) const {
QString tip(P2QSTRING(item->getDisplayName()));
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
if (contact) {
return RosterTooltip::buildDetailedTooltip(contact, cachedImageScaler_);
}
return tip;
}
QString RosterModel::getAvatar(RosterItem* item) const {
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
if (!contact) {
return "";
}
return P2QSTRING(pathToString(contact->getAvatarPath()));
}
QString RosterModel::getStatusText(RosterItem* item) const {
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
if (!contact) return "";
return P2QSTRING(contact->getStatusText());
}
+QString RosterModel::getJID(RosterItem* item) const {
+ ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
+ return contact ? P2QSTRING(contact->getJID().toString()) : QString();
+}
+
+QString RosterModel::getDisplayJID(RosterItem* item) const {
+ ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
+ return contact ? P2QSTRING(contact->getDisplayJID().toString()) : QString();
+}
+
QIcon RosterModel::getPresenceIcon(RosterItem* item) const {
ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
if (!contact) return QIcon();
if (contact->blockState() == ContactRosterItem::IsBlocked ||
contact->blockState() == ContactRosterItem::IsDomainBlocked) {
return QIcon(":/icons/stop.png");
}
return QIcon(statusShowTypeToIconPath(contact->getStatusShow()));
}
QModelIndex RosterModel::index(int row, int column, const QModelIndex& parent) const {
if (!roster_) {
return QModelIndex();
}
GroupRosterItem* parentItem;
if (!parent.isValid()) {
//top level
parentItem = roster_->getRoot();
} else {
parentItem = dynamic_cast<GroupRosterItem*>(getItem(parent));
if (!parentItem) return QModelIndex();
}
return static_cast<size_t>(row) < parentItem->getDisplayedChildren().size() ? createIndex(row, column, parentItem->getDisplayedChildren()[row]) : QModelIndex();
}
QModelIndex RosterModel::index(RosterItem* item) const {
GroupRosterItem* parent = item->getParent();
/* Recursive check that it's ok to create such an item
Assuming there are more contacts in a group than groups in a
group, this could save a decent chunk of search time at startup.*/
if (parent == NULL || roster_ == NULL || (parent != roster_->getRoot() && !index(parent).isValid())) {
return QModelIndex();
}
diff --git a/Swift/QtUI/Roster/RosterModel.h b/Swift/QtUI/Roster/RosterModel.h
index 7f6cdd2..2b05044 100644
--- a/Swift/QtUI/Roster/RosterModel.h
+++ b/Swift/QtUI/Roster/RosterModel.h
@@ -1,67 +1,71 @@
/*
* Copyright (c) 2010-2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <QAbstractItemModel>
#include <QList>
#include <Swift/Controllers/Roster/Roster.h>
#include <Swift/QtUI/QtScaledAvatarCache.h>
namespace Swift {
enum RosterRoles {
StatusTextRole = Qt::UserRole,
AvatarRole = Qt::UserRole + 1,
PresenceIconRole = Qt::UserRole + 2,
StatusShowTypeRole = Qt::UserRole + 3,
ChildCountRole = Qt::UserRole + 4,
- IdleRole = Qt::UserRole + 5
+ IdleRole = Qt::UserRole + 5,
+ JIDRole = Qt::UserRole + 6,
+ DisplayJIDRole = Qt::UserRole + 7
};
class QtTreeWidget;
class RosterModel : public QAbstractItemModel {
Q_OBJECT
public:
RosterModel(QtTreeWidget* view, bool screenReaderMode);
~RosterModel();
void setRoster(Roster* swiftRoster);
Qt::ItemFlags flags(const QModelIndex& index) const;
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 index(RosterItem* item) const;
QModelIndex parent(const QModelIndex& index) const;
int rowCount(const QModelIndex& parent = QModelIndex()) const;
QMimeData* mimeData(const QModelIndexList& indexes) const;
signals:
void itemExpanded(const QModelIndex& item, bool expanded);
private:
void handleDataChanged(RosterItem* item);
void handleChildrenChanged(GroupRosterItem* item);
RosterItem* getItem(const QModelIndex& index) const;
QColor intToColor(int color) const;
QColor getTextColor(RosterItem* item) const;
QColor getBackgroundColor(RosterItem* item) const;
QString getToolTip(RosterItem* item) const;
QString getAvatar(RosterItem* item) const;
QString getStatusText(RosterItem* item) const;
+ QString getJID(RosterItem* item) const;
+ QString getDisplayJID(RosterItem* item) const;
QIcon getPresenceIcon(RosterItem* item) const;
int getChildCount(RosterItem* item) const;
bool getIsIdle(RosterItem* item) const;
void reLayout();
/** calculates screenreader-friendly text if in screenreader mode, otherwise uses alternative text */
QString getScreenReaderTextOr(RosterItem* item, const QString& alternative) const;
private:
Roster* roster_;
QtTreeWidget* view_;
QtScaledAvatarCache* cachedImageScaler_;
bool screenReader_;
};
}