diff --git a/localization/rssguard_cs.ts b/localization/rssguard_cs.ts
index 090da7b76..20ea76410 100644
--- a/localization/rssguard_cs.ts
+++ b/localization/rssguard_cs.ts
@@ -72,6 +72,13 @@
Hypertextový odkaz
+
+ CornerButton
+
+ Open new tab
+ Otevřít nový panel
+
+
FormAbout
@@ -210,7 +217,7 @@
Language
- Lokalizacce
+ Lokalizace
Proxy
@@ -424,6 +431,15 @@
no icon theme
žádné téma ikon
+
+ Some keyboard shortcuts are not unique.
+
+ Některé klávesové zkrátky jsou duplicitní.
+
+
+ Cannot save settings
+ Nastavení nelze uložit
+
FormWelcome
@@ -468,6 +484,13 @@
rotter.martinos@gmail.com
+
+ SkinFactory
+
+ default system skin
+ výchozí systémový vzhled
+
+
TabWidget
diff --git a/localization/rssguard_en.ts b/localization/rssguard_en.ts
index 1d527b282..c6454cd85 100644
--- a/localization/rssguard_en.ts
+++ b/localization/rssguard_en.ts
@@ -72,6 +72,13 @@
+
+ CornerButton
+
+ Open new tab
+
+
+
FormAbout
@@ -418,6 +425,15 @@
no icon theme
+
+ Some keyboard shortcuts are not unique.
+
+
+
+
+ Cannot save settings
+
+
FormWelcome
@@ -462,6 +478,13 @@
rotter.martinos@gmail.com
+
+ SkinFactory
+
+ default system skin
+
+
+
TabWidget
diff --git a/src/gui/dynamicshortcutswidget.cpp b/src/gui/dynamicshortcutswidget.cpp
index a6ab25bf3..594bd9dbb 100644
--- a/src/gui/dynamicshortcutswidget.cpp
+++ b/src/gui/dynamicshortcutswidget.cpp
@@ -19,6 +19,25 @@ DynamicShortcutsWidget::~DynamicShortcutsWidget() {
delete m_layout;
}
+bool DynamicShortcutsWidget::areShortcutsUnique() {
+ QList all_shortcuts;
+
+ // Obtain all shortcuts.
+ foreach (ActionBinding binding, m_actionBindings) {
+ QKeySequence new_shortcut = binding.second->shortcut();
+
+ if (all_shortcuts.contains(new_shortcut)) {
+ // Problem, two identical shortcuts found.
+ return false;
+ }
+ else {
+ all_shortcuts.append(binding.second->shortcut());
+ }
+ }
+
+ return true;
+}
+
void DynamicShortcutsWidget::updateShortcuts() {
foreach (ActionBinding binding, m_actionBindings) {
binding.first->setShortcut(binding.second->shortcut());
diff --git a/src/gui/dynamicshortcutswidget.h b/src/gui/dynamicshortcutswidget.h
index bc56e40ca..b60e99c45 100644
--- a/src/gui/dynamicshortcutswidget.h
+++ b/src/gui/dynamicshortcutswidget.h
@@ -23,6 +23,10 @@ class DynamicShortcutsWidget : public QWidget {
// and stored back to settings when application quits.
void updateShortcuts();
+ // Returns true if all shortcuts are unique,
+ // otherwise false.
+ bool areShortcutsUnique();
+
// Populates this widget with shortcut widgets for given actions.
// NOTE: This gets initial shortcut for each action from its properties, NOT from
// the application settings, so shortcuts from settings need to be
diff --git a/src/gui/formsettings.cpp b/src/gui/formsettings.cpp
index a65c876d0..63b8d4974 100644
--- a/src/gui/formsettings.cpp
+++ b/src/gui/formsettings.cpp
@@ -5,6 +5,7 @@
#include "gui/formsettings.h"
#include "gui/iconthemefactory.h"
+#include "gui/skinfactory.h"
#include "gui/systemtrayicon.h"
#include "gui/formmain.h"
#include "gui/webbrowser.h"
@@ -28,17 +29,31 @@ FormSettings::FormSettings(QWidget *parent) : QDialog(parent), m_ui(new Ui::Form
m_ui->m_treeLanguages->setHeaderHidden(false);
#if QT_VERSION >= 0x050000
+ // Setup languages.
m_ui->m_treeLanguages->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setSectionResizeMode(4, QHeaderView::ResizeToContents);
+
+ // Setup skins.
+ m_ui->m_treeSkins->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+ m_ui->m_treeSkins->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
+ m_ui->m_treeSkins->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
+ m_ui->m_treeSkins->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
#else
+ // Setup languages.
m_ui->m_treeLanguages->header()->setResizeMode(0, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setResizeMode(1, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setResizeMode(2, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setResizeMode(3, QHeaderView::ResizeToContents);
m_ui->m_treeLanguages->header()->setResizeMode(4, QHeaderView::ResizeToContents);
+
+ // Setup skins.
+ m_ui->m_treeSkins->header()->setResizeMode(0, QHeaderView::ResizeToContents);
+ m_ui->m_treeSkins->header()->setResizeMode(1, QHeaderView::ResizeToContents);
+ m_ui->m_treeSkins->header()->setResizeMode(2, QHeaderView::ResizeToContents);
+ m_ui->m_treeSkins->header()->setResizeMode(3, QHeaderView::ResizeToContents);
#endif
m_ui->m_treeLanguages->setHeaderLabels(QStringList()
@@ -48,8 +63,15 @@ FormSettings::FormSettings(QWidget *parent) : QDialog(parent), m_ui(new Ui::Form
<< tr("Author")
<< tr("Email"));
+ m_ui->m_treeSkins->setHeaderLabels(QStringList()
+ << tr("Name")
+ << tr("Version")
+ << tr("Author")
+ << tr("Email"));
+
// Establish needed connections.
- connect(this, SIGNAL(accepted()), this, SLOT(saveSettings()));
+ connect(m_ui->m_buttonBox, SIGNAL(accepted()),
+ this, SLOT(saveSettings()));
connect(m_ui->m_cmbProxyType, SIGNAL(currentIndexChanged(int)),
this, SLOT(onProxyTypeChanged(int)));
connect(m_ui->m_checkShowPassword, SIGNAL(stateChanged(int)),
@@ -88,7 +110,31 @@ void FormSettings::displayProxyPassword(int state) {
}
}
+bool FormSettings::doSaveCheck() {
+ bool everything_ok = true;
+ QString resulting_information;
+
+ everything_ok &= m_ui->m_shortcuts->areShortcutsUnique();
+
+ if (!m_ui->m_shortcuts->areShortcutsUnique()) {
+ resulting_information = resulting_information.append(tr("Some keyboard shortcuts are not unique.\n"));
+ }
+
+ if (!everything_ok) {
+ QMessageBox::warning(this,
+ tr("Cannot save settings"),
+ resulting_information);
+ }
+
+ return everything_ok;
+}
+
void FormSettings::saveSettings() {
+ // Make sure everything is saveable.
+ if (!doSaveCheck()) {
+ return;
+ }
+
// Save all settings.
saveGeneral();
saveShortcuts();
@@ -98,6 +144,8 @@ void FormSettings::saveSettings() {
saveLanguage();
Settings::getInstance()->checkSettings();
+
+ accept();
}
void FormSettings::onProxyTypeChanged(int index) {
@@ -349,6 +397,26 @@ void FormSettings::loadInterface() {
m_ui->m_cmbIconTheme->setCurrentIndex(theme_index);
}
#endif
+
+ // Load skin.
+ QList installed_skins = SkinFactory::getInstance()->getInstalledSkins();
+ QString active_skin = SkinFactory::getInstance()->getCurrentSkinName();
+
+ foreach (Skin skin, installed_skins) {
+ QTreeWidgetItem *new_item = new QTreeWidgetItem(QStringList() <<
+ skin.m_visibleName <<
+ skin.m_version <<
+ skin.m_author <<
+ skin.m_email);
+ new_item->setData(0, Qt::UserRole, QVariant::fromValue(skin));
+
+ // Add this skin and mark it as active if its active now.
+ m_ui->m_treeSkins->addTopLevelItem(new_item);
+
+ if (skin.m_baseName == active_skin) {
+ m_ui->m_treeSkins->setCurrentItem(new_item);
+ }
+ }
}
// Load tab settings.
@@ -387,6 +455,10 @@ void FormSettings::saveInterface() {
QString selected_icon_theme = m_ui->m_cmbIconTheme->itemData(m_ui->m_cmbIconTheme->currentIndex()).toString();
IconThemeFactory::getInstance()->setCurrentIconTheme(selected_icon_theme);
+ // Save and activate new skin.
+ Skin active_skin = m_ui->m_treeSkins->currentItem()->data(0, Qt::UserRole).value();
+ SkinFactory::getInstance()->setCurrentSkinName(active_skin.m_baseName);
+
// Save tab settings.
settings->setValue(APP_CFG_GUI, "tab_close_mid_button",
m_ui->m_checkCloseTabsMiddleClick->isChecked());
diff --git a/src/gui/formsettings.h b/src/gui/formsettings.h
index f03b1a4f0..ea43b0929 100644
--- a/src/gui/formsettings.h
+++ b/src/gui/formsettings.h
@@ -22,6 +22,9 @@ class FormSettings : public QDialog {
explicit FormSettings(QWidget *parent = 0);
virtual ~FormSettings();
+ protected:
+ bool doSaveCheck();
+
protected slots:
// Saves settings into global configuration.
void saveSettings();
diff --git a/src/gui/formsettings.ui b/src/gui/formsettings.ui
index b986b9d81..d293233d2 100644
--- a/src/gui/formsettings.ui
+++ b/src/gui/formsettings.ui
@@ -6,7 +6,7 @@
0
0
- 680
+ 829
414
@@ -17,7 +17,7 @@
-
- 4
+ 2
@@ -69,8 +69,8 @@
0
0
- 100
- 30
+ 585
+ 368
@@ -142,8 +142,29 @@
- -
-
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 0
+
+
+ false
+
+
+ false
+
+
+
+ 1
+
+
+
@@ -528,9 +549,15 @@
-
+
+
+ 220
+ 0
+
+
- 150
+ 220
16777215
@@ -586,22 +613,6 @@
-
- m_buttonBox
- accepted()
- FormSettings
- accept()
-
-
- 257
- 404
-
-
- 157
- 274
-
-
-
m_buttonBox
rejected()
diff --git a/src/gui/skinfactory.cpp b/src/gui/skinfactory.cpp
index e05e7f151..9d2555640 100644
--- a/src/gui/skinfactory.cpp
+++ b/src/gui/skinfactory.cpp
@@ -34,10 +34,15 @@ void SkinFactory::loadCurrentSkin() {
bool loaded = false;
Skin skin_data = getSkinInfo(skin_name_from_settings, &loaded);
- if (loaded) {
+ if (skin_name_from_settings == APP_THEME_SYSTEM) {
+ qApp->setStyleSheet(QString());
+ qApp->setStyle(NULL);
+ qDebug("System default skin loaded.");
+ }
+ else if (loaded) {
loadSkinFromData(skin_data.m_rawData, skin_name_from_settings);
- foreach (QString style, skin_data.m_stylesName.split("\n")) {
+ foreach (QString style, skin_data.m_stylesNames) {
if (qApp->setStyle(style) != 0) {
qDebug("Style '%s' loaded.", qPrintable(style));
break;
@@ -96,21 +101,27 @@ Skin SkinFactory::getSkinInfo(const QString &skin_name, bool *ok) {
QXmlQuery query;
QFile skin_file(APP_SKIN_PATH + QDir::separator() + skin_name);
- if (!skin_file.open(QIODevice::ReadOnly) ||!query.setFocus(&skin_file)) {
+ if (!skin_file.open(QIODevice::ReadOnly) || !query.setFocus(&skin_file)) {
if (ok) {
*ok = false;
}
return skin;
}
+ // Obtain visible skin name.
+ query.setQuery("string(skin/name)");
+ query.evaluateTo(&skin.m_visibleName);
+ skin.m_visibleName = skin.m_visibleName.remove("\n");
+
// Obtain skin raw data.
query.setQuery("string(skin/data)");
query.evaluateTo(&skin.m_rawData);
// Obtain style name.
query.setQuery("string(/skin/style)");
- query.evaluateTo(&skin.m_stylesName);
- skin.m_stylesName = skin.m_stylesName.remove("\n");
+ QString styles;
+ query.evaluateTo(&styles);
+ skin.m_stylesNames = styles.remove("\n").split(",");
// Obtain author.
query.setQuery("string(/skin/author/name)");
@@ -137,7 +148,7 @@ Skin SkinFactory::getSkinInfo(const QString &skin_name, bool *ok) {
if (ok) {
*ok = !skin.m_author.isEmpty() && !skin.m_version.isEmpty() &&
!skin.m_baseName.isEmpty() && !skin.m_email.isEmpty() &&
- !skin.m_rawData.isEmpty() && !skin.m_stylesName.isEmpty();
+ !skin.m_rawData.isEmpty() && !skin.m_stylesNames.isEmpty();
}
return skin;
@@ -145,5 +156,36 @@ Skin SkinFactory::getSkinInfo(const QString &skin_name, bool *ok) {
QList SkinFactory::getInstalledSkins() {
QList skins;
+
+ Skin default_skin;
+ default_skin.m_author = "-";
+ default_skin.m_baseName = APP_THEME_SYSTEM;
+ default_skin.m_email = "-";
+ default_skin.m_version = "-";
+ default_skin.m_visibleName = tr("default system skin");
+ skins.append(default_skin);
+
+ bool skin_load_ok;
+ QStringList skin_directories = QDir(APP_SKIN_PATH).entryList(QDir::Dirs |
+ QDir::NoDotAndDotDot |
+ QDir::NoSymLinks |
+ QDir::Readable);
+
+ foreach (QString base_directory, skin_directories) {
+ // Check skins installed in this base directory.
+ QStringList skin_files = QDir(APP_SKIN_PATH + QDir::separator() + base_directory).entryList(QStringList() << "*.xml",
+ QDir::Files | QDir::Readable | QDir::NoDotAndDotDot | QDir::NoSymLinks);
+
+ foreach (QString skin_file, skin_files) {
+ // Check if skin file is valid and add it if it is valid.
+ Skin skin_info = getSkinInfo(base_directory + QDir::separator() + skin_file,
+ &skin_load_ok);
+
+ if (skin_load_ok) {
+ skins.append(skin_info);
+ }
+ }
+ }
+
return skins;
}
diff --git a/src/gui/skinfactory.h b/src/gui/skinfactory.h
index 5c8c84c6e..80427a675 100644
--- a/src/gui/skinfactory.h
+++ b/src/gui/skinfactory.h
@@ -3,23 +3,31 @@
#include
#include
+#include
+#include
struct Skin {
QString m_baseName;
- QString m_stylesName;
+ QString m_visibleName;
+ QStringList m_stylesNames;
QString m_author;
QString m_email;
QString m_version;
QString m_rawData;
};
+Q_DECLARE_METATYPE(Skin)
+
class SkinFactory : public QObject {
Q_OBJECT
private:
explicit SkinFactory(QObject *parent = 0);
+ // Loads the skin from give skin_data.
+ // NOTE: Extra relative path escaping is done for loading of
+ // external resources.
bool loadSkinFromData(QString skin_data, const QString &skin_path);
public:
diff --git a/src/main.cpp b/src/main.cpp
index 484b7cb1d..5744ebb69 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -72,6 +72,7 @@ int main(int argc, char *argv[]) {
IconThemeFactory::getInstance()->setupSearchPaths();
IconThemeFactory::getInstance()->loadCurrentIconTheme(false);
SkinFactory::getInstance()->loadCurrentSkin();
+ SkinFactory::getInstance()->getInstalledSkins();
// Load localization and setup locale before any widget is constructed.
LoadLocalization();