Changeset View
Changeset View
Standalone View
Standalone View
kcms/desktoppaths/globalpaths.cpp
Show All 34 Lines | |||||
35 | // (c) David Faure 2000 | 35 | // (c) David Faure 2000 | ||
36 | 36 | | |||
37 | 37 | | |||
38 | // Own | 38 | // Own | ||
39 | #include "globalpaths.h" | 39 | #include "globalpaths.h" | ||
40 | #include "ui_globalpaths.h" | 40 | #include "ui_globalpaths.h" | ||
41 | #include "desktoppathssettings.h" | 41 | #include "desktoppathssettings.h" | ||
42 | 42 | | |||
43 | // Qt | | |||
44 | #include <QCheckBox> | | |||
45 | #include <QComboBox> | | |||
46 | #include <QLabel> | | |||
47 | #include <QLayout> | | |||
48 | #include <QFormLayout> | | |||
49 | #include <QApplication> | | |||
50 | #include <QLoggingCategory> | | |||
51 | #include <QStandardPaths> | | |||
52 | | ||||
53 | // KDE | | |||
54 | #include <kconfiggroup.h> | | |||
55 | #include <kfileitem.h> | | |||
56 | #include <kio/copyjob.h> | | |||
57 | #include <kio/deletejob.h> | | |||
58 | #include <kio/job.h> | | |||
59 | #include <kio/jobuidelegate.h> | | |||
60 | #include <kjobwidgets.h> | | |||
61 | #include <KLocalizedString> | | |||
62 | #include <kmessagebox.h> | | |||
63 | #include <kurlrequester.h> | | |||
64 | #include <KPluginFactory> | 43 | #include <KPluginFactory> | ||
65 | #include <KConfig> | | |||
66 | #include <KSharedConfig> | | |||
67 | | ||||
68 | Q_LOGGING_CATEGORY(KCM_DESKTOPPATH, "kcm_desktoppath") | | |||
69 | 44 | | |||
70 | K_PLUGIN_FACTORY(KcmDesktopPathsFactory, registerPlugin<DesktopPathConfig>();) | 45 | K_PLUGIN_FACTORY(KcmDesktopPathsFactory, registerPlugin<DesktopPathConfig>();) | ||
71 | 46 | | |||
72 | //----------------------------------------------------------------------------- | 47 | //----------------------------------------------------------------------------- | ||
73 | 48 | | |||
74 | DesktopPathConfig::DesktopPathConfig(QWidget *parent, const QVariantList &) | 49 | DesktopPathConfig::DesktopPathConfig(QWidget *parent, const QVariantList &) | ||
75 | : KCModule( parent ) | 50 | : KCModule( parent ) | ||
76 | , m_ui(new Ui::DesktopPathsView) | 51 | , m_ui(new Ui::DesktopPathsView) | ||
77 | , m_pathsSettings(new DesktopPathsSettings(this)) | 52 | , m_pathsSettings(new DesktopPathsSettings(this)) | ||
78 | { | 53 | { | ||
79 | m_ui->setupUi(this); | 54 | m_ui->setupUi(this); | ||
80 | setQuickHelp(i18n("<h1>Paths</h1>\n" | 55 | setQuickHelp(i18n("<h1>Paths</h1>\n" | ||
81 | "This module allows you to choose where in the filesystem the " | 56 | "This module allows you to choose where in the filesystem the " | ||
82 | "files on your desktop should be stored.\n" | 57 | "files on your desktop should be stored.\n" | ||
83 | "Use the \"Whats This?\" (Shift+F1) to get help on specific options.")); | 58 | "Use the \"Whats This?\" (Shift+F1) to get help on specific options.")); | ||
84 | addConfig(m_pathsSettings, this); | 59 | addConfig(m_pathsSettings, this); | ||
85 | } | 60 | } | ||
86 | 61 | | |||
87 | DesktopPathConfig::~DesktopPathConfig() | 62 | DesktopPathConfig::~DesktopPathConfig() | ||
88 | { | 63 | { | ||
89 | } | 64 | } | ||
90 | 65 | | |||
91 | void DesktopPathConfig::save() | | |||
92 | { | | |||
93 | bool autostartMoved = false; | | |||
94 | | ||||
95 | QUrl desktopURL = m_pathsSettings->desktopLocation(); | | |||
96 | | ||||
97 | QUrl autostartURL = m_pathsSettings->autostartLocation(); | | |||
98 | QUrl newAutostartURL = m_ui->kcfg_autostartLocation->url(); | | |||
99 | | ||||
100 | if ( !m_ui->kcfg_desktopLocation->url().matches( desktopURL, QUrl::StripTrailingSlash ) ) | | |||
101 | { | | |||
102 | // Test which other paths were inside this one (as it is by default) | | |||
103 | // and for each, test where it should go. | | |||
104 | // * Inside destination -> let them be moved with the desktop (but adjust name if necessary) | | |||
105 | // * Not inside destination -> move first | | |||
106 | // !!! | | |||
107 | qCDebug(KCM_DESKTOPPATH) << "desktopURL=" << desktopURL; | | |||
108 | QString urlDesktop = m_ui->kcfg_desktopLocation->url().toLocalFile(); | | |||
109 | if ( !urlDesktop.endsWith(QLatin1Char('/'))) | | |||
110 | urlDesktop+=QLatin1Char('/'); | | |||
111 | | ||||
112 | if ( desktopURL.isParentOf( autostartURL ) ) | | |||
113 | { | | |||
114 | qCDebug(KCM_DESKTOPPATH) << "Autostart is on the desktop"; | | |||
115 | | ||||
116 | // Either the Autostart field wasn't changed (-> need to update it) | | |||
117 | if ( newAutostartURL.matches(autostartURL, QUrl::StripTrailingSlash) ) | | |||
118 | { | | |||
119 | // Hack. It could be in a subdir inside desktop. Hmmm... Argl. | | |||
120 | m_ui->kcfg_autostartLocation->setUrl(QUrl::fromLocalFile(urlDesktop + QStringLiteral("Autostart/"))); | | |||
121 | qCDebug(KCM_DESKTOPPATH) << "Autostart is moved with the desktop"; | | |||
122 | autostartMoved = true; | | |||
123 | } | | |||
124 | // or it has been changed (->need to move it from here) | | |||
125 | else | | |||
126 | { | | |||
127 | QUrl futureAutostartURL = QUrl::fromLocalFile(urlDesktop + QStringLiteral("Autostart/")); | | |||
128 | if ( newAutostartURL.matches( futureAutostartURL, QUrl::StripTrailingSlash ) ) | | |||
129 | autostartMoved = true; | | |||
130 | else | | |||
131 | autostartMoved = moveDir( m_pathsSettings->autostartLocation(), m_ui->kcfg_autostartLocation->url(), i18n("Autostart") ); | | |||
132 | } | | |||
133 | } | | |||
134 | | ||||
135 | if ( moveDir( m_pathsSettings->desktopLocation(), QUrl::fromLocalFile( urlDesktop ), i18n("Desktop") ) ) | | |||
136 | { | | |||
137 | //save in XDG path | | |||
138 | m_pathsSettings->setDesktopLocation(QUrl::fromLocalFile(urlDesktop)); | | |||
139 | } | | |||
140 | } | | |||
141 | | ||||
142 | if ( !newAutostartURL.matches( autostartURL, QUrl::StripTrailingSlash ) ) | | |||
143 | { | | |||
144 | if (!autostartMoved) | | |||
145 | autostartMoved = moveDir( m_pathsSettings->autostartLocation(), m_ui->kcfg_autostartLocation->url(), i18n("Autostart") ); | | |||
146 | if (autostartMoved) | | |||
147 | { | | |||
148 | m_pathsSettings->setAutostartLocation(m_ui->kcfg_autostartLocation->url()); | | |||
149 | } | | |||
150 | } | | |||
151 | | ||||
152 | xdgSavePath(m_ui->kcfg_documentsLocation, m_pathsSettings->documentsLocation(), "documentsLocation", i18n("Documents")); | | |||
153 | xdgSavePath(m_ui->kcfg_downloadsLocation, m_pathsSettings->downloadsLocation(), "downloadsLocation", i18n("Downloads")); | | |||
154 | xdgSavePath(m_ui->kcfg_videosLocation, m_pathsSettings->videosLocation(), "videosLocation", i18n("Movies")); | | |||
155 | xdgSavePath(m_ui->kcfg_picturesLocation, m_pathsSettings->picturesLocation(), "picturesLocation", i18n("Pictures")); | | |||
156 | xdgSavePath(m_ui->kcfg_musicLocation, m_pathsSettings->musicLocation(), "musicLocation", i18n("Music")); | | |||
157 | | ||||
158 | m_pathsSettings->save(); | | |||
159 | } | | |||
160 | | ||||
161 | bool DesktopPathConfig::xdgSavePath(KUrlRequester* ur, const QUrl& currentUrl, const char* xdgKey, const QString& type) | | |||
162 | { | | |||
163 | QUrl newUrl = ur->url(); | | |||
164 | //url might be empty, use QDir::homePath (the default for xdg) then | | |||
165 | if (!newUrl.isValid()) { | | |||
166 | newUrl = QUrl(QUrl::fromLocalFile(QDir::homePath())); | | |||
167 | } | | |||
168 | if (!newUrl.matches(currentUrl, QUrl::StripTrailingSlash)) { | | |||
169 | const QString path = newUrl.toLocalFile(); | | |||
170 | if (!QDir(path).exists()) { | | |||
171 | // Check permissions | | |||
172 | if (QDir().mkpath(path)) { | | |||
173 | QDir().rmdir(path); // rmdir again, so that we get a fast rename | | |||
174 | } else { | | |||
175 | KMessageBox::sorry(this, KIO::buildErrorString(KIO::ERR_CANNOT_MKDIR, path)); | | |||
176 | ur->setUrl(currentUrl); // revert | | |||
177 | return false; | | |||
178 | } | | |||
179 | } | | |||
180 | if (moveDir(currentUrl, newUrl, type)) { | | |||
181 | auto item = m_pathsSettings->findItem(xdgKey); | | |||
182 | Q_ASSERT(item); | | |||
183 | item->setProperty(newUrl); | | |||
184 | return true; | | |||
185 | } | | |||
186 | } | | |||
187 | return false; | | |||
188 | } | | |||
189 | | ||||
190 | bool DesktopPathConfig::moveDir( const QUrl & src, const QUrl & dest, const QString & type ) | | |||
191 | { | | |||
192 | if (!src.isLocalFile() || !dest.isLocalFile()) | | |||
193 | return true; | | |||
194 | if (!QFile::exists(src.toLocalFile())) | | |||
195 | return true; | | |||
196 | // Do not move $HOME! #193057 | | |||
197 | const QString translatedPath = src.toLocalFile(); | | |||
198 | if (translatedPath == QDir::homePath() || translatedPath == QDir::homePath() + QLatin1Char('/')) { | | |||
199 | return true; | | |||
200 | } | | |||
201 | | ||||
202 | m_ok = true; | | |||
203 | | ||||
204 | QString question; | | |||
205 | KGuiItem yesItem; | | |||
206 | KGuiItem noItem; | | |||
207 | if (QFile::exists(dest.toLocalFile())) { | | |||
208 | // TODO: check if the src dir is empty? Nothing to move, then... | | |||
209 | question = i18n("The path for '%1' has been changed.\nDo you want the files to be moved from '%2' to '%3'?", | | |||
210 | type, src.toLocalFile(), | | |||
211 | dest.toLocalFile()); | | |||
212 | yesItem = KGuiItem(i18nc("Move files from old to new place", "Move")); | | |||
213 | noItem = KGuiItem(i18nc("Use the new directory but do not move files", "Do not Move")); | | |||
214 | } else { | | |||
215 | question = i18n("The path for '%1' has been changed.\nDo you want to move the directory '%2' to '%3'?", | | |||
216 | type, src.toLocalFile(), | | |||
217 | dest.toLocalFile()); | | |||
218 | yesItem = KGuiItem(i18nc("Move the directory", "Move")); | | |||
219 | noItem = KGuiItem(i18nc("Use the new directory but do not move anything", "Do not Move")); | | |||
220 | } | | |||
221 | | ||||
222 | // Ask for confirmation before moving the files | | |||
223 | if (KMessageBox::questionYesNo(this, question, i18n("Confirmation Required"), | | |||
224 | yesItem, noItem) | | |||
225 | == KMessageBox::Yes ) | | |||
226 | { | | |||
227 | if (QFile::exists(dest.toLocalFile())) { | | |||
228 | // Destination already exists -- should always be the case, for most types, | | |||
229 | // but maybe not for the complex autostart case (to be checked...) | | |||
230 | m_copyToDest = dest; | | |||
231 | m_copyFromSrc = src; | | |||
232 | KIO::ListJob* job = KIO::listDir( src ); | | |||
233 | job->setAutoDelete(false); // see <noautodelete> below | | |||
234 | KJobWidgets::setWindow(job, this); | | |||
235 | job->uiDelegate()->setAutoErrorHandlingEnabled(true); | | |||
236 | connect(job, &KIO::ListJob::entries, this, &DesktopPathConfig::slotEntries); | | |||
237 | // slotEntries will move every file/subdir individually into the dest | | |||
238 | job->exec(); | | |||
239 | if (m_ok) { | | |||
240 | QDir().rmdir(src.toLocalFile()); // hopefully it's empty by now | | |||
241 | } | | |||
242 | delete job; | | |||
243 | } | | |||
244 | else | | |||
245 | { | | |||
246 | qCDebug(KCM_DESKTOPPATH) << "Direct move from" << src << "to" << dest; | | |||
247 | KIO::Job * job = KIO::move( src, dest ); | | |||
248 | KJobWidgets::setWindow(job, this); | | |||
249 | connect(job, &KIO::Job::result, this, &DesktopPathConfig::slotResult); | | |||
250 | job->exec(); | | |||
251 | } | | |||
252 | } | | |||
253 | qCDebug(KCM_DESKTOPPATH) << "DesktopPathConfig::slotResult returning " << m_ok; | | |||
254 | return m_ok; | | |||
255 | } | | |||
256 | | ||||
257 | void DesktopPathConfig::slotEntries(KIO::Job*, const KIO::UDSEntryList& list) | | |||
258 | { | | |||
259 | QListIterator<KIO::UDSEntry> it(list); | | |||
260 | while (it.hasNext()) { | | |||
261 | KFileItem file(it.next(), m_copyFromSrc, true, true); | | |||
262 | qCDebug(KCM_DESKTOPPATH) << file.url(); | | |||
263 | if (file.url() == m_copyFromSrc || file.name() == QLatin1String("..")) { | | |||
264 | continue; | | |||
265 | } | | |||
266 | | ||||
267 | KIO::Job * moveJob = KIO::move(file.url(), m_copyToDest); | | |||
268 | KJobWidgets::setWindow(moveJob, this); | | |||
269 | connect(moveJob, &KIO::Job::result, this, &DesktopPathConfig::slotResult); | | |||
270 | moveJob->exec(); // sub-event loop here. <noautodelete>: the main job is not autodeleted because it would be deleted here | | |||
271 | } | | |||
272 | } | | |||
273 | | ||||
274 | void DesktopPathConfig::slotResult( KJob * job ) | | |||
275 | { | | |||
276 | if (job->error()) { | | |||
277 | if ( job->error() != KIO::ERR_DOES_NOT_EXIST ) | | |||
278 | m_ok = false; | | |||
279 | | ||||
280 | // If the source doesn't exist, no wonder we couldn't move the dir. | | |||
281 | // In that case, trust the user and set the new setting in any case. | | |||
282 | | ||||
283 | static_cast<KIO::Job*>(job)->uiDelegate()->showErrorMessage(); | | |||
284 | } | | |||
285 | } | | |||
286 | | ||||
287 | #include "globalpaths.moc" | 66 | #include "globalpaths.moc" |