refactor(log): Convert LogLevel into a class using LogLevel::Level as its enum, store values as the Option string display as localized string'

This commit is contained in:
sithlord48 2026-05-10 10:44:44 -04:00 committed by Nick Bolton
parent b0413ed4ff
commit acf865fa11
38 changed files with 398 additions and 120 deletions

View file

@ -1,6 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers * SPDX-FileCopyrightText: (C) 2025 - 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -41,6 +41,6 @@ public:
/*! /*!
Writes the given string to the log with the given level. Writes the given string to the log with the given level.
*/ */
virtual void writeLog(LogLevel, const QString &) = 0; virtual void writeLog(LogLevel::Level, const QString &) = 0;
//@} //@}
}; };

View file

@ -1,5 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -23,12 +24,12 @@ void ArchLogUnix::closeLog()
closelog(); closelog();
} }
void ArchLogUnix::writeLog(LogLevel level, const QString &msg) void ArchLogUnix::writeLog(LogLevel::Level level, const QString &msg)
{ {
// convert level // convert level
int priority; int priority;
switch (level) { switch (level) {
using enum LogLevel; using enum LogLevel::Level;
case Error: case Error:
priority = LOG_ERR; priority = LOG_ERR;
break; break;

View file

@ -1,5 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -21,5 +22,5 @@ public:
// IArchLog overrides // IArchLog overrides
void openLog(const QString &name) override; void openLog(const QString &name) override;
void closeLog() override; void closeLog() override;
void writeLog(LogLevel, const QString &) override; void writeLog(LogLevel::Level, const QString &) override;
}; };

View file

@ -1,5 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -33,17 +34,17 @@ void ArchLogWindows::closeLog()
} }
} }
void ArchLogWindows::writeLog(LogLevel level, const QString &msg) void ArchLogWindows::writeLog(LogLevel::Level level, const QString &msg)
{ {
if (m_eventLog != nullptr) { if (m_eventLog != nullptr) {
// convert priority // convert priority
WORD type; WORD type;
switch (level) { switch (level) {
case LogLevel::Error: case LogLevel::Level::Error:
type = EVENTLOG_ERROR_TYPE; type = EVENTLOG_ERROR_TYPE;
break; break;
case LogLevel::Warning: case LogLevel::Level::Warning:
type = EVENTLOG_WARNING_TYPE; type = EVENTLOG_WARNING_TYPE;
break; break;

View file

@ -1,5 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -24,7 +25,7 @@ public:
// IArchLog overrides // IArchLog overrides
void openLog(const QString &name) override; void openLog(const QString &name) override;
void closeLog() override; void closeLog() override;
void writeLog(LogLevel, const QString &) override; void writeLog(LogLevel::Level, const QString &) override;
private: private:
HANDLE m_eventLog; HANDLE m_eventLog;

View file

@ -1,6 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers * SPDX-FileCopyrightText: (C) 2025 - 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -46,7 +46,7 @@ public:
message to all outputters in the outputter chain, otherwise message to all outputters in the outputter chain, otherwise
it continues. Most implementations should return true. it continues. Most implementations should return true.
*/ */
virtual bool write(LogLevel level, const QString &message) = 0; virtual bool write(LogLevel::Level level, const QString &message) = 0;
//@} //@}
}; };

View file

@ -1,5 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -36,14 +37,14 @@ static const int g_numPriority = 6;
// for visual studio, then NDEBUG will be set (even if your VS solution // for visual studio, then NDEBUG will be set (even if your VS solution
// config is Debug). // config is Debug).
#ifndef NDEBUG #ifndef NDEBUG
static const LogLevel g_defaultMaxPriority = LogLevel::Debug; static const auto g_defaultMaxPriority = LogLevel::Level::Debug;
#else #else
static const LogLevel g_defaultMaxPriority = LogLevel::Info; static const auto g_defaultMaxPriority = LogLevel::Level::Info;
#endif #endif
namespace { namespace {
LogLevel getPriority(const char *&fmt) LogLevel::Level getPriority(const char *&fmt)
{ {
if (strnlen(fmt, SIZE_MAX) < kPriorityPrefixLength) { if (strnlen(fmt, SIZE_MAX) < kPriorityPrefixLength) {
throw std::invalid_argument("invalid format string, too short"); throw std::invalid_argument("invalid format string, too short");
@ -53,10 +54,10 @@ LogLevel getPriority(const char *&fmt)
throw std::invalid_argument("invalid format string, missing priority"); throw std::invalid_argument("invalid format string, missing priority");
} }
return static_cast<LogLevel>(fmt[2] - '0'); return static_cast<LogLevel::Level>(fmt[2] - '0');
} }
std::vector<char> makeMessage(const char *filename, int lineNumber, const char *message, LogLevel priority) std::vector<char> makeMessage(const char *filename, int lineNumber, const char *message, LogLevel::Level priority)
{ {
// base size includes null terminator, colon, space, etc. // base size includes null terminator, colon, space, etc.
@ -150,7 +151,7 @@ const char *Log::getFilterName() const
return getFilterName(getFilter()); return getFilterName(getFilter());
} }
const char *Log::getFilterName(LogLevel level) const const char *Log::getFilterName(LogLevel::Level level) const
{ {
const auto levelIndex = static_cast<int>(level); const auto levelIndex = static_cast<int>(level);
if (levelIndex < 0) { if (levelIndex < 0) {
@ -164,7 +165,7 @@ void Log::print(const char *file, int line, const char *fmt, ...)
const int initBufferSize = 1024; const int initBufferSize = 1024;
const int bufferResizeScale = 2; const int bufferResizeScale = 2;
LogLevel priority = getPriority(fmt); const auto priority = getPriority(fmt);
fmt += kPriorityPrefixLength; fmt += kPriorityPrefixLength;
if (priority > getFilter()) { if (priority > getFilter()) {
@ -188,7 +189,7 @@ void Log::print(const char *file, int line, const char *fmt, ...)
} }
} }
if (priority == LogLevel::Print) { if (priority == LogLevel::Level::Print) {
output(priority, buffer.data()); output(priority, buffer.data());
} else { } else {
auto message = makeMessage(file, line, buffer.data(), priority); auto message = makeMessage(file, line, buffer.data(), priority);
@ -235,26 +236,26 @@ bool Log::setFilter(const QString &maxPriority)
for (int i = 0; i < g_numPriority; ++i) { for (int i = 0; i < g_numPriority; ++i) {
if (maxPriority == QString(g_priority[i])) { if (maxPriority == QString(g_priority[i])) {
setFilter(static_cast<LogLevel>(i)); setFilter(static_cast<LogLevel::Level>(i));
return true; return true;
} }
} }
return false; return false;
} }
void Log::setFilter(LogLevel maxPriority) void Log::setFilter(LogLevel::Level maxPriority)
{ {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
m_maxPriority = maxPriority; m_maxPriority = maxPriority;
} }
LogLevel Log::getFilter() const LogLevel::Level Log::getFilter() const
{ {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
return m_maxPriority; return m_maxPriority;
} }
void Log::output(LogLevel priority, const char *msg) void Log::output(LogLevel::Level priority, const char *msg)
{ {
assert(static_cast<int>(priority) >= -2 && static_cast<int>(priority) < g_numPriority); assert(static_cast<int>(priority) >= -2 && static_cast<int>(priority) < g_numPriority);
assert(msg != nullptr); assert(msg != nullptr);

View file

@ -1,5 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers.
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -88,7 +89,7 @@ public:
bool setFilter(const QString &name); bool setFilter(const QString &name);
//! Set the minimum priority filter (by ordinal). //! Set the minimum priority filter (by ordinal).
void setFilter(LogLevel); void setFilter(LogLevel::Level);
//@} //@}
//! @name accessors //! @name accessors
@ -103,28 +104,28 @@ public:
void print(const char *file, int line, const char *format, ...); void print(const char *file, int line, const char *format, ...);
//! Get the minimum priority level. //! Get the minimum priority level.
LogLevel getFilter() const; LogLevel::Level getFilter() const;
//! Get the filter name of the current filter level. //! Get the filter name of the current filter level.
const char *getFilterName() const; const char *getFilterName() const;
//! Get the filter name of a specified filter level. //! Get the filter name of a specified filter level.
const char *getFilterName(LogLevel level) const; const char *getFilterName(LogLevel::Level level) const;
//! Get the singleton instance of the log //! Get the singleton instance of the log
static Log *getInstance(); static Log *getInstance();
//! Get the console filter level (messages above this are not sent to //! Get the console filter level (messages above this are not sent to
//! console). //! console).
LogLevel getConsoleMaxLevel() const LogLevel::Level getConsoleMaxLevel() const
{ {
return LogLevel::Verbose; return LogLevel::Level::Verbose;
} }
//@} //@}
private: private:
void output(LogLevel priority, const char *msg); void output(LogLevel::Level priority, const char *msg);
private: private:
using OutputterList = std::list<ILogOutputter *>; using OutputterList = std::list<ILogOutputter *>;
@ -134,7 +135,7 @@ private:
mutable std::mutex m_mutex; mutable std::mutex m_mutex;
OutputterList m_outputters; OutputterList m_outputters;
OutputterList m_alwaysOutputters; OutputterList m_alwaysOutputters;
LogLevel m_maxPriority; LogLevel::Level m_maxPriority;
}; };
/*! /*!

View file

@ -1,6 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers * SPDX-FileCopyrightText: (C) 2025 - 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -31,7 +31,7 @@ void StopLogOutputter::close()
// do nothing // do nothing
} }
bool StopLogOutputter::write(LogLevel, const QString &) bool StopLogOutputter::write(LogLevel::Level, const QString &)
{ {
return false; return false;
} }
@ -50,9 +50,10 @@ void ConsoleLogOutputter::close()
// do nothing // do nothing
} }
bool ConsoleLogOutputter::write(LogLevel level, const QString &msg) bool ConsoleLogOutputter::write(LogLevel::Level level, const QString &msg)
{ {
if ((level >= LogLevel::Fatal) && (level <= LogLevel::Warning)) using enum LogLevel::Level;
if ((level >= Fatal) && (level <= Warning))
std::cerr << qPrintable(msg) << std::endl; std::cerr << qPrintable(msg) << std::endl;
else else
std::cout << qPrintable(msg) << std::endl; std::cout << qPrintable(msg) << std::endl;
@ -79,7 +80,7 @@ void SystemLogOutputter::close()
ARCH->closeLog(); ARCH->closeLog();
} }
bool SystemLogOutputter::write(LogLevel level, const QString &msg) bool SystemLogOutputter::write(LogLevel::Level level, const QString &msg)
{ {
ARCH->writeLog(level, msg); ARCH->writeLog(level, msg);
return true; return true;
@ -126,7 +127,7 @@ void FileLogOutputter::setLogFilename(const QString &logFile)
m_fileName = logFile; m_fileName = logFile;
} }
bool FileLogOutputter::write(LogLevel, const QString &message) bool FileLogOutputter::write(LogLevel::Level, const QString &message)
{ {
QFile file(m_fileName); QFile file(m_fileName);
if (!file.open(QFile::WriteOnly | QFile::Append)) if (!file.open(QFile::WriteOnly | QFile::Append))

View file

@ -1,6 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers * SPDX-FileCopyrightText: (C) 2025 - 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -26,7 +26,7 @@ public:
// ILogOutputter overrides // ILogOutputter overrides
void open(const QString &title) override; void open(const QString &title) override;
void close() override; void close() override;
bool write(LogLevel level, const QString &message) override; bool write(LogLevel::Level level, const QString &message) override;
}; };
//! Write log to console //! Write log to console
@ -43,7 +43,7 @@ public:
// ILogOutputter overrides // ILogOutputter overrides
void open(const QString &title) override; void open(const QString &title) override;
void close() override; void close() override;
bool write(LogLevel level, const QString &message) override; bool write(LogLevel::Level level, const QString &message) override;
void flush() const; void flush() const;
}; };
@ -62,7 +62,7 @@ public:
// ILogOutputter overrides // ILogOutputter overrides
void open(const QString &title) override; void open(const QString &title) override;
void close() override; void close() override;
bool write(LogLevel level, const QString &message) override; bool write(LogLevel::Level level, const QString &message) override;
void setLogFilename(const QString &title); void setLogFilename(const QString &title);
@ -83,7 +83,7 @@ public:
// ILogOutputter overrides // ILogOutputter overrides
void open(const QString &title) override; void open(const QString &title) override;
void close() override; void close() override;
bool write(LogLevel level, const QString &message) override; bool write(LogLevel::Level level, const QString &message) override;
}; };
//! Write log to system log only //! Write log to system log only

View file

@ -1,23 +1,101 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/ */
#pragma once #pragma once
#include <QObject>
#include <QString>
//! Log levels class LogLevel : private QObject
/*!
The logging priority levels in order of highest to lowest priority.
*/
enum class LogLevel
{ {
Print = -1, //!< For print only (no file or time) Q_OBJECT
Fatal, //!< For fatal errors //! Log levels
Error, //!< For serious errors /*!
Warning, //!< For minor errors and warnings The logging priority levels in order of highest to lowest priority.
Info, //!< For informational messages */
Debug, //!< For important debugging messages public:
Verbose //!< For verbose debugging messages enum class Level
{
Print = -1, //!< For print only (no file or time)
Fatal, //!< For fatal errors
Error, //!< For serious errors
Warning, //!< For minor errors and warnings
Info, //!< For informational messages
Debug, //!< For important debugging messages
Verbose //!< For verbose debugging messages
};
Q_ENUM(Level)
static QString toOption(const LogLevel::Level &level)
{
return toOption(static_cast<int>(level));
}
static QString toOption(const int &level)
{
if (level < 0 || level > m_levelOptions.size())
return "";
return m_levelOptions.at(level);
}
static LogLevel::Level fromOption(const QString &level)
{
const auto index = m_levelOptions.indexOf(level, 0, Qt::CaseInsensitive);
if (index < 0 || index >= m_levelOptions.count())
return LogLevel::Level::Info;
return LogLevel::Level(index);
}
static QString toString(const LogLevel::Level &level)
{
return toString(static_cast<int>(level));
}
static QString toString(const int &level)
{
if (level < 0 || level > m_levelNames.size())
return "";
return tr(m_levelNames.at(level).toUtf8());
}
static QStringList logLevelOptions()
{
return m_levelOptions;
}
static QStringList logLevelNames()
{
return m_levelNames;
}
private:
// clang-format off
/**
* @brief m_levelOptions, Valid values for the log level options, Never translated
*/
inline static const QStringList m_levelOptions {
QStringLiteral("FATAL")
, QStringLiteral("ERROR")
, QStringLiteral("WARNING")
, QStringLiteral("INFO")
, QStringLiteral("DEBUG")
, QStringLiteral("VERBOSE")
};
/**
* @brief m_levelNames, Strings used to present level names to the user, Expected to be translated
*/
inline static const QStringList m_levelNames = {
QT_TR_NOOP("Fatal")
, QT_TR_NOOP("Error")
, QT_TR_NOOP("Warning")
, QT_TR_NOOP("Info")
, QT_TR_NOOP("Debug")
, QT_TR_NOOP("Verbose")
};
// clang-format on
}; };

View file

@ -6,6 +6,7 @@
#include "Settings.h" #include "Settings.h"
#include "LogLevel.h"
#include "NetworkProtocol.h" #include "NetworkProtocol.h"
#include "UrlConstants.h" #include "UrlConstants.h"
@ -95,6 +96,10 @@ Settings::Settings(QObject *parent) : QObject(parent)
void Settings::upgradeSettings() void Settings::upgradeSettings()
{ {
const auto logValue = m_settings->value(Settings::Log::Level).toString();
if (!LogLevel::logLevelOptions().contains(logValue, Qt::CaseInsensitive))
m_settings->setValue(Settings::Log::Level, defaultValue(Settings::Log::Level));
for (const auto [oldKey, newKey] : m_upgradedMap.asKeyValueRange()) { for (const auto [oldKey, newKey] : m_upgradedMap.asKeyValueRange()) {
if (m_settings->contains(oldKey) && !m_settings->contains(newKey)) { if (m_settings->contains(oldKey) && !m_settings->contains(newKey)) {
m_settings->setValue(newKey, m_settings->value(oldKey)); m_settings->setValue(newKey, m_settings->value(oldKey));
@ -156,13 +161,6 @@ QString Settings::cleanComputerName(const QString &name)
return cleanName; return cleanName;
} }
int Settings::logLevelToInt(const QString &level)
{
if (level.isEmpty() || !m_logLevels.contains(level, Qt::CaseInsensitive))
return 4;
return static_cast<int>(m_logLevels.indexOf(level, 0, Qt::CaseInsensitive));
}
QVariant Settings::defaultValue(const QString &key) QVariant Settings::defaultValue(const QString &key)
{ {
if (m_defaultFalseValues.contains(key)) if (m_defaultFalseValues.contains(key))
@ -181,7 +179,7 @@ QVariant Settings::defaultValue(const QString &key)
return QStringLiteral("%1/%2.log").arg(QDir::homePath(), kAppId); return QStringLiteral("%1/%2.log").arg(QDir::homePath(), kAppId);
if (key == Log::Level) if (key == Log::Level)
return 4; // INFO return QVariant::fromValue(LogLevel::Level::Info).toString();
if (key == Daemon::Elevate) if (key == Daemon::Elevate)
return !Settings::isPortableMode(); return !Settings::isPortableMode();
@ -215,11 +213,6 @@ QVariant Settings::defaultValue(const QString &key)
return QVariant(); return QVariant();
} }
QString Settings::logLevelText()
{
return Settings::m_logLevels.at(Settings::value(Log::Level).toInt());
}
QSettingsProxy &Settings::proxy() QSettingsProxy &Settings::proxy()
{ {
return *instance()->m_settingsProxy; return *instance()->m_settingsProxy;
@ -291,6 +284,11 @@ QString Settings::tlsTrustedClientsDb()
return QFileInfo(QStringLiteral("%1/trusted-clients").arg(instance()->tlsDir())).absoluteFilePath(); return QFileInfo(QStringLiteral("%1/trusted-clients").arg(instance()->tlsDir())).absoluteFilePath();
} }
QString Settings::logLevelText()
{
return Settings::value(Log::Level).toString();
}
void Settings::setValue(const QString &key, const QVariant &value) void Settings::setValue(const QString &key, const QVariant &value)
{ {
const bool useState = Settings::m_stateKeys.contains(key) && !instance()->isPortableMode(); const bool useState = Settings::m_stateKeys.contains(key) && !instance()->isPortableMode();

View file

@ -151,7 +151,6 @@ public:
static QSettingsProxy &proxy(); static QSettingsProxy &proxy();
static void save(bool emitSaving = true); static void save(bool emitSaving = true);
static QStringList validKeys(); static QStringList validKeys();
static int logLevelToInt(const QString &level);
static QString portableSettingsFile(); static QString portableSettingsFile();
Q_SIGNALS: Q_SIGNALS:
@ -190,15 +189,6 @@ private:
std::shared_ptr<QSettingsProxy> m_settingsProxy; std::shared_ptr<QSettingsProxy> m_settingsProxy;
// clang-format off // clang-format off
inline static const QStringList m_logLevels = {
QStringLiteral("FATAL")
, QStringLiteral("ERROR")
, QStringLiteral("WARNING")
, QStringLiteral("INFO")
, QStringLiteral("DEBUG")
, QStringLiteral("TRACE")
};
inline static const QStringList m_validKeys = { inline static const QStringList m_validKeys = {
Settings::Client::DynamicConnectionRetry Settings::Client::DynamicConnectionRetry
, Settings::Client::InvertYScroll , Settings::Client::InvertYScroll

View file

@ -7,6 +7,7 @@
*/ */
#include "SettingsDialog.h" #include "SettingsDialog.h"
#include "common/LogLevel.h"
#include "common/PlatformInfo.h" #include "common/PlatformInfo.h"
#include "ui_SettingsDialog.h" #include "ui_SettingsDialog.h"
@ -216,7 +217,9 @@ void SettingsDialog::accept()
{ {
Settings::setValue(Settings::Core::Port, ui->sbPort->value()); Settings::setValue(Settings::Core::Port, ui->sbPort->value());
Settings::setValue(Settings::Core::Interface, ui->comboInterface->currentData()); Settings::setValue(Settings::Core::Interface, ui->comboInterface->currentData());
Settings::setValue(Settings::Log::Level, ui->comboLogLevel->currentIndex()); Settings::setValue(
Settings::Log::Level, LogLevel::toOption(static_cast<LogLevel::Level>(ui->comboLogLevel->currentIndex()))
);
Settings::setValue(Settings::Log::ToFile, ui->groupLogToFile->isChecked()); Settings::setValue(Settings::Log::ToFile, ui->groupLogToFile->isChecked());
Settings::setValue(Settings::Log::File, ui->lineLogFilename->text()); Settings::setValue(Settings::Log::File, ui->lineLogFilename->text());
Settings::setValue(Settings::Daemon::Elevate, ui->cbElevateDaemon->isChecked()); Settings::setValue(Settings::Daemon::Elevate, ui->cbElevateDaemon->isChecked());
@ -251,7 +254,7 @@ void SettingsDialog::accept()
void SettingsDialog::loadFromConfig() void SettingsDialog::loadFromConfig()
{ {
ui->sbPort->setValue(Settings::value(Settings::Core::Port).toInt()); ui->sbPort->setValue(Settings::value(Settings::Core::Port).toInt());
ui->comboLogLevel->setCurrentIndex(Settings::value(Settings::Log::Level).toInt()); ui->comboLogLevel->setCurrentIndex(static_cast<int>(LogLevel::fromOption(Settings::logLevelText())));
ui->groupLogToFile->setChecked(Settings::value(Settings::Log::ToFile).toBool()); ui->groupLogToFile->setChecked(Settings::value(Settings::Log::ToFile).toBool());
ui->lineLogFilename->setText(Settings::value(Settings::Log::File).toString()); ui->lineLogFilename->setText(Settings::value(Settings::Log::File).toString());
ui->cbPreventSleep->setChecked(Settings::value(Settings::Core::PreventSleep).toBool()); ui->cbPreventSleep->setChecked(Settings::value(Settings::Core::PreventSleep).toBool());
@ -284,7 +287,9 @@ void SettingsDialog::loadFromConfig()
ui->rbCloseToTray->setChecked(closeToTray); ui->rbCloseToTray->setChecked(closeToTray);
ui->rbExitOnClose->setChecked(!closeToTray); ui->rbExitOnClose->setChecked(!closeToTray);
ui->lblDebugWarning->setVisible(Settings::value(Settings::Log::Level).toInt() > 3); ui->lblDebugWarning->setVisible(
Settings::value(Settings::Log::Level).toInt() > static_cast<int>(LogLevel::Level::Info)
);
ui->comboInterface->setCurrentText(Settings::value(Settings::Core::Interface).toString()); ui->comboInterface->setCurrentText(Settings::value(Settings::Core::Interface).toString());
if (ui->comboInterface->currentIndex() <= 0) { if (ui->comboInterface->currentIndex() <= 0) {
@ -409,7 +414,7 @@ void SettingsDialog::updateRequestedKeySize() const
void SettingsDialog::logLevelChanged() void SettingsDialog::logLevelChanged()
{ {
ui->lblDebugWarning->setVisible(ui->comboLogLevel->currentIndex() > 3); ui->lblDebugWarning->setVisible(ui->comboLogLevel->currentIndex() > static_cast<int>(LogLevel::Level::Info));
} }
bool SettingsDialog::isModified() const bool SettingsDialog::isModified() const
@ -419,7 +424,7 @@ bool SettingsDialog::isModified() const
bool modified = bool modified =
(ui->sbPort->value() != Settings::value(Settings::Core::Port).toInt()) || (ui->sbPort->value() != Settings::value(Settings::Core::Port).toInt()) ||
(ui->comboLogLevel->currentIndex() != Settings::value(Settings::Log::Level).toInt()) || (ui->comboLogLevel->currentIndex() != static_cast<int>(LogLevel::fromOption(Settings::logLevelText()))) ||
(ui->groupLogToFile->isChecked() != Settings::value(Settings::Log::ToFile).toBool()) || (ui->groupLogToFile->isChecked() != Settings::value(Settings::Log::ToFile).toBool()) ||
(ui->lineLogFilename->text() != Settings::value(Settings::Log::File).toString()) || (ui->lineLogFilename->text() != Settings::value(Settings::Log::File).toString()) ||
(ui->rbAutoHide->isChecked() != Settings::value(Settings::Gui::Autohide).toBool()) || (ui->rbAutoHide->isChecked() != Settings::value(Settings::Gui::Autohide).toBool()) ||
@ -450,10 +455,12 @@ bool SettingsDialog::isModified() const
bool SettingsDialog::isDefault() const bool SettingsDialog::isDefault() const
{ {
const auto processMode = Settings::defaultValue(Settings::Core::ProcessMode).value<Settings::ProcessMode>(); const auto processMode = Settings::defaultValue(Settings::Core::ProcessMode).value<Settings::ProcessMode>();
const auto logLevelIndex =
static_cast<int>(LogLevel::fromOption(Settings::defaultValue(Settings::Log::Level).toString()));
return ( return (
(ui->sbPort->value() == Settings::defaultValue(Settings::Core::Port).toInt()) && (ui->sbPort->value() == Settings::defaultValue(Settings::Core::Port).toInt()) &&
(ui->comboLogLevel->currentIndex() == Settings::defaultValue(Settings::Log::Level).toInt()) && (ui->comboLogLevel->currentIndex() == logLevelIndex) &&
(ui->groupLogToFile->isChecked() == Settings::defaultValue(Settings::Log::ToFile).toBool()) && (ui->groupLogToFile->isChecked() == Settings::defaultValue(Settings::Log::ToFile).toBool()) &&
(ui->lineLogFilename->text() == Settings::defaultValue(Settings::Log::File).toString()) && (ui->lineLogFilename->text() == Settings::defaultValue(Settings::Log::File).toString()) &&
(ui->rbAutoHide->isChecked() == Settings::defaultValue(Settings::Gui::Autohide).toBool()) && (ui->rbAutoHide->isChecked() == Settings::defaultValue(Settings::Gui::Autohide).toBool()) &&
@ -482,7 +489,9 @@ bool SettingsDialog::isDefault() const
void SettingsDialog::resetToDefault() void SettingsDialog::resetToDefault()
{ {
ui->sbPort->setValue(Settings::defaultValue(Settings::Core::Port).toInt()); ui->sbPort->setValue(Settings::defaultValue(Settings::Core::Port).toInt());
ui->comboLogLevel->setCurrentIndex(Settings::defaultValue(Settings::Log::Level).toInt()); ui->comboLogLevel->setCurrentIndex(
static_cast<int>(LogLevel::fromOption(Settings::defaultValue(Settings::Log::Level).toString()))
);
ui->groupLogToFile->setChecked(Settings::defaultValue(Settings::Log::ToFile).toBool()); ui->groupLogToFile->setChecked(Settings::defaultValue(Settings::Log::ToFile).toBool());
ui->lineLogFilename->setText(Settings::defaultValue(Settings::Log::File).toString()); ui->lineLogFilename->setText(Settings::defaultValue(Settings::Log::File).toString());
ui->cbPreventSleep->setChecked(Settings::defaultValue(Settings::Core::PreventSleep).toBool()); ui->cbPreventSleep->setChecked(Settings::defaultValue(Settings::Core::PreventSleep).toBool());

View file

@ -66,7 +66,7 @@ void logRemoteSecureCipherInfo(const SSL *ssl)
void SslLogger::logSecureLibInfo() void SslLogger::logSecureLibInfo()
{ {
if (CLOG->getFilter() >= LogLevel::Debug) { if (CLOG->getFilter() >= LogLevel::Level::Debug) {
LOG_DEBUG("openssl version: %s", SSLeay_version(SSLEAY_VERSION)); LOG_DEBUG("openssl version: %s", SSLeay_version(SSLEAY_VERSION));
LOG_VERBOSE("openssl flags: %s", SSLeay_version(SSLEAY_CFLAGS)); LOG_VERBOSE("openssl flags: %s", SSLeay_version(SSLEAY_CFLAGS));
LOG_VERBOSE("openssl built on: %s", SSLeay_version(SSLEAY_BUILT_ON)); LOG_VERBOSE("openssl built on: %s", SSLeay_version(SSLEAY_BUILT_ON));
@ -77,7 +77,7 @@ void SslLogger::logSecureLibInfo()
void SslLogger::logSecureCipherInfo(const SSL *ssl) void SslLogger::logSecureCipherInfo(const SSL *ssl)
{ {
if (ssl && CLOG->getFilter() >= LogLevel::Verbose) { if (ssl && CLOG->getFilter() >= LogLevel::Level::Verbose) {
logLocalSecureCipherInfo(ssl); logLocalSecureCipherInfo(ssl);
logRemoteSecureCipherInfo(ssl); logRemoteSecureCipherInfo(ssl);
} }

View file

@ -22,7 +22,7 @@ void MSWindowsDebugOutputter::close()
// do nothing // do nothing
} }
bool MSWindowsDebugOutputter::write(LogLevel level, const QString &msg) bool MSWindowsDebugOutputter::write(LogLevel::Level level, const QString &msg)
{ {
std::wstring out = msg.toStdWString() + L"\n"; std::wstring out = msg.toStdWString() + L"\n";
OutputDebugString(out.c_str()); OutputDebugString(out.c_str());

View file

@ -23,6 +23,6 @@ public:
// ILogOutputter overrides // ILogOutputter overrides
void open(const QString &title) override; void open(const QString &title) override;
void close() override; void close() override;
bool write(LogLevel level, const QString &message) override; bool write(LogLevel::Level level, const QString &message) override;
void flush(); void flush();
}; };

View file

@ -355,7 +355,7 @@ void MSWindowsWatchdog::outputLoop(const void *)
// The file log outputter adds its own newlines, so trim the decoded string to avoid double newlines. // The file log outputter adds its own newlines, so trim the decoded string to avoid double newlines.
const auto trimmed = decoded.trimmed(); const auto trimmed = decoded.trimmed();
m_fileLogOutputter.write(LogLevel::Print, trimmed); m_fileLogOutputter.write(LogLevel::Level::Print, trimmed);
if (m_foreground) { if (m_foreground) {
// Doesn't add it's own newlines, so use the original ones from the process output. // Doesn't add it's own newlines, so use the original ones from the process output.

View file

@ -5,10 +5,11 @@
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/ */
#include "platform/XWindowsClipboard.h"
#include "arch/Arch.h" #include "arch/Arch.h"
#include "base/Log.h" #include "base/Log.h"
#include "platform/XWindowsClipboard.h"
#include "base/Stopwatch.h" #include "base/Stopwatch.h"
#include "platform/XWindowsClipboardBMPConverter.h" #include "platform/XWindowsClipboardBMPConverter.h"
#include "platform/XWindowsClipboardHTMLConverter.h" #include "platform/XWindowsClipboardHTMLConverter.h"
@ -1000,7 +1001,7 @@ bool XWindowsClipboard::sendReply(Reply *reply)
reply->m_replied = true; reply->m_replied = true;
// nothing to log // nothing to log
if (CLOG->getFilter() < LogLevel::Verbose) { if (CLOG->getFilter() < LogLevel::Level::Verbose) {
sendNotify( sendNotify(
reply->m_requestor, m_selection, reply->m_target, reply->m_property, static_cast<unsigned int>(reply->m_time) reply->m_requestor, m_selection, reply->m_target, reply->m_property, static_cast<unsigned int>(reply->m_time)
); );

View file

@ -25,7 +25,7 @@ QString sanitizeBuffer(const std::stringstream &in)
void LogTests::initTestCase() void LogTests::initTestCase()
{ {
std::setlocale(LC_NUMERIC, "C"); std::setlocale(LC_NUMERIC, "C");
m_log.setFilter(LogLevel::Debug); m_log.setFilter(LogLevel::Level::Debug);
} }
void LogTests::printWithErrorValidOutput() void LogTests::printWithErrorValidOutput()

View file

@ -11,7 +11,7 @@
void UnicodeTests::initTestCase() void UnicodeTests::initTestCase()
{ {
m_log.setFilter(LogLevel::Verbose); m_log.setFilter(LogLevel::Level::Verbose);
} }
void UnicodeTests::UTF16ToUTF8() void UnicodeTests::UTF16ToUTF8()

View file

@ -8,6 +8,13 @@ create_test(
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/common" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/common"
) )
create_test(
NAME LogLevelTests
DEPENDS common
SOURCE LogLevelTests.cpp
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/common"
)
create_test( create_test(
NAME I18NTests NAME I18NTests
DEPENDS common DEPENDS common

View file

@ -0,0 +1,33 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "LogLevelTests.h"
#include <QFile>
#include <QSignalSpy>
#include "common/LogLevel.h"
void LogLevelTests::checkLogLevels_Valid()
{
QCOMPARE(LogLevel::fromOption(QStringLiteral("Fatal")), LogLevel::Level::Fatal);
QCOMPARE(LogLevel::fromOption(QStringLiteral("erRor")), LogLevel::Level::Error);
QCOMPARE(LogLevel::fromOption(QStringLiteral("wArning")), LogLevel::Level::Warning);
QCOMPARE(LogLevel::fromOption(QStringLiteral("info")), LogLevel::Level::Info);
QCOMPARE(LogLevel::fromOption("deBug"), LogLevel::Level::Debug);
QCOMPARE(LogLevel::fromOption("TraCe"), LogLevel::Level::Verbose);
}
void LogLevelTests::checkLogLevels_Invalid()
{
QCOMPARE(LogLevel::fromOption({}), LogLevel::Level::Info);
QCOMPARE(LogLevel::fromOption(QStringLiteral("INVALID")), LogLevel::Level::Info);
QCOMPARE(LogLevel::fromOption(QStringLiteral("deBug3")), LogLevel::Level::Info);
QCOMPARE(LogLevel::fromOption(QStringLiteral("infomatic")), LogLevel::Level::Info);
QCOMPARE(LogLevel::fromOption(QStringLiteral("warn")), LogLevel::Level::Info);
}
QTEST_MAIN(LogLevelTests)

View file

@ -0,0 +1,14 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include <QTest>
class LogLevelTests : public QObject
{
Q_OBJECT
private Q_SLOTS:
void checkLogLevels_Valid();
void checkLogLevels_Invalid();
};

View file

@ -101,23 +101,4 @@ void SettingsTests::checkCleanScreenName_LongName()
QCOMPARE(Settings::value(Settings::Core::ComputerName).toString(), expected); QCOMPARE(Settings::value(Settings::Core::ComputerName).toString(), expected);
} }
void SettingsTests::checkLogLevels_Valid()
{
QCOMPARE(Settings::logLevelToInt(QStringLiteral("Fatal")), 0);
QCOMPARE(Settings::logLevelToInt(QStringLiteral("erRor")), 1);
QCOMPARE(Settings::logLevelToInt(QStringLiteral("wArning")), 2);
QCOMPARE(Settings::logLevelToInt(QStringLiteral("info")), 3);
QCOMPARE(Settings::logLevelToInt(QStringLiteral("deBug")), 4);
QCOMPARE(Settings::logLevelToInt(QStringLiteral("TraCe")), 5);
}
void SettingsTests::checkLogLevels_Invalid()
{
QCOMPARE(Settings::logLevelToInt(QString()), 4);
QCOMPARE(Settings::logLevelToInt(QStringLiteral("INVALID")), 4);
QCOMPARE(Settings::logLevelToInt(QStringLiteral("debug3")), 4);
QCOMPARE(Settings::logLevelToInt(QStringLiteral("infomatic")), 4);
QCOMPARE(Settings::logLevelToInt(QStringLiteral("warn")), 4);
}
QTEST_MAIN(SettingsTests) QTEST_MAIN(SettingsTests)

View file

@ -24,8 +24,6 @@ private Q_SLOTS:
void checkValidSettings(); void checkValidSettings();
void checkCleanScreenName(); void checkCleanScreenName();
void checkCleanScreenName_LongName(); void checkCleanScreenName_LongName();
void checkLogLevels_Valid();
void checkLogLevels_Invalid();
private: private:
inline static const QString m_settingsPathTemp = QStringLiteral("tmp/test"); inline static const QString m_settingsPathTemp = QStringLiteral("tmp/test");

View file

@ -12,7 +12,7 @@
void ClipboardTests::initTestCase() void ClipboardTests::initTestCase()
{ {
m_log.setFilter(LogLevel::Verbose); m_log.setFilter(LogLevel::Level::Verbose);
} }
void ClipboardTests::basicFunction() void ClipboardTests::basicFunction()

View file

@ -11,7 +11,7 @@
void KeyboardLayoutManagerTests::initTestCase() void KeyboardLayoutManagerTests::initTestCase()
{ {
m_log.setFilter(LogLevel::Verbose); m_log.setFilter(LogLevel::Level::Verbose);
} }
void KeyboardLayoutManagerTests::remoteLayouts() void KeyboardLayoutManagerTests::remoteLayouts()

View file

@ -32,7 +32,7 @@ int main(int argc, char **argv)
arch.init(); arch.init();
Log log; Log log;
log.setFilter(LogLevel::Verbose); log.setFilter(LogLevel::Level::Verbose);
::testing::GTEST_FLAG(throw_on_failure) = true; ::testing::GTEST_FLAG(throw_on_failure) = true;
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);

View file

@ -12,7 +12,7 @@
void MSWindowsClipboardTests::initTestCase() void MSWindowsClipboardTests::initTestCase()
{ {
m_log.setFilter(LogLevel::Verbose); m_log.setFilter(LogLevel::Level::Verbose);
MSWindowsClipboard clipboard(NULL); MSWindowsClipboard clipboard(NULL);

View file

@ -19,7 +19,7 @@
void OSXKeyStateTests::initTestCase() void OSXKeyStateTests::initTestCase()
{ {
m_arch.init(); m_arch.init();
m_log.setFilter(LogLevel::Verbose); m_log.setFilter(LogLevel::Level::Verbose);
} }
void OSXKeyStateTests::mapModifiersFromOSX_OSXMask() void OSXKeyStateTests::mapModifiersFromOSX_OSXMask()

View file

@ -40,7 +40,7 @@ void WlClipboardTests::isAvailable()
void WlClipboardTests::initTestCase() void WlClipboardTests::initTestCase()
{ {
m_arch.init(); m_arch.init();
m_log.setFilter(LogLevel::Verbose); m_log.setFilter(LogLevel::Level::Verbose);
// Only run tests if Wayland clipboard tools are available // Only run tests if Wayland clipboard tools are available
if (!deskflow::platform::isWayland()) { if (!deskflow::platform::isWayland()) {

View file

@ -300,6 +300,33 @@ Do you want to connect to the server?
<translation type="unfinished">Adjuntar a la ventana</translation> <translation type="unfinished">Adjuntar a la ventana</translation>
</message> </message>
</context> </context>
<context>
<name>LogLevel</name>
<message>
<source>Fatal</source>
<translation type="unfinished">Fatal</translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished">Error</translation>
</message>
<message>
<source>Warning</source>
<translation type="unfinished">Advertencia</translation>
</message>
<message>
<source>Info</source>
<translation type="unfinished">Información</translation>
</message>
<message>
<source>Debug</source>
<translation type="unfinished">Depurar</translation>
</message>
<message>
<source>Verbose</source>
<translation type="unfinished">Verboso</translation>
</message>
</context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>

View file

@ -300,6 +300,33 @@ Vuoi connetterti al server?
<translation>Allega alla finestra</translation> <translation>Allega alla finestra</translation>
</message> </message>
</context> </context>
<context>
<name>LogLevel</name>
<message>
<source>Fatal</source>
<translation type="unfinished">Fatale</translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished">Errore</translation>
</message>
<message>
<source>Warning</source>
<translation type="unfinished">Avviso</translation>
</message>
<message>
<source>Info</source>
<translation type="unfinished">Informazioni</translation>
</message>
<message>
<source>Debug</source>
<translation type="unfinished">Debug</translation>
</message>
<message>
<source>Verbose</source>
<translation type="unfinished">Verboso</translation>
</message>
</context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>

View file

@ -300,6 +300,33 @@ Do you want to connect to the server?
<translation>ウィンドウに結合</translation> <translation>ウィンドウに結合</translation>
</message> </message>
</context> </context>
<context>
<name>LogLevel</name>
<message>
<source>Fatal</source>
<translation type="unfinished">重大</translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished">エラー</translation>
</message>
<message>
<source>Warning</source>
<translation type="unfinished">警告</translation>
</message>
<message>
<source>Info</source>
<translation type="unfinished">情報</translation>
</message>
<message>
<source>Debug</source>
<translation type="unfinished">デバッグ</translation>
</message>
<message>
<source>Verbose</source>
<translation type="unfinished">冗長</translation>
</message>
</context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>

View file

@ -300,6 +300,33 @@ Do you want to connect to the server?
<translation>창에 붙이기</translation> <translation>창에 붙이기</translation>
</message> </message>
</context> </context>
<context>
<name>LogLevel</name>
<message>
<source>Fatal</source>
<translation type="unfinished">치명적 오류</translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished">오류</translation>
</message>
<message>
<source>Warning</source>
<translation type="unfinished">경고</translation>
</message>
<message>
<source>Info</source>
<translation type="unfinished">정보</translation>
</message>
<message>
<source>Debug</source>
<translation type="unfinished">디버그</translation>
</message>
<message>
<source>Verbose</source>
<translation type="unfinished">말 수가 많은</translation>
</message>
</context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>

View file

@ -300,6 +300,33 @@ Do you want to connect to the server?
<translation>Прикрепить к окну</translation> <translation>Прикрепить к окну</translation>
</message> </message>
</context> </context>
<context>
<name>LogLevel</name>
<message>
<source>Fatal</source>
<translation type="unfinished">Критический</translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished">Ошибка</translation>
</message>
<message>
<source>Warning</source>
<translation type="unfinished">Предупреждение</translation>
</message>
<message>
<source>Info</source>
<translation type="unfinished">Инфо</translation>
</message>
<message>
<source>Debug</source>
<translation type="unfinished">Отладка</translation>
</message>
<message>
<source>Verbose</source>
<translation type="unfinished">Многословный</translation>
</message>
</context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>

View file

@ -300,6 +300,33 @@ Do you want to connect to the server?
<translation>吸附到窗口</translation> <translation>吸附到窗口</translation>
</message> </message>
</context> </context>
<context>
<name>LogLevel</name>
<message>
<source>Fatal</source>
<translation type="unfinished">致命</translation>
</message>
<message>
<source>Error</source>
<translation type="unfinished">错误</translation>
</message>
<message>
<source>Warning</source>
<translation type="unfinished">警告</translation>
</message>
<message>
<source>Info</source>
<translation type="unfinished">信息</translation>
</message>
<message>
<source>Debug</source>
<translation type="unfinished">调试</translation>
</message>
<message>
<source>Verbose</source>
<translation type="unfinished">冗长的</translation>
</message>
</context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>