kde-workspace/kcontrol/desktoppaths/kcmdesktoppaths.cpp
Ivailo Monev e16eb8e85d generic: adjust to KFileItem changes
the camera slave is on the chopping block, libtmp is supposed to be able
to handle PTP too

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2024-05-31 16:55:01 +03:00

373 lines
14 KiB
C++

/**
* Copyright (c) Martin R. Jones 1996
* Copyright (c) Bernd Wuebben 1998
* Copyright (c) Christian Tibirna 1998
* Copyright 1998-2007 David Faure <faure@kde.org>
* Copyright (c) 2010 Matthias Fuchs <mat69@gmx.net>
*
* 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.
*/
//
//
// "Desktop Options" Tab for KDesktop configuration
//
// (c) Martin R. Jones 1996
// (c) Bernd Wuebben 1998
//
// Layouts
// (c) Christian Tibirna 1998
// Port to KControl, split from Misc Tab, Port to KControl2
// (c) David Faure 1998
// Desktop menus, paths
// (c) David Faure 2000
// Own
#include "kcmdesktoppaths.h"
// Katie
#include <QtGui/QCheckBox>
#include <QtGui/QComboBox>
#include <QtGui/QLabel>
#include <QtGui/QLayout>
#include <QtGui/QFormLayout>
#include <QtGui/QDesktopWidget>
#include <QtGui/QApplication>
#include <QtDBus/QtDBus>
// KDE
#include <kconfiggroup.h>
#include <kdebug.h>
#include <kfileitem.h>
#include <kglobalsettings.h>
#include <kio/copyjob.h>
#include <kio/deletejob.h>
#include <kio/job.h>
#include <kio/jobuidelegate.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kmimetype.h>
#include <kstandarddirs.h>
#include <kurlrequester.h>
#include <kpluginfactory.h>
#include <kpluginloader.h>
#include "kcmdesktoppaths.h"
//-----------------------------------------------------------------------------
K_PLUGIN_FACTORY_DECLARATION(KcmDesktopPaths)
K_PLUGIN_FACTORY_DEFINITION(KcmDesktopPaths, registerPlugin<DesktopPathConfig>("dpath");)
K_EXPORT_PLUGIN(KcmDesktopPaths("kcm_desktoppaths"))
DesktopPathConfig::DesktopPathConfig(QWidget *parent, const QVariantList &)
: KCModule( KcmDesktopPaths::componentData(), parent )
{
QFormLayout *lay = new QFormLayout(this);
lay->setMargin(0);
setQuickHelp( i18n("<h1>Paths</h1>\n"
"This module allows you to choose where in the filesystem the "
"files on your desktop should be stored.\n"
"Use the \"Whats This?\" (Shift+F1) to get help on specific options."));
urDesktop = addRow(lay, i18n("Desktop path:"),
i18n("This folder contains all the files"
" which you see on your desktop. You can change the location of this"
" folder if you want to, and the contents will move automatically"
" to the new location as well."));
urDocument = addRow(lay, i18n("Documents path:"),
i18n("This folder will be used by default to "
"load or save documents from or to."));
urDownload = addRow(lay, i18n("Downloads path:"),
i18n("This folder will be used by default to "
"save your downloaded items."));
urMovie = addRow(lay, i18n("Movies path:"),
i18n("This folder will be used by default to "
"load or save movies from or to."));
urPicture = addRow(lay, i18n("Pictures path:"),
i18n("This folder will be used by default to "
"load or save pictures from or to."));
urMusic = addRow(lay, i18n("Music path:"),
i18n("This folder will be used by default to "
"load or save music from or to."));
}
KUrlRequester* DesktopPathConfig::addRow(QFormLayout *lay, const QString& label, const QString& whatsThis)
{
KUrlRequester* ur = new KUrlRequester(this);
ur->setMode(KFile::Directory | KFile::LocalOnly);
lay->addRow(label, ur);
connect(ur, SIGNAL(textChanged(QString)), this, SLOT(changed()));
lay->labelForField(ur)->setWhatsThis(whatsThis);
ur->setWhatsThis(whatsThis);
return ur;
}
void DesktopPathConfig::load()
{
// Desktop Paths
urDesktop->setUrl( KGlobalSettings::desktopPath() );
urDocument->setUrl( KGlobalSettings::documentPath() );
urDownload->setUrl( KGlobalSettings::downloadPath() );
urMovie->setUrl( KGlobalSettings::videosPath() );
urPicture->setUrl( KGlobalSettings::picturesPath() );
urMusic->setUrl( KGlobalSettings::musicPath() );
emit changed(false);
}
void DesktopPathConfig::defaults()
{
// Desktop Paths - keep defaults in sync with kglobalsettings.cpp
urDesktop->setUrl( QString(QDir::homePath() + "/Desktop") );
urDocument->setUrl( QString(QDir::homePath() + "/Documents") );
urDownload->setUrl( QString(QDir::homePath() + "/Downloads") );
urMovie->setUrl( QString(QDir::homePath() + "/Movies") );
urPicture->setUrl( QString(QDir::homePath() + "/Pictures") );
urMusic->setUrl( QString(QDir::homePath() + "/Music") );
}
// the following method is copied from kdelibs/kdecore/config/kconfiggroup.cpp
static bool cleanHomeDirPath( QString &path, const QString &homeDir )
{
if (!path.startsWith(homeDir))
return false;
int len = homeDir.length();
// replace by "$HOME" if possible
if (len && (path.length() == len || path[len] == '/')) {
path.replace(0, len, QString::fromLatin1("$HOME"));
return true;
} else
return false;
}
// TODO this functionality is duplicated in libkonq - keep it only there and export
static QString translatePath( QString path ) // krazy:exclude=passbyvalue
{
// keep only one single '/' at the beginning - needed for cleanHomeDirPath()
while (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) ) {
// kDebug() << "Path was replaced\n";
}
return path;
}
void DesktopPathConfig::save()
{
KSharedConfig::Ptr config = KGlobal::config();
KConfigGroup configGroup( config, "Paths" );
bool pathChanged = false;
KUrl desktopURL( KGlobalSettings::desktopPath() );
if ( !urDesktop->url().equals( desktopURL, KUrl::RemoveTrailingSlash ) )
{
// 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
// !!!
kDebug() << "desktopURL=" << desktopURL;
QString urlDesktop = urDesktop->url().toLocalFile();
if ( !urlDesktop.endsWith('/'))
urlDesktop+='/';
if ( moveDir( KUrl( KGlobalSettings::desktopPath() ), KUrl( urlDesktop ), i18n("Desktop") ) )
{
//save in XDG path
const QString userDirsFile(KGlobal::dirs()->localxdgconfdir() + QLatin1String("user-dirs.dirs"));
KConfig xdgUserConf( userDirsFile, KConfig::SimpleConfig );
KConfigGroup g( &xdgUserConf, "" );
g.writeEntry( "XDG_DESKTOP_DIR", QString("\"" + translatePath( urlDesktop ) + "\"") );
pathChanged = true;
}
}
config->sync();
if (xdgSavePath(urDocument, KGlobalSettings::documentPath(), "XDG_DOCUMENTS_DIR", i18n("Documents")))
pathChanged = true;
if (xdgSavePath(urDownload, KGlobalSettings::downloadPath(), "XDG_DOWNLOAD_DIR", i18n("Downloads")))
pathChanged = true;
if (xdgSavePath(urMovie, KGlobalSettings::videosPath(), "XDG_VIDEOS_DIR", i18n("Movies")))
pathChanged = true;
if (xdgSavePath(urPicture, KGlobalSettings::picturesPath(), "XDG_PICTURES_DIR", i18n("Pictures")))
pathChanged = true;
if (xdgSavePath(urMusic, KGlobalSettings::musicPath(), "XDG_MUSIC_DIR", i18n("Music")))
pathChanged = true;
if (pathChanged) {
kDebug() << "sending message SettingsChanged";
KGlobalSettings::self()->emitChange(KGlobalSettings::PathsChanged);
}
}
bool DesktopPathConfig::xdgSavePath(KUrlRequester* ur, const KUrl& currentUrl, const char* xdgKey, const QString& type)
{
KUrl newUrl = ur->url();
//url might be empty, use QDir::homePath (the default for xdg) then
if (!newUrl.isValid()) {
newUrl = KUrl(QDir::homePath());
}
if (!newUrl.equals(currentUrl, KUrl::RemoveTrailingSlash)) {
const QString path = newUrl.toLocalFile();
if (!QDir(path).exists()) {
// Check permissions
if (KStandardDirs::makeDir(path)) {
QDir().rmdir(path); // rmdir again, so that we get a fast rename
} else {
KMessageBox::sorry(this, KIO::buildErrorString(KIO::ERR_COULD_NOT_MKDIR, path));
ur->setUrl(currentUrl); // revert
return false;
}
}
if (moveDir(currentUrl, newUrl, type)) {
//save in XDG user-dirs.dirs config file, this is where KGlobalSettings/QStandardPaths reads from.
const QString userDirsFile(KGlobal::dirs()->localxdgconfdir() + QLatin1String("user-dirs.dirs"));
KConfig xdgUserConf(userDirsFile, KConfig::SimpleConfig);
KConfigGroup g(&xdgUserConf, "");
g.writeEntry(xdgKey, QString("\"" + translatePath(path) + "\""));
return true;
}
}
return false;
}
bool DesktopPathConfig::moveDir( const KUrl & src, const KUrl & dest, const QString & type )
{
if (!src.isLocalFile() || !dest.isLocalFile())
return true;
if (!QDir(src.toLocalFile()).exists())
return true;
// Do not move $HOME! #193057
const QString translatedPath = translatePath(src.toLocalFile());
if (translatedPath == "$HOME" || translatedPath == "$HOME/") {
return true;
}
m_ok = true;
QString question;
KGuiItem yesItem;
KGuiItem noItem;
const bool destExists = QDir(dest.toLocalFile()).exists();
if (destExists) {
// 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(),
dest.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(),
dest.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 (destExists) {
// 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
job->ui()->setWindow(this);
job->ui()->setAutoErrorHandlingEnabled(true);
connect(job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)),
this, SLOT(slotEntries(KIO::Job*,KIO::UDSEntryList)));
// slotEntries will move every file/subdir individually into the dest
job->exec();
if (m_ok) {
QDir().rmdir(src.toLocalFile()); // hopefully it's empty by now
}
delete job;
}
else
{
kDebug() << "Direct move from" << src << "to" << dest;
KIO::Job * job = KIO::move( src, dest );
job->ui()->setWindow(this);
connect(job, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*)));
job->exec();
}
}
kDebug() << "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(it.next());
kDebug() << file.url();
if (file.url() == m_copyFromSrc || file.url().fileName() == "..") {
continue;
}
KIO::Job * moveJob = KIO::move(file.url(), m_copyToDest);
moveJob->ui()->setWindow(this);
connect(moveJob, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*)));
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.
static_cast<KIO::Job*>(job)->ui()->showErrorMessage();
}
}
#include "moc_kcmdesktoppaths.cpp"