diff --git a/kdevplatform/shell/runtimecontroller.cpp b/kdevplatform/shell/runtimecontroller.cpp index fb66148cec..e2ad831a05 100644 --- a/kdevplatform/shell/runtimecontroller.cpp +++ b/kdevplatform/shell/runtimecontroller.cpp @@ -1,155 +1,165 @@ /* Copyright 2017 Aleix Pol Gonzalez 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 "runtimecontroller.h" #include #include #include #include #include #include #include "core.h" #include "uicontroller.h" #include "mainwindow.h" #include "debug.h" using namespace KDevelop; class IdentityRuntime : public IRuntime { QString name() const override { return i18n("Host System"); } void startProcess(KProcess *process) const override { - connect(process, &QProcess::errorOccurred, this, [process](QProcess::ProcessError error) { +#if QT_VERSION < 0x050600 + connect(process, static_cast(&QProcess::error), +#else + connect(process, &QProcess::errorOccurred, +#endif + this, [process](QProcess::ProcessError error) { qCWarning(SHELL) << "error:" << error << process->program() << process->errorString(); }); process->start(); } void startProcess(QProcess *process) const override { - connect(process, &QProcess::errorOccurred, this, [process](QProcess::ProcessError error) { +#if QT_VERSION < 0x050600 + connect(process, static_cast(&QProcess::error), +#else + connect(process, &QProcess::errorOccurred, +#endif + this, [process](QProcess::ProcessError error) { qCWarning(SHELL) << "error:" << error << process->program() << process->errorString(); }); process->start(); } KDevelop::Path pathInHost(const KDevelop::Path & runtimePath) const override { return runtimePath; } KDevelop::Path pathInRuntime(const KDevelop::Path & localPath) const override { return localPath; } void setEnabled(bool /*enabled*/) override {} QByteArray getenv(const QByteArray & varname) const override { return qgetenv(varname); } }; KDevelop::RuntimeController::RuntimeController(KDevelop::Core* core) : m_core(core) { const bool haveUI = (core->setupFlags() != Core::NoUi); if (haveUI) { m_runtimesMenu.reset(new QMenu()); } addRuntimes(new IdentityRuntime); setCurrentRuntime(m_runtimes.first()); if (haveUI) { setupActions(); } } KDevelop::RuntimeController::~RuntimeController() { m_currentRuntime->setEnabled(false); m_currentRuntime = nullptr; } void RuntimeController::setupActions() { // TODO not multi-window friendly, FIXME KActionCollection* ac = m_core->uiControllerInternal()->defaultMainWindow()->actionCollection(); auto action = new QAction(this); action->setStatusTip(i18n("Allows to select a runtime")); action->setMenu(m_runtimesMenu.data()); action->setIcon(QIcon::fromTheme(QStringLiteral("file-library-symbolic"))); auto updateActionText = [action](IRuntime* currentRuntime){ action->setText(i18n("Runtime: %1", currentRuntime->name())); }; connect(this, &RuntimeController::currentRuntimeChanged, action, updateActionText); updateActionText(m_currentRuntime); ac->addAction(QStringLiteral("switch_runtimes"), action); } void KDevelop::RuntimeController::initialize() { } KDevelop::IRuntime * KDevelop::RuntimeController::currentRuntime() const { Q_ASSERT(m_currentRuntime); return m_currentRuntime; } QVector KDevelop::RuntimeController::availableRuntimes() const { return m_runtimes; } void KDevelop::RuntimeController::setCurrentRuntime(KDevelop::IRuntime* runtime) { if (m_currentRuntime == runtime) return; Q_ASSERT(m_runtimes.contains(runtime)); if (m_currentRuntime) { m_currentRuntime->setEnabled(false); } qCDebug(SHELL) << "setting runtime..." << runtime->name() << "was" << m_currentRuntime; m_currentRuntime = runtime; m_currentRuntime->setEnabled(true); Q_EMIT currentRuntimeChanged(runtime); } void KDevelop::RuntimeController::addRuntimes(KDevelop::IRuntime * runtime) { if (!runtime->parent()) runtime->setParent(this); if (m_core->setupFlags() != Core::NoUi) { QAction* runtimeAction = new QAction(runtime->name(), m_runtimesMenu.data()); runtimeAction->setCheckable(true); connect(runtimeAction, &QAction::triggered, runtime, [this, runtime]() { setCurrentRuntime(runtime); }); connect(this, &RuntimeController::currentRuntimeChanged, runtimeAction, [runtimeAction, runtime](IRuntime* currentRuntime) { runtimeAction->setChecked(runtime == currentRuntime); }); connect(runtime, &QObject::destroyed, this, [this, runtimeAction](QObject* obj) { Q_ASSERT(m_currentRuntime != obj); m_runtimes.removeAll(qobject_cast(obj)); delete runtimeAction; }); m_runtimesMenu->addAction(runtimeAction); } else { connect(runtime, &QObject::destroyed, this, [this](QObject* obj) { Q_ASSERT(m_currentRuntime != obj); m_runtimes.removeAll(qobject_cast(obj)); }); } m_runtimes << runtime; } diff --git a/plugins/cmake/cmakecommandscontents.cpp b/plugins/cmake/cmakecommandscontents.cpp index d8566b35cb..d6d99c6216 100644 --- a/plugins/cmake/cmakecommandscontents.cpp +++ b/plugins/cmake/cmakecommandscontents.cpp @@ -1,182 +1,182 @@ /* KDevelop CMake Support * * Copyright 2009 Aleix Pol * * 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. */ #include "cmakecommandscontents.h" #include #include #include #include #include #include "cmakebuilderconfig.h" #include "cmakedoc.h" #include #include -static const QVector args = { - QLatin1String("--help-command"), QLatin1String("--help-variable"), QLatin1String("--help-module"), QLatin1String("--help-property"), QLatin1String(), QLatin1String() +static const QVector args = { + QLatin1String("--help-command"), QLatin1String("--help-variable"), QLatin1String("--help-module"), QLatin1String("--help-property"), QString(), QString() }; static QString modules [] = { i18n("Commands"), i18n("Variables"), i18n("Modules"), i18n("Properties"), i18n("Policies") }; CMakeCommandsContents::CMakeCommandsContents(QObject* parent) : QAbstractItemModel(parent) , m_namesForType(CMakeDocumentation::EOType) { QVector processes; for(int i=0; i<=CMakeDocumentation::Property; i++) { const QStringList params = { args[i]+QStringLiteral("-list") }; QProcess* process = new QProcess(this); process->setProperty("type", i); process->setProgram(CMakeBuilderSettings::self()->cmakeExecutable().toLocalFile()); process->setArguments(params); KDevelop::ICore::self()->runtimeController()->currentRuntime()->startProcess(process); connect(process, static_cast(&QProcess::finished), this, &CMakeCommandsContents::processOutput); } } void CMakeCommandsContents::processOutput(int code) { QProcess* process = qobject_cast(sender()); if (code!=0) { qDebug() << "failed" << process; return; } const CMakeDocumentation::Type type = CMakeDocumentation::Type(process->property("type").toInt()); QTextStream stream(process); QString line = stream.readLine(); //discard first line QMap newEntries; QVector names; while(stream.readLineInto(&line)) { newEntries[line]=type; names += line; } beginInsertRows(index(type, 0, {}), 0, names.count()-1); m_typeForName.unite(newEntries); m_namesForType[type] = names; endInsertRows(); } CMakeDocumentation::Type CMakeCommandsContents::typeFor(const QString& identifier) const { //TODO can do much better if(m_typeForName.contains(identifier)) { return m_typeForName[identifier]; } else if(m_typeForName.contains(identifier.toLower())) { return m_typeForName[identifier.toLower()]; } else if(m_typeForName.contains(identifier.toUpper())) { return m_typeForName[identifier.toUpper()]; } return CMakeDocumentation::EOType; } QString CMakeCommandsContents::descriptionForIdentifier(const QString& id, CMakeDocumentation::Type t) const { QString desc; if(args[t].size() != 0) { desc = CMake::executeProcess(CMakeBuilderSettings::self()->cmakeExecutable().toLocalFile(), { args[t], id.simplified() }); desc = desc.remove(QStringLiteral(":ref:")); const QString rst2html = QStandardPaths::findExecutable(QStringLiteral("rst2html")); if (rst2html.isEmpty()) { desc = ("
" + desc.toHtmlEscaped() + "
" + i18n("

For better cmake documentation rendering, install rst2html

") + ""); } else { QProcess p; p.start(rst2html, { "--no-toc-backlinks" }); p.write(desc.toUtf8()); p.closeWriteChannel(); p.waitForFinished(); desc = QString::fromUtf8(p.readAllStandardOutput()); } } return desc; } void CMakeCommandsContents::showItemAt(const QModelIndex& idx) const { if(idx.isValid() && int(idx.internalId())>=0) { QString desc=CMakeDoc::s_provider->descriptionForIdentifier(idx.data().toString(), (ICMakeDocumentation::Type) idx.parent().row()); CMakeDoc::Ptr doc(new CMakeDoc(idx.data().toString(), desc)); KDevelop::ICore::self()->documentationController()->showDocumentation(doc); } } QModelIndex CMakeCommandsContents::parent(const QModelIndex& child) const { if(child.isValid() && child.column()==0 && int(child.internalId())>=0) return createIndex(child.internalId(),0, -1); return QModelIndex(); } QModelIndex CMakeCommandsContents::index(int row, int column, const QModelIndex& parent) const { if(row<0 || column!=0) return QModelIndex(); if(!parent.isValid() && row==ICMakeDocumentation::EOType) return QModelIndex(); return createIndex(row,column, int(parent.isValid() ? parent.row() : -1)); } int CMakeCommandsContents::rowCount(const QModelIndex& parent) const { if(!parent.isValid()) return ICMakeDocumentation::EOType; else if(int(parent.internalId())<0) { int ss=names((ICMakeDocumentation::Type) parent.row()).size(); return ss; } return 0; } QVariant CMakeCommandsContents::data(const QModelIndex& index, int role) const { if (index.isValid()) { if(role==Qt::DisplayRole) { int internal(index.internalId()); if(internal>=0) return m_namesForType[internal].count() > index.row() ? QVariant(m_namesForType[internal].at(index.row())) : QVariant(); else return modules[index.row()]; } } return QVariant(); } int CMakeCommandsContents::columnCount(const QModelIndex& /*parent*/) const { return 1; } QVector CMakeCommandsContents::names(ICMakeDocumentation::Type t) const { return m_namesForType[t]; } diff --git a/plugins/projectmanagerview/cutcopypastehelpers.cpp b/plugins/projectmanagerview/cutcopypastehelpers.cpp index 0dad90fc79..51cdd6982f 100644 --- a/plugins/projectmanagerview/cutcopypastehelpers.cpp +++ b/plugins/projectmanagerview/cutcopypastehelpers.cpp @@ -1,350 +1,350 @@ /* This file is part of KDevelop Copyright (C) 2017 Alexander Potashev This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 "cutcopypastehelpers.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; namespace CutCopyPasteHelpers { TaskInfo::TaskInfo(const TaskStatus status, const TaskType type, const Path::List& src, const Path& dest) : m_status(status), m_type(type), m_src(src), m_dest(dest) { } TaskInfo TaskInfo::createMove(const bool ok, const Path::List& src, const Path& dest) { return TaskInfo(ok ? TaskStatus::SUCCESS : TaskStatus::FAILURE, TaskType::MOVE, src, dest); } TaskInfo TaskInfo::createCopy(const bool ok, const Path::List& src, const Path& dest) { return TaskInfo(ok ? TaskStatus::SUCCESS : TaskStatus::FAILURE, TaskType::COPY, src, dest); } TaskInfo TaskInfo::createDeletion(const bool ok, const Path::List& src, const Path& dest) { return TaskInfo(ok ? TaskStatus::SUCCESS : TaskStatus::FAILURE, TaskType::DELETION, src, dest); } static QWidget* createPasteStatsWidget(QWidget *parent, const QVector& tasks) { // TODO: Create a model for the task list, and use it here instead of using QTreeWidget QTreeWidget* treeWidget = new QTreeWidget(parent); QList items; for (const TaskInfo& task : tasks) { int srcCount = task.m_src.size(); const bool withChildren = srcCount != 1; const QString destPath = task.m_dest.pathOrUrl(); QString text; if (withChildren) { // Multiple source items in the current suboperation switch (task.m_type) { case TaskType::MOVE: text = i18np("Move %1 item into %2", "Move %1 items into %2", srcCount, destPath); break; case TaskType::COPY: text = i18np("Copy %1 item into %2", "Copy %1 items into %2", srcCount, destPath); break; case TaskType::DELETION: text = i18np("Delete %1 item", "Delete %1 items", srcCount); break; } } else { // One source item in the current suboperation const QString srcPath = task.m_src[0].pathOrUrl(); switch (task.m_type) { case TaskType::MOVE: text = i18n("Move item %1 into %2", srcPath, destPath); break; case TaskType::COPY: text = i18n("Copy item %1 into %2", srcPath, destPath); break; case TaskType::DELETION: text = i18n("Delete item %1", srcPath); break; } } QString tooltip; QString iconName; switch (task.m_status) { case TaskStatus::SUCCESS: tooltip = i18n("Suboperation succeeded"); iconName = QStringLiteral("dialog-ok"); break; case TaskStatus::FAILURE: tooltip = i18n("Suboperation failed"); iconName = QStringLiteral("dialog-error"); break; case TaskStatus::SKIPPED: tooltip = i18n("Suboperation skipped to prevent data loss"); iconName = QStringLiteral("dialog-warning"); break; } QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, text); item->setIcon(0, QIcon::fromTheme(iconName)); item->setToolTip(0, tooltip); items.append(item); if (withChildren) { for (const Path& src : task.m_src) { QTreeWidgetItem* childItem = new QTreeWidgetItem; childItem->setText(0, src.pathOrUrl()); item->addChild(childItem); } } } treeWidget->insertTopLevelItems(0, items); treeWidget->headerItem()->setHidden(true); return treeWidget; } SourceToDestinationMap mapSourceToDestination(const Path::List& sourcePaths, const Path& destinationPath) { // For example you are moving the following items into /dest/ // * /tests/ // * /tests/abc.cpp // If you pass them as is, moveFilesAndFolders() will crash (see note: // "Do not attempt to move subitems along with their parents"). // Thus we filter out subitems from "Path::List filteredPaths". // // /tests/abc.cpp will be implicitly moved to /dest/tests/abc.cpp, for // that reason we add "/dest/tests/abc.cpp" into "result.finalPaths" as well as // "/dest/tests". // // "result.finalPaths" will be used to highlight destination items after // copy/move. Path::List sortedPaths = sourcePaths; std::sort(sortedPaths.begin(), sortedPaths.end()); SourceToDestinationMap result; for (const Path& path : sortedPaths) { - if (!result.filteredPaths.isEmpty() && result.filteredPaths.rbegin()->isParentOf(path)) { + if (!result.filteredPaths.isEmpty() && std::reverse_iterator(result.filteredPaths.constBegin())->isParentOf(path)) { // think: "/tests" - const Path& previousPath = *result.filteredPaths.rbegin(); + const Path& previousPath = *std::reverse_iterator(result.filteredPaths.constBegin()); // think: "/dest" + "/".relativePath("/tests/abc.cpp") = /dest/tests/abc.cpp result.finalPaths[previousPath].append(Path(destinationPath, previousPath.parent().relativePath(path))); } else { // think: "/tests" result.filteredPaths.append(path); // think: "/dest" + "tests" = "/dest/tests" result.finalPaths[path].append(Path(destinationPath, path.lastPathSegment())); } } return result; } struct ClassifiedPaths { // Items originating from projects open in this KDevelop session QHash> itemsPerProject; // Items that do not belong to known projects Path::List alienSrcPaths; }; static ClassifiedPaths classifyPaths(const Path::List& paths, KDevelop::ProjectModel* projectModel) { ClassifiedPaths result; for (const Path& path : paths) { QList items = projectModel->itemsForPath(IndexedString(path.path())); if (!items.empty()) { for (ProjectBaseItem* item : items) { IProject* project = item->project(); if (!result.itemsPerProject.contains(project)) { result.itemsPerProject[project] = QList(); } result.itemsPerProject[project].append(item); } } else { result.alienSrcPaths.append(path); } } return result; } QVector copyMoveItems(const Path::List& paths, ProjectBaseItem* destItem, const Operation operation) { KDevelop::ProjectModel* projectModel = KDevelop::ICore::self()->projectController()->projectModel(); const ClassifiedPaths cl = classifyPaths(paths, projectModel); QVector tasks; IProject* destProject = destItem->project(); IProjectFileManager* destProjectFileManager = destProject->projectFileManager(); ProjectFolderItem* destFolder = destItem->folder(); Path destPath = destFolder->path(); for (IProject* srcProject : cl.itemsPerProject.keys()) { const auto& itemsList = cl.itemsPerProject[srcProject]; Path::List pathsList; for (KDevelop::ProjectBaseItem* item : itemsList) { pathsList.append(item->path()); } if (srcProject == destProject) { if (operation == Operation::CUT) { // Move inside project const bool ok = destProjectFileManager->moveFilesAndFolders(itemsList, destFolder); tasks.append(TaskInfo::createMove(ok, pathsList, destPath)); } else { // Copy inside project const bool ok = destProjectFileManager->copyFilesAndFolders(pathsList, destFolder); tasks.append(TaskInfo::createCopy(ok, pathsList, destPath)); } } else { // Copy/move between projects: // 1. Copy and add into destination project; // 2. Remove from source project. const bool copy_ok = destProjectFileManager->copyFilesAndFolders(pathsList, destFolder); tasks.append(TaskInfo::createCopy(copy_ok, pathsList, destPath)); if (operation == Operation::CUT) { if (copy_ok) { IProjectFileManager* srcProjectFileManager = srcProject->projectFileManager(); const bool deletion_ok = srcProjectFileManager->removeFilesAndFolders(itemsList); tasks.append(TaskInfo::createDeletion(deletion_ok, pathsList, destPath)); } else { tasks.append(TaskInfo(TaskStatus::SKIPPED, TaskType::DELETION, pathsList, destPath)); } } } } // Copy/move items from outside of all open projects if (!cl.alienSrcPaths.isEmpty()) { const bool alien_copy_ok = destProjectFileManager->copyFilesAndFolders(cl.alienSrcPaths, destFolder); tasks.append(TaskInfo::createCopy(alien_copy_ok, cl.alienSrcPaths, destPath)); if (operation == Operation::CUT) { if (alien_copy_ok) { QList urlsToDelete; for (const Path& path : cl.alienSrcPaths) { urlsToDelete.append(path.toUrl()); } KIO::DeleteJob* deleteJob = KIO::del(urlsToDelete); const bool deletion_ok = deleteJob->exec(); tasks.append(TaskInfo::createDeletion(deletion_ok, cl.alienSrcPaths, destPath)); } else { tasks.append(TaskInfo(TaskStatus::SKIPPED, TaskType::DELETION, cl.alienSrcPaths, destPath)); } } } return tasks; } void showWarningDialogForFailedPaste(QWidget* parent, const QVector& tasks) { QDialog* dialog = new QDialog(parent); dialog->setWindowTitle(i18nc("@title:window", "Paste Failed")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Ok); QObject::connect(buttonBox, &QDialogButtonBox::clicked, dialog, &QDialog::accept); dialog->setWindowModality(Qt::WindowModal); dialog->setModal(true); QWidget* mainWidget = new QWidget(dialog); QVBoxLayout* mainLayout = new QVBoxLayout(mainWidget); const int spacingHint = mainWidget->style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); mainLayout->setSpacing(spacingHint * 2); // provide extra spacing mainLayout->setMargin(0); QHBoxLayout* hLayout = new QHBoxLayout; hLayout->setMargin(0); hLayout->setSpacing(-1); // use default spacing mainLayout->addLayout(hLayout, 0); QLabel* iconLabel = new QLabel(mainWidget); // Icon QStyleOption option; option.initFrom(mainWidget); QIcon icon = QIcon::fromTheme(QStringLiteral("dialog-warning")); iconLabel->setPixmap(icon.pixmap(mainWidget->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, mainWidget))); QVBoxLayout* iconLayout = new QVBoxLayout(); iconLayout->addStretch(1); iconLayout->addWidget(iconLabel); iconLayout->addStretch(5); hLayout->addLayout(iconLayout, 0); hLayout->addSpacing(spacingHint); const QString text = i18n("Failed to paste. Below is a list of suboperations that have been attempted."); QLabel* messageLabel = new QLabel(text, mainWidget); messageLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); hLayout->addWidget(messageLabel, 5); QWidget* statsWidget = createPasteStatsWidget(dialog, tasks); QVBoxLayout* topLayout = new QVBoxLayout; dialog->setLayout(topLayout); topLayout->addWidget(mainWidget); topLayout->addWidget(statsWidget, 1); topLayout->addWidget(buttonBox); dialog->setMinimumSize(300, qMax(150, qMax(iconLabel->sizeHint().height(), messageLabel->sizeHint().height()))); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); } } // namespace CutCopyPasteHelpers