From f870446677a56a88221ddcc80df4840fbd6734a8 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 15 Jun 2017 14:34:11 +0200 Subject: [PATCH] Add Locator to extra editor windows And open a popup if other windows are active. That way we avoid switching to the main window. Change-Id: Ia6d8d3fb4361ac31e406356d40056a2c0b79d114 Reviewed-by: David Schulz --- .../coreplugin/editormanager/editorwindow.cpp | 18 +++ src/plugins/coreplugin/locator/locator.cpp | 22 ++- src/plugins/coreplugin/locator/locator.h | 5 + .../coreplugin/locator/locatormanager.cpp | 37 +++-- .../coreplugin/locator/locatormanager.h | 2 +- .../coreplugin/locator/locatorwidget.cpp | 145 +++++++++++++++--- .../coreplugin/locator/locatorwidget.h | 20 ++- 7 files changed, 203 insertions(+), 46 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/editorwindow.cpp b/src/plugins/coreplugin/editormanager/editorwindow.cpp index 38aca997058..69673172038 100644 --- a/src/plugins/coreplugin/editormanager/editorwindow.cpp +++ b/src/plugins/coreplugin/editormanager/editorwindow.cpp @@ -28,9 +28,14 @@ #include "editorarea.h" #include "editormanager_p.h" +#include #include #include +#include +#include +#include +#include #include namespace Core { @@ -46,6 +51,14 @@ EditorWindow::EditorWindow(QWidget *parent) : setLayout(layout); layout->addWidget(m_area); setFocusProxy(m_area); + auto statusBar = new QStatusBar; + layout->addWidget(statusBar); + auto splitter = new NonResizingSplitter(statusBar); + splitter->setChildrenCollapsible(false); + statusBar->addPermanentWidget(splitter, 10); + auto locatorWidget = createStaticLocatorWidget(Locator::instance()); + splitter->addWidget(locatorWidget); + splitter->addWidget(new QWidget); setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_QuitOnClose, false); // don't prevent Qt Creator from closing resize(QSize(800, 600)); @@ -61,6 +74,11 @@ EditorWindow::EditorWindow(QWidget *parent) : deleteLater(); }); updateWindowTitle(); + + // register locator widget for this window + auto agg = new Aggregation::Aggregate; + agg->add(this); + agg->add(locatorWidget); } EditorWindow::~EditorWindow() diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index 3fd604bd7ca..5f0bfaf6a47 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -86,6 +86,11 @@ Locator::~Locator() qDeleteAll(m_customFilters); } +Locator *Locator::instance() +{ + return m_instance; +} + void Locator::initialize(CorePlugin *corePlugin, const QStringList &, QString *) { m_corePlugin = corePlugin; @@ -103,15 +108,14 @@ void Locator::initialize(CorePlugin *corePlugin, const QStringList &, QString *) ActionContainer *mtools = ActionManager::actionContainer(Constants::M_TOOLS); mtools->addAction(cmd); - auto locatorWidget = new LocatorWidget(this); - new LocatorPopup(locatorWidget, locatorWidget); // child of locatorWidget + m_locatorWidget = createStaticLocatorWidget(this); StatusBarWidget *view = new StatusBarWidget; - view->setWidget(locatorWidget); + view->setWidget(m_locatorWidget); view->setContext(Context("LocatorWidget")); view->setPosition(StatusBarWidget::First); m_corePlugin->addAutoReleasedObject(view); - new LocatorManager(locatorWidget); + new LocatorManager(this); m_openDocumentsFilter = new OpenDocumentsFilter; m_corePlugin->addObject(m_openDocumentsFilter); @@ -135,6 +139,11 @@ void Locator::initialize(CorePlugin *corePlugin, const QStringList &, QString *) void Locator::extensionsInitialized() { + // register locator widget for main window + auto agg = new Aggregation::Aggregate; + agg->add(ICore::mainWindow()); + agg->add(m_locatorWidget); + m_filters = ExtensionSystem::PluginManager::getObjects(); Utils::sort(m_filters, [](const ILocatorFilter *first, const ILocatorFilter *second) -> bool { if (first->priority() != second->priority()) @@ -341,6 +350,11 @@ void Locator::setRefreshInterval(int interval) m_refreshTimer.start(); } +LocatorWidget *Locator::mainLocatorWidget() +{ + return m_instance->m_locatorWidget; +} + void Locator::refresh(QList filters) { if (filters.isEmpty()) diff --git a/src/plugins/coreplugin/locator/locator.h b/src/plugins/coreplugin/locator/locator.h index c2431b99a04..af5bbca7240 100644 --- a/src/plugins/coreplugin/locator/locator.h +++ b/src/plugins/coreplugin/locator/locator.h @@ -43,6 +43,7 @@ class CorePlugin; class OpenDocumentsFilter; class FileSystemFilter; class LocatorSettingsPage; +class LocatorWidget; class ExternalToolsFilter; class Locator : public QObject @@ -53,6 +54,8 @@ public: Locator(); ~Locator(); + static Locator *instance(); + void initialize(CorePlugin *corePlugin, const QStringList &arguments, QString *errorMessage); void extensionsInitialized(); bool delayedInitialize(); @@ -63,6 +66,7 @@ public: void setCustomFilters(QList f); int refreshInterval(); void setRefreshInterval(int interval); + static LocatorWidget *mainLocatorWidget(); signals: void filtersChanged(); @@ -89,6 +93,7 @@ private: ExecuteFilter *m_executeFilter; CorePlugin *m_corePlugin = nullptr; ExternalToolsFilter *m_externalToolsFilter; + LocatorWidget *m_locatorWidget; }; } // namespace Internal diff --git a/src/plugins/coreplugin/locator/locatormanager.cpp b/src/plugins/coreplugin/locator/locatormanager.cpp index 5e65c4f58a3..54b37f337bb 100644 --- a/src/plugins/coreplugin/locator/locatormanager.cpp +++ b/src/plugins/coreplugin/locator/locatormanager.cpp @@ -29,29 +29,45 @@ #include "locator.h" #include "locatorwidget.h" +#include +#include #include #include +using namespace Core::Internal; + namespace Core { -static Internal::LocatorWidget *m_locatorWidget = 0; - -LocatorManager::LocatorManager(Internal::LocatorWidget *locatorWidget) - : QObject(locatorWidget) +LocatorManager::LocatorManager(QObject *parent) + : QObject(parent) { - m_locatorWidget = locatorWidget; +} + +static LocatorWidget *locatorWidget() +{ + static QPointer popup; + QWidget *window = ICore::dialogParent()->window(); + if (auto *widget = Aggregation::query(window)) { + if (popup) + popup->close(); + return widget; + } + if (!popup) { + popup = createLocatorPopup(Locator::instance(), window); + popup->show(); + } + return popup->inputWidget(); } void LocatorManager::showFilter(ILocatorFilter *filter) { QTC_ASSERT(filter, return); - QTC_ASSERT(m_locatorWidget, return); QString searchText = tr(""); - const QString currentText = m_locatorWidget->currentText().trimmed(); + const QString currentText = locatorWidget()->currentText().trimmed(); // add shortcut string at front or replace existing shortcut string if (!currentText.isEmpty()) { searchText = currentText; - foreach (ILocatorFilter *otherfilter, Internal::Locator::filters()) { + foreach (ILocatorFilter *otherfilter, Locator::filters()) { if (currentText.startsWith(otherfilter->shortcutString() + QLatin1Char(' '))) { searchText = currentText.mid(otherfilter->shortcutString().length() + 1); break; @@ -66,8 +82,7 @@ void LocatorManager::showFilter(ILocatorFilter *filter) void LocatorManager::show(const QString &text, int selectionStart, int selectionLength) { - QTC_ASSERT(m_locatorWidget, return); - m_locatorWidget->showText(text, selectionStart, selectionLength); + locatorWidget()->showText(text, selectionStart, selectionLength); } -} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/locator/locatormanager.h b/src/plugins/coreplugin/locator/locatormanager.h index 0f020e4c2f7..65079ee7862 100644 --- a/src/plugins/coreplugin/locator/locatormanager.h +++ b/src/plugins/coreplugin/locator/locatormanager.h @@ -40,7 +40,7 @@ class CORE_EXPORT LocatorManager : public QObject Q_OBJECT public: - LocatorManager(Internal::LocatorWidget *locatorWidget); + LocatorManager(QObject *parent = 0); static void showFilter(ILocatorFilter *filter); static void show(const QString &text, int selectionStart = -1, int selectionLength = 0); diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 2b513367c54..61282cfb85b 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -49,7 +49,9 @@ #include #include +#include #include +#include #include #include #include @@ -112,6 +114,28 @@ public: void showCurrentItemToolTip(); void keyPressEvent(QKeyEvent *event); + bool eventFilter(QObject *watched, QEvent *event); +}; + +class TopLeftLocatorPopup : public LocatorPopup +{ +public: + TopLeftLocatorPopup(LocatorWidget *locatorWidget) + : LocatorPopup(locatorWidget, locatorWidget) {} + +protected: + void updateGeometry() override; + void inputLostFocus() override; +}; + +class CenteredLocatorPopup : public LocatorPopup +{ +public: + CenteredLocatorPopup(LocatorWidget *locatorWidget, QWidget *parent) + : LocatorPopup(locatorWidget, parent) {} + +protected: + void updateGeometry() override; }; // =========== LocatorModel =========== @@ -226,6 +250,8 @@ CompletionList::CompletionList(QWidget *parent) const QStyleOptionViewItem &option = viewOptions(); const QSize shint = itemDelegate()->sizeHint(option, QModelIndex()); setFixedHeight(shint.height() * 17 + frameWidth() * 2); + + installEventFilter(this); } void CompletionList::setModel(QAbstractItemModel *newModel) @@ -241,20 +267,41 @@ void CompletionList::setModel(QAbstractItemModel *newModel) } } -void LocatorPopup::resize() +void LocatorPopup::updateGeometry() { - static const int MIN_WIDTH = 730; - const QSize windowSize = m_window ? m_window->size() : QSize(MIN_WIDTH, 0); - - const int width = qMax(MIN_WIDTH, windowSize.width() * 2 / 3); - m_preferredSize = QSize(width, sizeHint().height()); - QWidget::resize(m_preferredSize); m_tree->resizeHeaders(); } -QSize LocatorPopup::preferredSize() const +void TopLeftLocatorPopup::updateGeometry() { - return m_preferredSize; + QTC_ASSERT(parentWidget(), return); + const QSize size = preferredSize(); + const QRect rect(parentWidget()->mapToGlobal(QPoint(0, -size.height())), size); + setGeometry(rect); + LocatorPopup::updateGeometry(); +} + +void CenteredLocatorPopup::updateGeometry() +{ + QTC_ASSERT(parentWidget(), return); + const QSize size = preferredSize(); + const QSize parentSize = parentWidget()->size(); + const QPoint pos = parentWidget()->mapToGlobal({(parentSize.width() - size.width()) / 2, + parentSize.height() / 2 - size.height()}); + QRect rect(pos, size); + // invisible widget doesn't have the right screen set yet, so use the parent widget to + // check for available geometry + const QRect available = QApplication::desktop()->availableGeometry(parentWidget()); + if (rect.right() > available.right()) + rect.moveRight(available.right()); + if (rect.bottom() > available.bottom()) + rect.moveBottom(available.bottom()); + if (rect.top() < available.top()) + rect.moveTop(available.top()); + if (rect.left() < available.left()) + rect.moveLeft(available.left()); + setGeometry(rect); + LocatorPopup::updateGeometry(); } void LocatorPopup::updateWindow() @@ -271,25 +318,36 @@ void LocatorPopup::updateWindow() bool LocatorPopup::event(QEvent *event) { - if (event->type() == QEvent::ParentChange) + if (event->type() == QEvent::ParentChange) { updateWindow(); + } else if (event->type() == QEvent::Show) + updateGeometry(); return QWidget::event(event); } bool LocatorPopup::eventFilter(QObject *watched, QEvent *event) { if (watched == m_window && event->type() == QEvent::Resize) - resize(); + updateGeometry(); return QWidget::eventFilter(watched, event); } -void LocatorPopup::showPopup() +QSize LocatorPopup::preferredSize() +{ + static const int MIN_WIDTH = 730; + const QSize windowSize = m_window ? m_window->size() : QSize(MIN_WIDTH, 0); + + const int width = qMax(MIN_WIDTH, windowSize.width() * 2 / 3); + return QSize(width, sizeHint().height()); +} + +void TopLeftLocatorPopup::inputLostFocus() +{ + hide(); +} + +void LocatorPopup::inputLostFocus() { - QTC_ASSERT(parentWidget(), return); - const QSize size = preferredSize(); - const QRect rect(parentWidget()->mapToGlobal(QPoint(0, -size.height())), size); - setGeometry(rect); - show(); } void CompletionList::resizeHeaders() @@ -300,10 +358,9 @@ void CompletionList::resizeHeaders() LocatorPopup::LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent) : QWidget(parent), - m_tree(new CompletionList(this)) + m_tree(new CompletionList(this)), + m_inputWidget(locatorWidget) { - setWindowFlags(Qt::ToolTip); - m_tree->setFrameStyle(QFrame::NoFrame); m_tree->setModel(locatorWidget->model()); @@ -315,8 +372,9 @@ LocatorPopup::LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent) layout->addWidget(m_tree); connect(locatorWidget, &LocatorWidget::parentChanged, this, &LocatorPopup::updateWindow); - connect(locatorWidget, &LocatorWidget::showPopup, this, &LocatorPopup::showPopup); - connect(locatorWidget, &LocatorWidget::hidePopup, this, &LocatorPopup::hide); + connect(locatorWidget, &LocatorWidget::showPopup, this, &LocatorPopup::show); + connect(locatorWidget, &LocatorWidget::hidePopup, this, &LocatorPopup::close); + connect(locatorWidget, &LocatorWidget::lostFocus, this, &LocatorPopup::inputLostFocus); connect(locatorWidget, &LocatorWidget::selectRow, m_tree, [this](int row) { m_tree->setCurrentIndex(m_tree->model()->index(row, 0)); }); @@ -331,7 +389,7 @@ LocatorPopup::LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent) locatorWidget->scheduleAcceptEntry(index); }); - resize(); + updateGeometry(); } CompletionList *LocatorPopup::completionList() const @@ -339,6 +397,11 @@ CompletionList *LocatorPopup::completionList() const return m_tree; } +LocatorWidget *LocatorPopup::inputWidget() const +{ + return m_inputWidget; +} + void LocatorPopup::focusOutEvent(QFocusEvent *event) { if (event->reason() == Qt::ActiveWindowFocusReason) hide(); @@ -402,6 +465,22 @@ void CompletionList::keyPressEvent(QKeyEvent *event) Utils::TreeView::keyPressEvent(event); } +bool CompletionList::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == this && event->type() == QEvent::ShortcutOverride) { + QKeyEvent *ke = static_cast(event); + switch (ke->key()) { + case Qt::Key_Escape: + if (!ke->modifiers()) { + event->accept(); + return true; + } + break; + } + } + return Utils::TreeView::eventFilter(watched, event); +} + // =========== LocatorWidget =========== LocatorWidget::LocatorWidget(Locator *locator) : @@ -576,7 +655,7 @@ bool LocatorWidget::eventFilter(QObject *obj, QEvent *event) } } } else if (obj == m_fileLineEdit && event->type() == QEvent::FocusOut) { - emit hidePopup(); + emit lostFocus(); } else if (obj == m_fileLineEdit && event->type() == QEvent::FocusIn) { QFocusEvent *fev = static_cast(event); if (fev->reason() != Qt::ActiveWindowFocusReason) @@ -796,5 +875,23 @@ void LocatorWidget::addSearchResults(int firstIndex, int endIndex) } } +LocatorWidget *createStaticLocatorWidget(Locator *locator) +{ + auto widget = new LocatorWidget(locator); + auto popup = new TopLeftLocatorPopup(widget); // owned by widget + popup->setWindowFlags(Qt::ToolTip); + return widget; +} + +LocatorPopup *createLocatorPopup(Locator *locator, QWidget *parent) +{ + auto widget = new LocatorWidget(locator); + auto popup = new CenteredLocatorPopup(widget, parent); + popup->layout()->addWidget(widget); + popup->setWindowFlags(Qt::Popup); + popup->setAttribute(Qt::WA_DeleteOnClose); + return popup; +} + } // namespace Internal } // namespace Core diff --git a/src/plugins/coreplugin/locator/locatorwidget.h b/src/plugins/coreplugin/locator/locatorwidget.h index 29fa810ea95..3f42d05a3aa 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.h +++ b/src/plugins/coreplugin/locator/locatorwidget.h @@ -64,6 +64,7 @@ public: signals: void showCurrentItemToolTip(); + void lostFocus(); void hidePopup(); void selectRow(int row); void handleKey(QKeyEvent *keyEvent); // only use with DirectConnection, event is deleted @@ -109,21 +110,28 @@ public: LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent = 0); CompletionList *completionList() const; + LocatorWidget *inputWidget() const; void focusOutEvent (QFocusEvent *event) override; - void resize(); - QSize preferredSize() const; bool event(QEvent *event) override; bool eventFilter(QObject *watched, QEvent *event) override; +protected: + QSize preferredSize(); + virtual void updateGeometry(); + virtual void inputLostFocus(); + + QPointer m_window; + private: - void showPopup(); + void updateWindow(); CompletionList *m_tree; - QSize m_preferredSize; - QPointer m_window; - void updateWindow(); + LocatorWidget *m_inputWidget; }; +LocatorWidget *createStaticLocatorWidget(Locator *locator); +LocatorPopup *createLocatorPopup(Locator *locator, QWidget *parent); + } // namespace Internal } // namespace Core