/* * @Author: Uyanide pywang0608@foxmail.com * @Date: 2025-11-30 20:59:57 * @LastEditTime: 2026-01-15 09:55:26 * @Description: THE utils header that every project needs :) */ #ifndef UTILS_H #define UTILS_H #include #include #include #include #include #include #include /** * @brief Defer execution of a callable until the end of the current scope. * * @tparam Callable */ template class Defer { Callable m_func; public: explicit Defer(Callable&& func) : m_func(std::forward(func)) {} Defer() = delete; Defer(const Defer&) = delete; ~Defer() { m_func(); } }; /** * @brief Check if a file exists, is a regular file, and is readable. * * @param path */ inline bool checkFile(const QString& path) { QFileInfo checkFile(path); // According to Qt docs, "exists() returns true if the symlink points to an existing target, otherwise it returns false." // So no need to separately check for isSymbolicLink() or isSymLink(). return checkFile.exists() && checkFile.isFile() && checkFile.isReadable(); } /** * @brief Check if a directory exists, is a directory, and is readable. * * @param path */ inline bool checkDir(const QString& path) { QFileInfo checkFile(path); return checkFile.exists() && checkFile.isDir() && checkFile.isReadable(); } /** * @brief Expand environment variables and ~ in a given path. * * @param path Input path * @return QString Expanded path */ 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); } /** * @brief Split the file name from a given path. * * @param path * @return QString */ static QString splitNameFromPath(const QString& path) { QFileInfo fileInfo(path); return fileInfo.fileName(); } /** * @brief In addition to checking if the file exists and is readable, * also checks if the file has a valid image extension. * * @param filePath * @return true * @return false */ 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 static const QList formats = QImageReader::supportedImageFormats(); QString ext = QFileInfo(filePath).suffix().toLower(); return formats.contains(ext.toUtf8()); } #endif // UTILS_H