summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/QtUI')
-rw-r--r--Swift/QtUI/ChatList/QtChatListWindow.cpp25
-rw-r--r--Swift/QtUI/ChatList/QtChatListWindow.h6
-rw-r--r--Swift/QtUI/ChattablesModel.cpp63
-rw-r--r--Swift/QtUI/ChattablesModel.h34
-rw-r--r--Swift/QtUI/FlowLayout.cpp7
-rw-r--r--Swift/QtUI/FlowLayout.h2
-rw-r--r--Swift/QtUI/QtBookmarkDetailWindow.cpp8
-rw-r--r--Swift/QtUI/QtBookmarkDetailWindow.ui23
-rw-r--r--Swift/QtUI/QtCachedImageScaler.cpp2
-rw-r--r--Swift/QtUI/QtChatOverview.cpp66
-rw-r--r--Swift/QtUI/QtChatOverview.h28
-rw-r--r--Swift/QtUI/QtChatOverviewBundle.cpp146
-rw-r--r--Swift/QtUI/QtChatOverviewBundle.h61
-rw-r--r--Swift/QtUI/QtChatOverviewDelegate.cpp88
-rw-r--r--Swift/QtUI/QtChatOverviewDelegate.h23
-rw-r--r--Swift/QtUI/QtChatTabs.cpp20
-rw-r--r--Swift/QtUI/QtChatTabs.h6
-rw-r--r--Swift/QtUI/QtChatTabsShortcutOnlySubstitute.cpp108
-rw-r--r--Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h40
-rw-r--r--Swift/QtUI/QtChatWindow.cpp113
-rw-r--r--Swift/QtUI/QtChatWindow.h17
-rw-r--r--Swift/QtUI/QtChatWindowFactory.cpp22
-rw-r--r--Swift/QtUI/QtChatWindowFactory.h8
-rw-r--r--Swift/QtUI/QtDBUSURIHandler.cpp4
-rw-r--r--Swift/QtUI/QtEditBookmarkWindow.cpp1
-rw-r--r--Swift/QtUI/QtEmojiCell.cpp15
-rw-r--r--Swift/QtUI/QtEmojisScroll.h4
-rw-r--r--Swift/QtUI/QtEmojisSelector.cpp9
-rw-r--r--Swift/QtUI/QtEmojisSelector.h4
-rw-r--r--Swift/QtUI/QtExpandedListView.cpp111
-rw-r--r--Swift/QtUI/QtExpandedListView.h34
-rw-r--r--Swift/QtUI/QtFdpFormSubmitWindow.cpp215
-rw-r--r--Swift/QtUI/QtFdpFormSubmitWindow.h75
-rw-r--r--Swift/QtUI/QtFormWidget.cpp2
-rw-r--r--Swift/QtUI/QtHighlightNotificationConfigDialog.cpp6
-rw-r--r--Swift/QtUI/QtHistoryWindow.cpp4
-rw-r--r--Swift/QtUI/QtJoinMUCWindow.cpp2
-rw-r--r--Swift/QtUI/QtJoinMUCWindow.ui8
-rw-r--r--Swift/QtUI/QtListWidget.cpp20
-rw-r--r--Swift/QtUI/QtListWidget.h23
-rw-r--r--Swift/QtUI/QtLoginWindow.cpp4
-rw-r--r--Swift/QtUI/QtLoginWindow.h5
-rw-r--r--Swift/QtUI/QtMainWindow.cpp37
-rw-r--r--Swift/QtUI/QtMainWindow.h48
-rw-r--r--Swift/QtUI/QtPlainChatView.cpp8
-rw-r--r--Swift/QtUI/QtSingleWindow.cpp91
-rw-r--r--Swift/QtUI/QtSingleWindow.h25
-rw-r--r--Swift/QtUI/QtStatusWidget.cpp12
-rw-r--r--Swift/QtUI/QtSwift.cpp254
-rw-r--r--Swift/QtUI/QtSwift.h47
-rw-r--r--Swift/QtUI/QtTabbable.h2
-rw-r--r--Swift/QtUI/QtUIFactory.cpp96
-rw-r--r--Swift/QtUI/QtUIFactory.h38
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardFieldInfo.h4
-rw-r--r--Swift/QtUI/QtVCardWidget/QtVCardWidget.cpp4
-rw-r--r--Swift/QtUI/QtWebKitChatView.cpp64
-rw-r--r--Swift/QtUI/QtWebKitChatView.h68
-rw-r--r--Swift/QtUI/QtWebView.cpp6
-rw-r--r--Swift/QtUI/SConscript221
-rw-r--r--Swift/QtUI/ServerList/QtServerListView.cpp31
-rw-r--r--Swift/QtUI/ServerList/QtServerListView.h25
-rw-r--r--Swift/QtUI/ServerList/ServerListDelegate.cpp117
-rw-r--r--Swift/QtUI/ServerList/ServerListDelegate.h31
-rw-r--r--Swift/QtUI/ServerList/ServerListModel.cpp68
-rw-r--r--Swift/QtUI/ServerList/ServerListModel.h87
-rw-r--r--Swift/QtUI/Trellis/QtDynamicGridLayout.cpp23
-rw-r--r--Swift/QtUI/Trellis/QtDynamicGridLayout.h4
-rw-r--r--Swift/QtUI/Trellis/QtGridSelectionDialog.cpp6
-rw-r--r--Swift/QtUI/UserSearch/ContactListModel.cpp28
-rw-r--r--Swift/QtUI/UserSearch/QtUserSearchWindow.h50
70 files changed, 2223 insertions, 734 deletions
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.cpp b/Swift/QtUI/ChatList/QtChatListWindow.cpp
index 3caed57..2fd05c4 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.cpp
+++ b/Swift/QtUI/ChatList/QtChatListWindow.cpp
@@ -86,11 +86,9 @@ void QtChatListWindow::handleClicked(const QModelIndex& index) {
void QtChatListWindow::setupContextMenus() {
mucMenu_ = new QMenu();
- onlineOnlyActions_ << mucMenu_->addAction(tr("Add New Bookmark"), this, SLOT(handleAddBookmark()));
onlineOnlyActions_ << mucMenu_->addAction(tr("Edit Bookmark"), this, SLOT(handleEditBookmark()));
onlineOnlyActions_ << mucMenu_->addAction(tr("Remove Bookmark"), this, SLOT(handleRemoveBookmark()));
emptyMenu_ = new QMenu();
- onlineOnlyActions_ << emptyMenu_->addAction(tr("Add New Bookmark"), this, SLOT(handleAddBookmark()));
}
void QtChatListWindow::handleItemActivated(const QModelIndex& index) {
@@ -132,7 +130,7 @@ void QtChatListWindow::setRecents(const std::list<ChatListWindow::Chat>& recents
model_->setRecents(recents);
}
-void QtChatListWindow::setUnreadCount(int unread) {
+void QtChatListWindow::setUnreadCount(size_t unread) {
emit onCountUpdated(unread);
}
@@ -146,22 +144,6 @@ void QtChatListWindow::handleRemoveBookmark() {
eventStream_->send(std::make_shared<RemoveMUCBookmarkUIEvent>(mucItem->getBookmark()));
}
-void QtChatListWindow::handleAddBookmarkFromRecents() {
- const ChatListRecentItem* item = dynamic_cast<const ChatListRecentItem*>(contextMenuItem_);
- if (item) {
- const ChatListWindow::Chat& chat = item->getChat();
- MUCBookmark bookmark(chat.jid, chat.jid.toBare().toString());
- bookmark.setNick(chat.nick);
- bookmark.setPassword(chat.password);
- eventStream_->send(std::make_shared<AddMUCBookmarkUIEvent>(bookmark));
- }
-}
-
-void QtChatListWindow::handleAddBookmark() {
- (new QtAddBookmarkWindow(eventStream_))->show();
-}
-
-
void QtChatListWindow::handleEditBookmark() {
const ChatListMUCItem* mucItem = dynamic_cast<const ChatListMUCItem*>(contextMenuItem_);
if (!mucItem) return;
@@ -208,11 +190,8 @@ void QtChatListWindow::contextMenuEvent(QContextMenuEvent* event) {
if (mucItem) {
contextMenuItem_ = mucItem;
bookmarkAction = mucRecentsMenu.addAction(tr("Edit Bookmark"), this, SLOT(handleEditBookmark()));
+ bookmarkAction->setEnabled(isOnline_);
}
- else {
- bookmarkAction = mucRecentsMenu.addAction(tr("Add to Bookmarks"), this, SLOT(handleAddBookmarkFromRecents()));
- }
- bookmarkAction->setEnabled(isOnline_);
mucRecentsMenu.addAction(tr("Clear recents"), this, SLOT(handleClearRecentsRequested()));
mucRecentsMenu.exec(QCursor::pos());
return;
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.h b/Swift/QtUI/ChatList/QtChatListWindow.h
index 834e318..3322001 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.h
+++ b/Swift/QtUI/ChatList/QtChatListWindow.h
@@ -27,18 +27,16 @@ namespace Swift {
void removeWhiteboardSession(const JID& jid);
void setBookmarksEnabled(bool enabled);
void setRecents(const std::list<ChatListWindow::Chat>& recents);
- void setUnreadCount(int unread);
+ void setUnreadCount(size_t unread);
void clearBookmarks();
virtual void setOnline(bool isOnline);
signals:
- void onCountUpdated(int count);
+ void onCountUpdated(size_t count);
private slots:
void handleItemActivated(const QModelIndex&);
- void handleAddBookmark();
void handleEditBookmark();
void handleRemoveBookmark();
- void handleAddBookmarkFromRecents();
void handleClicked(const QModelIndex& index);
void handleSettingChanged(const std::string& setting);
void handleClearRecentsRequested();
diff --git a/Swift/QtUI/ChattablesModel.cpp b/Swift/QtUI/ChattablesModel.cpp
new file mode 100644
index 0000000..67d0579
--- /dev/null
+++ b/Swift/QtUI/ChattablesModel.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/QtUI/ChattablesModel.h>
+
+#include <QDebug>
+
+#include <Swift/Controllers/Chat/Chattables.h>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+ChattablesModel::ChattablesModel(Chattables& chattables, QObject* parent) : QAbstractListModel(parent), chattables_(chattables) {
+ using scoped_connection = boost::signals2::scoped_connection;
+ connectionList_.emplace_back(std::make_unique<scoped_connection>(
+ chattables_.onBeginAdd.connect([this](int index) {beginInsertRows(QModelIndex(), index, index);})
+ ));
+ connectionList_.emplace_back(std::make_unique<scoped_connection>(
+ chattables_.onAdded.connect([this]() {endInsertRows();})
+ ));
+ connectionList_.emplace_back(std::make_unique<scoped_connection>(
+ chattables_.onChanged.connect(
+ [this](const JID& jid, int index) {
+ auto modelIndex = createIndex(index, 0, const_cast<JID*>(&jid));
+ dataChanged(modelIndex, modelIndex, {});
+ }
+ )
+ ));
+}
+
+int ChattablesModel::rowCount(const QModelIndex& /*parent*/) const {
+ return chattables_.get().size();
+}
+
+QVariant ChattablesModel::data(const QModelIndex& index, int role) const {
+ //FIXME: Check validity
+ auto state = chattables_.getState(chattables_.get()[index.row()]);
+ if (role == Qt::DisplayRole) {
+ return P2QSTRING((state.name.empty() ? state.jid.toString() : state.name));
+ }
+ if (role == UnreadCountRole) {
+ return QString::number(state.unreadCount);
+ }
+ if (role == TypeRole) {
+ switch (state.type) {
+ case Chattables::State::Type::Room: return "ROOM";
+ case Chattables::State::Type::Person: return "PERSON";
+ }
+ }
+ if (role == StatusRole) {
+ return QVariant(static_cast<int>(state.status));
+ }
+ if (role == JIDRole) {
+ return P2QSTRING(state.jid.toString());
+ }
+ return QVariant();
+}
+
+}
diff --git a/Swift/QtUI/ChattablesModel.h b/Swift/QtUI/ChattablesModel.h
new file mode 100644
index 0000000..6617d97
--- /dev/null
+++ b/Swift/QtUI/ChattablesModel.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <boost/signals2/connection.hpp>
+
+#include <QAbstractListModel>
+
+namespace Swift {
+class Chattables;
+class ChattablesModel : public QAbstractListModel {
+ public:
+ enum ChattablesRoles {
+ UnreadCountRole = Qt::UserRole,
+ TypeRole = Qt::UserRole + 1,
+ StatusRole = Qt::UserRole + 2,
+ JIDRole = Qt::UserRole + 3
+ };
+ ChattablesModel(Chattables& chattables, QObject* parent);
+ int rowCount(const QModelIndex& parent = QModelIndex()) const;
+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
+ private:
+ Chattables& chattables_;
+ std::vector<std::unique_ptr<boost::signals2::scoped_connection>> connectionList_;
+};
+
+}
diff --git a/Swift/QtUI/FlowLayout.cpp b/Swift/QtUI/FlowLayout.cpp
index c42b7e1..8a12841 100644
--- a/Swift/QtUI/FlowLayout.cpp
+++ b/Swift/QtUI/FlowLayout.cpp
@@ -49,7 +49,6 @@
****************************************************************************/
#include <QtWidgets>
-
#include "FlowLayout.h"
FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
: QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
@@ -108,12 +107,12 @@ QLayoutItem *FlowLayout::takeAt(int index)
if (index >= 0 && index < itemList.size())
return itemList.takeAt(index);
else
- return 0;
+ return nullptr;
}
Qt::Orientations FlowLayout::expandingDirections() const
{
- return 0;
+ return nullptr;
}
bool FlowLayout::hasHeightForWidth() const
@@ -192,7 +191,7 @@ int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
return -1;
} else if (parent->isWidgetType()) {
QWidget *pw = static_cast<QWidget *>(parent);
- return pw->style()->pixelMetric(pm, 0, pw);
+ return pw->style()->pixelMetric(pm, nullptr, pw);
} else {
return static_cast<QLayout *>(parent)->spacing();
}
diff --git a/Swift/QtUI/FlowLayout.h b/Swift/QtUI/FlowLayout.h
index 1453d45..29d527f 100644
--- a/Swift/QtUI/FlowLayout.h
+++ b/Swift/QtUI/FlowLayout.h
@@ -59,7 +59,7 @@ class FlowLayout : public QLayout
public:
explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
- ~FlowLayout();
+ ~FlowLayout() override;
void addItem(QLayoutItem *item) override;
int horizontalSpacing() const;
diff --git a/Swift/QtUI/QtBookmarkDetailWindow.cpp b/Swift/QtUI/QtBookmarkDetailWindow.cpp
index 920e94e..efa0e25 100644
--- a/Swift/QtUI/QtBookmarkDetailWindow.cpp
+++ b/Swift/QtUI/QtBookmarkDetailWindow.cpp
@@ -42,7 +42,7 @@ boost::optional<MUCBookmark> QtBookmarkDetailWindow::createBookmarkFromForm() {
MUCBookmark bookmark(room, name);
std::string nick(Q2PSTRING(nick_->text()));
std::string password(Q2PSTRING(password_->text()));
- bookmark.setAutojoin(autojoin_->isChecked());
+ bookmark.setAutojoin(true);
if (!nick.empty()) {
bookmark.setNick(nick);
}
@@ -68,12 +68,6 @@ void QtBookmarkDetailWindow::createFormFromBookmark(const MUCBookmark& bookmark)
if (bookmark.getPassword()) {
password_->setText(P2QSTRING((*bookmark.getPassword())));
}
-
- if (bookmark.getAutojoin()) {
- autojoin_->setCheckState(Qt::Checked);
- } else {
- autojoin_->setCheckState(Qt::Unchecked);
- }
}
}
diff --git a/Swift/QtUI/QtBookmarkDetailWindow.ui b/Swift/QtUI/QtBookmarkDetailWindow.ui
index be55686..affb7e4 100644
--- a/Swift/QtUI/QtBookmarkDetailWindow.ui
+++ b/Swift/QtUI/QtBookmarkDetailWindow.ui
@@ -82,29 +82,6 @@
<item row="3" column="1">
<widget class="QLineEdit" name="password_"/>
</item>
- <item row="4" column="0">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="4" column="1">
- <widget class="QCheckBox" name="autojoin_">
- <property name="text">
- <string>Enter automatically</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
</layout>
</item>
<item>
diff --git a/Swift/QtUI/QtCachedImageScaler.cpp b/Swift/QtUI/QtCachedImageScaler.cpp
index e1f540b..445d113 100644
--- a/Swift/QtUI/QtCachedImageScaler.cpp
+++ b/Swift/QtUI/QtCachedImageScaler.cpp
@@ -21,7 +21,7 @@ QtCachedImageScaler::QtCachedImageScaler() {
boost::filesystem::path QtCachedImageScaler::getScaledImage(const boost::filesystem::path& imagePath, int size) {
boost::filesystem::path scaledImagePath(imagePath);
- std::string suffix = "." + boost::lexical_cast<std::string>(size);
+ std::string suffix = "." + std::to_string(size);
scaledImagePath = stringToPath(pathToString(scaledImagePath) + suffix);
if (!boost::filesystem::exists(scaledImagePath)) {
QImage image(P2QSTRING(pathToString(imagePath)));
diff --git a/Swift/QtUI/QtChatOverview.cpp b/Swift/QtUI/QtChatOverview.cpp
new file mode 100644
index 0000000..76943e9
--- /dev/null
+++ b/Swift/QtUI/QtChatOverview.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/QtUI/QtChatOverview.h>
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPalette>
+#include <QVBoxLayout>
+
+#include <Swift/Controllers/Chat/Chattables.h>
+
+#include <Swift/QtUI/ChattablesModel.h>
+#include <Swift/QtUI/QtChatOverviewBundle.h>
+
+namespace Swift {
+
+QtChatOverview::QtChatOverview(Chattables& chattables, QWidget* parent) : QWidget(parent), chattables_(chattables) {
+ QPalette newPalette = palette();
+ newPalette.setColor(QPalette::Background, {38, 81, 112});
+ setAutoFillBackground(true);
+ newPalette.setColor(QPalette::Foreground, {255, 255, 255});
+ setPalette(newPalette);
+
+ auto mainLayout = new QVBoxLayout();
+ setLayout(mainLayout);
+
+ auto headerLayout = new QHBoxLayout();
+ mainLayout->addLayout(headerLayout);
+ auto allLabel = new QLabel(tr("All"), this);
+ allLabel->setStyleSheet("color: white;");
+ auto peopleLabel = new QLabel(tr("People"), this);
+ peopleLabel->setStyleSheet("color: white;");
+ auto roomsLabel = new QLabel(tr("Rooms"), this);
+ roomsLabel->setStyleSheet("color: white;");
+ headerLayout->addWidget(allLabel);
+ headerLayout->addWidget(peopleLabel);
+ headerLayout->addWidget(roomsLabel);
+
+ rootModel_ = new ChattablesModel(chattables_, this);
+
+ auto unreadBundle = new QtChatOverviewBundle(rootModel_, "UNREAD", true, this);
+ connect(unreadBundle, SIGNAL(clicked(JID)), this, SLOT(handleItemClicked(JID)));
+ mainLayout->addWidget(unreadBundle);
+
+ auto peopleBundle = new QtChatOverviewBundle(rootModel_, "PEOPLE", false, this);
+ connect(peopleBundle, SIGNAL(clicked(JID)), this, SLOT(handleItemClicked(JID)));
+ mainLayout->addWidget(peopleBundle);
+
+ auto roomsBundle = new QtChatOverviewBundle(rootModel_, "ROOMS", false, this);
+ connect(roomsBundle, SIGNAL(clicked(JID)), this, SLOT(handleItemClicked(JID)));
+ mainLayout->addWidget(roomsBundle);
+
+ mainLayout->addStretch();
+}
+
+QtChatOverview::~QtChatOverview() {}
+
+void QtChatOverview::handleItemClicked(JID jid) {
+ chattables_.onActivated(jid);
+}
+
+} // namespace Swift
diff --git a/Swift/QtUI/QtChatOverview.h b/Swift/QtUI/QtChatOverview.h
new file mode 100644
index 0000000..8cd7762
--- /dev/null
+++ b/Swift/QtUI/QtChatOverview.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <QWidget>
+
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+ class Chattables;
+ class ChattablesModel;
+ class QtChatOverview : public QWidget {
+ Q_OBJECT
+ public:
+ QtChatOverview(Chattables&, QWidget* parent);
+ ~QtChatOverview() override;
+
+ private slots:
+ void handleItemClicked(JID jid);
+ private:
+ Chattables& chattables_;
+ ChattablesModel* rootModel_;
+ };
+}
diff --git a/Swift/QtUI/QtChatOverviewBundle.cpp b/Swift/QtUI/QtChatOverviewBundle.cpp
new file mode 100644
index 0000000..121ae2e
--- /dev/null
+++ b/Swift/QtUI/QtChatOverviewBundle.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/QtUI/QtChatOverviewBundle.h>
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPalette>
+#include <QSortFilterProxyModel>
+#include <QVBoxLayout>
+
+#include <Swiften/Elements/StatusShow.h>
+
+#include <Swift/QtUI/ChattablesModel.h>
+#include <Swift/QtUI/QtChatOverviewDelegate.h>
+#include <Swift/QtUI/QtClickableLabel.h>
+#include <Swift/QtUI/QtExpandedListView.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+BundleFilter::BundleFilter(QObject* parent) : QSortFilterProxyModel(parent) {
+ sort(0, Qt::AscendingOrder);
+ setDynamicSortFilter(true);
+ setSortCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
+}
+
+void BundleFilter::addFilter(Filter filter) {
+ filters_.emplace(filter);
+ invalidateFilter();
+}
+
+bool BundleFilter::hasFilter(Filter filter) {
+ return filters_.count(filter) > 0;
+}
+
+void BundleFilter::removeFilter(Filter filter) {
+ filters_.erase(filter);
+ invalidateFilter();
+}
+
+bool BundleFilter::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const {
+ auto row = sourceModel()->index(sourceRow, 0, sourceParent);
+ if (filters_.count(Filter::Unread)) {
+ if (row.data(ChattablesModel::UnreadCountRole).toInt() == 0) {
+ return false;
+ }
+ }
+ if (filters_.count(Filter::People)) {
+ if (row.data(ChattablesModel::TypeRole).toString() != "PERSON") {
+ return false;
+ }
+ }
+ if (filters_.count(Filter::Rooms)) {
+ if (row.data(ChattablesModel::TypeRole).toString() != "ROOM") {
+ return false;
+ }
+ }
+ if (filters_.count(Filter::Online)) {
+ if (static_cast<StatusShow::Type>(row.data(ChattablesModel::StatusRole).toInt()) == StatusShow::None) {
+ return false;
+ }
+ }
+ return true;
+}
+
+QtChatOverviewBundle::QtChatOverviewBundle(ChattablesModel* rootModel, QString name, bool hideWhenEmpty, QWidget* parent) : QWidget(parent), rootModel_(rootModel), hideWhenEmpty_(hideWhenEmpty) {
+ proxyModel_ = new BundleFilter(this);
+ if (name == "UNREAD") { // FIXME: Obviously needs a better approach
+ proxyModel_->addFilter(BundleFilter::Filter::Unread);
+ }
+ if (name == "PEOPLE") {
+ proxyModel_->addFilter(BundleFilter::Filter::People);
+ proxyModel_->addFilter(BundleFilter::Filter::Online);
+ }
+ if (name == "ROOMS") {
+ proxyModel_->addFilter(BundleFilter::Filter::Rooms);
+ proxyModel_->addFilter(BundleFilter::Filter::Online);
+ }
+ proxyModel_->setSourceModel(rootModel);
+
+
+ auto mainLayout = new QVBoxLayout();
+ setLayout(mainLayout);
+
+ auto headerLayout = new QHBoxLayout();
+ mainLayout->addLayout(headerLayout);
+ auto nameLabel = new QLabel(name, this);
+ nameLabel->setStyleSheet("color: white;");
+ headerLayout->addWidget(nameLabel);
+ headerLayout->addStretch();
+ if (!hideWhenEmpty_) {
+ filterLabel_ = new QtClickableLabel(this);
+ filterLabel_->setText(tr("Online"));
+ filterLabel_->setStyleSheet("color: white;");
+ headerLayout->addWidget(filterLabel_);
+ connect(filterLabel_, SIGNAL(clicked()), this, SLOT(handleFilterClicked()));
+ }
+ listView_ = new QtExpandedListView(this);
+ listView_->setModel(proxyModel_);
+ listView_->setFrameStyle(QFrame::NoFrame);
+ listView_->setItemDelegate(new QtChatOverviewDelegate(this));
+ connect(listView_, SIGNAL(clicked(const QModelIndex&)), this, SLOT(handleItemClicked(const QModelIndex&)));
+ mainLayout->addWidget(listView_);
+
+ if (hideWhenEmpty_) {
+ connect(proxyModel_, &QAbstractItemModel::modelReset, this, [&](){
+ updateVisibility();
+ });
+ connect(proxyModel_, &QAbstractItemModel::rowsInserted, this, [&](){
+ updateVisibility();
+ });
+ connect(proxyModel_, &QAbstractItemModel::rowsRemoved, this, [&](){
+ updateVisibility();
+ });
+ updateVisibility();
+ }
+}
+
+QtChatOverviewBundle::~QtChatOverviewBundle() {}
+
+void QtChatOverviewBundle::handleFilterClicked() {
+ if (proxyModel_->hasFilter(BundleFilter::Filter::Online)) {
+ proxyModel_->removeFilter(BundleFilter::Filter::Online);
+ filterLabel_->setText(tr("All"));
+ }
+ else {
+ proxyModel_->addFilter(BundleFilter::Filter::Online);
+ filterLabel_->setText(tr("Online"));
+ }
+}
+
+void QtChatOverviewBundle::updateVisibility() {
+ auto shouldBeVisible = (proxyModel_->rowCount(listView_->rootIndex()) > 0);
+ setVisible(shouldBeVisible);
+}
+
+
+void QtChatOverviewBundle::handleItemClicked(const QModelIndex& index) {
+ clicked(JID(Q2PSTRING(index.data(ChattablesModel::JIDRole).toString())));
+}
+
+} // namespace Swift
diff --git a/Swift/QtUI/QtChatOverviewBundle.h b/Swift/QtUI/QtChatOverviewBundle.h
new file mode 100644
index 0000000..95fd5d2
--- /dev/null
+++ b/Swift/QtUI/QtChatOverviewBundle.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <set>
+
+#include <QSortFilterProxyModel>
+#include <QString>
+#include <QWidget>
+
+#include <Swiften/JID/JID.h>
+
+class QListView;
+
+namespace Swift {
+ class ChattablesModel;
+ class QtClickableLabel;
+ class QtExpandedListView;
+
+ class BundleFilter : public QSortFilterProxyModel {
+ Q_OBJECT
+ public:
+ enum class Filter {Unread, People, Rooms, Online};
+ BundleFilter(QObject* parent);
+ void addFilter(Filter);
+ bool hasFilter(Filter);
+ void removeFilter(Filter);
+ protected:
+ bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const;
+ private:
+ std::set<Filter> filters_;
+ };
+
+ class QtChatOverviewBundle : public QWidget {
+ Q_OBJECT
+ public:
+ QtChatOverviewBundle(ChattablesModel*, QString name, bool hideWhenEmpty, QWidget* parent);
+ ~QtChatOverviewBundle() override;
+
+ signals:
+ void clicked(JID jid);
+
+ private slots:
+ void handleFilterClicked();
+ void handleItemClicked(const QModelIndex&);
+
+ private:
+ void updateVisibility();
+
+ private:
+ ChattablesModel* rootModel_;
+ QtExpandedListView* listView_;
+ BundleFilter* proxyModel_;
+ bool hideWhenEmpty_;
+ QtClickableLabel* filterLabel_ = nullptr;
+ };
+}
diff --git a/Swift/QtUI/QtChatOverviewDelegate.cpp b/Swift/QtUI/QtChatOverviewDelegate.cpp
new file mode 100644
index 0000000..00821fe
--- /dev/null
+++ b/Swift/QtUI/QtChatOverviewDelegate.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/QtUI/QtChatOverviewDelegate.h>
+
+#include <Swiften/Elements/StatusShow.h>
+
+#include <Swift/QtUI/ChattablesModel.h>
+#include <Swift/QtUI/Roster/DelegateCommons.h>
+
+namespace Swift {
+
+QtChatOverviewDelegate::QtChatOverviewDelegate(QObject* parent) : QItemDelegate(parent), nameFont(QApplication::font()) {
+
+}
+
+QtChatOverviewDelegate::~QtChatOverviewDelegate() {}
+
+QSize QtChatOverviewDelegate::sizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const {
+ int heightByAvatar = DelegateCommons::avatarSize + DelegateCommons::verticalMargin * 2;
+ QFontMetrics nameMetrics(nameFont);
+ int sizeByText = 2 * DelegateCommons::verticalMargin + nameMetrics.height();
+ return QSize(150, sizeByText > heightByAvatar ? sizeByText : heightByAvatar);
+}
+
+void QtChatOverviewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
+ painter->save();
+ QRect fullRegion(option.rect);
+ const int statusCircleRadius = 3;
+ const int horizontalMargin = 4;
+
+ QColor bgColor(38, 81, 112);
+ QPen fontPen("white"); // FIXME
+
+ if (option.state & QStyle::State_Selected) {
+ //FIXME
+ }
+ painter->fillRect(fullRegion, bgColor);
+ painter->setPen(fontPen);
+
+ QFontMetrics nameMetrics(nameFont);
+ painter->setFont(nameFont);
+ QRect nameRegion(fullRegion.adjusted((horizontalMargin + statusCircleRadius) * 2, DelegateCommons::verticalMargin, 0, 0));
+ DelegateCommons::drawElidedText(painter, nameRegion, index.data(Qt::DisplayRole).toString());
+
+ const auto green = QColor(124, 243, 145);
+ const auto yellow = QColor(243, 243, 0);
+ const auto red = QColor(255, 45, 71);
+ const auto grey = QColor(159,159,159);
+ auto circleColour = grey;
+ auto status = static_cast<StatusShow::Type>(index.data(ChattablesModel::StatusRole).toInt());
+ switch (status) {
+ case StatusShow::Online: circleColour = green; break;
+ case StatusShow::FFC: circleColour = green; break;
+ case StatusShow::Away: circleColour = yellow; break;
+ case StatusShow::XA: circleColour = yellow; break;
+ case StatusShow::DND: circleColour = red; break;
+ case StatusShow::None: circleColour = grey; break;
+ }
+
+ painter->setRenderHint(QPainter::Antialiasing, true);
+
+ int unreadCount = index.data(ChattablesModel::UnreadCountRole).toInt();
+ if (unreadCount > 0) {
+ int unreadCountSize = 16;
+ QRect unreadRect(fullRegion.right() - unreadCountSize - horizontalMargin, fullRegion.top() + (fullRegion.height() - unreadCountSize) / 2, unreadCountSize, unreadCountSize);
+ QPen pen(QColor("white"));
+ pen.setWidth(1);
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setPen(pen);
+ painter->drawEllipse(unreadRect);
+ painter->setBackgroundMode(Qt::TransparentMode);
+ painter->setPen(QColor("white"));
+ DelegateCommons::drawElidedText(painter, unreadRect, QString("%1").arg(unreadCount), Qt::AlignCenter);
+ }
+
+ painter->setPen(circleColour);
+ painter->setBrush(circleColour);
+ painter->drawEllipse(fullRegion.topLeft() + QPointF(horizontalMargin + 4, fullRegion.height() / 2), statusCircleRadius, statusCircleRadius);
+
+
+ painter->restore();
+}
+
+} // namespace Swift
diff --git a/Swift/QtUI/QtChatOverviewDelegate.h b/Swift/QtUI/QtChatOverviewDelegate.h
new file mode 100644
index 0000000..b00337d
--- /dev/null
+++ b/Swift/QtUI/QtChatOverviewDelegate.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <QItemDelegate>
+#include <QFont>
+
+namespace Swift {
+ class QtChatOverviewDelegate : public QItemDelegate {
+ Q_OBJECT
+ public:
+ QtChatOverviewDelegate(QObject* parent);
+ ~QtChatOverviewDelegate() override;
+ QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
+ void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
+ private:
+ QFont nameFont;
+ };
+}
diff --git a/Swift/QtUI/QtChatTabs.cpp b/Swift/QtUI/QtChatTabs.cpp
index f4d0d46..edd0b87 100644
--- a/Swift/QtUI/QtChatTabs.cpp
+++ b/Swift/QtUI/QtChatTabs.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -24,6 +24,7 @@
#include <Swiften/Base/Log.h>
#include <Swift/Controllers/ChatMessageSummarizer.h>
+#include <Swift/Controllers/SettingConstants.h>
#include <Swift/QtUI/QtSwiftUtil.h>
#include <Swift/QtUI/QtTabWidget.h>
@@ -33,13 +34,13 @@
#include <Swift/QtUI/Trellis/QtGridSelectionDialog.h>
namespace Swift {
-QtChatTabs::QtChatTabs(bool singleWindow, SettingsProvider* settingsProvider, bool trellisMode) : QWidget(), singleWindow_(singleWindow), settingsProvider_(settingsProvider), trellisMode_(trellisMode), dynamicGrid_(nullptr), gridSelectionDialog_(nullptr) {
+QtChatTabs::QtChatTabs(SettingsProvider* settingsProvider, bool trellisMode) : QWidget(), settingsProvider_(settingsProvider), trellisMode_(trellisMode), dynamicGrid_(nullptr), gridSelectionDialog_(nullptr) {
#ifndef Q_OS_MAC
setWindowIcon(QIcon(":/logo-chat-16.png"));
#else
setAttribute(Qt::WA_ShowWithoutActivating);
#endif
- dynamicGrid_ = new QtDynamicGridLayout(this, trellisMode);
+ dynamicGrid_ = new QtDynamicGridLayout(settingsProvider->getSetting(SettingConstants::FUTURE), this, trellisMode);
connect(dynamicGrid_, SIGNAL(tabCloseRequested(int)), this, SLOT(handleTabCloseRequested(int)));
connect(dynamicGrid_, SIGNAL(onCurrentIndexChanged(int)), this, SLOT(handleCurrentTabIndexChanged(int)));
@@ -199,13 +200,8 @@ void QtChatTabs::handleTabClosing() {
if (widget && ((index = dynamicGrid_->indexOf(widget)) >= 0)) {
dynamicGrid_->removeTab(index);
if (dynamicGrid_->count() == 0) {
- if (!singleWindow_) {
- hide();
- }
- else {
- setWindowTitle("");
- onTitleChanged("");
- }
+ setWindowTitle("");
+ onTitleChanged("");
}
else {
handleTabTitleUpdated(dynamicGrid_->currentWidget());
@@ -425,4 +421,8 @@ void QtChatTabs::checkForFirstShow() {
}
}
+QSize QtChatTabs::sizeHint() const {
+ return QSize(600, 600);
+}
+
}
diff --git a/Swift/QtUI/QtChatTabs.h b/Swift/QtUI/QtChatTabs.h
index 0c12d96..6a758ca 100644
--- a/Swift/QtUI/QtChatTabs.h
+++ b/Swift/QtUI/QtChatTabs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -26,13 +26,14 @@ namespace Swift {
class QtChatTabs : public QWidget, public QtChatTabsBase {
Q_OBJECT
public:
- QtChatTabs(bool singleWindow, SettingsProvider* settingsProvider, bool trellisMode);
+ QtChatTabs(SettingsProvider* settingsProvider, bool trellisMode);
virtual ~QtChatTabs();
virtual void addTab(QtTabbable* tab);
void minimise();
QtTabbable* getCurrentTab();
void setViewMenu(QMenu* viewMenu);
+ QSize sizeHint() const;
signals:
void geometryChanged();
@@ -65,7 +66,6 @@ namespace Swift {
void checkForFirstShow();
private:
- bool singleWindow_;
SettingsProvider* settingsProvider_;
bool trellisMode_;
QtDynamicGridLayout* dynamicGrid_;
diff --git a/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.cpp b/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.cpp
deleted file mode 100644
index 40ab17f..0000000
--- a/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2015-2016 Isode Limited.
- * All rights reserved.
- * See the COPYING file for more information.
- */
-
-#include <Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h>
-
-#include <cassert>
-
-#include <QApplication>
-#include <QShortcut>
-
-#include <Swiften/Base/Log.h>
-
-#include <Swift/QtUI/QtTabbable.h>
-
-namespace Swift {
-
-QtChatTabsShortcutOnlySubstitute::QtChatTabsShortcutOnlySubstitute() : QWidget() {
-
-}
-
-QtChatTabsShortcutOnlySubstitute::~QtChatTabsShortcutOnlySubstitute() {
-
-}
-
-void QtChatTabsShortcutOnlySubstitute::addTab(QtTabbable* tab) {
- connect(tab, SIGNAL(requestNextTab()), this, SLOT(handleRequestedNextTab()), Qt::UniqueConnection);
- connect(tab, SIGNAL(requestActiveTab()), this, SLOT(handleRequestedActiveTab()), Qt::UniqueConnection);
- connect(tab, SIGNAL(requestPreviousTab()), this, SLOT(handleRequestedPreviousTab()), Qt::UniqueConnection);
-
- connect(new QShortcut(QKeySequence(tr("CTRL+W", "Close chat tab.")), tab), SIGNAL(activated()), this, SLOT(handleCloseTabShortcut()));
- connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_PageUp), tab), SIGNAL(activated()), tab, SIGNAL(requestPreviousTab()));
- connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_PageDown), tab), SIGNAL(activated()), tab, SIGNAL(requestNextTab()));
- connect(new QShortcut(QKeySequence(Qt::ALT + Qt::Key_A), tab), SIGNAL(activated()), tab, SIGNAL(requestActiveTab()));
-}
-
-void QtChatTabsShortcutOnlySubstitute::handleCloseTabShortcut() {
- QtTabbable* senderTab = dynamic_cast<QtTabbable*>(sender()->parent());
- SWIFT_LOG_ASSERT(senderTab, debug) << "No window to close." << std::endl;
- if (senderTab) {
- senderTab->close();
- }
-}
-
-void QtChatTabsShortcutOnlySubstitute::handleRequestedNextTab() {
- QtTabbable* senderTab = dynamic_cast<QtTabbable*>(sender());
-
- QList<QtTabbable*> tabs = tabbableWindows();
-
- int currentIndex = tabs.indexOf(senderTab);
- assert(currentIndex >= 0);
-
- QtTabbable* nextTab = tabs.at((currentIndex + 1) % tabs.size());
- nextTab->activateWindow();
-}
-
-void QtChatTabsShortcutOnlySubstitute::handleRequestedActiveTab() {
- QtTabbable* senderTab = dynamic_cast<QtTabbable*>(sender());
-
- QtTabbable::AlertType types[] = {QtTabbable::WaitingActivity, QtTabbable::ImpendingActivity};
-
- QList<QtTabbable*> tabs = tabbableWindows();
-
- for (auto& type : types) {
- int startIndex = tabs.indexOf(senderTab);
- int currentIndex = startIndex;
-
- do {
- currentIndex = (currentIndex + 1) % tabs.size();
- QtTabbable* currentTab = tabs.at(currentIndex);
- if (currentTab->getWidgetAlertState() == type) {
- currentTab->activateWindow();
- return;
- }
- } while (startIndex != currentIndex);
- }
-}
-
-void QtChatTabsShortcutOnlySubstitute::handleRequestedPreviousTab() {
- QtTabbable* senderTab = dynamic_cast<QtTabbable*>(sender());
-
- QList<QtTabbable*> tabs = tabbableWindows();
-
- int currentIndex = tabs.indexOf(senderTab);
- assert(currentIndex >= 0);
-
- QtTabbable* previousTab = tabs.at((currentIndex + tabs.size() - 1) % tabs.size());
- previousTab->activateWindow();
-}
-
-QList<QtTabbable*> QtChatTabsShortcutOnlySubstitute::tabbableWindows() const {
- QList<QWidget*> windows = qApp->topLevelWidgets();
-
- QList<QtTabbable*> tabbables;
- for (auto topLevelWidget : windows) {
- QtTabbable* tabbable = dynamic_cast<QtTabbable*>(topLevelWidget);
- if (tabbable) {
- tabbables << tabbable;
- }
- }
-
- return tabbables;
-}
-
-}
-
diff --git a/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h b/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h
deleted file mode 100644
index b330fe7..0000000
--- a/Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2015-2016 Isode Limited.
- * All rights reserved.
- * See the COPYING file for more information.
- */
-
-#pragma once
-
-#include <QList>
-#include <QWidget>
-
-#include <Swift/QtUI/QtChatTabsBase.h>
-
-class QShortcut;
-
-namespace Swift {
-
-class QtChatTabsShortcutOnlySubstitute : public QWidget, public QtChatTabsBase {
- Q_OBJECT
-
- public:
- QtChatTabsShortcutOnlySubstitute();
- virtual ~QtChatTabsShortcutOnlySubstitute();
-
- virtual void addTab(QtTabbable* tab);
-
- private slots:
- void handleCloseTabShortcut();
- void handleRequestedNextTab();
- void handleRequestedActiveTab();
- void handleRequestedPreviousTab();
-
- private:
- QList<QtTabbable*> tabbableWindows() const;
-
- private:
- QList<QShortcut*> shortcuts_;
-};
-
-}
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 874f710..82c65ce 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -111,8 +111,11 @@ QtChatWindow::QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventSt
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.
+ messageLog_ = new QtWebKitChatView(this, eventStream_, theme, this, settings); // 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.
}
+ // When used with QSplitter and setChildrenCollapsible(false), the following prevents
+ // this widget to be hidden, i.e. resized to zero width.
+ messageLog_->setMinimumWidth(20);
logRosterSplitter_->addWidget(messageLog_);
treeWidget_ = new QtOccupantListWidget(eventStream_, settings_, QtTreeWidget::MessageDisplayJID, this);
@@ -152,11 +155,15 @@ QtChatWindow::QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventSt
connect(input_, SIGNAL(lostFocus()), this, SLOT(handleTextInputLostFocus()));
connect(input_, SIGNAL(itemDropped(QDropEvent*)), this, SLOT(dropEvent(QDropEvent*)));
QPushButton* emojisButton_ = new QPushButton(this);
-
-#ifdef SWIFTEN_PLATFORM_MACOSX
emojisButton_->setText("\xF0\x9F\x98\x83");
-#else
- emojisButton_->setIcon(QIcon(":/emoticons/smile.png"));
+
+#if defined(SWIFTEN_PLATFORM_WINDOWS) || defined(SWIFTEN_PLATFORM_LINUX)
+ //Using a emoji glyph instead of an image makes the button sizes inequal in windows & linux,
+ //so we set fixed size for both buttons, the one that is hinted for actionButton_
+ emojisButton_->setMaximumWidth(actionButton_->sizeHint().width());
+ emojisButton_->setMaximumHeight(actionButton_->sizeHint().height());
+ actionButton_->setMaximumWidth(actionButton_->sizeHint().width());
+ actionButton_->setMaximumHeight(actionButton_->sizeHint().height());
#endif
connect(emojisButton_, SIGNAL(clicked()), this, SLOT(handleEmojisButtonClicked()));
@@ -353,6 +360,10 @@ QByteArray QtChatWindow::getSplitterState() {
void QtChatWindow::handleChangeSplitterState(QByteArray state) {
logRosterSplitter_->restoreState(state);
+#ifdef SWIFTEN_PLATFORM_MACOSX
+ logRosterSplitter_->setHandleWidth(0);
+#endif
+ logRosterSplitter_->setChildrenCollapsible(false);
}
void QtChatWindow::handleSplitterMoved(int, int) {
@@ -494,7 +505,7 @@ void QtChatWindow::showEvent(QShowEvent* event) {
QWidget::showEvent(event);
}
-void QtChatWindow::setUnreadMessageCount(int count) {
+void QtChatWindow::setUnreadMessageCount(size_t count) {
if (unreadCount_ != count) {
unreadCount_ = count;
updateTitleWithUnreadCount();
@@ -536,7 +547,7 @@ void QtChatWindow::flash() {
emit requestFlash();
}
-int QtChatWindow::getCount() {
+size_t QtChatWindow::getCount() {
return unreadCount_;
}
@@ -693,7 +704,7 @@ void QtChatWindow::handleEmojisButtonClicked() {
emojisLayout->setContentsMargins(style()->pixelMetric(QStyle::PM_MenuHMargin),style()->pixelMetric(QStyle::PM_MenuVMargin),
style()->pixelMetric(QStyle::PM_MenuHMargin),style()->pixelMetric(QStyle::PM_MenuVMargin));
emojisLayout->addWidget(emojisGrid_);
- emojisMenu_ = std::unique_ptr<QMenu>(new QMenu());
+ emojisMenu_ = std::make_unique<QMenu>();
emojisMenu_->setLayout(emojisLayout);
emojisMenu_->adjustSize();
@@ -716,7 +727,17 @@ void QtChatWindow::handleEmojiClicked(QString emoji) {
void QtChatWindow::handleTextInputReceivedFocus() {
lastLineTracker_.setHasFocus(true);
input_->setFocus();
- onAllMessagesRead();
+ if (focusTimer_) {
+ focusTimer_->stop();
+ }
+ else {
+ focusTimer_ = std::make_unique<QTimer>(this);
+ focusTimer_->setSingleShot(true);
+ focusTimer_->setTimerType(Qt::CoarseTimer);
+ connect(focusTimer_.get(), &QTimer::timeout, this, &QtChatWindow::handleFocusTimerTick);
+ }
+ focusTimer_->setInterval(1000);
+ focusTimer_->start();
}
void QtChatWindow::handleTextInputLostFocus() {
@@ -730,6 +751,7 @@ void QtChatWindow::handleActionButtonClicked() {
QAction* affiliations = nullptr;
QAction* destroy = nullptr;
QAction* invite = nullptr;
+ QAction* leave = nullptr;
QAction* block = nullptr;
QAction* unblock = nullptr;
@@ -783,6 +805,10 @@ void QtChatWindow::handleActionButtonClicked() {
invite = contextMenu.addAction(tr("Invite person to this room…"));
invite->setEnabled(isOnline_);
break;
+ case ChatWindow::Leave:
+ leave = contextMenu.addAction(tr("Leave room"));
+ leave->setEnabled(isOnline_);
+ break;
}
}
}
@@ -834,6 +860,9 @@ void QtChatWindow::handleActionButtonClicked() {
else if (result == invite) {
onInviteToChat(std::vector<JID>());
}
+ else if (result == leave) {
+ close();
+ }
else if (result == block) {
onBlockUserRequest();
}
@@ -867,14 +896,16 @@ void QtChatWindow::setCanInitiateImpromptuChats(bool supportsImpromptu) {
}
void QtChatWindow::showBookmarkWindow(const MUCBookmark& bookmark) {
- if (roomBookmarkState_ == RoomNotBookmarked) {
- QtAddBookmarkWindow* window = new QtAddBookmarkWindow(eventStream_, bookmark);
+ if (roomBookmarkState_ != RoomNotBookmarked) {
+ QtEditBookmarkWindow* window = new QtEditBookmarkWindow(eventStream_, bookmark);
window->show();
}
+#ifndef NOT_YET
else {
- QtEditBookmarkWindow* window = new QtEditBookmarkWindow(eventStream_, bookmark);
+ QtAddBookmarkWindow* window = new QtAddBookmarkWindow(eventStream_, bookmark);
window->show();
}
+#endif // ! NOT_YET
}
std::string QtChatWindow::getID() const {
@@ -984,4 +1015,60 @@ void QtChatWindow::setBookmarkState(RoomBookmarkState bookmarkState) {
roomBookmarkState_ = bookmarkState;
}
+void QtChatWindow::setChatSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue) {
+ auto layout = static_cast<QBoxLayout*>(this->layout());
+
+ if (securityMarkingLayout_) {
+ layout->removeItem(securityMarkingLayout_);
+ securityMarkingLayout_->removeWidget(securityMarkingDisplay_);
+ delete securityMarkingLayout_;
+ }
+ delete securityMarkingDisplay_;
+
+ securityMarkingLayout_ = new QHBoxLayout();
+ securityMarkingDisplay_ = new QLabel(P2QSTRING(markingValue));
+
+ securityMarkingLayout_->addWidget(securityMarkingDisplay_);
+ layout->insertLayout(1, securityMarkingLayout_);
+
+ auto palette = securityMarkingDisplay_->palette();
+ palette.setColor(securityMarkingDisplay_->foregroundRole(), P2QSTRING(markingForegroundColorValue));
+ palette.setColor(securityMarkingDisplay_->backgroundRole(), P2QSTRING(markingBackgroundColorValue));
+
+ securityMarkingDisplay_->setPalette(palette);
+ securityMarkingDisplay_->setContentsMargins(4,4,4,4);
+ securityMarkingDisplay_->setAutoFillBackground(true);
+ securityMarkingDisplay_->setAlignment(Qt::AlignCenter);
+}
+
+void QtChatWindow::removeChatSecurityMarking() {
+ if (!securityMarkingLayout_) {
+ return;
+ }
+
+ auto layout = static_cast<QBoxLayout*>(this->layout());
+
+ layout->removeItem(securityMarkingLayout_);
+ securityMarkingLayout_->removeWidget(securityMarkingDisplay_);
+
+ delete securityMarkingDisplay_;
+ delete securityMarkingLayout_;
+ securityMarkingDisplay_ = nullptr;
+ securityMarkingLayout_ = nullptr;
+}
+
+void QtChatWindow::handleFocusTimerTick() {
+ if (hasFocus()) {
+ onAllMessagesRead();
+ }
+ focusTimer_.reset();
+}
+
+void QtChatWindow::resendMessage(const std::string& id) {
+ if (!isOnline_ || (blockingState_ == IsBlocked)) {
+ return;
+ }
+ onResendMessageRequest(id);
+}
+
}
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index 361d7c6..b876d1e 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -34,6 +34,7 @@ class QComboBox;
class QLabel;
class QSplitter;
class QPushButton;
+class QTimer;
namespace Swift {
class QtChatView;
@@ -93,6 +94,7 @@ namespace Swift {
void replaceMessage(const ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time);
void replaceWithAction(const ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time);
+ void resendMessage(const std::string& id);
// File transfer related stuff
std::string addFileTransfer(const std::string& senderName, const std::string& avatarPath, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes, const std::string& description);
void setFileTransferProgress(std::string id, const int percentageDone);
@@ -104,7 +106,7 @@ namespace Swift {
void show();
bool isVisible() const;
void activate();
- void setUnreadMessageCount(int count);
+ void setUnreadMessageCount(size_t count);
void convertToMUC(MUCType mucType);
// TreeWidget *getTreeWidget();
void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels);
@@ -117,7 +119,7 @@ namespace Swift {
void setContactChatState(ChatState::ChatStateType state);
void setRosterModel(Roster* roster);
void setTabComplete(TabComplete* completer);
- int getCount();
+ size_t getCount();
virtual void replaceSystemMessage(const ChatMessage& message, const std::string& id, const TimestampBehaviour timestampBehaviour);
void replaceLastMessage(const ChatMessage& message, const TimestampBehaviour timestampBehaviour);
void setAckState(const std::string& id, AckState state);
@@ -194,8 +196,12 @@ namespace Swift {
void resetDayChangeTimer();
+ void setChatSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue);
+ void removeChatSecurityMarking();
+ void handleFocusTimerTick();
+
private:
- int unreadCount_;
+ size_t unreadCount_;
bool contactIsTyping_;
LastLineTracker lastLineTracker_;
std::string id_;
@@ -241,5 +247,8 @@ namespace Swift {
QPointer<QtEmojisSelector> emojisGrid_;
std::map<std::string, std::string> emoticonsMap_;
QTimer* dayChangeTimer = nullptr;
+ QHBoxLayout* securityMarkingLayout_ = nullptr;
+ QLabel* securityMarkingDisplay_ = nullptr;
+ std::unique_ptr<QTimer> focusTimer_;
};
}
diff --git a/Swift/QtUI/QtChatWindowFactory.cpp b/Swift/QtUI/QtChatWindowFactory.cpp
index 49cfe4d..33c8b94 100644
--- a/Swift/QtUI/QtChatWindowFactory.cpp
+++ b/Swift/QtUI/QtChatWindowFactory.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -11,7 +11,6 @@
#include <SwifTools/EmojiMapper.h>
#include <Swift/QtUI/QtChatTabs.h>
-#include <Swift/QtUI/QtChatTabsBase.h>
#include <Swift/QtUI/QtChatTheme.h>
#include <Swift/QtUI/QtChatWindow.h>
#include <Swift/QtUI/QtEmojisSelector.h>
@@ -23,22 +22,17 @@ namespace Swift {
static const QString SPLITTER_STATE = "mucSplitterState";
static const QString CHAT_TABS_GEOMETRY = "chatTabsGeometry";
-QtChatWindowFactory::QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabsBase* tabs, const QString& themePath, const std::map<std::string, std::string>& emoticonsMap) : themePath_(themePath), emoticonsMap_(emoticonsMap) {
+QtChatWindowFactory::QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabs* tabs, const QString& themePath, const std::map<std::string, std::string>& emoticonsMap) : themePath_(themePath), emoticonsMap_(emoticonsMap) {
qtOnlySettings_ = qtSettings;
settings_ = settings;
tabs_ = tabs;
theme_ = nullptr;
- QtChatTabs* fullTabs = dynamic_cast<QtChatTabs*>(tabs_);
- if (splitter) {
- assert(fullTabs && "Netbook mode and no-tabs interface is not supported!");
- splitter->addWidget(fullTabs);
- } else if (fullTabs) {
- QVariant chatTabsGeometryVariant = qtOnlySettings_->getQSettings()->value(CHAT_TABS_GEOMETRY);
- if (chatTabsGeometryVariant.isValid()) {
- fullTabs->restoreGeometry(chatTabsGeometryVariant.toByteArray());
- }
- connect(fullTabs, SIGNAL(geometryChanged()), this, SLOT(handleWindowGeometryChanged()));
+ splitter->addWidget(tabs_);
+ QVariant chatTabsGeometryVariant = qtOnlySettings_->getQSettings()->value(CHAT_TABS_GEOMETRY);
+ if (chatTabsGeometryVariant.isValid()) {
+ tabs_->restoreGeometry(chatTabsGeometryVariant.toByteArray());
}
+ connect(tabs_, SIGNAL(geometryChanged()), this, SLOT(handleWindowGeometryChanged()));
}
QtChatWindowFactory::~QtChatWindowFactory() {
@@ -60,7 +54,7 @@ ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStre
connect(this, SIGNAL(changeSplitterState(QByteArray)), chatWindow, SLOT(handleChangeSplitterState(QByteArray)));
QVariant splitterState = qtOnlySettings_->getQSettings()->value(SPLITTER_STATE);
- if(splitterState.isValid()) {
+ if (splitterState.isValid()) {
chatWindow->handleChangeSplitterState(splitterState.toByteArray());
}
diff --git a/Swift/QtUI/QtChatWindowFactory.h b/Swift/QtUI/QtChatWindowFactory.h
index 2bb6a90..3e4dca3 100644
--- a/Swift/QtUI/QtChatWindowFactory.h
+++ b/Swift/QtUI/QtChatWindowFactory.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -24,7 +24,7 @@
#include <Swift/QtUI/QtSettingsProvider.h>
namespace Swift {
- class QtChatTabsBase;
+ class QtChatTabs;
class QtChatTheme;
class UIEventStream;
class QtUIPreferences;
@@ -32,7 +32,7 @@ namespace Swift {
class QtChatWindowFactory : public QObject, public ChatWindowFactory {
Q_OBJECT
public:
- QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabsBase* tabs, const QString& themePath, const std::map<std::string, std::string>& emoticonsMap);
+ QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabs* tabs, const QString& themePath, const std::map<std::string, std::string>& emoticonsMap);
~QtChatWindowFactory();
ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream);
signals:
@@ -44,7 +44,7 @@ namespace Swift {
QString themePath_;
SettingsProvider* settings_;
QtSettingsProvider* qtOnlySettings_;
- QtChatTabsBase* tabs_;
+ QtChatTabs* tabs_;
QtChatTheme* theme_;
std::map<std::string, std::string> emoticonsMap_;
};
diff --git a/Swift/QtUI/QtDBUSURIHandler.cpp b/Swift/QtUI/QtDBUSURIHandler.cpp
index 34659f4..a1446c3 100644
--- a/Swift/QtUI/QtDBUSURIHandler.cpp
+++ b/Swift/QtUI/QtDBUSURIHandler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2016 Isode Limited.
+ * Copyright (c) 2011-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -19,7 +19,7 @@ using namespace Swift;
namespace {
class DBUSAdaptor: public QDBusAbstractAdaptor {
Q_OBJECT
- Q_CLASSINFO("D-Bus Interface", "im.swift.Swift.URIHandler");
+ Q_CLASSINFO("D-Bus Interface", "im.swift.Swift.URIHandler")
public:
DBUSAdaptor(QtDBUSURIHandler* uriHandler) : QDBusAbstractAdaptor(uriHandler), uriHandler(uriHandler) {
}
diff --git a/Swift/QtUI/QtEditBookmarkWindow.cpp b/Swift/QtUI/QtEditBookmarkWindow.cpp
index 1d6b467..c724c97 100644
--- a/Swift/QtUI/QtEditBookmarkWindow.cpp
+++ b/Swift/QtUI/QtEditBookmarkWindow.cpp
@@ -12,7 +12,6 @@ namespace Swift {
QtEditBookmarkWindow::QtEditBookmarkWindow(UIEventStream* eventStream, const MUCBookmark& bookmark) : eventStream_(eventStream), bookmark_(bookmark) {
name_->setText(P2QSTRING(bookmark.getName()));
room_->setText(P2QSTRING(bookmark.getRoom().toString()));
- autojoin_->setChecked(bookmark.getAutojoin());
nick_->setText(bookmark.getNick() ? P2QSTRING(bookmark.getNick().get()) : "");
password_->setText(bookmark.getPassword() ? P2QSTRING(bookmark.getPassword().get()) : "");
}
diff --git a/Swift/QtUI/QtEmojiCell.cpp b/Swift/QtUI/QtEmojiCell.cpp
index 865f1f6..106e968 100644
--- a/Swift/QtUI/QtEmojiCell.cpp
+++ b/Swift/QtUI/QtEmojiCell.cpp
@@ -1,11 +1,13 @@
/*
- * Copyright (c) 2016-2017 Isode Limited.
+ * Copyright (c) 2016-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/QtUI/QtEmojiCell.h>
+#include <Swiften/Base/Platform.h>
+
#include <QFont>
#include <QFontMetrics>
#include <QPushButton>
@@ -17,13 +19,20 @@ namespace Swift {
QtEmojiCell::QtEmojiCell(QString shortname, QString text, QWidget* parent) : QPushButton(parent) {
setText(text);
QFont font = this->font();
+#ifdef SWIFTEN_PLATFORM_WINDOWS
+ //Windows emoji font miscalculates the bounding rectangular that surrounds the emoji. We set a multiplier value to make it look consistent with linux & Mac
+ const float sizeMultiplier = 1.3;
+ font.setPointSize(18);
+#else
font.setPointSize(22);
+ const float sizeMultiplier = 1;
+#endif
font.setBold(true);
setFont(font);
const auto boundingRect = fontMetrics().boundingRect("\xF0\x9F\x98\x83");
- setFixedWidth(qMax(boundingRect.width(), boundingRect.height()));
- setFixedHeight(qMax(boundingRect.width(), boundingRect.height()));
+ setFixedWidth(qMax(sizeMultiplier*boundingRect.width(), sizeMultiplier*boundingRect.height()));
+ setFixedHeight(qMax(sizeMultiplier*boundingRect.width(), sizeMultiplier*boundingRect.height()));
setFlat(true);
setToolTip(shortname);
diff --git a/Swift/QtUI/QtEmojisScroll.h b/Swift/QtUI/QtEmojisScroll.h
index 959ab5f..f954c2d 100644
--- a/Swift/QtUI/QtEmojisScroll.h
+++ b/Swift/QtUI/QtEmojisScroll.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017 Isode Limited.
+ * Copyright (c) 2016-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -13,6 +13,6 @@ namespace Swift {
class QtEmojisScroll : public QWidget {
Q_OBJECT
public:
- QtEmojisScroll(QLayout* emojiLayout, QWidget *parent = 0);
+ QtEmojisScroll(QLayout* emojiLayout, QWidget* parent = nullptr);
};
}
diff --git a/Swift/QtUI/QtEmojisSelector.cpp b/Swift/QtUI/QtEmojisSelector.cpp
index 62ed862..fe2f235 100644
--- a/Swift/QtUI/QtEmojisSelector.cpp
+++ b/Swift/QtUI/QtEmojisSelector.cpp
@@ -24,7 +24,6 @@
namespace Swift {
QtEmojisSelector::QtEmojisSelector(QSettings* settings, const std::map<std::string, std::string>& emoticonsMap, QWidget* parent) : QTabWidget(parent), settings_(settings), emoticonsMap_(emoticonsMap) {
-#ifdef SWIFTEN_PLATFORM_MACOSX
recentEmojisGrid_ = addRecentTab();
connect(recentEmojisGrid_, SIGNAL(onEmojiSelected(QString)), this, SLOT(emojiClickedSlot(QString)));
@@ -34,17 +33,13 @@ namespace Swift {
connect(grid, SIGNAL(onEmojiSelected(QString)), this, SLOT(emojiClickedSlot(QString)));
}
}
-
loadSettings();
-#else
- setupEmoticonsTab();
-#endif
+ //The size of an emoji cell varies depending the OS, 42 is the ceil value.
+ setFixedSize(QSize(EmojiMapper::emojisInCategory.size() * 42, 300));
}
QtEmojisSelector::~QtEmojisSelector() {
-#ifdef SWIFTEN_PLATFORM_MACOSX
writeSettings();
-#endif
}
QtRecentEmojisGrid* QtEmojisSelector::addRecentTab() {
diff --git a/Swift/QtUI/QtEmojisSelector.h b/Swift/QtUI/QtEmojisSelector.h
index 7ac11d0..1a64cf4 100644
--- a/Swift/QtUI/QtEmojisSelector.h
+++ b/Swift/QtUI/QtEmojisSelector.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017 Isode Limited.
+ * Copyright (c) 2016-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -20,7 +20,7 @@ namespace Swift {
class QtEmojisSelector : public QTabWidget {
Q_OBJECT
public:
- QtEmojisSelector(QSettings* settings, const std::map<std::string, std::string>& emoticonsMap, QWidget * parent = 0);
+ QtEmojisSelector(QSettings* settings, const std::map<std::string, std::string>& emoticonsMap, QWidget* parent = nullptr);
~QtEmojisSelector();
public slots:
diff --git a/Swift/QtUI/QtExpandedListView.cpp b/Swift/QtUI/QtExpandedListView.cpp
new file mode 100644
index 0000000..84769c5
--- /dev/null
+++ b/Swift/QtUI/QtExpandedListView.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/QtUI/QtExpandedListView.h>
+
+#include <QWheelEvent>
+#include <QScrollArea>
+#include <QDebug>
+
+namespace Swift {
+
+QtExpandedListView::QtExpandedListView(QWidget* parent) : QListView(parent) {
+ // Disable macOS focus rectangle due to bad performance.
+ setAttribute(Qt::WA_MacShowFocusRect, 0);
+ setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed);
+}
+
+void QtExpandedListView::setModel(QAbstractItemModel* newModel) {
+ if (model()) {
+ disconnectFromModel(model());
+ }
+ if (newModel) {
+ connectToModel(newModel);
+ }
+ QListView::setModel(newModel);
+ adjustHeightToModelChange();
+}
+
+QtExpandedListView::~QtExpandedListView() {
+ if (model()) {
+ disconnectFromModel(model());
+ }
+}
+
+bool QtExpandedListView::viewportEvent(QEvent* event) {
+ // Ignore wheel events for faster mouse scrolling.
+ if (event && event->type() == QEvent::Wheel) {
+ return false;
+ }
+
+ return QListView::viewportEvent(event);
+}
+
+template <typename T>
+T getParentOfType(QWidget* start) {
+ auto parentW = start->parentWidget();
+ if (parentW == nullptr) {
+ return nullptr;
+ }
+ T result = dynamic_cast<T>(parentW);
+ if (result) {
+ return result;
+ }
+ return getParentOfType<T>(parentW);
+}
+
+void QtExpandedListView::currentChanged(const QModelIndex &current, const QModelIndex &) {
+ // Make sure that the current selected index is visible in the parent QScrollArea.
+ auto scrollArea = getParentOfType<QScrollArea*>(parentWidget());
+ if (scrollArea) {
+ auto scrollWidget = scrollArea->widget();
+ QList<QPoint> points;
+ auto visRect = visualRect(current);
+ points << mapTo(scrollWidget, visRect.topLeft());
+ points << mapTo(scrollWidget, visRect.topRight());
+ points << mapTo(scrollWidget, visRect.bottomLeft());
+ points << mapTo(scrollWidget, visRect.bottomRight());
+
+ for (auto&& point : points) {
+ scrollArea->ensureVisible(point.x(), point.y(), 0, 0);
+ }
+ }
+}
+
+void QtExpandedListView::adjustHeightToModelChange() {
+ updateGeometry();
+}
+
+QSize QtExpandedListView::minimumSizeHint() const {
+ auto sh = sizeHint();
+ return QSize(0, sh.height());
+}
+
+QSize QtExpandedListView::sizeHint() const {
+ auto listViewSH = QListView::sizeHint();
+ if (model()) {
+ auto lastRect = rectForIndex(model()->index(model()->rowCount()-1, 0, rootIndex()));
+ auto idealHeight = lastRect.y() + lastRect.height() + frameWidth() * 2;
+ listViewSH.setHeight(idealHeight);
+ }
+ return listViewSH;
+}
+
+void QtExpandedListView::connectToModel(QAbstractItemModel* model) {
+ connect(model, &QAbstractItemModel::dataChanged, this, &QtExpandedListView::adjustHeightToModelChange);
+ connect(model, &QAbstractItemModel::modelReset, this, &QtExpandedListView::adjustHeightToModelChange);
+ connect(model, &QAbstractItemModel::rowsInserted, this, &QtExpandedListView::adjustHeightToModelChange);
+ connect(model, &QAbstractItemModel::rowsRemoved, this, &QtExpandedListView::adjustHeightToModelChange);
+}
+
+void QtExpandedListView::disconnectFromModel(QAbstractItemModel* model) {
+ disconnect(model, &QAbstractItemModel::dataChanged, this, &QtExpandedListView::adjustHeightToModelChange);
+ disconnect(model, &QAbstractItemModel::modelReset, this, &QtExpandedListView::adjustHeightToModelChange);
+ disconnect(model, &QAbstractItemModel::rowsInserted, this, &QtExpandedListView::adjustHeightToModelChange);
+ disconnect(model, &QAbstractItemModel::rowsRemoved, this, &QtExpandedListView::adjustHeightToModelChange);
+}
+
+}
diff --git a/Swift/QtUI/QtExpandedListView.h b/Swift/QtUI/QtExpandedListView.h
new file mode 100644
index 0000000..df78376
--- /dev/null
+++ b/Swift/QtUI/QtExpandedListView.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <QListView>
+
+namespace Swift {
+
+class QtExpandedListView : public QListView {
+public:
+ QtExpandedListView(QWidget* parent);
+ ~QtExpandedListView() override;
+
+ void setModel(QAbstractItemModel* model) override;
+ bool viewportEvent(QEvent* event) override;
+ QSize minimumSizeHint() const override;
+ QSize sizeHint() const override;
+
+protected slots:
+ void currentChanged(const QModelIndex &current, const QModelIndex &previous) override;
+
+private slots:
+ void adjustHeightToModelChange();
+
+private:
+ void connectToModel(QAbstractItemModel* model);
+ void disconnectFromModel(QAbstractItemModel* model);
+};
+
+}
diff --git a/Swift/QtUI/QtFdpFormSubmitWindow.cpp b/Swift/QtUI/QtFdpFormSubmitWindow.cpp
new file mode 100644
index 0000000..5719f87
--- /dev/null
+++ b/Swift/QtUI/QtFdpFormSubmitWindow.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/QtUI/QtFdpFormSubmitWindow.h>
+
+#include <QCloseEvent>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QSpacerItem>
+#include <QVBoxLayout>
+
+#include <Swift/QtUI/QtFormWidget.h>
+#include <Swift/QtUI/QtListWidget.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+QtFdpFormSubmitWindow::QtFdpFormSubmitWindow(QWidget* parent) : QDialog(parent), FdpFormSubmitWindow() {
+ layout_ = new QVBoxLayout(this);
+ subLayout_ = new QHBoxLayout(this);
+
+ initNodeViewLayout();
+ initFormLayout();
+ subLayout_->addLayout(nodeViewLayout_);
+ subLayout_->addLayout(formLayout_);
+ subLayout_->setStretchFactor(nodeViewLayout_, 2);
+ subLayout_->setStretchFactor(formLayout_, 3);
+ layout_->addLayout(subLayout_);
+
+ submitButton_ = new QPushButton(tr("Submit Form"), this);
+ submitButton_->setEnabled(false);
+ okButton_ = new QPushButton(tr("Ok"), this);
+ okButton_->hide();
+ cancelButton_ = new QPushButton(tr("Cancel"), this);
+ connect(submitButton_, &QPushButton::clicked, this, &QtFdpFormSubmitWindow::handleSubmitClicked);
+ connect(okButton_, &QPushButton::clicked, this, &QWidget::close);
+ connect(cancelButton_, &QPushButton::clicked, this, &QWidget::close);
+ auto buttonSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ buttonLayout_ = new QHBoxLayout(this);
+ buttonLayout_->addItem(buttonSpacer);
+ buttonLayout_->addWidget(submitButton_);
+ buttonLayout_->addWidget(cancelButton_);
+ layout_->addLayout(buttonLayout_);
+
+ setMinimumWidth(800);
+ setMinimumHeight(600);
+
+ this->setWindowTitle(tr("FDP Form Submission"));
+}
+
+QtFdpFormSubmitWindow::~QtFdpFormSubmitWindow() {
+}
+
+void QtFdpFormSubmitWindow::closeEvent(QCloseEvent* event) {
+ event->ignore();
+ onCloseEvent();
+}
+
+void QtFdpFormSubmitWindow::initNodeViewLayout() {
+ nodeViewLayout_ = new QVBoxLayout(this);
+ auto domainSearchLayout = new QHBoxLayout(this);
+ pubSubDomainEdit_ = new QLineEdit(this);
+ loadDomainButton_ = new QPushButton(tr("Load"), this);
+ pubSubNodeView_ = new QtListWidget(this);
+ pubSubDomainEdit_->setPlaceholderText(tr("Enter pubsub domain here"));
+ pubSubNodeView_->setMinimumWidth(300);
+ connect(loadDomainButton_, &QPushButton::clicked, this, &QtFdpFormSubmitWindow::handleLoadDomainButtonClicked);
+ connect(pubSubNodeView_, &QListWidget::itemDoubleClicked, this, &QtFdpFormSubmitWindow::handlePubSubNodeViewItemDoubleClicked);
+ domainSearchLayout->addWidget(pubSubDomainEdit_);
+ domainSearchLayout->addWidget(loadDomainButton_);
+ nodeViewLayout_->addLayout(domainSearchLayout);
+ nodeViewLayout_->addWidget(pubSubNodeView_);
+}
+
+void QtFdpFormSubmitWindow::initFormLayout() {
+ formPlaceholder_ = new QLabel(tr("No form loaded"));
+ formPlaceholder_->setAlignment(Qt::AlignCenter);
+ formPlaceholder_->setMinimumWidth(200);
+ formPlaceholder_->setStyleSheet("QLabel { color : #AAAAAA; }");
+ formLayout_ = new QVBoxLayout(this);
+ formLayout_->addWidget(formPlaceholder_, Qt::AlignCenter);
+}
+
+void QtFdpFormSubmitWindow::show() {
+ QDialog::show();
+}
+
+void QtFdpFormSubmitWindow::raise() {
+ QDialog::raise();
+}
+
+void QtFdpFormSubmitWindow::addNode(const std::string& node, const std::string& nodeName) {
+ auto listItem = new QListWidgetItem(P2QSTRING(nodeName));
+ listItem->setData(Qt::UserRole, P2QSTRING(node));
+ pubSubNodeView_->addItem(listItem);
+}
+
+void QtFdpFormSubmitWindow::clearNodeData() {
+ pubSubNodeView_->clear();
+ pubSubNodeView_->setWordWrap(false);
+ disconnect(pubSubNodeView_, &QtListWidget::onResize, this, &QtFdpFormSubmitWindow::handleNodeListResize);
+}
+
+void QtFdpFormSubmitWindow::setFormData(const std::shared_ptr<Form>& form) {
+ if (formWidget_) {
+ formLayout_->removeWidget(formWidget_);
+ formWidget_->deleteLater();
+ formWidget_ = nullptr;
+ }
+ else if (!formPlaceholder_->isHidden()) {
+ formLayout_->removeWidget(formPlaceholder_);
+ formPlaceholder_->hide();
+ }
+ formWidget_ = new QtFormWidget(form);
+ formWidget_->setEditable(true);
+ formLayout_->addWidget(formWidget_);
+
+ if (!okButton_->isHidden()) {
+ buttonLayout_->removeWidget(okButton_);
+ okButton_->hide();
+ }
+ if (submitButton_->isHidden()) {
+ buttonLayout_->insertWidget(1, submitButton_);
+ submitButton_->show();
+ }
+ submitButton_->setEnabled(true);
+ cancelButton_->setEnabled(true);
+}
+
+void QtFdpFormSubmitWindow::showNodePlaceholder(NodeError nodeError) {
+ pubSubNodeView_->clear();
+ pubSubNodeView_->setWordWrap(true);
+ auto listItem = new QListWidgetItem;
+ auto placeholderText = P2QSTRING(getNodeErrorText(nodeError));
+ listItem->setText(placeholderText);
+ listItem->setTextAlignment(Qt::AlignCenter);
+ listItem->setFlags(Qt::NoItemFlags);
+ listItem->setSizeHint(QSize(listItem->sizeHint().width(), pubSubNodeView_->height()));
+ connect(pubSubNodeView_, &QtListWidget::onResize, this, &QtFdpFormSubmitWindow::handleNodeListResize);
+ pubSubNodeView_->addItem(listItem);
+}
+
+void QtFdpFormSubmitWindow::showFormPlaceholder(TemplateError templateError) {
+ if (formWidget_) {
+ formLayout_->removeWidget(formWidget_);
+ formWidget_->deleteLater();
+ formWidget_ = nullptr;
+ }
+ auto placeholderText = P2QSTRING(getTemplateErrorText(templateError));
+ formPlaceholder_->setText(placeholderText);
+ if (formPlaceholder_->isHidden()) {
+ formLayout_->addWidget(formPlaceholder_, Qt::AlignCenter);
+ formPlaceholder_->show();
+ }
+
+ if (!okButton_->isHidden()) {
+ buttonLayout_->removeWidget(okButton_);
+ okButton_->hide();
+ }
+ if (submitButton_->isHidden()) {
+ buttonLayout_->insertWidget(1, submitButton_);
+ submitButton_->show();
+ }
+ submitButton_->setEnabled(false);
+ cancelButton_->setEnabled(true);
+}
+
+void QtFdpFormSubmitWindow::handleLoadDomainButtonClicked() {
+ std::string domainUri = Q2PSTRING(pubSubDomainEdit_->text());
+ onRequestPubSubNodeData(domainUri);
+}
+
+void QtFdpFormSubmitWindow::handlePubSubListViewTemplateSelected(const std::string& nodeName) {
+ onRequestTemplateForm(nodeName);
+}
+
+void QtFdpFormSubmitWindow::handlePubSubNodeViewItemDoubleClicked(QListWidgetItem* item) {
+ handlePubSubListViewTemplateSelected(Q2PSTRING(item->data(Qt::UserRole).toString()));
+}
+
+void QtFdpFormSubmitWindow::handleSubmitClicked() {
+ auto form = formWidget_->getCompletedForm();
+ formWidget_->setDisabled(true);
+ submitButton_->setEnabled(false);
+ onSubmitForm(form);
+}
+
+void QtFdpFormSubmitWindow::handleSubmitServerResponse(bool submissionSuccess) {
+ if (submissionSuccess) {
+ if (!submitButton_->isHidden()) {
+ buttonLayout_->removeWidget(submitButton_);
+ submitButton_->hide();
+ }
+ if (okButton_->isHidden()) {
+ buttonLayout_->insertWidget(1, okButton_);
+ okButton_->show();
+ }
+ cancelButton_->setEnabled(false);
+ }
+ else {
+ formWidget_->setDisabled(false);
+ submitButton_->setEnabled(true);
+ }
+}
+
+void QtFdpFormSubmitWindow::handleNodeListResize() {
+ auto placeholderItem = pubSubNodeView_->item(0);
+ placeholderItem->setSizeHint(QSize(placeholderItem->sizeHint().width(), pubSubNodeView_->height()));
+}
+
+}
diff --git a/Swift/QtUI/QtFdpFormSubmitWindow.h b/Swift/QtUI/QtFdpFormSubmitWindow.h
new file mode 100644
index 0000000..b429927
--- /dev/null
+++ b/Swift/QtUI/QtFdpFormSubmitWindow.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <QDialog>
+
+#include <Swift/Controllers/UIInterfaces/FdpFormSubmitWindow.h>
+
+class QHBoxLayout;
+class QLabel;
+class QLineEdit;
+class QListWidgetItem;
+class QPushButton;
+class QTextEdit;
+class QVBoxLayout;
+
+namespace Swift {
+
+ class Form;
+ class QtFormWidget;
+ class QtListWidget;
+ class QtPubSubNodeController;
+
+ class QtFdpFormSubmitWindow : public QDialog, public FdpFormSubmitWindow {
+ Q_OBJECT
+
+ public:
+ QtFdpFormSubmitWindow(QWidget* parent = nullptr);
+ virtual ~QtFdpFormSubmitWindow() override;
+
+ protected:
+ virtual void closeEvent(QCloseEvent* event) override;
+
+ private:
+ void initNodeViewLayout();
+ void initFormLayout();
+ virtual void show() override;
+ virtual void raise() override;
+ virtual void addNode(const std::string& node, const std::string& nodeName) override;
+ virtual void clearNodeData() override;
+ virtual void setFormData(const std::shared_ptr<Form>& form) override;
+ virtual void showNodePlaceholder(NodeError nodeError) override;
+ virtual void showFormPlaceholder(TemplateError templateError) override;
+ virtual void handleSubmitServerResponse(bool submissionSuccess) override;
+
+ private slots:
+ void handleLoadDomainButtonClicked();
+ void handlePubSubListViewTemplateSelected(const std::string& nodeName);
+ void handlePubSubNodeViewItemDoubleClicked(QListWidgetItem* item);
+ void handleSubmitClicked();
+ void handleNodeListResize();
+
+ private:
+ QVBoxLayout* layout_;
+ QHBoxLayout* subLayout_;
+ QHBoxLayout* buttonLayout_;
+ QVBoxLayout* nodeViewLayout_;
+ QVBoxLayout* formLayout_;
+ QLineEdit* pubSubDomainEdit_;
+ QPushButton* loadDomainButton_;
+ QtListWidget* pubSubNodeView_;
+ QLabel* formPlaceholder_;
+ QTextEdit* nodePlaceholderTextEdit_ = nullptr;
+ QtFormWidget* formWidget_ = nullptr;
+ QPushButton* cancelButton_;
+ QPushButton* submitButton_ = nullptr;
+ QPushButton* okButton_ = nullptr;
+ };
+}
diff --git a/Swift/QtUI/QtFormWidget.cpp b/Swift/QtUI/QtFormWidget.cpp
index 96c2da0..860ddfa 100644
--- a/Swift/QtUI/QtFormWidget.cpp
+++ b/Swift/QtUI/QtFormWidget.cpp
@@ -147,7 +147,7 @@ QWidget* QtFormWidget::createWidget(FormField::ref field, const FormField::Type
std::string indexString;
if (index) {
/* for multi-item forms we need to distinguish between the different rows */
- indexString = boost::lexical_cast<std::string>(index);
+ indexString = std::to_string(index);
}
fields_[field->getName() + indexString] = widget;
return widget;
diff --git a/Swift/QtUI/QtHighlightNotificationConfigDialog.cpp b/Swift/QtUI/QtHighlightNotificationConfigDialog.cpp
index 19274a2..0521a2d 100644
--- a/Swift/QtUI/QtHighlightNotificationConfigDialog.cpp
+++ b/Swift/QtUI/QtHighlightNotificationConfigDialog.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017 Isode Limited.
+ * Copyright (c) 2016-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -50,7 +50,7 @@ QtHighlightNotificationConfigDialog::QtHighlightNotificationConfigDialog(QtSetti
}
});
connect(ui_.userHighlightTreeWidget, &QTreeWidget::currentItemChanged, [&](QTreeWidgetItem* current, QTreeWidgetItem* ) {
- ui_.removeUserHighlightPushButton->setEnabled(current != 0);
+ ui_.removeUserHighlightPushButton->setEnabled(current != nullptr);
});
// keyword highlight edit slots
@@ -72,7 +72,7 @@ QtHighlightNotificationConfigDialog::QtHighlightNotificationConfigDialog(QtSetti
}
});
connect(ui_.keywordHighlightTreeWidget, &QTreeWidget::currentItemChanged, [&](QTreeWidgetItem* current, QTreeWidgetItem* ) {
- ui_.removeKeywordHighlightPushButton->setEnabled(current != 0);
+ ui_.removeKeywordHighlightPushButton->setEnabled(current != nullptr);
});
// setup slots for main dialog buttons
diff --git a/Swift/QtUI/QtHistoryWindow.cpp b/Swift/QtUI/QtHistoryWindow.cpp
index 77a7f12..0e7e89d 100644
--- a/Swift/QtUI/QtHistoryWindow.cpp
+++ b/Swift/QtUI/QtHistoryWindow.cpp
@@ -49,7 +49,7 @@ QtHistoryWindow::QtHistoryWindow(SettingsProvider* settings, UIEventStream* even
idCounter_ = 0;
delete ui_.conversation_;
- conversation_ = new QtWebKitChatView(nullptr, nullptr, theme_, this, true); // Horrible unsafe. Do not do this. FIXME
+ conversation_ = new QtWebKitChatView(nullptr, nullptr, theme_, this, settings, true); // Horrible unsafe. Do not do this. FIXME
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
sizePolicy.setHorizontalStretch(80);
sizePolicy.setVerticalStretch(0);
@@ -131,7 +131,7 @@ void QtHistoryWindow::addMessage(const std::string &message, const std::string &
QTime dayTime = QTime(time.time_of_day().hours(), time.time_of_day().minutes(), time.time_of_day().seconds());
QDateTime qTime = QDateTime(date, dayTime);
- std::string id = "id" + boost::lexical_cast<std::string>(idCounter_++);
+ std::string id = "id" + std::to_string(idCounter_++);
QString qAvatarPath = scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.png" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded();
diff --git a/Swift/QtUI/QtJoinMUCWindow.cpp b/Swift/QtUI/QtJoinMUCWindow.cpp
index 13de1c9..550ae4a 100644
--- a/Swift/QtUI/QtJoinMUCWindow.cpp
+++ b/Swift/QtUI/QtJoinMUCWindow.cpp
@@ -49,7 +49,7 @@ void QtJoinMUCWindow::handleJoin() {
lastSetNick = Q2PSTRING(ui.nickName->text());
std::string password = Q2PSTRING(ui.password->text());
JID room(Q2PSTRING(ui.room->text()));
- uiEventStream->send(std::make_shared<JoinMUCUIEvent>(room, password, lastSetNick, ui.joinAutomatically->isChecked(), !ui.instantRoom->isChecked()));
+ uiEventStream->send(std::make_shared<JoinMUCUIEvent>(room, password, lastSetNick, !ui.instantRoom->isChecked()));
hide();
}
diff --git a/Swift/QtUI/QtJoinMUCWindow.ui b/Swift/QtUI/QtJoinMUCWindow.ui
index 24d6ab8..96f1d17 100644
--- a/Swift/QtUI/QtJoinMUCWindow.ui
+++ b/Swift/QtUI/QtJoinMUCWindow.ui
@@ -101,13 +101,6 @@
</spacer>
</item>
<item>
- <widget class="QCheckBox" name="joinAutomatically">
- <property name="text">
- <string>Enter automatically in future</string>
- </property>
- </widget>
- </item>
- <item>
<widget class="QPushButton" name="joinButton">
<property name="text">
<string>Enter Room</string>
@@ -124,7 +117,6 @@
<tabstop>nickName</tabstop>
<tabstop>password</tabstop>
<tabstop>instantRoom</tabstop>
- <tabstop>joinAutomatically</tabstop>
<tabstop>joinButton</tabstop>
</tabstops>
<resources/>
diff --git a/Swift/QtUI/QtListWidget.cpp b/Swift/QtUI/QtListWidget.cpp
new file mode 100644
index 0000000..e35bbbb
--- /dev/null
+++ b/Swift/QtUI/QtListWidget.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/QtUI/QtListWidget.h>
+
+#include <QListWidget>
+
+namespace Swift {
+
+QtListWidget::QtListWidget(QWidget* parent) : QListWidget(parent) {
+}
+
+void QtListWidget::resizeEvent(QResizeEvent*) {
+ emit onResize();
+}
+
+}
diff --git a/Swift/QtUI/QtListWidget.h b/Swift/QtUI/QtListWidget.h
new file mode 100644
index 0000000..b7380c4
--- /dev/null
+++ b/Swift/QtUI/QtListWidget.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <QListWidget>
+
+namespace Swift {
+
+class QtListWidget : public QListWidget {
+ Q_OBJECT
+ public:
+ QtListWidget(QWidget* parent = nullptr);
+ protected:
+ virtual void resizeEvent(QResizeEvent*);
+ signals:
+ void onResize();
+};
+
+}
diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp
index 654e921..8fdce4d 100644
--- a/Swift/QtUI/QtLoginWindow.cpp
+++ b/Swift/QtUI/QtLoginWindow.cpp
@@ -573,4 +573,8 @@ void QtLoginWindow::handleOpenConnectionOptions() {
}
}
+QSize QtLoginWindow::sizeHint() const {
+ return QSize(250, 600);
+}
+
}
diff --git a/Swift/QtUI/QtLoginWindow.h b/Swift/QtUI/QtLoginWindow.h
index 674e1e3..d3c2601 100644
--- a/Swift/QtUI/QtLoginWindow.h
+++ b/Swift/QtUI/QtLoginWindow.h
@@ -54,12 +54,15 @@ namespace Swift {
void hide();
QtMenus getMenus() const;
virtual void quit();
+ QSize sizeHint() const;
signals:
void geometryChanged();
- private slots:
+ public slots:
void loginClicked();
+
+ private slots:
void handleCertficateChecked(bool);
void handleQuit();
void handleShowXMLConsole();
diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp
index 0c1dd97..92488ae 100644
--- a/Swift/QtUI/QtMainWindow.cpp
+++ b/Swift/QtUI/QtMainWindow.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -19,6 +19,7 @@
#include <QListWidgetItem>
#include <QMenuBar>
#include <QPushButton>
+#include <QScrollArea>
#include <QTabWidget>
#include <QToolBar>
@@ -26,6 +27,7 @@
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/FdpFormSubmitWindowOpenUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h>
@@ -35,6 +37,7 @@
#include <Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h>
#include <Swift/QtUI/QtAdHocCommandWithJIDWindow.h>
+#include <Swift/QtUI/QtChatOverview.h>
#include <Swift/QtUI/QtLoginWindow.h>
#include <Swift/QtUI/QtSettingsProvider.h>
#include <Swift/QtUI/QtSwiftUtil.h>
@@ -52,7 +55,7 @@
namespace Swift {
-QtMainWindow::QtMainWindow(SettingsProvider* settings, UIEventStream* uiEventStream, QtLoginWindow::QtMenus loginMenus, StatusCache* statusCache, bool emoticonsExist, bool enableAdHocCommandOnJID) : QWidget(), MainWindow(false), loginMenus_(loginMenus) {
+QtMainWindow::QtMainWindow(Chattables& chattables, SettingsProvider* settings, UIEventStream* uiEventStream, QtLoginWindow::QtMenus loginMenus, StatusCache* statusCache, bool emoticonsExist, bool enableAdHocCommandOnJID) : QWidget(), MainWindow(false), chattables_(chattables), loginMenus_(loginMenus) {
uiEventStream_ = uiEventStream;
settings_ = settings;
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
@@ -66,11 +69,22 @@ QtMainWindow::QtMainWindow(SettingsProvider* settings, UIEventStream* uiEventStr
connect(meView_, SIGNAL(onShowCertificateInfo()), this, SLOT(handleShowCertificateInfo()));
tabs_ = new QtTabWidget(this);
-#if QT_VERSION >= 0x040500
tabs_->setDocumentMode(true);
-#endif
tabs_->setTabPosition(QTabWidget::South);
mainLayout->addWidget(tabs_);
+
+ if (settings->getSetting(SettingConstants::FUTURE)) {
+ chatOverview_ = new QtChatOverview(chattables, this);
+ auto overviewScroll = new QScrollArea(this);
+ overviewScroll->setWidgetResizable(true);
+ overviewScroll->setWidget(chatOverview_);
+ tabs_->addTab(overviewScroll, tr("&All"));
+
+ // When used with QSplitter and setChildrenCollapsible(false), the following prevents
+ // this widget to be hidden, i.e. resized to zero width.
+ chatOverview_->setMinimumWidth(20);
+ }
+
contactsTabWidget_ = new QWidget(this);
contactsTabWidget_->setContentsMargins(0, 0, 0, 0);
QBoxLayout *contactTabLayout = new QBoxLayout(QBoxLayout::TopToBottom, contactsTabWidget_);
@@ -82,9 +96,7 @@ QtMainWindow::QtMainWindow(SettingsProvider* settings, UIEventStream* uiEventStr
contactTabLayout->addWidget(treeWidget_);
new QtFilterWidget(this, treeWidget_, uiEventStream_, contactTabLayout);
-
tabs_->addTab(contactsTabWidget_, tr("&Contacts"));
-
eventWindow_ = new QtEventWindow(uiEventStream_);
connect(eventWindow_, SIGNAL(onNewEventCountUpdated(int)), this, SLOT(handleEventCountUpdated(int)));
@@ -103,8 +115,11 @@ QtMainWindow::QtMainWindow(SettingsProvider* settings, UIEventStream* uiEventStr
tabs_->tabBar()->hide();
tabBarCombo_ = new QComboBox(this);
tabBarCombo_->setAccessibleName("Current View");
+ tabBarCombo_->addItem(tr("All"));
+#ifndef NOT_YET
tabBarCombo_->addItem(tr("Contacts"));
tabBarCombo_->addItem(tr("Chats"));
+#endif
tabBarCombo_->addItem(tr("Notices"));
tabBarCombo_->setCurrentIndex(tabs_->currentIndex());
mainLayout->addWidget(tabBarCombo_);
@@ -185,6 +200,13 @@ QtMainWindow::QtMainWindow(SettingsProvider* settings, UIEventStream* uiEventStr
}
serverAdHocMenu_ = new QMenu(tr("Run Server Command"), this);
actionsMenu->addMenu(serverAdHocMenu_);
+ if (settings_->getSetting(SettingConstants::FUTURE)) {
+ actionsMenu->addSeparator();
+ submitFormAction_ = new QAction(tr("Submit Form"), this);
+ connect(submitFormAction_, &QAction::triggered, this, &QtMainWindow::handleSubmitFormActionTriggered);
+ actionsMenu->addAction(submitFormAction_);
+ onlineOnlyActions_ << submitFormAction_;
+ }
actionsMenu->addSeparator();
QAction* signOutAction = new QAction(tr("&Sign Out"), this);
connect(signOutAction, SIGNAL(triggered()), SLOT(handleSignOutAction()));
@@ -423,5 +445,8 @@ void QtMainWindow::setBlockingCommandAvailable(bool isAvailable) {
openBlockingListEditor_->setVisible(isAvailable);
}
+void QtMainWindow::handleSubmitFormActionTriggered() {
+ uiEventStream_->send(std::make_shared<FdpFormSubmitWindowOpenUIEvent>());
}
+}
diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h
index c46fdfc..b285831 100644
--- a/Swift/QtUI/QtMainWindow.h
+++ b/Swift/QtUI/QtMainWindow.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -12,6 +12,7 @@
#include <QMenu>
#include <QWidget>
+#include <Swift/Controllers/Chat/Chattables.h>
#include <Swift/Controllers/UIInterfaces/MainWindow.h>
#include <Swift/QtUI/ChatList/QtChatListWindow.h>
@@ -19,44 +20,45 @@
#include <Swift/QtUI/QtLoginWindow.h>
#include <Swift/QtUI/QtRosterHeader.h>
+class QAction;
class QComboBox;
class QLineEdit;
-class QPushButton;
-class QToolBar;
-class QAction;
class QMenu;
+class QPushButton;
class QTabWidget;
+class QToolBar;
namespace Swift {
+ class QtChatOverview;
class QtRosterWidget;
- class TreeWidget;
- class UIEventStream;
class QtTabWidget;
- class SettingsProvider;
class QtUIPreferences;
+ class SettingsProvider;
class StatusCache;
+ class TreeWidget;
+ class UIEventStream;
class QtMainWindow : public QWidget, public MainWindow {
Q_OBJECT
public:
- QtMainWindow(SettingsProvider*, UIEventStream* eventStream, QtLoginWindow::QtMenus loginMenus, StatusCache* statusCache, bool emoticonsExist, bool enableAdHocCommandOnJID);
- virtual ~QtMainWindow();
+ QtMainWindow(Chattables&, SettingsProvider*, UIEventStream* eventStream, QtLoginWindow::QtMenus loginMenus, StatusCache* statusCache, bool emoticonsExist, bool enableAdHocCommandOnJID);
+ virtual ~QtMainWindow() override;
std::vector<QMenu*> getMenus() {return menus_;}
- void setMyNick(const std::string& name);
- void setMyJID(const JID& jid);
- void setMyAvatarPath(const std::string& path);
- void setMyStatusText(const std::string& status);
- void setMyStatusType(StatusShow::Type type);
- void setMyContactRosterItem(std::shared_ptr<ContactRosterItem> contact);
- void setConnecting();
- void setStreamEncryptionStatus(bool tlsInPlaceAndValid);
- void openCertificateDialog(const std::vector<Certificate::ref>& chain);
+ void setMyNick(const std::string& name) override;
+ void setMyJID(const JID& jid) override;
+ void setMyAvatarPath(const std::string& path) override;
+ void setMyStatusText(const std::string& status) override;
+ void setMyStatusType(StatusShow::Type type) override;
+ void setMyContactRosterItem(std::shared_ptr<ContactRosterItem> contact) override;
+ void setConnecting() override;
+ void setStreamEncryptionStatus(bool tlsInPlaceAndValid) override;
+ void openCertificateDialog(const std::vector<Certificate::ref>& chain) override;
static void openCertificateDialog(const std::vector<Certificate::ref>& chain, QWidget* parent);
QtEventWindow* getEventWindow();
QtChatListWindow* getChatListWindow();
- void setRosterModel(Roster* roster);
- void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands);
- void setBlockingCommandAvailable(bool isAvailable);
+ void setRosterModel(Roster* roster) override;
+ void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) override;
+ void setBlockingCommandAvailable(bool isAvailable) override;
private slots:
void handleStatusChanged(StatusShow::Type showType, const QString &statusMessage);
void handleSettingChanged(const std::string& settingPath);
@@ -79,8 +81,10 @@ namespace Swift {
void handleShowCertificateInfo();
void handleEditBlockingList();
void handleSomethingSelectedChanged(bool itemSelected);
+ void handleSubmitFormActionTriggered();
private:
+ Chattables& chattables_;
SettingsProvider* settings_;
QtLoginWindow::QtMenus loginMenus_;
std::vector<QMenu*> menus_;
@@ -98,6 +102,7 @@ namespace Swift {
QMenu* serverAdHocMenu_;
QtTabWidget* tabs_;
QComboBox* tabBarCombo_;
+ QtChatOverview* chatOverview_;
QWidget* contactsTabWidget_;
QWidget* eventsTabWidget_;
QtEventWindow* eventWindow_;
@@ -106,5 +111,6 @@ namespace Swift {
std::vector<DiscoItems::Item> serverAdHocCommands_;
QList<QAction*> serverAdHocCommandActions_;
QList<QAction*> onlineOnlyActions_;
+ QAction* submitFormAction_;
};
}
diff --git a/Swift/QtUI/QtPlainChatView.cpp b/Swift/QtUI/QtPlainChatView.cpp
index 7e9c857..cdee1e6 100644
--- a/Swift/QtUI/QtPlainChatView.cpp
+++ b/Swift/QtUI/QtPlainChatView.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2017 Isode Limited.
+ * Copyright (c) 2013-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -42,7 +42,7 @@ QtPlainChatView::QtPlainChatView(QtChatWindow *window, UIEventStream* eventStrea
QtPlainChatView::~QtPlainChatView() {
}
-QString chatMessageToString(const ChatWindow::ChatMessage& message) {
+static QString chatMessageToString(const ChatWindow::ChatMessage& message) {
QString result;
for (auto&& part : message.getParts()) {
std::shared_ptr<ChatWindow::ChatTextMessagePart> textPart;
@@ -178,7 +178,7 @@ void QtPlainChatView::setAckState(const std::string& /*id*/, ChatWindow::AckStat
std::string QtPlainChatView::addFileTransfer(const std::string& senderName, const std::string& /*avatarPath*/, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes, const std::string& description)
{
- const std::string ftId = "ft" + boost::lexical_cast<std::string>(idGenerator_++);
+ const std::string ftId = "ft" + std::to_string(idGenerator_++);
const std::string sizeString = formatSize(sizeInBytes);
FileTransfer* transfer;
@@ -327,7 +327,7 @@ void QtPlainChatView::acceptMUCInvite()
{
AcceptMUCInviteAction *action = dynamic_cast<AcceptMUCInviteAction*>(sender());
if (action) {
- eventStream_->send(std::make_shared<JoinMUCUIEvent>(action->jid_.toString(), action->password_, boost::optional<std::string>(), false, false, action->isImpromptu_, action->isContinuation_));
+ eventStream_->send(std::make_shared<JoinMUCUIEvent>(action->jid_.toString(), action->password_, boost::optional<std::string>(), false, action->isImpromptu_, action->isContinuation_));
delete action->parent_;
}
}
diff --git a/Swift/QtUI/QtSingleWindow.cpp b/Swift/QtUI/QtSingleWindow.cpp
index 1fba497..af7e552 100644
--- a/Swift/QtUI/QtSingleWindow.cpp
+++ b/Swift/QtUI/QtSingleWindow.cpp
@@ -1,13 +1,21 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/QtUI/QtSingleWindow.h>
+#include <QPushButton>
+#include <QVBoxLayout>
+
+#include <Swiften/Base/Platform.h>
+
#include <Swift/QtUI/QtChatTabs.h>
+#include <Swift/QtUI/QtLoginWindow.h>
#include <Swift/QtUI/QtSettingsProvider.h>
+#include <Swift/QtUI/ServerList/QtServerListView.h>
+#include <Swift/QtUI/ServerList/ServerListModel.h>
namespace Swift {
@@ -16,31 +24,49 @@ static const QString SINGLE_WINDOW_SPLITS = QString("SINGLE_WINDOW_SPLITS");
QtSingleWindow::QtSingleWindow(QtSettingsProvider* settings) : QSplitter() {
settings_ = settings;
- QVariant geometryVariant = settings_->getQSettings()->value(SINGLE_WINDOW_GEOMETRY);
+ auto geometryVariant = settings_->getQSettings()->value(SINGLE_WINDOW_GEOMETRY);
if (geometryVariant.isValid()) {
restoreGeometry(geometryVariant.toByteArray());
}
- connect(this, SIGNAL(splitterMoved(int, int)), this, SLOT(handleSplitterMoved(int, int)));
+ connect(this, SIGNAL(splitterMoved(int, int)), this, SLOT(handleSplitterMoved(/*int, int*/)));
+ setChildrenCollapsible(false);
+
+ auto left = new QWidget(this);
+ serverList_ = new QtServerListView();
+ serverListModel_ = new ServerListModel();
+ serverList_->setModel(serverListModel_);
+ serverListModel_->setModelData(&accountData_);
+ accountData_.onDataChanged.connect(boost::bind(&ServerListModel::handleDataChanged, serverListModel_));
+ auto addButton = new QPushButton("+", left);
+ QVBoxLayout* leftLayout = new QVBoxLayout();
+ leftLayout->addWidget(serverList_);
+ leftLayout->addWidget(addButton);
+ left->setLayout(leftLayout);
+ QSplitter::addWidget(left);
+ loginWindows_ = new QStackedWidget(this);
+ QSplitter::addWidget(loginWindows_);
+ tabs_ = new QStackedWidget(this);
+ QSplitter::addWidget(tabs_);
restoreSplitters();
+ setStretchFactor(0, 0);
+ setStretchFactor(1, 0);
+ setStretchFactor(2, 1);
+ connect(serverList_, &QtServerListView::clicked, this, &QtSingleWindow::handleListItemClicked);
+ connect(addButton, &QPushButton::clicked, this, &QtSingleWindow::wantsToAddAccount);
+#ifdef SWIFTEN_PLATFORM_MACOSX
+ setHandleWidth(0);
+#endif
}
QtSingleWindow::~QtSingleWindow() {
}
-void QtSingleWindow::addWidget(QWidget* widget) {
- QtChatTabs* tabs = dynamic_cast<QtChatTabs*>(widget);
- if (tabs) {
- connect(tabs, SIGNAL(onTitleChanged(const QString&)), this, SLOT(handleTabsTitleChanged(const QString&)));
- }
- QSplitter::addWidget(widget);
-}
-
void QtSingleWindow::handleTabsTitleChanged(const QString& title) {
setWindowTitle(title);
}
-void QtSingleWindow::handleSplitterMoved(int, int) {
+void QtSingleWindow::handleSplitterMoved() {
QList<QVariant> variantValues;
QList<int> intValues = sizes();
for (const auto& value : intValues) {
@@ -50,17 +76,18 @@ void QtSingleWindow::handleSplitterMoved(int, int) {
}
void QtSingleWindow::restoreSplitters() {
- QList<QVariant> variantValues = settings_->getQSettings()->value(SINGLE_WINDOW_SPLITS).toList();
- QList<int> intValues;
- for (auto&& value : variantValues) {
- intValues.append(value.toInt());
+ auto splitsVariant = settings_->getQSettings()->value(SINGLE_WINDOW_SPLITS);
+ if (splitsVariant.isValid()) {
+ auto variantValues = splitsVariant.toList();
+ QList<int> intValues;
+ for (auto&& value : variantValues) {
+ intValues.append(value.toInt());
+ }
+ setSizes(intValues);
+ }
+ else {
+ handleSplitterMoved();
}
- setSizes(intValues);
-}
-
-void QtSingleWindow::insertAtFront(QWidget* widget) {
- insertWidget(0, widget);
- restoreSplitters();
}
void QtSingleWindow::handleGeometryChanged() {
@@ -76,4 +103,24 @@ void QtSingleWindow::moveEvent(QMoveEvent*) {
handleGeometryChanged();
}
+void QtSingleWindow::addAccount(QtLoginWindow* loginWindow, QtChatTabs* tabs) {
+ loginWindows_->addWidget(loginWindow);
+ tabs_->addWidget(tabs);
+ std::string account = QString("Account %1").arg(loginWindows_->count()).toStdString();
+ accountData_.addAccount(account);
+ emit serverListModel_->layoutChanged();
+}
+
+void QtSingleWindow::handleListItemClicked(const QModelIndex& item) {
+ auto currentTabs = tabs_->widget(tabs_->currentIndex());
+ disconnect(currentTabs, SIGNAL(onTitleChanged(const QString&)), this, SLOT(handleTabsTitleChanged(const QString&)));
+ loginWindows_->setCurrentIndex(item.row());
+ tabs_->setCurrentIndex(item.row());
+ currentTabs = tabs_->widget(tabs_->currentIndex());
+ connect(currentTabs, SIGNAL(onTitleChanged(const QString&)), this, SLOT(handleTabsTitleChanged(const QString&)));
+ //TODO change the title of the window.
+ handleTabsTitleChanged(QString("Swift"));
+
+}
+
}
diff --git a/Swift/QtUI/QtSingleWindow.h b/Swift/QtUI/QtSingleWindow.h
index 804be65..a707cd3 100644
--- a/Swift/QtUI/QtSingleWindow.h
+++ b/Swift/QtUI/QtSingleWindow.h
@@ -1,29 +1,41 @@
/*
- * Copyright (c) 2010-2012 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
+#include <QListWidget>
#include <QSplitter>
+#include <QStackedWidget>
+
+#include <Swift/QtUI/ServerList/ServerListModel.h>
namespace Swift {
+ class QtChatTabs;
+ class QtLoginWindow;
class QtSettingsProvider;
+ class QtServerListView;
+ class ServerListModel;
class QtSingleWindow : public QSplitter {
Q_OBJECT
public:
QtSingleWindow(QtSettingsProvider* settings);
virtual ~QtSingleWindow();
- void insertAtFront(QWidget* widget);
- void addWidget(QWidget* widget);
+ void addAccount(QtLoginWindow* widget, QtChatTabs* tabs);
+
+ signals:
+ void wantsToAddAccount();
+
protected:
void resizeEvent(QResizeEvent*);
void moveEvent(QMoveEvent*);
private slots:
- void handleSplitterMoved(int, int);
+ void handleSplitterMoved();
void handleTabsTitleChanged(const QString& title);
+ void handleListItemClicked(const QModelIndex&);
private:
void handleGeometryChanged();
void restoreSplitters();
@@ -31,6 +43,11 @@ namespace Swift {
private:
QtSettingsProvider* settings_;
+ SwiftAccountData accountData_;
+ QtServerListView* serverList_;
+ ServerListModel* serverListModel_;
+ QStackedWidget* loginWindows_;
+ QStackedWidget* tabs_;
};
}
diff --git a/Swift/QtUI/QtStatusWidget.cpp b/Swift/QtUI/QtStatusWidget.cpp
index b175e5c..5e2ba5f 100644
--- a/Swift/QtUI/QtStatusWidget.cpp
+++ b/Swift/QtUI/QtStatusWidget.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -8,9 +8,6 @@
#include <algorithm>
-#include <boost/lambda/bind.hpp>
-#include <boost/lambda/lambda.hpp>
-
#include <QApplication>
#include <QBoxLayout>
#include <QComboBox>
@@ -32,8 +29,6 @@
#include <Swift/QtUI/QtLineEdit.h>
#include <Swift/QtUI/QtSwiftUtil.h>
-namespace lambda = boost::lambda;
-
namespace Swift {
QtStatusWidget::QtStatusWidget(StatusCache* statusCache, QWidget *parent) : QWidget(parent), statusCache_(statusCache), editCursor_(Qt::IBeamCursor), viewCursor_(Qt::PointingHandCursor) {
@@ -153,8 +148,9 @@ void QtStatusWidget::generateList() {
}
std::vector<StatusCache::PreviousStatus> previousStatuses = statusCache_->getMatches(Q2PSTRING(text), 8);
for (const auto& savedStatus : previousStatuses) {
- if (savedStatus.first.empty() || std::find_if(allTypes_.begin(), allTypes_.end(),
- savedStatus.second == lambda::_1 && savedStatus.first == lambda::bind(&statusShowTypeToFriendlyName, lambda::_1)) != allTypes_.end()) {
+ if (savedStatus.first.empty() || std::find_if(allTypes_.begin(), allTypes_.end(), [&](StatusShow::Type type) {
+ return (savedStatus.second == type) && (savedStatus.first == statusShowTypeToFriendlyName(type));
+ }) != allTypes_.end()) {
continue;
}
QListWidgetItem* item = new QListWidgetItem(P2QSTRING(savedStatus.first), menu_);
diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp
index 7daa5ce..8de5d70 100644
--- a/Swift/QtUI/QtSwift.cpp
+++ b/Swift/QtUI/QtSwift.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -22,8 +22,10 @@
#include <Swiften/Base/Path.h>
#include <Swiften/Base/Paths.h>
#include <Swiften/Base/Platform.h>
+#include <Swiften/Base/String.h>
#include <Swiften/Client/Client.h>
#include <Swiften/Elements/Presence.h>
+#include <Swiften/StringCodecs/Base64.h>
#include <Swiften/TLS/TLSContextFactory.h>
#include <SwifTools/Application/PlatformApplicationPathProvider.h>
@@ -33,7 +35,7 @@
#include <Swift/Controllers/ApplicationInfo.h>
#include <Swift/Controllers/BuildVersion.h>
-#include <Swift/Controllers/MainController.h>
+#include <Swift/Controllers/AccountController.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/Settings/SettingsProviderHierachy.h>
#include <Swift/Controllers/Settings/XMLSettingsProvider.h>
@@ -42,8 +44,6 @@
#include <Swift/Controllers/Storages/FileStoragesFactory.h>
#include <Swift/QtUI/QtChatTabs.h>
-#include <Swift/QtUI/QtChatTabsBase.h>
-#include <Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h>
#include <Swift/QtUI/QtChatWindowFactory.h>
#include <Swift/QtUI/QtLoginWindow.h>
#include <Swift/QtUI/QtSingleWindow.h>
@@ -92,16 +92,15 @@ po::options_description QtSwift::getOptionsDescription() {
("debug", "Turn on debug logging")
("help", "Show this help message")
("version", "Show version information")
- ("netbook-mode", "Use netbook mode display (unsupported)")
("no-tabs", "Don't manage chat windows in tabs (unsupported)")
("latency-debug", "Use latency debugging (unsupported)")
- ("multi-account", po::value<int>()->default_value(1), "Number of accounts to open windows for (unsupported)")
- ("start-minimized", "Don't show the login/roster window at startup")
- ("enable-jid-adhocs", "Enable AdHoc commands to custom JID's.")
+ ("enable-jid-adhocs", "Enable AdHoc commands to custom JIDs.")
#if QT_VERSION >= 0x040800
("language", po::value<std::string>(), "Use a specific language, instead of the system-wide one")
#endif
("logfile", po::value<std::string>()->implicit_value(""), "Save all logging information to a file")
+ ("enable-future", "Enable future features (unsupported). This will persist across restarts")
+ ("disable-future", "Disable future features. This will persist across restarts")
;
return result;
}
@@ -162,32 +161,28 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
qtSettings_ = new QtSettingsProvider();
xmlSettings_ = loadSettingsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "system-settings.xml")));
- settingsHierachy_ = new SettingsProviderHierachy();
- settingsHierachy_->addProviderToTopOfStack(xmlSettings_);
- settingsHierachy_->addProviderToTopOfStack(qtSettings_);
+ settingsHierarchy_ = new SettingsProviderHierachy();
+ settingsHierarchy_->addProviderToTopOfStack(xmlSettings_);
+ settingsHierarchy_->addProviderToTopOfStack(qtSettings_);
- networkFactories_.getTLSContextFactory()->setDisconnectOnCardRemoval(settingsHierachy_->getSetting(SettingConstants::DISCONNECT_ON_CARD_REMOVAL));
+ networkFactories_.getTLSContextFactory()->setDisconnectOnCardRemoval(settingsHierarchy_->getSetting(SettingConstants::DISCONNECT_ON_CARD_REMOVAL));
- std::map<std::string, std::string> emoticons;
- loadEmoticonsFile(":/emoticons/emoticons.txt", emoticons);
- loadEmoticonsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "emoticons.txt")), emoticons);
+ loadEmoticonsFile(":/emoticons/emoticons.txt", emoticons_);
+ loadEmoticonsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "emoticons.txt")), emoticons_);
- if (options.count("netbook-mode")) {
- splitter_ = new QtSingleWindow(qtSettings_);
- } else {
- splitter_ = nullptr;
+ splitter_ = new QtSingleWindow(qtSettings_);
+ connect(splitter_, SIGNAL(wantsToAddAccount()), this, SLOT(handleWantsToAddAccount()));
+
+ if (options.count("debug")) {
+ Log::setLogLevel(Swift::Log::debug);
}
- int numberOfAccounts = 1;
- try {
- numberOfAccounts = options["multi-account"].as<int>();
- } catch (...) {
- /* This seems to fail on a Mac when the .app is launched directly (the usual path).*/
- numberOfAccounts = 1;
+ if (options.count("enable-future")) {
+ settingsHierarchy_->storeSetting(SettingConstants::FUTURE, true);
}
- if (options.count("debug")) {
- Log::setLogLevel(Swift::Log::debug);
+ if (options.count("disable-future")) {
+ settingsHierarchy_->storeSetting(SettingConstants::FUTURE, false);
}
if (options.count("logfile")) {
@@ -199,6 +194,8 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
SWIFT_LOG(error) << "Error while retrieving the specified log file name from the command line" << std::endl;
}
}
+ //TODO this old option can be purged
+ useDelayForLatency_ = options.count("latency-debug") > 0;
// Load fonts
std::vector<std::string> fontNames = {
@@ -228,19 +225,19 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
SWIFT_LOG_ASSERT(error != -1, error) << "Failed to load font " << fontPath << std::endl;
}
- bool enableAdHocCommandOnJID = options.count("enable-jid-adhocs") > 0;
- tabs_ = nullptr;
- if (options.count("no-tabs") && !splitter_) {
- tabs_ = new QtChatTabsShortcutOnlySubstitute();
- }
- else {
- tabs_ = new QtChatTabs(splitter_ != nullptr, settingsHierachy_, true);
- }
- bool startMinimized = options.count("start-minimized") > 0;
+#ifdef SWIFTEN_PLATFORM_LINUX
+ std::string fontPath = std::string(":/themes/Default/Noto/NotoColorEmoji.ttf");
+ int error = QFontDatabase::addApplicationFont(P2QSTRING(fontPath));
+ SWIFT_LOG_ASSERT(error != -1, error) << "Failed to load font " << fontPath << std::endl;
+ QFont::insertSubstitution(QApplication::font().family(),"NotoColorEmoji");
+#endif
+#ifdef SWIFTEN_PLATFORM_WINDOWS
+ QFont::insertSubstitution(QApplication::font().family(), "Segoe UI Emoji");
+#endif
+ enableAdHocCommandOnJID_ = options.count("enable-jid-adhocs") > 0;
applicationPathProvider_ = new PlatformApplicationPathProvider(SWIFT_APPLICATION_NAME);
storagesFactory_ = new FileStoragesFactory(applicationPathProvider_->getDataDir(), networkFactories_.getCryptoProvider());
certificateStorageFactory_ = new CertificateFileStorageFactory(applicationPathProvider_->getDataDir(), tlsFactories_.getCertificateFactory(), networkFactories_.getCryptoProvider());
- chatWindowFactory_ = new QtChatWindowFactory(splitter_, settingsHierachy_, qtSettings_, tabs_, ":/themes/Default/", emoticons);
soundPlayer_ = new QtSoundPlayer(applicationPathProvider_);
// Ugly, because the dock depends on the tray, but the temporary
@@ -276,50 +273,24 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
statusCache_ = new StatusCache(applicationPathProvider_);
- if (splitter_) {
- splitter_->show();
- }
+ splitter_->show();
PlatformAutoUpdaterFactory autoUpdaterFactory;
- if (autoUpdaterFactory.isSupported() && settingsHierachy_->getSetting(QtUISettingConstants::ENABLE_SOFTWARE_UPDATES)
- && !settingsHierachy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL).empty()) {
- autoUpdater_ = autoUpdaterFactory.createAutoUpdater(updateChannelToFeed(settingsHierachy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL)));
+ if (autoUpdaterFactory.isSupported() && settingsHierarchy_->getSetting(QtUISettingConstants::ENABLE_SOFTWARE_UPDATES)
+ && !settingsHierarchy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL).empty()) {
+ autoUpdater_ = autoUpdaterFactory.createAutoUpdater(updateChannelToFeed(settingsHierarchy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL)));
autoUpdater_->checkForUpdates();
autoUpdater_->onUpdateStateChanged.connect(boost::bind(&QtSwift::handleAutoUpdaterStateChanged, this, _1));
- settingsHierachy_->onSettingChanged.connect([&](const std::string& path) {
+ settingsHierarchy_->onSettingChanged.connect([&](const std::string& path) {
if (path == QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL.getKey()) {
- autoUpdater_->setAppcastFeed(updateChannelToFeed(settingsHierachy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL)));
+ autoUpdater_->setAppcastFeed(updateChannelToFeed(settingsHierarchy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL)));
autoUpdater_->checkForUpdates();
}
});
}
-
- for (int i = 0; i < numberOfAccounts; i++) {
- if (i > 0) {
- // Don't add the first tray (see note above)
- systemTrays_.push_back(new QtSystemTray());
- }
- QtUIFactory* uiFactory = new QtUIFactory(settingsHierachy_, qtSettings_, tabs_, splitter_, systemTrays_[i], chatWindowFactory_, networkFactories_.getTimerFactory(), statusCache_, autoUpdater_, startMinimized, !emoticons.empty(), enableAdHocCommandOnJID);
- uiFactories_.push_back(uiFactory);
- MainController* mainController = new MainController(
- &clientMainThreadCaller_,
- &networkFactories_,
- uiFactory,
- settingsHierachy_,
- systemTrays_[i],
- soundPlayer_,
- storagesFactory_,
- certificateStorageFactory_,
- dock_,
- notifier_,
- uriHandler_,
- &idleDetector_,
- emoticons,
- options.count("latency-debug") > 0);
- mainControllers_.push_back(mainController);
- }
-
+ migrateLastLoginAccount();
+ restoreAccounts();
connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(handleAboutToQuit()));
}
@@ -328,17 +299,15 @@ QtSwift::~QtSwift() {
for (auto* factory : uiFactories_) {
delete factory;
}
- for (auto* controller : mainControllers_) {
+ for (auto* controller : accountControllers_) {
delete controller;
}
delete notifier_;
for (auto* tray : systemTrays_) {
delete tray;
}
- delete tabs_;
- delete chatWindowFactory_;
delete splitter_;
- delete settingsHierachy_;
+ delete settingsHierarchy_;
delete qtSettings_;
delete xmlSettings_;
delete statusCache_;
@@ -375,4 +344,139 @@ void QtSwift::handleAutoUpdaterStateChanged(AutoUpdater::State updatedState) {
}
}
+void QtSwift::handleWantsToAddAccount() {
+ auto loginWindow = addAccount();
+ if (!settingsHierarchy_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
+ for (const auto& profile : settingsHierarchy_->getAvailableProfiles()) {
+ ProfileSettingsProvider profileSettings(profile, settingsHierarchy_);
+ if (profileSettings.getIntSetting("enabled", 0)) {
+ // No point showing accounts that're already logged in
+ continue;
+ }
+ const auto& password = profileSettings.getStringSetting("pass");
+ const auto& certificate = profileSettings.getStringSetting("certificate");
+ const auto& jid = profileSettings.getStringSetting("jid");
+ const auto& clientOptions = parseClientOptions(profileSettings.getStringSetting("options"));
+ loginWindow->addAvailableAccount(jid, password, certificate, clientOptions);
+ }
+ }
+}
+
+void QtSwift::restoreAccounts() {
+ if (!settingsHierarchy_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
+ for (const auto& profile : settingsHierarchy_->getAvailableProfiles()) {
+ ProfileSettingsProvider profileSettings(profile, settingsHierarchy_);
+ if (!profileSettings.getIntSetting("enabled", 0)) {
+ continue;
+ }
+ const auto& jid = profileSettings.getStringSetting("jid");
+ const auto& password = profileSettings.getStringSetting("pass");
+ const auto& certificate = profileSettings.getStringSetting("certificate");
+ const auto& clientOptions = parseClientOptions(profileSettings.getStringSetting("options"));
+ auto loginWindow = addAccount();
+ loginWindow->addAvailableAccount(jid, password, certificate, clientOptions);
+ loginWindow->loginClicked();
+ }
+ }
+}
+
+void QtSwift::migrateLastLoginAccount() {
+ const SettingsProvider::Setting<bool> loginAutomatically = SettingsProvider::Setting<bool>("loginAutomatically", false);
+ if (settingsHierarchy_->getSetting(loginAutomatically)) {
+ auto selectedLoginJID = settingsHierarchy_->getSetting(SettingsProvider::Setting<std::string>("lastLoginJID", ""));
+ for (const auto& profile : settingsHierarchy_->getAvailableProfiles()) {
+ ProfileSettingsProvider profileSettings(profile, settingsHierarchy_);
+ if (profileSettings.getStringSetting("jid") == selectedLoginJID) {
+ profileSettings.storeInt("enabled", 1);
+ break;
+ }
+ }
+ settingsHierarchy_->storeSetting(loginAutomatically, false);
+ }
+}
+
+QtLoginWindow* QtSwift::addAccount() {
+ if (uiFactories_.size() > 0) {
+ // Don't add the first tray (see note above)
+ systemTrays_.push_back(new QtSystemTray());
+ }
+ auto tabs = new QtChatTabs(settingsHierarchy_, true);
+ QtUIFactory* uiFactory = new QtUIFactory(settingsHierarchy_, qtSettings_, tabs, splitter_, systemTrays_[systemTrays_.size() - 1], networkFactories_.getTimerFactory(), statusCache_, autoUpdater_, emoticons_, enableAdHocCommandOnJID_);
+ uiFactories_.push_back(uiFactory);
+ AccountController* accountController = new AccountController(
+ &clientMainThreadCaller_,
+ &networkFactories_,
+ uiFactory,
+ settingsHierarchy_,
+ systemTrays_[systemTrays_.size() - 1],
+ soundPlayer_,
+ storagesFactory_,
+ certificateStorageFactory_,
+ dock_,
+ notifier_,
+ uriHandler_,
+ &idleDetector_,
+ emoticons_,
+ useDelayForLatency_);
+ accountControllers_.push_back(accountController);
+
+ //FIXME - accountController has already created the window, so we can pass null here and get the old one
+ auto loginWindow = uiFactory->createLoginWindow(nullptr);
+
+ return dynamic_cast<QtLoginWindow*>(loginWindow);
+}
+
+//FIXME: Switch all this to boost::serialise
+
+#define CHECK_PARSE_LENGTH if (i >= segments.size()) {return result;}
+#define PARSE_INT_RAW(defaultValue) CHECK_PARSE_LENGTH intVal = defaultValue; try {intVal = boost::lexical_cast<int>(segments[i]);} catch(const boost::bad_lexical_cast&) {};i++;
+#define PARSE_STRING_RAW CHECK_PARSE_LENGTH stringVal = byteArrayToString(Base64::decode(segments[i]));i++;
+
+#define PARSE_BOOL(option, defaultValue) PARSE_INT_RAW(defaultValue); result.option = (intVal == 1);
+#define PARSE_INT(option, defaultValue) PARSE_INT_RAW(defaultValue); result.option = intVal;
+#define PARSE_STRING(option) PARSE_STRING_RAW; result.option = stringVal;
+#define PARSE_SAFE_STRING(option) PARSE_STRING_RAW; result.option = SafeString(createSafeByteArray(stringVal));
+#define PARSE_URL(option) {PARSE_STRING_RAW; result.option = URL::fromString(stringVal);}
+
+
+ClientOptions QtSwift::parseClientOptions(const std::string& optionString) {
+ ClientOptions result;
+ size_t i = 0;
+ int intVal = 0;
+ std::string stringVal;
+ std::vector<std::string> segments = String::split(optionString, ',');
+
+ PARSE_BOOL(useStreamCompression, 1);
+ PARSE_INT_RAW(-1);
+ switch (intVal) {
+ case 1: result.useTLS = ClientOptions::NeverUseTLS; break;
+ case 2: result.useTLS = ClientOptions::UseTLSWhenAvailable; break;
+ case 3: result.useTLS = ClientOptions::RequireTLS; break;
+ default:;
+ }
+ PARSE_BOOL(allowPLAINWithoutTLS, 0);
+ PARSE_BOOL(useStreamResumption, 0);
+ PARSE_BOOL(useAcks, 1);
+ PARSE_STRING(manualHostname);
+ PARSE_INT(manualPort, -1);
+ PARSE_INT_RAW(-1);
+ switch (intVal) {
+ case 1: result.proxyType = ClientOptions::NoProxy; break;
+ case 2: result.proxyType = ClientOptions::SystemConfiguredProxy; break;
+ case 3: result.proxyType = ClientOptions::SOCKS5Proxy; break;
+ case 4: result.proxyType = ClientOptions::HTTPConnectProxy; break;
+ }
+ PARSE_STRING(manualProxyHostname);
+ PARSE_INT(manualProxyPort, -1);
+ PARSE_URL(boshURL);
+ PARSE_URL(boshHTTPConnectProxyURL);
+ PARSE_SAFE_STRING(boshHTTPConnectProxyAuthID);
+ PARSE_SAFE_STRING(boshHTTPConnectProxyAuthPassword);
+ PARSE_BOOL(tlsOptions.schannelTLS1_0Workaround, false);
+ PARSE_BOOL(singleSignOn, false);
+
+ return result;
+}
+
+
}
diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h
index a7dc3cf..811b6e4 100644
--- a/Swift/QtUI/QtSwift.h
+++ b/Swift/QtUI/QtSwift.h
@@ -1,17 +1,19 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
+#include <map>
#include <string>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <Swiften/Base/Platform.h>
+#include <Swiften/Client/ClientOptions.h>
#include <Swiften/EventLoop/Qt/QtEventLoop.h>
#include <Swiften/Network/BoostNetworkFactories.h>
#include <Swiften/TLS/PlatformTLSFactories.h>
@@ -35,27 +37,28 @@ namespace po = boost::program_options;
class QSplitter;
namespace Swift {
- class QtUIFactory;
- class CertificateStorageFactory;
- class Dock;
- class Notifier;
- class StoragesFactory;
class ApplicationPathProvider;
class AvatarStorage;
class CapsStorage;
- class MainController;
- class QtSystemTray;
- class QtChatTabsBase;
+ class CertificateStorageFactory;
+ class Dock;
+ class EventLoop;
+ class AccountController;
+ class Notifier;
+ class QtChatTabs;
class QtChatWindowFactory;
- class QtSoundPlayer;
+ class QtLoginWindow;
class QtMUCSearchWindowFactory;
+ class QtSingleWindow;
+ class QtSoundPlayer;
+ class QtSystemTray;
+ class QtUIFactory;
class QtUserSearchWindowFactory;
- class EventLoop;
- class URIHandler;
class SettingsProviderHierachy;
- class XMLSettingsProvider;
class StatusCache;
- class QtSingleWindow;
+ class StoragesFactory;
+ class URIHandler;
+ class XMLSettingsProvider;
class QtSwift : public QObject {
Q_OBJECT
@@ -67,28 +70,35 @@ namespace Swift {
private slots:
void handleAboutToQuit();
void handleAutoUpdaterStateChanged(AutoUpdater::State updatedState);
+ void handleWantsToAddAccount();
private:
XMLSettingsProvider* loadSettingsFile(const QString& fileName);
void loadEmoticonsFile(const QString& fileName, std::map<std::string, std::string>& emoticons);
static const std::string& updateChannelToFeed(const std::string& channel);
+ QtLoginWindow* addAccount();
+ ClientOptions parseClientOptions(const std::string& optionString);
+ void restoreAccounts();
+ /**
+ * Upgrades the config from pre-multi-account to post-multi-account format (added in 5.0).
+ */
+ void migrateLastLoginAccount();
private:
QtEventLoop clientMainThreadCaller_;
PlatformTLSFactories tlsFactories_;
BoostNetworkFactories networkFactories_;
QtChatWindowFactory* chatWindowFactory_;
- std::vector<MainController*> mainControllers_;
+ std::vector<AccountController*> accountControllers_;
std::vector<QtSystemTray*> systemTrays_;
std::vector<QtUIFactory*> uiFactories_;
QtSettingsProvider* qtSettings_;
XMLSettingsProvider* xmlSettings_;
- SettingsProviderHierachy* settingsHierachy_;
+ SettingsProviderHierachy* settingsHierarchy_;
QtSingleWindow* splitter_;
QtSoundPlayer* soundPlayer_;
Dock* dock_;
URIHandler* uriHandler_;
- QtChatTabsBase* tabs_;
ApplicationPathProvider* applicationPathProvider_;
StoragesFactory* storagesFactory_;
CertificateStorageFactory* certificateStorageFactory_;
@@ -97,6 +107,9 @@ namespace Swift {
StatusCache* statusCache_;
PlatformIdleQuerier idleQuerier_;
ActualIdleDetector idleDetector_;
+ std::map<std::string, std::string> emoticons_;
+ bool enableAdHocCommandOnJID_ = false;
+ bool useDelayForLatency_;
#if defined(SWIFTEN_PLATFORM_MACOSX)
CocoaApplication cocoaApplication_;
CocoaApplicationActivateHelper cocoaApplicationActivateHelper_;
diff --git a/Swift/QtUI/QtTabbable.h b/Swift/QtUI/QtTabbable.h
index 5837702..63c60f4 100644
--- a/Swift/QtUI/QtTabbable.h
+++ b/Swift/QtUI/QtTabbable.h
@@ -19,7 +19,7 @@ namespace Swift {
bool isWidgetSelected();
virtual AlertType getWidgetAlertState() {return NoActivity;}
- virtual int getCount() {return 0;}
+ virtual size_t getCount() {return 0;}
virtual std::string getID() const = 0;
virtual void setEmphasiseFocus(bool /*emphasise*/) {}
diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp
index 583c477..93fca5f 100644
--- a/Swift/QtUI/QtUIFactory.cpp
+++ b/Swift/QtUI/QtUIFactory.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -19,10 +19,10 @@
#include <Swift/QtUI/QtAdHocCommandWindow.h>
#include <Swift/QtUI/QtBlockListEditorWindow.h>
#include <Swift/QtUI/QtChatTabs.h>
-#include <Swift/QtUI/QtChatTabsBase.h>
#include <Swift/QtUI/QtChatWindow.h>
#include <Swift/QtUI/QtChatWindowFactory.h>
#include <Swift/QtUI/QtContactEditWindow.h>
+#include <Swift/QtUI/QtFdpFormSubmitWindow.h>
#include <Swift/QtUI/QtFileTransferListWidget.h>
#include <Swift/QtUI/QtHighlightNotificationConfigDialog.h>
#include <Swift/QtUI/QtHistoryWindow.h>
@@ -41,30 +41,32 @@
namespace Swift {
-QtUIFactory::QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabsBase* tabs, QtSingleWindow* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, TimerFactory* timerFactory, StatusCache* statusCache, AutoUpdater* autoUpdater, bool startMinimized, bool emoticonsExist, bool enableAdHocCommandOnJID) : settings(settings), qtOnlySettings(qtOnlySettings), tabsBase(tabs), netbookSplitter(netbookSplitter), systemTray(systemTray), chatWindowFactory(chatWindowFactory), timerFactory_(timerFactory), lastMainWindow(nullptr), loginWindow(nullptr), statusCache(statusCache), autoUpdater(autoUpdater), startMinimized(startMinimized), emoticonsExist_(emoticonsExist), enableAdHocCommandOnJID_(enableAdHocCommandOnJID) {
- chatFontSize = settings->getSetting(QtUISettingConstants::CHATWINDOW_FONT_SIZE);
- historyFontSize_ = settings->getSetting(QtUISettingConstants::HISTORYWINDOW_FONT_SIZE);
- this->tabs = dynamic_cast<QtChatTabs*>(tabsBase);
+QtUIFactory::QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabs* tabs, QtSingleWindow* netbookSplitter, QtSystemTray* systemTray, TimerFactory* timerFactory, StatusCache* statusCache, AutoUpdater* autoUpdater, std::map<std::string, std::string>& emoticons, bool enableAdHocCommandOnJID) : settings_(settings), qtOnlySettings_(qtOnlySettings), tabs_(tabs), netbookSplitter_(netbookSplitter), systemTray_(systemTray), timerFactory_(timerFactory), lastMainWindow_(nullptr), loginWindow_(nullptr), statusCache_(statusCache), autoUpdater_(autoUpdater), emoticons_(emoticons), enableAdHocCommandOnJID_(enableAdHocCommandOnJID) {
+ emoticonsExist_ = !emoticons_.empty();
+ chatWindowFactory_ = new QtChatWindowFactory(netbookSplitter_, settings, qtOnlySettings, tabs_, ":/themes/Default/", emoticons_);
+ chatFontSize_ = settings_->getSetting(QtUISettingConstants::CHATWINDOW_FONT_SIZE);
+ historyFontSize_ = settings_->getSetting(QtUISettingConstants::HISTORYWINDOW_FONT_SIZE);
}
QtUIFactory::~QtUIFactory() {
- SWIFT_LOG(debug) << "Entering QtUIFactory destructor. chatWindows size:" << chatWindows.size() << std::endl;
- for (auto chat : chatWindows) {
+ SWIFT_LOG(debug) << "Entering QtUIFactory destructor. chatWindows size:" << chatWindows_.size() << std::endl;
+ for (auto chat : chatWindows_) {
SWIFT_LOG_ASSERT(chat.isNull(), debug) << "QtUIFactory has active chat windows and has not been reset properly" << std::endl;
}
+ delete chatWindowFactory_;
}
XMLConsoleWidget* QtUIFactory::createXMLConsoleWidget() {
QtXMLConsoleWidget* widget = new QtXMLConsoleWidget();
- tabsBase->addTab(widget);
+ tabs_->addTab(widget);
showTabs();
widget->show();
return widget;
}
HistoryWindow* QtUIFactory::createHistoryWindow(UIEventStream* uiEventStream) {
- QtHistoryWindow* window = new QtHistoryWindow(settings, uiEventStream);
- tabsBase->addTab(window);
+ QtHistoryWindow* window = new QtHistoryWindow(settings_, uiEventStream);
+ tabs_->addTab(window);
showTabs();
connect(window, SIGNAL(fontResized(int)), this, SLOT(handleHistoryWindowFontResized(int)));
@@ -75,53 +77,39 @@ HistoryWindow* QtUIFactory::createHistoryWindow(UIEventStream* uiEventStream) {
void QtUIFactory::handleHistoryWindowFontResized(int size) {
historyFontSize_ = size;
- settings->storeSetting(QtUISettingConstants::HISTORYWINDOW_FONT_SIZE, size);
+ settings_->storeSetting(QtUISettingConstants::HISTORYWINDOW_FONT_SIZE, size);
}
FileTransferListWidget* QtUIFactory::createFileTransferListWidget() {
QtFileTransferListWidget* widget = new QtFileTransferListWidget();
- tabsBase->addTab(widget);
+ tabs_->addTab(widget);
showTabs();
widget->show();
return widget;
}
-MainWindow* QtUIFactory::createMainWindow(UIEventStream* eventStream) {
- lastMainWindow = new QtMainWindow(settings, eventStream, loginWindow->getMenus(), statusCache, emoticonsExist_, enableAdHocCommandOnJID_);
- if (tabs) {
- tabs->setViewMenu(lastMainWindow->getMenus()[0]);
- }
- return lastMainWindow;
+MainWindow* QtUIFactory::createMainWindow(Chattables& chattables, UIEventStream* eventStream) {
+ lastMainWindow_ = new QtMainWindow(chattables, settings_, eventStream, loginWindow_->getMenus(), statusCache_, emoticonsExist_, enableAdHocCommandOnJID_);
+ tabs_->setViewMenu(lastMainWindow_->getMenus()[0]);
+ return lastMainWindow_;
}
LoginWindow* QtUIFactory::createLoginWindow(UIEventStream* eventStream) {
- loginWindow = new QtLoginWindow(eventStream, settings, timerFactory_, autoUpdater);
- if (netbookSplitter) {
- netbookSplitter->insertAtFront(loginWindow);
- }
- connect(systemTray, SIGNAL(clicked()), loginWindow, SLOT(toggleBringToFront()));
-
-#ifndef SWIFT_MOBILE
- QVariant loginWindowGeometryVariant = qtOnlySettings->getQSettings()->value("loginWindowGeometry");
- if (loginWindowGeometryVariant.isValid()) {
- loginWindow->restoreGeometry(loginWindowGeometryVariant.toByteArray());
+ if (loginWindow_) {
+ return loginWindow_;
}
- connect(loginWindow, SIGNAL(geometryChanged()), this, SLOT(handleLoginWindowGeometryChanged()));
- if (startMinimized) loginWindow->hide();
-#endif
- return loginWindow;
-}
-
-void QtUIFactory::handleLoginWindowGeometryChanged() {
- qtOnlySettings->getQSettings()->setValue("loginWindowGeometry", loginWindow->saveGeometry());
+ loginWindow_ = new QtLoginWindow(eventStream, settings_, timerFactory_, autoUpdater_);
+ netbookSplitter_->addAccount(loginWindow_, tabs_);
+ connect(systemTray_, SIGNAL(clicked()), loginWindow_, SLOT(toggleBringToFront()));
+ return loginWindow_;
}
EventWindow* QtUIFactory::createEventWindow() {
- return lastMainWindow->getEventWindow();
+ return lastMainWindow_->getEventWindow();
}
ChatListWindow* QtUIFactory::createChatListWindow(UIEventStream*) {
- return lastMainWindow->getChatListWindow();
+ return lastMainWindow_->getChatListWindow();
}
MUCSearchWindow* QtUIFactory::createMUCSearchWindow() {
@@ -129,27 +117,27 @@ MUCSearchWindow* QtUIFactory::createMUCSearchWindow() {
}
ChatWindow* QtUIFactory::createChatWindow(const JID& contact, UIEventStream* eventStream) {
- QtChatWindow* window = dynamic_cast<QtChatWindow*>(chatWindowFactory->createChatWindow(contact, eventStream));
+ QtChatWindow* window = dynamic_cast<QtChatWindow*>(chatWindowFactory_->createChatWindow(contact, eventStream));
// remove already closed and thereby deleted chat windows
- chatWindows.erase(std::remove_if(chatWindows.begin(), chatWindows.end(),
+ chatWindows_.erase(std::remove_if(chatWindows_.begin(), chatWindows_.end(),
[](QPointer<QtChatWindow>& window) {
return window.isNull();
- }), chatWindows.end());
+ }), chatWindows_.end());
- chatWindows.push_back(window);
+ chatWindows_.push_back(window);
connect(window, SIGNAL(fontResized(int)), this, SLOT(handleChatWindowFontResized(int)));
- window->handleFontResized(chatFontSize);
+ window->handleFontResized(chatFontSize_);
return window;
}
void QtUIFactory::handleChatWindowFontResized(int size) {
- chatFontSize = size;
- settings->storeSetting(QtUISettingConstants::CHATWINDOW_FONT_SIZE, size);
+ chatFontSize_ = size;
+ settings_->storeSetting(QtUISettingConstants::CHATWINDOW_FONT_SIZE, size);
// resize font in other chat windows
- for (auto&& existingWindow : chatWindows) {
+ for (auto&& existingWindow : chatWindows_) {
if (!existingWindow.isNull()) {
existingWindow->handleFontResized(size);
}
@@ -157,7 +145,7 @@ void QtUIFactory::handleChatWindowFontResized(int size) {
}
UserSearchWindow* QtUIFactory::createUserSearchWindow(UserSearchWindow::Type type, UIEventStream* eventStream, const std::set<std::string>& groups) {
- return new QtUserSearchWindow(eventStream, type, groups, qtOnlySettings);
+ return new QtUserSearchWindow(eventStream, type, groups, qtOnlySettings_);
}
JoinMUCWindow* QtUIFactory::createJoinMUCWindow(UIEventStream* uiEventStream) {
@@ -177,7 +165,7 @@ WhiteboardWindow* QtUIFactory::createWhiteboardWindow(std::shared_ptr<Whiteboard
}
HighlightEditorWindow* QtUIFactory::createHighlightEditorWindow() {
- return new QtHighlightNotificationConfigDialog(qtOnlySettings);
+ return new QtHighlightNotificationConfigDialog(qtOnlySettings_);
}
BlockListEditorWidget *QtUIFactory::createBlockListEditorWidget() {
@@ -188,11 +176,13 @@ AdHocCommandWindow* QtUIFactory::createAdHocCommandWindow(std::shared_ptr<Outgoi
return new QtAdHocCommandWindow(command);
}
+std::unique_ptr<FdpFormSubmitWindow> QtUIFactory::createFdpFormSubmitWindow() {
+ return std::make_unique<QtFdpFormSubmitWindow>();
+}
+
void QtUIFactory::showTabs() {
- if (tabs) {
- if (!tabs->isVisible()) {
- tabs->show();
- }
+ if (!tabs_->isVisible()) {
+ tabs_->show();
}
}
diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h
index 9989101..04836fe 100644
--- a/Swift/QtUI/QtUIFactory.h
+++ b/Swift/QtUI/QtUIFactory.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -17,8 +17,9 @@ class QSplitter;
namespace Swift {
class AutoUpdater;
+ class Chattables;
+ class FdpFormSubmitWindow;
class QtChatTabs;
- class QtChatTabsBase;
class QtChatTheme;
class QtChatWindow;
class QtChatWindowFactory;
@@ -35,11 +36,11 @@ namespace Swift {
class QtUIFactory : public QObject, public UIFactory {
Q_OBJECT
public:
- QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabsBase* tabs, QtSingleWindow* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, TimerFactory* timerFactory, StatusCache* statusCache, AutoUpdater* autoUpdater, bool startMinimized, bool emoticonsExist, bool enableAdHocCommandOnJID);
+ QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabs* tabs, QtSingleWindow* netbookSplitter, QtSystemTray* systemTray, TimerFactory* timerFactory, StatusCache* statusCache, AutoUpdater* autoUpdater, std::map<std::string, std::string>& emoticons, bool enableAdHocCommandOnJID);
~QtUIFactory();
virtual XMLConsoleWidget* createXMLConsoleWidget();
virtual HistoryWindow* createHistoryWindow(UIEventStream*);
- virtual MainWindow* createMainWindow(UIEventStream* eventStream);
+ virtual MainWindow* createMainWindow(Chattables& chattables, UIEventStream* eventStream);
virtual LoginWindow* createLoginWindow(UIEventStream* eventStream);
virtual EventWindow* createEventWindow();
virtual ChatListWindow* createChatListWindow(UIEventStream*);
@@ -54,9 +55,9 @@ namespace Swift {
virtual HighlightEditorWindow* createHighlightEditorWindow();
virtual BlockListEditorWidget* createBlockListEditorWidget();
virtual AdHocCommandWindow* createAdHocCommandWindow(std::shared_ptr<OutgoingAdHocCommandSession> command);
+ virtual std::unique_ptr<FdpFormSubmitWindow> createFdpFormSubmitWindow();
private slots:
- void handleLoginWindowGeometryChanged();
void handleChatWindowFontResized(int);
void handleHistoryWindowFontResized(int);
@@ -64,23 +65,22 @@ namespace Swift {
void showTabs();
private:
- SettingsProviderHierachy* settings;
- QtSettingsProvider* qtOnlySettings;
- QtChatTabsBase* tabsBase;
- QtChatTabs* tabs;
- QtSingleWindow* netbookSplitter;
- QtSystemTray* systemTray;
- QtChatWindowFactory* chatWindowFactory;
+ SettingsProviderHierachy* settings_;
+ QtSettingsProvider* qtOnlySettings_;
+ QtChatTabs* tabs_;
+ QtSingleWindow* netbookSplitter_;
+ QtSystemTray* systemTray_;
+ QtChatWindowFactory* chatWindowFactory_;
TimerFactory* timerFactory_;
- QtMainWindow* lastMainWindow;
- QtLoginWindow* loginWindow;
- StatusCache* statusCache;
- AutoUpdater* autoUpdater;
- std::vector<QPointer<QtChatWindow> > chatWindows;
- bool startMinimized;
- int chatFontSize;
+ QtMainWindow* lastMainWindow_;
+ QtLoginWindow* loginWindow_;
+ StatusCache* statusCache_;
+ AutoUpdater* autoUpdater_;
+ std::vector<QPointer<QtChatWindow> > chatWindows_;
+ int chatFontSize_;
int historyFontSize_;
bool emoticonsExist_;
+ std::map<std::string, std::string>& emoticons_;
bool enableAdHocCommandOnJID_;
};
}
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardFieldInfo.h b/Swift/QtUI/QtVCardWidget/QtVCardFieldInfo.h
index 093357a..fa42c49 100644
--- a/Swift/QtUI/QtVCardWidget/QtVCardFieldInfo.h
+++ b/Swift/QtUI/QtVCardWidget/QtVCardFieldInfo.h
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (c) 2016 Isode Limited.
+ * Copyright (c) 2016-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -36,7 +36,7 @@
} \
\
virtual bool testInstance(QWidget* widget) const { \
- return dynamic_cast<FIELD_CLASS*>(widget) != 0; \
+ return dynamic_cast<FIELD_CLASS*>(widget) != nullptr; \
} \
};
diff --git a/Swift/QtUI/QtVCardWidget/QtVCardWidget.cpp b/Swift/QtUI/QtVCardWidget/QtVCardWidget.cpp
index 290feca..1cd5505 100644
--- a/Swift/QtUI/QtVCardWidget/QtVCardWidget.cpp
+++ b/Swift/QtUI/QtVCardWidget/QtVCardWidget.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (c) 2014-2016 Isode Limited.
+ * Copyright (c) 2014-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -358,7 +358,7 @@ int QtVCardWidget::fieldTypeInstances(std::shared_ptr<QtVCardFieldInfo> fieldTyp
return instances;
}
-void layoutDeleteChildren(QLayout *layout) {
+static void layoutDeleteChildren(QLayout *layout) {
while(layout->count() > 0) {
QLayoutItem* child;
if ((child = layout->takeAt(0)) != nullptr) {
diff --git a/Swift/QtUI/QtWebKitChatView.cpp b/Swift/QtUI/QtWebKitChatView.cpp
index ea9a9c6..bca9e2e 100644
--- a/Swift/QtUI/QtWebKitChatView.cpp
+++ b/Swift/QtUI/QtWebKitChatView.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -11,9 +11,9 @@
#include <QDesktopWidget>
#include <QEventLoop>
#include <QFile>
+#include <QFileDevice>
#include <QFileDialog>
#include <QFileInfo>
-#include <QFileDevice>
#include <QInputDialog>
#include <QKeyEvent>
#include <QMessageBox>
@@ -28,6 +28,8 @@
#include <Swiften/Base/Log.h>
#include <Swiften/StringCodecs/Base64.h>
+#include <Swift/Controllers/SettingConstants.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
@@ -51,12 +53,15 @@ const QString QtWebKitChatView::ButtonFileTransferSendRequest = QString("filetra
const QString QtWebKitChatView::ButtonFileTransferAcceptRequest = QString("filetransfer-acceptrequest");
const QString QtWebKitChatView::ButtonFileTransferOpenFile = QString("filetransfer-openfile");
const QString QtWebKitChatView::ButtonMUCInvite = QString("mucinvite");
+const QString QtWebKitChatView::ButtonResendMessage = QString("resend-message");
+const QString QtWebKitChatView::ButtonResendPopup = QString("popup-resend");
+
namespace {
const double minimalFontScaling = 0.7;
}
-QtWebKitChatView::QtWebKitChatView(QtChatWindow* window, UIEventStream* eventStream, QtChatTheme* theme, QWidget* parent, bool disableAutoScroll) : QtChatView(parent), window_(window), eventStream_(eventStream), fontSizeSteps_(0), disableAutoScroll_(disableAutoScroll), previousMessageKind_(PreviosuMessageWasNone), previousMessageWasSelf_(false), showEmoticons_(false), insertingLastLine_(false), idCounter_(0) {
+QtWebKitChatView::QtWebKitChatView(QtChatWindow* window, UIEventStream* eventStream, QtChatTheme* theme, QWidget* parent, SettingsProvider* settings, bool disableAutoScroll /*= false*/) : QtChatView(parent), window_(window), eventStream_(eventStream), fontSizeSteps_(0), disableAutoScroll_(disableAutoScroll), previousMessageKind_(PreviosuMessageWasNone), previousMessageWasSelf_(false), showEmoticons_(false), insertingLastLine_(false), idCounter_(0), settings_(settings) {
theme_ = theme;
QVBoxLayout* mainLayout = new QVBoxLayout(this);
@@ -555,10 +560,13 @@ std::string QtWebKitChatView::addMessage(
QString scaledAvatarPath = QtScaledAvatarCache(32).getScaledAvatarPath(avatarPath.c_str());
+ std::string messageMarkingValue = "";
+
QString htmlString;
if (label) {
+ messageMarkingValue = label->getDisplayMarking();
htmlString = QString("<span style=\"border: thin dashed grey; padding-left: .5em; padding-right: .5em; color: %1; background-color: %2; font-size: 90%; margin-right: .5em; \" class='swift_label'>").arg(QtUtilities::htmlEscape(P2QSTRING(label->getForegroundColor()))).arg(QtUtilities::htmlEscape(P2QSTRING(label->getBackgroundColor())));
- htmlString += QString("%1</span> ").arg(QtUtilities::htmlEscape(P2QSTRING(label->getDisplayMarking())));
+ htmlString += QString("%1</span> ").arg(QtUtilities::htmlEscape(P2QSTRING(messageMarkingValue)));
}
QString styleSpanStart = style == "" ? "" : "<span style=\"" + style + "\">";
@@ -569,15 +577,16 @@ std::string QtWebKitChatView::addMessage(
QString highlightSpanEnd = highlightWholeMessage ? "</span>" : "";
htmlString += "<span class='swift_inner_message'>" + styleSpanStart + highlightSpanStart + message + highlightSpanEnd + styleSpanEnd + "</span>" ;
- bool appendToPrevious = appendToPreviousCheck(PreviousMessageWasMessage, senderName, senderIsSelf);
+ bool appendToPrevious = appendToPreviousCheck(PreviousMessageWasMessage, senderName, senderIsSelf, label);
QString qAvatarPath = scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.svg" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded();
- std::string id = "id" + boost::lexical_cast<std::string>(idCounter_++);
+ std::string id = "id" + std::to_string(idCounter_++);
addMessageBottom(std::make_shared<MessageSnippet>(htmlString, QtUtilities::htmlEscape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id), direction));
previousMessageWasSelf_ = senderIsSelf;
previousSenderName_ = P2QSTRING(senderName);
previousMessageKind_ = PreviousMessageWasMessage;
+ previousMessageDisplayMarking_ = messageMarkingValue;
return id;
}
@@ -600,6 +609,10 @@ QString QtWebKitChatView::buildChatWindowButton(const QString& name, const QStri
return html;
}
+QString QtWebKitChatView::buildChatWindowPopupImageButton(const QString& title, const QString& path, const QString& arg1, const QString& arg2, const QString& arg3, const QString& arg4, const QString& arg5) {
+ return QString("<div class=\"popup\" onclick='chatwindow.buttonClicked(\"%3\", \"%5\", \"6\", \"7\", \"8\", \"9\")' \"><img src='%1' title='%2'/><span class=\"popuptext\" id=\"resendPopup\" ><div class=\"resendButton\" onclick='chatwindow.buttonClicked(\"%4\", \"%5\", \"6\", \"7\", \"8\", \"9\")'>Resend</div></span></div>").arg(path).arg(title).arg(QtWebKitChatView::ButtonResendPopup).arg(QtWebKitChatView::ButtonResendMessage).arg(encodeButtonArgument(arg1)).arg(encodeButtonArgument(arg2)).arg(encodeButtonArgument(arg3)).arg(encodeButtonArgument(arg4)).arg(encodeButtonArgument(arg5));
+}
+
void QtWebKitChatView::resizeEvent(QResizeEvent* event) {
// This code ensures that if the user is scrolled all to the bottom of a chat view,
// the view stays scrolled to the bottom if the view is resized or if the message
@@ -645,7 +658,7 @@ std::string QtWebKitChatView::addFileTransfer(const std::string& senderName, con
bool appendToPrevious = appendToPreviousCheck(PreviousMessageWasFileTransfer, senderName, senderIsSelf);
QString scaledAvatarPath = QtScaledAvatarCache(32).getScaledAvatarPath(avatarPath.c_str());
QString qAvatarPath = scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.svg" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded();
- std::string id = "ftmessage" + boost::lexical_cast<std::string>(idCounter_++);
+ std::string id = "ftmessage" + std::to_string(idCounter_++);
addMessageBottom(std::make_shared<MessageSnippet>(htmlString, QtUtilities::htmlEscape(P2QSTRING(senderName)), B2QDATE(boost::posix_time::second_clock::universal_time()), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id), ChatSnippet::getDirection(actionText)));
previousMessageWasSelf_ = senderIsSelf;
@@ -679,7 +692,7 @@ std::string QtWebKitChatView::addWhiteboardRequest(const QString& contact, bool
"</div>";
}
QString qAvatarPath = "qrc:/icons/avatar.svg";
- std::string id = "wbmessage" + boost::lexical_cast<std::string>(idCounter_++);
+ std::string id = "wbmessage" + std::to_string(idCounter_++);
addMessageBottom(std::make_shared<MessageSnippet>(htmlString, QtUtilities::htmlEscape(contact), B2QDATE(boost::posix_time::second_clock::universal_time()), qAvatarPath, false, false, theme_, P2QSTRING(id), ChatSnippet::getDirection(actionText)));
previousMessageWasSelf_ = false;
previousSenderName_ = contact;
@@ -798,9 +811,23 @@ void QtWebKitChatView::handleHTMLButtonClicked(QString id, QString encodedArgume
QString elementID = arg3;
QString isImpromptu = arg4;
QString isContinuation = arg5;
- eventStream_->send(std::make_shared<JoinMUCUIEvent>(Q2PSTRING(roomJID), Q2PSTRING(password), boost::optional<std::string>(), false, false, isImpromptu.contains("true"), isContinuation.contains("true")));
+ eventStream_->send(std::make_shared<JoinMUCUIEvent>(Q2PSTRING(roomJID), Q2PSTRING(password), boost::optional<std::string>(), false, isImpromptu.contains("true"), isContinuation.contains("true")));
setMUCInvitationJoined(elementID);
}
+ else if (id.startsWith(ButtonResendPopup)) {
+ QString chatID = arg1;
+ QWebElement message = document_.findFirst("#" + arg1);
+ if (!message.isNull()) {
+ QWebElement popuptext = message.findFirst("span#resendPopup.popuptext");
+ if (!popuptext.isNull()) {
+ popuptext.toggleClass("show");
+ }
+ }
+ }
+ else if (id.startsWith(ButtonResendMessage)) {
+ QString chatID = arg1;
+ window_->resendMessage(Q2PSTRING(chatID));
+ }
else {
SWIFT_LOG(debug) << "Unknown HTML button! ( " << Q2PSTRING(id) << " )" << std::endl;
}
@@ -822,7 +849,7 @@ void QtWebKitChatView::addErrorMessage(const ChatWindow::ChatMessage& errorMessa
}
QString errorMessageHTML(chatMessageToHTML(errorMessage));
- std::string id = "id" + boost::lexical_cast<std::string>(idCounter_++);
+ std::string id = "id" + std::to_string(idCounter_++);
addMessageBottom(std::make_shared<SystemMessageSnippet>("<span class=\"error\">" + errorMessageHTML + "</span>", QDateTime::currentDateTime(), false, theme_, P2QSTRING(id), ChatSnippet::getDirection(errorMessage)));
previousMessageWasSelf_ = false;
@@ -835,7 +862,7 @@ std::string QtWebKitChatView::addSystemMessage(const ChatWindow::ChatMessage& me
}
QString messageHTML = chatMessageToHTML(message);
- std::string id = "id" + boost::lexical_cast<std::string>(idCounter_++);
+ std::string id = "id" + std::to_string(idCounter_++);
addMessageBottom(std::make_shared<SystemMessageSnippet>(messageHTML, QDateTime::currentDateTime(), false, theme_, P2QSTRING(id), getActualDirection(message, direction)));
previousMessageKind_ = PreviousMessageWasSystem;
@@ -901,7 +928,7 @@ void QtWebKitChatView::addPresenceMessage(const ChatWindow::ChatMessage& message
}
QString messageHTML = chatMessageToHTML(message);
- std::string id = "id" + boost::lexical_cast<std::string>(idCounter_++);
+ std::string id = "id" + std::to_string(idCounter_++);
addMessageBottom(std::make_shared<SystemMessageSnippet>(messageHTML, QDateTime::currentDateTime(), false, theme_, P2QSTRING(id), getActualDirection(message, direction)));
previousMessageKind_ = PreviousMessageWasPresence;
@@ -958,7 +985,9 @@ void QtWebKitChatView::setAckState(std::string const& id, ChatWindow::AckState s
xml = "";
displayReceiptInfo(P2QSTRING(id), true);
break;
- case ChatWindow::Failed: xml = "<img src='qrc:/icons/error.png' title='" + tr("This message may not have been transmitted.") + "'/>"; break;
+ case ChatWindow::Failed:
+ xml = buildChatWindowPopupImageButton(tr("This message may not have been sent. Click to resend."), "qrc:/icons/error.png", P2QSTRING(id));
+ break;
}
setAckXML(P2QSTRING(id), xml);
}
@@ -978,12 +1007,19 @@ void QtWebKitChatView::setMessageReceiptState(const std::string& id, ChatWindow:
setReceiptXML(P2QSTRING(id), xml);
}
-bool QtWebKitChatView::appendToPreviousCheck(PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf) {
+bool QtWebKitChatView::appendToPreviousCheck(PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf, const std::shared_ptr<SecurityLabel>& label /*=nullptr*/) {
bool result = previousMessageKind_ == messageKind && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_&& previousSenderName_ == P2QSTRING(senderName)));
if (insertingLastLine_) {
insertingLastLine_ = false;
return false;
}
+ if (settings_->getSetting(SettingConstants::MUC_MARKING_ELISION)) {
+ if (label && label->getDisplayMarking() != previousMessageDisplayMarking_) {
+ if (label->getDisplayMarking() != "") {
+ return false;
+ }
+ }
+ }
return result;
}
diff --git a/Swift/QtUI/QtWebKitChatView.h b/Swift/QtUI/QtWebKitChatView.h
index 802c216..f0b4459 100644
--- a/Swift/QtUI/QtWebKitChatView.h
+++ b/Swift/QtUI/QtWebKitChatView.h
@@ -13,8 +13,6 @@
#include <QWebElement>
#include <QWidget>
-#include <Swiften/Base/Override.h>
-
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
#include <Swift/QtUI/ChatSnippet.h>
@@ -30,6 +28,7 @@ namespace Swift {
class QtChatWindowJSBridge;
class UIEventStream;
class QtChatWindow;
+ class SettingsProvider;
class QtWebKitChatView : public QtChatView {
Q_OBJECT
@@ -43,43 +42,45 @@ namespace Swift {
static const QString ButtonFileTransferAcceptRequest;
static const QString ButtonFileTransferOpenFile;
static const QString ButtonMUCInvite;
+ static const QString ButtonResendMessage;
+ static const QString ButtonResendPopup;
public:
- QtWebKitChatView(QtChatWindow* window, UIEventStream* eventStream, QtChatTheme* theme, QWidget* parent, bool disableAutoScroll = false);
- ~QtWebKitChatView();
+ QtWebKitChatView(QtChatWindow* window, UIEventStream* eventStream, QtChatTheme* theme, QWidget* parent, SettingsProvider* settings, bool disableAutoScroll = false);
+ ~QtWebKitChatView() override;
/** Add message to window.
* @return id of added message (for acks).
*/
- virtual std::string addMessage(const ChatWindow::ChatMessage& message, const std::string& senderName, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) SWIFTEN_OVERRIDE;
+ virtual std::string addMessage(const ChatWindow::ChatMessage& message, const std::string& senderName, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) override;
/** Adds action to window.
* @return id of added message (for acks);
*/
- virtual std::string addAction(const ChatWindow::ChatMessage& message, const std::string& senderName, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) SWIFTEN_OVERRIDE;
-
- virtual std::string addSystemMessage(const ChatWindow::ChatMessage& message, ChatWindow::Direction direction) SWIFTEN_OVERRIDE;
- virtual void addPresenceMessage(const ChatWindow::ChatMessage& message, ChatWindow::Direction direction) SWIFTEN_OVERRIDE;
-
- virtual void addErrorMessage(const ChatWindow::ChatMessage& message) SWIFTEN_OVERRIDE;
- virtual void replaceMessage(const ChatWindow::ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time) SWIFTEN_OVERRIDE;
- virtual void replaceSystemMessage(const ChatWindow::ChatMessage& message, const std::string& id, ChatWindow::TimestampBehaviour timestampBehaviour) SWIFTEN_OVERRIDE;
- virtual void replaceWithAction(const ChatWindow::ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time) SWIFTEN_OVERRIDE;
- virtual void replaceLastMessage(const ChatWindow::ChatMessage& message, const ChatWindow::TimestampBehaviour timestampBehaviour) SWIFTEN_OVERRIDE;
- virtual void setAckState(const std::string& id, ChatWindow::AckState state) SWIFTEN_OVERRIDE;
-
- virtual std::string addFileTransfer(const std::string& senderName, const std::string& avatarPath, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes, const std::string& description) SWIFTEN_OVERRIDE;
- virtual void setFileTransferProgress(std::string, const int percentageDone) SWIFTEN_OVERRIDE;
- virtual void setFileTransferStatus(std::string, const ChatWindow::FileTransferState state, const std::string& msg = "") SWIFTEN_OVERRIDE;
- virtual void addMUCInvitation(const std::string& senderName, const JID& jid, const std::string& reason, const std::string& password, bool direct, bool isImpromptu, bool isContinuation) SWIFTEN_OVERRIDE;
- virtual std::string addWhiteboardRequest(const QString& contact, bool senderIsSelf) SWIFTEN_OVERRIDE;
- virtual void setWhiteboardSessionStatus(const std::string& id, const ChatWindow::WhiteboardSessionState state) SWIFTEN_OVERRIDE;
- virtual void setMessageReceiptState(const std::string& id, ChatWindow::ReceiptState state) SWIFTEN_OVERRIDE;
-
- virtual void showEmoticons(bool show) SWIFTEN_OVERRIDE;
+ virtual std::string addAction(const ChatWindow::ChatMessage& message, const std::string& senderName, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) override;
+
+ virtual std::string addSystemMessage(const ChatWindow::ChatMessage& message, ChatWindow::Direction direction) override;
+ virtual void addPresenceMessage(const ChatWindow::ChatMessage& message, ChatWindow::Direction direction) override;
+
+ virtual void addErrorMessage(const ChatWindow::ChatMessage& message) override;
+ virtual void replaceMessage(const ChatWindow::ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time) override;
+ virtual void replaceSystemMessage(const ChatWindow::ChatMessage& message, const std::string& id, ChatWindow::TimestampBehaviour timestampBehaviour) override;
+ virtual void replaceWithAction(const ChatWindow::ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time) override;
+ virtual void replaceLastMessage(const ChatWindow::ChatMessage& message, const ChatWindow::TimestampBehaviour timestampBehaviour) override;
+ virtual void setAckState(const std::string& id, ChatWindow::AckState state) override;
+
+ virtual std::string addFileTransfer(const std::string& senderName, const std::string& avatarPath, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes, const std::string& description) override;
+ virtual void setFileTransferProgress(std::string, const int percentageDone) override;
+ virtual void setFileTransferStatus(std::string, const ChatWindow::FileTransferState state, const std::string& msg = "") override;
+ virtual void addMUCInvitation(const std::string& senderName, const JID& jid, const std::string& reason, const std::string& password, bool direct, bool isImpromptu, bool isContinuation) override;
+ virtual std::string addWhiteboardRequest(const QString& contact, bool senderIsSelf) override;
+ virtual void setWhiteboardSessionStatus(const std::string& id, const ChatWindow::WhiteboardSessionState state) override;
+ virtual void setMessageReceiptState(const std::string& id, ChatWindow::ReceiptState state) override;
+
+ virtual void showEmoticons(bool show) override;
void addMessageTop(std::shared_ptr<ChatSnippet> snippet);
void addMessageBottom(std::shared_ptr<ChatSnippet> snippet);
int getSnippetPositionByDate(const QDate& date); // FIXME : This probably shouldn't have been public
- virtual void addLastSeenLine() SWIFTEN_OVERRIDE;
+ virtual void addLastSeenLine() override;
private: // previously public, now private
void replaceLastMessage(const QString& newMessage, const ChatWindow::TimestampBehaviour timestampBehaviour);
@@ -116,9 +117,9 @@ namespace Swift {
void resetTopInsertPoint();
void increaseFontSize(int numSteps = 1);
void decreaseFontSize();
- virtual void resizeFont(int fontSizeSteps) SWIFTEN_OVERRIDE;
- virtual void scrollToBottom() SWIFTEN_OVERRIDE;
- virtual void handleKeyPressEvent(QKeyEvent* event) SWIFTEN_OVERRIDE;
+ virtual void resizeFont(int fontSizeSteps) override;
+ virtual void scrollToBottom() override;
+ virtual void handleKeyPressEvent(QKeyEvent* event) override;
private slots:
void handleViewLoadFinished(bool);
@@ -152,15 +153,16 @@ namespace Swift {
const boost::posix_time::ptime& time,
const QString& style,
const HighlightAction& highlight);
- bool appendToPreviousCheck(PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf);
+ bool appendToPreviousCheck(PreviousMessageKind messageKind, const std::string& senderName, bool senderIsSelf, const std::shared_ptr<SecurityLabel>& label = nullptr);
static ChatSnippet::Direction getActualDirection(const ChatWindow::ChatMessage& message, ChatWindow::Direction direction);
QString getHighlightSpanStart(const std::string& text, const std::string& background);
QString getHighlightSpanStart(const HighlightAction& highlight);
QString chatMessageToHTML(const ChatWindow::ChatMessage& message);
static QString buildChatWindowButton(const QString& name, const QString& id, const QString& arg1 = QString(), const QString& arg2 = QString(), const QString& arg3 = QString(), const QString& arg4 = QString(), const QString& arg5 = QString());
+ static QString buildChatWindowPopupImageButton(const QString& title, const QString& path, const QString& arg1 = QString(), const QString& arg2 = QString(), const QString& arg3 = QString(), const QString& arg4 = QString(), const QString& arg5 = QString());
protected:
- void resizeEvent(QResizeEvent* event) SWIFTEN_OVERRIDE;
+ void resizeEvent(QResizeEvent* event) override;
private:
void headerEncode();
@@ -191,5 +193,7 @@ namespace Swift {
QString previousSenderName_;
std::map<QString, QString> descriptions_;
std::map<QString, QString> filePaths_;
+ std::string previousMessageDisplayMarking_;
+ SettingsProvider* settings_ = nullptr;
};
}
diff --git a/Swift/QtUI/QtWebView.cpp b/Swift/QtUI/QtWebView.cpp
index 967be1a..24636ed 100644
--- a/Swift/QtUI/QtWebView.cpp
+++ b/Swift/QtUI/QtWebView.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2017 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -7,8 +7,6 @@
#include <Swift/QtUI/QtWebView.h>
-#include <boost/numeric/conversion/cast.hpp>
-
#include <QFocusEvent>
#include <QKeyEvent>
#include <QKeySequence>
@@ -48,7 +46,7 @@ void QtWebView::keyPressEvent(QKeyEvent* event) {
modifiers,
event->text(),
event->isAutoRepeat(),
- boost::numeric_cast<unsigned short>(event->count()));
+ event->count());
QWebView::keyPressEvent(translatedEvent);
delete translatedEvent;
}
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 54f0450..a2ad9b1 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -7,6 +7,11 @@ def generateQRCTheme(dir, prefix) :
result += "<RCC version =\"1.0\">"
result += "<qresource prefix=\"/themes/" + prefix + "\">"
for (path, dirs, files) in os.walk(sourceDir) :
+ #skip the Noto emoji fonts in Windows. No need to package them since they aren't used
+ if "Noto" in path and not env["PLATFORM"] == "linux" :
+ continue
+ dirs.sort()
+ files.sort()
for file in files :
filePath = os.path.join(path,file)
result += "<file alias=\"%(alias)s\">%(path)s</file>" % {
@@ -22,9 +27,9 @@ Import("env")
myenv = env.Clone()
# Disable warnings that affect Qt
-myenv["CXXFLAGS"] = filter(lambda x : x != "-Wfloat-equal", myenv["CXXFLAGS"])
+myenv["CXXFLAGS"] = list(filter(lambda x : x != "-Wfloat-equal", myenv["CXXFLAGS"]))
if "clang" in env["CC"] :
- myenv.Append(CXXFLAGS = ["-Wno-float-equal", "-Wno-shorten-64-to-32", "-Wno-missing-prototypes", "-Wno-unreachable-code", "-Wno-disabled-macro-expansion", "-Wno-unused-private-field", "-Wno-extra-semi", "-Wno-duplicate-enum", "-Wno-missing-variable-declarations", "-Wno-conversion", "-Wno-undefined-reinterpret-cast"])
+ myenv.Append(CXXFLAGS = ["-Wno-float-equal", "-Wno-shorten-64-to-32", "-Wno-conversion"])
myenv.UseFlags(env["SWIFT_CONTROLLERS_FLAGS"])
myenv.UseFlags(env["SWIFTOOLS_FLAGS"])
@@ -110,131 +115,140 @@ myenv.WriteVal("DefaultTheme.qrc", myenv.Value(generateQRCTheme(myenv.Dir("#/Swi
sources = [
"main.cpp",
+ "ChatList/ChatListDelegate.cpp",
+ "ChatList/ChatListModel.cpp",
+ "ChatList/ChatListMUCItem.cpp",
+ "ChatList/ChatListRecentItem.cpp",
+ "ChatList/ChatListWhiteboardItem.cpp",
+ "ChatList/QtChatListWindow.cpp",
+ "ChattablesModel.cpp",
+ "ChatSnippet.cpp",
+ "EventViewer/EventDelegate.cpp",
+ "EventViewer/EventModel.cpp",
+ "EventViewer/QtEvent.cpp",
+ "EventViewer/QtEventWindow.cpp",
+ "EventViewer/TwoLineDelegate.cpp",
"FlowLayout.cpp",
+ "MessageSnippet.cpp",
+ "MUCSearch/MUCSearchDelegate.cpp",
+ "MUCSearch/MUCSearchEmptyItem.cpp",
+ "MUCSearch/MUCSearchModel.cpp",
+ "MUCSearch/MUCSearchRoomItem.cpp",
+ "MUCSearch/MUCSearchServiceItem.cpp",
+ "MUCSearch/QtLeafSortFilterProxyModel.cpp",
+ "MUCSearch/QtMUCSearchWindow.cpp",
+ "ServerList/ServerListDelegate.cpp",
+ "ServerList/ServerListModel.cpp",
+ "ServerList/QtServerListView.cpp",
+ "qrc_DefaultTheme.cc",
+ "qrc_Swift.cc",
"QtAboutWidget.cpp",
- "QtSpellCheckerWindow.cpp",
+ "QtAddBookmarkWindow.cpp",
+ "QtAdHocCommandWindow.cpp",
+ "QtAdHocCommandWithJIDWindow.cpp",
+ "QtAffiliationEditor.cpp",
"QtAvatarWidget.cpp",
- "QtUIFactory.cpp",
+ "QtBlockListEditorWindow.cpp",
+ "QtBookmarkDetailWindow.cpp",
+ "QtCachedImageScaler.cpp",
+ "QtChatOverview.cpp",
+ "QtChatOverviewBundle.cpp",
+ "QtChatOverviewDelegate.cpp",
+ "QtChatTabs.cpp",
+ "QtChatTabsBase.cpp",
+ "QtChatTheme.cpp",
+ "QtChatView.cpp",
+ "QtChatWindow.cpp",
"QtChatWindowFactory.cpp",
+ "QtChatWindowJSBridge.cpp",
+ "QtCheckBoxStyledItemDelegate.cpp",
"QtClickableLabel.cpp",
+ "QtClosableLineEdit.cpp",
+ "QtColorSelectionStyledItemDelegate.cpp",
+ "QtColorToolButton.cpp",
+ "QtConnectionSettingsWindow.cpp",
+ "QtContactEditWidget.cpp",
+ "QtContactEditWindow.cpp",
+ "QtEditBookmarkWindow.cpp",
+ "QtElidingLabel.cpp",
+ "QtEmojiCell.cpp",
+ "QtEmojisGrid.cpp",
+ "QtEmojisScroll.cpp",
+ "QtEmojisSelector.cpp",
+ "QtEmoticonsGrid.cpp",
+ "QtExpandedListView.cpp",
+ "QtFdpFormSubmitWindow.cpp",
+ "QtFileTransferListItemModel.cpp",
+ "QtFileTransferListWidget.cpp",
+ "QtFormResultItemModel.cpp",
+ "QtFormWidget.cpp",
+ "QtHighlightNotificationConfigDialog.cpp",
+ "QtHistoryWindow.cpp",
+ "QtJoinMUCWindow.cpp",
+ "QtLineEdit.cpp",
+ "QtListWidget.cpp",
"QtLoginWindow.cpp",
"QtMainWindow.cpp",
- "QtProfileWindow.cpp",
- "QtBlockListEditorWindow.cpp",
+ "QtMUCConfigurationWindow.cpp",
"QtNameWidget.cpp",
+ "QtPlainChatView.cpp",
+ "QtProfileWindow.cpp",
+ "QtRecentEmojisGrid.cpp",
+ "QtResourceHelper.cpp",
+ "QtRosterHeader.cpp",
+ "QtScaledAvatarCache.cpp",
"QtSettingsProvider.cpp",
+ "QtSingleWindow.cpp",
+ "QtSoundPlayer.cpp",
+ "QtSoundSelectionStyledItemDelegate.cpp",
+ "QtSpellCheckerWindow.cpp",
+ "QtSpellCheckHighlighter.cpp",
"QtStatusWidget.cpp",
- "QtScaledAvatarCache.cpp",
+ "QtSubscriptionRequestWindow.cpp",
"QtSwift.cpp",
- "QtURIHandler.cpp",
- "QtChatWindow.cpp",
- "QtChatView.cpp",
- "QtWebKitChatView.cpp",
- "QtPlainChatView.cpp",
- "QtChatTheme.cpp",
- "QtChatTabs.cpp",
- "QtChatTabsBase.cpp",
- "QtChatTabsShortcutOnlySubstitute.cpp",
- "QtSoundPlayer.cpp",
"QtSystemTray.cpp",
- "QtCachedImageScaler.cpp",
"QtTabbable.cpp",
"QtTabWidget.cpp",
"QtTextEdit.cpp",
- "QtXMLConsoleWidget.cpp",
- "QtHistoryWindow.cpp",
- "QtFileTransferListWidget.cpp",
- "QtFileTransferListItemModel.cpp",
- "QtAdHocCommandWindow.cpp",
- "QtAdHocCommandWithJIDWindow.cpp",
+ "QtUIFactory.cpp",
+ "QtUISettingConstants.cpp",
+ "QtUpdateFeedSelectionDialog.cpp",
+ "QtURIHandler.cpp",
+ "QtURLValidator.cpp",
"QtUtilities.cpp",
- "QtBookmarkDetailWindow.cpp",
- "QtAddBookmarkWindow.cpp",
- "QtEditBookmarkWindow.cpp",
- "QtEmojisGrid.cpp",
- "QtEmojiCell.cpp",
- "QtEmojisScroll.cpp",
- "QtEmojisSelector.cpp",
- "QtRecentEmojisGrid.cpp",
- "QtEmoticonsGrid.cpp",
- "QtContactEditWindow.cpp",
- "QtContactEditWidget.cpp",
- "QtSingleWindow.cpp",
- "QtColorToolButton.cpp",
- "QtClosableLineEdit.cpp",
- "QtHighlightNotificationConfigDialog.cpp",
- "ChatSnippet.cpp",
- "MessageSnippet.cpp",
- "SystemMessageSnippet.cpp",
- "QtElidingLabel.cpp",
- "QtFormWidget.cpp",
- "QtFormResultItemModel.cpp",
- "QtLineEdit.cpp",
- "QtJoinMUCWindow.cpp",
- "QtConnectionSettingsWindow.cpp",
- "Roster/RosterModel.cpp",
- "Roster/QtTreeWidget.cpp",
- "Roster/RosterDelegate.cpp",
- "Roster/GroupItemDelegate.cpp",
+ "QtWebKitChatView.cpp",
+ "QtWebView.cpp",
+ "QtXMLConsoleWidget.cpp",
"Roster/DelegateCommons.cpp",
+ "Roster/GroupItemDelegate.cpp",
"Roster/QtFilterWidget.cpp",
- "Roster/QtRosterWidget.cpp",
"Roster/QtOccupantListWidget.cpp",
+ "Roster/QtRosterWidget.cpp",
+ "Roster/QtTreeWidget.cpp",
+ "Roster/RosterDelegate.cpp",
+ "Roster/RosterModel.cpp",
"Roster/RosterTooltip.cpp",
- "EventViewer/EventModel.cpp",
- "EventViewer/EventDelegate.cpp",
- "EventViewer/TwoLineDelegate.cpp",
- "EventViewer/QtEventWindow.cpp",
- "EventViewer/QtEvent.cpp",
- "ChatList/QtChatListWindow.cpp",
- "ChatList/ChatListModel.cpp",
- "ChatList/ChatListDelegate.cpp",
- "ChatList/ChatListMUCItem.cpp",
- "ChatList/ChatListRecentItem.cpp",
- "ChatList/ChatListWhiteboardItem.cpp",
- "MUCSearch/MUCSearchDelegate.cpp",
- "MUCSearch/MUCSearchEmptyItem.cpp",
- "MUCSearch/MUCSearchModel.cpp",
- "MUCSearch/MUCSearchRoomItem.cpp",
- "MUCSearch/MUCSearchServiceItem.cpp",
- "MUCSearch/QtLeafSortFilterProxyModel.cpp",
- "MUCSearch/QtMUCSearchWindow.cpp",
+ "SystemMessageSnippet.cpp",
+ "Trellis/QtDNDTabBar.cpp",
+ "Trellis/QtDynamicGridLayout.cpp",
+ "Trellis/QtGridSelectionDialog.cpp",
"UserSearch/ContactListDelegate.cpp",
"UserSearch/ContactListModel.cpp",
"UserSearch/QtContactListWidget.cpp",
"UserSearch/QtSuggestingJIDInput.cpp",
- "UserSearch/QtUserSearchFirstPage.cpp",
- "UserSearch/QtUserSearchFirstMultiJIDPage.cpp",
+ "UserSearch/QtUserSearchDetailsPage.cpp",
"UserSearch/QtUserSearchFieldsPage.cpp",
+ "UserSearch/QtUserSearchFirstMultiJIDPage.cpp",
+ "UserSearch/QtUserSearchFirstPage.cpp",
"UserSearch/QtUserSearchResultsPage.cpp",
- "UserSearch/QtUserSearchDetailsPage.cpp",
"UserSearch/QtUserSearchWindow.cpp",
- "UserSearch/UserSearchModel.cpp",
"UserSearch/UserSearchDelegate.cpp",
+ "UserSearch/UserSearchModel.cpp",
+ "Whiteboard/ColorWidget.cpp",
"Whiteboard/FreehandLineItem.cpp",
"Whiteboard/GView.cpp",
- "Whiteboard/TextDialog.cpp",
"Whiteboard/QtWhiteboardWindow.cpp",
- "Whiteboard/ColorWidget.cpp",
- "QtSubscriptionRequestWindow.cpp",
- "QtRosterHeader.cpp",
- "QtWebView.cpp",
- "qrc_DefaultTheme.cc",
- "qrc_Swift.cc",
- "QtChatWindowJSBridge.cpp",
- "QtMUCConfigurationWindow.cpp",
- "QtAffiliationEditor.cpp",
- "QtUISettingConstants.cpp",
- "QtURLValidator.cpp",
- "QtResourceHelper.cpp",
- "QtSpellCheckHighlighter.cpp",
- "QtUpdateFeedSelectionDialog.cpp",
- "Trellis/QtDynamicGridLayout.cpp",
- "Trellis/QtDNDTabBar.cpp",
- "Trellis/QtGridSelectionDialog.cpp",
- "QtCheckBoxStyledItemDelegate.cpp",
- "QtColorSelectionStyledItemDelegate.cpp",
- "QtSoundSelectionStyledItemDelegate.cpp"
+ "Whiteboard/TextDialog.cpp"
]
if env["PLATFORM"] == "win32" :
@@ -478,9 +492,16 @@ if env["PLATFORM"] == "win32" :
outfile.close()
infile.close()
copying = env.Command(["Swift/COPYING.rtf"], ["COPYING"], convertToRTF)
+ if env.get("vcredistdir", "") :
+ vcredistdir = os.path.dirname(env["vcredistdir"])
+ else:
+ vcredistdir = os.path.dirname(env["vcredist"])+"\\..\\" + ("x86" if env["win_target_arch"] == "x86" else "x64") + "\\Microsoft.VC"+env.get("MSVC_VERSION", "").replace(".","")[:3]+".CRT\\"
wixvariables = {
'VCCRTFile': env["vcredist"],
- 'Version': str(myenv["SWIFT_VERSION_MAJOR"]) + "." + str(myenv["SWIFT_VERSION_MINOR"]) + "." + str(myenv["SWIFT_VERSION_PATCH"])
+ 'VCCRTPath': vcredistdir,
+ 'Version': str(myenv["SWIFT_VERSION_MAJOR"]) + "." + str(myenv["SWIFT_VERSION_MINOR"]) + "." + str(myenv["SWIFT_VERSION_PATCH"]),
+ 'MsvcVersion': str(env.get("MSVC_VERSION", "").replace(".","")[:3]),
+ 'MsvcDotVersion': str(env.get("MSVC_VERSION", "")[:4])
}
wixincludecontent = "<Include>"
for key in wixvariables:
@@ -496,16 +517,16 @@ if env["PLATFORM"] == "win32" :
def signToolAction(target = None, source = None, env = None):
signresult = 0
for x in range (1, 4) :
- print "Attemping to sign the packages [%s]" % x
+ print("Attemping to sign the packages [%s]" % x)
signresult = env.Execute('signtool.exe sign /fd SHA256 /f "${SIGNTOOL_KEY_PFX}" /t "${SIGNTOOL_TIMESTAMP_URL}" /d "Swift Installer" ' + str(target[0]))
if signresult != 1 :
break
#If all 3 attemps to sign the package failed, stop the build.
if signresult == 1 :
- print "Error: The build has failed to sign the installer package"
+ print("Error: The build has failed to sign the installer package")
Exit(1)
if signresult == 2 :
- print "Signing was completed with warnings."
+ print("Signing was completed with warnings.")
myenv.AddPostAction(lightTask, signToolAction)
diff --git a/Swift/QtUI/ServerList/QtServerListView.cpp b/Swift/QtUI/ServerList/QtServerListView.cpp
new file mode 100644
index 0000000..c22680f
--- /dev/null
+++ b/Swift/QtUI/ServerList/QtServerListView.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/QtUI/ServerList/QtServerListView.h>
+
+namespace Swift {
+
+QtServerListView::QtServerListView() {
+ QPalette newPalette = palette();
+ //TODO move color and theme variables to a shared location.
+ newPalette.setColor(QPalette::Base, { 38, 81, 112 });
+ setAutoFillBackground(true);
+ setPalette(newPalette);
+ delegate_ = std::make_unique<ServerListDelegate>();
+ setItemDelegate(delegate_.get());
+ setMaximumWidth(widgetWidth);
+ setMinimumWidth(widgetWidth);
+ setFrameStyle(QFrame::NoFrame);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setSelectionMode(QAbstractItemView::NoSelection);
+}
+
+QtServerListView::~QtServerListView() {
+
+}
+
+}
diff --git a/Swift/QtUI/ServerList/QtServerListView.h b/Swift/QtUI/ServerList/QtServerListView.h
new file mode 100644
index 0000000..bd625aa
--- /dev/null
+++ b/Swift/QtUI/ServerList/QtServerListView.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <QListView>
+
+#include <Swift/QtUI/ServerList/ServerListDelegate.h>
+
+namespace Swift {
+ class QtServerListView : public QListView {
+ Q_OBJECT
+ public:
+ QtServerListView();
+ virtual ~QtServerListView();
+ private:
+ std::unique_ptr<ServerListDelegate> delegate_;
+ static const int widgetWidth = 82;
+ };
+}
diff --git a/Swift/QtUI/ServerList/ServerListDelegate.cpp b/Swift/QtUI/ServerList/ServerListDelegate.cpp
new file mode 100644
index 0000000..2afb4ea
--- /dev/null
+++ b/Swift/QtUI/ServerList/ServerListDelegate.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/QtUI/ServerList/ServerListDelegate.h>
+
+#include <QApplication>
+#include <QBitmap>
+#include <QBrush>
+#include <QColor>
+#include <QDebug>
+#include <QFileInfo>
+#include <QFontMetrics>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPen>
+#include <QPolygon>
+
+#include <Swift/QtUI/QtScaledAvatarCache.h>
+#include <Swift/QtUI/ServerList/ServerListModel.h>
+
+namespace Swift {
+
+ServerListDelegate::ServerListDelegate() {
+
+}
+
+ServerListDelegate::~ServerListDelegate() {
+
+}
+
+void ServerListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
+ QColor bgColor(38, 81, 112);
+ painter->fillRect(option.rect, bgColor);
+ SwiftAccountData::SwiftAccountDataItem* item = static_cast<SwiftAccountData::SwiftAccountDataItem*>(index.internalPointer());
+ paintServerAvatar(painter, option, item->iconPath_, item->status_, false, item->unreadCount_);
+}
+
+QSize ServerListDelegate::sizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const {
+ //TODO Make this configurable.
+ return QSize(75, 75);
+}
+
+void ServerListDelegate::paintServerAvatar(QPainter* painter, const QStyleOptionViewItem& option, const QString& avatarPath, const StatusShow& /*serverPresence*/, bool isIdle, size_t unreadCount) const {
+ painter->save();
+ QRect fullRegion(option.rect);
+ if (option.state & QStyle::State_Selected) {
+ painter->fillRect(fullRegion, option.palette.highlight());
+ painter->setPen(option.palette.highlightedText().color());
+ }
+ auto secondLineColor = painter->pen().color();
+ secondLineColor.setAlphaF(0.7);
+
+ QRect presenceRegion(QPoint(common_.farLeftMargin, fullRegion.top() + common_.horizontalMargin), QSize(presenceIconWidth, presenceIconHeight));
+ QRect idleIconRegion(QPoint(common_.farLeftMargin, fullRegion.top()), QSize(presenceIconWidth * 2, presenceIconHeight - common_.verticalMargin));
+ int calculatedAvatarSize = fullRegion.height() - common_.verticalMargin;
+ //This overlaps the presenceIcon, so must be painted first
+ QRect avatarRegion(QPoint(presenceRegion.right() - common_.presenceIconWidth / 2, presenceRegion.top()), QSize(calculatedAvatarSize, calculatedAvatarSize));
+
+ QPixmap avatarPixmap;
+ if (!avatarPath.isEmpty()) {
+ QString scaledAvatarPath = QtScaledAvatarCache(avatarRegion.height()).getScaledAvatarPath(avatarPath);
+ if (QFileInfo(scaledAvatarPath).exists()) {
+ avatarPixmap.load(scaledAvatarPath);
+ }
+ }
+ if (avatarPixmap.isNull()) {
+ avatarPixmap = QPixmap(":/icons/avatar.svg").scaled(avatarRegion.height(), avatarRegion.width(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ }
+ painter->drawPixmap(avatarRegion.topLeft() + QPoint(((avatarRegion.width() - avatarPixmap.width()) / 2), (avatarRegion.height() - avatarPixmap.height()) / 2), avatarPixmap);
+ //Paint the presence status over the top of the avatar
+ //FIXME enable drawing status when ServerPresence data are available.
+ /*{
+ //TODO make the colors consistent with chattables work from QtChatOverviewDelegate::paint, copying for now
+ const auto green = QColor(124, 243, 145);
+ const auto yellow = QColor(243, 243, 0);
+ const auto red = QColor(255, 45, 71);
+ const auto grey = QColor(159, 159, 159);
+ QColor color = grey;
+ switch (serverPresence.getType()) {
+ case StatusShow::Online: color = green; break;
+ case StatusShow::FFC: color = green; break;
+ case StatusShow::Away: color = yellow; break;
+ case StatusShow::XA: color = yellow; break;
+ case StatusShow::DND: color = red; break;
+ case StatusShow::None: color = grey; break;
+ }
+ QPen pen(color);
+ pen.setWidth(1);
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setPen(pen);
+ painter->setBrush(QBrush(color, Qt::SolidPattern));
+ painter->drawEllipse(presenceRegion);
+ }*/
+
+ if (isIdle) {
+ common_.idleIcon.paint(painter, idleIconRegion, Qt::AlignBottom | Qt::AlignHCenter);
+ }
+
+ if (unreadCount > 0) {
+ QRect unreadRect(avatarRegion.right() - common_.unreadCountSize - common_.horizontalMargin, avatarRegion.top(), common_.unreadCountSize, common_.unreadCountSize);
+ QPen pen(QColor("black"));
+ pen.setWidth(1);
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setPen(pen);
+ painter->setBrush(QBrush(QColor("red"), Qt::SolidPattern));
+ painter->drawEllipse(unreadRect);
+ painter->setBackgroundMode(Qt::TransparentMode);
+ painter->setPen(QColor("white"));
+ common_.drawElidedText(painter, unreadRect, QString("%1").arg(unreadCount), Qt::AlignCenter);
+ }
+ painter->restore();
+}
+
+}
diff --git a/Swift/QtUI/ServerList/ServerListDelegate.h b/Swift/QtUI/ServerList/ServerListDelegate.h
new file mode 100644
index 0000000..3f8b72b
--- /dev/null
+++ b/Swift/QtUI/ServerList/ServerListDelegate.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <QStyledItemDelegate>
+
+#include <Swiften/Elements/StatusShow.h>
+
+#include <Swift/QtUI/Roster/DelegateCommons.h>
+
+namespace Swift {
+
+ class ServerListDelegate : public QStyledItemDelegate {
+ public:
+ ServerListDelegate();
+ ~ServerListDelegate() override;
+ QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
+ void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
+ private:
+ void paintServerAvatar(QPainter* painter, const QStyleOptionViewItem& option, const QString& avatarPath, const StatusShow& presence, bool isIdle, size_t unreadCount) const;
+ private:
+ DelegateCommons common_;
+ static const int presenceIconHeight = 12;
+ static const int presenceIconWidth = 12;
+ };
+
+}
diff --git a/Swift/QtUI/ServerList/ServerListModel.cpp b/Swift/QtUI/ServerList/ServerListModel.cpp
new file mode 100644
index 0000000..e5dc35e
--- /dev/null
+++ b/Swift/QtUI/ServerList/ServerListModel.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+//#include <Swift/QtUI/ServerList/ServerListModel.h>
+#include <QBrush>
+#include <QColor>
+#include <QMimeData>
+
+#include "ServerListModel.h"
+
+namespace Swift {
+
+ServerListModel::ServerListModel() {
+}
+
+ServerListModel::~ServerListModel() {
+}
+
+QVariant ServerListModel::data(const QModelIndex& index, int role) const {
+ if (!index.isValid()) {
+ return QVariant();
+ }
+ SwiftAccountData::SwiftAccountDataItem* item = static_cast<SwiftAccountData::SwiftAccountDataItem*>(index.internalPointer());
+ switch (role) {
+ case Qt::DisplayRole: return QString(item->userJID_.toBare().toString().c_str());
+ case Qt::BackgroundRole: return QBrush(Qt::transparent);
+ case Qt::ToolTipRole: return QString(item->userJID_.toBare().toString().c_str());
+ default: return QVariant();
+ }
+}
+
+QModelIndex ServerListModel::index(int row, int column, const QModelIndex& /*parent*/) const {
+ if (!modelData_ || static_cast<size_t>(row) >= modelData_->size()) {
+ return QModelIndex();
+ }
+ return createIndex(row, column, modelData_->getAccount(row));
+}
+
+QModelIndex ServerListModel::parent(const QModelIndex& /*index*/) const {
+ return QModelIndex();
+}
+
+QMimeData* ServerListModel::mimeData(const QModelIndexList& indexes) const {
+ return QAbstractItemModel::mimeData(indexes);
+}
+
+int ServerListModel::rowCount(const QModelIndex& /*parent*/) const {
+ if (!modelData_) {
+ return 0;
+ }
+ return modelData_->size();
+}
+
+int ServerListModel::columnCount(const QModelIndex& /*parent*/) const {
+ if (!modelData_) {
+ return 0;
+ }
+ return 1;
+}
+
+void ServerListModel::handleDataChanged() {
+ emit layoutChanged();
+}
+
+}
diff --git a/Swift/QtUI/ServerList/ServerListModel.h b/Swift/QtUI/ServerList/ServerListModel.h
new file mode 100644
index 0000000..ae89ade
--- /dev/null
+++ b/Swift/QtUI/ServerList/ServerListModel.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/signals2.hpp>
+
+#include <QAbstractItemModel>
+
+#include <Swiften/Elements/StatusShow.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+
+ class SwiftAccountData {
+ public:
+ struct SwiftAccountDataItem {
+ SwiftAccountDataItem(std::string serverID) : serverID_(serverID) {}
+ //FIXME eliminate serverID_, the userJID_ will be the ID when we connect with the actual data.
+ std::string serverID_;
+ QString iconPath_;
+ JID userJID_;
+ size_t unreadCount_ = 0;
+ StatusShow status_ = StatusShow::None;
+ boost::signals2::scoped_connection dataChangedConnection_;
+ boost::signals2::signal<void ()> onDataChanged;
+ void handleChangeStatusRequest(StatusShow::Type show, const std::string& /*statusText*/) {
+ status_ = show;
+ onDataChanged();
+ }
+ };
+ public:
+ SwiftAccountData() {}
+ ~SwiftAccountData() {
+ for (auto account : accounts_) {
+ delete account;
+ }
+ }
+ //FIXME make addAccount with SwiftAccountDataItem, and added after a succesfull connection to the server has been established.
+ void addAccount(JID userJID) {
+ SwiftAccountDataItem* newItem = new SwiftAccountDataItem(userJID);
+ newItem->dataChangedConnection_ = newItem->onDataChanged.connect(boost::bind(&SwiftAccountData::handleDataChanged, this));
+ accounts_.push_back(newItem);
+ }
+ SwiftAccountDataItem* getAccount(int index) {
+ if (index >= accounts_.size()) {
+ return nullptr;
+ }
+ return accounts_[index];
+ }
+ size_t size() {
+ return accounts_.size();
+ }
+ public:
+ boost::signals2::signal<void()> onDataChanged;
+ private:
+ void handleDataChanged() {
+ onDataChanged();
+ }
+ private:
+ QList<SwiftAccountDataItem*> accounts_;
+ };
+
+ class ServerListModel : public QAbstractItemModel {
+ Q_OBJECT
+ public:
+ ServerListModel();
+ ~ServerListModel() override;
+
+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
+ QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex& index) const override;
+
+ QMimeData* mimeData(const QModelIndexList& indexes) const override;
+
+ virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
+ virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
+
+ void setModelData(SwiftAccountData* data) { modelData_ = data; }
+ void handleDataChanged();
+ private:
+ SwiftAccountData* modelData_;
+ };
+}
diff --git a/Swift/QtUI/Trellis/QtDynamicGridLayout.cpp b/Swift/QtUI/Trellis/QtDynamicGridLayout.cpp
index 2509b3f..2402529 100644
--- a/Swift/QtUI/Trellis/QtDynamicGridLayout.cpp
+++ b/Swift/QtUI/Trellis/QtDynamicGridLayout.cpp
@@ -23,7 +23,7 @@
namespace Swift {
-QtDynamicGridLayout::QtDynamicGridLayout(QWidget* parent, bool enableDND) : QWidget(parent), dndEnabled_(enableDND), movingTab_(nullptr) {
+QtDynamicGridLayout::QtDynamicGridLayout(bool future, QWidget* parent, bool enableDND) : QWidget(parent), dndEnabled_(enableDND), movingTab_(nullptr), future_(future) {
gridLayout_ = new QGridLayout(this);
setContentsMargins(0,0,0,0);
setDimensions(QSize(1,1));
@@ -49,6 +49,9 @@ int QtDynamicGridLayout::addTab(QtTabbable* tab, const QString& title) {
tabWidget->addTab(tab, title);
}
tab->setEmphasiseFocus(getDimension().width() > 1 || getDimension().height() > 1);
+ if (future_) {
+ showHideFirstTabs(); // FIXME: Putting it here as a workaround until I work out why it doesn't work initially
+ }
return tabWidget ? indexOf(tab) : -1;
}
@@ -328,6 +331,24 @@ void QtDynamicGridLayout::setDimensions(const QSize& dim) {
setCurrentWidget(restoredWidget);
updateEmphasiseFocusOnTabs();
+
+ if (future_) {
+ showHideFirstTabs();
+ }
+}
+
+void QtDynamicGridLayout::showHideFirstTabs() {
+ int tmp;
+ auto firstTabs = indexToTabWidget(0, tmp);
+
+ if (firstTabs) {
+ if (gridLayout_->columnCount() == 1 && gridLayout_->rowCount() == 1) {
+ firstTabs->tabBar()->hide();
+ }
+ else {
+ firstTabs->tabBar()->show();
+ }
+ }
}
void QtDynamicGridLayout::updateEmphasiseFocusOnTabs() {
diff --git a/Swift/QtUI/Trellis/QtDynamicGridLayout.h b/Swift/QtUI/Trellis/QtDynamicGridLayout.h
index 682ae41..f3a2e96 100644
--- a/Swift/QtUI/Trellis/QtDynamicGridLayout.h
+++ b/Swift/QtUI/Trellis/QtDynamicGridLayout.h
@@ -20,7 +20,7 @@ namespace Swift {
class QtDynamicGridLayout : public QWidget {
Q_OBJECT
public:
- explicit QtDynamicGridLayout(QWidget* parent = nullptr, bool enableDND = false);
+ explicit QtDynamicGridLayout(bool future, QWidget* parent = nullptr, bool enableDND = false);
virtual ~QtDynamicGridLayout();
QSize getDimension() const;
@@ -71,6 +71,7 @@ namespace Swift {
void moveTab(QtTabWidget* tabWidget, int oldIndex, int newIndex);
QtTabWidget* createDNDTabWidget(QWidget* parent);
void updateEmphasiseFocusOnTabs();
+ void showHideFirstTabs();
private:
QGridLayout *gridLayout_;
@@ -78,5 +79,6 @@ namespace Swift {
QHash<QString, QPoint> tabPositions_;
QtTabbable* movingTab_;
bool resizing_ = false;
+ bool future_ = false;
};
}
diff --git a/Swift/QtUI/Trellis/QtGridSelectionDialog.cpp b/Swift/QtUI/Trellis/QtGridSelectionDialog.cpp
index 0533edf..e922e07 100644
--- a/Swift/QtUI/Trellis/QtGridSelectionDialog.cpp
+++ b/Swift/QtUI/Trellis/QtGridSelectionDialog.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016 Isode Limited.
+ * Copyright (c) 2014-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -76,7 +76,7 @@ int QtGridSelectionDialog::getDescriptionTextHeight() const {
int QtGridSelectionDialog::getDescriptionTextHeight(int width) const {
// Height of descriptive centered text below trellis
auto fontMetrics = QFontMetrics(QApplication::font());
- auto descriptionBB = fontMetrics.boundingRect(QRect(0, 0, width - 2 * horizontalMargin, 1000), Qt::TextWordWrap, descriptionText, 0, 0);
+ auto descriptionBB = fontMetrics.boundingRect(QRect(0, 0, width - 2 * horizontalMargin, 1000), Qt::TextWordWrap, descriptionText, 0, nullptr);
return (descriptionBB.height() + descriptionBB.y());
}
@@ -136,7 +136,7 @@ void QtGridSelectionDialog::paintEvent(QPaintEvent*) {
// draw description text
auto fontMetrics = QFontMetrics(QApplication::font());
- auto descriptionBB = fontMetrics.boundingRect(QRect(0,0, width() - 2 * horizontalMargin,0), Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap, descriptionText, 0, 0);
+ auto descriptionBB = fontMetrics.boundingRect(QRect(0,0, width() - 2 * horizontalMargin,0), Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap, descriptionText, 0, nullptr);
QStyleOption opt;
opt.initFrom(this);
diff --git a/Swift/QtUI/UserSearch/ContactListModel.cpp b/Swift/QtUI/UserSearch/ContactListModel.cpp
index 6ef85d7..5d8aa6c 100644
--- a/Swift/QtUI/UserSearch/ContactListModel.cpp
+++ b/Swift/QtUI/UserSearch/ContactListModel.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (c) 2014-2016 Isode Limited.
+ * Copyright (c) 2014-2018 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -22,32 +22,6 @@
namespace Swift {
-QDataStream& operator >>(QDataStream& in, StatusShow::Type& e){
- quint32 buffer;
- in >> buffer;
- switch(buffer) {
- case StatusShow::Online:
- e = StatusShow::Online;
- break;
- case StatusShow::Away:
- e = StatusShow::Away;
- break;
- case StatusShow::FFC:
- e = StatusShow::FFC;
- break;
- case StatusShow::XA:
- e = StatusShow::XA;
- break;
- case StatusShow::DND:
- e = StatusShow::DND;
- break;
- default:
- e = StatusShow::None;
- break;
- }
- return in;
-}
-
ContactListModel::ContactListModel(bool editable) : QAbstractItemModel(), editable_(editable) {
}
diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.h b/Swift/QtUI/UserSearch/QtUserSearchWindow.h
index fe536ab..f67712e 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchWindow.h
+++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.h
@@ -11,8 +11,6 @@
#include <QAbstractItemModel>
#include <QWizard>
-#include <Swiften/Base/Override.h>
-
#include <Swift/Controllers/UIInterfaces/UserSearchWindow.h>
#include <Swift/QtUI/UserSearch/ui_QtUserSearchWizard.h>
@@ -34,34 +32,34 @@ namespace Swift {
Q_OBJECT
public:
QtUserSearchWindow(UIEventStream* eventStream, UserSearchWindow::Type type, const std::set<std::string>& groups, SettingsProvider* settingsProvider);
- virtual ~QtUserSearchWindow();
+ virtual ~QtUserSearchWindow() override;
- virtual void addSavedServices(const std::vector<JID>& services) SWIFTEN_OVERRIDE;
+ virtual void addSavedServices(const std::vector<JID>& services) override;
- virtual void clear() SWIFTEN_OVERRIDE;
- virtual void show() SWIFTEN_OVERRIDE;
- virtual void setResults(const std::vector<UserSearchResult>& results) SWIFTEN_OVERRIDE;
- virtual void setResultsForm(Form::ref results) SWIFTEN_OVERRIDE;
- virtual void setSelectedService(const JID& jid) SWIFTEN_OVERRIDE;
- virtual void setServerSupportsSearch(bool error) SWIFTEN_OVERRIDE;
- virtual void setSearchError(bool error) SWIFTEN_OVERRIDE;
- virtual void setSearchFields(std::shared_ptr<SearchPayload> fields) SWIFTEN_OVERRIDE;
- virtual void setNameSuggestions(const std::vector<std::string>& suggestions) SWIFTEN_OVERRIDE;
- virtual void prepopulateJIDAndName(const JID& jid, const std::string& name) SWIFTEN_OVERRIDE;
- virtual void setContactSuggestions(const std::vector<Contact::ref>& suggestions) SWIFTEN_OVERRIDE;
- virtual void setJIDs(const std::vector<JID> &jids) SWIFTEN_OVERRIDE;
- virtual void setOriginator(const JID& originator) SWIFTEN_OVERRIDE;
- virtual void setRoomJID(const JID &roomJID) SWIFTEN_OVERRIDE;
- virtual std::string getReason() const SWIFTEN_OVERRIDE;
- virtual std::vector<JID> getJIDs() const SWIFTEN_OVERRIDE;
- virtual void setCanStartImpromptuChats(bool supportsImpromptu) SWIFTEN_OVERRIDE;
- virtual void updateContacts(const std::vector<Contact::ref> &contacts) SWIFTEN_OVERRIDE;
- virtual void addContacts(const std::vector<Contact::ref>& contacts) SWIFTEN_OVERRIDE;
- virtual void setCanSupplyDescription(bool allowed) SWIFTEN_OVERRIDE;
- virtual void setWarning(const boost::optional<std::string>& message) SWIFTEN_OVERRIDE;
+ virtual void clear() override;
+ virtual void show() override;
+ virtual void setResults(const std::vector<UserSearchResult>& results) override;
+ virtual void setResultsForm(Form::ref results) override;
+ virtual void setSelectedService(const JID& jid) override;
+ virtual void setServerSupportsSearch(bool error) override;
+ virtual void setSearchError(bool error) override;
+ virtual void setSearchFields(std::shared_ptr<SearchPayload> fields) override;
+ virtual void setNameSuggestions(const std::vector<std::string>& suggestions) override;
+ virtual void prepopulateJIDAndName(const JID& jid, const std::string& name) override;
+ virtual void setContactSuggestions(const std::vector<Contact::ref>& suggestions) override;
+ virtual void setJIDs(const std::vector<JID> &jids) override;
+ virtual void setOriginator(const JID& originator) override;
+ virtual void setRoomJID(const JID &roomJID) override;
+ virtual std::string getReason() const override;
+ virtual std::vector<JID> getJIDs() const override;
+ virtual void setCanStartImpromptuChats(bool supportsImpromptu) override;
+ virtual void updateContacts(const std::vector<Contact::ref> &contacts) override;
+ virtual void addContacts(const std::vector<Contact::ref>& contacts) override;
+ virtual void setCanSupplyDescription(bool allowed) override;
+ virtual void setWarning(const boost::optional<std::string>& message) override;
protected:
- virtual int nextId() const SWIFTEN_OVERRIDE;
+ virtual int nextId() const override;
private slots:
void handleFirstPageRadioChange();