/***************************************************************************
thememodel.cpp
-------------------
begin : 2026
copyright : (C) 2009-2026 by Andre Simon
email : a.simon@mailbox.org
***************************************************************************/
/*
This file is part of Highlight.
Highlight 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.
Highlight 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 Highlight. If not, see <http://www.gnu.org/licenses/>.
*/
#include "thememodel.h"
#include "themereader.h"
namespace
{
QColor toQColor(const highlight::Colour &c)
{
return QColor(c.getRed(), c.getGreen(), c.getBlue());
}
}
ThemeListModel::ThemeListModel(QObject *parent)
: QAbstractListModel(parent)
{
}
QStringList ThemeListModel::addThemes(const QDir &dir, const QString &idPrefix)
{
QStringList errors;
QList<ThemeEntry> newThemes;
const QStringList files = dir.entryList(QStringList("*.theme"), QDir::Files, QDir::Name);
for (const auto &fileName : files) {
highlight::ThemeReader reader;
if (!reader.load(dir.absoluteFilePath(fileName).toStdString())) {
errors << QString("%1: %2").arg(fileName, QString::fromStdString(reader.getErrorMessage()));
continue;
}
ThemeEntry entry;
entry.id = idPrefix + fileName.section('.', 0, 0);
entry.description = QString::fromStdString(reader.getDescription());
if (entry.description.isEmpty())
entry.description = fileName.section('.', 0, 0);
entry.categories = QString::fromStdString(reader.getCategoryDescription())
.split(',', Qt::SkipEmptyParts);
entry.background = toQColor(reader.getBgColour());
entry.foreground = toQColor(reader.getDefaultStyle().getColour());
entry.keyword = toQColor(reader.getKeywordStyle("kwa").getColour());
entry.type = toQColor(reader.getKeywordStyle("kwb").getColour());
entry.string = toQColor(reader.getStringStyle().getColour());
entry.number = toQColor(reader.getNumberStyle().getColour());
entry.comment = toQColor(reader.getCommentStyle().getColour());
newThemes.append(entry);
}
if (!newThemes.isEmpty()) {
beginInsertRows(QModelIndex(), themes.size(), themes.size() + newThemes.size() - 1);
themes.append(newThemes);
endInsertRows();
}
return errors;
}
int ThemeListModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : themes.size();
}
QVariant ThemeListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= themes.size())
return QVariant();
const ThemeEntry &t = themes.at(index.row());
switch (role) {
case Qt::DisplayRole:
return t.description;
case Qt::ToolTipRole:
return QString("%1\n%2").arg(t.id, t.categories.join(", "));
case ThemeIdRole:
return t.id;
case CategoriesRole:
return t.categories;
case SearchTextRole:
return QString("%1 %2 %3").arg(t.id, t.description, t.categories.join(' '));
case BackgroundRole:
return t.background;
case ForegroundRole:
return t.foreground;
case KeywordRole:
return t.keyword;
case TypeRole:
return t.type;
case StringRole:
return t.string;
case NumberRole:
return t.number;
case CommentRole:
return t.comment;
default:
return QVariant();
}
}
int ThemeListModel::rowOfTheme(const QString &id) const
{
for (int i = 0; i < themes.size(); ++i) {
if (themes.at(i).id == id)
return i;
}
return -1;
}
ThemeFilterProxyModel::ThemeFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
}
void ThemeFilterProxyModel::setSearchText(const QString &text)
{
searchTerms = text.split(' ', Qt::SkipEmptyParts);
invalidate();
}
bool ThemeFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
if (searchTerms.isEmpty())
return true;
QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent);
QString haystack = idx.data(ThemeListModel::SearchTextRole).toString();
for (const auto &term : searchTerms) {
if (!haystack.contains(term, Qt::CaseInsensitive))
return false;
}
return true;
}