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.
254 lines
7.1 KiB
254 lines
7.1 KiB
10 years ago
|
/* 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()));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|