mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge pull request #4322
noavarice (4): refactor: SmileyPack refactoring refactor: removed meaningless 'isValid' method docs: added docs for SmileyPack refactor: returned correct code format and some other small changes
This commit is contained in:
commit
17abfe3753
|
@ -232,8 +232,9 @@ void Settings::loadGlobal()
|
|||
|
||||
const QString DEFAULT_SMILEYS = ":/smileys/emojione/emoticons.xml";
|
||||
smileyPack = s.value("smileyPack", DEFAULT_SMILEYS).toString();
|
||||
if (!SmileyPack::isValid(smileyPack))
|
||||
if (!QFile::exists(smileyPack)) {
|
||||
smileyPack = DEFAULT_SMILEYS;
|
||||
}
|
||||
|
||||
emojiFontPointSize = s.value("emojiFontPointSize", 24).toInt();
|
||||
firstColumnHandlePos = s.value("firstColumnHandlePos", 50).toInt();
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
@ -19,34 +19,17 @@
|
|||
|
||||
#include "smileypack.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/widget/style.h"
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QBuffer>
|
||||
#include <QCoreApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QDir>
|
||||
#include <QDomDocument>
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
#include <QDomElement>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QFont>
|
||||
#include <QFontInfo>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QRegularExpression>
|
||||
#include <QStandardPaths>
|
||||
#include <QStringBuilder>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
|
||||
#if defined(Q_OS_FREEBSD)
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#define EMOTICONS_SUB_DIR QStringLiteral("emoticons")
|
||||
|
||||
/**
|
||||
* @class SmileyPack
|
||||
* @brief Maps emoticons to smileys.
|
||||
|
@ -67,7 +50,62 @@
|
|||
* @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\"\\>");
|
||||
|
||||
static const QString EMOTICONS_FILE_NAME = QStringLiteral("emoticons.xml");
|
||||
|
||||
/**
|
||||
* @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()
|
||||
{
|
||||
|
@ -86,56 +124,26 @@ SmileyPack& SmileyPack::getInstance()
|
|||
return smileyPack;
|
||||
}
|
||||
|
||||
QStringList SmileyPack::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
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Does the same as listSmileyPaths, but with default paths
|
||||
*/
|
||||
QList<QPair<QString, QString>> SmileyPack::listSmileyPacks()
|
||||
{
|
||||
return listSmileyPacks(defaultPaths);
|
||||
return listSmileyPacks(DEFAULT_PATHS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Searches all files called "emoticons.xml" within the every passed path in the depth of 2
|
||||
* @param paths Paths where to search for file
|
||||
* @return Vector of pairs: {directoryName, absolutePathToFile}
|
||||
*/
|
||||
QList<QPair<QString, QString>> SmileyPack::listSmileyPacks(const QStringList& paths)
|
||||
{
|
||||
QList<QPair<QString, QString>> smileyPacks;
|
||||
|
||||
const QString homePath = QDir::homePath();
|
||||
for (QString path : paths) {
|
||||
if (path.leftRef(1) == "~") {
|
||||
path.replace(0, 1, QDir::homePath());
|
||||
if (path.startsWith('~')) {
|
||||
path.replace(0, 1, homePath);
|
||||
}
|
||||
|
||||
QDir dir(path);
|
||||
|
@ -145,14 +153,11 @@ QList<QPair<QString, QString>> SmileyPack::listSmileyPacks(const QStringList& pa
|
|||
|
||||
for (const QString& subdirectory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||
dir.cd(subdirectory);
|
||||
|
||||
QFileInfoList entries = dir.entryInfoList(QStringList() << "emoticons.xml", QDir::Files);
|
||||
// Does it contain a file called emoticons.xml?
|
||||
if (entries.size() > 0) {
|
||||
QString packageName = dir.dirName();
|
||||
QString absPath = entries[0].absoluteFilePath();
|
||||
if (!smileyPacks.contains(QPair<QString, QString>(packageName, absPath))) {
|
||||
smileyPacks << QPair<QString, QString>(packageName, absPath);
|
||||
if (dir.exists(EMOTICONS_FILE_NAME)) {
|
||||
QString absPath = dir.absolutePath() + QDir::separator() + EMOTICONS_FILE_NAME;
|
||||
QPair<QString, QString> p{dir.dirName(), absPath};
|
||||
if (!smileyPacks.contains(p)) {
|
||||
smileyPacks.append(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,11 +168,6 @@ QList<QPair<QString, QString>> SmileyPack::listSmileyPacks(const QStringList& pa
|
|||
return smileyPacks;
|
||||
}
|
||||
|
||||
bool SmileyPack::isValid(const QString& filename)
|
||||
{
|
||||
return QFile(filename).exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load smile pack
|
||||
* @note The caller must lock loadingMutex and should run it in a thread
|
||||
|
@ -176,19 +176,16 @@ bool SmileyPack::isValid(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);
|
||||
if (!xmlFile.open(QIODevice::ReadOnly)) {
|
||||
if (!xmlFile.exists() || !xmlFile.open(QIODevice::ReadOnly)) {
|
||||
loadingMutex.unlock();
|
||||
return false; // cannot open file
|
||||
return false;
|
||||
}
|
||||
|
||||
QDomDocument doc;
|
||||
doc.setContent(xmlFile.readAll());
|
||||
xmlFile.close();
|
||||
|
||||
/* parse the cfg file
|
||||
* sample:
|
||||
* <?xml version='1.0'?>
|
||||
|
@ -205,103 +202,80 @@ bool SmileyPack::load(const QString& filename)
|
|||
*/
|
||||
|
||||
path = QFileInfo(filename).absolutePath();
|
||||
|
||||
QDomDocument doc;
|
||||
doc.setContent(xmlFile.readAll());
|
||||
|
||||
QDomNodeList emoticonElements = doc.elementsByTagName("emoticon");
|
||||
for (int i = 0; i < emoticonElements.size(); ++i) {
|
||||
QString file = emoticonElements.at(i).attributes().namedItem("file").nodeValue();
|
||||
QDomElement stringElement = emoticonElements.at(i).firstChildElement("string");
|
||||
|
||||
QStringList emoticonSet; // { ":)", ":-)" } etc.
|
||||
|
||||
const QString itemName = QStringLiteral("file");
|
||||
const QString childName = QStringLiteral("string");
|
||||
const int iconsCount = emoticonElements.size();
|
||||
emoticons.clear();
|
||||
emoticonToIcon.clear();
|
||||
icons.clear();
|
||||
icons.reserve(iconsCount);
|
||||
for (int i = 0; i < iconsCount; ++i) {
|
||||
QDomNode node = emoticonElements.at(i);
|
||||
QString iconName = node.attributes().namedItem(itemName).nodeValue();
|
||||
QString iconPath = QDir{path}.filePath(iconName);
|
||||
icons.append(QIcon{iconPath});
|
||||
QDomElement stringElement = node.firstChildElement(childName);
|
||||
QStringList emoticonList;
|
||||
while (!stringElement.isNull()) {
|
||||
QString emoticon = stringElement.text().replace("<", "<").replace(">", ">");
|
||||
filenameTable.insert(emoticon, file);
|
||||
|
||||
cacheSmiley(file); // preload all smileys
|
||||
|
||||
if (!getCachedSmiley(emoticon).isNull()) {
|
||||
emoticonSet.push_back(emoticon);
|
||||
}
|
||||
|
||||
emoticonToIcon.insert(emoticon, &icons[i]);
|
||||
emoticonList.append(emoticon);
|
||||
stringElement = stringElement.nextSibling().toElement();
|
||||
}
|
||||
|
||||
if (emoticonSet.size() > 0) {
|
||||
emoticons.push_back(emoticonSet);
|
||||
}
|
||||
emoticons.append(emoticonList);
|
||||
}
|
||||
|
||||
// success!
|
||||
loadingMutex.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString SmileyPack::smileyfied(QString msg)
|
||||
/**
|
||||
* @brief Replaces all found text emoticons to HTML reference with its according icon filename
|
||||
* @param msg Message where to search for emoticons
|
||||
* @return Formatted copy of message
|
||||
*/
|
||||
QString SmileyPack::smileyfied(const QString& msg)
|
||||
{
|
||||
QMutexLocker locker(&loadingMutex);
|
||||
|
||||
QRegExp exp("\\S+"); // matches words
|
||||
|
||||
int index = msg.indexOf(exp);
|
||||
|
||||
// if a word is key of a smiley, replace it by its corresponding image in Rich Text
|
||||
while (index >= 0) {
|
||||
QString key = exp.cap();
|
||||
if (filenameTable.contains(key)) {
|
||||
QString result(msg);
|
||||
QRegularExpression exp("\\S+");
|
||||
QRegularExpressionMatchIterator iter = exp.globalMatch(result);
|
||||
int replaceDiff = 0;
|
||||
while (iter.hasNext()) {
|
||||
QRegularExpressionMatch match = iter.next();
|
||||
QString key = match.captured();
|
||||
int startPos = match.capturedStart();
|
||||
int keyLength = key.length();
|
||||
if (emoticonToIcon.contains(key)) {
|
||||
QString imgRichText = getAsRichText(key);
|
||||
|
||||
msg.replace(index, key.length(), imgRichText);
|
||||
index += imgRichText.length() - key.length();
|
||||
result.replace(startPos + replaceDiff, keyLength, imgRichText);
|
||||
replaceDiff += imgRichText.length() - keyLength;
|
||||
}
|
||||
index = msg.indexOf(exp, index + key.length());
|
||||
}
|
||||
|
||||
return msg;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all emoticons that was extracted from files, grouped by according icon file
|
||||
*/
|
||||
QList<QStringList> SmileyPack::getEmoticons() const
|
||||
{
|
||||
QMutexLocker locker(&loadingMutex);
|
||||
return emoticons;
|
||||
}
|
||||
|
||||
QString SmileyPack::getAsRichText(const QString& key)
|
||||
{
|
||||
return QString("<img title=\"%1\" src=\"key:%1\"\\>").arg(key);
|
||||
}
|
||||
|
||||
QIcon SmileyPack::getAsIcon(const QString& key)
|
||||
/**
|
||||
* @brief Gets icon accoring to passed emoticon
|
||||
* @param emoticon Passed emoticon
|
||||
* @return Returns cached icon according to passed emoticon, null if no icon mapped to this emoticon
|
||||
*/
|
||||
QIcon SmileyPack::getAsIcon(const QString& emoticon)
|
||||
{
|
||||
QMutexLocker locker(&loadingMutex);
|
||||
return getCachedSmiley(key);
|
||||
}
|
||||
|
||||
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);
|
||||
return emoticonToIcon.contains(emoticon) ? *(emoticonToIcon[emoticon]) : QIcon();
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
|
@ -20,12 +20,9 @@
|
|||
#ifndef SMILEYPACK_H
|
||||
#define SMILEYPACK_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QIcon>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class SmileyPack : public QObject
|
||||
{
|
||||
|
@ -35,11 +32,9 @@ public:
|
|||
static SmileyPack& getInstance();
|
||||
static QList<QPair<QString, QString>> listSmileyPacks(const QStringList& paths);
|
||||
static QList<QPair<QString, QString>> listSmileyPacks();
|
||||
static bool isValid(const QString& filename);
|
||||
|
||||
QString smileyfied(QString msg);
|
||||
QString smileyfied(const QString& msg);
|
||||
QList<QStringList> getEmoticons() const;
|
||||
QString getAsRichText(const QString& key);
|
||||
QIcon getAsIcon(const QString& key);
|
||||
|
||||
private slots:
|
||||
|
@ -51,15 +46,11 @@ private:
|
|||
SmileyPack& operator=(const SmileyPack&) = delete;
|
||||
|
||||
bool load(const QString& filename);
|
||||
void cacheSmiley(const QString& name);
|
||||
QIcon getCachedSmiley(const QString& key);
|
||||
static QStringList loadDefaultPaths();
|
||||
|
||||
QHash<QString, QString> filenameTable;
|
||||
QHash<QString, QIcon> iconCache;
|
||||
QVector<QIcon> icons;
|
||||
QMap<QString, const QIcon*> emoticonToIcon;
|
||||
QList<QStringList> emoticons;
|
||||
QString path;
|
||||
static QStringList defaultPaths;
|
||||
mutable QMutex loadingMutex;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user