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/qtxdg/xdgdirs.cpp

344 lines
9.0 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 "xdgdirs.h"
#include <stdlib.h>
#include <QDir>
#include <QDebug>
#include <QStandardPaths>
static const QString userDirectoryString[8] =
{
QLatin1String("Desktop"),
QLatin1String("Download"),
QLatin1String("Templates"),
QLatin1String("Publicshare"),
QLatin1String("Documents"),
QLatin1String("Music"),
QLatin1String("Pictures"),
QLatin1String("Videos")
};
// Helper functions prototypes
void fixBashShortcuts(QString &s);
void removeEndingSlash(QString &s);
QString createDirectory(const QString &dir);
void cleanAndAddPostfix(QStringList &dirs, const QString& postfix);
QString userDirFallback(XdgDirs::UserDirectory dir);
/************************************************
Helper func.
************************************************/
void fixBashShortcuts(QString &s)
{
if (s.startsWith(QLatin1Char('~')))
s = QFile::decodeName(qgetenv("HOME")) + (s).mid(1);
}
void removeEndingSlash(QString &s)
{
// We don't check for empty strings. Caller must check it.
// Remove the ending slash, except for root dirs.
if (s.length() > 1 && s.endsWith(QLatin1Char('/')))
s.chop(1);
}
QString createDirectory(const QString &dir)
{
QDir d(dir);
if (!d.exists())
{
if (!d.mkpath(QLatin1String(".")))
{
qWarning() << QString::fromLatin1("Can't create %1 directory.").arg(d.absolutePath());
}
}
QString r = d.absolutePath();
removeEndingSlash(r);
return r;
}
void cleanAndAddPostfix(QStringList &dirs, const QString& postfix)
{
const int N = dirs.count();
for(int i = 0; i < N; ++i)
{
fixBashShortcuts(dirs[i]);
removeEndingSlash(dirs[i]);
dirs[i].append(postfix);
}
}
QString userDirFallback(XdgDirs::UserDirectory dir)
{
QString fallback;
const QString home = QFile::decodeName(qgetenv("HOME"));
if (home.isEmpty())
return QString::fromLatin1("/tmp");
else if (dir == XdgDirs::Desktop)
fallback = QString::fromLatin1("%1/%2").arg(home, QLatin1String("Desktop"));
else
fallback = home;
return fallback;
}
QString XdgDirs::userDirDefault(XdgDirs::UserDirectory dir)
{
// possible values for UserDirectory
Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos));
if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos)
return QString();
return userDirFallback(dir);
}
QString XdgDirs::userDir(XdgDirs::UserDirectory dir)
{
// possible values for UserDirectory
Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos));
if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos)
return QString();
QString folderName = userDirectoryString[dir];
const QString fallback = userDirFallback(dir);
QString configDir(configHome());
QFile configFile(configDir + QLatin1String("/user-dirs.dirs"));
if (!configFile.exists())
return fallback;
if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text))
return fallback;
QString userDirVar(QLatin1String("XDG_") + folderName.toUpper() + QLatin1String("_DIR"));
QTextStream in(&configFile);
QString line;
while (!in.atEnd())
{
line = in.readLine();
if (line.contains(userDirVar))
{
configFile.close();
// get path between quotes
line = line.section(QLatin1Char('"'), 1, 1);
if (line.isEmpty())
return fallback;
line.replace(QLatin1String("$HOME"), QLatin1String("~"));
fixBashShortcuts(line);
return line;
}
}
configFile.close();
return fallback;
}
bool XdgDirs::setUserDir(XdgDirs::UserDirectory dir, const QString& value, bool createDir)
{
// possible values for UserDirectory
Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos));
if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos)
return false;
const QString home = QFile::decodeName(qgetenv("HOME"));
if (!(value.startsWith(QLatin1String("$HOME"))
|| value.startsWith(QLatin1String("~/"))
|| value.startsWith(home)
|| value.startsWith(QDir(home).canonicalPath())))
return false;
QString folderName = userDirectoryString[dir];
QString configDir(configHome());
QFile configFile(configDir + QLatin1String("/user-dirs.dirs"));
// create the file if doesn't exist and opens it
if (!configFile.open(QIODevice::ReadWrite | QIODevice::Text))
return false;
QTextStream stream(&configFile);
QVector<QString> lines;
QString line;
bool foundVar = false;
while (!stream.atEnd())
{
line = stream.readLine();
if (line.indexOf(QLatin1String("XDG_") + folderName.toUpper() + QLatin1String("_DIR")) == 0)
{
foundVar = true;
QString path = line.section(QLatin1Char('"'), 1, 1);
line.replace(path, value);
lines.append(line);
}
else if (line.indexOf(QLatin1String("XDG_")) == 0)
{
lines.append(line);
}
}
stream.reset();
configFile.resize(0);
if (!foundVar)
stream << QString::fromLatin1("XDG_%1_DIR=\"%2\"\n").arg(folderName.toUpper(),(value));
for (QVector<QString>::iterator i = lines.begin(); i != lines.end(); ++i)
stream << *i << QLatin1Char('\n');
configFile.close();
if (createDir) {
QString path = QString(value).replace(QLatin1String("$HOME"), QLatin1String("~"));
fixBashShortcuts(path);
QDir().mkpath(path);
}
return true;
}
QString XdgDirs::dataHome(bool createDir)
{
QString s = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
fixBashShortcuts(s);
if (createDir)
return createDirectory(s);
removeEndingSlash(s);
return s;
}
QString XdgDirs::configHome(bool createDir)
{
QString s = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
fixBashShortcuts(s);
if (createDir)
return createDirectory(s);
removeEndingSlash(s);
return s;
}
QStringList XdgDirs::dataDirs(const QString &postfix)
{
QString d = QFile::decodeName(qgetenv("XDG_DATA_DIRS"));
QStringList dirs = d.split(QLatin1Char(':'), QString::SkipEmptyParts);
if (dirs.isEmpty()) {
dirs.append(QString::fromLatin1("/usr/local/share"));
dirs.append(QString::fromLatin1("/usr/share"));
} else {
QMutableListIterator<QString> it(dirs);
while (it.hasNext()) {
const QString dir = it.next();
if (!dir.startsWith(QLatin1Char('/')))
it.remove();
}
}
dirs.removeDuplicates();
cleanAndAddPostfix(dirs, postfix);
return dirs;
}
QStringList XdgDirs::configDirs(const QString &postfix)
{
QStringList dirs;
const QString env = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS"));
if (env.isEmpty())
dirs.append(QString::fromLatin1("/etc/xdg"));
else
dirs = env.split(QLatin1Char(':'), QString::SkipEmptyParts);
cleanAndAddPostfix(dirs, postfix);
return dirs;
}
QString XdgDirs::cacheHome(bool createDir)
{
QString s = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
fixBashShortcuts(s);
if (createDir)
return createDirectory(s);
removeEndingSlash(s);
return s;
}
QString XdgDirs::runtimeDir()
{
QString result = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
fixBashShortcuts(result);
removeEndingSlash(result);
return result;
}
QString XdgDirs::autostartHome(bool createDir)
{
QString s = QString::fromLatin1("%1/autostart").arg(configHome(createDir));
fixBashShortcuts(s);
if (createDir)
return createDirectory(s);
QDir d(s);
QString r = d.absolutePath();
removeEndingSlash(r);
return r;
}
QStringList XdgDirs::autostartDirs(const QString &postfix)
{
QStringList dirs;
const QStringList s = configDirs();
Q_FOREACH(const QString &dir, s)
dirs << QString::fromLatin1("%1/autostart").arg(dir) + postfix;
return dirs;
}