Commit ea8009b3 authored by Kevin Ottens's avatar Kevin Ottens
Browse files

DesktopPaths KCM: Move the settings logic to a KCoreConfigSkeleton class

Summary:
Our KCoreConfigSkeleton subclass is interestingly hand written since
it's too remote from what we usually do (the resulting file needs to be
sourceable and we don't want the usual behavior of removing keys when
they're set to defaults).

The only one which was "more standard" was the autostart path, but
really with the URL conversion on top and for just a single entry, I
shoved it in the hand written class as well.

Doesn't reduce the code much, but at least it separates that logic from
the KCM and it opens the door to properly working defaults button.

Reviewers: #plasma, crossi, bport, meven, mart, davidedmundson

Subscribers: plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D26389
parent 29c01adc
......@@ -3,6 +3,7 @@ add_definitions(-DTRANSLATION_DOMAIN=\"kcm_desktoppaths\")
set(kcm_desktoppaths_PART_SRCS
globalpaths.cpp
desktoppathssettings.cpp
)
add_library(kcm_desktoppaths MODULE ${kcm_desktoppaths_PART_SRCS})
......
/**
* Copyright 2020 Kevin Ottens <kevin.ottens@enioka.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "desktoppathssettings.h"
#include <QDir>
namespace {
//save in XDG user-dirs.dirs config file, this is where KGlobalSettings/QDesktopServices reads from.
KSharedConfig::Ptr userDirsConfig()
{
const QString userDirsFilePath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QStringLiteral("/user-dirs.dirs");
return KSharedConfig::openConfig(userDirsFilePath, KConfig::SimpleConfig);
}
QUrl defaultAutostartLocation()
{
return QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/.config/autostart"));
}
QUrl defaultDesktopLocation()
{
return QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Desktop"));
}
QUrl defaultDocumentsLocation()
{
return QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Documents"));
}
QUrl defaultDownloadsLocation()
{
return QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Downloads"));
}
QUrl defaultMusicLocation()
{
return QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Music"));
}
QUrl defaultPicturesLocation()
{
return QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Pictures"));
}
QUrl defaultVideosLocation()
{
return QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Videos"));
}
}
class PathsSettingsStore : public QObject
{
Q_OBJECT
Q_PROPERTY(QUrl autostartLocation READ autostartLocation WRITE setAutostartLocation)
public:
PathsSettingsStore(QObject *parent = nullptr)
: QObject(parent)
, m_config(KSharedConfig::openConfig())
{
}
QUrl autostartLocation() const
{
return readUrl(QStringLiteral("Autostart"), defaultAutostartLocation());
}
void setAutostartLocation(const QUrl &url)
{
if (url.matches(defaultAutostartLocation(), QUrl::StripTrailingSlash)) {
resetUrl(QStringLiteral("Autostart"));
} else {
writeUrl(QStringLiteral("Autostart"), url);
}
}
void save()
{
if (m_config->isDirty()) {
m_config->sync();
}
}
private:
QUrl readUrl(const QString &key, const QUrl &defaultValue) const
{
KConfigGroup group(m_config, QStringLiteral("Paths"));
const auto path = group.readPathEntry(key, QString());
if (path.isEmpty()) {
return defaultValue;
} else {
return QUrl::fromLocalFile(path);
}
}
void writeUrl(const QString &key, const QUrl &url)
{
KConfigGroup group(m_config, QStringLiteral("Paths"));
group.writePathEntry(key, url.toLocalFile(), KConfig::Normal | KConfig::Global);
}
void resetUrl(const QString &key)
{
KConfigGroup group(m_config, QStringLiteral("Paths"));
group.revertToDefault(key, KConfig::Normal | KConfig::Global);
}
KSharedConfig::Ptr m_config;
};
class XdgPathsSettingsStore : public QObject
{
Q_OBJECT
Q_PROPERTY(QUrl desktopLocation READ desktopLocation WRITE setDesktopLocation)
Q_PROPERTY(QUrl documentsLocation READ documentsLocation WRITE setDocumentsLocation)
Q_PROPERTY(QUrl downloadsLocation READ downloadsLocation WRITE setDownloadsLocation)
Q_PROPERTY(QUrl musicLocation READ musicLocation WRITE setMusicLocation)
Q_PROPERTY(QUrl picturesLocation READ picturesLocation WRITE setPicturesLocation)
Q_PROPERTY(QUrl videosLocation READ videosLocation WRITE setVideosLocation)
public:
XdgPathsSettingsStore(DesktopPathsSettings *parent = nullptr)
: QObject(parent)
, m_settings(parent)
{
}
QUrl desktopLocation() const
{
return readUrl(QStringLiteral("XDG_DESKTOP_DIR"), defaultDesktopLocation());
}
void setDesktopLocation(const QUrl &url)
{
writeUrl(QStringLiteral("XDG_DESKTOP_DIR"), url);
}
QUrl documentsLocation() const
{
return readUrl(QStringLiteral("XDG_DOCUMENTS_DIR"), defaultDocumentsLocation());
}
void setDocumentsLocation(const QUrl &url)
{
writeUrl(QStringLiteral("XDG_DOCUMENTS_DIR"), url);
}
QUrl downloadsLocation() const
{
return readUrl(QStringLiteral("XDG_DOWNLOAD_DIR"), defaultDownloadsLocation());
}
void setDownloadsLocation(const QUrl &url)
{
writeUrl(QStringLiteral("XDG_DOWNLOAD_DIR"), url);
}
QUrl musicLocation() const
{
return readUrl(QStringLiteral("XDG_MUSIC_DIR"), defaultMusicLocation());
}
void setMusicLocation(const QUrl &url)
{
writeUrl(QStringLiteral("XDG_MUSIC_DIR"), url);
}
QUrl picturesLocation() const
{
return readUrl(QStringLiteral("XDG_PICTURES_DIR"), defaultPicturesLocation());
}
void setPicturesLocation(const QUrl &url)
{
writeUrl(QStringLiteral("XDG_PICTURES_DIR"), url);
}
QUrl videosLocation() const
{
return readUrl(QStringLiteral("XDG_VIDEOS_DIR"), defaultVideosLocation());
}
void setVideosLocation(const QUrl &url)
{
writeUrl(QStringLiteral("XDG_VIDEOS_DIR"), url);
}
private:
QUrl readUrl(const QString &key, const QUrl &defaultValue) const
{
KConfigGroup group(m_settings->config(), QString());
const auto path = group.readPathEntry(key, QString());
if (path.isEmpty()) {
return defaultValue;
} else {
return QUrl::fromLocalFile(path.mid(1, path.length() - 2));
}
}
void writeUrl(const QString &key, const QUrl &url)
{
KConfigGroup group(m_settings->config(), QString());
// HACK to benefit from path translation (thus unexpanding $HOME)
group.writePathEntry(key, url.toLocalFile());
const auto path = group.readEntryUntranslated(key, QString());
group.writeEntry(key, QString(QStringLiteral("\"") + path + QStringLiteral("\"")));
}
DesktopPathsSettings *m_settings;
};
DesktopPathsSettings::DesktopPathsSettings(QObject *parent)
: KCoreConfigSkeleton(userDirsConfig(), parent)
, m_pathsStore(new PathsSettingsStore(this))
, m_xdgPathsStore(new XdgPathsSettingsStore(this))
{
addItem(new KPropertySkeletonItem(m_xdgPathsStore, "desktopLocation", defaultDesktopLocation()), "desktopLocation");
addItem(new KPropertySkeletonItem(m_pathsStore, "autostartLocation", defaultAutostartLocation()), "autostartLocation");
addItem(new KPropertySkeletonItem(m_xdgPathsStore, "documentsLocation", defaultDocumentsLocation()), "documentsLocation");
addItem(new KPropertySkeletonItem(m_xdgPathsStore, "downloadsLocation", defaultDownloadsLocation()), "downloadsLocation");
addItem(new KPropertySkeletonItem(m_xdgPathsStore, "musicLocation", defaultMusicLocation()), "musicLocation");
addItem(new KPropertySkeletonItem(m_xdgPathsStore, "picturesLocation", defaultPicturesLocation()), "picturesLocation");
addItem(new KPropertySkeletonItem(m_xdgPathsStore, "videosLocation", defaultVideosLocation()), "videosLocation");
}
QUrl DesktopPathsSettings::autostartLocation() const
{
return findItem("autostartLocation")->property().toUrl();
}
void DesktopPathsSettings::setAutostartLocation(const QUrl &url)
{
findItem("autostartLocation")->setProperty(url);
}
QUrl DesktopPathsSettings::desktopLocation() const
{
return findItem("desktopLocation")->property().toUrl();
}
void DesktopPathsSettings::setDesktopLocation(const QUrl &url)
{
findItem("desktopLocation")->setProperty(url);
}
QUrl DesktopPathsSettings::documentsLocation() const
{
return findItem("documentsLocation")->property().toUrl();
}
void DesktopPathsSettings::setDocumentsLocation(const QUrl &url)
{
findItem("documentsLocation")->setProperty(url);
}
QUrl DesktopPathsSettings::downloadsLocation() const
{
return findItem("downloadsLocation")->property().toUrl();
}
void DesktopPathsSettings::setDownloadsLocation(const QUrl &url)
{
findItem("downloadsLocation")->setProperty(url);
}
QUrl DesktopPathsSettings::musicLocation() const
{
return findItem("musicLocation")->property().toUrl();
}
void DesktopPathsSettings::setMusicLocation(const QUrl &url)
{
findItem("musicLocation")->setProperty(url);
}
QUrl DesktopPathsSettings::picturesLocation() const
{
return findItem("picturesLocation")->property().toUrl();
}
void DesktopPathsSettings::setPicturesLocation(const QUrl &url)
{
findItem("picturesLocation")->setProperty(url);
}
QUrl DesktopPathsSettings::videosLocation() const
{
return findItem("videosLocation")->property().toUrl();
}
void DesktopPathsSettings::setVideosLocation(const QUrl &url)
{
findItem("videosLocation")->setProperty(url);
}
bool DesktopPathsSettings::usrSave()
{
m_pathsStore->save();
return KCoreConfigSkeleton::usrSave();
}
#include "desktoppathssettings.moc"
/**
* Copyright 2020 Kevin Ottens <kevin.ottens@enioka.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DESKTOPPATHSSETTINGS_H
#define DESKTOPPATHSSETTINGS_H
#include <KCoreConfigSkeleton>
class PathsSettingsStore;
class XdgPathsSettingsStore;
class DesktopPathsSettings : public KCoreConfigSkeleton
{
Q_OBJECT
public:
DesktopPathsSettings(QObject *parent = nullptr);
QUrl autostartLocation() const;
void setAutostartLocation(const QUrl &url);
QUrl desktopLocation() const;
void setDesktopLocation(const QUrl &url);
QUrl documentsLocation() const;
void setDocumentsLocation(const QUrl &url);
QUrl downloadsLocation() const;
void setDownloadsLocation(const QUrl &url);
QUrl musicLocation() const;
void setMusicLocation(const QUrl &url);
QUrl picturesLocation() const;
void setPicturesLocation(const QUrl &url);
QUrl videosLocation() const;
void setVideosLocation(const QUrl &url);
private:
bool usrSave() override;
private:
PathsSettingsStore *m_pathsStore;
XdgPathsSettingsStore *m_xdgPathsStore;
};
#endif
......@@ -37,6 +37,7 @@
// Own
#include "globalpaths.h"
#include "desktoppathssettings.h"
// Qt
#include <QCheckBox>
......@@ -69,43 +70,9 @@ K_PLUGIN_FACTORY(KcmDesktopPathsFactory, registerPlugin<DesktopPathConfig>();)
//-----------------------------------------------------------------------------
static QUrl desktopLocation()
{
return QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
}
static QUrl autostartLocation()
{
return QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/autostart"));
}
static QUrl documentsLocation()
{
return QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
}
static QUrl downloadLocation()
{
return QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
}
static QUrl moviesLocation()
{
return QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MoviesLocation));
}
static QUrl picturesLocation()
{
return QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
}
static QUrl musicLocation()
{
return QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MusicLocation));
}
DesktopPathConfig::DesktopPathConfig(QWidget *parent, const QVariantList &)
: KCModule( parent )
, m_pathsSettings(new DesktopPathsSettings(this))
{
QFormLayout *lay = new QFormLayout(this);
lay->setVerticalSpacing(0);
......@@ -163,84 +130,44 @@ KUrlRequester* DesktopPathConfig::addRow(QFormLayout *lay, const QString& label,
void DesktopPathConfig::load()
{
m_pathsSettings->load();
// Desktop Paths
urDesktop->setUrl(desktopLocation());
urAutostart->setUrl(autostartLocation());
urDocument->setUrl(documentsLocation());
urDownload->setUrl(downloadLocation());
urMovie->setUrl(moviesLocation());
urPicture->setUrl(picturesLocation());
urMusic->setUrl(musicLocation());
urAutostart->setUrl(m_pathsSettings->autostartLocation());
urDesktop->setUrl(m_pathsSettings->desktopLocation());
urDocument->setUrl(m_pathsSettings->documentsLocation());
urDownload->setUrl(m_pathsSettings->downloadsLocation());
urMovie->setUrl(m_pathsSettings->videosLocation());
urPicture->setUrl(m_pathsSettings->picturesLocation());
urMusic->setUrl(m_pathsSettings->musicLocation());
emit changed(false);
}
void DesktopPathConfig::defaults()
{
// Desktop Paths - keep defaults in sync with kglobalsettings.cpp
urDesktop->setUrl(QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Desktop")));
urAutostart->setUrl(QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/.config/autostart")));
urDocument->setUrl(QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Documents")));
urDownload->setUrl(QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Downloads")));
urMovie->setUrl(QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Movies")));
urPicture->setUrl(QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Pictures")));
urMusic->setUrl(QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/Music")));
}
m_pathsSettings->setDefaults();
m_pathsSettings->setDefaults();
// the following method is copied from kdelibs/kdecore/config/kconfiggroup.cpp
static bool cleanHomeDirPath( QString &path, const QString &homeDir )
{
#ifdef Q_WS_WIN //safer
if (!QDir::convertSeparators(path).startsWith(QDir::convertSeparators(homeDir)))
return false;
#else
if (!path.startsWith(homeDir))
return false;
#endif
int len = homeDir.length();
// replace by "$HOME" if possible
if (len && (path.length() == len || path[len] == '/')) {
path.replace(0, len, QStringLiteral("$HOME"));
return true;
} else
return false;
}
// TODO this functionality is duplicated in libkonq - keep it only there and export
urAutostart->setUrl(m_pathsSettings->autostartLocation());
static QString translatePath( QString path ) // krazy:exclude=passbyvalue
{
// keep only one single '/' at the beginning - needed for cleanHomeDirPath()
while (path.length() >= 2 && path[0] == '/' && path[1] == '/')
path.remove(0,1);
// we probably should escape any $ ` and \ characters that may occur in the path, but the Qt code that reads back
// the file doesn't unescape them so not much point in doing so
// All of the 3 following functions to return the user's home directory
// can return different paths. We have to test all them.
const QString homeDir0 = QFile::decodeName(qgetenv("HOME"));
const QString homeDir1 = QDir::homePath();
const QString homeDir2 = QDir(homeDir1).canonicalPath();
if (cleanHomeDirPath(path, homeDir0) ||
cleanHomeDirPath(path, homeDir1) ||
cleanHomeDirPath(path, homeDir2) ) {
// qCDebug(KCM_DESKTOPPATH) << "Path was replaced\n";
}
return path;
urDesktop->setUrl(m_pathsSettings->desktopLocation());
urDocument->setUrl(m_pathsSettings->documentsLocation());
urDownload->setUrl(m_pathsSettings->downloadsLocation());
urMovie->setUrl(m_pathsSettings->videosLocation());
urPicture->setUrl(m_pathsSettings->picturesLocation());
urMusic->setUrl(m_pathsSettings->musicLocation());
}
void DesktopPathConfig::save()
{
KSharedConfig::Ptr config = KSharedConfig::openConfig();
KConfigGroup configGroup( config, "Paths" );
bool autostartMoved = false;
QUrl desktopURL(desktopLocation());
QUrl desktopURL = m_pathsSettings->desktopLocation();
QUrl autostartURL(autostartLocation());
QUrl autostartURL = m_pathsSettings->autostartLocation();
QUrl newAutostartURL = urAutostart->url();
if ( !urDesktop->url().matches( desktopURL, QUrl::StripTrailingSlash ) )
......@@ -274,37 +201,34 @@ void DesktopPathConfig::save()
if ( newAutostartURL.matches( futureAutostartURL, QUrl::StripTrailingSlash ) )
autostartMoved = true;
else
autostartMoved = moveDir( autostartLocation(), urAutostart->url(), i18n("Autostart") );
autostartMoved = moveDir( m_pathsSettings->autostartLocation(), urAutostart->url(), i18n("Autostart") );
}
}
if ( moveDir( desktopLocation(), QUrl::fromLocalFile( urlDesktop ), i18n("Desktop") ) )
if ( moveDir( m_pathsSettings->desktopLocation(), QUrl::fromLocalFile( urlDesktop ), i18n("Desktop") ) )
{
//save in XDG path
const QString userDirsFile(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QStringLiteral("/user-dirs.dirs"));
KConfig xdgUserConf( userDirsFile, KConfig::SimpleConfig );
KConfigGroup g( &xdgUserConf, "" );
g.writeEntry( "XDG_DESKTOP_DIR", QString("\"" + translatePath( urlDesktop ) + "\"") );
m_pathsSettings->setDesktopLocation(QUrl::fromLocalFile(urlDesktop));
}
}
if ( !newAutostartURL.matches( autostartURL, QUrl::StripTrailingSlash ) )
{
if (!autostartMoved)
autostartMoved = moveDir( autostartLocation(), urAutostart->url(), i18n("Autostart") );
autostartMoved = moveDir( m_pathsSettings->autostartLocation(), urAutostart->url(), i18n("Autostart") );
if (autostartMoved)
{
configGroup.writePathEntry( "Autostart", urAutostart->url().toLocalFile(), KConfigBase::Normal | KConfigBase::Global );
m_pathsSettings->setAutostartLocation(urAutostart->url());
}
}
config->sync();
xdgSavePath(urDocument, m_pathsSettings->documentsLocation(), "documentsLocation", i18n("Documents"));
xdgSavePath(urDownload, m_pathsSettings->downloadsLocation(), "downloadsLocation", i18n("Downloads"));
xdgSavePath(urMovie, m_pathsSettings->videosLocation(), "videosLocation", i18n("Movies"));
xdgSavePath(urPicture, m_pathsSettings->picturesLocation(), "picturesLocation", i18n("Pictures"));
xdgSavePath(urMusic, m_pathsSettings->musicLocation(), "musicLocation", i18n("Music"));
xdgSavePath(urDocument, documentsLocation(), "XDG_DOCUMENTS_DIR", i18n("Documents"));
xdgSavePath(urDownload, downloadLocation(), "XDG_DOWNLOAD_DIR", i18n("Downloads"));
xdgSavePath(urMovie, moviesLocation(), "XDG_VIDEOS_DIR", i18n("Movies"));
xdgSavePath(urPicture, picturesLocation(), "XDG_PICTURES_DIR", i18n("Pictures"));
xdgSavePath(urMusic, musicLocation(), "XDG_MUSIC_DIR", i18n("Music"));
m_pathsSettings->save();
}
bool DesktopPathConfig::xdgSavePath(KUrlRequester* ur, const QUrl& currentUrl, const char* xdgKey, const QString& type)
......@@ -327,11 +251,9 @@ bool DesktopPathConfig::xdgSavePath(KUrlRequester* ur, const QUrl& currentUrl, c
}
}
if (moveDir(currentUrl, newUrl, type)) {
//save in XDG user-dirs.dirs config file, this is where KGlobalSettings/QDesktopServices reads from.
const QString userDirsFile(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QStringLiteral("/user-dirs.dirs"));