ProjectExplorer: Let build systems do renamings in bulk

Like for the add and remove operations.

Change-Id: I734396b1b0f5a4ffb9cf193a0e32c8f7f60259ae
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Christian Kandeler
2024-09-11 17:04:01 +02:00
parent ff44f589f5
commit 05430afdcf
24 changed files with 410 additions and 244 deletions

View File

@@ -2558,4 +2558,14 @@ FilePath TemporaryFilePath::filePath() const
return d->filePath;
}
FilePaths firstPaths(const FilePairs &pairs)
{
return transform(pairs, &FilePair::first);
}
FilePaths secondPaths(const FilePairs &pairs)
{
return transform(pairs, &FilePair::second);
}
} // Utils

View File

@@ -17,6 +17,7 @@
#include <functional>
#include <memory>
#include <optional>
#include <utility>
#include <variant>
QT_BEGIN_NAMESPACE
@@ -53,7 +54,12 @@ public:
const QDirIterator::IteratorFlags iteratorFlags = QDirIterator::NoIteratorFlags;
};
using FilePaths = QList<class FilePath>;
class FilePath;
using FilePaths = QList<FilePath>;
using FilePair = std::pair<FilePath, FilePath>;
using FilePairs = QList<FilePair>;
QTCREATOR_UTILS_EXPORT FilePaths firstPaths(const FilePairs &pairs);
QTCREATOR_UTILS_EXPORT FilePaths secondPaths(const FilePairs &pairs);
class QTCREATOR_UTILS_EXPORT FilePathWatcher : public QObject
{

View File

@@ -962,16 +962,42 @@ bool CMakeBuildSystem::canRenameFile(Node *context,
return false;
}
bool CMakeBuildSystem::renameFile(Node *context,
const FilePath &oldFilePath,
const FilePath &newFilePath)
bool CMakeBuildSystem::renameFiles(Node *context, const FilePairs &filesToRename, FilePaths *notRenamed)
{
if (auto n = dynamic_cast<CMakeTargetNode *>(context)) {
const FilePath projDir = n->filePath().canonicalPath();
const auto n = dynamic_cast<CMakeTargetNode *>(context);
if (!n) {
if (notRenamed)
*notRenamed = firstPaths(filesToRename);
return false;
}
bool shouldRunCMake = false;
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
if (!renameFile(n, oldFilePath, newFilePath, shouldRunCMake)) {
success = false;
if (notRenamed)
*notRenamed << oldFilePath;
}
}
if (shouldRunCMake && settings(project()).autorunCMake())
runCMake();
return success;
}
bool CMakeBuildSystem::renameFile(
CMakeTargetNode *context,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath,
bool &shouldRunCMake)
{
const FilePath projDir = context->filePath().canonicalPath();
const FilePath newRelPath = newFilePath.canonicalPath().relativePathFrom(projDir).cleanPath();
const QString newRelPathName = newRelPath.toString();
const QString targetName = n->buildKey();
const QString targetName = context->buildKey();
const QString key
= QStringList{projDir.path(), targetName, oldFilePath.path(), newFilePath.path()}.join(
";");
@@ -1008,7 +1034,6 @@ bool CMakeBuildSystem::renameFile(Node *context,
editor->setCursorPosition(editor->position() + 1);
editor->replace(fileToRename->relativeFileName.length(), newRelPathName);
editor->editorWidget()->autoIndent();
if (!Core::DocumentManager::saveDocument(editor->document())) {
qCCritical(cmakeBuildSystemLog).noquote()
@@ -1023,13 +1048,9 @@ bool CMakeBuildSystem::renameFile(Node *context,
fileToRename = projectFileArgumentPosition(targetName, fileToRename->relativeFileName);
} while (fileToRename && !fileToRename->fromGlobbing);
if (haveGlobbing && settings(project()).autorunCMake())
runCMake();
if (haveGlobbing)
shouldRunCMake = true;
return true;
}
return false;
}
void CMakeBuildSystem::buildNamedTarget(const QString &target)

View File

@@ -61,9 +61,9 @@ public:
bool canRenameFile(ProjectExplorer::Node *context,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath) final;
bool renameFile(ProjectExplorer::Node *context,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath) final;
bool renameFiles(ProjectExplorer::Node *context,
const Utils::FilePairs &filesToRename,
Utils::FilePaths *notRenamed) final;
void buildNamedTarget(const QString &target) final;
Utils::FilePaths filesGeneratedFrom(const Utils::FilePath &sourceFile) const final;
@@ -157,6 +157,9 @@ private:
Utils::FilePaths *);
bool addTsFiles(ProjectExplorer::Node *context, const Utils::FilePaths &filePaths,
Utils::FilePaths *);
bool renameFile(CMakeTargetNode *context,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath, bool &shouldRunCMake);
// Actually ask for parsing:
enum ReparseParameters {

View File

@@ -114,7 +114,10 @@ public:
}
RemovedFilesFromProject removeFiles(Node *, const FilePaths &filePaths, FilePaths *) final;
bool renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath) final;
bool renameFiles(
Node *,
const Utils::FilePairs &filesToRename,
Utils::FilePaths *notRenamed) final;
bool addFiles(Node *, const FilePaths &filePaths, FilePaths *) final;
QString name() const final { return QLatin1String("generic"); }
@@ -376,21 +379,42 @@ bool GenericBuildSystem::setFiles(const QStringList &filePaths)
return saveRawFileList(newList);
}
bool GenericBuildSystem::renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath)
bool GenericBuildSystem::renameFiles(Node *, const FilePairs &filesToRename, FilePaths *notRenamed)
{
QStringList newList = m_rawFileList;
QHash<QString, QString>::iterator i = m_rawListEntries.find(oldFilePath.toString());
if (i != m_rawListEntries.end()) {
int index = newList.indexOf(i.value());
if (index != -1) {
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
const auto fail = [&] {
success = false;
if (notRenamed)
*notRenamed << oldFilePath;
};
const auto i = m_rawListEntries.find(oldFilePath.toString());
if (i == m_rawListEntries.end()) {
fail();
continue;
}
const int index = newList.indexOf(i.value());
if (index == -1) {
fail();
continue;
}
QDir baseDir(projectDirectory().toString());
newList.removeAt(index);
insertSorted(&newList, baseDir.relativeFilePath(newFilePath.toString()));
}
if (!saveRawFileList(newList)) {
success = false;
if (notRenamed)
*notRenamed = firstPaths(filesToRename);
}
return saveRawFileList(newList);
return success;
}
static QStringList readFlags(const QString &filePath)

View File

@@ -234,9 +234,17 @@ bool NimbleBuildSystem::deleteFiles(Node *, const FilePaths &)
return true;
}
bool NimbleBuildSystem::renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath)
bool NimbleBuildSystem::renameFiles(Node *, const FilePairs &filesToRename, FilePaths *notRenamed)
{
return m_projectScanner.renameFile(oldFilePath.toString(), newFilePath.toString());
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
if (!m_projectScanner.renameFile(oldFilePath.toString(), newFilePath.toString())) {
success = false;
if (notRenamed)
*notRenamed << oldFilePath;
}
}
return success;
}
} // Nim

