mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
refactor: SmileyPack refactoring
Brief list of changes: - removed unnecessary headers; - QList several times replaced with QVector for faster iteration; - some other things
This commit is contained in:
parent
b691cf9bed
commit
e0f1a01a74
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright © 2014-2015 by The qTox Project Contributors
|
Copyright © 2014-2017 by The qTox Project Contributors
|
||||||
|
|
||||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
@ -19,34 +19,17 @@
|
||||||
|
|
||||||
#include "smileypack.h"
|
#include "smileypack.h"
|
||||||
#include "src/persistence/settings.h"
|
#include "src/persistence/settings.h"
|
||||||
#include "src/widget/style.h"
|
|
||||||
|
|
||||||
#include <QBuffer>
|
|
||||||
#include <QBuffer>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDir>
|
|
||||||
#include <QDomDocument>
|
|
||||||
#include <QDomDocument>
|
|
||||||
#include <QDomElement>
|
#include <QDomElement>
|
||||||
#include <QDomElement>
|
#include <QRegularExpression>
|
||||||
#include <QFile>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QFont>
|
|
||||||
#include <QFontInfo>
|
|
||||||
#include <QIcon>
|
|
||||||
#include <QPixmap>
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QStringBuilder>
|
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
|
||||||
#if defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_FREEBSD)
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EMOTICONS_SUB_DIR QStringLiteral("emoticons")
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class SmileyPack
|
* @class SmileyPack
|
||||||
* @brief Maps emoticons to smileys.
|
* @brief Maps emoticons to smileys.
|
||||||
|
@ -67,7 +50,60 @@
|
||||||
* @brief Contains all directories where smileys could be found
|
* @brief Contains all directories where smileys could be found
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QStringList SmileyPack::defaultPaths = loadDefaultPaths();
|
QStringList loadDefaultPaths();
|
||||||
|
|
||||||
|
static const QStringList DEFAULT_PATHS = loadDefaultPaths();
|
||||||
|
|
||||||
|
static const QString RICH_TEXT_PATTERN = QStringLiteral("<img title=\"%1\" src=\"key:%1\"\\>");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct list of standard directories with "emoticons" sub dir, whether these directories
|
||||||
|
* exist or not
|
||||||
|
* @return Constructed list of default emoticons directories
|
||||||
|
*/
|
||||||
|
QStringList loadDefaultPaths()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_FREEBSD)
|
||||||
|
// TODO: Remove when will be fixed.
|
||||||
|
// Workaround to fix https://bugreports.qt.io/browse/QTBUG-57522
|
||||||
|
setlocale(LC_ALL, "");
|
||||||
|
#endif
|
||||||
|
const QString EMOTICONS_SUB_PATH = QDir::separator() + QStringLiteral("emoticons");
|
||||||
|
QStringList paths
|
||||||
|
{":/smileys", "~/.kde4/share/emoticons", "~/.kde/share/emoticons", EMOTICONS_SUB_PATH};
|
||||||
|
|
||||||
|
// qTox exclusive emoticons
|
||||||
|
QStandardPaths::StandardLocation location;
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
|
||||||
|
location = QStandardPaths::AppDataLocation;
|
||||||
|
#else
|
||||||
|
#warning "Qt < 5.4.0 has a trouble with unicode symbols in path on few systems"
|
||||||
|
location = QStandardPaths::DataLocation;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QStringList locations = QStandardPaths::standardLocations(location);
|
||||||
|
// system wide emoticons
|
||||||
|
locations.append(QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation));
|
||||||
|
for (QString qtoxPath : locations) {
|
||||||
|
qtoxPath.append(EMOTICONS_SUB_PATH);
|
||||||
|
if (!paths.contains(qtoxPath)) {
|
||||||
|
paths.append(qtoxPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wraps passed string into smiley HTML image reference
|
||||||
|
* @param key Describes which smiley is needed
|
||||||
|
* @return Key that wrapped into image ref
|
||||||
|
*/
|
||||||
|
QString getAsRichText(const QString& key)
|
||||||
|
{
|
||||||
|
return RICH_TEXT_PATTERN.arg(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SmileyPack::SmileyPack()
|
SmileyPack::SmileyPack()
|
||||||
{
|
{
|
||||||
|
@ -86,56 +122,19 @@ SmileyPack& SmileyPack::getInstance()
|
||||||
return smileyPack;
|
return smileyPack;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList SmileyPack::loadDefaultPaths()
|
QVector<QPair<QString, QString>> SmileyPack::listSmileyPacks()
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_FREEBSD)
|
return listSmileyPacks(DEFAULT_PATHS);
|
||||||
// TODO: Remove when will be fixed.
|
|
||||||
// Workaround to fix https://bugreports.qt.io/browse/QTBUG-57522
|
|
||||||
setlocale(LC_ALL, "");
|
|
||||||
#endif
|
|
||||||
QStringList paths =
|
|
||||||
QStringList{":/smileys", "~/.kde4/share/emoticons", "~/.kde/share/emoticons"};
|
|
||||||
// qTox should find emoticons next to the binary
|
|
||||||
paths.append('.' + QDir::separator() + EMOTICONS_SUB_DIR);
|
|
||||||
|
|
||||||
// qTox exclusive emoticons
|
|
||||||
QStandardPaths::StandardLocation location;
|
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
|
|
||||||
location = QStandardPaths::AppDataLocation;
|
|
||||||
#else
|
|
||||||
#warning "Qt < 5.4.0 has a trouble with unicode symbols in path on few systems"
|
|
||||||
location = QStandardPaths::DataLocation;
|
|
||||||
#endif
|
|
||||||
for (auto qtoxPath : QStandardPaths::standardLocations(location)) {
|
|
||||||
qtoxPath += QDir::separator() + EMOTICONS_SUB_DIR;
|
|
||||||
if (!paths.contains(qtoxPath)) {
|
|
||||||
paths << qtoxPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// system wide emoticons
|
|
||||||
for (auto genericPath : QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) {
|
|
||||||
genericPath += QDir::separator() + EMOTICONS_SUB_DIR;
|
|
||||||
if (!paths.contains(genericPath)) {
|
|
||||||
paths << genericPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return paths;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QPair<QString, QString>> SmileyPack::listSmileyPacks()
|
QVector<QPair<QString, QString>> SmileyPack::listSmileyPacks(const QStringList& paths)
|
||||||
{
|
{
|
||||||
return listSmileyPacks(defaultPaths);
|
QVector<QPair<QString, QString>> smileyPacks;
|
||||||
}
|
const QString fileName = QStringLiteral("emoticons.xml");
|
||||||
|
const QString homePath = QDir::homePath();
|
||||||
QList<QPair<QString, QString>> SmileyPack::listSmileyPacks(const QStringList& paths)
|
|
||||||
{
|
|
||||||
QList<QPair<QString, QString>> smileyPacks;
|
|
||||||
|
|
||||||
for (QString path : paths) {
|
for (QString path : paths) {
|
||||||
if (path.leftRef(1) == "~") {
|
if (path.startsWith('~')) {
|
||||||
path.replace(0, 1, QDir::homePath());
|
path.replace(0, 1, homePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir dir(path);
|
QDir dir(path);
|
||||||
|
@ -145,14 +144,11 @@ QList<QPair<QString, QString>> SmileyPack::listSmileyPacks(const QStringList& pa
|
||||||
|
|
||||||
for (const QString& subdirectory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
for (const QString& subdirectory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||||
dir.cd(subdirectory);
|
dir.cd(subdirectory);
|
||||||
|
if (dir.exists(fileName)) {
|
||||||
QFileInfoList entries = dir.entryInfoList(QStringList() << "emoticons.xml", QDir::Files);
|
QString absPath = dir.absolutePath() + QDir::separator() + fileName;
|
||||||
// Does it contain a file called emoticons.xml?
|
QPair<QString, QString> p{dir.dirName(), absPath};
|
||||||
if (entries.size() > 0) {
|
if (!smileyPacks.contains(p)) {
|
||||||
QString packageName = dir.dirName();
|
smileyPacks.append(p);
|
||||||
QString absPath = entries[0].absoluteFilePath();
|
|
||||||
if (!smileyPacks.contains(QPair<QString, QString>(packageName, absPath))) {
|
|
||||||
smileyPacks << QPair<QString, QString>(packageName, absPath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,19 +172,16 @@ bool SmileyPack::isValid(const QString& filename)
|
||||||
*/
|
*/
|
||||||
bool SmileyPack::load(const QString& filename)
|
bool SmileyPack::load(const QString& filename)
|
||||||
{
|
{
|
||||||
// discard old data
|
|
||||||
filenameTable.clear();
|
|
||||||
iconCache.clear();
|
|
||||||
emoticons.clear();
|
|
||||||
path.clear();
|
|
||||||
|
|
||||||
// open emoticons.xml
|
|
||||||
QFile xmlFile(filename);
|
QFile xmlFile(filename);
|
||||||
if (!xmlFile.open(QIODevice::ReadOnly)) {
|
if (!xmlFile.exists() || !xmlFile.open(QIODevice::ReadOnly)) {
|
||||||
loadingMutex.unlock();
|
loadingMutex.unlock();
|
||||||
return false; // cannot open file
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QDomDocument doc;
|
||||||
|
doc.setContent(xmlFile.readAll());
|
||||||
|
xmlFile.close();
|
||||||
|
|
||||||
/* parse the cfg file
|
/* parse the cfg file
|
||||||
* sample:
|
* sample:
|
||||||
* <?xml version='1.0'?>
|
* <?xml version='1.0'?>
|
||||||
|
@ -205,61 +198,54 @@ bool SmileyPack::load(const QString& filename)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
path = QFileInfo(filename).absolutePath();
|
path = QFileInfo(filename).absolutePath();
|
||||||
|
|
||||||
QDomDocument doc;
|
|
||||||
doc.setContent(xmlFile.readAll());
|
|
||||||
|
|
||||||
QDomNodeList emoticonElements = doc.elementsByTagName("emoticon");
|
QDomNodeList emoticonElements = doc.elementsByTagName("emoticon");
|
||||||
for (int i = 0; i < emoticonElements.size(); ++i) {
|
const QString itemName = QStringLiteral("file");
|
||||||
QString file = emoticonElements.at(i).attributes().namedItem("file").nodeValue();
|
const QString childName = QStringLiteral("string");
|
||||||
QDomElement stringElement = emoticonElements.at(i).firstChildElement("string");
|
emoticons.clear();
|
||||||
|
emoticonToIcon.clear();
|
||||||
QStringList emoticonSet; // { ":)", ":-)" } etc.
|
icons.clear();
|
||||||
|
const int iconsCount = emoticonElements.size();
|
||||||
|
icons.reserve(iconsCount);
|
||||||
|
for (int i = 0; i < iconsCount; ++i) {
|
||||||
|
QString iconName = emoticonElements.at(i).attributes().namedItem(itemName).nodeValue();
|
||||||
|
QString iconPath = QDir{path}.filePath(iconName);
|
||||||
|
icons.append(QIcon{iconPath});
|
||||||
|
QDomElement stringElement = emoticonElements.at(i).firstChildElement(childName);
|
||||||
|
QStringList emoticonList;
|
||||||
while (!stringElement.isNull()) {
|
while (!stringElement.isNull()) {
|
||||||
QString emoticon = stringElement.text().replace("<", "<").replace(">", ">");
|
QString emoticon = stringElement.text().replace("<", "<").replace(">", ">");
|
||||||
filenameTable.insert(emoticon, file);
|
emoticonToIcon.insert(emoticon, &icons[i]);
|
||||||
|
emoticonList.append(emoticon);
|
||||||
cacheSmiley(file); // preload all smileys
|
|
||||||
|
|
||||||
if (!getCachedSmiley(emoticon).isNull()) {
|
|
||||||
emoticonSet.push_back(emoticon);
|
|
||||||
}
|
|
||||||
|
|
||||||
stringElement = stringElement.nextSibling().toElement();
|
stringElement = stringElement.nextSibling().toElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emoticonSet.size() > 0) {
|
emoticons.append(emoticonList);
|
||||||
emoticons.push_back(emoticonSet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// success!
|
|
||||||
loadingMutex.unlock();
|
loadingMutex.unlock();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SmileyPack::smileyfied(QString msg)
|
QString SmileyPack::smileyfied(const QString& msg)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&loadingMutex);
|
QMutexLocker locker(&loadingMutex);
|
||||||
|
QString result(msg);
|
||||||
QRegExp exp("\\S+"); // matches words
|
QRegularExpression exp("\\S+");
|
||||||
|
QRegularExpressionMatchIterator iter = exp.globalMatch(result);
|
||||||
int index = msg.indexOf(exp);
|
int replaceDiff = 0;
|
||||||
|
while (iter.hasNext()) {
|
||||||
// if a word is key of a smiley, replace it by its corresponding image in Rich Text
|
QRegularExpressionMatch match = iter.next();
|
||||||
while (index >= 0) {
|
QString key = match.captured();
|
||||||
QString key = exp.cap();
|
int startPos = match.capturedStart();
|
||||||
if (filenameTable.contains(key)) {
|
int keyLength = key.length();
|
||||||
|
if (emoticonToIcon.contains(key)) {
|
||||||
QString imgRichText = getAsRichText(key);
|
QString imgRichText = getAsRichText(key);
|
||||||
|
result.replace(startPos + replaceDiff, keyLength, imgRichText);
|
||||||
msg.replace(index, key.length(), imgRichText);
|
replaceDiff += imgRichText.length() - keyLength;
|
||||||
index += imgRichText.length() - key.length();
|
|
||||||
}
|
}
|
||||||
index = msg.indexOf(exp, index + key.length());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QStringList> SmileyPack::getEmoticons() const
|
QList<QStringList> SmileyPack::getEmoticons() const
|
||||||
|
@ -268,40 +254,10 @@ QList<QStringList> SmileyPack::getEmoticons() const
|
||||||
return emoticons;
|
return emoticons;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SmileyPack::getAsRichText(const QString& key)
|
QIcon SmileyPack::getAsIcon(const QString& emoticon)
|
||||||
{
|
|
||||||
return QString("<img title=\"%1\" src=\"key:%1\"\\>").arg(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon SmileyPack::getAsIcon(const QString& key)
|
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&loadingMutex);
|
QMutexLocker locker(&loadingMutex);
|
||||||
return getCachedSmiley(key);
|
return emoticonToIcon.contains(emoticon) ? *(emoticonToIcon[emoticon]) : QIcon();
|
||||||
}
|
|
||||||
|
|
||||||
void SmileyPack::cacheSmiley(const QString& name)
|
|
||||||
{
|
|
||||||
QString filename = QDir(path).filePath(name);
|
|
||||||
|
|
||||||
QIcon icon;
|
|
||||||
icon.addFile(filename);
|
|
||||||
iconCache.insert(name, icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon SmileyPack::getCachedSmiley(const QString& key)
|
|
||||||
{
|
|
||||||
// valid key?
|
|
||||||
if (!filenameTable.contains(key)) {
|
|
||||||
return QPixmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// cache it if needed
|
|
||||||
QString file = filenameTable.value(key);
|
|
||||||
if (!iconCache.contains(file)) {
|
|
||||||
cacheSmiley(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return iconCache.value(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SmileyPack::onSmileyPackChanged()
|
void SmileyPack::onSmileyPackChanged()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright © 2014-2015 by The qTox Project Contributors
|
Copyright © 2014-2017 by The qTox Project Contributors
|
||||||
|
|
||||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
@ -20,12 +20,9 @@
|
||||||
#ifndef SMILEYPACK_H
|
#ifndef SMILEYPACK_H
|
||||||
#define SMILEYPACK_H
|
#define SMILEYPACK_H
|
||||||
|
|
||||||
#include <QHash>
|
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
#include <QMap>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QObject>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
class SmileyPack : public QObject
|
class SmileyPack : public QObject
|
||||||
{
|
{
|
||||||
|
@ -33,13 +30,12 @@ class SmileyPack : public QObject
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SmileyPack& getInstance();
|
static SmileyPack& getInstance();
|
||||||
static QList<QPair<QString, QString>> listSmileyPacks(const QStringList& paths);
|
static QVector<QPair<QString, QString>> listSmileyPacks(const QStringList& paths);
|
||||||
static QList<QPair<QString, QString>> listSmileyPacks();
|
static QVector<QPair<QString, QString>> listSmileyPacks();
|
||||||
static bool isValid(const QString& filename);
|
static bool isValid(const QString& filename);
|
||||||
|
|
||||||
QString smileyfied(QString msg);
|
QString smileyfied(const QString& msg);
|
||||||
QList<QStringList> getEmoticons() const;
|
QList<QStringList> getEmoticons() const;
|
||||||
QString getAsRichText(const QString& key);
|
|
||||||
QIcon getAsIcon(const QString& key);
|
QIcon getAsIcon(const QString& key);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -51,15 +47,11 @@ private:
|
||||||
SmileyPack& operator=(const SmileyPack&) = delete;
|
SmileyPack& operator=(const SmileyPack&) = delete;
|
||||||
|
|
||||||
bool load(const QString& filename);
|
bool load(const QString& filename);
|
||||||
void cacheSmiley(const QString& name);
|
|
||||||
QIcon getCachedSmiley(const QString& key);
|
|
||||||
static QStringList loadDefaultPaths();
|
|
||||||
|
|
||||||
QHash<QString, QString> filenameTable;
|
QVector<QIcon> icons;
|
||||||
QHash<QString, QIcon> iconCache;
|
QMap<QString, QIcon const*> emoticonToIcon;
|
||||||
QList<QStringList> emoticons;
|
QList<QStringList> emoticons;
|
||||||
QString path;
|
QString path;
|
||||||
static QStringList defaultPaths;
|
|
||||||
mutable QMutex loadingMutex;
|
mutable QMutex loadingMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user