Adding upstream version 0.3.1.

Signed-off-by: Alf Gaida <agaida@siduction.org>
This commit is contained in:
Alf Gaida 2017-10-22 00:01:49 +02:00
parent 7abe319414
commit 3deb287238
No known key found for this signature in database
GPG Key ID: CD280A0B4D72827C
5 changed files with 157 additions and 68 deletions

View File

@ -1,34 +0,0 @@
<!--- Provide a general summary of the issue in the Title above -->
<!--- You could delete sections and/or questions irrelevant to your report --->
##### Expected Behavior
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
##### Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
##### Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
##### Steps to Reproduce (for bugs)
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1.
2.
3.
4.
##### Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
##### System Information
<!--- Include as many relevant details about the system you experienced the bug in -->
* Distribution & Version:
* Kernel:
* Qt Version:
* cmake Version:
* Package version:

View File

@ -1,7 +1,19 @@
libqtxdg-3.0.0 / 2017-09-22 libqtxdg-3.1.0 / 2017-10-21
=========================== ===========================
* Bump version to 3.1.0
* xdgdesktopfile: Add API for getting actions info
* xdgdesktopfile: Add support for activating actions
* xdgdesktopfile: Add getting actions
* Check $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS for mimeapps.list first.
* Fix reading and writing mimeapps.list file.
* Don't export github templates
3.0.0 / 2017-09-22
==================
* Release 3.0.0: Update changelog
* Backport support for Scale directory key according to Icon Theme spec * Backport support for Scale directory key according to Icon Theme spec
* Bump Major to 3 * Bump Major to 3
* test: Drop Q_FOREACH * test: Drop Q_FOREACH

View File

@ -26,7 +26,7 @@ else()
endif() endif()
set(QTXDG_MAJOR_VERSION 3) set(QTXDG_MAJOR_VERSION 3)
set(QTXDG_MINOR_VERSION 0) set(QTXDG_MINOR_VERSION 1)
set(QTXDG_PATCH_VERSION 0) set(QTXDG_PATCH_VERSION 0)
set(QTXDG_VERSION_STRING ${QTXDG_MAJOR_VERSION}.${QTXDG_MINOR_VERSION}.${QTXDG_PATCH_VERSION}) set(QTXDG_VERSION_STRING ${QTXDG_MAJOR_VERSION}.${QTXDG_MINOR_VERSION}.${QTXDG_PATCH_VERSION})

View File