View File

@@ -58,8 +58,10 @@ private:
const Utils::FilePaths &filePaths,
Utils::FilePaths *) override;
bool deleteFiles(ProjectExplorer::Node *, const Utils::FilePaths &) override;
bool renameFile(ProjectExplorer::Node *,
const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) override;
bool renameFiles(
ProjectExplorer::Node *,
const Utils::FilePairs &filesToRename,
Utils::FilePaths *notRenamed) override;
QString name() const final { return QLatin1String("mimble"); }
void triggerParsing() final;

View File

@@ -152,7 +152,10 @@ public:
const FilePaths &filePaths,
FilePaths *) final;
bool deleteFiles(Node *, const FilePaths &) final;
bool renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath) final;
bool renameFiles(
Node *,
const Utils::FilePairs &filesToRename,
Utils::FilePaths *notRenamed) final;
QString name() const final { return QLatin1String("nim"); }
void triggerParsing() final;
@@ -237,9 +240,17 @@ bool NimBuildSystem::deleteFiles(Node *, const FilePaths &)
return true;
}
bool NimBuildSystem::renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath)
bool NimBuildSystem::renameFiles(Node *, const FilePairs &filesToRename, FilePaths *notRenamed)
{
return m_projectScanner.renameFile(oldFilePath.toString(), newFilePath.toString());
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
if (!m_projectScanner.renameFile(oldFilePath.toString(), newFilePath.toString())) {
success = false;
if (notRenamed)
*notRenamed << oldFilePath;
}
}
return success;
}
BuildSystem *createNimBuildSystem(Target *target)

