1 /*
2 * Copyright (C) Pedram Pourang (aka Tsu Jan) 2018 <tsujan2000@gmail.com>
3 *
4 * Kvantum is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Kvantum is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "KvCommand.h"
19 #include <QDir>
20 #include <QSettings>
21
22 namespace KvManager {
23
getHomeConfig()24 static const QString getHomeConfig()
25 {
26 QString xdg_config_home;
27 char * _xdg_config_home = getenv ("XDG_CONFIG_HOME");
28 if (!_xdg_config_home)
29 xdg_config_home = QString ("%1/.config").arg (QDir::homePath());
30 else
31 xdg_config_home = QString (_xdg_config_home);
32 return xdg_config_home;
33 }
34
isThemeDir(const QString & folderPath)35 static bool isThemeDir (const QString &folderPath)
36 {
37 if (folderPath.isEmpty()) return false;
38 QDir dir = QDir (folderPath);
39 if (!dir.exists()) return false;
40
41 QString themeName = dir.dirName();
42
43 QStringList parts = folderPath.split ("/");
44 if (parts.last() == "Kvantum")
45 {
46 if (parts.size() < 3)
47 return false;
48 else
49 themeName = parts.at (parts.size() - 2);
50 }
51
52 /* "Default" is reserved for the copied default theme,
53 "Kvantum" for the alternative installation paths. */
54 if (themeName == "Default" || themeName == "Kvantum")
55 return false;
56 /* QSettings doesn't accept spaces in the name */
57 QString s = themeName.simplified();
58 if (s.contains (" "))
59 return false;
60
61 if (QFile::exists (folderPath + QString ("/%1.kvconfig").arg (themeName))
62 || QFile::exists (folderPath + QString ("/%1.svg").arg (themeName)))
63 {
64 return true;
65 }
66
67 return false;
68 }
69
isLightWithDarkDir(const QString & folderPath)70 static bool isLightWithDarkDir (const QString &folderPath)
71 {
72 if (folderPath.endsWith ("Dark"))
73 return false;
74 QDir dir = QDir (folderPath);
75 QString themeName = dir.dirName();
76 QStringList parts = folderPath.split ("/");
77 if (parts.last() == "Kvantum")
78 {
79 if (parts.size() < 3)
80 return false;
81 else
82 themeName = parts.at (parts.size() - 2);
83 }
84 if (themeName == "Default" || themeName == "Kvantum")
85 return false;
86 if (QFile::exists (folderPath + QString ("/%1.kvconfig").arg (themeName + "Dark"))
87 || QFile::exists (folderPath + QString ("/%1.svg").arg (themeName + "Dark")))
88 {
89 return true;
90 }
91 return false;
92 }
93
getAllThemes()94 static const QStringList getAllThemes()
95 {
96 const QString xdg_config_home = getHomeConfig();
97 QStringList list;
98
99 /* first add the user themes to the list */
100 QDir kv = QDir (QString ("%1/Kvantum").arg (xdg_config_home));
101 if (kv.exists())
102 {
103 const QStringList folders = kv.entryList (QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
104 for (const QString &folder : folders)
105 {
106 QString path = QString ("%1/Kvantum/%2").arg (xdg_config_home).arg (folder);
107 if (isThemeDir (path))
108 {
109 list << folder;
110 if (isLightWithDarkDir (path))
111 list << (folder + "Dark");
112 }
113 }
114 }
115 QString homeDir = QDir::homePath();
116 kv = QDir (QString ("%1/.themes").arg (homeDir));
117 if (kv.exists())
118 {
119 const QStringList folders = kv.entryList (QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
120 for (const QString &folder : folders)
121 {
122 QString path = QString ("%1/.themes/%2/Kvantum").arg (homeDir).arg (folder);
123 if (isThemeDir (path) && !folder.contains ("#"))
124 {
125 if (!list.contains (folder)) // the themes installed in the config folder have priority
126 list << folder;
127 if (isLightWithDarkDir (path) && !list.contains (folder + "Dark"))
128 list << (folder + "Dark");
129 }
130 }
131 }
132 kv = QDir (QString ("%1/.local/share/themes").arg (homeDir));
133 if (kv.exists())
134 {
135 const QStringList folders = kv.entryList (QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
136 for (const QString &folder : folders)
137 {
138 QString path = QString ("%1/.local/share/themes/%2/Kvantum").arg (homeDir).arg (folder);
139 if (isThemeDir (path) && !folder.contains ("#"))
140 {
141 if (!list.contains (folder)) // the user themes installed in the above paths have priority
142 list << folder;
143 if (isLightWithDarkDir (path) && !list.contains (folder + "Dark"))
144 list << (folder + "Dark");
145 }
146 }
147 }
148
149 /* now add the root themes */
150 QStringList rootList;
151 kv = QDir (QString (DATADIR) + QString ("/Kvantum"));
152 if (kv.exists())
153 {
154 const QStringList folders = kv.entryList (QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
155 for (const QString &folder : folders)
156 {
157 QString path = QString (DATADIR) + QString ("/Kvantum/%1").arg (folder);
158 if (!folder.contains ("#") && isThemeDir (path))
159 {
160 if (!list.contains (folder) // a user theme with the same name takes priority
161 && !list.contains (folder + "#"))
162 {
163 rootList << folder;
164 }
165 if (isLightWithDarkDir (path)
166 && !list.contains (folder + "Dark")
167 && !list.contains (folder + "Dark" + "#"))
168 {
169 rootList << (folder + "Dark");
170 }
171 }
172 }
173 }
174 kv = QDir (QString (DATADIR) + QString ("/themes"));
175 if (kv.exists())
176 {
177 const QStringList folders = kv.entryList (QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
178 for (const QString &folder : folders)
179 {
180 QString path = QString (DATADIR) + QString ("/themes/%1/Kvantum").arg (folder);
181 if (!folder.contains ("#") && isThemeDir (path))
182 {
183 if (!list.contains (folder) // a user theme with the same name takes priority
184 && !list.contains (folder + "#")
185 // a root theme inside 'DATADIR/Kvantum/' with the same name takes priority
186 && !rootList.contains (folder))
187 {
188 rootList << folder;
189 }
190 if (isLightWithDarkDir (path)
191 && !list.contains (folder + "Dark")
192 && !list.contains (folder + "Dark" + "#")
193 && !rootList.contains (folder + "Dark"))
194 {
195 rootList << (folder + "Dark");
196 }
197 }
198 }
199 }
200 if (!rootList.isEmpty())
201 list << rootList;
202
203 if (list.isEmpty() || !list.contains ("Default#"))
204 list << "Default";
205
206 return list;
207 }
208
setTheme(const QString & theme)209 bool setTheme (const QString& theme)
210 {
211 QString theTheme = theme;
212 const QStringList themes = getAllThemes();
213 if (!themes.contains (theTheme))
214 {
215 if (!theTheme.endsWith("#") && themes.contains (theTheme + "#"))
216 theTheme += "#";
217 else return false;
218 }
219 QString configFile = QString ("%1/Kvantum/kvantum.kvconfig").arg (getHomeConfig());
220 QSettings settings (configFile, QSettings::NativeFormat);
221 if (!settings.isWritable()) return false;
222
223 if (settings.value ("theme").toString() != theTheme)
224 settings.setValue ("theme", theTheme);
225
226 return true;
227 }
228
assignTheme(const QString & theme,const QStringList & apps)229 bool assignTheme (const QString& theme, const QStringList& apps)
230 {
231 QString configFile = QString ("%1/Kvantum/kvantum.kvconfig").arg (getHomeConfig());
232 QSettings settings (configFile, QSettings::NativeFormat);
233 if (!settings.isWritable()) return false;
234
235 if (theme.isEmpty()) // remove all assignments
236 settings.remove ("Applications");
237 else
238 {
239 QString theTheme = theme;
240 const QStringList themes = getAllThemes();
241 if (!themes.contains (theTheme))
242 {
243 if (!theTheme.endsWith("#") && themes.contains (theTheme + "#"))
244 theTheme += "#";
245 else return false;
246 }
247
248 settings.beginGroup ("Applications");
249 if (apps.isEmpty())
250 settings.remove (theTheme);
251 else
252 settings.setValue (theTheme, apps);
253 settings.endGroup();
254 }
255
256 return true;
257 }
258
259 }
260