diff --git a/interfaces/iuicontroller.h b/interfaces/iuicontroller.h --- a/interfaces/iuicontroller.h +++ b/interfaces/iuicontroller.h @@ -130,16 +130,6 @@ virtual void registerStatus(QObject* status) = 0; /** - * Shows an assistant popup at bottom within the current central widget - * @p assistant the assistant that will be shown in a popup */ - virtual void popUpAssistant(const QExplicitlySharedDataPointer& assistant) = 0; - - /** - * Hides the assistant if it is currently being shown - */ - virtual void hideAssistant() = 0; - - /** * This is meant to be used by IDocument subclasses to initialize the * Sublime::Document. */ diff --git a/language/assistant/staticassistantsmanager.cpp b/language/assistant/staticassistantsmanager.cpp --- a/language/assistant/staticassistantsmanager.cpp +++ b/language/assistant/staticassistantsmanager.cpp @@ -222,7 +222,7 @@ m_activeAssistant = assistant; if (m_activeAssistant) { connect(m_activeAssistant.data(), &IAssistant::hide, q, &StaticAssistantsManager::hideAssistant, Qt::UniqueConnection); - ICore::self()->uiController()->popUpAssistant(IAssistant::Ptr(m_activeAssistant.data())); + // TODO: Add fake problem here, so we can invoke the problem nav context m_assistantStartedAt = m_currentView.data()->cursorPosition(); } diff --git a/language/duchain/navigation/problemnavigationcontext.h b/language/duchain/navigation/problemnavigationcontext.h --- a/language/duchain/navigation/problemnavigationcontext.h +++ b/language/duchain/navigation/problemnavigationcontext.h @@ -20,12 +20,30 @@ #define KDEVPLATFORM_PROBLEMNAVIGATIONCONTEXT_H #include +#include + #include #include #include namespace KDevelop { +class KDEVPLATFORMLANGUAGE_EXPORT AssistantNavigationContext : public AbstractNavigationContext +{ + Q_OBJECT + public: + explicit AssistantNavigationContext(const IAssistant::Ptr& assistant); + ~AssistantNavigationContext(); + + virtual QString name() const override; + virtual QString html(bool shorten = false) override; + + NavigationContextPointer executeKeyAction(QString key) override; + + private: + IAssistant::Ptr m_assistant; +}; + class KDEVPLATFORMLANGUAGE_EXPORT ProblemNavigationContext : public AbstractNavigationContext { Q_OBJECT @@ -38,6 +56,8 @@ virtual QWidget* widget() const override; virtual bool isWidgetMaximized() const override; + NavigationContextPointer executeKeyAction(QString key) override; + private: IProblem::Ptr m_problem; diff --git a/language/duchain/navigation/problemnavigationcontext.cpp b/language/duchain/navigation/problemnavigationcontext.cpp --- a/language/duchain/navigation/problemnavigationcontext.cpp +++ b/language/duchain/navigation/problemnavigationcontext.cpp @@ -18,6 +18,8 @@ #include "problemnavigationcontext.h" +#include "util/debug.h" + #include #include @@ -27,37 +29,75 @@ #include #include #include -#include #include using namespace KDevelop; +namespace { + +QString KEY_START_ASSISTANT() { return QStringLiteral("start_assistant"); } +QString KEY_INVOKE_ACTION(int num) { return QStringLiteral("invoke_action_%1").arg(num); } + +} + + +KDevelop::AssistantNavigationContext::AssistantNavigationContext(const IAssistant::Ptr& assistant) + : m_assistant(assistant) +{ +} + +KDevelop::AssistantNavigationContext::~AssistantNavigationContext() +{ +} + + +QString KDevelop::AssistantNavigationContext::name() const +{ + return i18n("Assistant"); +} + +QString KDevelop::AssistantNavigationContext::html(bool shorten) +{ + clear(); + m_shorten = shorten; + + modifyHtml() += i18n("Solutions:") + "
"; + + int index = 0; + foreach (auto assistantAction, m_assistant->actions()) { + makeLink(i18n("Apply solution %1", index), KEY_INVOKE_ACTION(index), + NavigationAction(KEY_INVOKE_ACTION(index))); + modifyHtml() += ": " + assistantAction->description().toHtmlEscaped() + "
"; + ++index; + } + + return currentHtml(); +} + +NavigationContextPointer AssistantNavigationContext::executeKeyAction(QString key) +{ + if (key.startsWith(QLatin1String("invoke_action_"))) { + if (!m_assistant) + return {}; + + const auto index = key.replace(QLatin1String("invoke_action_"), QString()).toInt(); + auto action = m_assistant->actions().value(index); + if (action) { + action->execute(); + } else { + qCWarning(LANGUAGE()) << "Action got removed in-between"; + return {}; + } + } + + return {}; +} + + ProblemNavigationContext::ProblemNavigationContext(const IProblem::Ptr& problem) : m_problem(problem) , m_widget(nullptr) { - QExplicitlySharedDataPointer< IAssistant > solution = problem->solutionAssistant(); - if(solution && !solution->actions().isEmpty()) { - m_widget = new QWidget; - QHBoxLayout* layout = new QHBoxLayout(m_widget); - RichTextPushButton* button = new RichTextPushButton; -// button->setPopupMode(QToolButton::InstantPopup); - if(!solution->title().isEmpty()) - button->setHtml(i18n("Solve: %1", solution->title())); - else - button->setHtml(i18n("Solve")); - - QMenu* menu = new QMenu; - menu->setFocusPolicy(Qt::NoFocus); - foreach(IAssistantAction::Ptr action, solution->actions()) { - menu->addAction(action->toKAction(this)); - } - button->setMenu(menu); - - layout->addWidget(button); - layout->setAlignment(button, Qt::AlignLeft); - m_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - } } ProblemNavigationContext::~ProblemNavigationContext() @@ -80,14 +120,20 @@ return i18n("Problem"); } - QString ProblemNavigationContext::html(bool shorten) { clear(); m_shorten = shorten; modifyHtml() += QStringLiteral("

"); - modifyHtml() += i18n("Problem in %1:
", m_problem->sourceString()); + modifyHtml() += i18n("Problem in %1: ", m_problem->sourceString()); + auto assistant = m_problem->solutionAssistant(); + if (assistant && !assistant->actions().isEmpty()) { + makeLink(i18n("Start Assistant (%1 solutions)", assistant->actions().count()), KEY_START_ASSISTANT(), + NavigationAction(KEY_START_ASSISTANT())); + modifyHtml() += QStringLiteral("
"); + } + modifyHtml() += m_problem->description().toHtmlEscaped(); modifyHtml() += QStringLiteral("
"); modifyHtml() += "" + m_problem->explanation().toHtmlEscaped() + ""; @@ -126,3 +172,16 @@ modifyHtml() += QStringLiteral("

"); return currentHtml(); } + +NavigationContextPointer ProblemNavigationContext::executeKeyAction(QString key) +{ + if (key == KEY_START_ASSISTANT()) { + auto assistant = m_problem->solutionAssistant(); + if (!assistant) + return {}; + + return NavigationContextPointer(new AssistantNavigationContext(assistant)); + } + + return {}; +} diff --git a/plugins/contextbrowser/contextbrowser.h b/plugins/contextbrowser/contextbrowser.h --- a/plugins/contextbrowser/contextbrowser.h +++ b/plugins/contextbrowser/contextbrowser.h @@ -170,6 +170,7 @@ QWidget* toolbarWidgetForMainWindow(Sublime::MainWindow* window); void createActionsForMainWindow(Sublime::MainWindow* window, QString& xmlFile, KActionCollection& actions) override; + QWidget* navigationWidgetForPosition(KTextEditor::View* view, KTextEditor::Cursor position); void switchUse(bool forward); void clearMouseHover(); diff --git a/plugins/contextbrowser/contextbrowser.cpp b/plugins/contextbrowser/contextbrowser.cpp --- a/plugins/contextbrowser/contextbrowser.cpp +++ b/plugins/contextbrowser/contextbrowser.cpp @@ -63,10 +63,12 @@ #include #include #include +#include #include #include #include #include +#include #include @@ -413,42 +415,57 @@ } } -void ContextBrowserPlugin::showToolTip(KTextEditor::View* view, KTextEditor::Cursor position) { - - ContextBrowserView* contextView = browserViewForWidget(view); - if(contextView && contextView->isVisible() && !contextView->isLocked()) - return; // If the context-browser view is visible, it will care about updating by itself - +QWidget* ContextBrowserPlugin::navigationWidgetForPosition(KTextEditor::View* view, KTextEditor::Cursor position) +{ QUrl viewUrl = view->document()->url(); auto languages = ICore::self()->languageController()->languagesForUrl(viewUrl); - QWidget* navigationWidget = 0; - { - DUChainReadLocker lock(DUChain::lock()); - foreach (const auto language, languages) { - auto widget = language->specialLanguageObjectNavigationWidget(viewUrl, KTextEditor::Cursor(position)); - navigationWidget = qobject_cast(widget); - if(navigationWidget) - break; - } + DUChainReadLocker lock(DUChain::lock()); + foreach (const auto language, languages) { + auto widget = language->specialLanguageObjectNavigationWidget(viewUrl, KTextEditor::Cursor(position)); + auto navigationWidget = qobject_cast(widget); + if(navigationWidget) + return navigationWidget; + } - if(!navigationWidget) { - Declaration* decl = DUChainUtils::declarationForDefinition( DUChainUtils::itemUnderCursor(viewUrl, KTextEditor::Cursor(position)) ); - if (decl && decl->kind() == Declaration::Alias) { - AliasDeclaration* alias = dynamic_cast(decl); - Q_ASSERT(alias); - DUChainReadLocker lock; - decl = alias->aliasedDeclaration().declaration(); - } - if(decl) { - if(m_currentToolTipDeclaration == IndexedDeclaration(decl) && m_currentToolTip) - return; - m_currentToolTipDeclaration = IndexedDeclaration(decl); - navigationWidget = decl->context()->createNavigationWidget(decl, DUChainUtils::standardContextForUrl(viewUrl)); + TopDUContext* topContext = DUChainUtils::standardContextForUrl(view->document()->url()); + if (topContext) { + const auto problems = topContext->problems(); + foreach (auto problem, problems) { + if (problem->rangeInCurrentRevision().contains(position)) { + auto widget = new AbstractNavigationWidget; + widget->setContext(NavigationContextPointer(new ProblemNavigationContext(problem))); + return widget; } } } + auto declUnderCursor = DUChainUtils::itemUnderCursor(viewUrl, position); + Declaration* decl = DUChainUtils::declarationForDefinition(declUnderCursor); + if (decl && decl->kind() == Declaration::Alias) { + AliasDeclaration* alias = dynamic_cast(decl); + Q_ASSERT(alias); + DUChainReadLocker lock; + decl = alias->aliasedDeclaration().declaration(); + } + if(decl) { + if(m_currentToolTipDeclaration == IndexedDeclaration(decl) && m_currentToolTip) + return nullptr; + + m_currentToolTipDeclaration = IndexedDeclaration(decl); + return decl->context()->createNavigationWidget(decl, DUChainUtils::standardContextForUrl(viewUrl)); + } + + return nullptr; +} + +void ContextBrowserPlugin::showToolTip(KTextEditor::View* view, KTextEditor::Cursor position) { + + ContextBrowserView* contextView = browserViewForWidget(view); + if(contextView && contextView->isVisible() && !contextView->isLocked()) + return; // If the context-browser view is visible, it will care about updating by itself + + auto navigationWidget = navigationWidgetForPosition(view, position); if(navigationWidget) { // If we have an invisible context-view, assign the tooltip navigation-widget to it. @@ -466,7 +483,8 @@ KTextEditor::Range itemRange; { DUChainReadLocker lock; - itemRange = DUChainUtils::itemRangeUnderCursor(viewUrl, KTextEditor::Cursor(position)); + auto viewUrl = view->document()->url(); + itemRange = DUChainUtils::itemRangeUnderCursor(viewUrl, position); } tooltip->setHandleRect(getItemBoundingRect(view, itemRange)); tooltip->resize( navigationWidget->sizeHint() + QSize(10, 10) ); diff --git a/shell/AssistantButton.qml b/shell/AssistantButton.qml deleted file mode 100644 --- a/shell/AssistantButton.qml +++ /dev/null @@ -1,101 +0,0 @@ -/* - Copyright 2014 Sven Brauch - Copyright 2014 Kevin Funk - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2 as published by the Free Software Foundation. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -import QtQuick 2.2 - -// Component which provides a single button for the assistant widget. - -Rectangle { - id: root - - property color foreground - property color background - property color highlight - - property bool highlighted: false - // text on the button - property string text - // text in the shortcut field - property int button - // emitted when the button is clicked with the mouse - signal triggered() - - y: -1 - width: text.width + 4 - height: number.height + 4 - - color: Qt.lighter(root.background, 1.5) - border.color: Qt.lighter(root.foreground, 1.5) - - Behavior on opacity { - NumberAnimation { duration: 150; } - } - MouseArea { - id: mouseArea - - anchors.fill: parent - onClicked: root.triggered() - - hoverEnabled: true - - Row { - // row containing the separators, shortcut text, and button text - z: 3 - id: text - anchors.centerIn: parent - spacing: 0 - Rectangle { width: 2; height: 1; color: Qt.rgba(0, 0, 0, 0) } // padding - Text { - // shortcut key - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: 1 - id: number - color: root.foreground - text: button - z: 2 - } - Rectangle { width: 3; height: 1; color: Qt.rgba(0, 0, 0, 0) } // padding - Rectangle { y: 1; width: 1; color: root.foreground; height: root.height - 1; opacity: 0.3 } // line - Rectangle { width: 4; height: 1; color: Qt.rgba(0, 0, 0, 0) } // padding - Text { - // actual button text - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: 1 - color: root.foreground - text: root.text - textFormat: Text.PlainText - } - Rectangle { width: 2; height: 1; color: Qt.rgba(0, 0, 0, 0) } // padding - } - Rectangle { - // the background color for the shortcut key box, invisible by default. - id: highlightArea - Behavior on opacity { - NumberAnimation { duration: 200 } - } - opacity: (root.highlighted || mouseArea.containsMouse) ? 0.5 : 0.0 - x: 1 - y: 1 - z: 1 - height: text.height - width: number.width + 6 - color: root.highlight - } - } -} diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -11,7 +11,6 @@ workingsets/workingsetwidget.cpp workingsets/closedworkingsetswidget.cpp workingsets/workingsethelpers.cpp - assistantpopup.cpp mainwindow.cpp mainwindow_p.cpp plugincontroller.cpp @@ -172,5 +171,3 @@ filteredproblemstore.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kdevplatform/shell COMPONENT Devel ) - -install( FILES AssistantButton.qml assistantpopup.qml DESTINATION ${KDE_INSTALL_DATADIR}/kdevelop ) diff --git a/shell/assistantpopup.h b/shell/assistantpopup.h deleted file mode 100644 --- a/shell/assistantpopup.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - Copyright 2009 David Nolden - Copyright 2012 Milian Wolff - Copyright 2014 Sven Brauch - Copyright 2014 Kevin Funk - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2 as published by the Free Software Foundation. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef KDEVPLATFORM_ASSISTANTPOPUP_H -#define KDEVPLATFORM_ASSISTANTPOPUP_H - -#include -#include -#include - -namespace KTextEditor -{ -class View; -class Cursor; -} - -class AssistantPopupConfig : public QObject -{ - Q_OBJECT - Q_PROPERTY(QColor foreground READ foreground NOTIFY colorsChanged) - Q_PROPERTY(QColor background READ background NOTIFY colorsChanged) - Q_PROPERTY(QColor highlight READ highlight NOTIFY colorsChanged) - - Q_PROPERTY(QString title READ title NOTIFY titleChanged) - Q_PROPERTY(QList model READ model NOTIFY modelChanged) - Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged) - Q_PROPERTY(QSize viewSize READ viewSize WRITE setViewSize NOTIFY viewSizeChanged) - -public: - explicit AssistantPopupConfig(QObject *parent = 0); - - QColor foreground() const { return m_foreground; } - QColor background() const { return m_background; } - QColor highlight() const { return m_highlight; } - - QSize viewSize() const { return m_viewSize; }; - void setViewSize(const QSize &size); - - QString title() const { return m_title; } - void setTitle(const QString& title); - QList model() const { return m_model; } - void setModel(const QList& model); - - void setColorsFromView(QObject *view); - - bool isActive() const; - void setActive(bool active); - -signals: - void colorsChanged(); - - void titleChanged(const QString& title); - void modelChanged(const QList& model); - void activeChanged(bool active); - void viewSizeChanged(const QSize& size); - -private: - QColor m_foreground; - QColor m_background; - QColor m_highlight; - - QString m_title; - QList m_model; - bool m_active; - QSize m_viewSize; -}; - -Q_DECLARE_METATYPE(AssistantPopupConfig*) - -class AssistantPopup : public QQuickWidget -{ - Q_OBJECT - -public: - typedef QExplicitlySharedDataPointer Ptr; - - /** - * The current main window will be used as parent widget for the popup. - * This is to make use of the maximal space available and prevent any lines - * in e.g. the editor to be hidden by the popup. - */ - AssistantPopup(); - - /** - * Reset this popup for view @p view and show assistant @p assistant - * - * @p view The widget below which the assistant should be shown. - */ - void reset(KTextEditor::View *view, const KDevelop::IAssistant::Ptr &assistant); - - KDevelop::IAssistant::Ptr assistant() const; - -private slots: - void updatePosition(KTextEditor::View* view, const KTextEditor::Cursor& newPos); - void updateState(); - void updateLayout(); - - void executeHideAction(); - void hideAssistant(); - -protected: - bool eventFilter(QObject* object, QEvent* event) override; - -private: - void setView(KTextEditor::View* view); - void setAssistant(const KDevelop::IAssistant::Ptr& assistant); - void setActive( bool active ); - - KDevelop::IAssistant::Ptr m_assistant; - QPointer m_view; - AssistantPopupConfig* m_config; - QList m_shortcuts; - bool m_firstLayoutCompleted; -}; - -#endif // KDEVPLATFORM_ASSISTANTPOPUP_H diff --git a/shell/assistantpopup.cpp b/shell/assistantpopup.cpp deleted file mode 100644 --- a/shell/assistantpopup.cpp +++ /dev/null @@ -1,380 +0,0 @@ -/* - Copyright 2009 David Nolden - Copyright 2012 Milian Wolff - Copyright 2014 Sven Brauch - Copyright 2014 Kevin Funk - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2 as published by the Free Software Foundation. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "assistantpopup.h" -#include "sublime/holdupdates.h" -#include "util/kdevstringhandler.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -using namespace KDevelop; - -namespace { - -const int ASSISTANT_MODIFIER = -#ifdef Q_OS_MAC -Qt::CTRL; -#else -Qt::ALT; -#endif - -const int ASSISTANT_MOD_KEY = -#ifdef Q_OS_MAC -Qt::Key_Control; -#else -Qt::Key_Alt; -#endif - -QWidget* findByClassname(const KTextEditor::View* view, const QString& klass) -{ - auto children = view->findChildren(); - foreach ( auto child, children ) { - if ( child->metaObject()->className() == klass ) { - return child; - } - } - return nullptr; -}; - -/** - * @brief Get the geometry of the inner part (with the text) of the KTextEditor::View being used. - */ -QRect textWidgetGeometry(const KTextEditor::View *view) -{ - // Subtract the width of the right scrollbar - int scrollbarWidth = 0; - if ( auto scrollbar = findByClassname(view, QStringLiteral("KateScrollBar")) ) { - scrollbarWidth = scrollbar->width(); - } - // Subtract the width of the bottom scrollbar - int bottomScrollbarWidth = 0; - if ( auto bottom = findByClassname(view, QStringLiteral("QScrollBar")) ) { - bottomScrollbarWidth = bottom->height(); - } - auto geom = view->geometry(); - - geom.adjust(0, 0, -scrollbarWidth, -bottomScrollbarWidth); - return geom; -} - -} - -AssistantPopupConfig::AssistantPopupConfig(QObject *parent) - : QObject(parent) - , m_active(false) -{ -} - -void AssistantPopupConfig::setColorsFromView(QObject *view) -{ - auto iface = dynamic_cast(view); - Q_ASSERT(iface); - m_foreground = iface->configValue(QStringLiteral("line-number-color")).value(); - m_background = iface->configValue(QStringLiteral("icon-border-color")).value(); - m_highlight = iface->configValue(QStringLiteral("folding-marker-color")).value(); - if ( KColorUtils::luma(m_background) < 0.3 ) { - m_foreground = KColorUtils::lighten(m_foreground, 0.7); - } - const float lumaDiff = KColorUtils::luma(m_highlight) - KColorUtils::luma(m_background); - if ( qAbs(lumaDiff) < 0.5 ) { - m_highlight = QColor::fromHsv(m_highlight.hue(), - qMin(255, m_highlight.saturation() + 80), - lumaDiff > 0 ? qMin(255, m_highlight.value() + 120) - : qMax(80, m_highlight.value() - 40)); - } - emit colorsChanged(); -} - -bool AssistantPopupConfig::isActive() const -{ - return m_active; -} - -void AssistantPopupConfig::setActive(bool active) -{ - if (m_active == active) { - return; - } - - m_active = active; - emit activeChanged(m_active); -} - -void AssistantPopupConfig::setViewSize(const QSize& size) -{ - if (size != m_viewSize) { - m_viewSize = size; - emit viewSizeChanged(size); - } -} - -void AssistantPopupConfig::setTitle(const QString& title) -{ - if (m_title == title) { - return; - } - - m_title = title; - emit titleChanged(m_title); -} - -void AssistantPopupConfig::setModel(const QList& model) -{ - if (m_model == model) { - return; - } - - qDeleteAll( m_model ); - m_model = model; - emit modelChanged(model); -} - -AssistantPopup::AssistantPopup() -// main window as parent to use maximal space available in worst case - : QQuickWidget(ICore::self()->uiController()->activeMainWindow()) - , m_config(new AssistantPopupConfig(this)) - , m_firstLayoutCompleted(false) -{ - setAttribute(Qt::WA_ShowWithoutActivating); - - rootContext()->setContextProperty(QStringLiteral("config"), m_config); - - setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kdevelop/assistantpopup.qml")))); - if (!rootObject()) { - qWarning() << "Failed to load assistant markup! The assistant will not work."; - } else { - connect(rootObject(), &QQuickItem::widthChanged, this, &AssistantPopup::updateLayout); - connect(rootObject(), &QQuickItem::heightChanged, this, &AssistantPopup::updateLayout); - } - - for (int i = Qt::Key_0; i <= Qt::Key_9; ++i) { - m_shortcuts.append(new QShortcut(ASSISTANT_MODIFIER + i, this)); - } - setActive(false); - - connect(qApp, &QApplication::applicationStateChanged, this, [this]{ setActive(false); }); -} - -void AssistantPopup::reset(KTextEditor::View* view, const IAssistant::Ptr& assistant) -{ - setView(view); - setAssistant(assistant); - updateState(); -} - -void AssistantPopup::setView(KTextEditor::View* view) -{ - if (m_view == view) { - return; - } - - setActive(false); - - if (m_view) { - m_view->removeEventFilter(this); - disconnect(m_view.data(), &KTextEditor::View::verticalScrollPositionChanged, - this, &AssistantPopup::updatePosition); - } - m_view = view; - m_config->setViewSize(m_view ? m_view->size() : QSize()); - if (m_view) { - m_view->installEventFilter(this); - connect(m_view.data(), &KTextEditor::View::verticalScrollPositionChanged, - this, &AssistantPopup::updatePosition); - } -} - -void AssistantPopup::setAssistant(const IAssistant::Ptr& assistant) -{ - if (m_assistant == assistant) { - return; - } - - if (m_assistant) { - disconnect(m_assistant.data(), &IAssistant::hide, this, &AssistantPopup::hideAssistant); - disconnect(m_assistant.data(), &IAssistant::actionsChanged, this, &AssistantPopup::updateState); - } - m_assistant = assistant; - if (m_assistant) { - connect(m_assistant.data(), &IAssistant::hide, this, &AssistantPopup::hideAssistant); - connect(m_assistant.data(), &IAssistant::actionsChanged, this, &AssistantPopup::updateState); - } else { - hide(); - } -} - -void AssistantPopup::setActive(bool active) -{ - m_config->setActive(active); - foreach (auto shortcut, m_shortcuts) { - shortcut->setEnabled(active); - } -} - -bool AssistantPopup::eventFilter(QObject* object, QEvent* event) -{ - Q_UNUSED(object); - - if (!m_view || (object != m_view.data())) - return false; - - if (event->type() == QEvent::Resize) { - updateLayout(); - } else if (event->type() == QEvent::Hide) { - executeHideAction(); - } else if (event->type() == QEvent::KeyPress) { - auto keyEvent = static_cast(event); - if (keyEvent->modifiers() == ASSISTANT_MODIFIER) { - setActive(true); - } - if (keyEvent->key() == Qt::Key_Escape) { - executeHideAction(); - } - } else if (event->type() == QEvent::KeyRelease) { - auto keyEvent = static_cast(event); - if (keyEvent->modifiers() == ASSISTANT_MODIFIER || keyEvent->key() == ASSISTANT_MOD_KEY) { - setActive(false); - } - } - return false; -} - -void AssistantPopup::updatePosition(KTextEditor::View* view, const KTextEditor::Cursor& newPos) -{ - static const int MARGIN = 12; - - if (newPos.isValid() && newPos.line() == 0) { - // the position is not going to change; don't waste time - return; - } - - auto editorGeometry = textWidgetGeometry(view); - const auto startCursorCoordinate = view->cursorToCoordinate(KTextEditor::Cursor(0, 0)); - - // algorithm for popup positioning: - // if we are scrolled to the top: show at bottom - // else: - // if: current cursor position is in upper half => show at bottom - // else: show at top - const bool showAtBottom = startCursorCoordinate.y() == 0 ? true : - view->cursorPositionCoordinates().y() < view->height()/2; - const QPoint targetLocation = showAtBottom ? - parentWidget()->mapFromGlobal(view->mapToGlobal(editorGeometry.bottomRight() - + QPoint(-width() - MARGIN, -MARGIN - height()))) : - parentWidget()->mapFromGlobal(view->mapToGlobal(editorGeometry.topRight() - + QPoint(-width() - MARGIN, MARGIN))); - if (pos() == targetLocation) { - return; - } - - Sublime::HoldUpdates hold(ICore::self()->uiController()->activeMainWindow()); - move(targetLocation); -} - -IAssistant::Ptr AssistantPopup::assistant() const -{ - return m_assistant; -} - -void AssistantPopup::executeHideAction() -{ - if ( isVisible() ) { - m_assistant->doHide(); - } -} - -void AssistantPopup::hideAssistant() -{ - reset(nullptr, {}); // indirectly calls hide() -} - -void AssistantPopup::updateLayout() -{ - if ( !m_view ) { - return; - } - - m_config->setViewSize(m_view->size()); - // https://bugreports.qt.io/browse/QTBUG-44876 - resize(rootObject()->width(), rootObject()->height()); - updatePosition(m_view, KTextEditor::Cursor::invalid()); - - // HACK: QQuickWidget is corrupted due to above resize on the first show - if (!m_firstLayoutCompleted) { - hide(); - show(); - m_firstLayoutCompleted = true; - } -} - -void AssistantPopup::updateState() -{ - if (!m_assistant || m_assistant->actions().isEmpty() || !m_view) { - hide(); - return; - } - - auto curShortcut = m_shortcuts.constBegin(); - auto hideAction = new QAction(i18n("Hide"), this); - connect(*curShortcut, &QShortcut::activated, hideAction, &QAction::trigger); - connect(hideAction, &QAction::triggered, this, &AssistantPopup::executeHideAction); - - QList items; - foreach (IAssistantAction::Ptr action, m_assistant->actions()) { - QAction* asQAction = action->toKAction(); - items << asQAction; - asQAction->setParent(this); - //For some reason, QAction's setShortcut does nothing, so we manage with QShortcut - if (++curShortcut != m_shortcuts.constEnd()) { - connect(*curShortcut, &QShortcut::activated, asQAction, &QAction::trigger); - } - connect(action.data(), SIGNAL(executed(IAssistantAction*)), hideAction, SLOT(trigger())); - } - items << hideAction; - - auto view = ICore::self()->documentController()->activeTextDocumentView(); - m_config->setColorsFromView(view); - m_config->setModel(items); - m_config->setTitle(m_assistant->title()); - setActive(false); - - show(); -} - diff --git a/shell/assistantpopup.qml b/shell/assistantpopup.qml deleted file mode 100644 --- a/shell/assistantpopup.qml +++ /dev/null @@ -1,89 +0,0 @@ -/* - Copyright 2014 Sven Brauch - Copyright 2014 Kevin Funk - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2 as published by the Free Software Foundation. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -// This file provides the whole assistant, including title and buttons. - -import QtQuick 2.2 - -Rectangle { - id: root - - readonly property int vSpacing: 4 - readonly property int hSpacing: 4 - readonly property real itemsWidth: { - var totalWidth = title.width; - for (var i = 0; i < items.count; ++i) { - totalWidth += items.itemAt(i).width; - } - return totalWidth + (items.count + 2) * hSpacing; - } - readonly property bool useVerticalLayout: config.viewSize.width * 0.90 < itemsWidth - - // QQuickWidget crashes if either of these is zero - // Use ceil to ensure the widget always fits the non-integral content size - width: Math.ceil(Math.max(hSpacing, mainFlow.width + hSpacing * 2)) - height: Math.ceil(Math.max(vSpacing, mainFlow.height + vSpacing * 2)) - - border.width: 1 - border.color: Qt.lighter(config.foreground) - gradient: Gradient { - GradientStop { position: 0.0; color: Qt.lighter(config.background) } - GradientStop { position: 1.0; color: config.background } - } - - Flow { - id: mainFlow - - anchors { - centerIn: parent - } - - flow: root.useVerticalLayout ? Flow.TopToBottom : Flow.LeftToRight - spacing: root.useVerticalLayout ? root.vSpacing : root.hSpacing - - Text { - id: title - - color: config.foreground - font.bold: true - text: config.title - } - - - Repeater { - id: items - objectName: "items" - - y: 5 - model: config.model - - AssistantButton { - text: modelData.text - highlighted: config.active - // what is displayed in the hotkey field of the button - button: index == items.model.length - 1 ? 0 : index + 1 - foreground: config.foreground - background: config.background - highlight: config.highlight - - onTriggered: { modelData.trigger() } - } - } - } -} diff --git a/shell/uicontroller.h b/shell/uicontroller.h --- a/shell/uicontroller.h +++ b/shell/uicontroller.h @@ -85,8 +85,6 @@ /*! @p status must implement KDevelop::IStatus */ void registerStatus(QObject* status) override; - void popUpAssistant(const KDevelop::IAssistant::Ptr& assistant) override; - void showErrorMessage(const QString& message, int timeout) override; /// Returns list of available view factories together with their ToolDocuments. @@ -112,8 +110,6 @@ void slotAreaChanged(Sublime::Area* area); void slotActiveToolViewChanged(Sublime::View* view); - void hideAssistant() override; - private: void addToolViewIfWanted(IToolViewFactory* factory, Sublime::ToolDocument* doc, diff --git a/shell/uicontroller.cpp b/shell/uicontroller.cpp --- a/shell/uicontroller.cpp +++ b/shell/uicontroller.cpp @@ -49,7 +49,6 @@ #include "partdocument.h" #include "textdocument.h" #include "documentcontroller.h" -#include "assistantpopup.h" #include #include "workingsetcontroller.h" #include "workingsets/workingset.h" @@ -146,8 +145,6 @@ QPointer activeSublimeWindow; bool areasRestored; - /// Currently shown assistant popup. - QPointer currentShownAssistant; /// QWidget implementing IToolViewActionListener interface, or null QPointer activeActionListener; QTimer m_assistantTimer; @@ -722,35 +719,6 @@ QMetaObject::invokeMethod(mw, "showErrorMessage", Q_ARG(QString, message), Q_ARG(int, timeout)); } -void UiController::hideAssistant() -{ - if (d->currentShownAssistant) { - d->currentShownAssistant->hide(); - } -} - -void UiController::popUpAssistant(const KDevelop::IAssistant::Ptr& assistant) -{ - if(!assistant) - return; - - Sublime::View* view = d->activeSublimeWindow->activeView(); - if( !view ) - { - qCDebug(SHELL) << "no active view in mainwindow"; - return; - } - - auto editorView = qobject_cast(view->widget()); - Q_ASSERT(editorView); - if (editorView) { - if ( !d->currentShownAssistant ) { - d->currentShownAssistant = new AssistantPopup; - } - d->currentShownAssistant->reset(editorView, assistant); - } -} - const QHash< IToolViewFactory*, Sublime::ToolDocument* >& UiController::factoryDocuments() const { return d->factoryDocuments;