summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Maudsley <richard.maudsley@isode.com>2014-03-14 14:15:34 (GMT)
committerKevin Smith <git@kismith.co.uk>2014-04-02 11:14:52 (GMT)
commitc9275affd040ee1ca7c1d599b28df3b363bef888 (patch)
tree04afffe1e766f897f2208cf097a307a5fe530032 /Swift/QtUI
parentb92fe0b47d519da5fd55ba55ad0838e1ff69195c (diff)
downloadswift-contrib-c9275affd040ee1ca7c1d599b28df3b363bef888.zip
swift-contrib-c9275affd040ee1ca7c1d599b28df3b363bef888.tar.bz2
Make the impromptu MUCs behave more like a regular chat.
This hides occupant types in the participant list and initiates a direct 1-to-1 on occupant double-click instead of MUC-proxied 1-to-1. Change-Id: I76c57fe52beb3e4236524c1d8cfbd583d3dc3f62
Diffstat (limited to 'Swift/QtUI')
-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
10 files changed, 75 insertions, 34 deletions
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_;
};
}