From 96ef6c797b9ae8f87a0701b2e559d90c1b7b6141 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Wed, 2 Aug 2017 14:39:45 +0200 Subject: CppEditor: split CppEditor and CppEditorWidget Change-Id: Id3c815184f7f3bace0276e947f6b6f76e61ec6de Reviewed-by: Nikolai Kosjar --- src/plugins/cppeditor/cppeditor.cpp | 992 +----------------------------------- 1 file changed, 2 insertions(+), 990 deletions(-) (limited to 'src/plugins/cppeditor/cppeditor.cpp') diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 1c68cf5ab5..a2b622a2f9 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -24,81 +24,12 @@ ****************************************************************************/ #include "cppeditor.h" - #include "cppautocompleter.h" -#include "cppdocumentationcommenthelper.h" -#include "cppeditorconstants.h" -#include "cppeditordocument.h" -#include "cppeditorplugin.h" -#include "cppfollowsymbolundercursor.h" #include "cpphighlighter.h" -#include "cpplocalrenaming.h" -#include "cppminimizableinfobars.h" -#include "cpppreprocessordialog.h" -#include "cppquickfixassistant.h" -#include "cppuseselectionsupdater.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum { UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200 }; - -using namespace Core; -using namespace CPlusPlus; -using namespace CppTools; -using namespace TextEditor; namespace CppEditor { namespace Internal { @@ -108,931 +39,12 @@ CppEditor::CppEditor() addContext(ProjectExplorer::Constants::CXX_LANGUAGE_ID); } -void CppEditor::decorateEditor(TextEditorWidget *editor) +void CppEditor::decorateEditor(TextEditor::TextEditorWidget *editor) { editor->textDocument()->setSyntaxHighlighter(new CppHighlighter); editor->textDocument()->setIndenter(new CppTools::CppQtStyleIndenter); editor->setAutoCompleter(new CppAutoCompleter); } -class CppEditorWidgetPrivate -{ -public: - CppEditorWidgetPrivate(CppEditorWidget *q); - -public: - QPointer m_modelManager; - - CppEditorDocument *m_cppEditorDocument; - CppEditorOutline *m_cppEditorOutline; - - QTimer m_updateFunctionDeclDefLinkTimer; - - CppLocalRenaming m_localRenaming; - - SemanticInfo m_lastSemanticInfo; - - CppUseSelectionsUpdater m_useSelectionsUpdater; - - FunctionDeclDefLinkFinder *m_declDefLinkFinder; - QSharedPointer m_declDefLink; - - QScopedPointer m_followSymbolUnderCursor; - - QAction *m_parseContextAction = nullptr; - ParseContextWidget *m_parseContextWidget = nullptr; - QToolButton *m_preprocessorButton = nullptr; - MinimizableInfoBars::Actions m_showInfoBarActions; - - CppSelectionChanger m_cppSelectionChanger; -}; - -CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q) - : m_modelManager(CppModelManager::instance()) - , m_cppEditorDocument(qobject_cast(q->textDocument())) - , m_cppEditorOutline(new CppEditorOutline(q)) - , m_localRenaming(q) - , m_useSelectionsUpdater(q) - , m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q)) - , m_followSymbolUnderCursor(new FollowSymbolUnderCursor(q)) - , m_cppSelectionChanger() -{ -} - -CppEditorWidget::CppEditorWidget() - : d(new CppEditorWidgetPrivate(this)) -{ - qRegisterMetaType("CppTools::SemanticInfo"); -} - -void CppEditorWidget::finalizeInitialization() -{ - d->m_cppEditorDocument = qobject_cast(textDocument()); - - setLanguageSettingsId(CppTools::Constants::CPP_SETTINGS_ID); - - // function combo box sorting - connect(CppEditorPlugin::instance(), &CppEditorPlugin::outlineSortingChanged, - outline(), &CppEditorOutline::setSorted); - - connect(d->m_cppEditorDocument, &CppEditorDocument::codeWarningsUpdated, - this, &CppEditorWidget::onCodeWarningsUpdated); - connect(d->m_cppEditorDocument, &CppEditorDocument::ifdefedOutBlocksUpdated, - this, &CppEditorWidget::onIfdefedOutBlocksUpdated); - connect(d->m_cppEditorDocument, &CppEditorDocument::cppDocumentUpdated, - this, &CppEditorWidget::onCppDocumentUpdated); - connect(d->m_cppEditorDocument, &CppEditorDocument::semanticInfoUpdated, - this, [this](const CppTools::SemanticInfo &info) { updateSemanticInfo(info); }); - - connect(d->m_declDefLinkFinder, &FunctionDeclDefLinkFinder::foundLink, - this, &CppEditorWidget::onFunctionDeclDefLinkFound); - - connect(&d->m_useSelectionsUpdater, - &CppUseSelectionsUpdater::selectionsForVariableUnderCursorUpdated, - &d->m_localRenaming, - &CppLocalRenaming::updateSelectionsForVariableUnderCursor); - - connect(&d->m_useSelectionsUpdater, &CppUseSelectionsUpdater::finished, this, - [this] (SemanticInfo::LocalUseMap localUses) { - d->m_lastSemanticInfo.localUsesUpdated = true; - d->m_lastSemanticInfo.localUses = localUses; - }); - - connect(document(), &QTextDocument::contentsChange, - &d->m_localRenaming, &CppLocalRenaming::onContentsChangeOfEditorWidgetDocument); - connect(&d->m_localRenaming, &CppLocalRenaming::finished, [this] { - cppEditorDocument()->recalculateSemanticInfoDetached(); - }); - connect(&d->m_localRenaming, &CppLocalRenaming::processKeyPressNormally, - this, &CppEditorWidget::processKeyNormally); - connect(this, &QPlainTextEdit::cursorPositionChanged, - d->m_cppEditorOutline, &CppEditorOutline::updateIndex); - - connect(cppEditorDocument(), &CppEditorDocument::preprocessorSettingsChanged, this, - [this](bool customSettings) { - updateWidgetHighlighting(d->m_preprocessorButton, customSettings); - }); - - // set up function declaration - definition link - d->m_updateFunctionDeclDefLinkTimer.setSingleShot(true); - d->m_updateFunctionDeclDefLinkTimer.setInterval(UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL); - connect(&d->m_updateFunctionDeclDefLinkTimer, &QTimer::timeout, - this, &CppEditorWidget::updateFunctionDeclDefLinkNow); - connect(this, &QPlainTextEdit::cursorPositionChanged, this, &CppEditorWidget::updateFunctionDeclDefLink); - connect(this, &QPlainTextEdit::textChanged, this, &CppEditorWidget::updateFunctionDeclDefLink); - - // set up the use highlighitng - connect(this, &CppEditorWidget::cursorPositionChanged, this, [this]() { - if (!d->m_localRenaming.isActive()) - d->m_useSelectionsUpdater.scheduleUpdate(); - - // Notify selection expander about the changed cursor. - d->m_cppSelectionChanger.onCursorPositionChanged(textCursor()); - }); - - // Toolbar: Outline/Overview combo box - insertExtraToolBarWidget(TextEditorWidget::Left, d->m_cppEditorOutline->widget()); - - // Toolbar: Parse context - ParseContextModel &parseContextModel = cppEditorDocument()->parseContextModel(); - d->m_parseContextWidget = new ParseContextWidget(parseContextModel, this); - d->m_parseContextAction = insertExtraToolBarWidget(TextEditorWidget::Left, - d->m_parseContextWidget); - d->m_parseContextAction->setVisible(false); - connect(&parseContextModel, &ParseContextModel::updated, - this, [this](bool areMultipleAvailable) { - d->m_parseContextAction->setVisible(areMultipleAvailable); - }); - - // Toolbar: '#' Button - // TODO: Make "Additional Preprocessor Directives" also useful with Clang Code Model. - if (!d->m_modelManager->isClangCodeModelActive()) { - d->m_preprocessorButton = new QToolButton(this); - d->m_preprocessorButton->setText(QLatin1String("#")); - Command *cmd = ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG); - connect(cmd, &Command::keySequenceChanged, - this, &CppEditorWidget::updatePreprocessorButtonTooltip); - updatePreprocessorButtonTooltip(); - connect(d->m_preprocessorButton, &QAbstractButton::clicked, - this, &CppEditorWidget::showPreProcessorWidget); - - insertExtraToolBarWidget(TextEditorWidget::Left, d->m_preprocessorButton); - } - - // Toolbar: Actions to show minimized info bars - d->m_showInfoBarActions = MinimizableInfoBars::createShowInfoBarActions([this](QWidget *w) { - return this->insertExtraToolBarWidget(TextEditorWidget::Left, w); - }); - connect(&cppEditorDocument()->minimizableInfoBars(), &MinimizableInfoBars::showAction, - this, &CppEditorWidget::onShowInfoBarAction); -} - -void CppEditorWidget::finalizeInitializationAfterDuplication(TextEditorWidget *other) -{ - QTC_ASSERT(other, return); - CppEditorWidget *cppEditorWidget = qobject_cast(other); - QTC_ASSERT(cppEditorWidget, return); - - if (cppEditorWidget->isSemanticInfoValidExceptLocalUses()) - updateSemanticInfo(cppEditorWidget->semanticInfo()); - d->m_cppEditorOutline->update(); - const Id selectionKind = CodeWarningsSelection; - setExtraSelections(selectionKind, cppEditorWidget->extraSelections(selectionKind)); - - if (isWidgetHighlighted(cppEditorWidget->d->m_preprocessorButton)) - updateWidgetHighlighting(d->m_preprocessorButton, true); - - d->m_parseContextWidget->syncToModel(); - d->m_parseContextAction->setVisible( - d->m_cppEditorDocument->parseContextModel().areMultipleAvailable()); -} - -CppEditorWidget::~CppEditorWidget() -{ - // non-inline destructor, see section "Forward Declared Pointers" of QScopedPointer. -} - -CppEditorDocument *CppEditorWidget::cppEditorDocument() const -{ - return d->m_cppEditorDocument; -} - -CppEditorOutline *CppEditorWidget::outline() const -{ - return d->m_cppEditorOutline; -} - -void CppEditorWidget::paste() -{ - if (d->m_localRenaming.handlePaste()) - return; - - TextEditorWidget::paste(); -} - -void CppEditorWidget::cut() -{ - if (d->m_localRenaming.handleCut()) - return; - - TextEditorWidget::cut(); -} - -void CppEditorWidget::selectAll() -{ - if (d->m_localRenaming.handleSelectAll()) - return; - - TextEditorWidget::selectAll(); -} - -void CppEditorWidget::onCppDocumentUpdated() -{ - d->m_cppEditorOutline->update(); -} - -void CppEditorWidget::onCodeWarningsUpdated(unsigned revision, - const QList selections, - const TextEditor::RefactorMarkers &refactorMarkers) -{ - if (revision != documentRevision()) - return; - - setExtraSelections(TextEditorWidget::CodeWarningsSelection, selections); - setRefactorMarkers(refactorMarkersWithoutClangMarkers() + refactorMarkers); -} - -void CppEditorWidget::onIfdefedOutBlocksUpdated(unsigned revision, - const QList ifdefedOutBlocks) -{ - if (revision != documentRevision()) - return; - setIfdefedOutBlocks(ifdefedOutBlocks); -} - -void CppEditorWidget::onShowInfoBarAction(const Id &id, bool show) -{ - QAction *action = d->m_showInfoBarActions.value(id); - QTC_ASSERT(action, return); - action->setVisible(show); -} - -void CppEditorWidget::findUsages() -{ - if (!d->m_modelManager) - return; - - SemanticInfo info = d->m_lastSemanticInfo; - info.snapshot = CppModelManager::instance()->snapshot(); - info.snapshot.insert(info.doc); - - if (const Macro *macro = CppTools::findCanonicalMacro(textCursor(), info.doc)) { - d->m_modelManager->findMacroUsages(*macro); - } else { - CanonicalSymbol cs(info.doc, info.snapshot); - Symbol *canonicalSymbol = cs(textCursor()); - if (canonicalSymbol) - d->m_modelManager->findUsages(canonicalSymbol, cs.context()); - } -} - -void CppEditorWidget::renameUsages(const QString &replacement) -{ - if (!d->m_modelManager) - return; - - SemanticInfo info = d->m_lastSemanticInfo; - info.snapshot = CppModelManager::instance()->snapshot(); - info.snapshot.insert(info.doc); - - if (const Macro *macro = CppTools::findCanonicalMacro(textCursor(), info.doc)) { - d->m_modelManager->renameMacroUsages(*macro, replacement); - } else { - CanonicalSymbol cs(info.doc, info.snapshot); - if (Symbol *canonicalSymbol = cs(textCursor())) - if (canonicalSymbol->identifier() != 0) - d->m_modelManager->renameUsages(canonicalSymbol, cs.context(), replacement); - } -} - -bool CppEditorWidget::selectBlockUp() -{ - if (!behaviorSettings().m_smartSelectionChanging) - return TextEditorWidget::selectBlockUp(); - - QTextCursor cursor = textCursor(); - d->m_cppSelectionChanger.startChangeSelection(); - const bool changed = - d->m_cppSelectionChanger.changeSelection( - CppSelectionChanger::ExpandSelection, - cursor, - d->m_lastSemanticInfo.doc); - if (changed) - setTextCursor(cursor); - d->m_cppSelectionChanger.stopChangeSelection(); - - return changed; -} - -bool CppEditorWidget::selectBlockDown() -{ - if (!behaviorSettings().m_smartSelectionChanging) - return TextEditorWidget::selectBlockDown(); - - QTextCursor cursor = textCursor(); - d->m_cppSelectionChanger.startChangeSelection(); - const bool changed = - d->m_cppSelectionChanger.changeSelection( - CppSelectionChanger::ShrinkSelection, - cursor, - d->m_lastSemanticInfo.doc); - if (changed) - setTextCursor(cursor); - d->m_cppSelectionChanger.stopChangeSelection(); - - return changed; -} - -void CppEditorWidget::updateWidgetHighlighting(QWidget *widget, bool highlight) -{ - if (!widget) - return; - - widget->setProperty("highlightWidget", highlight); - widget->update(); -} - -bool CppEditorWidget::isWidgetHighlighted(QWidget *widget) -{ - return widget ? widget->property("highlightWidget").toBool() : false; -} - -void CppEditorWidget::renameSymbolUnderCursor() -{ - if (refactoringEngine()) - renameSymbolUnderCursorClang(); - else - renameSymbolUnderCursorBuiltin(); -} - -void CppEditorWidget::renameSymbolUnderCursorBuiltin() -{ - updateSemanticInfo(d->m_cppEditorDocument->recalculateSemanticInfo(), - /*updateUseSelectionSynchronously=*/ true); - - if (!d->m_localRenaming.start()) // Rename local symbol - renameUsages(); // Rename non-local symbol or macro -} - -namespace { - -QList fetchProjectParts(CppTools::CppModelManager *modelManager, - const Utils::FileName &filePath) -{ - QList projectParts = modelManager->projectPart(filePath); - - if (projectParts.isEmpty()) - projectParts = modelManager->projectPartFromDependencies(filePath); - if (projectParts.isEmpty()) - projectParts.append(modelManager->fallbackProjectPart()); - - return projectParts; -} - -ProjectPart *findProjectPartForCurrentProject(const QList &projectParts, - ProjectExplorer::Project *currentProject) -{ - auto found = std::find_if(projectParts.cbegin(), - projectParts.cend(), - [&] (const CppTools::ProjectPart::Ptr &projectPart) { - return projectPart->project == currentProject; - }); - - if (found != projectParts.cend()) - return (*found).data(); - - return 0; -} - -} - -ProjectPart *CppEditorWidget::projectPart() const -{ - if (!d->m_modelManager) - return 0; - - auto projectParts = fetchProjectParts(d->m_modelManager, textDocument()->filePath()); - - return findProjectPartForCurrentProject(projectParts, - ProjectExplorer::ProjectTree::currentProject()); -} - -namespace { - -using ClangBackEnd::V2::SourceLocationContainer; -using TextEditor::Convenience::selectAt; - -QTextCharFormat occurrencesTextCharFormat() -{ - using TextEditor::TextEditorSettings; - - return TextEditorSettings::fontSettings().toTextCharFormat(TextEditor::C_OCCURRENCES); -} - -QList -sourceLocationsToExtraSelections(const std::vector &sourceLocations, - uint selectionLength, - CppEditorWidget *cppEditorWidget) -{ - const auto textCharFormat = occurrencesTextCharFormat(); - - QList selections; - selections.reserve(int(sourceLocations.size())); - - auto sourceLocationToExtraSelection = [&] (const SourceLocationContainer &sourceLocation) { - QTextEdit::ExtraSelection selection; - - selection.cursor = selectAt(cppEditorWidget->textCursor(), - sourceLocation.line(), - sourceLocation.column(), - selectionLength); - selection.format = textCharFormat; - - return selection; - }; - - - std::transform(sourceLocations.begin(), - sourceLocations.end(), - std::back_inserter(selections), - sourceLocationToExtraSelection); - - return selections; -}; - -} - -void CppEditorWidget::renameSymbolUnderCursorClang() -{ - using ClangBackEnd::SourceLocationsContainer; - - ProjectPart *theProjectPart = projectPart(); - if (refactoringEngine()->isUsable() && theProjectPart) { - d->m_useSelectionsUpdater.abortSchedule(); - - QPointer cppEditorWidget = this; - - auto renameSymbols = [=] (const QString &symbolName, - const SourceLocationsContainer &sourceLocations, - int revision) { - if (cppEditorWidget) { - viewport()->setCursor(Qt::IBeamCursor); - - if (revision == document()->revision()) { - auto selections = sourceLocationsToExtraSelections(sourceLocations.sourceLocationContainers(), - symbolName.size(), - cppEditorWidget); - setExtraSelections(TextEditor::TextEditorWidget::CodeSemanticsSelection, - selections); - d->m_localRenaming.updateSelectionsForVariableUnderCursor(selections); - if (!d->m_localRenaming.start()) - renameUsages(); - } - } - }; - - refactoringEngine()->startLocalRenaming(textCursor(), - textDocument()->filePath(), - document()->revision(), - theProjectPart, - std::move(renameSymbols)); - - viewport()->setCursor(Qt::BusyCursor); - } -} - -void CppEditorWidget::updatePreprocessorButtonTooltip() -{ - if (!d->m_preprocessorButton) - return; - - Command *cmd = ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG); - QTC_ASSERT(cmd, return); - d->m_preprocessorButton->setToolTip(cmd->action()->toolTip()); -} - -void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit) -{ - if (!d->m_modelManager) - return; - - if (!d->m_lastSemanticInfo.doc) - return; - - // Find function declaration or definition under cursor - Function *functionDefinitionSymbol = 0; - Symbol *functionDeclarationSymbol = 0; - - ASTPath astPathFinder(d->m_lastSemanticInfo.doc); - const QList astPath = astPathFinder(textCursor()); - - for (int i = 0, size = astPath.size(); i < size; ++i) { - AST *ast = astPath.at(i); - if (FunctionDefinitionAST *functionDefinitionAST = ast->asFunctionDefinition()) { - if ((functionDefinitionSymbol = functionDefinitionAST->symbol)) - break; // Function definition found! - } else if (SimpleDeclarationAST *simpleDeclaration = ast->asSimpleDeclaration()) { - if (List *symbols = simpleDeclaration->symbols) { - if (Symbol *symbol = symbols->value) { - if (symbol->isDeclaration() && symbol->type()->isFunctionType()) { - functionDeclarationSymbol = symbol; - break; // Function declaration found! - } - } - } - } - } - - // Link to function definition/declaration - CppEditorWidget::Link symbolLink; - if (functionDeclarationSymbol) { - symbolLink = linkToSymbol(d->m_modelManager->symbolFinder() - ->findMatchingDefinition(functionDeclarationSymbol, d->m_modelManager->snapshot())); - } else if (functionDefinitionSymbol) { - const Snapshot snapshot = d->m_modelManager->snapshot(); - LookupContext context(d->m_lastSemanticInfo.doc, snapshot); - ClassOrNamespace *binding = context.lookupType(functionDefinitionSymbol); - const QList declarations = context.lookup(functionDefinitionSymbol->name(), - functionDefinitionSymbol->enclosingScope()); - - QList best; - foreach (const LookupItem &r, declarations) { - if (Symbol *decl = r.declaration()) { - if (Function *funTy = decl->type()->asFunctionType()) { - if (funTy->match(functionDefinitionSymbol)) { - if (decl != functionDefinitionSymbol && binding == r.binding()) - best.prepend(decl); - else - best.append(decl); - } - } - } - } - - if (best.isEmpty()) - return; - symbolLink = linkToSymbol(best.first()); - } - - // Open Editor at link position - if (symbolLink.hasValidTarget()) - openLink(symbolLink, inNextSplit != alwaysOpenLinksInNextSplit()); -} - -CppEditorWidget::Link CppEditorWidget::findLinkAt(const QTextCursor &cursor, bool resolveTarget, - bool inNextSplit) -{ - if (!d->m_modelManager) - return Link(); - - return d->m_followSymbolUnderCursor->findLink(cursor, resolveTarget, - d->m_modelManager->snapshot(), - d->m_lastSemanticInfo.doc, - d->m_modelManager->symbolFinder(), - inNextSplit); -} - -unsigned CppEditorWidget::documentRevision() const -{ - return document()->revision(); -} - -static bool isClangFixItAvailableMarker(const RefactorMarker &marker) -{ - return marker.data.toString() - == QLatin1String(CppTools::Constants::CPP_CLANG_FIXIT_AVAILABLE_MARKER_ID); -} - -RefactorMarkers CppEditorWidget::refactorMarkersWithoutClangMarkers() const -{ - RefactorMarkers clearedRefactorMarkers; - - foreach (const RefactorMarker &marker, refactorMarkers()) { - if (isClangFixItAvailableMarker(marker)) - continue; - - clearedRefactorMarkers.append(marker); - } - - return clearedRefactorMarkers; -} - -RefactoringEngineInterface *CppEditorWidget::refactoringEngine() const -{ - return CppTools::CppModelManager::refactoringEngine(); -} - -bool CppEditorWidget::isSemanticInfoValidExceptLocalUses() const -{ - return d->m_lastSemanticInfo.doc - && d->m_lastSemanticInfo.revision == documentRevision() - && !d->m_lastSemanticInfo.snapshot.isEmpty(); -} - -bool CppEditorWidget::isSemanticInfoValid() const -{ - return isSemanticInfoValidExceptLocalUses() && d->m_lastSemanticInfo.localUsesUpdated; -} - -SemanticInfo CppEditorWidget::semanticInfo() const -{ - return d->m_lastSemanticInfo; -} - -bool CppEditorWidget::event(QEvent *e) -{ - switch (e->type()) { - case QEvent::ShortcutOverride: - // handle escape manually if a rename is active - if (static_cast(e)->key() == Qt::Key_Escape && d->m_localRenaming.isActive()) { - e->accept(); - return true; - } - break; - default: - break; - } - - return TextEditorWidget::event(e); -} - -void CppEditorWidget::processKeyNormally(QKeyEvent *e) -{ - TextEditorWidget::keyPressEvent(e); -} - -void CppEditorWidget::contextMenuEvent(QContextMenuEvent *e) -{ - // ### enable - // updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource())); - - QPointer menu(new QMenu(this)); - - ActionContainer *mcontext = ActionManager::actionContainer(Constants::M_CONTEXT); - QMenu *contextMenu = mcontext->menu(); - - QMenu *quickFixMenu = new QMenu(tr("&Refactor"), menu); - quickFixMenu->addAction(ActionManager::command(Constants::RENAME_SYMBOL_UNDER_CURSOR)->action()); - - if (isSemanticInfoValidExceptLocalUses()) { - d->m_useSelectionsUpdater.update(CppUseSelectionsUpdater::Synchronous); - AssistInterface *interface = createAssistInterface(QuickFix, ExplicitlyInvoked); - if (interface) { - QScopedPointer processor( - CppEditorPlugin::instance()->quickFixProvider()->createProcessor()); - QScopedPointer proposal(processor->perform(interface)); - if (!proposal.isNull()) { - auto model = static_cast(proposal->model()); - for (int index = 0; index < model->size(); ++index) { - auto item = static_cast(model->proposalItem(index)); - QuickFixOperation::Ptr op = item->data().value(); - QAction *action = quickFixMenu->addAction(op->description()); - connect(action, &QAction::triggered, this, [op] { op->perform(); }); - } - delete model; - } - } - } - - foreach (QAction *action, contextMenu->actions()) { - menu->addAction(action); - if (action->objectName() == QLatin1String(Constants::M_REFACTORING_MENU_INSERTION_POINT)) - menu->addMenu(quickFixMenu); - } - - appendStandardContextMenuActions(menu); - - menu->exec(e->globalPos()); - if (!menu) - return; - delete menu; -} - -void CppEditorWidget::keyPressEvent(QKeyEvent *e) -{ - if (d->m_localRenaming.handleKeyPressEvent(e)) - return; - - if (handleStringSplitting(e)) - return; - - if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { - if (trySplitComment(this, semanticInfo().snapshot)) { - e->accept(); - return; - } - } - - TextEditorWidget::keyPressEvent(e); -} - -bool CppEditorWidget::handleStringSplitting(QKeyEvent *e) const -{ - if (!TextEditorSettings::completionSettings().m_autoSplitStrings) - return false; - - if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { - QTextCursor cursor = textCursor(); - - const Kind stringKind = CPlusPlus::MatchingText::stringKindAtCursor(cursor); - if (stringKind >= T_FIRST_STRING_LITERAL && stringKind < T_FIRST_RAW_STRING_LITERAL) { - cursor.beginEditBlock(); - if (cursor.positionInBlock() > 0 - && cursor.block().text().at(cursor.positionInBlock() - 1) == QLatin1Char('\\')) { - // Already escaped: simply go back to line, but do not indent. - cursor.insertText(QLatin1String("\n")); - } else if (e->modifiers() & Qt::ShiftModifier) { - // With 'shift' modifier, escape the end of line character - // and start at beginning of next line. - cursor.insertText(QLatin1String("\\\n")); - } else { - // End the current string, and start a new one on the line, properly indented. - cursor.insertText(QLatin1String("\"\n\"")); - textDocument()->autoIndent(cursor); - } - cursor.endEditBlock(); - e->accept(); - return true; - } - } - - return false; -} - -void CppEditorWidget::slotCodeStyleSettingsChanged(const QVariant &) -{ - QtStyleCodeFormatter formatter; - formatter.invalidateCache(document()); -} - -void CppEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo, - bool updateUseSelectionSynchronously) -{ - if (semanticInfo.revision != documentRevision()) - return; - - d->m_lastSemanticInfo = semanticInfo; - - if (!d->m_localRenaming.isActive()) { - const CppUseSelectionsUpdater::CallType type = updateUseSelectionSynchronously - ? CppUseSelectionsUpdater::Synchronous - : CppUseSelectionsUpdater::Asynchronous; - d->m_useSelectionsUpdater.update(type); - } - - // schedule a check for a decl/def link - updateFunctionDeclDefLink(); -} - -AssistInterface *CppEditorWidget::createAssistInterface(AssistKind kind, AssistReason reason) const -{ - if (kind == Completion) { - if (CppCompletionAssistProvider *cap = - qobject_cast(cppEditorDocument()->completionAssistProvider())) { - LanguageFeatures features = LanguageFeatures::defaultFeatures(); - if (Document::Ptr doc = d->m_lastSemanticInfo.doc) - features = doc->languageFeatures(); - features.objCEnabled |= cppEditorDocument()->isObjCEnabled(); - return cap->createAssistInterface( - textDocument()->filePath().toString(), - this, - features, - position(), - reason); - } - } else if (kind == QuickFix) { - if (isSemanticInfoValid()) - return new CppQuickFixInterface(const_cast(this), reason); - } else { - return TextEditorWidget::createAssistInterface(kind, reason); - } - return 0; -} - -QSharedPointer CppEditorWidget::declDefLink() const -{ - return d->m_declDefLink; -} - -void CppEditorWidget::onRefactorMarkerClicked(const RefactorMarker &marker) -{ - if (marker.data.canConvert()) { - applyDeclDefLinkChanges(true); - } else if (isClangFixItAvailableMarker(marker)) { - int line, column; - if (Convenience::convertPosition(document(), marker.cursor.position(), &line, &column)) { - setTextCursor(marker.cursor); - invokeAssist(TextEditor::QuickFix); - } - } -} - -void CppEditorWidget::updateFunctionDeclDefLink() -{ - const int pos = textCursor().selectionStart(); - - // if there's already a link, abort it if the cursor is outside or the name changed - // (adding a prefix is an exception since the user might type a return type) - if (d->m_declDefLink - && (pos < d->m_declDefLink->linkSelection.selectionStart() - || pos > d->m_declDefLink->linkSelection.selectionEnd() - || !d->m_declDefLink->nameSelection.selectedText().trimmed() - .endsWith(d->m_declDefLink->nameInitial))) { - abortDeclDefLink(); - return; - } - - // don't start a new scan if there's one active and the cursor is already in the scanned area - const QTextCursor scannedSelection = d->m_declDefLinkFinder->scannedSelection(); - if (!scannedSelection.isNull() - && scannedSelection.selectionStart() <= pos - && scannedSelection.selectionEnd() >= pos) { - return; - } - - d->m_updateFunctionDeclDefLinkTimer.start(); -} - -void CppEditorWidget::updateFunctionDeclDefLinkNow() -{ - IEditor *editor = EditorManager::currentEditor(); - if (!editor || editor->widget() != this) - return; - - const Snapshot semanticSnapshot = d->m_lastSemanticInfo.snapshot; - const Document::Ptr semanticDoc = d->m_lastSemanticInfo.doc; - - if (d->m_declDefLink) { - // update the change marker - const Utils::ChangeSet changes = d->m_declDefLink->changes(semanticSnapshot); - if (changes.isEmpty()) - d->m_declDefLink->hideMarker(this); - else - d->m_declDefLink->showMarker(this); - return; - } - - if (!isSemanticInfoValidExceptLocalUses()) - return; - - Snapshot snapshot = CppModelManager::instance()->snapshot(); - snapshot.insert(semanticDoc); - - d->m_declDefLinkFinder->startFindLinkAt(textCursor(), semanticDoc, snapshot); -} - -void CppEditorWidget::onFunctionDeclDefLinkFound(QSharedPointer link) -{ - abortDeclDefLink(); - d->m_declDefLink = link; - IDocument *targetDocument = DocumentModel::documentForFilePath( d->m_declDefLink->targetFile->fileName()); - if (textDocument() != targetDocument) { - if (auto textDocument = qobject_cast(targetDocument)) - connect(textDocument, &IDocument::contentsChanged, - this, &CppEditorWidget::abortDeclDefLink); - } - -} - -void CppEditorWidget::applyDeclDefLinkChanges(bool jumpToMatch) -{ - if (!d->m_declDefLink) - return; - d->m_declDefLink->apply(this, jumpToMatch); - abortDeclDefLink(); - updateFunctionDeclDefLink(); -} - -FollowSymbolUnderCursor *CppEditorWidget::followSymbolUnderCursorDelegate() -{ - return d->m_followSymbolUnderCursor.data(); -} - -void CppEditorWidget::encourageApply() -{ - if (d->m_localRenaming.encourageApply()) - return; - - TextEditorWidget::encourageApply(); -} - -void CppEditorWidget::abortDeclDefLink() -{ - if (!d->m_declDefLink) - return; - - IDocument *targetDocument = DocumentModel::documentForFilePath(d->m_declDefLink->targetFile->fileName()); - if (textDocument() != targetDocument) { - if (auto textDocument = qobject_cast(targetDocument)) - disconnect(textDocument, &IDocument::contentsChanged, - this, &CppEditorWidget::abortDeclDefLink); - } - - d->m_declDefLink->hideMarker(this); - d->m_declDefLink.clear(); -} - -void CppEditorWidget::showPreProcessorWidget() -{ - const QString filePath = textDocument()->filePath().toString(); - - CppPreProcessorDialog dialog(filePath, this); - if (dialog.exec() == QDialog::Accepted) { - const QByteArray extraDirectives = dialog.extraPreprocessorDirectives().toUtf8(); - cppEditorDocument()->setExtraPreprocessorDirectives(extraDirectives); - cppEditorDocument()->scheduleProcessDocument(); - } -} - } // namespace Internal } // namespace CppEditor -- cgit v1.2.3