vnote/src/core/thememgr.cpp

251 lines
6.4 KiB
C++

#include "thememgr.h"
#include <QRegularExpression>
#include <QDir>
#include <QDebug>
#include <utils/pathutils.h>
#include "exception.h"
#include <utils/iconutils.h>
#include <vtextedit/vtexteditor.h>
#include "configmgr.h"
#include "coreconfig.h"
#include "theme.h"
using namespace vnotex;
QStringList ThemeMgr::s_searchPaths;
QStringList ThemeMgr::s_webStylesSearchPaths;
ThemeMgr::ThemeMgr(const QString &p_currentThemeName, QObject *p_parent)
: QObject(p_parent)
{
loadAvailableThemes();
loadCurrentTheme(p_currentThemeName);
IconUtils::setDefaultIconForeground(paletteColor("base#icon#fg"), paletteColor("base#icon#disabled#fg"));
}
QString ThemeMgr::getIconFile(const QString &p_icon) const
{
Q_ASSERT(!p_icon.isEmpty());
QRegularExpression sep("[/\\\\]");
if (p_icon.indexOf(sep) != -1) {
return p_icon;
}
// If there is an ICONS folder in the theme configuration, use the custom ICONS from it.
QString customIcon = getFile(Theme::File::Icon) + "/" + p_icon;
if (QFile::exists(customIcon)) {
return customIcon;
} else {
return ":/vnotex/data/core/icons/" + p_icon;
}
}
void ThemeMgr::loadAvailableThemes()
{
m_themes.clear();
for (const auto &pa : s_searchPaths) {
loadThemes(pa);
}
if (m_themes.isEmpty()) {
Exception::throwOne(Exception::Type::EssentialFileMissing,
QStringLiteral("no available themes found in paths: %1").arg(s_searchPaths.join(QLatin1Char(';'))));
}
}
void ThemeMgr::loadThemes(const QString &p_path)
{
qDebug() << "search for themes in" << p_path;
QDir dir(p_path);
dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
auto themeFolders = dir.entryList();
const auto localeStr = ConfigMgr::getInst().getCoreConfig().getLocaleToUse();
for (auto &folder : themeFolders) {
checkAndAddThemeFolder(PathUtils::concatenateFilePath(p_path, folder), localeStr);
}
}
void ThemeMgr::checkAndAddThemeFolder(const QString &p_folder, const QString &p_locale)
{
if (Theme::isValidThemeFolder(p_folder)) {
ThemeInfo info;
info.m_name = PathUtils::dirName(p_folder);
info.m_displayName = Theme::getDisplayName(p_folder, p_locale);
info.m_folderPath = p_folder;
m_themes.push_back(info);
qDebug() << "add theme" << info.m_name << info.m_displayName << info.m_folderPath;
}
}
const Theme &ThemeMgr::getCurrentTheme() const
{
return *m_currentTheme;
}
void ThemeMgr::loadCurrentTheme(const QString &p_themeName)
{
auto themeFolder = findThemeFolder(p_themeName);
if (themeFolder.isNull()) {
qWarning() << "failed to locate theme" << p_themeName;
} else {
qInfo() << "using theme" << p_themeName;
m_currentTheme.reset(loadTheme(themeFolder));
}
if (!m_currentTheme) {
const QString defaultTheme("pure");
qWarning() << "fall back to default theme" << defaultTheme;
m_currentTheme.reset(loadTheme(findThemeFolder(defaultTheme)));
}
}
Theme *ThemeMgr::loadTheme(const QString &p_themeFolder)
{
if (p_themeFolder.isEmpty()) {
qWarning("failed to load theme from empty folder");
return nullptr;
}
try {
return Theme::fromFolder(p_themeFolder);
} catch (Exception &p_e) {
qWarning("failed to load theme from folder %s (%s)",
p_themeFolder.toStdString().c_str(),
p_e.what());
return nullptr;
}
}
QString ThemeMgr::findThemeFolder(const QString &p_name) const
{
auto theme = findTheme(p_name);
if (theme) {
return theme->m_folderPath;
}
return QString();
}
const ThemeMgr::ThemeInfo *ThemeMgr::findTheme(const QString &p_name) const
{
for (const auto &info : m_themes) {
if (info.m_name == p_name) {
return &info;
}
}
return nullptr;
}
QString ThemeMgr::fetchQtStyleSheet() const
{
Q_ASSERT(m_currentTheme);
if (!m_currentTheme) {
return QString();
}
return m_currentTheme->fetchQtStyleSheet();
}
QString ThemeMgr::paletteColor(const QString &p_name) const
{
Q_ASSERT(m_currentTheme);
return m_currentTheme->paletteColor(p_name);
}
void ThemeMgr::addSearchPath(const QString &p_path)
{
s_searchPaths << p_path;
}
QString ThemeMgr::getFile(Theme::File p_fileType) const
{
return m_currentTheme->getFile(p_fileType);
}
QString ThemeMgr::getEditorHighlightTheme() const
{
return m_currentTheme->getEditorHighlightTheme();
}
QString ThemeMgr::getMarkdownEditorHighlightTheme() const
{
return m_currentTheme->getMarkdownEditorHighlightTheme();
}
void ThemeMgr::addSyntaxHighlightingSearchPaths(const QStringList &p_paths)
{
vte::VTextEditor::addSyntaxCustomSearchPaths(p_paths);
}
const QColor &ThemeMgr::getBaseBackground() const
{
return m_baseBackground;
}
void ThemeMgr::setBaseBackground(const QColor &p_bg)
{
m_baseBackground = p_bg;
}
const QVector<ThemeMgr::ThemeInfo> &ThemeMgr::getAllThemes() const
{
return m_themes;
}
QPixmap ThemeMgr::getThemePreview(const QString &p_name) const
{
auto theme = findTheme(p_name);
if (theme) {
return Theme::getCover(theme->m_folderPath);
}
return QPixmap();
}
void ThemeMgr::refresh()
{
loadAvailableThemes();
}
void ThemeMgr::addWebStylesSearchPath(const QString &p_path)
{
s_webStylesSearchPaths << p_path;
}
QVector<QPair<QString, QString>> ThemeMgr::getWebStyles() const
{
QVector<QPair<QString, QString>> styles;
// From themes.
for (const auto &th : m_themes) {
auto filePath = Theme::getFile(th.m_folderPath, Theme::File::WebStyleSheet);
if (!filePath.isEmpty()) {
styles.push_back(qMakePair(tr("[Theme] %1 %2").arg(th.m_displayName, PathUtils::fileName(filePath)),
filePath));
}
filePath = Theme::getFile(th.m_folderPath, Theme::File::HighlightStyleSheet);
if (!filePath.isEmpty()) {
styles.push_back(qMakePair(tr("[Theme] %1 %2").arg(th.m_displayName, PathUtils::fileName(filePath)),
filePath));
}
}
// From search paths.
for (const auto &pa : s_webStylesSearchPaths) {
QDir dir(pa);
auto styleFiles = dir.entryList({"*.css"}, QDir::Files);
for (const auto &file : styleFiles) {
styles.push_back(qMakePair(file, dir.filePath(file)));
}
}
return styles;
}