summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/QtUI/QtChatWindow.cpp12
-rw-r--r--Swift/QtUI/QtChatWindow.h4
-rw-r--r--Swift/QtUI/QtChatWindowFactory.cpp4
-rw-r--r--Swift/QtUI/QtChatWindowFactory.h6
-rw-r--r--Swift/QtUI/QtEmojiCell.cpp15
-rw-r--r--Swift/QtUI/QtEmojiCell.h7
-rw-r--r--Swift/QtUI/QtEmojisGrid.cpp6
-rw-r--r--Swift/QtUI/QtEmojisGrid.h1
-rw-r--r--Swift/QtUI/QtEmojisScroll.cpp6
-rw-r--r--Swift/QtUI/QtEmojisSelector.cpp24
-rw-r--r--Swift/QtUI/QtEmojisSelector.h8
-rw-r--r--Swift/QtUI/QtEmoticonsGrid.cpp40
-rw-r--r--Swift/QtUI/QtEmoticonsGrid.h23
-rw-r--r--Swift/QtUI/QtSwift.cpp2
-rw-r--r--Swift/QtUI/SConscript1
15 files changed, 147 insertions, 12 deletions
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 345139c..f57b83f 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -1,97 +1,100 @@
/*
* Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/QtUI/QtChatWindow.h>
+#include <map>
#include <memory>
+#include <string>
#include <boost/cstdint.hpp>
#include <boost/lexical_cast.hpp>
#include <QApplication>
#include <QBoxLayout>
#include <QCloseEvent>
#include <QComboBox>
#include <QCursor>
#include <QDebug>
#include <QFileDialog>
#include <QFileInfo>
#include <QFontMetrics>
#include <QInputDialog>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QMessageBox>
#include <QMimeData>
#include <QPoint>
#include <QPushButton>
#include <QSize>
#include <QSplitter>
#include <QString>
#include <QTextDocument>
#include <QTextEdit>
#include <QTime>
#include <QToolButton>
#include <QUrl>
#include <Swiften/Base/Log.h>
+#include <Swiften/Base/Platform.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swift/Controllers/Roster/Roster.h>
#include <Swift/Controllers/Roster/RosterItem.h>
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <SwifTools/EmojiMapper.h>
#include <SwifTools/TabComplete.h>
#include <Swift/QtUI/QtAddBookmarkWindow.h>
#include <Swift/QtUI/QtEditBookmarkWindow.h>
#include <Swift/QtUI/QtEmojisSelector.h>
#include <Swift/QtUI/QtPlainChatView.h>
#include <Swift/QtUI/QtScaledAvatarCache.h>
#include <Swift/QtUI/QtSettingsProvider.h>
#include <Swift/QtUI/QtTextEdit.h>
#include <Swift/QtUI/QtUISettingConstants.h>
#include <Swift/QtUI/QtUtilities.h>
#include <Swift/QtUI/QtWebKitChatView.h>
#include <Swift/QtUI/Roster/QtOccupantListWidget.h>
namespace Swift {
-QtChatWindow::QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings, QtSettingsProvider* qtOnlySettings) : QtTabbable(), id_(Q2PSTRING(contact)), contact_(contact), nextAlertId_(0), eventStream_(eventStream), settings_(settings), qtOnlySettings_(qtOnlySettings), blockingState_(BlockingUnsupported), isMUC_(false), supportsImpromptuChat_(false), roomBookmarkState_(RoomNotBookmarked) {
+QtChatWindow::QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings, QtSettingsProvider* qtOnlySettings, const std::map<std::string, std::string>& emoticonsMap) : QtTabbable(), id_(Q2PSTRING(contact)), contact_(contact), nextAlertId_(0), eventStream_(eventStream), settings_(settings), qtOnlySettings_(qtOnlySettings), blockingState_(BlockingUnsupported), isMUC_(false), supportsImpromptuChat_(false), roomBookmarkState_(RoomNotBookmarked), emoticonsMap_(emoticonsMap) {
unreadCount_ = 0;
isOnline_ = true;
completer_ = nullptr;
affiliationEditor_ = nullptr;
theme_ = theme;
isCorrection_ = false;
labelModel_ = nullptr;
correctionEnabled_ = Maybe;
fileTransferEnabled_ = Maybe;
updateTitleWithUnreadCount();
assert(settings);
setAcceptDrops(true);
alertStyleSheet_ = ".QWidget, QTextEdit { background: rgb(255, 255, 153); color: black }";
QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
layout->setContentsMargins(0,0,0,0);
layout->setSpacing(2);
alertLayout_ = new QVBoxLayout();
layout->addLayout(alertLayout_);
subjectLayout_ = new QBoxLayout(QBoxLayout::LeftToRight);
subject_ = new QLineEdit(this);
subjectLayout_->addWidget(subject_);
setSubject("");
subject_->setReadOnly(true);
QPushButton* actionButton_ = new QPushButton(this);
actionButton_->setIcon(QIcon(":/icons/actions.png"));
@@ -120,61 +123,66 @@ QtChatWindow::QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventSt
midBar_ = new QWidget(this);
//layout->addWidget(midBar);
midBar_->setAutoFillBackground(true);
QHBoxLayout *midBarLayout = new QHBoxLayout(midBar_);
midBarLayout->setContentsMargins(0,0,0,0);
midBarLayout->setSpacing(2);
//midBarLayout->addStretch();
labelsWidget_ = new QComboBox(this);
labelsWidget_->setFocusPolicy(Qt::NoFocus);
labelsWidget_->hide();
labelsWidget_->setSizeAdjustPolicy(QComboBox::AdjustToContents);
midBarLayout->addWidget(labelsWidget_,0);
connect(labelsWidget_, SIGNAL(currentIndexChanged(int)), this, SLOT(handleCurrentLabelChanged(int)));
defaultLabelsPalette_ = labelsWidget_->palette();
QHBoxLayout* inputBarLayout = new QHBoxLayout();
inputBarLayout->setContentsMargins(0,0,0,0);
inputBarLayout->setSpacing(2);
input_ = new QtTextEdit(settings_, this);
input_->setAcceptRichText(false);
inputBarLayout->addWidget(midBar_);
inputBarLayout->addWidget(input_);
correctingLabel_ = new QLabel(tr("Correcting"), this);
inputBarLayout->addWidget(correctingLabel_);
correctingLabel_->hide();
connect(input_, SIGNAL(receivedFocus()), this, SLOT(handleTextInputReceivedFocus()));
connect(input_, SIGNAL(lostFocus()), this, SLOT(handleTextInputLostFocus()));
QPushButton* emojisButton_ = new QPushButton(this);
+
+#ifdef SWIFTEN_PLATFORM_MACOSX
emojisButton_->setText("\xF0\x9F\x98\x83");
+#else
+ emojisButton_->setIcon(QIcon(":/emoticons/smile.png"));
+#endif
connect(emojisButton_, SIGNAL(clicked()), this, SLOT(handleEmojisButtonClicked()));
// using an extra layout to work around Qt margin glitches on OS X
QHBoxLayout* actionLayout = new QHBoxLayout();
actionLayout->addWidget(emojisButton_);
actionLayout->addWidget(actionButton_);
inputBarLayout->addLayout(actionLayout);
layout->addLayout(inputBarLayout);
inputClearing_ = false;
contactIsTyping_ = false;
tabCompletion_ = false;
connect(input_, SIGNAL(unhandledKeyPressEvent(QKeyEvent*)), this, SLOT(handleKeyPressEvent(QKeyEvent*)));
connect(input_, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
connect(input_, SIGNAL(textChanged()), this, SLOT(handleInputChanged()));
connect(input_, SIGNAL(cursorPositionChanged()), this, SLOT(handleCursorPositionChanged()));
setFocusProxy(input_);
logRosterSplitter_->setFocusProxy(input_);
midBar_->setFocusProxy(input_);
messageLog_->setFocusProxy(input_);
connect(messageLog_, SIGNAL(gotFocus()), input_, SLOT(setFocus()));
resize(400,300);
connect(messageLog_, SIGNAL(fontResized(int)), this, SIGNAL(fontResized(int)));
connect(messageLog_, SIGNAL(logCleared()), this, SLOT(handleLogCleared()));
treeWidget_->onSomethingSelectedChanged.connect(boost::bind(&QtChatWindow::handleOccupantSelectionChanged, this, _1));
treeWidget_->onOccupantActionSelected.connect(boost::bind(boost::ref(onOccupantActionSelected), _1, _2));
@@ -635,61 +643,61 @@ void QtChatWindow::dropEvent(QDropEvent *event) {
else if (event->mimeData()->hasFormat("application/vnd.swift.contact-jid-list")) {
std::vector<JID> invites = jidListFromQByteArray(event->mimeData()->data("application/vnd.swift.contact-jid-list"));
onInviteToChat(invites);
}
}
std::vector<JID> QtChatWindow::jidListFromQByteArray(const QByteArray& dataBytes) {
QDataStream dataStream(dataBytes);
std::vector<JID> invites;
while (!dataStream.atEnd()) {
QString jidString;
dataStream >> jidString;
invites.push_back(Q2PSTRING(jidString));
}
return invites;
}
void QtChatWindow::setAvailableOccupantActions(const std::vector<OccupantAction>& actions) {
treeWidget_->setAvailableOccupantActions(actions);
}
void QtChatWindow::setSubject(const std::string& subject) {
//subject_->setVisible(!subject.empty());
subject_->setText(P2QSTRING(subject));
subject_->setToolTip(P2QSTRING(subject));
subject_->setCursorPosition(0);
}
void QtChatWindow::handleEmojisButtonClicked() {
// Create QtEmojisSelector and QMenu
- emojisGrid_ = new QtEmojisSelector(qtOnlySettings_->getQSettings());
+ emojisGrid_ = new QtEmojisSelector(qtOnlySettings_->getQSettings(), emoticonsMap_);
auto emojisLayout = new QVBoxLayout();
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_->setLayout(emojisLayout);
emojisMenu_->adjustSize();
connect(emojisGrid_, SIGNAL(emojiClicked(QString)), this, SLOT(handleEmojiClicked(QString)));
QSize menuSize = emojisMenu_->size();
emojisMenu_->exec(QPoint(QCursor::pos().x() - menuSize.width(), QCursor::pos().y() - menuSize.height()));
}
void QtChatWindow::handleEmojiClicked(QString emoji) {
if (isVisible()) {
input_->textCursor().insertText(emoji);
input_->setFocus();
// The next line also deletes the emojisGrid_, as it was added to the
// layout of the emojisMenu_.
emojisMenu_.reset();
}
}
void QtChatWindow::handleTextInputReceivedFocus() {
lastLineTracker_.setHasFocus(true);
input_->setFocus();
onAllMessagesRead();
}
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index 4c64c84..fca4aec 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -1,39 +1,40 @@
/*
* Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <map>
+#include <string>
#include <QMap>
#include <QMenu>
#include <QPointer>
#include <QString>
#include <QTextCursor>
#include <QVBoxLayout>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
#include <SwifTools/EmojiMapper.h>
#include <SwifTools/LastLineTracker.h>
#include <Swift/QtUI/ChatSnippet.h>
#include <Swift/QtUI/QtAffiliationEditor.h>
#include <Swift/QtUI/QtEmojisSelector.h>
#include <Swift/QtUI/QtMUCConfigurationWindow.h>
#include <Swift/QtUI/QtSwiftUtil.h>
#include <Swift/QtUI/QtTabbable.h>
class QTextEdit;
class QLineEdit;
class QComboBox;
class QLabel;
class QSplitter;
class QPushButton;
namespace Swift {
class QtChatView;
class QtOccupantListWidget;
@@ -54,61 +55,61 @@ namespace Swift {
return static_cast<int>(availableLabels_.size());
}
virtual QVariant data(const QModelIndex& index, int role) const {
if (!index.isValid()) {
return QVariant();
}
std::shared_ptr<SecurityLabel> label = availableLabels_[index.row()].getLabel();
if (label && role == Qt::TextColorRole) {
return P2QSTRING(label->getForegroundColor());
}
if (label && role == Qt::TextColorRole) {
return P2QSTRING(label->getBackgroundColor());
}
if (role == Qt::DisplayRole) {
std::string selector = availableLabels_[index.row()].getSelector();
std::string displayMarking = label ? label->getDisplayMarking() : "";
QString labelName = selector.empty() ? displayMarking.c_str() : selector.c_str();
return labelName;
}
return QVariant();
}
std::vector<SecurityLabelsCatalog::Item> availableLabels_;
};
class QtChatWindow : public QtTabbable, public ChatWindow {
Q_OBJECT
public:
- QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings, QtSettingsProvider* qtOnlySettings);
+ QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings, QtSettingsProvider* qtOnlySettings, const std::map<std::string, std::string>& emoticonsMap);
virtual ~QtChatWindow();
std::string addMessage(const ChatMessage& message, const std::string &senderName, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
std::string addAction(const ChatMessage& message, const std::string &senderName, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
std::string addSystemMessage(const ChatMessage& message, Direction direction);
void addPresenceMessage(const ChatMessage& message, Direction direction);
void addErrorMessage(const ChatMessage& message);
void replaceMessage(const ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time);
void replaceWithAction(const ChatMessage& message, const std::string& id, const boost::posix_time::ptime& time);
// File transfer related stuff
std::string addFileTransfer(const std::string& senderName, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes, const std::string& description);
void setFileTransferProgress(std::string id, const int percentageDone);
void setFileTransferStatus(std::string id, const FileTransferState state, const std::string& msg);
std::string addWhiteboardRequest(bool senderIsSelf);
void setWhiteboardSessionStatus(std::string id, const ChatWindow::WhiteboardSessionState state);
void show();
bool isVisible() const;
void activate();
void setUnreadMessageCount(int count);
void convertToMUC(MUCType mucType);
// TreeWidget *getTreeWidget();
void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels);
void setSecurityLabelsEnabled(bool enabled);
void setSecurityLabelsError();
SecurityLabelsCatalog::Item getSelectedSecurityLabel();
void setName(const std::string& name);
void setOnline(bool online);
@@ -209,32 +210,33 @@ namespace Swift {
QLabel* correctingLabel_;
boost::optional<AlertID> correctingAlert_;
QVBoxLayout* alertLayout_;
std::map<AlertID, QWidget*> alertWidgets_;
AlertID nextAlertId_;
TabComplete* completer_;
QLineEdit* subject_;
bool isCorrection_;
bool inputClearing_;
bool tabCompletion_;
UIEventStream* eventStream_;
bool isOnline_;
QSplitter *logRosterSplitter_;
Tristate correctionEnabled_;
Tristate fileTransferEnabled_;
QString alertStyleSheet_;
QPointer<QtMUCConfigurationWindow> mucConfigurationWindow_;
QPointer<QtAffiliationEditor> affiliationEditor_;
SettingsProvider* settings_ = nullptr;
QtSettingsProvider* qtOnlySettings_ = nullptr;
std::vector<ChatWindow::RoomAction> availableRoomActions_;
QPalette defaultLabelsPalette_;
LabelModel* labelModel_;
BlockingState blockingState_;
bool impromptu_;
bool isMUC_;
bool supportsImpromptuChat_;
RoomBookmarkState roomBookmarkState_;
std::unique_ptr<QMenu> emojisMenu_;
QPointer<QtEmojisSelector> emojisGrid_;
+ std::map<std::string, std::string> emoticonsMap_;
};
}
diff --git a/Swift/QtUI/QtChatWindowFactory.cpp b/Swift/QtUI/QtChatWindowFactory.cpp
index 5a4a501..49cfe4d 100644
--- a/Swift/QtUI/QtChatWindowFactory.cpp
+++ b/Swift/QtUI/QtChatWindowFactory.cpp
@@ -1,87 +1,87 @@
/*
* Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/QtUI/QtChatWindowFactory.h>
#include <QDesktopWidget>
#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>
#include <Swift/QtUI/QtSingleWindow.h>
#include <Swift/QtUI/QtSwiftUtil.h>
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) : themePath_(themePath) {
+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) {
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()));
}
}
QtChatWindowFactory::~QtChatWindowFactory() {
delete theme_;
}
ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStream* eventStream) {
if (!theme_) {
theme_ = new QtChatTheme(themePath_);
if (theme_->getIncomingContent().isEmpty()) {
delete theme_;
theme_ = new QtChatTheme(":/themes/Default/"); /* Use the inbuilt theme */
}
}
- QtChatWindow* chatWindow = new QtChatWindow(P2QSTRING(contact.toString()), theme_, eventStream, settings_, qtOnlySettings_);
+ QtChatWindow* chatWindow = new QtChatWindow(P2QSTRING(contact.toString()), theme_, eventStream, settings_, qtOnlySettings_, emoticonsMap_);
connect(chatWindow, SIGNAL(splitterMoved()), this, SLOT(handleSplitterMoved()));
connect(this, SIGNAL(changeSplitterState(QByteArray)), chatWindow, SLOT(handleChangeSplitterState(QByteArray)));
QVariant splitterState = qtOnlySettings_->getQSettings()->value(SPLITTER_STATE);
if(splitterState.isValid()) {
chatWindow->handleChangeSplitterState(splitterState.toByteArray());
}
if (tabs_) {
tabs_->addTab(chatWindow);
} else {
QVariant chatGeometryVariant = qtOnlySettings_->getQSettings()->value(CHAT_TABS_GEOMETRY);
if (chatGeometryVariant.isValid()) {
chatWindow->restoreGeometry(chatGeometryVariant.toByteArray());
}
connect(chatWindow, SIGNAL(geometryChanged()), this, SLOT(handleWindowGeometryChanged()));
}
return chatWindow;
}
void QtChatWindowFactory::handleWindowGeometryChanged() {
qtOnlySettings_->getQSettings()->setValue(CHAT_TABS_GEOMETRY, qobject_cast<QWidget*>(sender())->saveGeometry());
}
void QtChatWindowFactory::handleSplitterMoved() {
QByteArray splitterState = qobject_cast<QtChatWindow*>(sender())->getSplitterState();
qtOnlySettings_->getQSettings()->setValue(SPLITTER_STATE, QVariant(splitterState));
emit changeSplitterState(splitterState);
}
diff --git a/Swift/QtUI/QtChatWindowFactory.h b/Swift/QtUI/QtChatWindowFactory.h
index a217215..2bb6a90 100644
--- a/Swift/QtUI/QtChatWindowFactory.h
+++ b/Swift/QtUI/QtChatWindowFactory.h
@@ -1,47 +1,51 @@
/*
* Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
+#include <map>
+#include <string>
+
#include <QMenu>
#include <QObject>
#include <QSplitter>
#include <QVBoxLayout>
#include <Swiften/JID/JID.h>
#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <SwifTools/EmojiMapper.h>
#include <Swift/QtUI/QtEmojisSelector.h>
#include <Swift/QtUI/QtSettingsProvider.h>
namespace Swift {
class QtChatTabsBase;
class QtChatTheme;
class UIEventStream;
class QtUIPreferences;
class QtSingleWindow;
class QtChatWindowFactory : public QObject, public ChatWindowFactory {
Q_OBJECT
public:
- QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabsBase* tabs, const QString& themePath);
+ QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabsBase* tabs, const QString& themePath, const std::map<std::string, std::string>& emoticonsMap);
~QtChatWindowFactory();
ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream);
signals:
void changeSplitterState(QByteArray);
private slots:
void handleWindowGeometryChanged();
void handleSplitterMoved();
private:
QString themePath_;
SettingsProvider* settings_;
QtSettingsProvider* qtOnlySettings_;
QtChatTabsBase* tabs_;
QtChatTheme* theme_;
+ std::map<std::string, std::string> emoticonsMap_;
};
}
diff --git a/Swift/QtUI/QtEmojiCell.cpp b/Swift/QtUI/QtEmojiCell.cpp
index 3f2c652..865f1f6 100644
--- a/Swift/QtUI/QtEmojiCell.cpp
+++ b/Swift/QtUI/QtEmojiCell.cpp
@@ -3,41 +3,54 @@
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/QtUI/QtEmojiCell.h>
#include <QFont>
#include <QFontMetrics>
#include <QPushButton>
#include <QString>
#include <SwifTools/EmojiMapper.h>
namespace Swift {
QtEmojiCell::QtEmojiCell(QString shortname, QString text, QWidget* parent) : QPushButton(parent) {
setText(text);
QFont font = this->font();
font.setPointSize(22);
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()));
setFlat(true);
setToolTip(shortname);
connect(this, SIGNAL(clicked()), this, SLOT(handleEmojiClicked()));
}
+ QtEmojiCell::QtEmojiCell(QIcon icon, QString text, QWidget* parent) : QPushButton(parent), text_(text) {
+ setIcon(icon);
+ setFlat(true);
+ connect(this, SIGNAL(clicked()), this, SLOT(handleEmojiClicked()));
+ setFixedSize(icon.availableSizes()[0] * 1.5);
+ }
+
QtEmojiCell::QtEmojiCell(const QtEmojiCell& b) : QtEmojiCell(b.toolTip(), b.text()) {
+
}
QtEmojiCell::~QtEmojiCell() {
}
void QtEmojiCell::handleEmojiClicked () {
- emit emojiClicked(text());
+ if (text_.isEmpty()) {
+ emit emojiClicked(text());
+ }
+ else {
+ emit emojiClicked(text_);
+ }
}
}
diff --git a/Swift/QtUI/QtEmojiCell.h b/Swift/QtUI/QtEmojiCell.h
index 62f989b..250b10d 100644
--- a/Swift/QtUI/QtEmojiCell.h
+++ b/Swift/QtUI/QtEmojiCell.h
@@ -1,30 +1,35 @@
/*
- * Copyright (c) 2016 Isode Limited.
+ * Copyright (c) 2016-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <QPushButton>
#include <QString>
#include <SwifTools/EmojiMapper.h>
class QWidget;
class QMouseEvent;
namespace Swift {
class QtEmojiCell : public QPushButton {
Q_OBJECT
public:
QtEmojiCell(const QtEmojiCell& b);
QtEmojiCell(QString shortname, QString text, QWidget* parent = nullptr);
+ QtEmojiCell(QIcon icon, QString text, QWidget* parent = nullptr);
~QtEmojiCell();
+
signals:
void emojiClicked(QString emojiAsText);
private slots:
void handleEmojiClicked();
+
+ private:
+ QString text_;
};
}
diff --git a/Swift/QtUI/QtEmojisGrid.cpp b/Swift/QtUI/QtEmojisGrid.cpp
index 6064a66..981dd67 100644
--- a/Swift/QtUI/QtEmojisGrid.cpp
+++ b/Swift/QtUI/QtEmojisGrid.cpp
@@ -20,43 +20,49 @@
namespace Swift {
static const int emojiCellSpacing = 2;
QtEmojisGrid::QtEmojisGrid() : FlowLayout(0, emojiCellSpacing, emojiCellSpacing) {
}
QtEmojisGrid::QtEmojisGrid(QString categoryName) : FlowLayout(0, emojiCellSpacing, emojiCellSpacing) {
auto category = EmojiMapper::categoryNameToEmojis(Q2PSTRING(categoryName));
QVector<QString> categoryEmojis;
for (const auto& emoji : category) {
categoryEmojis.push_back(P2QSTRING(emoji));
}
setEmojis(categoryEmojis);
}
void QtEmojisGrid::setEmojis(const QVector<QString>& emojis) {
clearEmojis();
for (const auto& unicodeEmoji : emojis) {
QString shortname = QString::fromStdString(EmojiMapper::unicodeToShortname(Q2PSTRING(unicodeEmoji)));
auto emoji = new QtEmojiCell(shortname, unicodeEmoji);
connect(emoji, SIGNAL(emojiClicked(QString)), this, SIGNAL(onEmojiSelected(QString)));
addItem(new QWidgetItem(emoji));
}
}
+ void QtEmojisGrid::addEmoticon(QIcon icon, QString text) {
+ auto emoji = new QtEmojiCell(icon, text);
+ connect(emoji, SIGNAL(emojiClicked(QString)), this, SIGNAL(onEmojiSelected(QString)));
+ addItem(new QWidgetItem(emoji));
+ }
+
void QtEmojisGrid::clearEmojis() {
QLayoutItem* child = nullptr;
while ((child = this->takeAt(0)) != nullptr) {
if (child->widget()) {
child->widget()->hide();
removeWidget(child->widget());
}
else {
removeItem(child);
}
}
}
}
diff --git a/Swift/QtUI/QtEmojisGrid.h b/Swift/QtUI/QtEmojisGrid.h
index b7ba87f..5e6c770 100644
--- a/Swift/QtUI/QtEmojisGrid.h
+++ b/Swift/QtUI/QtEmojisGrid.h
@@ -1,32 +1,33 @@
/*
* Copyright (c) 2016-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <QString>
#include <QVector>
#include <SwifTools/EmojiMapper.h>
#include <Swift/QtUI/FlowLayout.h>
namespace Swift {
class QtEmojisGrid : public FlowLayout {
Q_OBJECT
public:
explicit QtEmojisGrid();
explicit QtEmojisGrid(QString categoryName);
protected:
void setEmojis(const QVector<QString>& emojis);
+ void addEmoticon(QIcon icon, QString text);
private:
void clearEmojis();
signals:
void onEmojiSelected(QString emoji);
};
}
diff --git a/Swift/QtUI/QtEmojisScroll.cpp b/Swift/QtUI/QtEmojisScroll.cpp
index 2c347bb..be505b6 100644
--- a/Swift/QtUI/QtEmojisScroll.cpp
+++ b/Swift/QtUI/QtEmojisScroll.cpp
@@ -1,32 +1,38 @@
/*
* Copyright (c) 2016-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/QtUI/QtEmojisScroll.h>
#include <QLayout>
#include <QScrollArea>
#include <QStyle>
+#include <Swiften/Base/Platform.h>
+
#include <Swift/QtUI/QtEmojisGrid.h>
#include <Swift/QtUI/QtRecentEmojisGrid.h>
namespace Swift {
QtEmojisScroll::QtEmojisScroll(QLayout* emojiLayout, QWidget *parent) : QWidget(parent) {
auto selector = new QWidget();
auto scrollArea = new QScrollArea();
scrollArea->setWidgetResizable(true);
scrollArea->setWidget(selector);
selector->setLayout(emojiLayout);
this->setLayout(new QVBoxLayout);
this->layout()->addWidget(scrollArea);
this->layout()->setContentsMargins(0,0,0,0);
if (emojiLayout->itemAt(0)) {
+#ifdef SWIFTEN_PLATFORM_MACOSX
setMinimumHeight(emojiLayout->itemAt(0)->minimumSize().height() * 8);
+#else
+ setMinimumHeight(emojiLayout->itemAt(0)->minimumSize().height() * 2);
+#endif
}
}
}
diff --git a/Swift/QtUI/QtEmojisSelector.cpp b/Swift/QtUI/QtEmojisSelector.cpp
index 8b21380..62ed862 100644
--- a/Swift/QtUI/QtEmojisSelector.cpp
+++ b/Swift/QtUI/QtEmojisSelector.cpp
@@ -1,75 +1,95 @@
/*
* Copyright (c) 2016-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/QtUI/QtEmojisSelector.h>
#include <QScrollArea>
#include <QSettings>
#include <QString>
+#include <QTabBar>
#include <QWidget>
+#include <Swiften/Base/Platform.h>
+
#include <SwifTools/EmojiMapper.h>
#include <Swift/QtUI/QtEmojisGrid.h>
#include <Swift/QtUI/QtEmojisScroll.h>
+#include <Swift/QtUI/QtEmoticonsGrid.h>
#include <Swift/QtUI/QtRecentEmojisGrid.h>
#include <Swift/QtUI/QtSwiftUtil.h>
namespace Swift {
- QtEmojisSelector::QtEmojisSelector(QSettings* settings, QWidget* parent) : QTabWidget(parent), settings_(settings) {
+ 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)));
for (const auto& category : EmojiMapper::getCategories()) {
if (category != "modifier") {
QtEmojisGrid* grid = addTab(P2QSTRING(category));
connect(grid, SIGNAL(onEmojiSelected(QString)), this, SLOT(emojiClickedSlot(QString)));
}
}
loadSettings();
+#else
+ setupEmoticonsTab();
+#endif
}
QtEmojisSelector::~QtEmojisSelector() {
+#ifdef SWIFTEN_PLATFORM_MACOSX
writeSettings();
+#endif
}
QtRecentEmojisGrid* QtEmojisSelector::addRecentTab() {
QtRecentEmojisGrid* recent = new QtRecentEmojisGrid(settings_);
QtEmojisScroll* scroll = new QtEmojisScroll(recent);
QTabWidget::addTab(scroll, QString::fromStdString(EmojiMapper::categoryToFlagshipUnicodeEmoji("recent")));
setTabToolTip(count()-1, tr("Recent"));
return recent;
}
QtEmojisGrid* QtEmojisSelector::addTab(QString categoryName) {
QtEmojisGrid* grid = new QtEmojisGrid(categoryName);
QtEmojisScroll* scroll = new QtEmojisScroll(grid);
QTabWidget::addTab(scroll, QString::fromStdString(EmojiMapper::categoryToFlagshipUnicodeEmoji(Q2PSTRING(categoryName))));
setTabToolTip(count()-1, categoryName.replace(0, 1, categoryName[0].toUpper()));
return grid;
}
void QtEmojisSelector::loadSettings() {
if (settings_->contains("currentEmojiTab")) {
setCurrentIndex(settings_->value("currentEmojiTab").toInt());
} else {
setCurrentIndex(1); //index of people category
}
}
void QtEmojisSelector::writeSettings() {
settings_->setValue("currentEmojiTab", currentIndex());
}
+ void QtEmojisSelector::setupEmoticonsTab() {
+ QtEmojisGrid* grid = new QtEmoticonsGrid(emoticonsMap_);
+ QtEmojisScroll* scroll = new QtEmojisScroll(grid);
+ QTabWidget::addTab(scroll, QIcon(":/emoticons/smile.png"),"");
+ connect(grid, SIGNAL(onEmojiSelected(QString)), this, SLOT(emojiClickedSlot(QString)));
+ tabBar()->hide();
+ }
+
void QtEmojisSelector::emojiClickedSlot(QString emoji) {
- recentEmojisGrid_->handleEmojiClicked(emoji);
+ if (recentEmojisGrid_) {
+ recentEmojisGrid_->handleEmojiClicked(emoji);
+ }
emit emojiClicked(emoji);
}
}
diff --git a/Swift/QtUI/QtEmojisSelector.h b/Swift/QtUI/QtEmojisSelector.h
index 1065aa0..7ac11d0 100644
--- a/Swift/QtUI/QtEmojisSelector.h
+++ b/Swift/QtUI/QtEmojisSelector.h
@@ -1,40 +1,46 @@
/*
* Copyright (c) 2016-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
+#include <map>
+#include <string>
+
#include <QSettings>
#include <QTabWidget>
#include <Swift/QtUI/QtEmojisGrid.h>
#include <Swift/QtUI/QtRecentEmojisGrid.h>
namespace Swift {
class QtEmojisSelector : public QTabWidget {
Q_OBJECT
public:
- QtEmojisSelector(QSettings* settings, QWidget * parent = 0);
+ QtEmojisSelector(QSettings* settings, const std::map<std::string, std::string>& emoticonsMap, QWidget * parent = 0);
~QtEmojisSelector();
public slots:
void emojiClickedSlot(QString emoji);
signals:
void emojiClicked(QString emoji);
private:
QtRecentEmojisGrid* addRecentTab();
QtEmojisGrid* addTab(QString categoryName);
void loadSettings();
void writeSettings();
+ void setupEmoticonsTab();
+
private:
QSettings* settings_ = nullptr;
QtRecentEmojisGrid* recentEmojisGrid_ = nullptr;
+ std::map<std::string, std::string> emoticonsMap_;
};
}
diff --git a/Swift/QtUI/QtEmoticonsGrid.cpp b/Swift/QtUI/QtEmoticonsGrid.cpp
new file mode 100644
index 0000000..a592e90
--- /dev/null
+++ b/Swift/QtUI/QtEmoticonsGrid.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/QtUI/QtEmoticonsGrid.h>
+
+#include <unordered_set>
+
+#include <SwifTools/EmojiMapper.h>
+
+#include <Swift/QtUI/QtEmojiCell.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+ QtEmoticonsGrid::QtEmoticonsGrid(const std::map<std::string, std::string>& emoticonsMap) : QtEmojisGrid() {
+ std::unordered_set<std::string> usedEmoticons;
+ for (const auto& emoticonPair : emoticonsMap) {
+ if (usedEmoticons.find(emoticonPair.second) == usedEmoticons.end()) {
+ usedEmoticons.insert(emoticonPair.second);
+
+ auto filePath = P2QSTRING(emoticonPair.second);
+ if (filePath.startsWith("qrc:/")) {
+ filePath.remove(0, 3);
+ }
+ auto icon = QIcon(filePath);
+ auto text = P2QSTRING(emoticonPair.first);
+
+ addEmoticon(icon, text);
+ }
+ }
+ }
+
+ QtEmoticonsGrid::~QtEmoticonsGrid() {
+
+ }
+
+}
diff --git a/Swift/QtUI/QtEmoticonsGrid.h b/Swift/QtUI/QtEmoticonsGrid.h
new file mode 100644
index 0000000..2fc2907
--- /dev/null
+++ b/Swift/QtUI/QtEmoticonsGrid.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include <Swift/QtUI/QtEmojisGrid.h>
+
+namespace Swift {
+ class QtEmoticonsGrid : public QtEmojisGrid {
+ Q_OBJECT
+ public:
+ explicit QtEmoticonsGrid(const std::map<std::string, std::string>& emoticonsMap);
+ ~QtEmoticonsGrid();
+
+ };
+}
diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp
index b61147d..7b4e2c3 100644
--- a/Swift/QtUI/QtSwift.cpp
+++ b/Swift/QtUI/QtSwift.cpp
@@ -202,61 +202,61 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
"themes/Default/Lato2OFL/Lato-Italic.ttf",
"themes/Default/Lato2OFL/Lato-Light.ttf",
"themes/Default/Lato2OFL/Lato-LightItalic.ttf",
"themes/Default/Lato2OFL/Lato-Medium.ttf",
"themes/Default/Lato2OFL/Lato-MediumItalic.ttf",
"themes/Default/Lato2OFL/Lato-Regular.ttf",
"themes/Default/Lato2OFL/Lato-Semibold.ttf",
"themes/Default/Lato2OFL/Lato-SemiboldItalic.ttf",
"themes/Default/Lato2OFL/Lato-Thin.ttf",
"themes/Default/Lato2OFL/Lato-ThinItalic.ttf"
};
for (auto&& fontName : fontNames) {
std::string fontPath = std::string(":/") + fontName;
int error = QFontDatabase::addApplicationFont(P2QSTRING(fontPath));
assert((error != -1) && "Failed to load font.");
}
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;
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/");
+ 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
// multi-account hack creates one tray per account.
QtSystemTray* systemTray = new QtSystemTray();
systemTrays_.push_back(systemTray);
#if defined(HAVE_GROWL)
notifier_ = new GrowlNotifier(SWIFT_APPLICATION_NAME);
#elif defined(SWIFTEN_PLATFORM_WINDOWS)
notifier_ = new WindowsNotifier(SWIFT_APPLICATION_NAME, applicationPathProvider_->getResourcePath("/images/logo-icon-32.png"), systemTray->getQSystemTrayIcon());
#elif defined(SWIFTEN_PLATFORM_LINUX)
notifier_ = new FreeDesktopNotifier(SWIFT_APPLICATION_NAME);
#elif defined(SWIFTEN_PLATFORM_MACOSX)
notifier_ = new NotificationCenterNotifier();
#else
notifier_ = new NullNotifier();
#endif
#if defined(SWIFTEN_PLATFORM_MACOSX)
dock_ = new MacOSXDock(&cocoaApplication_);
#else
dock_ = new NullDock();
#endif
#if defined(SWIFTEN_PLATFORM_MACOSX)
uriHandler_ = new QtURIHandler();
#elif defined(SWIFTEN_PLATFORM_WIN32)
uriHandler_ = new NullURIHandler();
#else
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 69e99e7..1bcba64 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -115,60 +115,61 @@ sources = [
"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",
"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",
"Roster/DelegateCommons.cpp",
"Roster/QtFilterWidget.cpp",
"Roster/QtRosterWidget.cpp",
"Roster/QtOccupantListWidget.cpp",
"Roster/RosterTooltip.cpp",
"EventViewer/EventModel.cpp",
"EventViewer/EventDelegate.cpp",
"EventViewer/TwoLineDelegate.cpp",
"EventViewer/QtEventWindow.cpp",
"EventViewer/QtEvent.cpp",
"ChatList/QtChatListWindow.cpp",