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

DesktopPaths KCM: Remove the moving directory logic

This simplifies greatly this otherwise mundane KCM. It introduced a lot
of complexity while gettings things wrong anyway: it would miss if a
directory is included in another one except in the "autostart inside
desktop" case, it would also leave you stranded in case of an
uncompleted move.

So now the KCM has a clear purpose: edit the settings. Moving data
around is still up to the user using a proper filemanager.

Long term it would probably be better for the filemanager to edit the
settings automatically when the user move on of those folders around,
then the KCM could be decommissioned.

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

Subscribers: plasma-devel

Tags: #plasma

Differential Revision:
parent f9fb1115
......@@ -40,32 +40,7 @@
#include "ui_globalpaths.h"
#include "desktoppathssettings.h"
// Qt
#include <QCheckBox>
#include <QComboBox>
#include <QLabel>
#include <QLayout>
#include <QFormLayout>
#include <QApplication>
#include <QLoggingCategory>
#include <QStandardPaths>
// KDE
#include <kconfiggroup.h>
#include <kfileitem.h>
#include <kio/copyjob.h>
#include <kio/deletejob.h>
#include <kio/job.h>
#include <kio/jobuidelegate.h>
#include <kjobwidgets.h>
#include <KLocalizedString>
#include <kmessagebox.h>
#include <kurlrequester.h>
#include <KPluginFactory>
#include <KConfig>
#include <KSharedConfig>
K_PLUGIN_FACTORY(KcmDesktopPathsFactory, registerPlugin<DesktopPathConfig>();)
......@@ -88,200 +63,4 @@ DesktopPathConfig::~DesktopPathConfig()
void DesktopPathConfig::save()
bool autostartMoved = false;
QUrl desktopURL = m_pathsSettings->desktopLocation();
QUrl autostartURL = m_pathsSettings->autostartLocation();
QUrl newAutostartURL = m_ui->kcfg_autostartLocation->url();
if ( !m_ui->kcfg_desktopLocation->url().matches( desktopURL, QUrl::StripTrailingSlash ) )
// Test which other paths were inside this one (as it is by default)
// and for each, test where it should go.
// * Inside destination -> let them be moved with the desktop (but adjust name if necessary)
// * Not inside destination -> move first
// !!!
qCDebug(KCM_DESKTOPPATH) << "desktopURL=" << desktopURL;
QString urlDesktop = m_ui->kcfg_desktopLocation->url().toLocalFile();
if ( !urlDesktop.endsWith(QLatin1Char('/')))
if ( desktopURL.isParentOf( autostartURL ) )
qCDebug(KCM_DESKTOPPATH) << "Autostart is on the desktop";
// Either the Autostart field wasn't changed (-> need to update it)
if ( newAutostartURL.matches(autostartURL, QUrl::StripTrailingSlash) )
// Hack. It could be in a subdir inside desktop. Hmmm... Argl.
m_ui->kcfg_autostartLocation->setUrl(QUrl::fromLocalFile(urlDesktop + QStringLiteral("Autostart/")));
qCDebug(KCM_DESKTOPPATH) << "Autostart is moved with the desktop";
autostartMoved = true;
// or it has been changed (->need to move it from here)
QUrl futureAutostartURL = QUrl::fromLocalFile(urlDesktop + QStringLiteral("Autostart/"));
if ( newAutostartURL.matches( futureAutostartURL, QUrl::StripTrailingSlash ) )
autostartMoved = true;
autostartMoved = moveDir( m_pathsSettings->autostartLocation(), m_ui->kcfg_autostartLocation->url(), i18n("Autostart") );
if ( moveDir( m_pathsSettings->desktopLocation(), QUrl::fromLocalFile( urlDesktop ), i18n("Desktop") ) )
//save in XDG path
if ( !newAutostartURL.matches( autostartURL, QUrl::StripTrailingSlash ) )
if (!autostartMoved)
autostartMoved = moveDir( m_pathsSettings->autostartLocation(), m_ui->kcfg_autostartLocation->url(), i18n("Autostart") );
if (autostartMoved)
xdgSavePath(m_ui->kcfg_documentsLocation, m_pathsSettings->documentsLocation(), "documentsLocation", i18n("Documents"));
xdgSavePath(m_ui->kcfg_downloadsLocation, m_pathsSettings->downloadsLocation(), "downloadsLocation", i18n("Downloads"));
xdgSavePath(m_ui->kcfg_videosLocation, m_pathsSettings->videosLocation(), "videosLocation", i18n("Movies"));
xdgSavePath(m_ui->kcfg_picturesLocation, m_pathsSettings->picturesLocation(), "picturesLocation", i18n("Pictures"));
xdgSavePath(m_ui->kcfg_musicLocation, m_pathsSettings->musicLocation(), "musicLocation", i18n("Music"));
bool DesktopPathConfig::xdgSavePath(KUrlRequester* ur, const QUrl& currentUrl, const char* xdgKey, const QString& type)
QUrl newUrl = ur->url();
//url might be empty, use QDir::homePath (the default for xdg) then
if (!newUrl.isValid()) {
newUrl = QUrl(QUrl::fromLocalFile(QDir::homePath()));
if (!newUrl.matches(currentUrl, QUrl::StripTrailingSlash)) {
const QString path = newUrl.toLocalFile();
if (!QDir(path).exists()) {
// Check permissions
if (QDir().mkpath(path)) {
QDir().rmdir(path); // rmdir again, so that we get a fast rename
} else {
KMessageBox::sorry(this, KIO::buildErrorString(KIO::ERR_CANNOT_MKDIR, path));
ur->setUrl(currentUrl); // revert
return false;
if (moveDir(currentUrl, newUrl, type)) {
auto item = m_pathsSettings->findItem(xdgKey);
return true;
return false;
bool DesktopPathConfig::moveDir( const QUrl & src, const QUrl & dest, const QString & type )
if (!src.isLocalFile() || !dest.isLocalFile())
return true;
if (!QFile::exists(src.toLocalFile()))
return true;
// Do not move $HOME! #193057
const QString translatedPath = src.toLocalFile();
if (translatedPath == QDir::homePath() || translatedPath == QDir::homePath() + QLatin1Char('/')) {
return true;
m_ok = true;
QString question;
KGuiItem yesItem;
KGuiItem noItem;
if (QFile::exists(dest.toLocalFile())) {
// TODO: check if the src dir is empty? Nothing to move, then...
question = i18n("The path for '%1' has been changed.\nDo you want the files to be moved from '%2' to '%3'?",
type, src.toLocalFile(),
yesItem = KGuiItem(i18nc("Move files from old to new place", "Move"));
noItem = KGuiItem(i18nc("Use the new directory but do not move files", "Do not Move"));
} else {
question = i18n("The path for '%1' has been changed.\nDo you want to move the directory '%2' to '%3'?",
type, src.toLocalFile(),
yesItem = KGuiItem(i18nc("Move the directory", "Move"));
noItem = KGuiItem(i18nc("Use the new directory but do not move anything", "Do not Move"));
// Ask for confirmation before moving the files
if (KMessageBox::questionYesNo(this, question, i18n("Confirmation Required"),
yesItem, noItem)
== KMessageBox::Yes )
if (QFile::exists(dest.toLocalFile())) {
// Destination already exists -- should always be the case, for most types,
// but maybe not for the complex autostart case (to be checked...)
m_copyToDest = dest;
m_copyFromSrc = src;
KIO::ListJob* job = KIO::listDir( src );
job->setAutoDelete(false); // see <noautodelete> below
KJobWidgets::setWindow(job, this);
connect(job, &KIO::ListJob::entries, this, &DesktopPathConfig::slotEntries);
// slotEntries will move every file/subdir individually into the dest
if (m_ok) {
QDir().rmdir(src.toLocalFile()); // hopefully it's empty by now
delete job;
qCDebug(KCM_DESKTOPPATH) << "Direct move from" << src << "to" << dest;
KIO::Job * job = KIO::move( src, dest );
KJobWidgets::setWindow(job, this);
connect(job, &KIO::Job::result, this, &DesktopPathConfig::slotResult);
qCDebug(KCM_DESKTOPPATH) << "DesktopPathConfig::slotResult returning " << m_ok;
return m_ok;
void DesktopPathConfig::slotEntries(KIO::Job*, const KIO::UDSEntryList& list)
QListIterator<KIO::UDSEntry> it(list);
while (it.hasNext()) {
KFileItem file(, m_copyFromSrc, true, true);
qCDebug(KCM_DESKTOPPATH) << file.url();
if (file.url() == m_copyFromSrc || == QLatin1String("..")) {
KIO::Job * moveJob = KIO::move(file.url(), m_copyToDest);
KJobWidgets::setWindow(moveJob, this);
connect(moveJob, &KIO::Job::result, this, &DesktopPathConfig::slotResult);
moveJob->exec(); // sub-event loop here. <noautodelete>: the main job is not autodeleted because it would be deleted here
void DesktopPathConfig::slotResult( KJob * job )
if (job->error()) {
if ( job->error() != KIO::ERR_DOES_NOT_EXIST )
m_ok = false;
// If the source doesn't exist, no wonder we couldn't move the dir.
// In that case, trust the user and set the new setting in any case.
#include "globalpaths.moc"
......@@ -31,15 +31,6 @@
#include <kcmodule.h>
#include <kio/global.h>
#include <kio/udsentry.h>
#include <QUrl>
class QFormLayout;
class KJob;
class KUrlRequester;
namespace KIO { class Job; }
namespace Ui { class DesktopPathsView; }
......@@ -53,27 +44,12 @@ class DesktopPathConfig : public KCModule
DesktopPathConfig( QWidget *parent, const QVariantList &args );
DesktopPathConfig(QWidget *parent, const QVariantList &args);
~DesktopPathConfig() override;
void save() override;
private Q_SLOTS:
void slotEntries( KIO::Job * job, const KIO::UDSEntryList& list);
bool xdgSavePath(KUrlRequester* ur, const QUrl& currentUrl, const char* xdgKey, const QString& type);
QScopedPointer<Ui::DesktopPathsView> m_ui;
DesktopPathsSettings *m_pathsSettings;
bool moveDir( const QUrl & src, const QUrl & dest, const QString & type );
bool m_ok;
QUrl m_copyToDest; // used when the destination directory already exists
QUrl m_copyFromSrc;
private Q_SLOTS:
void slotResult( KJob * job );
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment