mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
commit
2a04fcfcf9
|
@ -34,11 +34,36 @@ SmileyPack& SmileyPack::getInstance()
|
||||||
return smileyPack;
|
return smileyPack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QPair<QString, QString> > SmileyPack::listSmileyPacks(const QString &path)
|
||||||
|
{
|
||||||
|
QList<QPair<QString, QString> > smileyPacks;
|
||||||
|
|
||||||
|
QDir dir(path);
|
||||||
|
foreach (const QString& subdirectory, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
|
||||||
|
{
|
||||||
|
dir.cd(subdirectory);
|
||||||
|
|
||||||
|
QFileInfoList entries = dir.entryInfoList(QStringList() << "emoticons.xml", QDir::Files);
|
||||||
|
if (entries.size() > 0) // does it contain a file called emoticons.xml?
|
||||||
|
{
|
||||||
|
QString packageName = dir.dirName();
|
||||||
|
QString relPath = QDir(QCoreApplication::applicationDirPath()).relativeFilePath(entries[0].absoluteFilePath());
|
||||||
|
smileyPacks << QPair<QString, QString>(packageName, relPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
dir.cdUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return smileyPacks;
|
||||||
|
}
|
||||||
|
|
||||||
bool SmileyPack::load(const QString& filename)
|
bool SmileyPack::load(const QString& filename)
|
||||||
{
|
{
|
||||||
// discard old data
|
// discard old data
|
||||||
assignmentTable.clear();
|
filenameTable.clear();
|
||||||
cache.clear();
|
imgCache.clear();
|
||||||
|
emoticons.clear();
|
||||||
|
path.clear();
|
||||||
|
|
||||||
// open emoticons.xml
|
// open emoticons.xml
|
||||||
QFile xmlFile(filename);
|
QFile xmlFile(filename);
|
||||||
|
@ -60,6 +85,8 @@ bool SmileyPack::load(const QString& filename)
|
||||||
* </messaging-emoticon-map>
|
* </messaging-emoticon-map>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
path = QFileInfo(filename).absolutePath();
|
||||||
|
|
||||||
QDomDocument doc;
|
QDomDocument doc;
|
||||||
doc.setContent(xmlFile.readAll());
|
doc.setContent(xmlFile.readAll());
|
||||||
|
|
||||||
|
@ -69,42 +96,39 @@ bool SmileyPack::load(const QString& filename)
|
||||||
QString file = emoticonElements.at(i).attributes().namedItem("file").nodeValue();
|
QString file = emoticonElements.at(i).attributes().namedItem("file").nodeValue();
|
||||||
QDomElement stringElement = emoticonElements.at(i).firstChildElement("string");
|
QDomElement stringElement = emoticonElements.at(i).firstChildElement("string");
|
||||||
|
|
||||||
|
QStringList emoticonSet; // { ":)", ":-)" } etc.
|
||||||
|
|
||||||
while (!stringElement.isNull())
|
while (!stringElement.isNull())
|
||||||
{
|
{
|
||||||
QString rune = stringElement.text();
|
QString emoticon = stringElement.text();
|
||||||
assignmentTable.insert(rune, file);
|
filenameTable.insert(emoticon, file);
|
||||||
|
emoticonSet.push_back(emoticon);
|
||||||
|
cacheSmiley(file); // preload all smileys
|
||||||
|
|
||||||
stringElement = stringElement.nextSibling().toElement();
|
stringElement = stringElement.nextSibling().toElement();
|
||||||
}
|
}
|
||||||
|
emoticons.push_back(emoticonSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
path = QFileInfo(filename).absolutePath();
|
|
||||||
|
|
||||||
// success!
|
// success!
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SmileyPack::replaceEmoticons(QString msg)
|
QString SmileyPack::smileyfied(QString msg)
|
||||||
{
|
{
|
||||||
QRegExp exp("\\S+"); // matches words
|
QRegExp exp("\\S+"); // matches words
|
||||||
|
|
||||||
int index = msg.indexOf(exp);
|
int index = msg.indexOf(exp);
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
// if a word is key of a smiley, replace it by its corresponding image in Rich Text
|
// if a word is key of a smiley, replace it by its corresponding image in Rich Text
|
||||||
while (index >= 0)
|
while (index >= 0)
|
||||||
{
|
{
|
||||||
QString key = exp.cap();
|
QString key = exp.cap();
|
||||||
if (assignmentTable.contains(key))
|
if (filenameTable.contains(key))
|
||||||
{
|
{
|
||||||
QString file = assignmentTable[key];
|
QString imgRichText = getAsRichText(key);
|
||||||
if (!cache.contains(file)) {
|
|
||||||
loadSmiley(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString imgRichText = "<img src=\"data:image/png;base64," % cache[file] % "\">";
|
msg.replace(index, key.length(), imgRichText);
|
||||||
|
|
||||||
msg.replace(index + offset, key.length(), imgRichText);
|
|
||||||
index += imgRichText.length() - key.length();
|
index += imgRichText.length() - key.length();
|
||||||
}
|
}
|
||||||
index = msg.indexOf(exp, index + key.length());
|
index = msg.indexOf(exp, index + key.length());
|
||||||
|
@ -113,7 +137,25 @@ QString SmileyPack::replaceEmoticons(QString msg)
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SmileyPack::loadSmiley(const QString &name)
|
QList<QStringList> SmileyPack::getEmoticons() const
|
||||||
|
{
|
||||||
|
return emoticons;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SmileyPack::getAsRichText(const QString &key)
|
||||||
|
{
|
||||||
|
return "<img src=\"data:image/png;base64," % QString(getCachedSmiley(key).toBase64()) % "\">";
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon SmileyPack::getAsIcon(const QString &key)
|
||||||
|
{
|
||||||
|
QPixmap pm;
|
||||||
|
pm.loadFromData(getCachedSmiley(key), "PNG");
|
||||||
|
|
||||||
|
return QIcon(pm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmileyPack::cacheSmiley(const QString &name)
|
||||||
{
|
{
|
||||||
QSize size(16, 16); // TODO: adapt to text size
|
QSize size(16, 16); // TODO: adapt to text size
|
||||||
QString filename = path % '/' % name;
|
QString filename = path % '/' % name;
|
||||||
|
@ -127,10 +169,25 @@ void SmileyPack::loadSmiley(const QString &name)
|
||||||
QBuffer buffer(&scaledImgData);
|
QBuffer buffer(&scaledImgData);
|
||||||
scaledImg.save(&buffer, "PNG");
|
scaledImg.save(&buffer, "PNG");
|
||||||
|
|
||||||
cache.insert(name, scaledImgData.toBase64());
|
imgCache.insert(name, scaledImgData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray SmileyPack::getCachedSmiley(const QString &key)
|
||||||
|
{
|
||||||
|
// valid key?
|
||||||
|
if (!filenameTable.contains(key))
|
||||||
|
return QByteArray();
|
||||||
|
|
||||||
|
// cache it if needed
|
||||||
|
QString file = filenameTable.value(key);
|
||||||
|
if (!imgCache.contains(file)) {
|
||||||
|
cacheSmiley(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return imgCache.value(file);
|
||||||
|
}
|
||||||
|
|
||||||
void SmileyPack::onSmileyPackChanged()
|
void SmileyPack::onSmileyPackChanged()
|
||||||
{
|
{
|
||||||
load(Settings::getInstance().getSmileyPack());
|
load(Settings::getInstance().getSmileyPack());
|
||||||
|
|
19
smileypack.h
19
smileypack.h
|
@ -18,8 +18,9 @@
|
||||||
#define SMILEYPACK_H
|
#define SMILEYPACK_H
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QString>
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
//maps emoticons to smileys
|
//maps emoticons to smileys
|
||||||
class SmileyPack : public QObject
|
class SmileyPack : public QObject
|
||||||
|
@ -27,9 +28,13 @@ class SmileyPack : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static SmileyPack& getInstance();
|
static SmileyPack& getInstance();
|
||||||
|
static QList<QPair<QString, QString>> listSmileyPacks(const QString& path);
|
||||||
|
|
||||||
bool load(const QString &filename);
|
bool load(const QString &filename);
|
||||||
QString replaceEmoticons(QString msg);
|
QString smileyfied(QString msg);
|
||||||
|
QList<QStringList> getEmoticons() const;
|
||||||
|
QString getAsRichText(const QString& key);
|
||||||
|
QIcon getAsIcon(const QString& key);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onSmileyPackChanged();
|
void onSmileyPackChanged();
|
||||||
|
@ -39,11 +44,13 @@ private:
|
||||||
SmileyPack(SmileyPack&) = delete;
|
SmileyPack(SmileyPack&) = delete;
|
||||||
SmileyPack& operator=(const SmileyPack&) = delete;
|
SmileyPack& operator=(const SmileyPack&) = delete;
|
||||||
|
|
||||||
void loadSmiley(const QString& name);
|
void cacheSmiley(const QString& name);
|
||||||
|
QByteArray getCachedSmiley(const QString& key);
|
||||||
|
|
||||||
QHash<QString, QString> assignmentTable; // matches an emoticon to its corresponding smiley
|
QHash<QString, QString> filenameTable; // matches an emoticon to its corresponding smiley ie. ":)" -> "happy.png"
|
||||||
QHash<QString, QString> cache; // base64 representation of a smiley
|
QHash<QString, QByteArray> imgCache; // (scaled) representation of a smiley ie. "happy.png" -> data
|
||||||
QString path; // directory containing the cfg file
|
QList<QStringList> emoticons; // {{ ":)", ":-)" }, {":(", ...}, ... }
|
||||||
|
QString path; // directory containing the cfg and image files
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SMILEYPACK_H
|
#endif // SMILEYPACK_H
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QWidgetAction>
|
||||||
|
#include <QGridLayout>
|
||||||
|
|
||||||
ChatForm::ChatForm(Friend* chatFriend)
|
ChatForm::ChatForm(Friend* chatFriend)
|
||||||
: f(chatFriend), curRow{0}, lockSliderToBottom{true}
|
: f(chatFriend), curRow{0}, lockSliderToBottom{true}
|
||||||
|
@ -188,6 +190,7 @@ ChatForm::ChatForm(Friend* chatFriend)
|
||||||
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
|
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
|
||||||
connect(chatArea->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged()));
|
connect(chatArea->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged()));
|
||||||
connect(chatArea, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onChatContextMenuRequested(QPoint)));
|
connect(chatArea, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onChatContextMenuRequested(QPoint)));
|
||||||
|
connect(emoteButton, SIGNAL(clicked()), this, SLOT(onEmoteButtonClicked()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatForm::~ChatForm()
|
ChatForm::~ChatForm()
|
||||||
|
@ -239,7 +242,7 @@ void ChatForm::addFriendMessage(QString message)
|
||||||
|
|
||||||
void ChatForm::addMessage(QString author, QString message, QString date)
|
void ChatForm::addMessage(QString author, QString message, QString date)
|
||||||
{
|
{
|
||||||
message = SmileyPack::getInstance().replaceEmoticons(message);
|
message = SmileyPack::getInstance().smileyfied(message);
|
||||||
addMessage(new QLabel(author), new QLabel(message), new QLabel(date));
|
addMessage(new QLabel(author), new QLabel(message), new QLabel(date));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,3 +655,53 @@ void ChatForm::onSaveLogClicked()
|
||||||
file.write(log.toUtf8());
|
file.write(log.toUtf8());
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatForm::onEmoteButtonClicked()
|
||||||
|
{
|
||||||
|
QList<QStringList> emoticons = SmileyPack::getInstance().getEmoticons();
|
||||||
|
|
||||||
|
QMenu menu;
|
||||||
|
QGridLayout* gridLayout = new QGridLayout;
|
||||||
|
menu.setLayout(gridLayout);
|
||||||
|
|
||||||
|
int colCount = sqrt(emoticons.size()) + 1;
|
||||||
|
int row = 0;
|
||||||
|
int col = 0;
|
||||||
|
for (const QStringList& set : emoticons)
|
||||||
|
{
|
||||||
|
QPushButton* button = new QPushButton;
|
||||||
|
button->setIcon(SmileyPack::getInstance().getAsIcon(set[0]));
|
||||||
|
button->setToolTip(set.join(" "));
|
||||||
|
button->setProperty("sequence", set[0]);
|
||||||
|
connect(button, &QPushButton::clicked, this, &ChatForm::onAddEmote);
|
||||||
|
|
||||||
|
gridLayout->addWidget(button, row, ++col);
|
||||||
|
if (col >= colCount)
|
||||||
|
{
|
||||||
|
col = 0;
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* sender = qobject_cast<QWidget*>(QObject::sender());
|
||||||
|
if (sender)
|
||||||
|
{
|
||||||
|
QPoint pos(gridLayout->totalSizeHint().width() / 2, gridLayout->totalSizeHint().height());
|
||||||
|
menu.exec(sender->mapToGlobal(-pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatForm::onAddEmote()
|
||||||
|
{
|
||||||
|
// hide the QMenu
|
||||||
|
QMenu* menu = qobject_cast<QMenu*>(QObject::sender()->parent());
|
||||||
|
if (menu)
|
||||||
|
menu->hide();
|
||||||
|
|
||||||
|
// insert the emoticon
|
||||||
|
QWidget* sender = qobject_cast<QWidget*>(QObject::sender());
|
||||||
|
if (sender)
|
||||||
|
msgEdit->insertPlainText(' ' + sender->property("sequence").toString() + ' ');
|
||||||
|
|
||||||
|
msgEdit->setFocus(); // refocus so that you can continue typing
|
||||||
|
}
|
||||||
|
|
|
@ -83,6 +83,8 @@ private slots:
|
||||||
void onCancelCallTriggered();
|
void onCancelCallTriggered();
|
||||||
void onChatContextMenuRequested(QPoint pos);
|
void onChatContextMenuRequested(QPoint pos);
|
||||||
void onSaveLogClicked();
|
void onSaveLogClicked();
|
||||||
|
void onEmoteButtonClicked();
|
||||||
|
void onAddEmote();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Friend* f;
|
Friend* f;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "settingsform.h"
|
#include "settingsform.h"
|
||||||
#include "widget/widget.h"
|
#include "widget/widget.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "smileypack.h"
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
@ -53,7 +54,9 @@ SettingsForm::SettingsForm()
|
||||||
makeToxPortable.setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox"));
|
makeToxPortable.setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox"));
|
||||||
|
|
||||||
smileyPackLabel.setText(tr("Smiley Pack", "Text on smiley pack label"));
|
smileyPackLabel.setText(tr("Smiley Pack", "Text on smiley pack label"));
|
||||||
smileyPackFilename.setText(Settings::getInstance().getSmileyPack());
|
for (auto entry : SmileyPack::listSmileyPacks("./smileys"))
|
||||||
|
smileyPackBrowser.addItem(entry.first, entry.second);
|
||||||
|
smileyPackBrowser.setCurrentIndex(smileyPackBrowser.findData(Settings::getInstance().getSmileyPack()));
|
||||||
|
|
||||||
main->setLayout(&layout);
|
main->setLayout(&layout);
|
||||||
layout.addWidget(&nameLabel);
|
layout.addWidget(&nameLabel);
|
||||||
|
@ -67,8 +70,7 @@ SettingsForm::SettingsForm()
|
||||||
layout.addWidget(&useTranslations);
|
layout.addWidget(&useTranslations);
|
||||||
layout.addWidget(&makeToxPortable);
|
layout.addWidget(&makeToxPortable);
|
||||||
layout.addWidget(&smileyPackLabel);
|
layout.addWidget(&smileyPackLabel);
|
||||||
layout.addWidget(&smileyPackFilename);
|
layout.addWidget(&smileyPackBrowser);
|
||||||
layout.addWidget(&smileyBrowseFileButton);
|
|
||||||
layout.addStretch();
|
layout.addStretch();
|
||||||
|
|
||||||
head->setLayout(&headLayout);
|
head->setLayout(&headLayout);
|
||||||
|
@ -79,7 +81,7 @@ SettingsForm::SettingsForm()
|
||||||
connect(&useTranslations, SIGNAL(stateChanged(int)), this, SLOT(onUseTranslationUpdated()));
|
connect(&useTranslations, SIGNAL(stateChanged(int)), this, SLOT(onUseTranslationUpdated()));
|
||||||
connect(&makeToxPortable, SIGNAL(stateChanged(int)), this, SLOT(onMakeToxPortableUpdated()));
|
connect(&makeToxPortable, SIGNAL(stateChanged(int)), this, SLOT(onMakeToxPortableUpdated()));
|
||||||
connect(&idLabel, SIGNAL(clicked()), this, SLOT(copyIdClicked()));
|
connect(&idLabel, SIGNAL(clicked()), this, SLOT(copyIdClicked()));
|
||||||
connect(&smileyBrowseFileButton, SIGNAL(clicked()), this, SLOT(onBrowseSmileyFilename()));
|
connect(&smileyPackBrowser, SIGNAL(currentIndexChanged(int)), this, SLOT(onSmileyBrowserIndexChanged(int)));
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsForm::~SettingsForm()
|
SettingsForm::~SettingsForm()
|
||||||
|
@ -127,16 +129,8 @@ void SettingsForm::onMakeToxPortableUpdated()
|
||||||
Settings::getInstance().setMakeToxPortable(makeToxPortable.isChecked());
|
Settings::getInstance().setMakeToxPortable(makeToxPortable.isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsForm::onBrowseSmileyFilename()
|
void SettingsForm::onSmileyBrowserIndexChanged(int index)
|
||||||
{
|
{
|
||||||
// directory containing a file called emoticons.xml
|
QString filename = smileyPackBrowser.itemData(index).toString();
|
||||||
QString filename = QFileDialog::getOpenFileName(nullptr, tr("Select smiley pack"), QDir::currentPath(), "emoticons.xml");
|
Settings::getInstance().setSmileyPack(filename);
|
||||||
|
|
||||||
// get relative path to app's local directory
|
|
||||||
QString relPath = QDir::current().relativeFilePath(filename);
|
|
||||||
|
|
||||||
// save
|
|
||||||
Settings::getInstance().setSmileyPack(relPath);
|
|
||||||
smileyPackFilename.setText(relPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
|
#include <QComboBox>
|
||||||
#include "widget/tool/clickablelabel.h"
|
#include "widget/tool/clickablelabel.h"
|
||||||
#include "ui_widget.h"
|
#include "ui_widget.h"
|
||||||
#include "widget/selfcamview.h"
|
#include "widget/selfcamview.h"
|
||||||
|
@ -47,7 +48,7 @@ private slots:
|
||||||
void onEnableIPv6Updated();
|
void onEnableIPv6Updated();
|
||||||
void onUseTranslationUpdated();
|
void onUseTranslationUpdated();
|
||||||
void onMakeToxPortableUpdated();
|
void onMakeToxPortableUpdated();
|
||||||
void onBrowseSmileyFilename();
|
void onSmileyBrowserIndexChanged(int index);
|
||||||
void copyIdClicked();
|
void copyIdClicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -58,8 +59,7 @@ private:
|
||||||
QCheckBox enableIPv6, useTranslations, makeToxPortable;
|
QCheckBox enableIPv6, useTranslations, makeToxPortable;
|
||||||
QVBoxLayout layout, headLayout;
|
QVBoxLayout layout, headLayout;
|
||||||
QWidget *main, *head;
|
QWidget *main, *head;
|
||||||
QLineEdit smileyPackFilename;
|
QComboBox smileyPackBrowser;
|
||||||
QToolButton smileyBrowseFileButton;
|
|
||||||
public:
|
public:
|
||||||
QLineEdit name, statusText;
|
QLineEdit name, statusText;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user