diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index fff8f898095..dd7fd644847 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -1333,6 +1333,11 @@ void QmlJSTextEditorWidget::findUsages() m_findReferences->findUsages(file()->fileName(), textCursor().position()); } +void QmlJSTextEditorWidget::renameUsages() +{ + m_findReferences->renameUsages(file()->fileName(), textCursor().position()); +} + void QmlJSTextEditorWidget::showContextPane() { if (m_contextPane && m_semanticInfo.isValid()) { diff --git a/src/plugins/qmljseditor/qmljseditor.h b/src/plugins/qmljseditor/qmljseditor.h index eab40676167..09997b8d28e 100644 --- a/src/plugins/qmljseditor/qmljseditor.h +++ b/src/plugins/qmljseditor/qmljseditor.h @@ -168,6 +168,7 @@ public slots: void forceSemanticRehighlight(); void followSymbolUnderCursor(); void findUsages(); + void renameUsages(); void showContextPane(); virtual void setFontSettings(const TextEditor::FontSettings &); diff --git a/src/plugins/qmljseditor/qmljseditorconstants.h b/src/plugins/qmljseditor/qmljseditorconstants.h index 3acabb70b8e..4784b610336 100644 --- a/src/plugins/qmljseditor/qmljseditorconstants.h +++ b/src/plugins/qmljseditor/qmljseditorconstants.h @@ -52,6 +52,7 @@ const char * const TASK_SEARCH = "QmlJSEditor.TaskSearch"; const char * const FOLLOW_SYMBOL_UNDER_CURSOR = "QmlJSEditor.FollowSymbolUnderCursor"; const char * const FIND_USAGES = "QmlJSEditor.FindUsages"; +const char * const RENAME_USAGES = "QmlJSEditor.RenameUsages"; const char * const SHOW_QT_QUICK_HELPER = "QmlJSEditor.ShowQtQuickHelper"; const char * const QML_MIMETYPE = "application/x-qml"; diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp index 10164bae0a5..5d1315fc008 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.cpp +++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp @@ -180,6 +180,13 @@ bool QmlJSEditorPlugin::initialize(const QStringList & /*arguments*/, QString *e contextMenu->addAction(cmd); qmlToolsMenu->addAction(cmd); + QAction *renameUsagesAction = new QAction(tr("Rename Usages"), this); + cmd = am->registerAction(renameUsagesAction, Constants::RENAME_USAGES, context); + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+R"))); + connect(renameUsagesAction, SIGNAL(triggered()), this, SLOT(renameUsages())); + contextMenu->addAction(cmd); + qmlToolsMenu->addAction(cmd); + QAction *showQuickToolbar = new QAction(tr("Show Qt Quick Toolbar"), this); cmd = am->registerAction(showQuickToolbar, Constants::SHOW_QT_QUICK_HELPER, context); #ifdef Q_WS_MACX @@ -281,6 +288,13 @@ void QmlJSEditorPlugin::findUsages() editor->findUsages(); } +void QmlJSEditorPlugin::renameUsages() +{ + Core::EditorManager *em = Core::EditorManager::instance(); + if (QmlJSTextEditorWidget *editor = qobject_cast(em->currentEditor()->widget())) + editor->renameUsages(); +} + void QmlJSEditorPlugin::showContextPane() { Core::EditorManager *em = Core::EditorManager::instance(); diff --git a/src/plugins/qmljseditor/qmljseditorplugin.h b/src/plugins/qmljseditor/qmljseditorplugin.h index 18f43d2333b..91968d1f3f9 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.h +++ b/src/plugins/qmljseditor/qmljseditorplugin.h @@ -94,6 +94,7 @@ public: public Q_SLOTS: void followSymbolUnderCursor(); void findUsages(); + void renameUsages(); void showContextPane(); private Q_SLOTS: diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index e16577fd4df..436af01a5f7 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -795,7 +795,8 @@ static void find_helper(QFutureInterface &future, const ModelManagerInterface::WorkingCopy workingCopy, Snapshot snapshot, const QString fileName, - quint32 offset) + quint32 offset, + QString replacement) { // update snapshot from workingCopy to make sure it's up to date // ### remove? @@ -832,6 +833,8 @@ static void find_helper(QFutureInterface &future, const QString &name = findTarget.name(); if (name.isEmpty()) return; + if (!replacement.isNull() && replacement.isEmpty()) + replacement = name; QStringList files; foreach (const Document::Ptr &doc, snapshot) { @@ -841,12 +844,14 @@ static void find_helper(QFutureInterface &future, future.setProgressRange(0, files.size()); + // report a dummy usage to indicate the search is starting + FindReferences::Usage searchStarting(replacement, QString(), 0, 0, 0); + if (findTarget.typeKind() == findTarget.TypeKind){ const ObjectValue *typeValue = value_cast(findTarget.targetValue()); if (!typeValue) return; - // report a dummy usage to indicate the search is starting - future.reportResult(FindReferences::Usage()); + future.reportResult(searchStarting); SearchFileForType process(context, name, typeValue); UpdateUI reduce(&future); @@ -859,8 +864,7 @@ static void find_helper(QFutureInterface &future, scope->lookupMember(name, &context, &scope); if (!scope) return; - // report a dummy usage to indicate the search is starting - future.reportResult(FindReferences::Usage()); + future.reportResult(searchStarting); ProcessFile process(context, name, scope); UpdateUI reduce(&future); @@ -871,18 +875,30 @@ static void find_helper(QFutureInterface &future, } void FindReferences::findUsages(const QString &fileName, quint32 offset) -{ - findAll_helper(fileName, offset); -} - -void FindReferences::findAll_helper(const QString &fileName, quint32 offset) { ModelManagerInterface *modelManager = ModelManagerInterface::instance(); - QFuture result = QtConcurrent::run( &find_helper, modelManager->workingCopy(), - modelManager->snapshot(), fileName, offset); + modelManager->snapshot(), fileName, offset, + QString()); + m_watcher.setFuture(result); +} + +void FindReferences::renameUsages(const QString &fileName, quint32 offset, + const QString &replacement) +{ + ModelManagerInterface *modelManager = ModelManagerInterface::instance(); + + // an empty non-null string asks the future to use the current name as base + QString newName = replacement; + if (newName.isNull()) + newName = QLatin1String(""); + + QFuture result = QtConcurrent::run( + &find_helper, modelManager->workingCopy(), + modelManager->snapshot(), fileName, offset, + newName); m_watcher.setFuture(result); } @@ -890,7 +906,18 @@ void FindReferences::displayResults(int first, int last) { // the first usage is always a dummy to indicate we now start searching if (first == 0) { - Find::SearchResult *search = _resultWindow->startNewSearch(Find::SearchResultWindow::SearchOnly); + Usage dummy = m_watcher.future().resultAt(0); + QString replacement = dummy.path; + + Find::SearchResult *search; + if (replacement.isEmpty()) { + search = _resultWindow->startNewSearch(Find::SearchResultWindow::SearchOnly); + } else { + search = _resultWindow->startNewSearch(Find::SearchResultWindow::SearchAndReplace); + _resultWindow->setTextToReplace(replacement); + connect(search, SIGNAL(replaceButtonClicked(QString,QList)), + SLOT(onReplaceButtonClicked(QString,QList))); + } connect(search, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem))); _resultWindow->popup(true); @@ -930,3 +957,26 @@ void FindReferences::openEditor(const Find::SearchResultItem &item) Core::EditorManager::instance()->openEditor(item.text, QString(), Core::EditorManager::ModeSwitch); } } + +void FindReferences::onReplaceButtonClicked(const QString &text, const QList &items) +{ + const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(text, items); + + // files that are opened in an editor are changed, but not saved + QStringList changedOnDisk; + QStringList changedUnsavedEditors; + Core::EditorManager *editorManager = Core::EditorManager::instance(); + foreach (const QString &fileName, fileNames) { + if (editorManager->editorsForFileName(fileName).isEmpty()) + changedOnDisk += fileName; + else + changedUnsavedEditors += fileName; + } + + if (!changedOnDisk.isEmpty()) + QmlJS::ModelManagerInterface::instance()->updateSourceFiles(changedOnDisk, true); + if (!changedUnsavedEditors.isEmpty()) + QmlJS::ModelManagerInterface::instance()->updateSourceFiles(changedUnsavedEditors, false); + + _resultWindow->hide(); +} diff --git a/src/plugins/qmljseditor/qmljsfindreferences.h b/src/plugins/qmljseditor/qmljsfindreferences.h index 8ea7785c0e7..f16f6e013a2 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.h +++ b/src/plugins/qmljseditor/qmljsfindreferences.h @@ -81,14 +81,14 @@ Q_SIGNALS: public: void findUsages(const QString &fileName, quint32 offset); + void renameUsages(const QString &fileName, quint32 offset, + const QString &replacement = QString()); private Q_SLOTS: void displayResults(int first, int last); void searchFinished(); void openEditor(const Find::SearchResultItem &item); - -private: - void findAll_helper(const QString &fileName, quint32 offset); + void onReplaceButtonClicked(const QString &text, const QList &items); private: Find::SearchResultWindow *_resultWindow;