View File

@@ -224,10 +224,10 @@ bool BuildSystem::canRenameFile(Node *, const FilePath &oldFilePath, const FileP
return true;
}
bool BuildSystem::renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath)
bool BuildSystem::renameFiles(Node *, const FilePairs &filesToRename, FilePaths *notRenamed)
{
Q_UNUSED(oldFilePath)
Q_UNUSED(newFilePath)
if (notRenamed)
*notRenamed = firstPaths(filesToRename);
return false;
}

View File

@@ -77,9 +77,8 @@ public:
virtual bool canRenameFile(Node *context,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath);
virtual bool renameFile(Node *context,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath);
virtual bool renameFiles(
Node *context, const Utils::FilePairs &filesToRename, Utils::FilePaths *notRenamed);
virtual bool addDependencies(Node *context, const QStringList &dependencies);
virtual bool supportsAction(Node *context, ProjectAction action, const Node *node) const;
virtual void buildNamedTarget(const QString &target) { Q_UNUSED(target) }

View File

@@ -2478,16 +2478,88 @@ void ProjectExplorerPlugin::showOutputPaneForRunControl(RunControl *runControl)
appOutputPane().showOutputPaneForRunControl(runControl);
}
QList<std::pair<FilePath, FilePath>> ProjectExplorerPlugin::renameFiles(
const QList<std::pair<Node *, Utils::FilePath>> &nodesAndNewFilePaths)
static HandleIncludeGuards canTryToRenameIncludeGuards(const Node *node)
{
QList<std::pair<FilePath, FilePath>> renamedFiles;
for (const auto &[node, newFilePath] : nodesAndNewFilePaths) {
if (const auto res = renameFile(node, newFilePath.toString()))
renamedFiles << *res;
return node->asFileNode() && node->asFileNode()->fileType() == FileType::Header
? HandleIncludeGuards::Yes : HandleIncludeGuards::No;
}
FilePairs ProjectExplorerPlugin::renameFiles(
const QList<std::pair<Node *, FilePath>> &nodesAndNewFilePaths)
{
const QList<std::pair<Node *, FilePath>> nodesAndNewFilePathsFiltered
= Utils::filtered(nodesAndNewFilePaths, [](const std::pair<Node *, FilePath> &elem) {
return !elem.first->filePath().equalsCaseSensitive(elem.second);
});
FilePaths renamedOnly;
FilePaths failedRenamings;
const auto renameFile = [&failedRenamings](const Node *node, const FilePath &newFilePath) {
if (!Core::FileUtils::renameFile(
node->filePath(), newFilePath, canTryToRenameIncludeGuards(node))) {
failedRenamings << node->filePath();
return false;
}
emit instance()->filesRenamed(renamedFiles);
return renamedFiles;
return true;
};
QHash<FolderNode *, QList<std::pair<Node *, FilePath>>> renamingsPerParentNode;
for (const auto &elem : nodesAndNewFilePathsFiltered) {
if (FolderNode * const folderNode = elem.first->parentFolderNode())
renamingsPerParentNode[folderNode] << elem;
else if (renameFile(elem.first, elem.second))
renamedOnly << elem.first->filePath();
}
for (auto it = renamingsPerParentNode.cbegin(); it != renamingsPerParentNode.cend(); ++it) {
FilePairs toUpdateInProject;
for (const std::pair<Node *, FilePath> &elem : it.value()) {
const bool canUpdateProject
= it.key()->canRenameFile(elem.first->filePath(), elem.second);
if (renameFile(elem.first, elem.second)) {
if (canUpdateProject )
toUpdateInProject << std::make_pair(elem.first->filePath(), elem.second);
else
renamedOnly << elem.first->filePath();
}
}
if (toUpdateInProject.isEmpty())
continue;
FilePaths notRenamed;
if (!it.key()->renameFiles(toUpdateInProject, &notRenamed))
renamedOnly << notRenamed;
}
if (!failedRenamings.isEmpty() || !renamedOnly.isEmpty()) {
const auto pathsAsHtmlList = [](const FilePaths &files) {
QString s("<ul>");
for (const FilePath &f : files)
s.append("<li>").append(f.toUserOutput()).append("</li>");
return s.append("</ul>");
};
QString failedRenamingsString;
if (!failedRenamings.isEmpty()) {
failedRenamingsString = Tr::tr("The following files could not be renamed: %1")
.arg(pathsAsHtmlList(failedRenamings));
}
QString renamedOnlyString;
if (!renamedOnly.isEmpty()) {
renamedOnlyString = Tr::tr(
"<br>The following files were renamed, but their project files could not "
"be updated accordingly: %1")
.arg(pathsAsHtmlList(renamedOnly));
}
QTimer::singleShot(0, m_instance, [message = failedRenamingsString + renamedOnlyString] {
QMessageBox::warning(
ICore::dialogParent(), Tr::tr("Renaming Did Not Fully Succeed"), message);
});
}
FilePairs allRenamedFiles;
for (const std::pair<Node *, FilePath> &candidate : nodesAndNewFilePathsFiltered) {
if (!failedRenamings.contains(candidate.first->filePath()))
allRenamedFiles.emplaceBack(candidate.first->filePath(), candidate.second);
}
emit instance()->filesRenamed(allRenamedFiles);
return allRenamedFiles;
}
#ifdef WITH_TESTS
@@ -2761,7 +2833,7 @@ void ProjectExplorerPluginPrivate::extendFolderNavigationWidgetFactory()
const QVector<FolderNode *> folderNodes = renamableFolderNodes(before, after);
QVector<FolderNode *> failedNodes;
for (FolderNode *folder : folderNodes) {
if (!folder->renameFile(before, after))
if (!folder->renameFiles({std::make_pair(before, after)}, nullptr))
failedNodes.append(folder);
}
if (!failedNodes.isEmpty()) {
@@ -3859,12 +3931,6 @@ void ProjectExplorerPluginPrivate::removeFile()
Core::FileUtils::removeFiles(pathList, deleteFile);
}
static HandleIncludeGuards canTryToRenameIncludeGuards(const Node *node)
{
return node->asFileNode() && node->asFileNode()->fileType() == FileType::Header
? HandleIncludeGuards::Yes : HandleIncludeGuards::No;
}
void ProjectExplorerPluginPrivate::duplicateFile()
{
Node *currentNode = ProjectTree::currentNode();
@@ -3959,67 +4025,6 @@ void ProjectExplorerPluginPrivate::handleRenameFile()
}
}
std::optional<std::pair<FilePath, FilePath>>
ProjectExplorerPlugin::renameFile(Node *node, const QString &newFileName)
{
const FilePath oldFilePath = node->filePath().absoluteFilePath();
FolderNode *folderNode = node->parentFolderNode();
QTC_ASSERT(folderNode, return {});
const QString projectFileName = folderNode->managingProject()->filePath().fileName();
const FilePath newFilePath = FilePath::fromString(newFileName);
if (oldFilePath.equalsCaseSensitive(newFilePath))
return {};
const HandleIncludeGuards handleGuards = canTryToRenameIncludeGuards(node);
if (!folderNode->canRenameFile(oldFilePath, newFilePath)) {
QTimer::singleShot(0, m_instance,
[oldFilePath, newFilePath, projectFileName, handleGuards] {
int res = QMessageBox::question(ICore::dialogParent(),
Tr::tr("Project Editing Failed"),
Tr::tr("The project file %1 cannot be automatically changed.\n\n"
"Rename %2 to %3 anyway?")
.arg(projectFileName)
.arg(oldFilePath.toUserOutput())
.arg(newFilePath.toUserOutput()));
if (res == QMessageBox::Yes) {
QTC_CHECK(Core::FileUtils::renameFile(oldFilePath, newFilePath, handleGuards));
}
});
return {};
}
if (Core::FileUtils::renameFile(oldFilePath, newFilePath, handleGuards)) {
// Tell the project plugin about rename
// TODO: We might want to separate this into an extra step to make bulk renamings safer;
// see CppModelManager::renameIncludes().
if (!folderNode->renameFile(oldFilePath, newFilePath)) {
const QString renameFileError = Tr::tr("The file %1 was renamed to %2, but the project "
"file %3 could not be automatically changed.")
.arg(oldFilePath.toUserOutput())
.arg(newFilePath.toUserOutput())
.arg(projectFileName);
QTimer::singleShot(0, m_instance, [renameFileError] {
QMessageBox::warning(ICore::dialogParent(),
Tr::tr("Project Editing Failed"),
renameFileError);
});
}
return std::make_pair(oldFilePath, newFilePath);
}
const QString renameFileError = Tr::tr("The file %1 could not be renamed %2.")
.arg(oldFilePath.toUserOutput())
.arg(newFilePath.toUserOutput());
QTimer::singleShot(0, m_instance, [renameFileError] {
QMessageBox::warning(ICore::dialogParent(), Tr::tr("Cannot Rename File"), renameFileError);
});
return {};
}
void ProjectExplorerPluginPrivate::handleSetStartupProject()
{
setStartupProject(ProjectTree::currentProject());
@@ -4133,7 +4138,7 @@ void ProjectExplorerPlugin::renameFilesForSymbol(const QString &oldSymbolName,
const QString &newSymbolName, const FilePaths &files, bool preferLowerCaseFileNames)
{
static const auto isAllLowerCase = [](const QString &text) { return text.toLower() == text; };
QList<std::pair<FilePath, FilePath>> renamedFiles;
QList<std::pair<Node *, FilePath>> filesToRename;
for (const FilePath &file : files) {
Node * const node = ProjectTree::nodeForFile(file);
if (!node)
@@ -4164,10 +4169,9 @@ void ProjectExplorerPlugin::renameFilesForSymbol(const QString &oldSymbolName,
const QString newFilePath = file.absolutePath().toString() + '/' + newBaseName + '.'
+ file.completeSuffix();
if (const auto res = renameFile(node, newFilePath))
renamedFiles << *res;
filesToRename.emplaceBack(node, FilePath::fromString(newFilePath));
}
emit instance()->filesRenamed(renamedFiles);
renameFiles(filesToRename);
}
void ProjectManager::registerProjectCreator(const QString &mimeType,

View File

@@ -123,8 +123,8 @@ public:
static void startRunControl(RunControl *runControl);
static void showOutputPaneForRunControl(RunControl *runControl);
static QList<std::pair<Utils::FilePath, Utils::FilePath>>
renameFiles(const QList<std::pair<Node *, Utils::FilePath>> &nodesAndNewFilePaths);
static Utils::FilePairs renameFiles(
const QList<std::pair<Node *, Utils::FilePath>> &nodesAndNewFilePaths);
#ifdef WITH_TESTS
static bool renameFile(const Utils::FilePath &source, const Utils::FilePath &target,
@@ -182,13 +182,11 @@ signals:
void runControlStarted(ProjectExplorer::RunControl *runControl);
void runControlStoped(ProjectExplorer::RunControl *runControl);
void filesRenamed(const QList<std::pair<Utils::FilePath, Utils::FilePath>> &oldAndNewPaths);
void filesRenamed(const Utils::FilePairs &oldAndNewPaths);
private:
static bool coreAboutToClose();
void handleCommandLineArguments(const QStringList &arguments);
static std::optional<std::pair<Utils::FilePath, Utils::FilePath>>
renameFile(Node *node, const QString &newFilePath);
};
} // namespace ProjectExplorer

View File

@@ -837,11 +837,11 @@ bool FolderNode::canRenameFile(const FilePath &oldFilePath, const FilePath &newF
return false;
}
bool FolderNode::renameFile(const FilePath &oldFilePath, const FilePath &newFilePath)
bool FolderNode::renameFiles(const FilePairs &filesToRename, FilePaths *notRenamed)
{
ProjectNode *pn = managingProject();
if (pn)
return pn->renameFile(oldFilePath, newFilePath);
return pn->renameFiles(filesToRename, notRenamed);
return false;
}
@@ -970,17 +970,20 @@ bool ProjectNode::deleteFiles(const FilePaths &filePaths)
return false;
}
bool ProjectNode::canRenameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath)
bool ProjectNode::canRenameFile(
const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath)
{
if (BuildSystem *bs = buildSystem())
if (BuildSystem * const bs = buildSystem())
return bs->canRenameFile(this, oldFilePath, newFilePath);
return true;
return false;
}
bool ProjectNode::renameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath)
bool ProjectNode::renameFiles(const FilePairs &filesToRename, FilePaths *notRenamed)
{
if (BuildSystem *bs = buildSystem())
return bs->renameFile(this, oldFilePath, newFilePath);
return bs->renameFiles(this, filesToRename, notRenamed);
if (notRenamed)
*notRenamed = firstPaths(filesToRename);
return false;
}

View File

@@ -13,6 +13,7 @@
#include <functional>
#include <optional>
#include <utility>
#include <variant>
namespace Utils { class MimeType; }
@@ -300,7 +301,7 @@ public:
virtual bool deleteFiles(const Utils::FilePaths &filePaths);
virtual bool canRenameFile(const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath);
virtual bool renameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath);
virtual bool renameFiles(const Utils::FilePairs &filesToRename, Utils::FilePaths *notRenamed);
virtual bool addDependencies(const QStringList &dependencies);
class AddNewInformation
@@ -382,8 +383,9 @@ public:
RemovedFilesFromProject removeFiles(const Utils::FilePaths &filePaths,
Utils::FilePaths *notRemoved = nullptr) final;
bool deleteFiles(const Utils::FilePaths &filePaths) final;
bool canRenameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) final;
bool renameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) final;
bool canRenameFile(
const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) override;
bool renameFiles(const Utils::FilePairs &filesToRename, Utils::FilePaths *notRenamed) final;
bool addDependencies(const QStringList &dependencies) final;
bool supportsAction(ProjectAction action, const Node *node) const final;

View File

@@ -305,17 +305,33 @@ bool PythonBuildSystem::deleteFiles(Node *, const FilePaths &)
return true;
}
bool PythonBuildSystem::renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath)
bool PythonBuildSystem::renameFiles(Node *, const FilePairs &filesToRename, FilePaths *notRenamed)
{
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
bool found = false;
for (FileEntry &entry : m_files) {
if (entry.filePath == oldFilePath) {
found = true;
entry.filePath = newFilePath;
entry.rawEntry = newFilePath.relativeChildPath(projectDirectory()).toString();
break;
}
}
if (!found) {
success = false;
if (notRenamed)
*notRenamed << oldFilePath;
}
}
return save();
if (!save()) {
if (notRenamed)
*notRenamed = firstPaths(filesToRename);
return false;
}
return success;
}
void PythonBuildSystem::parse()

