feat: cli options
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
.cache
|
||||
.vscode
|
||||
.qtcreator
|
||||
build-dbg
|
||||
build
|
||||
*.log
|
||||
|
||||
+14
-10
@@ -1,6 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(wallpaper_carousel VERSION 0.1 LANGUAGES CXX)
|
||||
project(Wallpaper_Carousel VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
set(EXECUTABLE_NAME "wallpaper-carousel")
|
||||
|
||||
configure_file(src/version.h.in ${CMAKE_BINARY_DIR}/generated/version.h)
|
||||
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
@@ -27,7 +31,7 @@ set(PROJECT_SOURCES
|
||||
)
|
||||
|
||||
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
||||
qt_add_executable(wallpaper-carousel
|
||||
qt_add_executable(${EXECUTABLE_NAME}
|
||||
MANUAL_FINALIZATION
|
||||
${PROJECT_SOURCES}
|
||||
src/utils.h
|
||||
@@ -44,22 +48,22 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
||||
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
|
||||
else()
|
||||
if(ANDROID)
|
||||
add_library(wallpaper-carousel SHARED
|
||||
add_library(${EXECUTABLE_NAME} SHARED
|
||||
${PROJECT_SOURCES}
|
||||
)
|
||||
|
||||
# Define properties for Android with Qt 5 after find_package() calls as:
|
||||
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
|
||||
else()
|
||||
add_executable(wallpaper-carousel
|
||||
add_executable(${EXECUTABLE_NAME}
|
||||
${PROJECT_SOURCES}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(wallpaper-carousel PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
target_link_libraries(${EXECUTABLE_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
|
||||
target_include_directories(wallpaper-carousel PRIVATE src)
|
||||
target_include_directories(${EXECUTABLE_NAME} PRIVATE src ${CMAKE_BINARY_DIR}/generated)
|
||||
|
||||
# if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
|
||||
# target_compile_definitions(wallpaper_chooser PRIVATE
|
||||
@@ -74,7 +78,7 @@ if(${QT_VERSION} VERSION_LESS 6.1.0)
|
||||
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.wallpaper_chooser)
|
||||
endif()
|
||||
|
||||
set_target_properties(wallpaper-carousel PROPERTIES
|
||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES
|
||||
${BUNDLE_ID_OPTION}
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
@@ -83,16 +87,16 @@ set_target_properties(wallpaper-carousel PROPERTIES
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS wallpaper-carousel
|
||||
install(TARGETS ${EXECUTABLE_NAME}
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_LIST_DIR}/app/wallpaper-carousel.desktop
|
||||
install(FILES ${CMAKE_CURRENT_LIST_DIR}/app/${EXECUTABLE_NAME}.desktop
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications
|
||||
)
|
||||
|
||||
if(QT_VERSION_MAJOR EQUAL 6)
|
||||
qt_finalize_executable(wallpaper-carousel)
|
||||
qt_finalize_executable(${EXECUTABLE_NAME})
|
||||
endif()
|
||||
|
||||
+4
-9
@@ -1,4 +1,4 @@
|
||||
#!/bin/env bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -9,15 +9,10 @@ path="$(dirname "$(readlink -f "$0")")"
|
||||
cmake -S "$path/.." -B "$path/../build" \
|
||||
-DCMAKE_INSTALL_PREFIX="$prefix"
|
||||
|
||||
cmake --build "$path/../build"
|
||||
cmake --build "$path/../build" --config Release -- -j"$(nproc)"
|
||||
|
||||
if [ ! -w "$prefix" ] && [ "$(id -u)" -ne 0 ]; then
|
||||
sudo cmake --install "$path/../build"
|
||||
sudo cmake --install "$path/../build" --config Release
|
||||
else
|
||||
cmake --install "$path/../build"
|
||||
fi
|
||||
|
||||
if command -v update-desktop-database &>/dev/null; then
|
||||
echo "Updating desktop database..."
|
||||
update-desktop-database "$prefix"/share/applications/ || true
|
||||
cmake --install "$path/../build" --config Release
|
||||
fi
|
||||
|
||||
+24
-74
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-08-05 01:34:52
|
||||
* @LastEditTime: 2026-01-15 00:48:36
|
||||
* @LastEditTime: 2026-01-15 03:54:42
|
||||
* @Description: Configuration manager.
|
||||
*/
|
||||
#include "config.h"
|
||||
@@ -15,19 +15,27 @@
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
using namespace GeneralLogger;
|
||||
|
||||
static QString expandPath(const QString& path);
|
||||
|
||||
const QString Config::s_DefaultConfigFileName = "config.json";
|
||||
|
||||
Config::Config(const QString& configDir, const QStringList& searchDirs, QObject* parent)
|
||||
Config::Config(
|
||||
const QString& configDir,
|
||||
const QStringList& searchDirs,
|
||||
const QString& configPath,
|
||||
QObject* parent)
|
||||
: QObject(parent), m_configDir(configDir) {
|
||||
debug(QString("Loading configuration from: %1 ...").arg(configDir));
|
||||
if (configPath.isEmpty()) {
|
||||
info(QString("Configuration directory: %1").arg(configDir));
|
||||
_loadConfig(configDir + QDir::separator() + s_DefaultConfigFileName);
|
||||
|
||||
debug(QString("Additional search directories: %1").arg(searchDirs.join(", ")));
|
||||
} else {
|
||||
_loadConfig(configPath);
|
||||
}
|
||||
if (!searchDirs.isEmpty()) {
|
||||
info(QString("Additional search directories: %1").arg(searchDirs.join(", ")));
|
||||
m_wallpaperConfig.dirs.append(searchDirs);
|
||||
}
|
||||
|
||||
debug("Loading wallpapers ...");
|
||||
_loadWallpapers();
|
||||
@@ -37,6 +45,7 @@ Config::~Config() {
|
||||
}
|
||||
|
||||
void Config::_loadConfig(const QString& configPath) {
|
||||
info(QString("Loading configuration from: %1").arg(configPath));
|
||||
QFile configFile(configPath);
|
||||
if (!configFile.open(QIODevice::ReadOnly)) {
|
||||
critical(QString("Failed to open config file: %1").arg(configPath));
|
||||
@@ -158,17 +167,16 @@ void Config::_loadConfig(const QString& configPath) {
|
||||
if (currentObj.contains(pathParts[i]) && currentObj[pathParts[i]].isObject()) {
|
||||
currentObj = currentObj[pathParts[i]].toObject();
|
||||
} else {
|
||||
warn(QString("Path '%1' not found").arg(pathParts.mid(0, i + 1).join('.')));
|
||||
debug(QString("Path '%1' not found").arg(pathParts.mid(0, i + 1).join('.')));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取目标值
|
||||
const QString& finalKey = pathParts.last();
|
||||
if (currentObj.contains(finalKey)) {
|
||||
mapping.parser(currentObj[finalKey]);
|
||||
} else {
|
||||
warn(QString("Key '%1' not found in '%2'").arg(finalKey).arg(mapping.path));
|
||||
debug(QString("Key '%1' not found in '%2'").arg(finalKey).arg(mapping.path));
|
||||
}
|
||||
})();
|
||||
}
|
||||
@@ -187,11 +195,11 @@ void Config::_loadWallpapers() {
|
||||
debug(QString("Loading wallpapers from %1 specified directories...").arg(m_wallpaperConfig.dirs.size()));
|
||||
for (const QString& dirPath : m_wallpaperConfig.dirs) {
|
||||
QDir dir(dirPath);
|
||||
if (dir.exists()) {
|
||||
if (checkDir(dirPath)) {
|
||||
QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
|
||||
for (const QString& file : files) {
|
||||
QString filePath = dir.filePath(file);
|
||||
paths.insert(filePath);
|
||||
paths.insert(expandPath(filePath));
|
||||
}
|
||||
} else {
|
||||
warn(QString("Directory '%1' does not exist").arg(dirPath));
|
||||
@@ -205,70 +213,12 @@ void Config::_loadWallpapers() {
|
||||
|
||||
m_wallpapers.reserve(paths.size());
|
||||
for (const QString& path : paths) {
|
||||
if (isValidImageFile(path)) {
|
||||
if (checkImageFile(path)) {
|
||||
m_wallpapers.append(path);
|
||||
} else {
|
||||
warn(QString("File '%1' is not recognized as a valid image file").arg(path));
|
||||
}
|
||||
}
|
||||
|
||||
info(QString("Found %1 wallpapers").arg(paths.size()));
|
||||
}
|
||||
|
||||
bool Config::isValidImageFile(const QString& filePath) {
|
||||
static const QStringList validExtensions = {
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".jfif",
|
||||
".png",
|
||||
".bmp",
|
||||
".gif",
|
||||
".webp",
|
||||
".tiff",
|
||||
".avif",
|
||||
".heic",
|
||||
".heif"};
|
||||
|
||||
// check if exist
|
||||
if (!QFile::exists(filePath)) {
|
||||
warn(QString("File does not exist: %1").arg(filePath));
|
||||
return false;
|
||||
}
|
||||
// check if normal file
|
||||
QFileInfo fileInfo(filePath);
|
||||
if (!(fileInfo.isFile() || fileInfo.isSymbolicLink()) || !fileInfo.isReadable()) {
|
||||
warn(QString("Invalid file: %1").arg(filePath));
|
||||
return false;
|
||||
}
|
||||
// check if valid extension
|
||||
for (const QString& ext : validExtensions) {
|
||||
if (filePath.endsWith(ext, Qt::CaseInsensitive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
warn(QString("Unsupported file type: %1").arg(filePath));
|
||||
return false;
|
||||
}
|
||||
|
||||
static QString expandPath(const QString& path) {
|
||||
QString expandedPath = path;
|
||||
|
||||
if (expandedPath.startsWith("~/")) {
|
||||
expandedPath.replace(0, 1, QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
|
||||
} else if (expandedPath == "~") {
|
||||
expandedPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
}
|
||||
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
QRegularExpression envVarRegex(R"(\$([A-Za-z_][A-Za-z0-9_]*))");
|
||||
QRegularExpressionMatchIterator i = envVarRegex.globalMatch(expandedPath);
|
||||
|
||||
while (i.hasNext()) {
|
||||
QRegularExpressionMatch match = i.next();
|
||||
QString varName = match.captured(1);
|
||||
QString varValue = env.value(varName);
|
||||
if (!varValue.isEmpty()) {
|
||||
expandedPath.replace(match.captured(0), varValue);
|
||||
}
|
||||
}
|
||||
|
||||
return QDir::cleanPath(expandedPath);
|
||||
info(QString("Found %1 files").arg(paths.size()));
|
||||
}
|
||||
|
||||
+6
-4
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-08-05 01:34:52
|
||||
* @LastEditTime: 2025-08-07 23:24:02
|
||||
* @LastEditTime: 2026-01-15 03:40:25
|
||||
* @Description: Configuration manager.
|
||||
*/
|
||||
#ifndef CONFIG_H
|
||||
@@ -46,12 +46,14 @@ class Config : public QObject {
|
||||
bool reverse = false;
|
||||
};
|
||||
|
||||
Config(const QString& configDir, const QStringList& searchDirs = {}, QObject* parent = nullptr);
|
||||
Config(
|
||||
const QString& configDir,
|
||||
const QStringList& searchDirs = {},
|
||||
const QString& configPath = "",
|
||||
QObject* parent = nullptr);
|
||||
|
||||
~Config();
|
||||
|
||||
static bool isValidImageFile(const QString& filePath);
|
||||
|
||||
[[nodiscard]] const QStringList& getWallpapers() const { return m_wallpapers; }
|
||||
|
||||
[[nodiscard]] qint64 getWallpaperCount() const { return m_wallpapers.size(); }
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-08-05 01:22:53
|
||||
* @LastEditTime: 2026-01-14 23:26:32
|
||||
* @LastEditTime: 2026-01-15 03:42:17
|
||||
* @Description: Animated carousel widget for displaying and selecting images.
|
||||
*/
|
||||
#ifndef IMAGES_CAROUSEL_H
|
||||
#define IMAGES_CAROUSEL_H
|
||||
|
||||
#include <qqueue.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QKeyEvent>
|
||||
#include <QMutex>
|
||||
|
||||
+29
-28
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-08-07 01:12:37
|
||||
* @LastEditTime: 2026-01-15 02:10:15
|
||||
* @LastEditTime: 2026-01-15 02:34:40
|
||||
* @Description: Implementation of logger.
|
||||
*/
|
||||
#include "logger.h"
|
||||
@@ -15,12 +15,13 @@
|
||||
#include <QTextStream>
|
||||
#include <cstdio>
|
||||
|
||||
Q_LOGGING_CATEGORY(logMain, "wallpaper.carousel")
|
||||
#include "version.h"
|
||||
|
||||
static QTextStream* g_logStream = nullptr;
|
||||
static bool g_isColored = false;
|
||||
static QMutex g_logMutex;
|
||||
static const QString g_appName = "wallpaper.carousel"; // same as above
|
||||
Q_LOGGING_CATEGORY(logMain, APP_NAME)
|
||||
|
||||
static QTextStream* s_logStream = nullptr;
|
||||
static bool s_isColored = false;
|
||||
static QMutex s_logMutex;
|
||||
|
||||
static bool checkIsColored(FILE* stream) {
|
||||
if (!stream || !isatty(fileno(stream))) {
|
||||
@@ -37,51 +38,51 @@ static bool checkIsColored(FILE* stream) {
|
||||
static void messageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
|
||||
Q_UNUSED(context);
|
||||
|
||||
QMutexLocker locker(&g_logMutex);
|
||||
QMutexLocker locker(&s_logMutex);
|
||||
|
||||
QString levelTag;
|
||||
QString colorTag;
|
||||
QString colorText;
|
||||
QString resetColor = g_isColored ? "\033[0m" : "";
|
||||
QString resetColor = s_isColored ? "\033[0m" : "";
|
||||
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
levelTag = "[DEBUG]";
|
||||
colorTag = g_isColored ? "\033[36m" : ""; // Cyan
|
||||
colorTag = s_isColored ? "\033[36m" : ""; // Cyan
|
||||
break;
|
||||
case QtInfoMsg:
|
||||
levelTag = "[INFO]";
|
||||
colorTag = g_isColored ? "\033[92m" : ""; // Light Green
|
||||
colorText = g_isColored ? "\033[32m" : ""; // Green
|
||||
colorTag = s_isColored ? "\033[92m" : ""; // Light Green
|
||||
colorText = s_isColored ? "\033[32m" : ""; // Green
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
levelTag = "[WARN]";
|
||||
colorTag = g_isColored ? "\033[93m" : ""; // Light Yellow
|
||||
colorText = g_isColored ? "\033[33m" : ""; // Yellow
|
||||
colorTag = s_isColored ? "\033[93m" : ""; // Light Yellow
|
||||
colorText = s_isColored ? "\033[33m" : ""; // Yellow
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
levelTag = "[ERROR]";
|
||||
colorTag = g_isColored ? "\033[91m" : ""; // Light Red
|
||||
colorText = g_isColored ? "\033[31m" : ""; // Red
|
||||
colorTag = s_isColored ? "\033[91m" : ""; // Light Red
|
||||
colorText = s_isColored ? "\033[31m" : ""; // Red
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
levelTag = "[FATAL]";
|
||||
colorTag = g_isColored ? "\033[95m" : ""; // Magenta
|
||||
colorTag = s_isColored ? "\033[95m" : ""; // Magenta
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_logStream) {
|
||||
(*g_logStream) << colorTag << levelTag << " " << colorText << msg << resetColor << Qt::endl;
|
||||
g_logStream->flush();
|
||||
if (s_logStream) {
|
||||
(*s_logStream) << colorTag << levelTag << " " << colorText << msg << resetColor << Qt::endl;
|
||||
s_logStream->flush();
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::init(FILE* stream) {
|
||||
if (stream) {
|
||||
delete g_logStream;
|
||||
g_logStream = new QTextStream(stream);
|
||||
delete s_logStream;
|
||||
s_logStream = new QTextStream(stream);
|
||||
}
|
||||
g_isColored = checkIsColored(stream);
|
||||
s_isColored = checkIsColored(stream);
|
||||
|
||||
qInstallMessageHandler(messageOutput);
|
||||
}
|
||||
@@ -89,25 +90,25 @@ void Logger::init(FILE* stream) {
|
||||
void Logger::setLogLevel(QtMsgType level) {
|
||||
switch (level) {
|
||||
case QtDebugMsg:
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=true").arg(g_appName));
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=true").arg(APP_NAME));
|
||||
break;
|
||||
case QtInfoMsg:
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=false\n%1.info=true").arg(g_appName));
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=false\n%1.info=true").arg(APP_NAME));
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=false\n%1.info=false\n%1.warning=true").arg(g_appName));
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=false\n%1.info=false\n%1.warning=true").arg(APP_NAME));
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=false\n%1.info=false\n%1.warning=false\n%1.critical=true").arg(g_appName));
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=false\n%1.info=false\n%1.warning=false\n%1.critical=true").arg(APP_NAME));
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=false\n%1.info=false\n%1.warning=false\n%1.critical=false").arg(g_appName));
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=false\n%1.info=false\n%1.warning=false\n%1.critical=false").arg(APP_NAME));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::quiet() {
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=false\n%1.info=false\n%1.warning=false\n%1.critical=false\n%1.fatal=false").arg(g_appName));
|
||||
QLoggingCategory::setFilterRules(QString("%1.debug=false\n%1.info=false\n%1.warning=false\n%1.critical=false\n%1.fatal=false").arg(APP_NAME));
|
||||
}
|
||||
|
||||
void GeneralLogger::debug(const QString& msg) {
|
||||
|
||||
+111
-35
@@ -1,13 +1,11 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-08-05 00:37:58
|
||||
* @LastEditTime: 2026-01-15 01:43:14
|
||||
* @Description: Entry point.
|
||||
* @LastEditTime: 2026-01-15 03:41:55
|
||||
* @Description: Argument parser and entry point.
|
||||
*/
|
||||
#include <qapplication.h>
|
||||
#include <qlogging.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <QTextStream>
|
||||
@@ -15,49 +13,127 @@
|
||||
#include "config.h"
|
||||
#include "logger.h"
|
||||
#include "main_window.h"
|
||||
#include "utils.h"
|
||||
#include "version.h"
|
||||
|
||||
static class AppOptions {
|
||||
QCommandLineParser parser{};
|
||||
|
||||
void printVersion() {
|
||||
QTextStream out(stdout);
|
||||
out << APP_NAME << " version " << APP_VERSION << Qt::endl;
|
||||
doReturn = true;
|
||||
}
|
||||
|
||||
void printHelp() {
|
||||
QTextStream out(stdout);
|
||||
out << parser.helpText() << Qt::endl;
|
||||
doReturn = true;
|
||||
}
|
||||
|
||||
void printError() {
|
||||
if (!errorText.isEmpty()) {
|
||||
QTextStream out(stderr);
|
||||
out << errorText << Qt::endl;
|
||||
printHelp();
|
||||
}
|
||||
doReturn = true;
|
||||
}
|
||||
|
||||
public:
|
||||
QString configPath = "";
|
||||
QStringList appendDirs;
|
||||
QString errorText = "";
|
||||
bool doReturn = false;
|
||||
|
||||
void parseArgs(QApplication* a) {
|
||||
parser.setApplicationDescription("A small wallpaper utility made with Qt");
|
||||
|
||||
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||
const QCommandLineOption versionOption = parser.addVersionOption();
|
||||
|
||||
QCommandLineOption verboseOption(QStringList() << "V" << "verbose", "Set log level to DEBUG");
|
||||
parser.addOption(verboseOption);
|
||||
|
||||
QCommandLineOption quietOption(QStringList() << "q" << "quiet", "Suppress all log output");
|
||||
parser.addOption(quietOption);
|
||||
|
||||
QCommandLineOption appendDirOption(QStringList() << "d" << "append-dir", "Append an additional wallpaper search directory", "dir");
|
||||
parser.addOption(appendDirOption);
|
||||
|
||||
QCommandLineOption configFileOption(QStringList() << "c" << "config-file", "Specify a custom configuration file", "file");
|
||||
parser.addOption(configFileOption);
|
||||
|
||||
if (!parser.parse(a->arguments())) {
|
||||
errorText = parser.errorText();
|
||||
doReturn = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (parser.isSet(versionOption)) {
|
||||
printVersion();
|
||||
return;
|
||||
}
|
||||
|
||||
if (parser.isSet(helpOption)) {
|
||||
printHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
if (parser.isSet(verboseOption)) {
|
||||
Logger::setLogLevel(QtDebugMsg);
|
||||
} else if (parser.isSet(quietOption)) {
|
||||
Logger::quiet();
|
||||
} else {
|
||||
Logger::setLogLevel(QtInfoMsg);
|
||||
}
|
||||
|
||||
for (const QString& dir : parser.values(appendDirOption)) {
|
||||
if (checkDir(dir)) {
|
||||
appendDirs.append(dir);
|
||||
} else {
|
||||
errorText = QString("Error: Directory does not exist or is not accessible: %1").arg(dir);
|
||||
printError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.isSet(configFileOption)) {
|
||||
QString path = parser.value(configFileOption);
|
||||
if (checkFile(path)) {
|
||||
configPath = path;
|
||||
} else {
|
||||
errorText = QString("Error: Config file does not exist or is not accessible: %1").arg(path);
|
||||
printError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} s_options;
|
||||
|
||||
static QString getConfigDir() {
|
||||
auto configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||
if (configDir.isEmpty()) {
|
||||
configDir = QDir::homePath() + QDir::separator() + ".config" + QDir::separator() + "wallpaper_chooser";
|
||||
configDir = QDir::homePath() + QDir::separator() + ".config" + QDir::separator() + APP_NAME;
|
||||
}
|
||||
QDir().mkpath(configDir);
|
||||
return configDir;
|
||||
}
|
||||
|
||||
static void setLogLevel(int argc, char* argv[]) {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
QString arg(argv[i]);
|
||||
if (arg == "--debug" || arg == "-vvv" || arg == "--verbose") {
|
||||
Logger::setLogLevel(QtDebugMsg);
|
||||
return;
|
||||
} else if (arg == "--info" || arg == "-vv") {
|
||||
Logger::setLogLevel(QtInfoMsg);
|
||||
return;
|
||||
} else if (arg == "--warn" || arg == "-v") {
|
||||
Logger::setLogLevel(QtWarningMsg);
|
||||
return;
|
||||
} else if (arg == "--critical") {
|
||||
Logger::setLogLevel(QtCriticalMsg);
|
||||
return;
|
||||
} else if (arg == "--fatal") {
|
||||
Logger::setLogLevel(QtFatalMsg);
|
||||
return;
|
||||
} else if (arg == "--quiet") {
|
||||
Logger::quiet();
|
||||
return;
|
||||
}
|
||||
}
|
||||
Logger::setLogLevel(QtInfoMsg);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
QApplication a(argc, argv);
|
||||
a.setApplicationName(APP_NAME);
|
||||
a.setApplicationVersion(APP_VERSION);
|
||||
|
||||
Logger::init(stderr);
|
||||
setLogLevel(argc, argv);
|
||||
Logger::init();
|
||||
s_options.parseArgs(&a);
|
||||
|
||||
Config config(getConfigDir());
|
||||
if (s_options.doReturn) {
|
||||
return s_options.errorText.isEmpty() ? 0 : 1;
|
||||
}
|
||||
|
||||
Config config(getConfigDir(), s_options.appendDirs, s_options.configPath, &a);
|
||||
|
||||
MainWindow w(config);
|
||||
w.show();
|
||||
|
||||
+73
-1
@@ -1,13 +1,18 @@
|
||||
/*
|
||||
* @Author: Uyanide pywang0608@foxmail.com
|
||||
* @Date: 2025-11-30 20:59:57
|
||||
* @LastEditTime: 2025-12-07 06:08:18
|
||||
* @LastEditTime: 2026-01-15 03:11:08
|
||||
* @Description: THE utils header that every project needs :)
|
||||
*/
|
||||
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QRegularExpression>
|
||||
#include <QStandardPaths>
|
||||
#include <utility>
|
||||
|
||||
template <typename Callable>
|
||||
@@ -26,4 +31,71 @@ class Defer {
|
||||
}
|
||||
};
|
||||
|
||||
inline bool checkFile(const QString& path) {
|
||||
QFileInfo checkFile(path);
|
||||
return checkFile.exists() && checkFile.isFile() && checkFile.isReadable();
|
||||
}
|
||||
|
||||
inline bool checkDir(const QString& path) {
|
||||
QFileInfo checkFile(path);
|
||||
return checkFile.exists() && checkFile.isDir() && checkFile.isReadable();
|
||||
}
|
||||
|
||||
inline QString expandPath(const QString& path) {
|
||||
QString expandedPath = path;
|
||||
|
||||
if (expandedPath.startsWith("~/")) {
|
||||
expandedPath.replace(0, 1, QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
|
||||
} else if (expandedPath == "~") {
|
||||
expandedPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
}
|
||||
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
QRegularExpression envVarRegex(R"(\$([A-Za-z_][A-Za-z0-9_]*))");
|
||||
QRegularExpressionMatchIterator i = envVarRegex.globalMatch(expandedPath);
|
||||
|
||||
while (i.hasNext()) {
|
||||
QRegularExpressionMatch match = i.next();
|
||||
QString varName = match.captured(1);
|
||||
QString varValue = env.value(varName);
|
||||
if (!varValue.isEmpty()) {
|
||||
expandedPath.replace(match.captured(0), varValue);
|
||||
}
|
||||
}
|
||||
|
||||
return QDir::cleanPath(expandedPath);
|
||||
}
|
||||
|
||||
inline bool checkImageFile(const QString& filePath) {
|
||||
static const QStringList validExtensions = {
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".jfif",
|
||||
".png",
|
||||
".bmp",
|
||||
".gif",
|
||||
".webp",
|
||||
".tiff",
|
||||
".avif",
|
||||
".heic",
|
||||
".heif"};
|
||||
|
||||
// check if exist
|
||||
if (!QFile::exists(filePath)) {
|
||||
return false;
|
||||
}
|
||||
// check if normal file
|
||||
QFileInfo fileInfo(filePath);
|
||||
if (!(fileInfo.isFile() || fileInfo.isSymbolicLink()) || !fileInfo.isReadable()) {
|
||||
return false;
|
||||
}
|
||||
// check if valid extension
|
||||
for (const QString& ext : validExtensions) {
|
||||
if (filePath.endsWith(ext, Qt::CaseInsensitive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // UTILS_H
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#define APP_VERSION "@PROJECT_VERSION@"
|
||||
#define APP_NAME "@EXECUTABLE_NAME@"
|
||||
Reference in New Issue
Block a user