From 8d5062bf559ded8e7047627cbe324f24c054edee Mon Sep 17 00:00:00 2001 From: "Tu, Truong" Date: Wed, 23 May 2012 16:10:38 -0700 Subject: [PATCH] "Initial commit to Gerrit" --- MAction | 1 + MExport | 1 + MGConfItem | 1 + MNotification | 1 + MNotificationGroup | 1 + mdataaccess.h | 85 ++++++++++ mdatastore.h | 71 ++++++++ mdesktopentry.cpp | 417 +++++++++++++++++++++++++++++++++++++++++++++++ mdesktopentry.h | 245 ++++++++++++++++++++++++++++ mdesktopentry_p.h | 87 ++++++++++ metatypedeclarations.h | 30 ++++ mfiledatastore.cpp | 331 +++++++++++++++++++++++++++++++++++++ mfiledatastore.h | 126 +++++++++++++++ mfiledatastore_p.h | 43 +++++ mgconfitem.cpp | 421 ++++++++++++++++++++++++++++++++++++++++++++++++ mgconfitem.h | 145 +++++++++++++++++ mlite-global.h | 12 ++ mlite.pc | 11 ++ mlite.pro | 70 ++++++++ mremoteaction.cpp | 136 ++++++++++++++++ mremoteaction.h | 100 ++++++++++++ mremoteaction_p.h | 49 ++++++ packaging/mlite.changes | 62 +++++++ packaging/mlite.spec | 61 +++++++ 24 files changed, 2507 insertions(+) create mode 100644 MAction create mode 100644 MExport create mode 100644 MGConfItem create mode 100644 MNotification create mode 100644 MNotificationGroup create mode 100644 mdataaccess.h create mode 100644 mdatastore.h create mode 100644 mdesktopentry.cpp create mode 100644 mdesktopentry.h create mode 100644 mdesktopentry_p.h create mode 100644 metatypedeclarations.h create mode 100644 mfiledatastore.cpp create mode 100644 mfiledatastore.h create mode 100644 mfiledatastore_p.h create mode 100644 mgconfitem.cpp create mode 100644 mgconfitem.h create mode 100644 mlite-global.h create mode 100644 mlite.pc create mode 100644 mlite.pro create mode 100644 mremoteaction.cpp create mode 100644 mremoteaction.h create mode 100644 mremoteaction_p.h create mode 100644 packaging/mlite.changes create mode 100644 packaging/mlite.spec diff --git a/MAction b/MAction new file mode 100644 index 0000000..6df1190 --- /dev/null +++ b/MAction @@ -0,0 +1 @@ +#include "maction.h" diff --git a/MExport b/MExport new file mode 100644 index 0000000..d7fba78 --- /dev/null +++ b/MExport @@ -0,0 +1 @@ +#include "mlite-global.h" diff --git a/MGConfItem b/MGConfItem new file mode 100644 index 0000000..6955ba1 --- /dev/null +++ b/MGConfItem @@ -0,0 +1 @@ +#include "mgconfitem.h" diff --git a/MNotification b/MNotification new file mode 100644 index 0000000..b0231e3 --- /dev/null +++ b/MNotification @@ -0,0 +1 @@ +#include "mnotification.h" diff --git a/MNotificationGroup b/MNotificationGroup new file mode 100644 index 0000000..ecf6304 --- /dev/null +++ b/MNotificationGroup @@ -0,0 +1 @@ +#include "mnotificationgroup.h" diff --git a/mdataaccess.h b/mdataaccess.h new file mode 100644 index 0000000..19c5592 --- /dev/null +++ b/mdataaccess.h @@ -0,0 +1,85 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** . +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MDATAACCESS_H +#define MDATAACCESS_H + +#include "mlite-global.h" +#include +#include +#include +#include + +/*! + * \brief Interface for reading and storing key values. + * + * Users can read and write key values using this interface. The user + * also get notified when changes happen in the key values. + */ +class MLITESHARED_EXPORT MDataAccess : public QObject +{ + Q_OBJECT + +public: + /*! + * Destroys the MDataAccess. + */ + virtual ~MDataAccess() {} + + /*! + * Returns a value for a key. + * If the key doesn't exist, an invalid (QVariant::Invalid) value is returned. + * \param key the key. + * \return the requested value. + */ + virtual QVariant value(const QString &key) const = 0; + + /*! + * Sets a new value for a key. If the key isn't found, nothing + * happens and \c false is returned. + * \param key the key to be changed. + * \param value the new value. + * \return \c true if setting was successful, \c false otherwise + */ + virtual bool setValue(const QString &key, const QVariant &value) = 0; + + /*! + * Returns a list of all specified keys. + */ + virtual QStringList allKeys() const = 0; + + /*! + * Returns \c true if there exists a key called \a key and \c false otherwise. + * + * \param key the key to test + * \return a boolean value telling if the key exists or not + * \sa value() and setValue(). + */ + virtual bool contains(const QString &key) const = 0; + +Q_SIGNALS: + /*! + * A signal that is emitted when a key value changes. + * \param key the key that changed. + * \param value the new value. + */ + void valueChanged(const QString &key, const QVariant &value); +}; + +#endif // MDATAACCESS_H diff --git a/mdatastore.h b/mdatastore.h new file mode 100644 index 0000000..7804d84 --- /dev/null +++ b/mdatastore.h @@ -0,0 +1,71 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** . +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MDATASTORE_H +#define MDATASTORE_H + +#include "mdataaccess.h" +#include "mlite-global.h" + +/*! + * Interface for reading and storing data. + * + * The difference between this class and \c MDataAccess is that this interface + * can also be used to create and remove keys. + */ +class MLITESHARED_EXPORT MDataStore : public MDataAccess +{ + Q_OBJECT + +public: + /*! + * Destroys the MDataStore. + */ + virtual ~MDataStore() {} + + /*! + * This will add a new key with the given value or change the value of an + * existing key if the key already exists. + * + * Concrete implementations of MDataStore have to ensure that the data + * is being synchronized with the backend when this is called. + * + * \param key the key to set the value for + * \param value the value for the key + * \return \c true if the key was changed or added, \c false otherwise + */ + virtual bool createValue(const QString &key, const QVariant &value) = 0; + + /*! + * Removes the data of the given key from the datastore. + * Concrete implementations of MDataStore have to ensure that the data is being synchronized + * with the backend when this is called. + */ + virtual void remove(const QString &key) = 0; + + /*! + * Removes all entries in this datastore. + * Concrete implementations of MDataStore have to ensure that the data is being synchronized + * with the backend when this is called. + */ + virtual void clear() = 0; + +}; + +#endif // MDATASTORE_H diff --git a/mdesktopentry.cpp b/mdesktopentry.cpp new file mode 100644 index 0000000..8e84773 --- /dev/null +++ b/mdesktopentry.cpp @@ -0,0 +1,417 @@ +/*************************************************************************** +** This file was derived from the MDesktopEntry implementation in the +** +** +** Original Copyright: +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright on new work: +** Copyright 2011 Intel Corp. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "mdesktopentry.h" +#include "mdesktopentry_p.h" +#include "mgconfitem.h" + +const QString TypeKey("Desktop Entry/Type"); +const QString VersionKey("Desktop Entry/Version"); +const QString NameKey("Desktop Entry/Name"); +const QString GenericNameKey("Desktop Entry/GenericName"); +const QString NoDisplayKey("Desktop Entry/NoDisplay"); +const QString CommentKey("Desktop Entry/Comment"); +const QString IconKey("Desktop Entry/Icon"); +const QString HiddenKey("Desktop Entry/Hidden"); +const QString OnlyShowInKey("Desktop Entry/OnlyShowIn"); +const QString NotShowInKey("Desktop Entry/NotShowIn"); +const QString TryExecKey("Desktop Entry/TryExec"); +const QString ExecKey("Desktop Entry/Exec"); +const QString PathKey("Desktop Entry/Path"); +const QString TerminalKey("Desktop Entry/Terminal"); +const QString MimeTypeKey("Desktop Entry/MimeType"); +const QString CategoriesKey("Desktop Entry/Categories"); +const QString StartupNotifyKey("Desktop Entry/StartupNotify"); +const QString StartupWMClassKey("Desktop Entry/StartupWMClass"); +const QString URLKey("Desktop Entry/URL"); +const QString LogicalIdKey("Desktop Entry/X-MeeGo-Logical-Id"); +const QString TranslationCatalogKey("Desktop Entry/X-MeeGo-Translation-Catalog"); +const QString XMaemoServiceKey("Desktop Entry/X-Maemo-Service"); + +// The syntax of the locale string in the POSIX environment variables +// related to locale is: +// +// [language[_territory][.codeset][@modifier]] +// +// (see: http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html) +// +// language is usually lower case in Linux but according to the above specification +// it may start with uppercase as well (i.e. LANG=Fr_FR is allowed). +// +void parsePosixLang(const QString &localeString, QString *language, QString *country, QString *script) +{ + // we do not need the encoding and therefore use non-capturing + // parentheses for the encoding part here. + // The country part is usually a 2 letter uppercase code + // as in the above example, but there is the exception + // es_419, i.e. Spanish in Latin America where the “country code” + // is “419”. es_419 isn’t really a valid value for LANG, but for consistency + // let’s make this behave the same way as the icu locale names work for es_419, + // we only use LANG as a fallback to specify a locale when gconf isn’t available + // or doesn’t work. + QRegExp regexp("([a-z]{2,3})(_([A-Z]{2,2}|419))?(?:.(?:[a-zA-Z0-9-]+))?(@([A-Z][a-z]+))?"); + + if (regexp.indexIn(localeString) == 0 && + regexp.capturedTexts().size() == 6) { // size of regexp pattern above + + *language = regexp.capturedTexts().at(1); // language + + // POSIX locale modifier, interpreted as script + if (!regexp.capturedTexts().at(5).isEmpty()) + *script = regexp.capturedTexts().at(5); + else + *script = ""; + + if (!regexp.capturedTexts().at(3).isEmpty()) + *country = regexp.capturedTexts().at(3); // country + else + *country = ""; + } + else + { + *language = ""; + *script = ""; + *country = ""; + } +} + +MDesktopEntryPrivate::MDesktopEntryPrivate(const QString &fileName) : + sourceFileName(fileName), + valid(true), + q_ptr(NULL) +{ + QFile file(fileName); + + //Checks if the file exists and opens it in readonly mode + if (file.exists() && file.open(QIODevice::ReadOnly)) + { + readDesktopFile(file, desktopEntriesMap); + } + else + { + qDebug() << "Specified Desktop file does not exist" << fileName; + } +} + +MDesktopEntryPrivate::~MDesktopEntryPrivate() +{ +} + +bool MDesktopEntryPrivate::readDesktopFile(QIODevice &device, QMap &desktopEntriesMap) +{ + // Group header is of form [groupname] + // The group name is captured + // Group names may contain all ASCII characters except for [ and ] and control characters + QRegExp groupHeaderRE("\\[([\\0040-\\0132\\0134\\0136-\\0176]+)\\]"); + // Key-value pair is of form Key=Value or Key[localization]=Value + // The first capture is the key and the second capture is the value + QRegExp keyValueRE("([A-Za-z0-9-]+" // key + "(?:\\[[A-Za-z0-9_@.-]+\\])?" // optional localization + ")" // end key capturing + "\\s*=\\s*" // equals + "(.*)"); // value + QString currentGroup; + QStringList groupNames; + QTextStream stream(&device); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + while (!stream.atEnd()) { + QString line = stream.readLine().trimmed(); + if (!line.isEmpty() && !line.startsWith('#')) { + if (keyValueRE.exactMatch(line) && !currentGroup.isEmpty()) { + // A key-value line was found. Prepend the key with the current group name. + QString desktopKey = currentGroup + '/' + keyValueRE.cap(1); + + // Check whether it's already in the map + if (!desktopEntriesMap.contains(desktopKey)) { + QString value = keyValueRE.cap(2); + + // Check whether this is a known multivalue key + if (desktopKey == CategoriesKey || desktopKey == OnlyShowInKey || + desktopKey == NotShowInKey || desktopKey == MimeTypeKey) { + if (value.endsWith("\\;") || !value.endsWith(';')) { + // Multivalue doesn't end with a semicolon so mark the desktop entry invalid + qDebug() << "Value for multivalue key" << desktopKey << "does not end in a semicolon"; + valid = false; + } + } + + // Add the value to the desktop entries map + desktopEntriesMap.insert(desktopKey, value); + } else { + // Key is already present in the map so issue a warning + qDebug() << "Key" << desktopKey << "already defined. Value" << keyValueRE.cap(2) << "is ignored"; + } + } else if (groupHeaderRE.exactMatch(line)) { + // A group header line was found and if it's not already defined, set it as current group + if (!groupNames.contains(groupHeaderRE.cap(1), Qt::CaseSensitive)) { + if (groupNames.isEmpty() && groupHeaderRE.cap(1) != "Desktop Entry") { + qDebug() << "Desktop entry should start with group name \"Desktop Entry\" "; + valid = false; + } else { + groupNames.push_back(groupHeaderRE.cap(1)); + currentGroup = groupHeaderRE.cap(1); + } + } + // Redefining a group name will cause the desktop entry to become invalid but still parsed by the parser. + else { + currentGroup = groupHeaderRE.cap(1); + qDebug() << "Multiple definitions of group" << groupHeaderRE.cap(1); + valid = false; + } + } else { + qDebug() << "Invalid .desktop entry line:" << line; + } + } + } + return valid; +} + +bool MDesktopEntryPrivate::boolValue(const QString &key) const +{ + return desktopEntriesMap.value(key) == "true"; +} + +QStringList MDesktopEntryPrivate::stringListValue(const QString &key) const +{ + QStringList list; + QString value = desktopEntriesMap.value(key); + + // Split the string using ; but not \; as the separator + const int valueLength = value.length(); + for (int current = 0; current < valueLength;) { + bool previousIsBackslash = false; + const int start = current; + for (int end = current; end < valueLength; ++current, ++end) { + if (value.at(end) == ';' && !previousIsBackslash) { + // Replace \; with ; + list.append(value.mid(start, end - start).replace("\\;", ";")); + current++; + break; + } + + previousIsBackslash = value.at(end) == '\\'; + } + } + + return list; +} + +MDesktopEntry::MDesktopEntry(const QString &fileName) : + d_ptr(new MDesktopEntryPrivate(fileName)) +{ +} + +MDesktopEntry::MDesktopEntry(MDesktopEntryPrivate &dd) : + d_ptr(&dd) +{ +} + +MDesktopEntry::~MDesktopEntry() +{ + delete d_ptr; +} + +QString MDesktopEntry::fileName() const +{ + return d_ptr->sourceFileName; +} + +bool MDesktopEntry::contains(const QString &key) const +{ + return d_ptr->desktopEntriesMap.contains(key); +} + +bool MDesktopEntry::contains(const QString &group, const QString &key) const +{ + return d_ptr->desktopEntriesMap.contains(group + '/' + key); +} + +QString MDesktopEntry::value(const QString &key) const +{ + return d_ptr->desktopEntriesMap.value(key); +} + +QString MDesktopEntry::value(const QString &group, const QString &key) const +{ + return d_ptr->desktopEntriesMap.value(group + '/' + key); +} + +bool MDesktopEntry::isValid() const +{ + // The Type and Name keys always have to be present + if (!contains(TypeKey)) { + return false; + } + + if (!contains(NameKey)) { + return false; + } + + // In case of an application the Exec key needs to be present + if (type() == "Application" && !contains(ExecKey)) { + return false; + } + + // In case of a link the URL key needs to be present + if (type() == "Link" && !contains(URLKey)) { + return false; + } + + // In case the desktop entry is invalid for some explicit reason + // Some cases are: + // 1. Group name defined multiple times + // 2. Desktop entry's first group should be "Desktop Entry" + if (!d_ptr->valid) { + return false; + } + return true; +} + +uint MDesktopEntry::hash() const +{ + return qHash(type() + name()); +} + +QString MDesktopEntry::type() const +{ + return value(TypeKey); +} + +QString MDesktopEntry::version() const +{ + return value(VersionKey); +} + +QString MDesktopEntry::name() const +{ + QString name = value(NameKey); + QString lang, script, country, postfixKey; + + MGConfItem item("/system/ux/locale"); + if (item.value() == QVariant::Invalid) + parsePosixLang(getenv("LANG"), &lang, &country, &script); + else + parsePosixLang(item.value().toString(), &lang, &country, &script); + + if (contains(postfixKey = NameKey + '[' + lang + '_' + country + '@' + script + ']') || + contains(postfixKey = NameKey + '[' + lang + '_' + country + ']') || + contains(postfixKey = NameKey + '[' + lang + ']')) { + // Use the freedesktop.org standard localization style + name = value(postfixKey); + } + + return name; +} + +QString MDesktopEntry::nameUnlocalized() const +{ + return value(NameKey); +} + +QString MDesktopEntry::genericName() const +{ + return value(GenericNameKey); +} + +bool MDesktopEntry::noDisplay() const +{ + return d_ptr->boolValue(NoDisplayKey); +} + +QString MDesktopEntry::comment() const +{ + return value(CommentKey); +} + +QString MDesktopEntry::icon() const +{ + return value(IconKey); +} + +bool MDesktopEntry::hidden() const +{ + return d_ptr->boolValue(HiddenKey); +} + +QStringList MDesktopEntry::onlyShowIn() const +{ + return d_ptr->stringListValue(OnlyShowInKey); +} + +QStringList MDesktopEntry::notShowIn() const +{ + return d_ptr->stringListValue(NotShowInKey); +} + +QString MDesktopEntry::tryExec() const +{ + return value(TryExecKey); +} + +QString MDesktopEntry::exec() const +{ + return value(ExecKey); +} + +QString MDesktopEntry::xMaemoService() const +{ + return value(XMaemoServiceKey); +} + +QString MDesktopEntry::path() const +{ + return value(PathKey); +} + +bool MDesktopEntry::terminal() const +{ + return d_ptr->boolValue(TerminalKey); +} + +QStringList MDesktopEntry::mimeType() const +{ + return d_ptr->stringListValue(MimeTypeKey); +} + +QStringList MDesktopEntry::categories() const +{ + return d_ptr->stringListValue(CategoriesKey); +} + +bool MDesktopEntry::startupNotify() const +{ + return d_ptr->boolValue(StartupNotifyKey); +} + +QString MDesktopEntry::startupWMClass() const +{ + return value(StartupWMClassKey); +} + +QString MDesktopEntry::url() const +{ + return value(URLKey); +} diff --git a/mdesktopentry.h b/mdesktopentry.h new file mode 100644 index 0000000..3fd9684 --- /dev/null +++ b/mdesktopentry.h @@ -0,0 +1,245 @@ +/*************************************************************************** +** This file was derived from the MDesktopEntry implementation in the +** +** +** Original Copyright: +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright on new work: +** Copyright 2011 Intel Corp. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MDESKTOPENTRY_H_ +#define MDESKTOPENTRY_H_ + +#include +#include +#include + +class MDesktopEntryPrivate; + +/*! + * MDesktopEntry provides the means to read freedesktop.org desktop entry + * files. + * + * MDesktopEntry object reads desktop file data from the desktop file given as + * a construction parameter. + * + * The isValid() method determines whether the input desktop file conforms to the + * standard defined by freedesktop.org. + * + * For more information see: + * http://standards.freedesktop.org/desktop-entry-spec/latest/index.html + * + */ +class MLITESHARED_EXPORT MDesktopEntry +{ +public: + /*! + * Reads input desktop file and constructs new MDesktopEntry object + * of it. + * + * \param fileName the name of the file to read the desktop entry from + */ + MDesktopEntry(const QString &fileName); + + /*! + * Destroys the MDesktopEntry. + */ + virtual ~MDesktopEntry(); + + /*! + * Returns the name of the file where the information for this + * desktop entry was read from. + * \return The desktop entry file name. + */ + QString fileName() const; + + /*! + * Indicates whether desktop entry information adheres to the requirements + * set in the freedesktop.org standard. + * Freedesktop.org defines required keys that one has to fill to have a + * valid desktop file. This checks whether those keys are defined. + */ + virtual bool isValid() const; + + /*! + * Calculates a hash value based on the required type and name keys + * of the desktop definition. + */ + virtual uint hash() const; + + /*! + * Returns the value of Type key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString type() const; + + /*! + * Returns the value of Version key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString version() const; + + /*! + * Returns the localized value of Name key or an empty string if it is + * not defined in the input desktop entry file. The localization + * requires either a X-MeeGo-Logical-Id attribute with optional + * X-MeeGo-Translation-Catalog attribute or freedesktop.org standard + * style localized name attribute. Returns the name as unlocalized + * if the logical id cannot be found from the catalog. \see nameUnlocalized + */ + QString name() const; + + /*! + * Returns the unlocalized value of Name key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString nameUnlocalized() const; + + /*! + * Returns the value of GenericName key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString genericName() const; + + /*! + * Indicates whether value of NoDisplay key is true or false. + * Returns false if NoDisplay key is undefined. + */ + bool noDisplay() const; + + /*! + * Returns the value of Comment key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString comment() const; + + /*! + * Returns the value of Icon key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString icon() const; + + /*! + * Indicates whether value of Hidden key is true or false. + * Returns false if Hidden key is undefined. + */ + bool hidden() const; + + /*! + * Returns the value of OnlyShowIn key or an empty string list if it is + * not defined in the input desktop entry file. + */ + QStringList onlyShowIn() const; + + /*! + * Returns the value of NotShowIn key or an empty string list if it is + * not defined in the input desktop entry file. + */ + QStringList notShowIn() const; + + /*! + * Returns the value of TryExec key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString tryExec() const; + + /*! + * Returns the value of Exec key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString exec() const; + + /*! + * Returns the value of Path key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString path() const; + + /*! + * Indicates whether value of Terminal key is true or false. + * Returns false if Terminal key is undefined. + */ + bool terminal() const; + + /*! + * Returns the value of MimeTypes key or an empty string list if it is + * not defined in the input desktop entry file. + */ + QStringList mimeType() const; + + /*! + * Returns the value of Categories key or an empty string list if it is + * not defined in the input desktop entry file. + */ + QStringList categories() const; + + /*! + * Indicates whether value of StartupNotify key is true or false. + * Returns false if StartupNotify key is undefined. + */ + bool startupNotify() const; + + /*! + * Returns the value of StartupWMClass key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString startupWMClass() const; + + /*! + * Returns the value of URL key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString url() const; + + /*! + * Returns the value of X-Osso-Service key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString xMaemoService() const; + + /*! + * Returns the value of the key- key or an empty string if it is + * not defined in the input desktop entry file. + */ + QString value(const QString &key) const; + + /*! + * Returns the value of the group-key stored as "group/key" + * key or an empty string if it is not defined in the input desktop entry file. + */ + QString value(const QString &group, const QString &key) const; + + /*! + * Indicates whether map contains key or not. + * Returns false if key is not present. + */ + bool contains(const QString &key) const; + + /*! + * Indicates whether map contains group/key or not. + * Returns false if key is not present. + */ + bool contains(const QString &group, const QString &key) const; + +protected: + /*! \internal */ + //! Pointer to the private class + MDesktopEntryPrivate *const d_ptr; + MDesktopEntry(MDesktopEntryPrivate &dd); + /*! \internal_end */ + +private: + Q_DISABLE_COPY(MDesktopEntry) + Q_DECLARE_PRIVATE(MDesktopEntry) +}; +#endif /* MDESKTOPENTRY_H_ */ + diff --git a/mdesktopentry_p.h b/mdesktopentry_p.h new file mode 100644 index 0000000..91637a7 --- /dev/null +++ b/mdesktopentry_p.h @@ -0,0 +1,87 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** . +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MDESKTOPENTRY_P_H +#define MDESKTOPENTRY_P_H + +class MDesktopEntry; + +/*! + * MDesktopEntryPrivate is the private class for MDesktopEntry. + */ +class MDesktopEntryPrivate +{ + Q_DECLARE_PUBLIC(MDesktopEntry) + +public: + /*! + * Constructs a new MDesktopEntryPrivate class. + * + * \param fileName the name of the file to read the desktop entry from + */ + MDesktopEntryPrivate(const QString &fileName); + + /*! + * Destroys the MDesktopEntryPrivate. + */ + virtual ~MDesktopEntryPrivate(); + + /*! + * Parses a desktop entry file. + * + * \param device the QIODevice to read the desktop file from + * \param map the QMap to store key-value pairs to + * \return true if desktop file can be parsed + */ + bool readDesktopFile(QIODevice &device, QMap &map); + + //! The name of the file where the information for this desktop entry was read from. + QString sourceFileName; + + //! A map for storing the desktop entries keys and their corresponding values + QMap desktopEntriesMap; + + /*! + * Returns the boolean value of a key. + * + * \param key the key to return the boolean value for + * \return true if the value of specified key is set to "true" and false otherwise. + */ + bool boolValue(const QString &key) const; + + /*! + * Returns the string list value of a key. The list will be populated + * with semicolon separated parts of the key value. + * + * \param key the key to return the string list value for + * \return a string list containing the semicolon separated parts of the key value + */ + QStringList stringListValue(const QString &key) const; + + //! Flag to indicate whether the desktop entry is valid during parsing + bool valid; + +protected: + /* + * \brief this q_ptr starts the inheritance hierarchy + */ + MDesktopEntry *q_ptr; +}; + +#endif diff --git a/metatypedeclarations.h b/metatypedeclarations.h new file mode 100644 index 0000000..472413f --- /dev/null +++ b/metatypedeclarations.h @@ -0,0 +1,30 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** . +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef METATYPEDECLARATIONS_H +#define METATYPEDECLARATIONS_H + +#include "mnotification.h" +#include "mnotificationgroup.h" + +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) + +#endif // METATYPEDECLARATIONS_H diff --git a/mfiledatastore.cpp b/mfiledatastore.cpp new file mode 100644 index 0000000..6c035d9 --- /dev/null +++ b/mfiledatastore.cpp @@ -0,0 +1,331 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** . +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ +#include "mfiledatastore.h" +#include "mfiledatastore_p.h" +#include +#include + +/*! + * Creates a temporary file in the directory of an original file. + * \param originalPath Absolute path that is used as a base for generating + * the temporary file. + * \return Path of the created file, or an empty string if creating the + * file fails. The returned value is a copy, so for uses where it's assigned + * to a variable, it need not be const. For cases where it's passed as a + * parameter, it need not be const because references to non-const will + * not bind to function return values, because they are rvalues. When + * C++0x brings rvalue references, the value should not be const in order + * to allow rvalue references to bind to it and thus enable moving from it. + */ +static QString createTempFile(const QString &originalPath) +{ + QString returnValue; + QTemporaryFile tempFile(originalPath); + if (tempFile.open()) { + tempFile.setAutoRemove(false); + returnValue = tempFile.fileName(); + } + return returnValue; +} + +/*! + * Copies settings from a QSettings object to another QSettings object. + * \param originalSettings Settings to copy. + * \param newSettings Target of the copy. + * \return true if copying succeeds, false if it fails. + */ +static bool copySettings(const QSettings &originalSettings, + QSettings &newSettings) +{ + QStringList keys = originalSettings.allKeys(); + foreach(const QString & key, originalSettings.allKeys()) { + newSettings.setValue(key, originalSettings.value(key)); + if (newSettings.status() != QSettings::NoError) { + return false; + } + } + return true; +} + +/*! + * Renames a file. Ensures that a file with the new name + * doesn't exist. + * \param oldname Name of the file to rename. + * \param newName New name. + */ +static void renameSettingFile(const QString &oldName, + const QString &newName) +{ + QFile::remove(newName); + QFile::rename(oldName, newName); +} + +/*! + * Adds the necessary paths to the file system watcher + * \param filePath Path (including name) of the file to watch. + * \param watcher The file system watcher. + */ +static void addPathsToWatcher(const QString &filePath, + QScopedPointer& watcher) +{ + QFileInfo fileInfo(filePath); + QString directory; + bool fileExists = fileInfo.exists(); + if (fileExists) { + // If the file exists, we can take the canonical path directly + directory = fileInfo.canonicalPath(); + } else { + // If the file doesn't exist, canonicalPath would return an empty string. That's why + // we need to get the parent directory first. + QFileInfo parentPath(fileInfo.absolutePath()); + if (parentPath.exists()) { + directory = parentPath.canonicalFilePath(); + } + } + + if (!directory.isEmpty()) { + // Watch the directory if it's not being watched yet + if (!watcher->directories().contains(directory)) { + watcher->addPath(directory); + } + } + + // Watch the file itself if it's not being watched yet + if (fileExists && !watcher->files().contains(filePath)) { + watcher->addPath(filePath); + } +} + +/*! + * Saves the settings to a file. The settings are first + * saved to a temporary file, and then that file is copied + * over the original settings. This avoids clearing settings + * when there's no disk space. + * \param originalSettings Settings to save. + */ +static bool doSync(QSettings &originalSettings, QScopedPointer& watcher) +{ + bool returnValue = false; + QString tempFileName = createTempFile(originalSettings.fileName()); + if (!tempFileName.isEmpty()) { + QSettings copiedSettings(tempFileName, QSettings::IniFormat); + if (copySettings(originalSettings, copiedSettings)) { + copiedSettings.sync(); + if (copiedSettings.status() == QSettings::NoError) { + renameSettingFile(tempFileName, originalSettings.fileName()); + returnValue = true; + } + } + } + addPathsToWatcher(originalSettings.fileName(), watcher); + return returnValue; +} + +MFileDataStorePrivate::MFileDataStorePrivate(const QString &filePath) : + settings(filePath, QSettings::IniFormat), + watcher(new QFileSystemWatcher()) +{ + settings.sync(); +} + +MFileDataStore::MFileDataStore(const QString &filePath) : + d_ptr(new MFileDataStorePrivate(filePath)) +{ + Q_D(MFileDataStore); + takeSnapshot(); + addPathsToWatcher(filePath, d->watcher); + connect(d->watcher.data(), SIGNAL(fileChanged(QString)), + this, SLOT(fileChanged(QString))); + connect(d->watcher.data(), SIGNAL(directoryChanged(QString)), + this, SLOT(directoryChanged(QString))); +} + +MFileDataStore::~MFileDataStore() +{ + delete d_ptr; +} + +bool MFileDataStore::createValue(const QString &key, const QVariant &value) +{ + Q_D(MFileDataStore); + bool returnValue = false; + // QSettings has some kind of a cache so we'll prevent any temporary writes + // by checking if the data can be actually stored before doing anything + if (isWritable()) { + bool originalValueSet = d->settings.contains(key); + QVariant originalValue = d->settings.value(key); + d->settings.setValue(key, value); + bool syncOk = doSync(d->settings, d->watcher); + if (syncOk) { + returnValue = true; + // Emit valueChanged signal when value is changed or a new key is added + if ((originalValueSet && originalValue != value) + || !originalValueSet) { + d->settingsSnapshot[key] = value; + emit valueChanged(key, value); + } + } else if (originalValueSet) { + // if sync fails, make sure the value in memory is the original + d->settings.setValue(key, originalValue); + } else { + d->settings.remove(key); + } + + } + return returnValue; +} + +bool MFileDataStore::setValue(const QString &key, const QVariant &value) +{ + Q_D(MFileDataStore); + bool returnValue = false; + // QSettings has some kind of a cache so we'll prevent any temporary writes + // by checking if the data can be actually stored before doing anything + if (isWritable() && d->settings.contains(key)) { + QVariant originalValue = d->settings.value(key); + d->settings.setValue(key, value); + bool syncOk = doSync(d->settings, d->watcher); + if (syncOk) { + returnValue = true; + // Emit valueChanged signal when value is changed + if (originalValue != value) { + d->settingsSnapshot[key] = value; + emit valueChanged(key, value); + } + } else { + // if sync fails, make sure the value in memory is the original + d->settings.setValue(key, originalValue); + } + } + return returnValue; +} + +QVariant MFileDataStore::value(const QString &key) const +{ + Q_D(const MFileDataStore); + return d->settings.value(key); +} + +QStringList MFileDataStore::allKeys() const +{ + Q_D(const MFileDataStore); + return d->settings.allKeys(); +} + +void MFileDataStore::remove(const QString &key) +{ + Q_D(MFileDataStore); + // QSettings has some kind of a cache so we'll prevent any temporary writes + // by checking if the data can be actually stored before doing anything + if (isWritable()) { + bool originalValueSet = d->settings.contains(key); + if (!originalValueSet) { + return; + } + QVariant originalValue = d->settings.value(key); + d->settings.remove(key); + bool syncOk = doSync(d->settings, d->watcher); + if (!syncOk) { + if (originalValueSet) { + // if sync fails, make sure the value in memory is the original + d->settings.setValue(key, originalValue); + } + } else { + d->settingsSnapshot.remove(key); + emit valueChanged(key, QVariant()); + } + } +} + +void MFileDataStore::clear() +{ + Q_D(MFileDataStore); + // QSettings has some kind of a cache so we'll prevent any temporary writes + // by checking if the data can be actually stored before doing anything + if (isWritable()) { + d->settings.clear(); + d->settings.sync(); + takeSnapshot(); + } +} + +bool MFileDataStore::contains(const QString &key) const +{ + Q_D(const MFileDataStore); + return d->settings.contains(key); +} + +bool MFileDataStore::isReadable() const +{ + Q_D(const MFileDataStore); + return d->settings.status() == QSettings::NoError; +} + +bool MFileDataStore::isWritable() const +{ + Q_D(const MFileDataStore); + return d->settings.isWritable() && d->settings.status() == QSettings::NoError; +} + +void MFileDataStore::takeSnapshot() +{ + Q_D(MFileDataStore); + d->settingsSnapshot.clear(); + foreach(const QString & key, d->settings.allKeys()) { + d->settingsSnapshot.insert(key, d->settings.value(key)); + } +} + +void MFileDataStore::fileChanged(const QString &fileName) +{ + Q_D(MFileDataStore); + // sync the settings and add the path, for observing + // the file even if it was deleted + d->settings.sync(); + addPathsToWatcher(d->settings.fileName(), d->watcher); + if (d->settings.fileName() == fileName && isWritable()) { + // Check whether the values for existing keys have changed or + // if keys have been deleted + foreach(const QString & key, d->settingsSnapshot.keys()) { + if ((d->settings.contains(key) + && d->settings.value(key) != d->settingsSnapshot.value(key)) + || (!d->settings.contains(key))) { + emit valueChanged(key, d->settings.value(key)); + } + } + // Check whether new keys have been added + foreach(const QString & key, d->settings.allKeys()) { + if (!d->settingsSnapshot.contains(key)) { + emit valueChanged(key, d->settings.value(key)); + } + } + takeSnapshot(); + } +} + +void MFileDataStore::directoryChanged(const QString &fileName) +{ + Q_D(MFileDataStore); + if (fileName == QFileInfo(d->settings.fileName()).canonicalPath()) { + // we can't know which file changed, so we'll sync at this + // point. This is not very optimal, but it at least works. + fileChanged(d->settings.fileName()); + } +} + diff --git a/mfiledatastore.h b/mfiledatastore.h new file mode 100644 index 0000000..f0a0cc0 --- /dev/null +++ b/mfiledatastore.h @@ -0,0 +1,126 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** . +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MFILEDATASTORE_H +#define MFILEDATASTORE_H + +#include "mlite-global.h" +#include "mdatastore.h" + +class MFileDataStorePrivate; + +/*! + * Concrete implementation of \c MDataStore interface. This class stores the data to the + * filesystem. The file name is given as a constructor parameter. + */ +class MLITESHARED_EXPORT MFileDataStore : public MDataStore +{ + Q_OBJECT +public: + /*! + * Constructor. + * \param filePath Absolute path to the file that the settings will be written to and read from. + */ + explicit MFileDataStore(const QString &filePath); + + /*! + * Destructor + */ + virtual ~MFileDataStore(); + + //! \reimp + /*! + * If \c isWritable returns \c false, this method returns \c false. + */ + virtual bool createValue(const QString &key, const QVariant &value); + /*! + * If \c isWritable returns \c false, this method returns \c false. + */ + virtual bool setValue(const QString &key, const QVariant &value); + /*! + * If \c isReadable returns \c false, this method returns an empty QVariant. + */ + virtual QVariant value(const QString &key) const; + /*! + * If \c isReadable returns \c false, this method returns an empty list. + */ + virtual QStringList allKeys() const; + /*! + * If \c isWritable returns \c false, this method does nothing. + */ + virtual void remove(const QString &key); + /*! + * If \c isWritable returns \c false, this method does nothing. + */ + virtual void clear(); + /*! + * If \c isReadable returns \c false, this method returns \c false. + */ + virtual bool contains(const QString &key) const; + //! \reimp_end + + /*! + * Queries if this data store is readable. If this method returns \c true you + * can use the reading methods of this class (\c value, \c allKeys, \c contains). + * If this method returns \c false, the reading methods don't provide the real data. + * \sa value, allKeys, contains + * \return \c true if the data store can be read. + */ + bool isReadable() const; + + /*! + * Queries if this data store is writable. If this method returns \c true you + * can use the writing methods of this class (\c setValue, \c remove, \c clear). + * If this method returns \c false, the writing methods don't modify the data store. + * \sa setValue, remove, clear + * \return \c true if the data store can be written. + */ + bool isWritable() const; + +private: + /*! + * Takes a snapshot of keys and values in the underlying QSettings. + * This allows us to check for external modifications. QSettings seems + * to pick up such modifications automatically, so we compare the settings + * to the snapshot when we notice a file change. + */ + void takeSnapshot(); + +private slots: + /*! + * Notifies that the settings file has been changed in the filesystem externally + * \param fileName The name of the file modified + */ + void fileChanged(const QString &fileName); + + /*! + * Notifies that the directory of the settings file has been changed in the filesystem externally + * \param fileName The name of the file modified + */ + void directoryChanged(const QString &fileName); + +protected: + MFileDataStorePrivate * const d_ptr; + +private: + Q_DECLARE_PRIVATE(MFileDataStore) + Q_DISABLE_COPY(MFileDataStore) +}; + +#endif // MFILEDATASTORE_H diff --git a/mfiledatastore_p.h b/mfiledatastore_p.h new file mode 100644 index 0000000..08ccfb0 --- /dev/null +++ b/mfiledatastore_p.h @@ -0,0 +1,43 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** . +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MFILEDATASTORE_P_H +#define MFILEDATASTORE_P_H + +#include +#include +#include +#include + +class MFileDataStorePrivate +{ +public: + MFileDataStorePrivate(const QString &filePath); + + //! The used data storing backend + QSettings settings; + + //! Snapshot of the settings, used for observing external file changes + QMap settingsSnapshot; + + //! File system watcher wrapped with QScopedPointer to monitor changes in the settings file + QScopedPointer watcher; +}; + +#endif // MFILEDATASTORE_P_H diff --git a/mgconfitem.cpp b/mgconfitem.cpp new file mode 100644 index 0000000..ba7a40e --- /dev/null +++ b/mgconfitem.cpp @@ -0,0 +1,421 @@ +/*************************************************************************** +** This file was derived from the MDesktopEntry implementation in the +** +** +** Original Copyright: +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright on new work: +** Copyright 2011 Intel Corp. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "mgconfitem.h" + +#include +#include + +struct MGConfItemPrivate { + MGConfItemPrivate() : + notify_id(0), + have_gconf(false) + {} + + QString key; + QVariant value; + guint notify_id; + bool have_gconf; + + static void notify_trampoline(GConfClient *, guint, GConfEntry *, gpointer); +}; + +/* We get the default client and never release it, on purpose, to + avoid disconnecting from the GConf daemon when a program happens to + not have any GConfItems for short periods of time. + */ +static GConfClient * +get_gconf_client () +{ + static GConfClient *s_gconf_client = 0; + struct GConfClientDestroyer { + ~GConfClientDestroyer() { g_object_unref(s_gconf_client); s_gconf_client = 0; } + }; + + static GConfClientDestroyer gconfClientDestroyer; + if (s_gconf_client) + return s_gconf_client; + + g_type_init(); + s_gconf_client = gconf_client_get_default(); + + return s_gconf_client; +} + + +#define withClient(c) for (GConfClient *c = get_gconf_client (); c; c = NULL) + +static QByteArray convertKey(const QString &key) +{ + if (key.startsWith('/')) + return key.toUtf8(); + else { + QString replaced = key; + replaced.replace('.', '/'); + qDebug() << "Using dot-separated key names with MGConfItem is deprecated."; + qDebug() << "Please use" << '/' + replaced << "instead of" << key; + return '/' + replaced.toUtf8(); + } +} + +static QString convertKey(const char *key) +{ + return QString::fromUtf8(key); +} + +static QVariant convertValue(GConfValue *src) +{ + if (!src) { + return QVariant(); + } else { + switch (src->type) { + case GCONF_VALUE_INVALID: + return QVariant(QVariant::Invalid); + case GCONF_VALUE_BOOL: + return QVariant((bool)gconf_value_get_bool(src)); + case GCONF_VALUE_INT: + return QVariant(gconf_value_get_int(src)); + case GCONF_VALUE_FLOAT: + return QVariant(gconf_value_get_float(src)); + case GCONF_VALUE_STRING: + return QVariant(QString::fromUtf8(gconf_value_get_string(src))); + case GCONF_VALUE_LIST: + switch (gconf_value_get_list_type(src)) { + case GCONF_VALUE_STRING: { + QStringList result; + for (GSList *elts = gconf_value_get_list(src); elts; elts = elts->next) + result.append(QString::fromUtf8(gconf_value_get_string((GConfValue *)elts->data))); + return QVariant(result); + } + default: { + QList result; + for (GSList *elts = gconf_value_get_list(src); elts; elts = elts->next) + result.append(convertValue((GConfValue *)elts->data)); + return QVariant(result); + } + } + case GCONF_VALUE_SCHEMA: + default: + return QVariant(); + } + } +} + +static GConfValue *convertString(const QString &str) +{ + GConfValue *v = gconf_value_new(GCONF_VALUE_STRING); + gconf_value_set_string(v, str.toUtf8().data()); + return v; +} + +static GConfValueType primitiveType(const QVariant &elt) +{ + switch (elt.type()) { + case QVariant::String: + return GCONF_VALUE_STRING; + case QVariant::Int: + return GCONF_VALUE_INT; + case QVariant::Double: + return GCONF_VALUE_FLOAT; + case QVariant::Bool: + return GCONF_VALUE_BOOL; + default: + return GCONF_VALUE_INVALID; + } +} + +static GConfValueType uniformType(const QList &list) +{ + GConfValueType result = GCONF_VALUE_INVALID; + + foreach(const QVariant & elt, list) { + GConfValueType elt_type = primitiveType(elt); + + if (elt_type == GCONF_VALUE_INVALID) + return GCONF_VALUE_INVALID; + + if (result == GCONF_VALUE_INVALID) + result = elt_type; + else if (result != elt_type) + return GCONF_VALUE_INVALID; + } + + if (result == GCONF_VALUE_INVALID) + return GCONF_VALUE_STRING; // empty list. + else + return result; +} + +static int convertValue(const QVariant &src, GConfValue **valp) +{ + GConfValue *v; + + switch (src.type()) { + case QVariant::Invalid: + v = NULL; + break; + case QVariant::Bool: + v = gconf_value_new(GCONF_VALUE_BOOL); + gconf_value_set_bool(v, src.toBool()); + break; + case QVariant::Int: + v = gconf_value_new(GCONF_VALUE_INT); + gconf_value_set_int(v, src.toInt()); + break; + case QVariant::Double: + v = gconf_value_new(GCONF_VALUE_FLOAT); + gconf_value_set_float(v, src.toDouble()); + break; + case QVariant::String: + v = convertString(src.toString()); + break; + case QVariant::StringList: { + GSList *elts = NULL; + v = gconf_value_new(GCONF_VALUE_LIST); + gconf_value_set_list_type(v, GCONF_VALUE_STRING); + foreach(const QString & str, src.toStringList()) + elts = g_slist_prepend(elts, convertString(str)); + gconf_value_set_list_nocopy(v, g_slist_reverse(elts)); + break; + } + case QVariant::List: { + GConfValueType elt_type = uniformType(src.toList()); + if (elt_type == GCONF_VALUE_INVALID) + v = NULL; + else { + GSList *elts = NULL; + v = gconf_value_new(GCONF_VALUE_LIST); + gconf_value_set_list_type(v, elt_type); + foreach(const QVariant & elt, src.toList()) { + GConfValue *val = NULL; + convertValue(elt, &val); // guaranteed to succeed. + elts = g_slist_prepend(elts, val); + } + gconf_value_set_list_nocopy(v, g_slist_reverse(elts)); + } + break; + } + default: + return 0; + } + + *valp = v; + return 1; +} + +void MGConfItemPrivate::notify_trampoline(GConfClient *, + guint, + GConfEntry *, + gpointer data) +{ + MGConfItem *item = (MGConfItem *)data; + item->update_value(true); +} + +void MGConfItem::update_value(bool emit_signal) +{ + QVariant new_value; + + withClient(client) { + GError *error = NULL; + QByteArray k = convertKey(priv->key); + GConfValue *v = gconf_client_get(client, k.data(), &error); + + if (error) { + qDebug() << error->message; + g_error_free(error); + new_value = priv->value; + } else { + new_value = convertValue(v); + if (v) + gconf_value_free(v); + } + } + + if (new_value != priv->value) { + priv->value = new_value; + if (emit_signal) + emit valueChanged(); + } +} + +QString MGConfItem::key() const +{ + return priv->key; +} + +QVariant MGConfItem::value() const +{ + return priv->value; +} + +QVariant MGConfItem::value(const QVariant &def) const +{ + if (priv->value.isNull()) + return def; + else + return priv->value; +} + +void MGConfItem::set(const QVariant &val) +{ + withClient(client) { + QByteArray k = convertKey(priv->key); + GConfValue *v; + if (convertValue(val, &v)) { + GError *error = NULL; + + if (v) { + gconf_client_set(client, k.data(), v, &error); + gconf_value_free(v); + } else { + gconf_client_unset(client, k.data(), &error); + } + + if (error) { + qDebug() << error->message; + g_error_free(error); + } else if (priv->value != val) { + priv->value = val; + emit valueChanged(); + } + + } else + qDebug() << "Can't store a" << val.typeName(); + } +} + +void MGConfItem::unset() +{ + set(QVariant()); +} + +QList MGConfItem::listDirs() const +{ + QList children; + + withClient(client) { + QByteArray k = convertKey(priv->key); + GError *error = NULL; + GSList *dirs = gconf_client_all_dirs(client, k.data(), &error); + if(error) { + qDebug() << error->message; + g_error_free(error); + return children; + } + + for (GSList *d = dirs; d; d = d->next) { + children.append(convertKey((char *)d->data)); + g_free(d->data); + } + g_slist_free(dirs); + } + + return children; +} + +QList MGConfItem::listEntries() const +{ + QList children; + + withClient(client) { + QByteArray k = convertKey(priv->key); + GError *error = NULL; + GSList *entries = gconf_client_all_entries(client, k.data(), &error); + if(error) { + qDebug() << error->message; + g_error_free(error); + return children; + } + + for (GSList *e = entries; e; e = e->next) { + children.append(convertKey(((GConfEntry *)e->data)->key)); + gconf_entry_free((GConfEntry *)e->data); + } + g_slist_free(entries); + } + + return children; +} + +MGConfItem::MGConfItem(const QString &key, QObject *parent) + : QObject(parent) +{ + priv = new MGConfItemPrivate; + priv->key = key; + withClient(client) { + QByteArray k = convertKey(priv->key); + GError *error = NULL; + + int index = k.lastIndexOf('/'); + if (index > 0) { + QByteArray dir = k.left(index); + gconf_client_add_dir(client, dir.data(), GCONF_CLIENT_PRELOAD_ONELEVEL, &error); + } else { + gconf_client_add_dir(client, k.data(), GCONF_CLIENT_PRELOAD_NONE, &error); + } + + if(error) { + qDebug() << error->message; + g_error_free(error); + return; + } + priv->notify_id = gconf_client_notify_add(client, k.data(), + MGConfItemPrivate::notify_trampoline, this, + NULL, &error); + if(error) { + qDebug() << error->message; + g_error_free(error); + priv->have_gconf = false; + return; + } + update_value(false); + } + priv->have_gconf = true; +} + +MGConfItem::~MGConfItem() +{ + if(priv->have_gconf) { + withClient(client) { + QByteArray k = convertKey(priv->key); + gconf_client_notify_remove(client, priv->notify_id); + GError *error = NULL; + + // Use the same dir as in ctor + int index = k.lastIndexOf('/'); + if (index > 0) { + k = k.left(index); + } + gconf_client_remove_dir(client, k.data(), &error); + + if(error) { + qDebug() << error->message; + g_error_free(error); + //return; // or priv not deleted + } + } + } + delete priv; +} diff --git a/mgconfitem.h b/mgconfitem.h new file mode 100644 index 0000000..6f23ed5 --- /dev/null +++ b/mgconfitem.h @@ -0,0 +1,145 @@ +/*************************************************************************** +** This file was derived from the MDesktopEntry implementation in the +** +** +** Original Copyright: +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright on new work: +** Copyright 2011 Intel Corp. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MGCONFITEM_H +#define MGCONFITEM_H + +#include +#include +#include + +#include + +/*! + + \brief MGConfItem is a simple C++ wrapper for GConf. + + Creating a MGConfItem instance gives you access to a single GConf + key. You can get and set its value, and connect to its + valueChanged() signal to be notified about changes. + + The value of a GConf key is returned to you as a QVariant, and you + pass in a QVariant when setting the value. MGConfItem converts + between a QVariant and GConf values as needed, and according to the + following rules: + + - A QVariant of type QVariant::Invalid denotes an unset GConf key. + + - QVariant::Int, QVariant::Double, QVariant::Bool are converted to + and from the obvious equivalents. + + - QVariant::String is converted to/from a GConf string and always + uses the UTF-8 encoding. No other encoding is supported. + + - QVariant::StringList is converted to a list of UTF-8 strings. + + - QVariant::List (which denotes a QList) is converted + to/from a GConf list. All elements of such a list must have the + same type, and that type must be one of QVariant::Int, + QVariant::Double, QVariant::Bool, or QVariant::String. (A list of + strings is returned as a QVariant::StringList, however, when you + get it back.) + + - Any other QVariant or GConf value is essentially ignored. + + \warning MGConfItem is as thread-safe as GConf. + +*/ + +class MLITESHARED_EXPORT MGConfItem : public QObject +{ + Q_OBJECT + +public: + /*! Initializes a MGConfItem to access the GConf key denoted by + \a key. Key names should follow the normal GConf conventions + like "/myapp/settings/first". + + \param key The name of the key. + \param parent Parent object + */ + explicit MGConfItem(const QString &key, QObject *parent = 0); + + /*! Finalizes a MGConfItem. + */ + virtual ~MGConfItem(); + + /*! Returns the key of this item, as given to the constructor. + */ + QString key() const; + + /*! Returns the current value of this item, as a QVariant. + */ + QVariant value() const; + + /*! Returns the current value of this item, as a QVariant. If + * there is no value for this item, return \a def instead. + */ + QVariant value(const QVariant &def) const; + + /*! Set the value of this item to \a val. If \a val can not be + represented in GConf or GConf refuses to accept it for other + reasons, the current value is not changed and nothing happens. + + When the new value is different from the old value, the + changedValue() signal is emitted on this MGConfItem as part + of calling set(), but other MGConfItem:s for the same key do + only receive a notification once the main loop runs. + + \param val The new value. + */ + void set(const QVariant &val); + + /*! Unset this item. This is equivalent to + + \code + item.set(QVariant(QVariant::Invalid)); + \endcode + */ + void unset(); + + /*! Return a list of the directories below this item. The + returned strings are absolute key names like + "/myapp/settings". + + A directory is a key that has children. The same key might + also have a value, but that is confusing and best avoided. + */ + QList listDirs() const; + + /*! Return a list of entries below this item. The returned + strings are absolute key names like "/myapp/settings/first". + + A entry is a key that has a value. The same key might also + have children, but that is confusing and is best avoided. + */ + QList listEntries() const; + +Q_SIGNALS: + /*! Emitted when the value of this item has changed. + */ + void valueChanged(); + +private: + friend struct MGConfItemPrivate; + struct MGConfItemPrivate *priv; + + void update_value(bool emit_signal); +}; + +#endif // MGCONFITEM_H diff --git a/mlite-global.h b/mlite-global.h new file mode 100644 index 0000000..5c43227 --- /dev/null +++ b/mlite-global.h @@ -0,0 +1,12 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#include + +#if defined(MLITE_LIBRARY) +# define MLITESHARED_EXPORT Q_DECL_EXPORT +#else +# define MLITESHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // MLITE_GLOBAL_H diff --git a/mlite.pc b/mlite.pc new file mode 100644 index 0000000..58fc204 --- /dev/null +++ b/mlite.pc @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include/mlite + +Name: mlite +Description: Selected classes pulled from the MeeGo Touch Framework +Version: 0.0.1 +Cflags: -I${includedir} +Libs: -L${libdir} -lmlite +Requires: QtDBus QtGui diff --git a/mlite.pro b/mlite.pro new file mode 100644 index 0000000..f3417d2 --- /dev/null +++ b/mlite.pro @@ -0,0 +1,70 @@ +QT = gui core dbus +if (wayland) { + TARGET = $$qtLibraryTarget(mlite-wayland) +} else { + TARGET = $$qtLibraryTarget(mlite-xlib) +} +TEMPLATE = lib + +CONFIG += create_pc create_prl no_install_prl link_pkgconfig +PKGCONFIG += gconf-2.0 + +DEFINES += MLITE_LIBRARY + +OBJECTS_DIR = .obj +MOC_DIR = .moc + +SOURCES += \ + mgconfitem.cpp \ + mdesktopentry.cpp \ + mfiledatastore.cpp + + +HEADERS += \ + mdesktopentry_p.h \ + mdesktopentry.h \ + mgconfitem.h \ + mlite-global.h \ + mfiledatastore.h \ + mfiledatastore_p.h \ + mdataaccess.h \ + mdatastore.h \ + MGConfItem + +INSTALL_HEADERS += \ + mgconfitem.h \ + mdesktopentry.h \ + mlite-global.h \ + mfiledatastore.h \ + MGConfItem + +headers.files += $$INSTALL_HEADERS +if (wayland) { + headers.path = $$INSTALL_ROOT/usr/include/mlite-wayland +} else { + headers.path = $$INSTALL_ROOT/usr/include/mlite-xlib +} + +QMAKE_PKGCONFIG_NAME = $$target.name +QMAKE_PKGCONFIG_DESCRIPTION = mlite classes +QMAKE_PKGCONFIG_LIBDIR = $$target.path +if (wayland) { + QMAKE_PKGCONFIG_INCDIR = $$headers.path +} else { + QMAKE_PKGCONFIG_INCDIR = $$headers.path +} +QMAKE_PKGCONFIG_DESTDIR = pkgconfig + +target.path += $$[QT_INSTALL_LIBS] + +INSTALLS += target headers + +TRANSLATIONS += $${SOURCES} $${HEADERS} $${OTHER_FILES} +VERSION = 0.1.2 +PROJECT_NAME = mlite + +dist.commands += rm -fR $${PROJECT_NAME}-$${VERSION} && +dist.commands += git clone . $${PROJECT_NAME}-$${VERSION} && +dist.commands += rm -fR $${PROJECT_NAME}-$${VERSION}/.git && +dist.commands += tar jcpvf $${PROJECT_NAME}-$${VERSION}.tar.bz2 $${PROJECT_NAME}-$${VERSION} +QMAKE_EXTRA_TARGETS += dist diff --git a/mremoteaction.cpp b/mremoteaction.cpp new file mode 100644 index 0000000..e4c4521 --- /dev/null +++ b/mremoteaction.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** . +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#include "mremoteaction.h" +#include "mremoteaction_p.h" + +#include +#include +#include + +MRemoteActionPrivate::MRemoteActionPrivate() : + MActionPrivate() +{ +} + +MRemoteActionPrivate::~MRemoteActionPrivate() +{ +} + +MRemoteAction::MRemoteAction(const QString &serviceName, const QString &objectPath, const QString &interface, const QString &methodName, const QList &arguments, QObject *parent) : MAction(*new MRemoteActionPrivate, parent) +{ + Q_D(MRemoteAction); + + d->serviceName = serviceName; + d->objectPath = objectPath; + d->interface = interface; + d->methodName = methodName; + d->arguments = arguments; + + connect(this, SIGNAL(triggered()), this, SLOT(call())); +} + +MRemoteAction::MRemoteAction(const QString &string, QObject *parent) : MAction(*new MRemoteActionPrivate, parent) +{ + fromString(string); + + connect(this, SIGNAL(triggered()), this, SLOT(call())); +} + +MRemoteAction::MRemoteAction(MRemoteActionPrivate &dd, QObject *parent) : MAction(dd, parent) +{ + connect(this, SIGNAL(triggered()), this, SLOT(call())); +} + +MRemoteAction::~MRemoteAction() +{ +} + +QString MRemoteAction::toString() const +{ + Q_D(const MRemoteAction); + + QString s; + if (!d->serviceName.isEmpty() && !d->objectPath.isEmpty() && !d->interface.isEmpty() && !d->methodName.isEmpty()) { + s.append(d->serviceName).append(' '); + s.append(d->objectPath).append(' '); + s.append(d->interface).append(' '); + s.append(d->methodName); + + foreach(const QVariant & arg, d->arguments) { + // Serialize the QVariant into a QBuffer + QBuffer buffer; + buffer.open(QIODevice::ReadWrite); + QDataStream stream(&buffer); + stream << arg; + buffer.close(); + + // Encode the contents of the QBuffer in Base64 + s.append(' '); + s.append(buffer.buffer().toBase64().data()); + } + } + + return s; +} + +void MRemoteAction::fromString(const QString &string) +{ + Q_D(MRemoteAction); + + QStringList l = string.split(' '); + + if (l.count() > 3) { + d->serviceName = l.at(0); + d->objectPath = l.at(1); + d->interface = l.at(2); + d->methodName = l.at(3); + } + + const int count = l.count(); + for (int i = 4; i < count; ++i) { + QByteArray byteArray = QByteArray::fromBase64(l.at(i).toAscii()); + QBuffer buffer(&byteArray); + buffer.open(QIODevice::ReadOnly); + QDataStream stream(&buffer); + QVariant arg; + stream >> arg; + buffer.close(); + + d->arguments.append(arg); + } +} + +MRemoteAction::MRemoteAction(const MRemoteAction &action) : MAction(*new MRemoteActionPrivate, action.parent()) +{ + fromString(action.toString()); + + connect(this, SIGNAL(triggered()), this, SLOT(call())); +} + +void MRemoteAction::call() +{ + Q_D(MRemoteAction); + + QDBusInterface interface(d->serviceName, d->objectPath, d->interface.toAscii()); + if (interface.isValid()) + { + interface.asyncCallWithArgumentList(d->methodName, d->arguments); + } +} diff --git a/mremoteaction.h b/mremoteaction.h new file mode 100644 index 0000000..8a600f9 --- /dev/null +++ b/mremoteaction.h @@ -0,0 +1,100 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** . +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MREMOTEACTION_H_ +#define MREMOTEACTION_H_ + +#include +#include "mlite-global.h" + +class MRemoteActionPrivate; + +/*! + * \class MRemoteAction + * + * \brief MRemoteAction implements a MAction that executes a D-Bus call when triggered. + * The D-Bus related parameters can be serialized and unserialized into a string. + */ +class MLITESHARED_EXPORT MRemoteAction : public MAction +{ + Q_OBJECT + +public: + /*! + * \brief Constructs a MRemoteAction from a D-Bus service path, object path, interface and arguments. + * + * \param serviceName the service path of the D-Bus object to be called + * \param objectPath the object path of the D-Bus object to be called + * \param interface the interface of the D-Bus object to be called + * \param methodName the name of the D-Bus method to call + * \param arguments the arguments of the D-Bus call. Defaults to no arguments. + * \param parent Parent object + */ + explicit MRemoteAction(const QString &serviceName, const QString &objectPath, const QString &interface, const QString &methodName, const QList &arguments = QList(), QObject *parent = NULL); + + /*! + * \brief Constructs a MRemoteAction from a string representation of a D-Bus remote action acquired with toString(). + * + * \param string the QString to construct the MRemoteAction from + * \param parent Parent object + */ + explicit MRemoteAction(const QString &string = QString(), QObject *parent = NULL); + + /*! + * \brief Constructs a copy of another MRemoteAction. + * + * \param action the MRemoteAction to copy + */ + MRemoteAction(const MRemoteAction &action); + + /*! + * \brief Destroys the MRemoteAction. + */ + virtual ~MRemoteAction(); + + /*! + * Returns a string representation of this remote action. + * + * \return a string representation of this remote action + */ + QString toString() const; + +protected Q_SLOTS: + /*! + * \brief A slot for calling the D-Bus function when the action is triggered + */ + void call(); + +protected: + /*! + * \brief Initializes the MRemoteAction from a string representation + * + * \param string a string representation of a remote action + */ + void fromString(const QString &string); + + //! \internal + MRemoteAction(MRemoteActionPrivate &dd, QObject *parent = NULL); + //! \internal_end + +private: + Q_DECLARE_PRIVATE(MRemoteAction) +}; + +#endif /* MREMOTEACTION_H_ */ diff --git a/mremoteaction_p.h b/mremoteaction_p.h new file mode 100644 index 0000000..ffedded --- /dev/null +++ b/mremoteaction_p.h @@ -0,0 +1,49 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** . +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MREMOTEACTION_P_H +#define MREMOTEACTION_P_H + +#include "maction_p.h" +#include + +class MRemoteAction; +class QDBusInterface; + +class MRemoteActionPrivate : public MActionPrivate +{ + Q_DECLARE_PUBLIC(MRemoteAction) + +public: + MRemoteActionPrivate(); + virtual ~MRemoteActionPrivate(); + + //! The name of the D-Bus service to call + QString serviceName; + //! The path of the D-Bus object to call + QString objectPath; + //! The name of the D-Bus interface to call + QString interface; + //! The name of the D-Bus method to call + QString methodName; + //! The arguments of the D-Bus call + QList arguments; +}; + +#endif diff --git a/packaging/mlite.changes b/packaging/mlite.changes new file mode 100644 index 0000000..e32a1c7 --- /dev/null +++ b/packaging/mlite.changes @@ -0,0 +1,62 @@ +* Wed May 23 23:07:10 UTC 2012 - tu.c.truong@intel.com +- Initial commit to Gerrit + +* Mon Mar 26 2012 Rusty Lynch - 0.1.2 +- Updating to 0.1.2 which will correctly namespace the library + and pc files for either -wayland or -xlib + +* Wed Mar 21 2012 Rusty Lynch - 0.1.1 +- Adding multiple backend support + +* Thu Dec 15 2011 Tracy Graydon - 0.1.1 +- Git Tag: 20111215.1 + 6ed3838: Drop the extraneous makefile for yaml + +* Thu Dec 15 2011 Tracy Graydon - 0.1.1 +- Git Tag: 20111215.0 + 4a13747: Couple of spec changes for mlite + +* Wed Dec 14 2011 Tracy Graydon - 0.1 +- Git Tag: 20111214.5 + b4e7e0f: so much for that + +* Wed Dec 14 2011 Tracy Graydon - 0.0.6 +- Git Tag: 20111214.4 + 1f9ef18: vain attempt to fix the versioning + +* Wed Dec 14 2011 Tracy Graydon - 0.0.9a +- Git Tag: 20111214.3 + 2868ec2: argh yaml ref in spec + +* Wed Dec 14 2011 Tracy Graydon - 0.0.9a +- Git Tag: 20111214.2 + 941ba08: mlite release + +* Wed Dec 14 2011 Tracy Graydon - 0.0.6 +- Git Tag: 20111214.1 + be36b06: mlite + +* Wed Dec 14 2011 Tracy Graydon - 0.0.9 +- Git Tag: 20111214.0 + 51c9019: fix spec + +* Tue Dec 13 2011 Tracy Graydon - 0.0.9 +- Git Tag: 20111213.4 + 7c03f82: mlite mlite mlite + +* Tue Dec 13 2011 Tracy Graydon - 0.0.8 +- Git Tag: 20111213.3 + 392912a: put the yaml back in for now + +* Tue Dec 13 2011 Tracy Graydon - 0.0.8 +- Git Tag: 20111213.2 + 8c46373: remove yaml from Makefile + +* Tue Dec 13 2011 Tracy Graydon - 0.0.8 +- Git Tag: 20111213.1 + 0679be7: remove yaml from Makefile + +* Tue Dec 13 2011 Tracy Graydon - 0.0.6 +- Git Tag: 20111213.0 + ec24b4e: update spec + diff --git a/packaging/mlite.spec b/packaging/mlite.spec new file mode 100644 index 0000000..32789fb --- /dev/null +++ b/packaging/mlite.spec @@ -0,0 +1,61 @@ +%define buildwayland 1 +%if %{buildwayland} +%define backend wayland +%else +%define backend xlib +%endif + +Name: mlite-%{backend} +Summary: Touchscreen classes for UX-IVI support +Version: 0.1.2 +Release: 1 +Group: System/Libraries +License: LGPL v2.1 +URL: http://www.tizen.org +Source0: mlite-%{version}.tar.bz2 + +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig +BuildRequires: pkgconfig(gconf-2.0) +BuildRequires: pkgconfig(QtCore-%{backend}) +BuildRequires: pkgconfig(QtOpenGL-%{backend}) + +%description +Select set of useful classes to support touchscreen for UX-IVI support. + + +%package devel +Summary: mlite development package +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Development files needed for using the mlite library + + +%prep +%setup -q -n mlite-%{version} + +%build + +%qmake CONFIG+=%{backend} + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%qmake_install + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +/usr/lib/*.so.* + +%files devel +%defattr(-,root,root,-) +/usr/include/mlite-%{backend} +/usr/lib/pkgconfig/*.pc +/usr/lib/*.so + -- 2.7.4