-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy paththemeiconsmodel.cpp
More file actions
162 lines (146 loc) · 5.4 KB
/
themeiconsmodel.cpp
File metadata and controls
162 lines (146 loc) · 5.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <QIcon>
#include <QSet>
#include <QDir>
#include <QDebug>
#include "themeiconsmodel.h"
ThemeIconsModel::ThemeIconsModel(QHash<QString, IconTheme> themes, const QString &theme_name,
QObject *parent):
QAbstractListModel(parent),
icon_themes(std::move(themes))
{
set_current_theme(theme_name.isNull() ? QIcon::themeName() : theme_name);
}
ThemeIconsModel::ThemeIconsModel(QObject *parent): QAbstractListModel(parent)
{
}
int ThemeIconsModel::rowCount(const QModelIndex &) const
{
return icon_names.size();
}
QVariant ThemeIconsModel::data(const QModelIndex &index, int role) const
{
const int row = index.row();
if (row < 0 || row >= icon_names.size() || index.column() != 0) {
return QVariant();
}
switch(role) {
case Qt::DisplayRole:
case Qt::StatusTipRole:
case Qt::ToolTipRole:
return icon_names.at(row);
case Qt::DecorationRole: {
const QString &name = icon_names.at(row);
// TODO: implement cache with limited amount of memory
// TODO: implement async loading
if (icon_cache.contains(name))
return icon_cache[name];
QIcon icon = icon_by_name(name);
icon_cache[name] = icon;
return icon;
}
case IconInfoRole: {
const QString &name = icon_names.at(row);
QStringList icon_theme_names = get_icon_theme_chain(name);
if (icon_theme_names.isEmpty())
return QVariant();
const IconTheme &theme = icon_themes[icon_theme_names.at(0)];
const QVector<IconTheme::Directory> &dirs = theme.dirs();
QStringList sizes;
QSet<QString> contexts;
for (const IconTheme::IconFileInfo& icon_info: theme.icons()[name]) {
const IconTheme::Directory &dir = dirs.at(icon_info.directory_index);
QString size;
if (dir.type == IconTheme::Directory::Type::Scalable) {
size = QString("[%1-%2]").arg(dir.min_size).arg(dir.max_size);
} else {
size = QString("%1x%1").arg(dir.size);
}
if (dir.scale > 1) {
sizes.append(QString("%1@%2x").arg(size).arg(dir.scale));
} else {
sizes.append(size);
}
contexts.insert(dir.context);
}
return QVariant::fromValue(IconInfo{name, sizes, contexts.toList(), icon_theme_names});
}
default:
return QVariant();
}
}
void ThemeIconsModel::set_themes(const QHash<QString, IconTheme> &themes, const QString &theme_name)
{
icon_themes=themes;
set_current_theme(theme_name.isNull() ? QIcon::themeName() : theme_name);
}
void ThemeIconsModel::set_current_theme(QString theme)
{
if (!icon_themes.contains(theme) || theme == selected_theme)
return;
beginResetModel();
selected_theme = theme;
icon_cache.clear();
// build list of icons from selected theme and parent themes
QSet<QString> theme_icons;
QStringList theme_chain{selected_theme};
for (int i = 0; i < theme_chain.size(); i++) {
const IconTheme &theme = icon_themes[theme_chain[i]];
theme_chain.append(theme.parents());
theme_icons.unite(QSet<QString>::fromList(theme.icons().keys()));
}
icon_names = theme_icons.toList();
qDebug() << "selected_theme: " << selected_theme;
endResetModel();
}
QIcon ThemeIconsModel::icon_by_name(const QString &name) const
{
static_assert(IconTheme::FileExtension::PNG == 0, "IconTheme::FileExtension::PNG != 0");
static_assert(IconTheme::FileExtension::SVG == 1, "IconTheme::FileExtension::SVG != 1");
static_assert(IconTheme::FileExtension::XPM == 2, "IconTheme::FileExtension::XPM != 2");
static const char * extensions[IconTheme::FileExtension::LENGTH] = {
"png",
"svg",
"xpm"
};
QIcon icon;
QString icon_theme_name = get_icon_theme(name);
if (icon_theme_name.isNull())
return icon;
const IconTheme &theme = icon_themes[icon_theme_name];
const QVector<IconTheme::Directory> &dirs = theme.dirs();
for (const IconTheme::IconFileInfo& icon_info: theme.icons()[name]) {
QString file_path = QString("%1/%2/%3.%4")
.arg(theme.path())
.arg(dirs[icon_info.directory_index].path)
.arg(name)
.arg(extensions[icon_info.extension]);
icon.addFile(file_path);
}
return icon;
}
QString ThemeIconsModel::get_icon_theme(const QString &name) const
{
QStringList theme_chain{selected_theme};
for (int i = 0; i < theme_chain.size(); i++) {
const IconTheme &theme = icon_themes[theme_chain[i]];
theme_chain.append(theme.parents());
if (!theme.icons().contains(name))
continue;
return theme_chain[i];
}
qWarning() << "Icon " << name << " not found";
return QString();
}
QStringList ThemeIconsModel::get_icon_theme_chain(const QString &name) const
{
QStringList chain;
QStringList theme_chain{selected_theme};
for (int i = 0; i < theme_chain.size(); i++) {
const IconTheme &theme = icon_themes[theme_chain[i]];
theme_chain.append(theme.parents());
if (!theme.icons().contains(name))
continue;
chain.append(theme_chain[i]);
}
return chain;
}