Removed global settings object. Fixes ticket #18.
[tagua/yd.git] / src / pref_theme.cpp
blob35dd40fc1379c4a7282c1a6b49945035b8f11e77
1 /*
2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@sns.it>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 // */
11 #include <QDir>
12 #include <QFileInfo>
13 #include <QStringList>
14 #include <QListWidgetItem>
16 #include <KDesktopFile>
17 #include <KStandardDirs>
19 #include "mastersettings.h"
20 #include "luaapi/loader.h"
21 #include "variants/variants.h"
22 #include "tagua.h"
23 #include "pref_theme.h"
25 void PrefTheme::read_theme_info(ThemeInfo& info, const QString& desktopFile) {
26 info.desktopFile = desktopFile;
27 if (!KDesktopFile::isDesktopFile(desktopFile)) {
28 return;
31 KDesktopFile theme(desktopFile);
32 KConfigGroup themeData = theme.desktopGroup();
34 info.name = theme.readName();
35 info.description = theme.readComment();
36 info.description.replace("|", "\n");
37 info.variants = themeData.readEntry("X-Tagua-Variants").split(QRegExp("\\s*,\\s*"));
38 info.file_name = themeData.readEntry("X-Tagua-Script");
39 if (info.file_name.isEmpty()) {
40 // use a file with the same name as the .desktop, but with as .lua extension
41 info.file_name = desktopFile;
42 info.file_name.replace(QRegExp("\\.desktop$"), ".lua");
44 else {
45 QFileInfo filePath(info.file_name);
46 QFileInfo desktopPath(desktopFile);
47 if (!filePath.isAbsolute()) {
48 // the file is relative to the .desktop directory
49 info.file_name = QDir(desktopPath.path()).filePath(info.file_name);
54 PrefTheme::ThemeInfoList PrefTheme::to_theme_info_list(const QStringList& files, const Settings& s) {
55 std::cout << "about to examine " << files.size() << " desktop files" << std::endl;
56 std::map<QString, ThemeInfo> cache;
58 SettingArray themes = s.group("themes").array("theme");
59 foreach (Settings s_theme, themes) {
60 ThemeInfo info = ThemeInfo::fromSettings(s_theme);
61 cache[info.desktopFile] = info;
64 ThemeInfoList allluafiles;
65 ThemeInfoList retv;
66 bool updated = false;
68 for(int i = 0; i < files.size(); i++) {
69 QDateTime lm = QFileInfo(files[i]).lastModified();
70 std::map<QString, ThemeInfo>::iterator it = cache.find(files[i]);
72 if (it != cache.end() && it->second.last_modified == lm) {
73 if (!it->second.name.isEmpty())
74 retv << it->second;
76 else {
77 updated = true;
79 ThemeInfo info;
80 info.last_modified = lm;
81 read_theme_info(info, files[i]);
82 retv << info;
83 allluafiles << info;
85 if (info.name.isEmpty()) {
86 ERROR("No name property in " << files[i]);
91 if(updated) {
92 SettingArray themes = s.group("themes").newArray("theme");
94 for (int i = 0; i < allluafiles.size(); i++) {
95 Settings s_theme = themes.append();
96 allluafiles[i].save(s_theme);
100 return retv;
103 OptList PrefTheme::get_file_options(const QString& f, bool reload_defaults) {
104 if(!reload_defaults)
105 if(boost::shared_ptr<OptList> o = m_new_theme_options[f])
106 return *o;
108 LuaApi::Loader l;
109 l.runFile(f);
111 boost::shared_ptr<OptList> o(new OptList(l.getValue<OptList>("options", 0, NULL, true)));
112 if(l.error()) {
113 ERROR(l.errorString());
114 l.clearError();
117 if(!reload_defaults) {
118 SettingMap<QString> s_lua = settings().group("lua-settings").map<QString>("entry", "file-name");
119 Settings entry = s_lua.insert(f);
120 options_list_load_from_settings(*o, entry.group("options"));
122 m_new_theme_options[f] = o;
124 return *o;
127 PrefTheme::PrefTheme(QWidget *parent)
128 : QWidget(parent) {
129 setupUi(this);
131 Category *c;
133 c = new Category(NULL, this);
134 m_categories["pieces"] = c;
135 tabWidget->addTab(c, "&Pieces");
137 c = new Category(NULL, this);
138 m_categories["squares"] = c;
139 tabWidget->addTab(c, "&Squares");
141 c = new Category(NULL, this);
142 m_categories["controls"] = c;
143 tabWidget->addTab(c, "&Controls");
145 MasterSettings s(".tagua_config_cache.xml");
146 connect(comboVariant, SIGNAL(currentIndexChanged(int)), this, SLOT(variantChanged()));
148 for(CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) {
149 Category* c = cit->second;
151 c->m_list->setSelectionMode(QAbstractItemView::SingleSelection);
152 connect(c->m_list, SIGNAL(itemSelectionChanged()), c, SLOT(themeChanged()));
153 connect(c->m_check, SIGNAL(toggled(bool)), c, SLOT(themeChecked(bool)));
154 c->m_opt_layout = new QHBoxLayout(c->m_widget);
155 c->m_opt_layout->setMargin(0);
157 c->m_themes = to_theme_info_list(
158 KGlobal::dirs()->findAllResources("appdata", "themes/"+cit->first+"/*.desktop", KStandardDirs::Recursive),
159 s.group(cit->first)
162 std::cout << "loaded " << c->m_themes.size() << " themes" << std::endl;
165 const Variant::Variants& all = Variant::allVariants();
166 for(Variant::Variants::const_iterator it = all.begin(); it != all.end(); ++it)
167 comboVariant->addItem(it->first, QVariant(it->first));
169 variantChanged();
172 PrefTheme::~PrefTheme() {
176 void PrefTheme::apply() {
177 SettingMap<QString> variants = settings().group("variants").map<QString>("variant", "name");
179 for(CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) {
180 Category* c = cit->second;
182 for(std::map<QString, QString>::iterator it = c->m_new_themes.begin();
183 it != c->m_new_themes.end(); ++it) {
184 Settings var = variants.insert(it->first);
185 var[cit->first+"-theme"] = it->second;
187 for(std::map<QString, bool>::iterator it = c->m_new_use_def.begin();
188 it != c->m_new_use_def.end(); ++it) {
189 Settings var = variants.insert(it->first);
190 var[cit->first+"-use-def"] = it->second;
194 for(std::map<QString, boost::shared_ptr<OptList> >::iterator it = m_new_theme_options.begin();
195 it != m_new_theme_options.end(); ++it) {
196 SettingMap<QString> s_lua = settings().group("lua-settings").map<QString>("entry", "file-name");
197 Settings entry = s_lua.insert(it->first);
198 options_list_save_to_settings(*it->second, entry.group("options"));
202 void PrefTheme::update_list_view(QListWidget* list, const ThemeInfoList& themes,
203 QString variant, QString settings_theme) {
204 list->clear();
206 int selected = 0;
207 QListWidgetItem *prev_sel = 0;
209 for (int i = 0; i < themes.size(); i++) {
210 int ok = 0;
211 ok = themes[i].variants.contains("any", Qt::CaseInsensitive) ? 1 : ok;
212 ok = themes[i].variants.contains("any[default]", Qt::CaseInsensitive) ? 2 : ok;
213 ok = themes[i].variants.contains(variant, Qt::CaseInsensitive) ? 3 : ok;
214 ok = themes[i].variants.contains(variant+"[default]", Qt::CaseInsensitive) ? 4 : ok;
215 if (!ok)
216 continue;
217 ok = (themes[i].desktopFile == settings_theme) ? 5 : ok;
218 QListWidgetItem *w = new QListWidgetItem(themes[i].name, list);
220 w->setData(Qt::UserRole, i);
221 if(ok > selected) {
222 if(prev_sel)
223 list->setItemSelected(prev_sel, false);
224 list->setItemSelected(w, true);
225 prev_sel = w;
226 selected = ok;
231 void PrefTheme::variantChanged() {
232 QString c = comboVariant->itemData(comboVariant->currentIndex()).toString();
233 VariantInfo *vi = Variant::variant(c);
234 if(!vi) {
235 for(CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) {
236 Category* c = cit->second;
238 c->m_check->hide();
239 c->m_list->clear();
240 c->m_list->setEnabled(false);
241 c->m_label->setText(QString());
242 c->m_label->setEnabled(false);
245 return;
248 QString vname = vi->name();
249 QString vproxy = vi->themeProxy();
250 SettingMap<QString> variants = settings().group("variants").map<QString>("variant", "name");
251 Settings var = variants.insert(vname);
252 bool ck = vname != vproxy;
254 for(CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) {
255 Category* c = cit->second;
257 c->m_check->setVisible(ck);
258 if(ck) {
259 bool d = c->m_new_use_def.count(vname) ? c->m_new_use_def[vname]
260 : (var[cit->first+"-use-def"] | true).value();
261 c->m_check->setText("Same as "+vproxy);
262 c->m_check->setChecked(d);
263 c->m_list->setEnabled(!d);
264 c->m_label->setEnabled(!d);
266 else {
267 c->m_list->setEnabled(true);
268 c->m_label->setEnabled(true);
271 QString th = c->m_new_themes.count(vname) ? c->m_new_themes[vname]
272 : (var[cit->first+"-theme"] | QString()).value();
273 update_list_view(c->m_list, c->m_themes, vproxy, th);
277 ThemeInfo PrefTheme::getBestTheme(VariantInfo* vi, const QString& category) {
278 QString tag = category + "-theme";
279 QString deftag = category + "-use-def";
280 QString v = vi->name();
281 SettingMap<QString> variants = settings().group("variants").map<QString>("variant", "name");
282 if (v != vi->themeProxy() &&
283 (variants.insert(v)[deftag] | true) )
284 v = vi->themeProxy();
286 Settings var = variants.insert(v);
287 if (var[tag]) {
288 // there is a theme in the settings, so pick this
289 ThemeInfo res;
290 read_theme_info(res, var[tag].value<QString>());
291 return res;
294 MasterSettings s(".tagua_config_cache.xml");
295 KStandardDirs* dirs = KGlobal::dirs();
296 ThemeInfoList themes = to_theme_info_list(dirs->findAllResources("appdata", "themes/"+category+"/*.desktop",
297 KStandardDirs::Recursive), s.group(category));
298 std::cout << "found " << themes.size() << " themes" << std::endl;
300 int best = 0;
301 ThemeInfo* retv;
302 for(int i=0;i<themes.size();i++) {
303 int ok = 0;
304 ok = themes[i].variants.contains("any", Qt::CaseInsensitive) ? 1 : ok;
305 ok = themes[i].variants.contains("any[default]", Qt::CaseInsensitive) ? 2 : ok;
306 ok = themes[i].variants.contains(v, Qt::CaseInsensitive) ? 3 : ok;
307 ok = themes[i].variants.contains(v+"[default]", Qt::CaseInsensitive) ? 4 : ok;
308 if (!ok)
309 continue;
311 if (ok > best) {
312 retv = &themes[i];
313 best = ok;
317 if (*retv)
318 var[tag] = retv->desktopFile;
320 return *retv;
323 PrefThemeCategory::PrefThemeCategory(QWidget* parent, PrefTheme* owner)
324 : QWidget(parent)
325 , m_parent(owner)
326 , m_opt_layout(NULL)
327 , m_opt_widget(NULL) {
328 setupUi(this);
329 m_reset = new QAction(KIcon("eraser"), "&Reset to default", this);
330 m_reset->setShortcut(Qt::CTRL+Qt::Key_Z);
331 connect(m_reset, SIGNAL(triggered()), this, SLOT(reset()));
332 m_resetButton->setDefaultAction(m_reset);
333 m_resetButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
336 void PrefThemeCategory::reset() {
337 if(!m_opt_widget)
338 return;
340 QList<QListWidgetItem *> l = m_list->selectedItems();
341 if(l.isEmpty())
342 return;
344 int i = l[0]->data(Qt::UserRole).toInt();
345 if (i >= 0 && i < m_themes.size()) {
346 OptList ol = m_parent->get_file_options(m_themes[i].file_name, true);
347 qobject_cast<OptionWidget*>(m_opt_widget)->setValues(ol);
351 void PrefThemeCategory::themeChanged() {
352 QList<QListWidgetItem *> l = m_list->selectedItems();
353 if(!l.isEmpty()) {
354 int i = l[0]->data(Qt::UserRole).toInt();
355 if(i>=0 && i<m_themes.size()) {
356 m_label->setText(m_themes[i].description);
358 QString c = m_parent->comboVariant->itemData(m_parent->comboVariant->currentIndex()).toString();
359 VariantInfo *vi = Variant::variant(c);
360 if(vi)
361 m_new_themes[vi->name()] = m_themes[i].desktopFile;
363 if(m_opt_widget) {
364 delete m_opt_widget;
365 m_opt_widget = NULL;
367 OptList ol = m_parent->get_file_options(m_themes[i].file_name);
368 if(ol.size() != 0) {
369 m_opt_widget = new OptionWidget(ol, m_widget);
370 m_opt_layout->addWidget(m_opt_widget);
371 m_reset->setEnabled(true);
373 else
374 m_reset->setEnabled(false);
375 return;
378 m_label->setText(QString());
381 void PrefThemeCategory::themeChecked(bool ck) {
382 m_list->setEnabled(!ck);
383 m_label->setEnabled(!ck);
385 QString c = m_parent->comboVariant->itemData(m_parent->comboVariant->currentIndex()).toString();
386 VariantInfo *vi = Variant::variant(c);
387 if(vi)
388 m_new_use_def[vi->name()] = ck;