View File

@@ -25,9 +25,10 @@ public:
const Utils::FilePaths &filePaths,
Utils::FilePaths *) override;
bool deleteFiles(ProjectExplorer::Node *, const Utils::FilePaths &) override;
bool renameFile(ProjectExplorer::Node *,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath) override;
bool renameFiles(
ProjectExplorer::Node *,
const Utils::FilePairs &filesToRename,
Utils::FilePaths *notRenamed) override;
QString name() const override { return QLatin1String("python"); }
void parse();

View File

@@ -267,27 +267,43 @@ RemovedFilesFromProject QbsBuildSystem::removeFiles(Node *context, const FilePat
return BuildSystem::removeFiles(context, filePaths, notRemoved);
}
bool QbsBuildSystem::renameFile(Node *context,
const FilePath &oldFilePath,
const FilePath &newFilePath)
bool QbsBuildSystem::renameFiles(Node *context, const FilePairs &filesToRename, FilePaths *notRenamed)
{
if (auto *n = dynamic_cast<QbsGroupNode *>(context)) {
const QbsProductNode * const prdNode = parentQbsProductNode(n);
QTC_ASSERT(prdNode, return false);
return renameFileInProduct(oldFilePath.toString(),
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
if (!renameFileInProduct(
oldFilePath.toString(),
newFilePath.toString(),
prdNode->productData(),
n->groupData());
n->groupData())) {
success = false;
if (notRenamed)
*notRenamed << oldFilePath;
}
}
return success;
}
if (auto *n = dynamic_cast<QbsProductNode *>(context)) {
return renameFileInProduct(oldFilePath.toString(),
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
if (!renameFileInProduct(
oldFilePath.toString(),
newFilePath.toString(),
n->productData(),
n->mainGroup());
n->mainGroup())) {
success = false;
if (notRenamed)
*notRenamed << oldFilePath;
}
}
return success;
}
return BuildSystem::renameFile(context, oldFilePath, newFilePath);
return BuildSystem::renameFiles(context, filesToRename, notRenamed);
}
QVariant QbsBuildSystem::additionalData(Id id) const
@@ -409,6 +425,7 @@ bool QbsBuildSystem::renameFileInProduct(
if (newPath.isEmpty())
return false;
FilePaths dummy;
// FIXME: The qbs API need a (bulk) renaming feature
if (removeFilesFromProduct({FilePath::fromString(oldPath)}, product, group, &dummy)
!= RemovedFilesFromProject::Ok) {
return false;

View File

@@ -67,8 +67,10 @@ public:
ProjectExplorer::RemovedFilesFromProject removeFiles(ProjectExplorer::Node *context,
const Utils::FilePaths &filePaths,
Utils::FilePaths *notRemoved = nullptr) final;
bool renameFile(ProjectExplorer::Node *context,
const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) final;
bool renameFiles(
ProjectExplorer::Node *context,
const Utils::FilePairs &filesToRename,
Utils::FilePaths *notRenamed) final;
Utils::FilePaths filesGeneratedFrom(const Utils::FilePath &sourceFile) const final;
QVariant additionalData(Utils::Id id) const final;
QString name() const final { return QLatin1String("qbs"); }

View File

@@ -254,16 +254,27 @@ bool QmakeBuildSystem::canRenameFile(Node *context,
return BuildSystem::canRenameFile(context, oldFilePath, newFilePath);
}
bool QmakeBuildSystem::renameFile(Node *context,
const FilePath &oldFilePath,
const FilePath &newFilePath)
bool QmakeBuildSystem::renameFiles(Node *context, const FilePairs &filesToRename, FilePaths *notRenamed)
{
if (auto n = dynamic_cast<QmakePriFileNode *>(context)) {
QmakePriFile *pri = n->priFile();
return pri ? pri->renameFile(oldFilePath, newFilePath) : false;
if (!pri) {
if (notRenamed)
*notRenamed = firstPaths(filesToRename);
return false;
}
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
if (!pri->renameFile(oldFilePath, newFilePath)) {
success = false;
if (notRenamed)
*notRenamed << oldFilePath;
}
}
return success;
}
return BuildSystem::renameFile(context, oldFilePath, newFilePath);
return BuildSystem::renameFiles(context, filesToRename, notRenamed);
}
bool QmakeBuildSystem::addDependencies(Node *context, const QStringList &dependencies)

View File

@@ -79,9 +79,9 @@ public:
bool canRenameFile(ProjectExplorer::Node *context,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath) override;
bool renameFile(ProjectExplorer::Node *context,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath) override;
bool renameFiles(ProjectExplorer::Node *context,
const Utils::FilePairs &filesToRename,
Utils::FilePaths *notRenamed) override;
bool addDependencies(ProjectExplorer::Node *context,
const QStringList &dependencies) override;
QString name() const final { return QLatin1String("qmake"); }

View File

@@ -627,19 +627,35 @@ bool QmlBuildSystem::deleteFiles(Node *context, const Utils::FilePaths &filePath
return BuildSystem::deleteFiles(context, filePaths);
}
bool QmlBuildSystem::renameFile(Node *context,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath)
bool QmlBuildSystem::renameFiles(Node *context,
const Utils::FilePairs &filesToRename,
Utils::FilePaths *notRenamed)
{
if (dynamic_cast<Internal::QmlProjectNode *>(context)) {
if (oldFilePath.endsWith(mainFile()))
return setMainFileInProjectFile(newFilePath);
if (oldFilePath.endsWith(m_projectItem->mainUiFile()))
return setMainUiFileInProjectFile(newFilePath);
return true;
if (!dynamic_cast<Internal::QmlProjectNode *>(context))
return BuildSystem::renameFiles(context, filesToRename, notRenamed);
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
const auto fail = [&] {
success = false;
if (notRenamed)
*notRenamed << oldFilePath;
};
if (oldFilePath.endsWith(mainFile())) {
if (!setMainFileInProjectFile(newFilePath))
fail();
continue;
}
if (oldFilePath.endsWith(m_projectItem->mainUiFile())) {
if (!setMainUiFileInProjectFile(newFilePath))
fail();
continue;
}
return BuildSystem::renameFile(context, oldFilePath, newFilePath);
// Why is this not an error?
}
return success;
}
QString QmlBuildSystem::mainFile() const

View File

@@ -35,9 +35,9 @@ public:
const Utils::FilePaths &filePaths,
Utils::FilePaths *notAdded = nullptr) override;
bool deleteFiles(ProjectExplorer::Node *context, const Utils::FilePaths &filePaths) override;
bool renameFile(ProjectExplorer::Node *context,
const Utils::FilePath &oldFilePath,
const Utils::FilePath &newFilePath) override;
bool renameFiles(ProjectExplorer::Node *context,
const Utils::FilePairs &filesToRename,
Utils::FilePaths *notRenamed) override;
bool updateProjectFile();

