forked from qt-creator/qt-creator
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:
@@ -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
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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,15 +1048,11 @@ 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)
|
||||
{
|
||||
CMakeProjectManager::Internal::buildTarget(this, target);
|
||||
|
@@ -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 {
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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) }
|
||||
|
@@ -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;
|
||||
}
|
||||
emit instance()->filesRenamed(renamedFiles);
|
||||
return renamedFiles;
|
||||
|
||||
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;
|
||||
}
|
||||
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, ¬Renamed))
|
||||
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,
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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()
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
|
@@ -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"); }
|
||||
|
@@ -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)
|
||||
|
@@ -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"); }
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user