File indexing completed on 2024-04-28 04:37:03

0001 /*
0002     SPDX-FileCopyrightText: 2010 Milian Wolff <mail@milianw.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "helper.h"
0008 
0009 #include "debug.h"
0010 #include "path.h"
0011 
0012 #include <QApplication>
0013 #include <QDir>
0014 #include <QFileInfo>
0015 
0016 #include <KIO/CopyJob>
0017 #include <KIO/DeleteJob>
0018 #include <KIO/StatJob>
0019 #include <KIO/StoredTransferJob>
0020 #include <KIO/MkdirJob>
0021 #include <KJobWidgets>
0022 #include <KLocalizedString>
0023 #include <KTextEditor/Document>
0024 
0025 #include <interfaces/iproject.h>
0026 #include <vcs/interfaces/ibasicversioncontrol.h>
0027 #include <interfaces/iplugin.h>
0028 #include <vcs/vcsjob.h>
0029 #include <interfaces/icore.h>
0030 #include <interfaces/idocumentcontroller.h>
0031 #include <interfaces/iuicontroller.h>
0032 #include <sublime/message.h>
0033 
0034 using namespace KDevelop;
0035 
0036 bool KDevelop::removeUrl(const KDevelop::IProject* project, const QUrl& url, const bool isFolder)
0037 {
0038     qCDebug(PROJECT) << "Removing url:" << url << "from project" << project;
0039 
0040     QWidget* window = QApplication::activeWindow();
0041 
0042     auto job = KIO::statDetails(url, KIO::StatJob::DestinationSide, KIO::StatNoDetails);
0043     KJobWidgets::setWindow(job, window);
0044     if (!job->exec()) {
0045         qCWarning(PROJECT) << "tried to remove non-existing url:" << url << project << isFolder;
0046         return true;
0047     }
0048 
0049     IPlugin* vcsplugin=project->versionControlPlugin();
0050     if(vcsplugin) {
0051         auto* vcs=vcsplugin->extension<IBasicVersionControl>();
0052 
0053         // We have a vcs and the file/folder is controller, need to make the rename through vcs
0054         if(vcs->isVersionControlled(url)) {
0055             VcsJob* job=vcs->remove(QList<QUrl>() << url);
0056             if(job) {
0057                 return job->exec();
0058             }
0059         }
0060     }
0061 
0062     //if we didn't find a VCS, we remove using KIO (if the file still exists, the vcs plugin might have simply deleted the url without returning a job
0063     auto deleteJob = KIO::del(url);
0064     KJobWidgets::setWindow(deleteJob, window);
0065     if (!deleteJob->exec() && url.isLocalFile() && (QFileInfo::exists(url.toLocalFile()))) {
0066         const QString messageText =
0067             isFolder ? i18n( "Cannot remove folder <i>%1</i>.", url.toDisplayString(QUrl::PreferLocalFile) )
0068                         : i18n( "Cannot remove file <i>%1</i>.", url.toDisplayString(QUrl::PreferLocalFile) );
0069         auto* message = new Sublime::Message(messageText, Sublime::Message::Error);
0070         ICore::self()->uiController()->postMessage(message);
0071         return false;
0072     }
0073     return true;
0074 }
0075 
0076 bool KDevelop::removePath(const KDevelop::IProject* project, const KDevelop::Path& path, const bool isFolder)
0077 {
0078     return removeUrl(project, path.toUrl(), isFolder);
0079 }
0080 
0081 bool KDevelop::createFile(const QUrl& file)
0082 {
0083     auto statJob = KIO::statDetails(file, KIO::StatJob::DestinationSide, KIO::StatNoDetails);
0084     KJobWidgets::setWindow(statJob, QApplication::activeWindow());
0085     if (statJob->exec()) {
0086         const QString messageText = i18n("The file <i>%1</i> already exists.", file.toDisplayString(QUrl::PreferLocalFile));
0087         auto* message = new Sublime::Message(messageText, Sublime::Message::Error);
0088         ICore::self()->uiController()->postMessage(message);
0089         return false;
0090     }
0091 
0092     {
0093         auto uploadJob = KIO::storedPut(QByteArray("\n"), file, -1);
0094         KJobWidgets::setWindow(uploadJob, QApplication::activeWindow());
0095         if (!uploadJob->exec()) {
0096             const QString messageText = i18n("Cannot create file <i>%1</i>.", file.toDisplayString(QUrl::PreferLocalFile));
0097             auto* message = new Sublime::Message(messageText, Sublime::Message::Error);
0098             ICore::self()->uiController()->postMessage(message);
0099             return false;
0100         }
0101     }
0102     return true;
0103 }
0104 
0105 bool KDevelop::createFile(const KDevelop::Path& file)
0106 {
0107     return createFile(file.toUrl());
0108 }
0109 
0110 bool KDevelop::createFolder(const QUrl& folder)
0111 {
0112     auto mkdirJob = KIO::mkdir(folder);
0113     KJobWidgets::setWindow(mkdirJob, QApplication::activeWindow());
0114     if (!mkdirJob->exec()) {
0115         const QString messageText = i18n("Cannot create folder <i>%1</i>.", folder.toDisplayString(QUrl::PreferLocalFile));
0116         auto* message = new Sublime::Message(messageText, Sublime::Message::Error);
0117         ICore::self()->uiController()->postMessage(message);
0118         return false;
0119     }
0120     return true;
0121 }
0122 
0123 bool KDevelop::createFolder(const KDevelop::Path& folder)
0124 {
0125     return createFolder(folder.toUrl());
0126 }
0127 
0128 bool KDevelop::renameUrl(const KDevelop::IProject* project, const QUrl& oldname, const QUrl& newname)
0129 {
0130     bool wasVcsMoved = false;
0131     IPlugin* vcsplugin = project->versionControlPlugin();
0132     if (vcsplugin) {
0133         auto* vcs = vcsplugin->extension<IBasicVersionControl>();
0134 
0135         // We have a vcs and the file/folder is controller, need to make the rename through vcs
0136         if (vcs->isVersionControlled(oldname)) {
0137             VcsJob* job = vcs->move(oldname, newname);
0138             if (job && !job->exec()) {
0139                 return false;
0140             }
0141             wasVcsMoved = true;
0142         }
0143     }
0144     // Fallback for the case of no vcs, or not-vcs-managed file/folder
0145 
0146     // try to save-as the text document, so users can directly continue to work
0147     // on the renamed url as well as keeping the undo-stack intact
0148     IDocument* document = ICore::self()->documentController()->documentForUrl(oldname);
0149     if (document && document->textDocument()) {
0150         if (!document->textDocument()->saveAs(newname)) {
0151             return false;
0152         }
0153         if (!wasVcsMoved) {
0154             // unlink the old file
0155             removeUrl(project, oldname, false);
0156         }
0157         return true;
0158     } else if (!wasVcsMoved) {
0159         // fallback for non-textdocuments (also folders e.g.)
0160         KIO::CopyJob* job = KIO::move(oldname, newname);
0161         KJobWidgets::setWindow(job, QApplication::activeWindow());
0162         bool success = job->exec();
0163         if (success) {
0164             // save files that where opened in this folder under the new name
0165             Path oldBasePath(oldname);
0166             Path newBasePath(newname);
0167             const auto documents = ICore::self()->documentController()->openDocuments();
0168             for (auto* doc : documents) {
0169                 auto textDoc = doc->textDocument();
0170                 if (textDoc && oldname.isParentOf(doc->url())) {
0171                     const auto path = Path(textDoc->url());
0172                     const auto relativePath = oldBasePath.relativePath(path);
0173                     const auto newPath = Path(newBasePath, relativePath);
0174                     textDoc->saveAs(newPath.toUrl());
0175                 }
0176             }
0177         }
0178         return success;
0179     } else {
0180         return true;
0181     }
0182 }
0183 
0184 bool KDevelop::renamePath(const KDevelop::IProject* project, const KDevelop::Path& oldName, const KDevelop::Path& newName)
0185 {
0186     return renameUrl(project, oldName.toUrl(), newName.toUrl());
0187 }
0188 
0189 bool KDevelop::copyUrl(const KDevelop::IProject* project, const QUrl& source, const QUrl& target)
0190 {
0191     IPlugin* vcsplugin=project->versionControlPlugin();
0192     if(vcsplugin) {
0193         auto* vcs=vcsplugin->extension<IBasicVersionControl>();
0194 
0195         // We have a vcs and the file/folder is controller, need to make the rename through vcs
0196         if(vcs->isVersionControlled(source)) {
0197             VcsJob* job=vcs->copy(source, target);
0198             if(job) {
0199                 return job->exec();
0200             }
0201         }
0202     }
0203 
0204     // Fallback for the case of no vcs, or not-vcs-managed file/folder
0205     auto job = KIO::copy(source, target);
0206     KJobWidgets::setWindow(job, QApplication::activeWindow());
0207     return job->exec();
0208 }
0209 
0210 bool KDevelop::copyPath(const KDevelop::IProject* project, const KDevelop::Path& source, const KDevelop::Path& target)
0211 {
0212     return copyUrl(project, source.toUrl(), target.toUrl());
0213 }
0214 
0215 Path KDevelop::proposedBuildFolder(const Path& sourceFolder)
0216 {
0217     Path proposedBuildFolder;
0218     if (sourceFolder.path().contains(QLatin1String("/src/"))) {
0219         const QString srcBuildPath = sourceFolder.path().replace(QLatin1String("/src/"), QLatin1String("/build/"));
0220         Q_ASSERT(!srcBuildPath.isEmpty());
0221         if (QDir(srcBuildPath).exists()) {
0222             proposedBuildFolder = Path(srcBuildPath);
0223         }
0224     }
0225     if (!proposedBuildFolder.isValid()) {
0226         proposedBuildFolder = Path(sourceFolder, QStringLiteral("build"));
0227     }
0228 
0229     return proposedBuildFolder;
0230 }