View File

@@ -157,7 +157,7 @@ public:
RemovedFilesFromProject removeFiles(const Utils::FilePaths &filePaths,
Utils::FilePaths *notRemoved) final;
bool canRenameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) override;
bool renameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) final;
bool renameFiles(const FilePairs &filesToRename, FilePaths *notRenamed) final;
QString prefix() const { return m_prefix; }
ResourceTopLevelNode *resourceNode() const { return m_topLevelNode; }
@@ -211,9 +211,9 @@ bool SimpleResourceFolderNode::canRenameFile(const FilePath &oldFilePath,
return prefixNode()->canRenameFile(oldFilePath, newFilePath);
}
bool SimpleResourceFolderNode::renameFile(const FilePath &oldFilePath, const FilePath &newFilePath)
bool SimpleResourceFolderNode::renameFiles(const FilePairs &filesToRename, FilePaths *notRenamed)
{
return prefixNode()->renameFile(oldFilePath, newFilePath);
return prefixNode()->renameFiles(filesToRename, notRenamed);
}
} // Internal
@@ -531,7 +531,7 @@ bool ResourceFolderNode::canRenameFile(const FilePath &oldFilePath, const FilePa
return fileEntryExists;
}
bool ResourceFolderNode::renameFile(const FilePath &oldFilePath, const FilePath &newFilePath)
bool ResourceFolderNode::renameFiles(const FilePairs &filesToRename, FilePaths *notRenamed)
{
ResourceFile file(m_topLevelNode->filePath());
if (file.load() != IDocument::OpenResult::Success)
@@ -540,16 +540,27 @@ bool ResourceFolderNode::renameFile(const FilePath &oldFilePath, const FilePath
if (index == -1)
return false;
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
bool found = false;
for (int j = 0; j < file.fileCount(index); ++j) {
if (file.file(index, j) == oldFilePath.toString()) {
file.replaceFile(index, j, newFilePath.toString());
FileChangeBlocker changeGuard(m_topLevelNode->filePath());
file.save();
return true;
found = true;
break;
}
}
if (!found) {
success = false;
if (notRenamed)
*notRenamed << oldFilePath;
}
}
return false;
FileChangeBlocker changeGuard(m_topLevelNode->filePath());
file.save();
return success;
}
bool ResourceFolderNode::renamePrefix(const QString &prefix, const QString &lang)

View File

@@ -55,7 +55,8 @@ public:
ProjectExplorer::RemovedFilesFromProject removeFiles(const Utils::FilePaths &filePaths,
Utils::FilePaths *notRemoved) override;
bool canRenameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) override;
bool renameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) override;
bool renameFiles(
const Utils::FilePairs &filesToRename, Utils::FilePaths *notRenamed) override;
bool renamePrefix(const QString &prefix, const QString &lang);