From 85e53159321ab3e013dd2fc0a16748ed6755b119 Mon Sep 17 00:00:00 2001 From: Daniel Baczynski Date: Wed, 25 Mar 2015 01:16:20 +0100 Subject: Add emoticons input popup This is simple popup menu added to chat window where it is possible to choose an emoticon. To activate click on the smiling face next to input field. When emoticon is selected its text equivalent is appended to input. License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details. Test-Information: Tested on Ubuntu 14.10 with KDE and Qt 4.8.6 Change-Id: I6c5907959970398c9c38591f64ceec20efcbf409 diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp index 33bec75..f25c033 100644 --- a/Swift/QtUI/QtChatWindow.cpp +++ b/Swift/QtUI/QtChatWindow.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -23,7 +24,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -57,7 +60,7 @@ namespace Swift { -QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings) : QtTabbable(), id_(Q2PSTRING(contact)), contact_(contact), nextAlertId_(0), eventStream_(eventStream), blockingState_(BlockingUnsupported), isMUC_(false), supportsImpromptuChat_(false) { +QtChatWindow::QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings, const std::map& emoticons) : QtTabbable(), id_(Q2PSTRING(contact)), contact_(contact), nextAlertId_(0), eventStream_(eventStream), blockingState_(BlockingUnsupported), isMUC_(false), supportsImpromptuChat_(false) { settings_ = settings; unreadCount_ = 0; isOnline_ = true; @@ -140,8 +143,17 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt inputBarLayout->addWidget(correctingLabel_); correctingLabel_->hide(); + QPushButton* emoticonsButton_ = new QPushButton(this); + emoticonsButton_->setIcon(QIcon(":/emoticons/smile.png")); + connect(emoticonsButton_, SIGNAL(clicked()), this, SLOT(handleEmoticonsButtonClicked())); + + emoticonsMenu_ = new QMenu(this); + QtEmoticonsGrid* emoticonsGrid = new QtEmoticonsGrid(emoticons, emoticonsMenu_); + connect(emoticonsGrid, SIGNAL(emoticonClicked(QString)), this, SLOT(handleEmoticonClicked(QString))); + // using an extra layout to work around Qt margin glitches on OS X QHBoxLayout* actionLayout = new QHBoxLayout(); + actionLayout->addWidget(emoticonsButton_); actionLayout->addWidget(actionButton_); inputBarLayout->addLayout(actionLayout); @@ -514,6 +526,7 @@ void QtChatWindow::updateTitleWithUnreadCount() { + void QtChatWindow::flash() { emit requestFlash(); } @@ -637,6 +650,16 @@ void QtChatWindow::setSubject(const std::string& subject) { subject_->setCursorPosition(0); } +void QtChatWindow::handleEmoticonsButtonClicked() { + emoticonsMenu_->adjustSize(); + QSize menuSize = emoticonsMenu_->size(); + emoticonsMenu_->exec(QPoint(QCursor::pos().x() - menuSize.width(), QCursor::pos().y() - menuSize.height())); +} + +void QtChatWindow::handleEmoticonClicked(QString emoticonAsText) { + input_->textCursor().insertText(emoticonAsText); +} + void QtChatWindow::handleActionButtonClicked() { QMenu contextMenu; QAction* changeSubject = NULL; diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h index da3a3b9..5c6fa2a 100644 --- a/Swift/QtUI/QtChatWindow.h +++ b/Swift/QtUI/QtChatWindow.h @@ -8,9 +8,11 @@ #include +#include +#include #include +#include #include -#include #include @@ -18,12 +20,12 @@ #include #include +#include #include #include #include - class QTextEdit; class QLineEdit; class QComboBox; @@ -77,7 +79,7 @@ namespace Swift { Q_OBJECT public: - QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings); + QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings, const std::map& emoticons); virtual ~QtChatWindow(); std::string addMessage(const ChatMessage& message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight); std::string addAction(const ChatMessage& message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight); @@ -169,6 +171,8 @@ namespace Swift { void handleActionButtonClicked(); void handleAffiliationEditorAccepted(); void handleCurrentLabelChanged(int); + void handleEmoticonsButtonClicked(); + void handleEmoticonClicked(QString emoticonAsText); private: void updateTitleWithUnreadCount(); @@ -221,5 +225,6 @@ namespace Swift { bool impromptu_; bool isMUC_; bool supportsImpromptuChat_; + QMenu* emoticonsMenu_; }; } diff --git a/Swift/QtUI/QtChatWindowFactory.cpp b/Swift/QtUI/QtChatWindowFactory.cpp index 3793392..1774653 100644 --- a/Swift/QtUI/QtChatWindowFactory.cpp +++ b/Swift/QtUI/QtChatWindowFactory.cpp @@ -21,7 +21,7 @@ namespace Swift { static const QString SPLITTER_STATE = "mucSplitterState"; static const QString CHAT_TABS_GEOMETRY = "chatTabsGeometry"; -QtChatWindowFactory::QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabs* tabs, const QString& themePath) : themePath_(themePath) { +QtChatWindowFactory::QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabs* tabs, const QString& themePath, const std::map& emoticons) : themePath_(themePath), emoticons_(emoticons) { qtOnlySettings_ = qtSettings; settings_ = settings; tabs_ = tabs; @@ -50,7 +50,7 @@ ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStre } } - QtChatWindow *chatWindow = new QtChatWindow(P2QSTRING(contact.toString()), theme_, eventStream, settings_); + QtChatWindow* chatWindow = new QtChatWindow(P2QSTRING(contact.toString()), theme_, eventStream, settings_, emoticons_); connect(chatWindow, SIGNAL(splitterMoved()), this, SLOT(handleSplitterMoved())); connect(this, SIGNAL(changeSplitterState(QByteArray)), chatWindow, SLOT(handleChangeSplitterState(QByteArray))); diff --git a/Swift/QtUI/QtChatWindowFactory.h b/Swift/QtUI/QtChatWindowFactory.h index aa91d0b..c38202f 100644 --- a/Swift/QtUI/QtChatWindowFactory.h +++ b/Swift/QtUI/QtChatWindowFactory.h @@ -6,12 +6,16 @@ #pragma once -#include +#include +#include #include #include #include + +#include + #include namespace Swift { @@ -23,7 +27,7 @@ namespace Swift { class QtChatWindowFactory : public QObject, public ChatWindowFactory { Q_OBJECT public: - QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabs* tabs, const QString& themePath); + QtChatWindowFactory(QtSingleWindow* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabs* tabs, const QString& themePath, const std::map& emoticons); ~QtChatWindowFactory(); ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream); signals: @@ -37,6 +41,7 @@ namespace Swift { QtSettingsProvider* qtOnlySettings_; QtChatTabs* tabs_; QtChatTheme* theme_; + std::map emoticons_; }; } diff --git a/Swift/QtUI/QtEmoticonCell.cpp b/Swift/QtUI/QtEmoticonCell.cpp new file mode 100644 index 0000000..1c1f6ed --- /dev/null +++ b/Swift/QtUI/QtEmoticonCell.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015 Daniel Baczynski + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "QtEmoticonCell.h" + +namespace Swift { + +QtEmoticonCell::QtEmoticonCell(const QString emoticonAsText, QString filePath, QWidget* parent) : QLabel(parent), emoticonAsText_(emoticonAsText) { + if (filePath.startsWith("qrc:/")) { + filePath.remove(0, 3); + } + setPixmap(QPixmap(filePath)); + setToolTip(emoticonAsText_); +} + +QtEmoticonCell::~QtEmoticonCell() { + +} + +void QtEmoticonCell::mousePressEvent (QMouseEvent* event) { + emit emoticonClicked(emoticonAsText_); + QLabel::mousePressEvent(event); +} + +} + + diff --git a/Swift/QtUI/QtEmoticonCell.h b/Swift/QtUI/QtEmoticonCell.h new file mode 100644 index 0000000..379f5d6 --- /dev/null +++ b/Swift/QtUI/QtEmoticonCell.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 Daniel Baczynski + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +class QWidget; +class QMouseEvent; + +namespace Swift { + + class QtEmoticonCell : public QLabel { + Q_OBJECT + public: + QtEmoticonCell(const QString emoticonAsText, QString filePath, QWidget* parent = 0); + ~QtEmoticonCell(); + virtual void mousePressEvent(QMouseEvent* event); + + signals: + void emoticonClicked(QString emoticonAsText); + + private: + QString emoticonAsText_; + }; +} diff --git a/Swift/QtUI/QtEmoticonsGrid.cpp b/Swift/QtUI/QtEmoticonsGrid.cpp new file mode 100644 index 0000000..4a599ea --- /dev/null +++ b/Swift/QtUI/QtEmoticonsGrid.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015 Daniel Baczynski + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "QtEmoticonsGrid.h" + +#include + +#include + +#include + +#include + +namespace Swift { + +typedef std::map EmoticonsMap; // Without this typedef compiler complains when using foreach + +QtEmoticonsGrid::QtEmoticonsGrid(const std::map& emoticons, QWidget* parent) : QGridLayout(parent) { + makeUniqueEmoticonsMap(emoticons); + + // Create grid: 3 columns, [uniqueEmoticons_.size()/3] rows + int row = 0; + int column = 0; + + foreach(EmoticonsMap::value_type emoticon, uniqueEmoticons_) { + QtEmoticonCell* newCell = new QtEmoticonCell(P2QSTRING(emoticon.first), P2QSTRING(emoticon.second)); + addWidget(newCell, row, column); + connect(newCell, SIGNAL(emoticonClicked(QString)), this, SLOT(emoticonClickedSlot(QString))); + + column++; + if (column >= 3) { + column = 0; + row++; + } + } +} + +QtEmoticonsGrid::~QtEmoticonsGrid() { + +} + +void QtEmoticonsGrid::makeUniqueEmoticonsMap(const std::map& emoticons) { + std::set paths; + reverse_foreach(EmoticonsMap::value_type emoticon, emoticons) { + if (paths.find(emoticon.second) == paths.end()) { + uniqueEmoticons_.insert(emoticon); + paths.insert(emoticon.second); + } + } +} + +void QtEmoticonsGrid::emoticonClickedSlot(QString emoticonAsText) { + emit emoticonClicked(emoticonAsText); +} + +} diff --git a/Swift/QtUI/QtEmoticonsGrid.h b/Swift/QtUI/QtEmoticonsGrid.h new file mode 100644 index 0000000..b045b26 --- /dev/null +++ b/Swift/QtUI/QtEmoticonsGrid.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 Daniel Baczynski + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include + +class QWidget; + +namespace Swift { + + class QtEmoticonsGrid : public QGridLayout { + Q_OBJECT + public: + explicit QtEmoticonsGrid(const std::map& emoticons, QWidget* parent = 0); + virtual ~QtEmoticonsGrid(); + + signals: + void emoticonClicked(QString emoticonAsText); + + public slots: + void emoticonClickedSlot(QString emoticonAsText); + + private: + void makeUniqueEmoticonsMap(const std::map& emoticons); + + std::map uniqueEmoticons_; + }; +} diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp index 1d945da..bce3ca4 100644 --- a/Swift/QtUI/QtSwift.cpp +++ b/Swift/QtUI/QtSwift.cpp @@ -170,7 +170,7 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa 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_, ""); + chatWindowFactory_ = new QtChatWindowFactory(splitter_, settingsHierachy_, qtSettings_, tabs_, "", emoticons); soundPlayer_ = new QtSoundPlayer(applicationPathProvider_); // Ugly, because the dock depends on the tray, but the temporary diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 858df19..36f7cc9 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -124,6 +124,8 @@ sources = [ "QtBookmarkDetailWindow.cpp", "QtAddBookmarkWindow.cpp", "QtEditBookmarkWindow.cpp", + "QtEmoticonsGrid.cpp", + "QtEmoticonCell.cpp", "QtContactEditWindow.cpp", "QtContactEditWidget.cpp", "QtSingleWindow.cpp", -- cgit v0.10.2-6-g49f6