diff --git a/kate/CMakeLists.txt b/kate/CMakeLists.txt --- a/kate/CMakeLists.txt +++ b/kate/CMakeLists.txt @@ -20,6 +20,7 @@ kateconfigdialog.cpp kateconfigplugindialogpage.cpp katedocmanager.cpp + katefileactions.cpp katemainwindow.cpp katepluginmanager.cpp kateviewmanager.cpp diff --git a/kate/katefileactions.h b/kate/katefileactions.h new file mode 100644 --- /dev/null +++ b/kate/katefileactions.h @@ -0,0 +1,63 @@ +/* This file is part of the KDE project + Copyright (C) 2018 GregorMi + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KATE_FILEACTIONS_H +#define KATE_FILEACTIONS_H + +class QWidget; +namespace KTextEditor +{ + class Document; +} + +namespace KateFileActions +{ + /** + * Shows a Rename dialog to rename the file associated with the document. + * The document will be closed an reopened. + * + * Nothing is done if the document is nullptr or has no associated file. + * + * TODO: code was copied from ../addons/filetree/katefiletree.cpp + * (-> DUPLICATE CODE, the new code should be used there! How to publish it to be available there?) + */ + void renameDocumentFile(QWidget* parent, KTextEditor::Document* document); + + /** + * Asks the user if the file should really be deleted. If yes, the file + * is deleted from disk and the document closed. + * + * Nothing is done if the document is nullptr or has no associated file. + * + * TODO: code was copied from ../addons/filetree/katefiletree.cpp + * (-> DUPLICATE CODE, the new code should be used there! How to publish it to be available there?) + */ + void removeDocumentFile(QWidget* parent, KTextEditor::Document* document); + + /** + * Runs an external programm to compare the two given documents + * (if they have associated files) with KDiff3. + * + * TODO: handling when documentA or B is empty + * TODO: message if kdiff3 is not installed + * TODO: possibility to choose another program (like Kompare or Meld) + */ + void compareWithExternalProgram(KTextEditor::Document* documentA, KTextEditor::Document* documentB); +} + +#endif diff --git a/kate/katefileactions.cpp b/kate/katefileactions.cpp new file mode 100644 --- /dev/null +++ b/kate/katefileactions.cpp @@ -0,0 +1,124 @@ +/* This file is part of the KDE project + Copyright (C) 2018 GregorMi + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include "katefileactions.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +void KateFileActions::renameDocumentFile(QWidget* parent, KTextEditor::Document* doc) +{ + if (!doc) { + return; + } + + const QUrl oldFileUrl = doc->url(); + + if (oldFileUrl.isEmpty()) { // NEW + return; + } + + const QString oldFileName = doc->url().fileName(); + bool ok; + + QString newFileName = QInputDialog::getText(parent, // ADAPTED + i18n("Rename file"), i18n("New file name"), QLineEdit::Normal, oldFileName, &ok); + if (!ok) { + return; + } + + QUrl newFileUrl = oldFileUrl.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash); + newFileUrl.setPath(newFileUrl.path() + QLatin1Char('/') + newFileName); + + if (!newFileUrl.isValid()) { + return; + } + + if (!doc->closeUrl()) { + return; + } + + doc->waitSaveComplete(); + + KIO::CopyJob* job = KIO::move(oldFileUrl, newFileUrl); + QSharedPointer sc(new QMetaObject::Connection()); + auto success = [doc, sc] (KIO::Job*, const QUrl&, const QUrl &realNewFileUrl, const QDateTime&, bool, bool) { + doc->openUrl(realNewFileUrl); + doc->documentSavedOrUploaded(doc, true); + QObject::disconnect(*sc); + }; + *sc = parent->connect(job, &KIO::CopyJob::copyingDone, doc, success); + + if (!job->exec()) { + KMessageBox::sorry(parent, i18n("File \"%1\" could not be moved to \"%2\"", oldFileUrl.toDisplayString(), newFileUrl.toDisplayString())); + doc->openUrl(oldFileUrl); + } +} + +void KateFileActions::removeDocumentFile(QWidget* parent, KTextEditor::Document* doc) +{ + if (!doc) { + return; + } + + const auto& url = doc->url(); + + if (url.isEmpty()) { // NEW + return; + } + + bool go = (KMessageBox::warningContinueCancel(parent, + i18n("Do you really want to delete file \"%1\"?", url.toDisplayString()), + i18n("Delete file"), + KStandardGuiItem::yes(), KStandardGuiItem::no(), QLatin1String("filetreedeletefile") + ) == KMessageBox::Continue); + + if (!go) { + return; + } + + if (!KTextEditor::Editor::instance()->application()->closeDocument(doc)) { + return; // no extra message, the internals of ktexteditor should take care of that. + } + + if (url.isValid()) { + KIO::DeleteJob *job = KIO::del(url); + if (!job->exec()) { + KMessageBox::sorry(parent, i18n("File \"%1\" could not be deleted.", url.toDisplayString())); + } + } +} + +void KateFileActions::compareWithExternalProgram(KTextEditor::Document* documentA, KTextEditor::Document* documentB) +{ + qDebug() << documentA->url() << documentB->url(); + + KProcess process; + process << QStringLiteral("kdiff3") << documentA->url().toLocalFile() << documentB->url().toLocalFile(); + process.startDetached(); +} diff --git a/kate/kateviewspace.cpp b/kate/kateviewspace.cpp --- a/kate/kateviewspace.cpp +++ b/kate/kateviewspace.cpp @@ -23,6 +23,7 @@ #include "kateviewmanager.h" #include "katedocmanager.h" #include "kateapp.h" +#include "katefileactions.h" #include "katesessionmanager.h" #include "katedebug.h" #include "katetabbar.h" @@ -37,6 +38,7 @@ #if KIO_VERSION >= QT_VERSION_CHECK(5, 24, 0) #include #endif +#include #include #include @@ -595,13 +597,29 @@ menu.addSeparator(); QAction *aCopyPath = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy &Path")); QAction *aOpenFolder = menu.addAction(QIcon::fromTheme(QStringLiteral("document-open-folder")), i18n("&Open Containing Folder")); + QAction *aRenameFile = menu.addAction(QIcon::fromTheme(QLatin1String("edit-rename")), i18nc("@action:inmenu", "Rename File...")); + QAction *aDeleteFile = menu.addAction(QIcon::fromTheme(QLatin1String("edit-delete-shred")), i18nc("@action:inmenu", "Delete File")); + QAction *aFileProperties = menu.addAction(QIcon::fromTheme(QStringLiteral("dialog-object-properties")), i18n("File Properties")); + menu.addSeparator(); + QAction *aCompareWithActive = menu.addAction(QIcon::fromTheme(QStringLiteral("kompare")), i18n("Compare active with this document...")); if (KateApp::self()->documentManager()->documentList().count() < 2) { aCloseOthers->setEnabled(false); } + if (doc->url().isEmpty()) { aCopyPath->setEnabled(false); aOpenFolder->setEnabled(false); + aRenameFile->setEnabled(false); + aDeleteFile->setEnabled(false); + aFileProperties->setEnabled(false); + aCompareWithActive->setEnabled(false); + } + + auto activeDocument = KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView()->document(); // used for aCompareWithActive which is used with another tab which is not active + // both documents must have urls and must not be the same to have the compare feature enabled + if (activeDocument->url().isEmpty() || activeDocument == doc) { + aCompareWithActive->setEnabled(false); } QAction *choice = menu.exec(globalPos); @@ -618,6 +636,19 @@ #else QDesktopServices::openUrl(doc->url().adjusted(QUrl::RemoveFilename)); #endif + } else if (choice == aFileProperties) { + KFileItem fileItem(doc->url()); + QDialog* dlg = new KPropertiesDialog(fileItem); + dlg->setAttribute(Qt::WA_DeleteOnClose); + dlg->show(); + } else if (choice == aRenameFile) { + KateFileActions::renameDocumentFile(this, doc); + } + else if (choice == aDeleteFile) { + KateFileActions::removeDocumentFile(this, doc); + } + else if (choice == aCompareWithActive) { + KateFileActions::compareWithExternalProgram(activeDocument, doc); } }