Changeset View
Changeset View
Standalone View
Standalone View
plugins/contextbrowser/contextbrowser.cpp
Show First 20 Lines • Show All 438 Lines • ▼ Show 20 Line(s) | 438 | if(m_currentToolTip) { | |||
---|---|---|---|---|---|
439 | m_currentToolTip->deleteLater(); | 439 | m_currentToolTip->deleteLater(); | ||
440 | m_currentToolTip = nullptr; | 440 | m_currentToolTip = nullptr; | ||
441 | m_currentNavigationWidget = nullptr; | 441 | m_currentNavigationWidget = nullptr; | ||
442 | m_currentToolTipProblems.clear(); | 442 | m_currentToolTipProblems.clear(); | ||
443 | m_currentToolTipDeclaration = {}; | 443 | m_currentToolTipDeclaration = {}; | ||
444 | } | 444 | } | ||
445 | } | 445 | } | ||
446 | 446 | | |||
447 | static QVector<KDevelop::IProblem::Ptr> findProblemsUnderCursor(TopDUContext* topContext, KTextEditor::Cursor position) | 447 | static QVector<KDevelop::IProblem::Ptr> findProblemsUnderCursor(TopDUContext* topContext, KTextEditor::Cursor position, | ||
448 | KTextEditor::Range& handleRange) | ||||
448 | { | 449 | { | ||
449 | QVector<KDevelop::IProblem::Ptr> problems; | 450 | QVector<KDevelop::IProblem::Ptr> problems; | ||
451 | handleRange = KTextEditor::Range::invalid(); | ||||
452 | | ||||
450 | const auto modelsData = ICore::self()->languageController()->problemModelSet()->models(); | 453 | const auto modelsData = ICore::self()->languageController()->problemModelSet()->models(); | ||
451 | for (const auto& modelData : modelsData) { | 454 | for (const auto& modelData : modelsData) { | ||
452 | foreach (const auto& problem, modelData.model->problems(topContext->url())) { | 455 | foreach (const auto& problem, modelData.model->problems(topContext->url())) { | ||
453 | DocumentRange problemRange = problem->finalLocation(); | 456 | DocumentRange problemRange = problem->finalLocation(); | ||
454 | if (problemRange.contains(position) || (problemRange.isEmpty() && problemRange.boundaryAtCursor(position))) | 457 | if (problemRange.contains(position) || (problemRange.isEmpty() && problemRange.boundaryAtCursor(position))) { | ||
455 | problems += problem; | 458 | problems += problem; | ||
459 | // first? | ||||
460 | if (!handleRange.isValid()) { | ||||
461 | handleRange = problemRange; | ||||
462 | } else { | ||||
463 | handleRange.confineToRange(problemRange); | ||||
464 | } | ||||
465 | } | ||||
456 | } | 466 | } | ||
457 | } | 467 | } | ||
458 | 468 | | |||
459 | return problems; | 469 | return problems; | ||
460 | } | 470 | } | ||
461 | 471 | | |||
462 | static QVector<KDevelop::IProblem::Ptr> findProblemsCloseToCursor(TopDUContext* topContext, KTextEditor::Cursor position, KTextEditor::View* view) | 472 | static QVector<KDevelop::IProblem::Ptr> findProblemsCloseToCursor(const TopDUContext* topContext, KTextEditor::Cursor position, const KTextEditor::View* view, | ||
473 | KTextEditor::Range& handleRange) | ||||
463 | { | 474 | { | ||
475 | handleRange = KTextEditor::Range::invalid(); | ||||
476 | | ||||
464 | QVector<KDevelop::IProblem::Ptr> allProblems; | 477 | QVector<KDevelop::IProblem::Ptr> allProblems; | ||
465 | const auto modelsData = ICore::self()->languageController()->problemModelSet()->models(); | 478 | const auto modelsData = ICore::self()->languageController()->problemModelSet()->models(); | ||
466 | for (const auto& modelData : modelsData) { | 479 | for (const auto& modelData : modelsData) { | ||
467 | const auto problems = modelData.model->problems(topContext->url()); | 480 | const auto problems = modelData.model->problems(topContext->url()); | ||
468 | allProblems.reserve(allProblems.size() + problems.size()); | 481 | allProblems.reserve(allProblems.size() + problems.size()); | ||
469 | for (const auto& problem : problems) { | 482 | for (const auto& problem : problems) { | ||
470 | allProblems += problem; | 483 | allProblems += problem; | ||
471 | } | 484 | } | ||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Line(s) | 525 | foreach (auto problem, allProblems) { | |||
523 | 536 | | |||
524 | if (view->document()->text(dist).trimmed().isEmpty()) | 537 | if (view->document()->text(dist).trimmed().isEmpty()) | ||
525 | closestProblems += problem; | 538 | closestProblems += problem; | ||
526 | else | 539 | else | ||
527 | break; | 540 | break; | ||
528 | } | 541 | } | ||
529 | } | 542 | } | ||
530 | 543 | | |||
544 | if (!closestProblems.isEmpty()) { | ||||
545 | auto it = closestProblems.constBegin(); | ||||
546 | handleRange = (*it)->finalLocation(); | ||||
547 | ++it; | ||||
548 | for (auto end = closestProblems.constEnd(); it != end; ++it) { | ||||
549 | handleRange.confineToRange((*it)->finalLocation()); | ||||
550 | } | ||||
551 | } | ||||
552 | | ||||
531 | return closestProblems; | 553 | return closestProblems; | ||
532 | } | 554 | } | ||
533 | 555 | | |||
534 | QWidget* ContextBrowserPlugin::navigationWidgetForPosition(KTextEditor::View* view, KTextEditor::Cursor position) | 556 | QWidget* ContextBrowserPlugin::navigationWidgetForPosition(KTextEditor::View* view, KTextEditor::Cursor position, | ||
557 | KTextEditor::Range& itemRange) | ||||
brauch: In the API, you return a tuple for this use case, here you use a return argument instead. I… | |||||
Proposed to do that in the public API to follow the rest of the methods there. Personally not yet a fan of tuples, at least the QPair ones with their semantically poor first and second member names, so avoided to do that here. But given you asked, I tried a variant using also QPair for this method here, not sure I prefer it. Updating the patch next with that to give you an idea and something to choose from :) kossebau: Proposed to do that in the public API to follow the rest of the methods there.
Personally not… | |||||
535 | { | 558 | { | ||
536 | QUrl viewUrl = view->document()->url(); | 559 | QUrl viewUrl = view->document()->url(); | ||
537 | const auto languages = ICore::self()->languageController()->languagesForUrl(viewUrl); | 560 | const auto languages = ICore::self()->languageController()->languagesForUrl(viewUrl); | ||
538 | 561 | | |||
539 | DUChainReadLocker lock(DUChain::lock()); | 562 | DUChainReadLocker lock(DUChain::lock()); | ||
563 | | ||||
540 | for (const auto language : languages) { | 564 | for (const auto language : languages) { | ||
541 | auto widget = language->specialLanguageObjectNavigationWidget(viewUrl, KTextEditor::Cursor(position)); | 565 | auto widget = language->specialLanguageObjectNavigationWidget(viewUrl, position); | ||
542 | auto navigationWidget = qobject_cast<AbstractNavigationWidget*>(widget); | 566 | auto navigationWidget = qobject_cast<AbstractNavigationWidget*>(widget.first); | ||
543 | if(navigationWidget) | 567 | if (navigationWidget) { | ||
568 | itemRange = widget.second; | ||||
544 | return navigationWidget; | 569 | return navigationWidget; | ||
545 | } | 570 | } | ||
571 | } | ||||
546 | 572 | | |||
547 | TopDUContext* topContext = DUChainUtils::standardContextForUrl(view->document()->url()); | 573 | TopDUContext* topContext = DUChainUtils::standardContextForUrl(view->document()->url()); | ||
548 | if (topContext) { | 574 | if (topContext) { | ||
549 | // first pass: find problems under the cursor | 575 | // first pass: find problems under the cursor | ||
550 | const auto problems = findProblemsUnderCursor(topContext, position); | 576 | const auto problems = findProblemsUnderCursor(topContext, position, itemRange); | ||
551 | if (!problems.isEmpty()) { | 577 | if (!problems.isEmpty()) { | ||
552 | if (problems == m_currentToolTipProblems && m_currentToolTip) { | 578 | if (problems == m_currentToolTipProblems && m_currentToolTip) { | ||
553 | return nullptr; | 579 | return nullptr; | ||
554 | } | 580 | } | ||
555 | 581 | | |||
556 | m_currentToolTipProblems = problems; | 582 | m_currentToolTipProblems = problems; | ||
583 | | ||||
557 | auto widget = new AbstractNavigationWidget; | 584 | auto widget = new AbstractNavigationWidget; | ||
558 | auto context = new ProblemNavigationContext(problems); | 585 | auto context = new ProblemNavigationContext(problems); | ||
559 | context->setTopContext(TopDUContextPointer(topContext)); | 586 | context->setTopContext(TopDUContextPointer(topContext)); | ||
560 | widget->setContext(NavigationContextPointer(context)); | 587 | widget->setContext(NavigationContextPointer(context)); | ||
561 | return widget; | 588 | return widget; | ||
562 | } | 589 | } | ||
563 | } | 590 | } | ||
564 | 591 | | |||
565 | auto declUnderCursor = DUChainUtils::itemUnderCursor(viewUrl, position).declaration; | 592 | const auto itemUnderCursor = DUChainUtils::itemUnderCursor(viewUrl, position); | ||
593 | auto declUnderCursor = itemUnderCursor.declaration; | ||||
566 | Declaration* decl = DUChainUtils::declarationForDefinition(declUnderCursor); | 594 | Declaration* decl = DUChainUtils::declarationForDefinition(declUnderCursor); | ||
567 | if (decl && decl->kind() == Declaration::Alias) { | 595 | if (decl && decl->kind() == Declaration::Alias) { | ||
568 | AliasDeclaration* alias = dynamic_cast<AliasDeclaration*>(decl); | 596 | AliasDeclaration* alias = dynamic_cast<AliasDeclaration*>(decl); | ||
569 | Q_ASSERT(alias); | 597 | Q_ASSERT(alias); | ||
570 | DUChainReadLocker lock; | | |||
571 | decl = alias->aliasedDeclaration().declaration(); | 598 | decl = alias->aliasedDeclaration().declaration(); | ||
572 | } | 599 | } | ||
573 | if(decl) { | 600 | if(decl) { | ||
574 | if(m_currentToolTipDeclaration == IndexedDeclaration(decl) && m_currentToolTip) | 601 | if(m_currentToolTipDeclaration == IndexedDeclaration(decl) && m_currentToolTip) | ||
575 | return nullptr; | 602 | return nullptr; | ||
576 | 603 | | |||
577 | m_currentToolTipDeclaration = IndexedDeclaration(decl); | 604 | m_currentToolTipDeclaration = IndexedDeclaration(decl); | ||
605 | itemRange = itemUnderCursor.range; | ||||
578 | return decl->context()->createNavigationWidget(decl, DUChainUtils::standardContextForUrl(viewUrl)); | 606 | return decl->context()->createNavigationWidget(decl, DUChainUtils::standardContextForUrl(viewUrl)); | ||
579 | } | 607 | } | ||
580 | 608 | | |||
581 | if (topContext) { | 609 | if (topContext) { | ||
582 | // second pass: find closest problem to the cursor | 610 | // second pass: find closest problem to the cursor | ||
583 | const auto problems = findProblemsCloseToCursor(topContext, position, view); | 611 | const auto problems = findProblemsCloseToCursor(topContext, position, view, itemRange); | ||
584 | if (!problems.isEmpty()) { | 612 | if (!problems.isEmpty()) { | ||
585 | if (problems == m_currentToolTipProblems && m_currentToolTip) { | 613 | if (problems == m_currentToolTipProblems && m_currentToolTip) { | ||
586 | return nullptr; | 614 | return nullptr; | ||
587 | } | 615 | } | ||
588 | 616 | | |||
589 | m_currentToolTipProblems = problems; | 617 | m_currentToolTipProblems = problems; | ||
618 | | ||||
590 | auto widget = new AbstractNavigationWidget; | 619 | auto widget = new AbstractNavigationWidget; | ||
591 | // since the problem is not under cursor: show location | 620 | // since the problem is not under cursor: show location | ||
592 | widget->setContext(NavigationContextPointer(new ProblemNavigationContext(problems, ProblemNavigationContext::ShowLocation))); | 621 | widget->setContext(NavigationContextPointer(new ProblemNavigationContext(problems, ProblemNavigationContext::ShowLocation))); | ||
593 | return widget; | 622 | return widget; | ||
594 | } | 623 | } | ||
595 | } | 624 | } | ||
596 | 625 | | |||
597 | return nullptr; | 626 | return nullptr; | ||
598 | } | 627 | } | ||
599 | 628 | | |||
600 | void ContextBrowserPlugin::showToolTip(KTextEditor::View* view, KTextEditor::Cursor position) { | 629 | void ContextBrowserPlugin::showToolTip(KTextEditor::View* view, KTextEditor::Cursor position) { | ||
601 | ContextBrowserView* contextView = browserViewForWidget(view); | 630 | ContextBrowserView* contextView = browserViewForWidget(view); | ||
602 | if(contextView && contextView->isVisible() && !contextView->isLocked()) | 631 | if(contextView && contextView->isVisible() && !contextView->isLocked()) | ||
603 | return; // If the context-browser view is visible, it will care about updating by itself | 632 | return; // If the context-browser view is visible, it will care about updating by itself | ||
604 | 633 | | |||
605 | auto navigationWidget = navigationWidgetForPosition(view, position); | 634 | KTextEditor::Range itemRange = KTextEditor::Range::invalid(); | ||
635 | auto navigationWidget = navigationWidgetForPosition(view, position, itemRange); | ||||
606 | if(navigationWidget) { | 636 | if(navigationWidget) { | ||
607 | 637 | | |||
608 | // If we have an invisible context-view, assign the tooltip navigation-widget to it. | 638 | // If we have an invisible context-view, assign the tooltip navigation-widget to it. | ||
609 | // If the user makes the context-view visible, it will instantly contain the correct widget. | 639 | // If the user makes the context-view visible, it will instantly contain the correct widget. | ||
610 | if(contextView && !contextView->isLocked()) | 640 | if(contextView && !contextView->isLocked()) | ||
611 | contextView->setNavigationWidget(navigationWidget); | 641 | contextView->setNavigationWidget(navigationWidget); | ||
612 | 642 | | |||
613 | if(m_currentToolTip) { | 643 | if(m_currentToolTip) { | ||
614 | m_currentToolTip->deleteLater(); | 644 | m_currentToolTip->deleteLater(); | ||
615 | m_currentToolTip = nullptr; | 645 | m_currentToolTip = nullptr; | ||
616 | m_currentNavigationWidget = nullptr; | 646 | m_currentNavigationWidget = nullptr; | ||
617 | } | 647 | } | ||
618 | 648 | | |||
619 | KDevelop::NavigationToolTip* tooltip = new KDevelop::NavigationToolTip(view, view->mapToGlobal(view->cursorToCoordinate(position)) + QPoint(20, 40), navigationWidget); | 649 | KDevelop::NavigationToolTip* tooltip = new KDevelop::NavigationToolTip(view, view->mapToGlobal(view->cursorToCoordinate(position)) + QPoint(20, 40), navigationWidget); | ||
620 | KTextEditor::Range itemRange; | 650 | if (!itemRange.isValid()) { | ||
621 | { | 651 | qCWarning(PLUGIN_CONTEXTBROWSER) << "Got navigationwidget with invalid itemrange"; | ||
622 | DUChainReadLocker lock; | 652 | itemRange = KTextEditor::Range(position, 0); | ||
623 | auto viewUrl = view->document()->url(); | | |||
624 | itemRange = DUChainUtils::itemUnderCursor(viewUrl, position).range; | | |||
625 | } | 653 | } | ||
654 | | ||||
626 | tooltip->setHandleRect(KTextEditorHelpers::itemBoundingRect(view, itemRange)); | 655 | tooltip->setHandleRect(KTextEditorHelpers::itemBoundingRect(view, itemRange)); | ||
627 | tooltip->resize( navigationWidget->sizeHint() + QSize(10, 10) ); | 656 | tooltip->resize( navigationWidget->sizeHint() + QSize(10, 10) ); | ||
628 | QObject::connect( view, &KTextEditor::View::verticalScrollPositionChanged, | 657 | QObject::connect( view, &KTextEditor::View::verticalScrollPositionChanged, | ||
629 | this, &ContextBrowserPlugin::hideToolTip ); | 658 | this, &ContextBrowserPlugin::hideToolTip ); | ||
630 | QObject::connect( view, &KTextEditor::View::horizontalScrollPositionChanged, | 659 | QObject::connect( view, &KTextEditor::View::horizontalScrollPositionChanged, | ||
631 | this, &ContextBrowserPlugin::hideToolTip ); | 660 | this, &ContextBrowserPlugin::hideToolTip ); | ||
632 | qCDebug(PLUGIN_CONTEXTBROWSER) << "tooltip size" << tooltip->size(); | 661 | qCDebug(PLUGIN_CONTEXTBROWSER) << "tooltip size" << tooltip->size(); | ||
633 | m_currentToolTip = tooltip; | 662 | m_currentToolTip = tooltip; | ||
▲ Show 20 Lines • Show All 159 Lines • ▼ Show 20 Line(s) | 821 | { | |||
793 | // Highlight a special language object | 822 | // Highlight a special language object | ||
794 | if(allowHighlight) | 823 | if(allowHighlight) | ||
795 | { | 824 | { | ||
796 | highlights.highlights << PersistentMovingRange::Ptr(new PersistentMovingRange(specialRange, IndexedString(url))); | 825 | highlights.highlights << PersistentMovingRange::Ptr(new PersistentMovingRange(specialRange, IndexedString(url))); | ||
797 | highlights.highlights.back()->setAttribute(highlightedSpecialObjectAttribute(view)); | 826 | highlights.highlights.back()->setAttribute(highlightedSpecialObjectAttribute(view)); | ||
798 | highlights.highlights.back()->setZDepth(highlightingZDepth); | 827 | highlights.highlights.back()->setZDepth(highlightingZDepth); | ||
799 | } | 828 | } | ||
800 | if(updateBrowserView) | 829 | if(updateBrowserView) | ||
801 | updateBrowserView->setSpecialNavigationWidget(language->specialLanguageObjectNavigationWidget(url, highlightPosition)); | 830 | updateBrowserView->setSpecialNavigationWidget(language->specialLanguageObjectNavigationWidget(url, highlightPosition).first); | ||
802 | }else{ | 831 | }else{ | ||
803 | KDevelop::DUChainReadLocker lock( DUChain::lock(), 100 ); | 832 | KDevelop::DUChainReadLocker lock( DUChain::lock(), 100 ); | ||
804 | if(!lock.locked()) { | 833 | if(!lock.locked()) { | ||
805 | qCDebug(PLUGIN_CONTEXTBROWSER) << "Failed to lock du-chain in time"; | 834 | qCDebug(PLUGIN_CONTEXTBROWSER) << "Failed to lock du-chain in time"; | ||
806 | return; | 835 | return; | ||
807 | } | 836 | } | ||
808 | 837 | | |||
809 | TopDUContext* topContext = DUChainUtils::standardContextForUrl(view->document()->url()); | 838 | TopDUContext* topContext = DUChainUtils::standardContextForUrl(view->document()->url()); | ||
▲ Show 20 Lines • Show All 691 Lines • Show Last 20 Lines |
In the API, you return a tuple for this use case, here you use a return argument instead. I think you should return a tuple here as well.