@ -66,6 +66,7 @@ static const QStringList nonDetachExecs = QStringList()
static const QLatin1String onlyShowInKey("OnlyShowIn"); static const QLatin1String onlyShowInKey("OnlyShowIn");
static const QLatin1String notShowInKey("NotShowIn"); static const QLatin1String notShowInKey("NotShowIn");
static const QLatin1String categoriesKey("Categories"); static const QLatin1String categoriesKey("Categories");
static const QLatin1String actionsKey("Actions");
static const QLatin1String extendPrefixKey("X-"); static const QLatin1String extendPrefixKey("X-");
static const QLatin1String mimeTypeKey("MimeType"); static const QLatin1String mimeTypeKey("MimeType");
static const QLatin1String applicationsStr("applications"); static const QLatin1String applicationsStr("applications");
@ -274,14 +275,37 @@ QString &unEscapeExec(QString& str)
return doUnEscape(str, repl); return doUnEscape(str, repl);
} }
namespace
{
/*!
* Helper class for getting the keys for "Additional applications actions"
* ([Desktop Action %s] sections)
*/
class XdgDesktopAction : public XdgDesktopFile
{
public:
XdgDesktopAction(const XdgDesktopFile & parent, const QString & action)
: XdgDesktopFile(parent)
, m_prefix(QString{QLatin1String("Desktop Action %1")}.arg(action))
{}
protected:
virtual QString prefix() const { return m_prefix; }
private:
const QString m_prefix;
};
}
class XdgDesktopFileData: public QSharedData { class XdgDesktopFileData: public QSharedData {
public: public:
XdgDesktopFileData(); XdgDesktopFileData();
bool read(const QString &prefix); bool read(const QString &prefix);
XdgDesktopFile::Type detectType(XdgDesktopFile *q) const; XdgDesktopFile::Type detectType(XdgDesktopFile *q) const;
bool startApplicationDetached(const XdgDesktopFile *q, const QStringList& urls) const; bool startApplicationDetached(const XdgDesktopFile *q, const QString & action, const QStringList& urls) const;
bool startLinkDetached(const XdgDesktopFile *q) const; bool startLinkDetached(const XdgDesktopFile *q) const;
bool startByDBus(const QStringList& urls) const; bool startByDBus(const QString & action, const QStringList& urls) const;
QStringList getListValue(const XdgDesktopFile * q, const QString & key, bool tryExtendPrefix) const;
QString mFileName; QString mFileName;
bool mIsValid; bool mIsValid;
@ -365,7 +389,7 @@ XdgDesktopFile::Type XdgDesktopFileData::detectType(XdgDesktopFile *q) const
return XdgDesktopFile::UnknownType; return XdgDesktopFile::UnknownType;
} }
bool XdgDesktopFileData::startApplicationDetached(const XdgDesktopFile *q, const QStringList& urls) const bool XdgDesktopFileData::startApplicationDetached(const XdgDesktopFile *q, const QString & action, const QStringList& urls) const
{ {
//DBusActivatable handling //DBusActivatable handling
if (q->value(QLatin1String("DBusActivatable"), false).toBool()) { if (q->value(QLatin1String("DBusActivatable"), false).toBool()) {
@ -390,10 +414,12 @@ bool XdgDesktopFileData::startApplicationDetached(const XdgDesktopFile *q, const
* We consider that this violation is more acceptable than an failure * We consider that this violation is more acceptable than an failure
* in launching an application. * in launching an application.
*/ */
if (startByDBus(urls)) if (startByDBus(action, urls))
return true; return true;
} }
QStringList args = q->expandExecString(urls); QStringList args = action.isEmpty()
? q->expandExecString(urls)
: XdgDesktopAction{*q, action}.expandExecString(urls);
if (args.isEmpty()) if (args.isEmpty())
return false; return false;
@ -481,8 +507,7 @@ bool XdgDesktopFileData::startLinkDetached(const XdgDesktopFile *q) const
return false; return false;
} }
// TODO: Handle ActivateAction bool XdgDesktopFileData::startByDBus(const QString & action, const QStringList& urls) const
bool XdgDesktopFileData::startByDBus(const QStringList& urls) const
{ {
QFileInfo f(mFileName); QFileInfo f(mFileName);
QString path(f.completeBaseName()); QString path(f.completeBaseName());
@ -509,7 +534,13 @@ bool XdgDesktopFileData::startByDBus(const QStringList& urls) const
<< ", but trying to continue..."; << ", but trying to continue...";
} }
QDBusMessage reply; QDBusMessage reply;
if (urls.isEmpty()) if (!action.isEmpty())
{
QList<QVariant> v_urls;
for (const auto & url : urls)
v_urls.append(url);
reply = app.call(QLatin1String("ActivateAction"), action, v_urls, platformData);
} else if (urls.isEmpty())
reply = app.call(QLatin1String("Activate"), platformData); reply = app.call(QLatin1String("Activate"), platformData);
else else
reply = app.call(QLatin1String("Open"), urls, platformData); reply = app.call(QLatin1String("Open"), urls, platformData);
@ -517,6 +548,19 @@ bool XdgDesktopFileData::startByDBus(const QStringList& urls) const
return QDBusMessage::ErrorMessage != reply.type(); return QDBusMessage::ErrorMessage != reply.type();
} }
QStringList XdgDesktopFileData::getListValue(const XdgDesktopFile * q, const QString & key, bool tryExtendPrefix) const
{
QString used_key = key;
if (!q->contains(used_key) && tryExtendPrefix)
{
used_key = extendPrefixKey + key;
if (!q->contains(used_key))
return QStringList();
}
return q->value(key).toString().split(QLatin1Char(';'), QString::SkipEmptyParts);
}
XdgDesktopFile::XdgDesktopFile(): XdgDesktopFile::XdgDesktopFile():
d(new XdgDesktopFileData) d(new XdgDesktopFileData)
@ -750,22 +794,13 @@ QVariant XdgDesktopFile::localizedValue(const QString& key, const QVariant& defa
QStringList XdgDesktopFile::categories() const QStringList XdgDesktopFile::categories() const
{ {
QString key; return d->getListValue(this, categoriesKey, true);
if (contains(categoriesKey))
{
key = categoriesKey;
}
else
{
key = extendPrefixKey + categoriesKey;
if (!contains(key))
return QStringList();
}
QStringList cats = value(key).toString().split(QLatin1Char(';'));
return cats;
} }
QStringList XdgDesktopFile::actions() const
{
return d->getListValue(this, actionsKey, false);
}
void XdgDesktopFile::removeEntry(const QString& key) void XdgDesktopFile::removeEntry(const QString& key)
{ {
@ -806,18 +841,41 @@ QIcon const XdgDesktopFile::icon(const QIcon& fallback) const
} }
QIcon const XdgDesktopFile::actionIcon(const QString & action, const QIcon& fallback) const
{
return d->mType == ApplicationType
? XdgDesktopAction{*this, action}.icon(icon(fallback))
: fallback;
}
QString const XdgDesktopFile::iconName() const QString const XdgDesktopFile::iconName() const
{ {
return value(iconKey).toString(); return value(iconKey).toString();
} }
QString const XdgDesktopFile::actionIconName(const QString & action) const
{
return d->mType == ApplicationType
? XdgDesktopAction{*this, action}.iconName()
: QString{};
}
QStringList XdgDesktopFile::mimeTypes() const QStringList XdgDesktopFile::mimeTypes() const
{ {
return value(mimeTypeKey).toString().split(QLatin1Char(';'), QString::SkipEmptyParts); return value(mimeTypeKey).toString().split(QLatin1Char(';'), QString::SkipEmptyParts);
} }
QString XdgDesktopFile::actionName(const QString & action) const
{
return d->mType == ApplicationType
? XdgDesktopAction{*this, action}.name()
: QString{};
}
XdgDesktopFile::Type XdgDesktopFile::type() const XdgDesktopFile::Type XdgDesktopFile::type() const
{ {
return d->mType; return d->mType;
@ -839,7 +897,7 @@ bool XdgDesktopFile::startDetached(const QStringList& urls) const
switch(d->mType) switch(d->mType)
{ {
case ApplicationType: case ApplicationType:
return d->startApplicationDetached(this, urls); return d->startApplicationDetached(this, QString{}, urls);
break; break;
case LinkType: case LinkType:
@ -851,6 +909,11 @@ bool XdgDesktopFile::startDetached(const QStringList& urls) const
} }
} }
bool XdgDesktopFile::actionActivate(const QString & action, const QStringList& urls) const
{
return d->mType == ApplicationType ? d->startApplicationDetached(this, action, urls) : false;
}
/************************************************ /************************************************
This is an overloaded function. This is an overloaded function.
@ -1396,7 +1459,7 @@ bool readDesktopFile(QIODevice & device, QSettings::SettingsMap & map)
if (value.contains(QLatin1Char(';'))) if (value.contains(QLatin1Char(';')))
{ {
map.insert(key, value.split(QLatin1Char(';'))); map.insert(key, value.split(QLatin1Char(';'), QString::SkipEmptyParts));
} }
else else
{ {
@ -1418,7 +1481,10 @@ bool writeDesktopFile(QIODevice & device, const QSettings::SettingsMap & map)
for (auto it = map.constBegin(); it != map.constEnd(); ++it) for (auto it = map.constBegin(); it != map.constEnd(); ++it)
{ {
if (! it.value().canConvert<QString>()) bool isString = it.value().canConvert<QString>();
bool isStringList = (it.value().type() == QVariant::StringList);
if ((! isString) && (! isStringList))
{ {
return false; return false;
} }
@ -1444,7 +1510,21 @@ bool writeDesktopFile(QIODevice & device, const QSettings::SettingsMap & map)
return false; return false;
} }
stream << remainingKey << QLatin1Char('=') << it.value().toString() << QLatin1Char('\n'); stream << remainingKey << QLatin1Char('=');
if (isString)
{
stream << it.value().toString() << QLatin1Char(';');
}
else /* if (isStringList) */
{
for (const QString &value: it.value().toStringList())
{
stream << value << QLatin1Char(';');
}
}
stream << QLatin1Char('\n');
} }
@ -1612,13 +1692,22 @@ QList<XdgDesktopFile*> XdgDesktopFileCache::getApps(const QString& mimetype)
XdgDesktopFile* XdgDesktopFileCache::getDefaultApp(const QString& mimetype) XdgDesktopFile* XdgDesktopFileCache::getDefaultApp(const QString& mimetype)
{ {
// First, we look in ~/.local/share/applications/mimeapps.list, /usr/local/share/applications/mimeapps.list and // First, we look in following places for a default in specified order:
// /usr/share/applications/mimeapps.list (in that order) for a default. // ~/.config/mimeapps.list
QStringList dataDirs = XdgDirs::dataDirs(); // /etc/xdg/mimeapps.list
dataDirs.prepend(XdgDirs::dataHome(false)); // ~/.local/share/applications/mimeapps.list
for (const QString &dataDir : const_cast<const QStringList&>(dataDirs)) // /usr/local/share/applications/mimeapps.list
// /usr/share/applications/mimeapps.list
QStringList mimeDirsList;
mimeDirsList.append(XdgDirs::configHome(false));
mimeDirsList.append(XdgDirs::configDirs());
mimeDirsList.append(XdgDirs::dataHome(false) + QLatin1String("/applications"));
mimeDirsList.append(XdgDirs::dataDirs(QLatin1String("/applications")));
for (const QString &mimeDir : const_cast<const QStringList&>(mimeDirsList))
{ {
QString defaultsListPath = dataDir + QLatin1String("/applications/mimeapps.list"); QString defaultsListPath = mimeDir + QLatin1String("/mimeapps.list");
if (QFileInfo::exists(defaultsListPath)) if (QFileInfo::exists(defaultsListPath))
{ {
QSettings defaults(defaultsListPath, desktopFileSettingsFormat()); QSettings defaults(defaultsListPath, desktopFileSettingsFormat());

View File

@ -130,6 +130,9 @@ public:
//! Returns the entry Categories. It supports X-Categories extensions. //! Returns the entry Categories. It supports X-Categories extensions.
QStringList categories() const; QStringList categories() const;
//! Returns list of values in entry Actions.
QStringList actions() const;
//! Returns true if there exists a setting called key; returns false otherwise. //! Returns true if there exists a setting called key; returns false otherwise.
bool contains(const QString& key) const; bool contains(const QString& key) const;
@ -142,9 +145,13 @@ public:
//! Returns an icon specified in this file. //! Returns an icon specified in this file.
QIcon const icon(const QIcon& fallback = QIcon()) const; QIcon const icon(const QIcon& fallback = QIcon()) const;
//! Returns an icon for application action \param action.
QIcon const actionIcon(const QString & action, const QIcon& fallback = QIcon()) const;
//! Returns an icon name specified in this file. //! Returns an icon name specified in this file.
QString const iconName() const; QString const iconName() const;
//! Returns an icon name for application action \param action.
QString const actionIconName(const QString & action) const;
//! Returns an list of mimetypes specified in this file. //! Returns an list of mimetypes specified in this file.
/*! @return Returns a list of the "MimeType=" entries. /*! @return Returns a list of the "MimeType=" entries.
@ -155,6 +162,8 @@ public:
//! This function is provided for convenience. It's equivalent to calling localizedValue("Name").toString(). //! This function is provided for convenience. It's equivalent to calling localizedValue("Name").toString().
QString name() const { return localizedValue(QLatin1String("Name")).toString(); } QString name() const { return localizedValue(QLatin1String("Name")).toString(); }
//! Returns an (localized) name for application action \param action.
QString actionName(const QString & action) const;
//! This function is provided for convenience. It's equivalent to calling localizedValue("Comment").toString(). //! This function is provided for convenience. It's equivalent to calling localizedValue("Comment").toString().
QString comment() const { return localizedValue(QLatin1String("Comment")).toString(); } QString comment() const { return localizedValue(QLatin1String("Comment")).toString(); }
@ -175,6 +184,19 @@ public:
//! This function is provided for convenience. It's equivalent to calling startDetached(QStringList(url)). //! This function is provided for convenience. It's equivalent to calling startDetached(QStringList(url)).
bool startDetached(const QString& url = QString()) const; bool startDetached(const QString& url = QString()) const;
/*! For file with Application type. Activates action defined by the \param action. Action is activated
* either with the [Desktop Action %s]/Exec or by the D-Bus if the [Desktop Entry]/DBusActivatable is set.
* \note Starting is done the same way as \sa startDetached()
*
* \return true on success; otherwise returns false.
* \param urls - A list of files or URLS. Each file is passed as a separate argument to the executable program.
*
* For file with Link type, do nothing.
*
* For file with Directory type, do nothing.
*/
bool actionActivate(const QString & action, const QStringList & urls) const;
/*! A Exec value consists of an executable program optionally followed by one or more arguments. /*! A Exec value consists of an executable program optionally followed by one or more arguments.
This function expands this arguments and returns command line string parts. This function expands this arguments and returns command line string parts.
Note this method make sense only for Application type. Note this method make sense only for Application type.