Work on skins.

This commit is contained in:
Martin Rotter 2013-09-06 20:26:12 +02:00
parent a80270560d
commit 99c011de41
7 changed files with 224 additions and 13 deletions

View File

@ -137,10 +137,11 @@ if(${USE_QT_5})
find_package(Qt5WebKitWidgets)
find_package(Qt5Widgets)
find_package(Qt5Xml)
find_package(Qt5XmlPatterns)
find_package(Qt5Network)
find_package(Qt5LinguistTools)
else(${USE_QT_5})
find_package(Qt4 REQUIRED QtCore QtGui QtSql QtNetwork QtWebkit QtXml)
find_package(Qt4 REQUIRED QtCore QtGui QtSql QtNetwork QtWebkit QtXml QtXmlPatterns)
include(${QT_USE_FILE})
endif(${USE_QT_5})
@ -157,9 +158,9 @@ if(MINGW AND WIN32)
)
set(APP_SOURCES ${APP_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/resources/executable_properties/rssguard_win.o)
# MSVC takes care of this automatically no need to use windres.exe
# MSVC takes care of this automatically - no need to use windres.exe
# for MSVC compilers.
elseif(WIN32)
elseif(MINGW AND WIN32)
set(APP_SOURCES ${APP_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/resources/executable_properties/rssguard_win.rc)
endif(MINGW AND WIN32)
@ -175,6 +176,7 @@ set(APP_SOURCES
src/gui/formmain.cpp
src/gui/systemtrayicon.cpp
src/gui/iconthemefactory.cpp
src/gui/skinfactory.cpp
src/gui/formsettings.cpp
src/gui/formwelcome.cpp
src/gui/formabout.cpp
@ -218,6 +220,7 @@ set(APP_HEADERS
src/gui/formmain.h
src/gui/systemtrayicon.h
src/gui/iconthemefactory.h
src/gui/skinfactory.h
src/gui/formsettings.h
src/gui/formwelcome.h
src/gui/formabout.h
@ -334,6 +337,7 @@ if(${USE_QT_5})
Sql
Network
Xml
XmlPatterns
WebKit
WebKitWidgets
)
@ -354,6 +358,7 @@ else(${USE_QT_5})
${QT_QTNETWORK_LIBRARY}
${QT_QTSQL_LIBRARY}
${QT_QTXML_LIBRARY}
${QT_QTXMLPATTERNS_LIBRARY}
${QT_QTMAIN_LIBRARY}
${QT_QTWEBKIT_LIBRARY}
)

View File

@ -122,7 +122,7 @@ void FormMain::cleanupResources() {
}
bool FormMain::event(QEvent *event) {
if (event->type() == ThemeFactoryEvent::type()) {
if (event->type() == IconThemeFactoryEvent::type()) {
// Handle the change of icon theme.
setupIcons();
event->accept();

View File

@ -11,20 +11,20 @@
QPointer<IconThemeFactory> IconThemeFactory::s_instance;
QEvent::Type ThemeFactoryEvent::m_typeOfEvent = QEvent::None;
QEvent::Type IconThemeFactoryEvent::m_typeOfEvent = QEvent::None;
//
// ThemeFactoryEvent class
//
ThemeFactoryEvent::ThemeFactoryEvent() : QEvent(ThemeFactoryEvent::type()) {
IconThemeFactoryEvent::IconThemeFactoryEvent() : QEvent(IconThemeFactoryEvent::type()) {
}
ThemeFactoryEvent::~ThemeFactoryEvent() {
IconThemeFactoryEvent::~IconThemeFactoryEvent() {
qDebug("Destroying IconThemeFactoryEvent.");
}
QEvent::Type ThemeFactoryEvent::type() {
QEvent::Type IconThemeFactoryEvent::type() {
if (m_typeOfEvent == QEvent::None) {
m_typeOfEvent = static_cast<QEvent::Type>(QEvent::registerEventType(2000));
}
@ -109,7 +109,7 @@ void IconThemeFactory::loadCurrentIconTheme(bool notify_widgets) {
if (notify_widgets) {
foreach (QWidget *widget, QtSingleApplication::allWidgets()) {
QtSingleApplication::postEvent((QObject*) widget,
new ThemeFactoryEvent());
new IconThemeFactoryEvent());
}
}
}

View File

@ -54,15 +54,15 @@ class IconThemeFactory : public QObject {
static QPointer<IconThemeFactory> s_instance;
};
class ThemeFactoryEvent : public QEvent {
class IconThemeFactoryEvent : public QEvent {
public:
enum Type {
IconThemeChange = 2000
};
// Constructors.
explicit ThemeFactoryEvent();
virtual ~ThemeFactoryEvent();
explicit IconThemeFactoryEvent();
virtual ~IconThemeFactoryEvent();
static QEvent::Type type();

149
src/gui/skinfactory.cpp Normal file
View File

@ -0,0 +1,149 @@
#include <QApplication>
#include <QDomDocument>
#include <QDir>
#include <QXmlQuery>
#include <QStyleFactory>
#include "core/defs.h"
#include "core/settings.h"
#include "gui/skinfactory.h"
QPointer<SkinFactory> SkinFactory::s_instance;
SkinFactory::SkinFactory(QObject *parent)
: QObject(parent), m_currentSkin(APP_THEME_SYSTEM) {
}
SkinFactory::~SkinFactory() {
qDebug("Destroying SkinFactory instance.");
}
SkinFactory *SkinFactory::getInstance() {
if (s_instance.isNull()) {
s_instance = new SkinFactory(qApp);
}
return s_instance;
}
void SkinFactory::loadCurrentSkin() {
QString skin_name_from_settings = Settings::getInstance()->value(APP_CFG_GUI,
"skin",
"base/plain.xml").toString();
bool loaded = false;
Skin skin_data = getSkinInfo(skin_name_from_settings, &loaded);
if (loaded) {
loadSkinFromData(skin_data.m_rawData, skin_name_from_settings);
foreach (QString style, skin_data.m_stylesName.split("\n")) {
if (qApp->setStyle(style) != 0) {
qDebug("Style '%s' loaded.", qPrintable(style));
break;
}
}
m_currentSkin = skin_name_from_settings;
qDebug("Skin '%s' loaded.", qPrintable(skin_name_from_settings));
}
else {
qDebug("Skin '%s' not loaded because style name is not specified or skin raw data is missing.",
qPrintable(skin_name_from_settings));
}
}
bool SkinFactory::loadSkinFromData(QString skin_data, const QString &skin_path) {
QStringList skin_parts = skin_path.split('/', QString::SkipEmptyParts);
// Skin does not contain leading folder name or the actual skin file name.
if (skin_parts.size() != 2) {
qDebug("Loading of sking %s failed because skin name does not contain "
"base folder name or the actual skin name.",
qPrintable(skin_path));
return false;
}
else {
qDebug("Loading skin '%s'.", qPrintable(skin_path));
}
// Create needed variables and create QFile object representing skin contents.
QString skin_folder = skin_parts.at(0);
// Here we use "/" instead of QDir::separator() because CSS2.1 url field
// accepts '/' as path elements separator.
//
// "##" is placeholder for the actual path to skin file. This is needed for using
// images within the QSS file.
QString parsed_data = skin_data.replace("##",
APP_SKIN_PATH + "/" + skin_folder + "/images");
qApp->setStyleSheet(parsed_data);
return true;
}
void SkinFactory::setCurrentSkinName(const QString &skin_name) {
Settings::getInstance()->setValue(APP_CFG_GUI, "skin", skin_name);
loadCurrentSkin();
}
QString SkinFactory::getCurrentSkinName() {
return m_currentSkin;
}
Skin SkinFactory::getSkinInfo(const QString &skin_name, bool *ok) {
Skin skin;
QXmlQuery query;
QFile skin_file(APP_SKIN_PATH + QDir::separator() + skin_name);
if (!skin_file.open(QIODevice::ReadOnly) ||!query.setFocus(&skin_file)) {
if (ok) {
*ok = false;
}
return skin;
}
// 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");
// Obtain author.
query.setQuery("string(/skin/author/name)");
query.evaluateTo(&skin.m_author);
skin.m_author = skin.m_author.remove("\n");
// Obtain email.
query.setQuery("string(/skin/author/email)");
query.evaluateTo(&skin.m_email);
skin.m_email = skin.m_email.remove("\n");
// Obtain version.
query.setQuery("string(/skin/@version)");
query.evaluateTo(&skin.m_version);
skin.m_version = skin.m_version.remove("\n");
// Obtain other information.
skin.m_baseName = skin_name;
// Free resources.
skin_file.close();
skin_file.deleteLater();
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();
}
return skin;
}
QList<Skin> SkinFactory::getInstalledSkins() {
QList<Skin> skins;
return skins;
}

54
src/gui/skinfactory.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef SKINFACTORY_H
#define SKINFACTORY_H
#include <QObject>
#include <QPointer>
struct Skin {
QString m_baseName;
QString m_stylesName;
QString m_author;
QString m_email;
QString m_version;
QString m_rawData;
};
class SkinFactory : public QObject {
Q_OBJECT
private:
explicit SkinFactory(QObject *parent = 0);
bool loadSkinFromData(QString skin_data, const QString &skin_path);
public:
// Singleton getter.
static SkinFactory *getInstance();
// Destructor.
virtual ~SkinFactory();
// Loads skin name from settings and sets it as active.
void loadCurrentSkin();
// Return the name of the currently activated skin.
// NOTE: Skin name is formatted as "<folder>/<skin>.xml".
QString getCurrentSkinName();
Skin getSkinInfo(const QString &skin_name, bool *ok = NULL);
QList<Skin> getInstalledSkins();
// Sets the desired skin as the active one if it exists.
void setCurrentSkinName(const QString &skin_name);
private:
// Holds name of the current skin.
QString m_currentSkin;
// Singleton.
static QPointer<SkinFactory> s_instance;
};
#endif // SKINFACTORY_H

View File

@ -11,6 +11,7 @@
#include "core/settings.h"
#include "core/dynamicshortcuts.h"
#include "gui/iconthemefactory.h"
#include "gui/skinfactory.h"
#include "gui/formmain.h"
#include "gui/formwelcome.h"
#include "gui/systemtrayicon.h"
@ -66,9 +67,11 @@ int main(int argc, char *argv[]) {
QtSingleApplication::addLibraryPath(APP_PLUGIN_PATH);
#endif
// Add an extra path for non-system icon themes and set current icon theme.
// Add an extra path for non-system icon themes and set current icon theme
// and skin.
IconThemeFactory::getInstance()->setupSearchPaths();
IconThemeFactory::getInstance()->loadCurrentIconTheme(false);
SkinFactory::getInstance()->loadCurrentSkin();
// Load localization and setup locale before any widget is constructed.
LoadLocalization();