424 lines
15 KiB
C++
424 lines
15 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 "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("openFileManagerWindowJob");
|
|
Shared::Global::HighlightInFileManager Shared::Global::hfm = 0;
|
|
#endif
|
|
|
|
#ifdef WITH_KCONFIG
|
|
QLibrary Shared::Global::colorSchemeTools("colorSchemeTools");
|
|
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({
|
|
tr("Online", "Availability"),
|
|
tr("Away", "Availability"),
|
|
tr("Absent", "Availability"),
|
|
tr("Busy", "Availability"),
|
|
tr("Chatty", "Availability"),
|
|
tr("Invisible", "Availability"),
|
|
tr("Offline", "Availability")
|
|
}),
|
|
connectionState({
|
|
tr("Disconnected", "ConnectionState"),
|
|
tr("Scheduled", "ConnectionState"),
|
|
tr("Connecting", "ConnectionState"),
|
|
tr("Connected", "ConnectionState"),
|
|
tr("Error", "ConnectionState")
|
|
}),
|
|
subscriptionState({
|
|
tr("None", "SubscriptionState"),
|
|
tr("From", "SubscriptionState"),
|
|
tr("To", "SubscriptionState"),
|
|
tr("Both", "SubscriptionState"),
|
|
tr("Unknown", "SubscriptionState")
|
|
}),
|
|
affiliation({
|
|
tr("Unspecified", "Affiliation"),
|
|
tr("Outcast", "Affiliation"),
|
|
tr("Nobody", "Affiliation"),
|
|
tr("Member", "Affiliation"),
|
|
tr("Admin", "Affiliation"),
|
|
tr("Owner", "Affiliation")
|
|
}),
|
|
role({
|
|
tr("Unspecified", "Role"),
|
|
tr("Nobody", "Role"),
|
|
tr("Visitor", "Role"),
|
|
tr("Participant", "Role"),
|
|
tr("Moderator", "Role")
|
|
}),
|
|
messageState({
|
|
tr("Pending", "MessageState"),
|
|
tr("Sent", "MessageState"),
|
|
tr("Delivered", "MessageState"),
|
|
tr("Error", "MessageState")
|
|
}),
|
|
accountPassword({
|
|
tr("Plain", "AccountPassword"),
|
|
tr("Jammed", "AccountPassword"),
|
|
tr("Always Ask", "AccountPassword"),
|
|
tr("KWallet", "AccountPassword")
|
|
}),
|
|
trustLevel({
|
|
tr("Undecided", "TrustLevel"),
|
|
tr("Automatically distrusted", "TrustLevel"),
|
|
tr("Manually distrusted", "TrustLevel"),
|
|
tr("Automatically trusted", "TrustLevel"),
|
|
tr("Manually trusted", "TrustLevel"),
|
|
tr("Authenticated", "TrustLevel")
|
|
}),
|
|
accountPasswordDescription({
|
|
tr("Your password is going to be stored in config file in plain text", "AccountPasswordDescription"),
|
|
tr("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"),
|
|
tr("Squawk is going to query you for the password on every start of the program", "AccountPasswordDescription"),
|
|
tr("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),
|
|
pluginSupport({
|
|
{"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)];
|
|
}
|
|
|
|
void Shared::Global::setSupported(const QString& pluginName, bool support)
|
|
{
|
|
std::map<QString, bool>::iterator itr = instance->pluginSupport.find(pluginName);
|
|
if (itr != instance->pluginSupport.end()) {
|
|
itr->second = support;
|
|
}
|
|
}
|
|
|
|
bool Shared::Global::supported(const QString& pluginName)
|
|
{
|
|
std::map<QString, bool>::iterator itr = instance->pluginSupport.find(pluginName);
|
|
if (itr != instance->pluginSupport.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)
|
|
{
|
|
if (supported("colorSchemeTools")) {
|
|
QIcon* icon = createPreview(path);
|
|
QIcon localIcon = *icon;
|
|
deletePreview(icon);
|
|
return localIcon;
|
|
} else {
|
|
return QIcon();
|
|
}
|
|
}
|
|
|
|
QString Shared::Global::getColorSchemeName(const QString& path)
|
|
{
|
|
if (supported("colorSchemeTools")) {
|
|
QString res;
|
|
colorSchemeName(path, res);
|
|
return res;
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
void Shared::Global::setTheme(const QString& path)
|
|
{
|
|
if (supported("colorSchemeTools")) {
|
|
if (path.toLower() == "system") {
|
|
QApplication::setPalette(getInstance()->defaultSystemPalette);
|
|
} else {
|
|
QPalette pallete;
|
|
createPalette(path, pallete);
|
|
QApplication::setPalette(pallete);
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|