diff --git a/src/plugins/coreplugin/find/searchresultwidget.cpp b/src/plugins/coreplugin/find/searchresultwidget.cpp index 2aa443630d740934c1c7a534e6b41af93b46e20b..4020060757d6ea0decd0c579bc47198270dc1aff 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.cpp +++ b/src/plugins/coreplugin/find/searchresultwidget.cpp @@ -185,6 +185,8 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) : m_preserveCaseCheck = new QCheckBox(m_topReplaceWidget); m_preserveCaseCheck->setText(tr("Preser&ve case")); m_preserveCaseCheck->setEnabled(false); + m_renameFilesCheckBox = new QCheckBox(m_topReplaceWidget); + m_renameFilesCheckBox->setVisible(false); m_preserveCaseCheck->setChecked(Find::hasFindFlag(FindPreserveCase)); connect(m_preserveCaseCheck, &QAbstractButton::clicked, Find::instance(), &Find::setPreserveCase); @@ -201,6 +203,7 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) : topReplaceLayout->addWidget(m_replaceTextEdit); topReplaceLayout->addWidget(m_replaceButton); topReplaceLayout->addWidget(m_preserveCaseCheck); + topReplaceLayout->addWidget(m_renameFilesCheckBox); topReplaceLayout->addStretch(2); setShowReplaceUI(m_replaceSupported); setSupportPreserveCase(true); @@ -228,6 +231,11 @@ void SearchResultWidget::setInfo(const QString &label, const QString &toolTip, c m_searchTerm->setVisible(!term.isEmpty()); } +QWidget *SearchResultWidget::additionalReplaceWidget() const +{ + return m_renameFilesCheckBox; +} + void SearchResultWidget::addResult(const QString &fileName, const QString &rowText, Search::TextRange mainRange, diff --git a/src/plugins/coreplugin/find/searchresultwidget.h b/src/plugins/coreplugin/find/searchresultwidget.h index 8fdda24e6da16365df10f081911b1bc6da06be3b..5c5e3374a6f83123c0932260dd4577d54a3f9725 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.h +++ b/src/plugins/coreplugin/find/searchresultwidget.h @@ -53,6 +53,7 @@ public: ~SearchResultWidget(); void setInfo(const QString &label, const QString &toolTip, const QString &term); + QWidget *additionalReplaceWidget() const; void addResult(const QString &fileName, const QString &lineText, @@ -130,6 +131,7 @@ private: QToolButton *m_replaceButton; QToolButton *m_searchAgainButton; QCheckBox *m_preserveCaseCheck; + QCheckBox *m_renameFilesCheckBox = nullptr; QWidget *m_descriptionContainer; QLabel *m_label; QLabel *m_searchTerm; diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index 08fbace9812c8aac159339584a258160c856833b..ce3d0e2a086b3d531a821e54840685f836150231 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -643,6 +643,11 @@ void SearchResult::setSearchAgainSupported(bool supported) m_widget->setSearchAgainSupported(supported); } +QWidget *SearchResult::additionalReplaceWidget() const +{ + return m_widget->additionalReplaceWidget(); +} + /*! Adds a single result line to the \gui {Search Results} output pane. diff --git a/src/plugins/coreplugin/find/searchresultwindow.h b/src/plugins/coreplugin/find/searchresultwindow.h index d9a15ab06eed783d8712b8baee2900a2997b9ed7..f62c2163110ac414ba041c0fc3dbdb04e51019ed 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.h +++ b/src/plugins/coreplugin/find/searchresultwindow.h @@ -61,6 +61,7 @@ public: QString textToReplace() const; int count() const; void setSearchAgainSupported(bool supported); + QWidget *additionalReplaceWidget() const; public slots: void addResult(const QString &fileName, diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp index de598e3d6197e78e3647131bb0c8828868e38215..5426664483c67011b0e0f9cb58d7f7af800e48dc 100644 --- a/src/plugins/cpptools/cppfindreferences.cpp +++ b/src/plugins/cpptools/cppfindreferences.cpp @@ -33,6 +33,9 @@ #include #include #include +#include +#include +#include #include #include @@ -42,6 +45,7 @@ #include #include +#include #include #include @@ -50,6 +54,7 @@ using namespace Core; using namespace CppTools::Internal; using namespace CppTools; using namespace CPlusPlus; +using namespace ProjectExplorer; static QByteArray getSource(const Utils::FileName &fileName, const WorkingCopy &workingCopy) @@ -336,6 +341,12 @@ void CppFindReferences::findUsages(Symbol *symbol, CppFindReferencesParameters parameters; parameters.symbolId = fullIdForSymbol(symbol); parameters.symbolFileName = QByteArray(symbol->fileName()); + + if (symbol->isClass() || symbol->isForwardClassDeclaration()) { + Overview overview; + parameters.prettySymbolName = overview.prettyName(context.path(symbol).last()); + } + search->setUserData(qVariantFromValue(parameters)); findAll_helper(search, symbol, context); } @@ -382,12 +393,48 @@ void CppFindReferences::onReplaceButtonClicked(const QString &text, m_modelManager->updateSourceFiles(fileNames.toSet()); SearchResultWindow::instance()->hide(); } + + auto search = qobject_cast(sender()); + QTC_ASSERT(search, return); + + CppFindReferencesParameters parameters = search->userData().value(); + if (parameters.filesToRename.isEmpty()) + return; + + auto renameFilesCheckBox = qobject_cast(search->additionalReplaceWidget()); + if (!renameFilesCheckBox || !renameFilesCheckBox->isChecked()) + return; + + const QStringList newPaths = + Utils::transform(parameters.filesToRename, + [¶meters, text](const Node *node) -> QString { + const QFileInfo fi = node->filePath().toFileInfo(); + const QString fileName = fi.fileName(); + QString newName = fileName; + newName.replace(parameters.prettySymbolName, text, Qt::CaseInsensitive); + + if (newName != fileName) { + newName = Utils::matchCaseReplacement(fileName, newName); + + return fi.absolutePath() + "/" + newName; + } + + return QString(); + }); + + for (int i = 0; i < parameters.filesToRename.size(); ++i) { + if (!newPaths.at(i).isEmpty()) { + Node *node = parameters.filesToRename.at(i); + ProjectExplorerPlugin::renameFile(node, newPaths.at(i)); + } + } } void CppFindReferences::searchAgain() { SearchResult *search = qobject_cast(sender()); CppFindReferencesParameters parameters = search->userData().value(); + parameters.filesToRename.clear(); Snapshot snapshot = CppModelManager::instance()->snapshot(); search->restart(); LookupContext context; @@ -467,6 +514,8 @@ Symbol *CppFindReferences::findSymbol(const CppFindReferencesParameters ¶met static void displayResults(SearchResult *search, QFutureWatcher *watcher, int first, int last) { + CppFindReferencesParameters parameters = search->userData().value(); + for (int index = first; index != last; ++index) { Usage result = watcher->future().resultAt(index); search->addResult(result.path.toString(), @@ -474,7 +523,45 @@ static void displayResults(SearchResult *search, QFutureWatcher *watcher, result.lineText, result.col, result.len); + + if (parameters.prettySymbolName.isEmpty()) + continue; + + if (Utils::contains(parameters.filesToRename, Utils::equal(&Node::filePath, result.path))) + continue; + + Node *node = SessionManager::nodeForFile(result.path); + if (!node) // Not part of any project + continue; + + const QFileInfo fi = node->filePath().toFileInfo(); + if (fi.baseName().compare(parameters.prettySymbolName, Qt::CaseInsensitive) == 0) + parameters.filesToRename.append(node); } + + search->setUserData(qVariantFromValue(parameters)); +} + +static void searchFinished(SearchResult *search, QFutureWatcher *watcher) +{ + search->finishSearch(watcher->isCanceled()); + + CppFindReferencesParameters parameters = search->userData().value(); + if (!parameters.filesToRename.isEmpty()) { + const QStringList filesToRename + = Utils::transform(parameters.filesToRename, [](const Node *node) { + return node->filePath().toUserOutput(); + }); + + auto renameCheckBox = qobject_cast(search->additionalReplaceWidget()); + if (renameCheckBox) { + renameCheckBox->setText(CppFindReferences::tr("Re&name %1 files.").arg(filesToRename.size())); + renameCheckBox->setToolTip(CppFindReferences::tr("Files:\n%1").arg(filesToRename.join('\n'))); + renameCheckBox->setVisible(true); + } + } + + watcher->deleteLater(); } void CppFindReferences::openEditor(const SearchResultItem &item) @@ -651,7 +738,9 @@ void CppFindReferences::createWatcher(const QFuture &future, SearchResult { QFutureWatcher *watcher = new QFutureWatcher(); // auto-delete: - connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); + connect(watcher, &QFutureWatcherBase::finished, watcher, [search, watcher]() { + searchFinished(search, watcher); + }); connect(watcher, &QFutureWatcherBase::resultsReadyAt, search, [search, watcher](int first, int last) { diff --git a/src/plugins/cpptools/cppfindreferences.h b/src/plugins/cpptools/cppfindreferences.h index 5a2dfc4cc5284544fec3d55cfefcb696a633c24e..422eedb0c9edb068609463b5325669f9eda296f8 100644 --- a/src/plugins/cpptools/cppfindreferences.h +++ b/src/plugins/cpptools/cppfindreferences.h @@ -40,6 +40,10 @@ class SearchResultItem; class SearchResult; } // namespace Core +namespace ProjectExplorer { +class Node; +} + namespace CppTools { class CppModelManager; @@ -50,6 +54,8 @@ class CppFindReferencesParameters public: QList symbolId; QByteArray symbolFileName; + QString prettySymbolName; + QVector filesToRename; }; class CppFindReferences: public QObject diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index ce2a042bc9ddabe96f3a7bc0d8d5e3516cab260a..97a93fce60b97b5ee55182f135f08e46453b0953 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -180,6 +180,8 @@ public: static void setRefactoringEngine(RefactoringEngineInterface *refactoringEngine); static RefactoringEngineInterface *refactoringEngine(); + void renameIncludes(const QString &oldFileName, const QString &newFileName); + signals: /// Project data might be locked while this is emitted. void aboutToRemoveFiles(const QStringList &files); @@ -205,7 +207,6 @@ private: // This should be executed in the GUI thread. friend class Tests::ModelManagerTestHelper; void onAboutToLoadSession(); - void renameIncludes(const QString &oldFileName, const QString &newFileName); void onProjectAdded(ProjectExplorer::Project *project); void onAboutToRemoveProject(ProjectExplorer::Project *project); void onActiveProjectChanged(ProjectExplorer::Project *project);