Add a newline after variant tag when saving PGN.
[tagua/yd.git] / src / pref_theme.cpp
blob93c0fa338d44735150c105d1d32c10fb95cf7fef
1 /*
2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@gmail.com>
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>
15 #include <KStandardDirs>
17 #include "foreach.h"
18 #include "mastersettings.h"
19 #include "luaapi/loader.h"
20 #include "variants.h"
21 #include "tagua.h"
22 #include "pref_theme.h"
25 PrefTheme::ThemeInfoList PrefTheme::to_theme_info_list(const QStringList& files, const Settings& s) {
26 //std::cout << "about to examine " << files.size() << " desktop files" << std::endl;
27 std::map<QString, ThemeInfo> cached_info;
29 SettingArray themes = s.group("themes").array("theme");
30 foreach (Settings s_theme, themes) {
31 ThemeInfo info = ThemeInfo::fromSettings(s_theme);
32 cached_info[info.desktopFile] = info;
35 ThemeInfoList all_themes;
36 bool updated = false;
38 for(int i = 0; i < files.size(); i++) {
39 QFileInfo file_info(files[i]);
40 std::map<QString, ThemeInfo>::iterator it = cached_info.find(files[i]);
42 if (it != cached_info.end()
43 && file_info.exists()
44 && it->second.last_modified == file_info.lastModified() ) {
45 all_themes << it->second;
46 cached_info.erase(it);
48 else {
49 updated = true;
51 ThemeInfo theme_info = ThemeInfo::fromDesktopFile(files[i]);
52 all_themes << theme_info;
54 if (theme_info.name.isEmpty()) {
55 ERROR("No name property in " << files[i]);
60 if(!cached_info.empty())
61 updated = true;
63 /* rewrite the cached configuration */
64 if(updated) {
65 SettingArray themes = s.group("themes").newArray("theme");
67 for (int i = 0; i < all_themes.size(); i++) {
68 Settings s_theme = themes.append();
69 all_themes[i].save(s_theme);
73 return all_themes;
77 OptList PrefTheme::get_file_options(const QString& f, bool reload_defaults) {
78 //std::cout << "get file options for " << f << std::endl;
80 if(!reload_defaults) {
81 std::map<QString, OptList>::iterator it = m_new_theme_options.find(f);
83 if(it != m_new_theme_options.end())
84 return it->second;
87 LuaApi::Loader lua_context;
88 lua_context.runFile(f);
90 if(lua_context.error()) {
91 ERROR(lua_context.errorString());
92 lua_context.clearError();
94 m_new_theme_options[f] = OptList();
95 return OptList();
98 OptList o = lua_context.getValue<OptList>("options", 0, NULL, true);
99 if(lua_context.error()) {
100 ERROR(lua_context.errorString());
101 lua_context.clearError();
104 if(!reload_defaults) {
105 SettingMap<QString> s_lua = settings().group("lua-settings").map<QString>("entry", "file-name");
106 Settings entry = s_lua.insert(f);
107 options_list_load_from_settings(o, entry.group("options"));
109 m_new_theme_options[f] = o;
111 return o;
115 int PrefTheme::theme_ok_for_variant(const ThemeInfo& theme_info, const QString& variant_name) {
116 if(theme_info.variants.contains(variant_name+"[default]", Qt::CaseInsensitive))
117 return 4;
118 if(theme_info.variants.contains(variant_name, Qt::CaseInsensitive))
119 return 3;
120 if(theme_info.variants.contains("any[default]", Qt::CaseInsensitive))
121 return 2;
122 if(theme_info.variants.contains("any", Qt::CaseInsensitive))
123 return 1;
124 return 0;
128 PrefTheme::PrefTheme(const QString& currentVariant, QWidget *parent)
129 : QWidget(parent) {
130 setupUi(this);
132 Category *c;
134 c = new Category(NULL, this);
135 m_categories["pieces"] = c;
136 tabWidget->addTab(c, "&Pieces");
138 c = new Category(NULL, this);
139 m_categories["squares"] = c;
140 tabWidget->addTab(c, "&Squares");
142 c = new Category(NULL, this);
143 m_categories["controls"] = c;
144 tabWidget->addTab(c, "&Controls");
146 MasterSettings cached_theme_info("tagua_config_cache.xml");
147 connect(comboVariant, SIGNAL(currentIndexChanged(int)), this, SLOT(variantChanged()));
149 for(CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) {
150 Category* c = cit->second;
152 c->m_list->setSelectionMode(QAbstractItemView::SingleSelection);
153 connect(c->m_list, SIGNAL(itemSelectionChanged()), c, SLOT(themeChanged()));
154 connect(c->m_check, SIGNAL(toggled(bool)), c, SLOT(themeChecked(bool)));
155 c->m_opt_layout = new QHBoxLayout(c->m_widget);
156 c->m_opt_layout->setMargin(0);
158 c->m_themes = to_theme_info_list(
159 KGlobal::dirs()->findAllResources("appdata",
160 "themes/"+cit->first+"/*.desktop",
161 KStandardDirs::Recursive),
162 cached_theme_info.group(cit->first)
165 //std::cout << "loaded " << c->m_themes.size() << " themes" << std::endl;
168 QStringList all = Variants::instance().all();
169 int index = 0;
170 int current = -1;
171 foreach (QString variant, all) {
172 if (variant == currentVariant) {
173 current = index;
175 comboVariant->addItem(variant, QVariant(variant));
176 index++;
179 if (current != -1)
180 comboVariant->setCurrentIndex(current);
182 variantChanged();
185 PrefTheme::~PrefTheme() {
189 void PrefTheme::apply() {
190 SettingMap<QString> variants = settings().group("variants").map<QString>("variant", "name");
192 for(CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) {
193 Category* c = cit->second;
195 for(std::map<QString, QString>::iterator it = c->m_new_themes.begin();
196 it != c->m_new_themes.end(); ++it) {
197 Settings var = variants.insert(it->first);
198 var[cit->first+"-theme"] = it->second;
200 for(std::map<QString, bool>::iterator it = c->m_new_use_def.begin();
201 it != c->m_new_use_def.end(); ++it) {
202 Settings var = variants.insert(it->first);
203 var[cit->first+"-use-def"] = it->second;
207 for(std::map<QString, OptList>::iterator it = m_new_theme_options.begin();
208 it != m_new_theme_options.end(); ++it) {
209 SettingMap<QString> s_lua = settings().group("lua-settings").map<QString>("entry", "file-name");
210 Settings entry = s_lua.insert(it->first);
211 options_list_save_to_settings(it->second, entry.group("options"));
215 void PrefTheme::update_list_view(QListWidget* list, const ThemeInfoList& themes,
216 QString variant_name, QString settings_theme) {
217 list->clear();
219 int selected_ok = 0;
220 QListWidgetItem *item_to_select = NULL;
222 for (int i = 0; i < themes.size(); i++) {
223 int ok = theme_ok_for_variant(themes[i], variant_name);
224 if (!ok)
225 continue;
227 ok = (themes[i].desktopFile == settings_theme) ? 5 : ok;
228 QListWidgetItem *list_item = new QListWidgetItem(themes[i].name, list);
230 list_item->setData(Qt::UserRole, i);
231 if(ok > selected_ok) {
232 item_to_select = list_item;
233 selected_ok = ok;
237 if(item_to_select)
238 list->setItemSelected(item_to_select, true);
241 void PrefTheme::variantChanged() {
242 QString category = comboVariant->itemData(comboVariant->currentIndex()).toString();
243 VariantFactory* vi = Variants::instance().getFactory(category);
245 if (!vi) {
246 for (CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) {
247 Category* c = cit->second;
249 c->m_check->hide();
250 c->m_list->clear();
251 c->m_list->setEnabled(false);
252 c->m_label->setText(QString());
253 c->m_label->setEnabled(false);
256 return;
259 QString variant_name = vi->name();
260 QString variant_proxy = vi->themeProxy();
261 SettingMap<QString> variants = settings().group("variants").map<QString>("variant", "name");
262 Settings var = variants.insert(variant_name);
263 bool check_proxy = variant_name != variant_proxy;
265 for(CategoryMap::iterator cit = m_categories.begin(); cit != m_categories.end(); ++cit) {
266 Category* c = cit->second;
268 c->m_check->setVisible(check_proxy);
269 if(check_proxy) {
270 bool use_def = c->m_new_use_def.count(variant_name)
271 ? c->m_new_use_def[variant_name]
272 : (var[cit->first+"-use-def"] | true).value();
273 c->m_check->setText("Same as "+variant_proxy);
274 c->m_check->setChecked(use_def);
275 c->m_list->setEnabled(!use_def);
276 c->m_label->setEnabled(!use_def);
278 else {
279 c->m_list->setEnabled(true);
280 c->m_label->setEnabled(true);
283 QString settings_theme = c->m_new_themes.count(variant_name)
284 ? c->m_new_themes[variant_name]
285 : (var[cit->first+"-theme"] | QString()).value();
286 update_list_view(c->m_list, c->m_themes, variant_proxy, settings_theme);
290 ThemeInfo PrefTheme::getBestTheme(const VariantPtr& vi, const QString& category) {
291 QString tag = category + "-theme";
292 QString deftag = category + "-use-def";
293 QString variant_name = vi->name();
294 QString variant_proxy_name = vi->themeProxy();
295 SettingMap<QString> variants = settings().group("variants").map<QString>("variant", "name");
296 if (variant_name != vi->themeProxy() &&
297 (variants.insert(variant_name)[deftag] | true) )
298 variant_name = vi->themeProxy();
300 Settings var_settings = variants.insert(variant_name);
301 if (var_settings[tag] && QFile::exists(var_settings[tag].value<QString>()) ) {
303 // there is a theme in the settings, so pick this
304 ThemeInfo res = ThemeInfo::fromDesktopFile(var_settings[tag].value<QString>());
305 if(theme_ok_for_variant(res, variant_proxy_name))
306 return res;
309 MasterSettings cached_theme_info("tagua_config_cache.xml");
310 KStandardDirs* std_dirs = KGlobal::dirs();
311 ThemeInfoList themes = to_theme_info_list(std_dirs->findAllResources("appdata",
312 "themes/" + category + "/*.desktop",
313 KStandardDirs::Recursive ),
314 cached_theme_info.group(category));
316 int best = 0;
317 ThemeInfo* retv = 0;
318 for(int i = 0; i < themes.size(); i++) {
319 int ok = theme_ok_for_variant(themes[i], variant_proxy_name);
320 if (!ok)
321 continue;
323 if (ok > best) {
324 retv = &themes[i];
325 best = ok;
330 if (retv && *retv) {
331 var_settings[tag] = retv->desktopFile;
334 return retv ? *retv : ThemeInfo();
337 PrefThemeCategory::PrefThemeCategory(QWidget* parent, PrefTheme* owner)
338 : QWidget(parent)
339 , m_parent(owner)
340 , m_opt_layout(NULL)
341 , m_opt_widget(NULL) {
342 setupUi(this);
343 m_reset = new QAction(KIcon("eraser"), "&Reset to default", this);
344 m_reset->setShortcut(Qt::CTRL+Qt::Key_Z);
345 connect(m_reset, SIGNAL(triggered()), this, SLOT(reset()));
346 m_resetButton->setDefaultAction(m_reset);
347 m_resetButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
350 void PrefThemeCategory::reset() {
351 if(!m_opt_widget)
352 return;
354 QList<QListWidgetItem *> l = m_list->selectedItems();
355 if(l.isEmpty())
356 return;
358 int i = l[0]->data(Qt::UserRole).toInt();
359 if (i >= 0 && i < m_themes.size()) {
360 OptList ol = m_parent->get_file_options(m_themes[i].file_name, true);
361 qobject_cast<OptionWidget*>(m_opt_widget)->setValues(ol);
365 void PrefThemeCategory::themeChanged() {
366 QList<QListWidgetItem *> l = m_list->selectedItems();
367 if(!l.isEmpty()) {
368 int i = l[0]->data(Qt::UserRole).toInt();
369 if(i>=0 && i<m_themes.size()) {
370 m_label->setText(m_themes[i].description);
372 QString c = m_parent->comboVariant->itemData(m_parent->comboVariant->currentIndex()).toString();
373 VariantFactory* vi = Variants::instance().getFactory(c);
374 if(vi)
375 m_new_themes[vi->name()] = m_themes[i].desktopFile;
377 if(m_opt_widget) {
378 delete m_opt_widget;
379 m_opt_widget = NULL;
381 OptList ol = m_parent->get_file_options(m_themes[i].file_name);
382 if (ol.size() != 0 && m_list->isEnabled()) {
383 m_opt_widget = new OptionWidget(ol, m_widget);
384 m_opt_layout->addWidget(m_opt_widget);
385 m_reset->setEnabled(true);
387 else
388 m_reset->setEnabled(false);
389 return;
392 m_label->setText(QString());
395 void PrefThemeCategory::themeChecked(bool ck) {
396 m_list->setEnabled(!ck);
397 m_label->setEnabled(!ck);
399 QString c = m_parent->comboVariant->itemData(m_parent->comboVariant->currentIndex()).toString();
400 VariantFactory* vi = Variants::instance().getFactory(c);
401 if (vi)
402 m_new_use_def[vi->name()] = ck;
403 themeChanged();