You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libqtxdg-packaging/xdgmenuapplinkprocessor.cpp

276 lines
7.8 KiB

/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenu.h"
#include "xdgmenuapplinkprocessor.h"
#include "xmlhelper.h"
#include "xdgdesktopfile.h"
#include <QDir>
/************************************************
************************************************/
XdgMenuApplinkProcessor::XdgMenuApplinkProcessor(QDomElement& element, XdgMenu* menu, XdgMenuApplinkProcessor *parent) :
QObject(parent)
{
mElement = element;
mParent = parent;
mMenu = menu;
mOnlyUnallocated = element.attribute("onlyUnallocated") == "1";
MutableDomElementIterator i(element, "Menu");
while(i.hasNext())
{
QDomElement e = i.next();
mChilds.append(new XdgMenuApplinkProcessor(e, mMenu, this));
}
}
/************************************************
************************************************/
XdgMenuApplinkProcessor::~XdgMenuApplinkProcessor()
{
}
/************************************************
************************************************/
void XdgMenuApplinkProcessor::run()
{
step1();
step2();
}
/************************************************
************************************************/
void XdgMenuApplinkProcessor::step1()
{
fillAppFileInfoList();
createRules();
// Check Include rules & mark as allocated ............
XdgMenuAppFileInfoHashIterator i(mAppFileInfoHash);
while(i.hasNext())
{
i.next();
XdgDesktopFile* file = i.value()->desktopFile();
if (mRules.checkInclude(i.key(), *file))
{
if (!mOnlyUnallocated)
i.value()->setAllocated(true);
if (!mRules.checkExclude(i.key(), *file))
{
mSelected.append(i.value());
}
}
}
// Process childs menus ...............................
foreach (XdgMenuApplinkProcessor* child, mChilds)
child->step1();
}
/************************************************
************************************************/
void XdgMenuApplinkProcessor::step2()
{
// Create AppLinks elements ...........................
QDomDocument doc = mElement.ownerDocument();
foreach (XdgMenuAppFileInfo* fileInfo, mSelected)
{
if (mOnlyUnallocated && fileInfo->allocated())
continue;
XdgDesktopFile* file = fileInfo->desktopFile();
bool show = false;
QStringList envs = mMenu->environments();
const int N = envs.size();
for (int i = 0; i < N; ++i)
{
if (file->isShown(envs.at(i)))
{
show = true;
break;
}
}
if (!show)
continue;
QDomElement appLink = doc.createElement("AppLink");
appLink.setAttribute("id", fileInfo->id());
appLink.setAttribute("title", file->localizedValue("Name").toString());
appLink.setAttribute("comment", file->localizedValue("Comment").toString());
appLink.setAttribute("genericName", file->localizedValue("GenericName").toString());
appLink.setAttribute("exec", file->value("Exec").toString());
appLink.setAttribute("terminal", file->value("Terminal").toBool());
appLink.setAttribute("startupNotify", file->value("StartupNotify").toBool());
appLink.setAttribute("path", file->value("Path").toString());
appLink.setAttribute("icon", file->value("Icon").toString());
appLink.setAttribute("desktopFile", file->fileName());
mElement.appendChild(appLink);
}
// Process childs menus ...............................
foreach (XdgMenuApplinkProcessor* child, mChilds)
child->step2();
}
/************************************************
For each <Menu> element, build a pool of desktop entries by collecting entries found
in each <AppDir> for the menu element. If two entries have the same desktop-file id,
the entry for the earlier (closer to the top of the file) <AppDir> must be discarded.
Next, add to the pool the entries for any <AppDir>s specified by ancestor <Menu>
elements. If a parent menu has a duplicate entry (same desktop-file id), the entry
for the child menu has priority.
************************************************/
void XdgMenuApplinkProcessor::fillAppFileInfoList()
{
// Build a pool by collecting entries found in <AppDir>
{
MutableDomElementIterator i(mElement, "AppDir");
i.toBack();
while(i.hasPrevious())
{
QDomElement e = i.previous();
findDesktopFiles(e.text(), QString());
mElement.removeChild(e);
}
}
// Add the entries for ancestor <Menu> ................
if (mParent)
{
XdgMenuAppFileInfoHashIterator i(mParent->mAppFileInfoHash);
while(i.hasNext())
{
i.next();
//if (!mAppFileInfoHash.contains(i.key()))
mAppFileInfoHash.insert(i.key(), i.value());
}
}
}
/************************************************
************************************************/
void XdgMenuApplinkProcessor::findDesktopFiles(const QString& dirName, const QString& prefix)
{
QDir dir(dirName);
mMenu->addWatchPath(dir.absolutePath());
QFileInfoList files = dir.entryInfoList(QStringList("*.desktop"), QDir::Files);
foreach (QFileInfo file, files)
{
XdgDesktopFile* f = XdgDesktopFileCache::getFile(file.canonicalFilePath());
if (f)
mAppFileInfoHash.insert(prefix + file.fileName(), new XdgMenuAppFileInfo(f, prefix + file.fileName(), this));
}
// Working recursively ............
QFileInfoList dirs = dir.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot);
foreach (QFileInfo d, dirs)
{
QString dn = d.canonicalFilePath();
if (dn != dirName)
{
findDesktopFiles(dn, QString("%1%2-").arg(prefix, d.fileName()));
}
}
}
/************************************************
Create rules
************************************************/
void XdgMenuApplinkProcessor::createRules()
{
MutableDomElementIterator i(mElement, QString());
while(i.hasNext())
{
QDomElement e = i.next();
if (e.tagName()=="Include")
{
mRules.addInclude(e);
mElement.removeChild(e);
}
else if (e.tagName()=="Exclude")
{
mRules.addExclude(e);
mElement.removeChild(e);
}
}
}
/************************************************
Check if the program is actually installed.
************************************************/
bool XdgMenuApplinkProcessor::checkTryExec(const QString& progName)
{
if (progName.startsWith(QDir::separator()))
return QFileInfo(progName).isExecutable();
QStringList dirs = QString(getenv("PATH")).split(":");
foreach (QString dir, dirs)
{
if (QFileInfo(QDir(dir), progName).isExecutable())
return true;
}
return false;
}