squawk/shared/global.cpp
2024-12-14 01:53:04 +02:00

428 lines
18 KiB
C++

/*
* Squawk messenger.
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "global.h"
#include <QFontDatabase>
#include "defines.h"
#include "enums.h"
#include "ui/models/roster.h"
#ifdef WITH_OMEMO
constexpr bool OMEMO_SUPPORT = true;
#else
constexpr bool OMEMO_SUPPORT = false;
#endif
QFont getFont (QFontDatabase::SystemFont type, bool bold = false, bool italic = false, qreal factor = 1.0) {
QFont font = QFontDatabase::systemFont(type);
if (bold)
font.setBold(true);
if (italic)
font.setItalic(true);
if (factor != 1.0) {
float ps = font.pointSizeF();
if (ps != -1)
font.setPointSizeF(ps * factor);
else
font.setPointSize(font.pointSize() * factor);
}
return font;
}
Shared::Global* Shared::Global::instance = 0;
const std::set<QString> Shared::Global::supportedImagesExts = {"png", "jpg", "webp", "jpeg", "gif", "svg"};
#ifdef WITH_KIO
QLibrary Shared::Global::openFileManagerWindowJob(QString("%1/openFileManagerWindowJob").arg(PLUGIN_PATH));
Shared::Global::HighlightInFileManager Shared::Global::hfm = 0;
#endif
#ifdef WITH_KCONFIG
QLibrary Shared::Global::colorSchemeTools(QString("%1/colorSchemeTools").arg(PLUGIN_PATH));
Shared::Global::CreatePreview Shared::Global::createPreview = 0;
Shared::Global::DeletePreview Shared::Global::deletePreview = 0;
Shared::Global::ColorSchemeName Shared::Global::colorSchemeName = 0;
Shared::Global::CreatePalette Shared::Global::createPalette = 0;
#endif
Shared::Global::Global():
availability({
QCoreApplication::translate("Global", "Online", "Availability"),
QCoreApplication::translate("Global", "Away", "Availability"),
QCoreApplication::translate("Global", "Absent", "Availability"),
QCoreApplication::translate("Global", "Busy", "Availability"),
QCoreApplication::translate("Global", "Chatty", "Availability"),
QCoreApplication::translate("Global", "Invisible", "Availability"),
QCoreApplication::translate("Global", "Offline", "Availability")
}),
connectionState({
QCoreApplication::translate("Global", "Disconnected", "ConnectionState"),
QCoreApplication::translate("Global", "Scheduled", "ConnectionState"),
QCoreApplication::translate("Global", "Connecting", "ConnectionState"),
QCoreApplication::translate("Global", "Connected", "ConnectionState"),
QCoreApplication::translate("Global", "Error", "ConnectionState")
}),
subscriptionState({
QCoreApplication::translate("Global", "None", "SubscriptionState"),
QCoreApplication::translate("Global", "From", "SubscriptionState"),
QCoreApplication::translate("Global", "To", "SubscriptionState"),
QCoreApplication::translate("Global", "Both", "SubscriptionState"),
QCoreApplication::translate("Global", "Unknown", "SubscriptionState")
}),
affiliation({
QCoreApplication::translate("Global", "Unspecified", "Affiliation"),
QCoreApplication::translate("Global", "Outcast", "Affiliation"),
QCoreApplication::translate("Global", "Nobody", "Affiliation"),
QCoreApplication::translate("Global", "Member", "Affiliation"),
QCoreApplication::translate("Global", "Admin", "Affiliation"),
QCoreApplication::translate("Global", "Owner", "Affiliation")
}),
role({
QCoreApplication::translate("Global", "Unspecified", "Role"),
QCoreApplication::translate("Global", "Nobody", "Role"),
QCoreApplication::translate("Global", "Visitor", "Role"),
QCoreApplication::translate("Global", "Participant", "Role"),
QCoreApplication::translate("Global", "Moderator", "Role")
}),
messageState({
QCoreApplication::translate("Global", "Pending", "MessageState"),
QCoreApplication::translate("Global", "Sent", "MessageState"),
QCoreApplication::translate("Global", "Delivered", "MessageState"),
QCoreApplication::translate("Global", "Error", "MessageState")
}),
accountPassword({
QCoreApplication::translate("Global", "Plain", "AccountPassword"),
QCoreApplication::translate("Global", "Jammed", "AccountPassword"),
QCoreApplication::translate("Global", "Always Ask", "AccountPassword"),
QCoreApplication::translate("Global", "KWallet", "AccountPassword")
}),
trustLevel({
QCoreApplication::translate("Global", "Undecided", "TrustLevel"),
QCoreApplication::translate("Global", "Automatically distrusted", "TrustLevel"),
QCoreApplication::translate("Global", "Manually distrusted", "TrustLevel"),
QCoreApplication::translate("Global", "Automatically trusted", "TrustLevel"),
QCoreApplication::translate("Global", "Manually trusted", "TrustLevel"),
QCoreApplication::translate("Global", "Authenticated", "TrustLevel")
}),
encryptionProtocols({
QCoreApplication::translate("Global", "None", "EncryptionProtocol"),
QCoreApplication::translate("Global", "OMEMO 0", "EncryptionProtocol"),
QCoreApplication::translate("Global", "OMEMO 1", "EncryptionProtocol"),
QCoreApplication::translate("Global", "OMEMO 2", "EncryptionProtocol")
}),
accountPasswordDescription({
QCoreApplication::translate("Global", "Your password is going to be stored in config file in plain text", "AccountPasswordDescription"),
QCoreApplication::translate("Global", "Your password is going to be stored in config file but jammed with constant encryption key you can find in program source code. It might look like encryption but it's not", "AccountPasswordDescription"),
QCoreApplication::translate("Global", "Squawk is going to query you for the password on every start of the program", "AccountPasswordDescription"),
QCoreApplication::translate("Global", "Your password is going to be stored in KDE wallet storage (KWallet). You're going to be queried for permissions", "AccountPasswordDescription")
}),
defaultSystemStyle(QApplication::style()->objectName()),
defaultSystemPalette(QApplication::palette()),
omemoSupport(OMEMO_SUPPORT),
defaultFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)),
monospaceFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)),
smallFont(getFont(QFontDatabase::SmallestReadableFont, false, true)),
headerFont(getFont(QFontDatabase::TitleFont, true, false, 1.1)),
titleFont(getFont(QFontDatabase::TitleFont, true, false, 1.3)),
defaultFontMetrics(defaultFont),
monospaceMetrics(monospaceFont),
smallFontMetrics(smallFont),
headerFontMetrics(headerFont),
titleFontMetrics(titleFont),
optionalFeatures({
{"KWallet", false},
{"openFileManagerWindowJob", false},
{"colorSchemeTools", false}
}),
fileCache()
{
if (instance != 0) {
throw 551;
}
instance = this;
#ifdef WITH_KIO
openFileManagerWindowJob.load();
if (openFileManagerWindowJob.isLoaded()) {
hfm = (HighlightInFileManager) openFileManagerWindowJob.resolve("highlightInFileManager");
if (hfm) {
setSupported("openFileManagerWindowJob", true);
qDebug() << "KIO::OpenFileManagerWindow support enabled";
} else {
qDebug() << "KIO::OpenFileManagerWindow support disabled: couldn't resolve required methods in the library";
}
} else {
qDebug() << "KIO::OpenFileManagerWindow support disabled: couldn't load the library" << openFileManagerWindowJob.errorString();
}
#endif
#ifdef WITH_KCONFIG
colorSchemeTools.load();
if (colorSchemeTools.isLoaded()) {
createPreview = (CreatePreview) colorSchemeTools.resolve("createPreview");
deletePreview = (DeletePreview) colorSchemeTools.resolve("deletePreview");
colorSchemeName = (ColorSchemeName) colorSchemeTools.resolve("colorSchemeName");
createPalette = (CreatePalette) colorSchemeTools.resolve("createPalette");
if (createPreview && deletePreview && colorSchemeName && createPalette) {
setSupported("colorSchemeTools", true);
qDebug() << "Color Schemes support enabled";
} else {
qDebug() << "Color Schemes support disabled: couldn't resolve required methods in the library";
}
} else {
qDebug() << "Color Schemes support disabled: couldn't load the library" << colorSchemeTools.errorString();
}
#endif
}
static const QSize defaultIconFileInfoHeight(50, 50);
Shared::Global::FileInfo Shared::Global::getFileInfo(const QString& path) {
std::map<QString, FileInfo>::const_iterator itr = instance->fileCache.find(path);
if (itr == instance->fileCache.end()) {
QMimeDatabase db;
QMimeType type = db.mimeTypeForFile(path);
QStringList parts = type.name().split("/");
QString big = parts.front();
QFileInfo info(path);
FileInfo::Preview p = FileInfo::Preview::none;
QSize size;
if (big == "image") {
QMovie mov(path);
if (mov.isValid() && mov.frameCount() > 1) {
p = FileInfo::Preview::animation;
} else {
p = FileInfo::Preview::picture;
}
QImageReader img(path);
size = img.size();
// } else if (big == "video") {
// p = FileInfo::Preview::movie;
// QMovie mov(path);
// size = mov.scaledSize();
// qDebug() << mov.isValid();
} else {
size = defaultIconFileInfoHeight;
}
itr = instance->fileCache.insert(std::make_pair(path, FileInfo({info.absoluteFilePath(), info.fileName(), size, type, p}))).first;
}
return itr->second;
}
Shared::Global * Shared::Global::getInstance() {
return instance;
}
QString Shared::Global::getName(Message::State rl) {
return instance->messageState[static_cast<int>(rl)];
}
QString Shared::Global::getName(Shared::Affiliation af) {
return instance->affiliation[static_cast<int>(af)];
}
QString Shared::Global::getName(Shared::Availability av) {
return instance->availability[static_cast<int>(av)];
}
QString Shared::Global::getName(Shared::ConnectionState cs) {
return instance->connectionState[static_cast<int>(cs)];
}
QString Shared::Global::getName(Shared::Role rl) {
return instance->role[static_cast<int>(rl)];
}
QString Shared::Global::getName(Shared::SubscriptionState ss) {
return instance->subscriptionState[static_cast<int>(ss)];
}
QString Shared::Global::getName(Shared::AccountPassword ap) {
return instance->accountPassword[static_cast<int>(ap)];
}
QString Shared::Global::getName(Shared::TrustLevel tl) {
return instance->trustLevel[static_cast<int>(tl)];
}
QString Shared::Global::getName(EncryptionProtocol ep) {
return instance->encryptionProtocols[static_cast<int>(ep)];
}
void Shared::Global::setSupported(const QString& pluginName, bool support) {
std::map<QString, bool>::iterator itr = instance->optionalFeatures.find(pluginName);
if (itr != instance->optionalFeatures.end()) {
itr->second = support;
}
}
bool Shared::Global::supported(const QString& pluginName) {
std::map<QString, bool>::iterator itr = instance->optionalFeatures.find(pluginName);
if (itr != instance->optionalFeatures.end())
return itr->second;
return false;
}
QString Shared::Global::getDescription(Shared::AccountPassword ap) {
return instance->accountPasswordDescription[static_cast<int>(ap)];
}
static const QStringList query = {"query", "default", "inode/directory"};
static const QRegularExpression dolphinReg("[Dd]olphin");
static const QRegularExpression nautilusReg("[Nn]autilus");
static const QRegularExpression cajaReg("[Cc]aja");
static const QRegularExpression nemoReg("[Nn]emo");
static const QRegularExpression konquerorReg("kfmclient");
static const QRegularExpression pcmanfmQtReg("pcmanfm-qt");
static const QRegularExpression pcmanfmReg("pcmanfm");
static const QRegularExpression thunarReg("thunar");
void Shared::Global::highlightInFileManager(const QString& path)
{
#ifdef WITH_KIO
if (supported("openFileManagerWindowJob")) {
hfm(path);
return;
} else {
qDebug() << "requested to highlight in file manager url" << path << "but it's not supported: KIO plugin isn't loaded, trying fallback";
}
#else
qDebug() << "requested to highlight in file manager url" << path << "but it's not supported: squawk wasn't compiled to support it, trying fallback";
#endif
QFileInfo info(path);
if (info.exists()) {
QProcess proc;
proc.start("xdg-mime", query);
proc.waitForFinished();
QString output = proc.readLine().simplified();
QString folder;
if (info.isDir())
folder = info.canonicalFilePath();
else
folder = info.canonicalPath();
if (output.contains(dolphinReg)) {
//there is a bug on current (21.04.0) dolphin, it works correct only if you already have dolphin launched
proc.startDetached("dolphin", QStringList() << "--select" << info.canonicalFilePath());
//KIO::highlightInFileManager({QUrl(info.canonicalFilePath())});
} else if (output.contains(nautilusReg)) {
proc.startDetached("nautilus", QStringList() << "--select" << info.canonicalFilePath()); //this worked on nautilus
} else if (output.contains(cajaReg)) {
proc.startDetached("caja", QStringList() << folder); //caja doesn't seem to support file selection command line, gonna just open directory
} else if (output.contains(nemoReg)) {
proc.startDetached("nemo", QStringList() << info.canonicalFilePath()); //nemo supports selecting files without keys
} else if (output.contains(konquerorReg)) {
proc.startDetached("konqueror", QStringList() << "--select" << info.canonicalFilePath()); //this worked on konqueror
} else if (output.contains(pcmanfmQtReg)) {
proc.startDetached("pcmanfm-qt", QStringList() << folder); //pcmanfm-qt doesn't seem to support open with selection, gonna just open directory
} else if (output.contains(pcmanfmReg)) {
proc.startDetached("pcmanfm", QStringList() << folder); //pcmanfm also doesn't seem to support open with selection, gonna just open directory
} else if (output.contains(thunarReg)) {
proc.startDetached("thunar", QStringList() << folder); //thunar doesn't seem to support open with selection, gonna just open directory
} else {
QDesktopServices::openUrl(QUrl::fromLocalFile(folder));
}
}
}
QIcon Shared::Global::createThemePreview(const QString& path) {
#ifdef WITH_KCONFIG
if (supported("colorSchemeTools")) {
QIcon* icon = createPreview(path);
QIcon localIcon = *icon;
deletePreview(icon);
return localIcon;
}
#endif
return QIcon();
}
QString Shared::Global::getColorSchemeName(const QString& path) {
#ifdef WITH_KCONFIG
if (supported("colorSchemeTools")) {
QString res;
colorSchemeName(path, res);
return res;
}
#endif
return "";
}
void Shared::Global::setTheme(const QString& path) {
#ifdef WITH_KCONFIG
if (supported("colorSchemeTools")) {
if (path.toLower() == "system") {
QApplication::setPalette(getInstance()->defaultSystemPalette);
} else {
QPalette pallete;
createPalette(path, pallete);
QApplication::setPalette(pallete);
}
}
#else
SHARED_UNUSED(path);
qDebug("setTheme() was called, but this version of squawk was compiled without KConfig support, ignoring");
#endif
}
void Shared::Global::setStyle(const QString& style) {
if (style.toLower() == "system")
QApplication::setStyle(getInstance()->defaultSystemStyle);
else
QApplication::setStyle(style);
}
#define FROM_INT_INPL(Enum) \
template<> \
Enum Shared::Global::fromInt(int src) \
{ \
if (src < static_cast<int>(Enum##Lowest) || src > static_cast<int>(Enum##Highest)) \
throw EnumOutOfRange(#Enum); \
\
return static_cast<Enum>(src); \
} \
template<> \
Enum Shared::Global::fromInt(unsigned int src) {return fromInt<Enum>(static_cast<int>(src));}
FROM_INT_INPL(Shared::Message::State)
FROM_INT_INPL(Shared::Affiliation)
FROM_INT_INPL(Shared::ConnectionState)
FROM_INT_INPL(Shared::Role)
FROM_INT_INPL(Shared::SubscriptionState)
FROM_INT_INPL(Shared::AccountPassword)
FROM_INT_INPL(Shared::Avatar)
FROM_INT_INPL(Shared::Availability)
FROM_INT_INPL(Shared::TrustLevel)
FROM_INT_INPL(Shared::EncryptionProtocol)