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 <david.schulz@qt.io>
This commit is contained in:
Eike Ziller
2017-06-15 14:34:11 +02:00
parent 38296f6acc
commit f870446677
7 changed files with 203 additions and 46 deletions

View File

@@ -28,9 +28,14 @@
#include "editorarea.h"
#include "editormanager_p.h"
#include <aggregation/aggregate.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/locator/locator.h>
#include <coreplugin/locator/locatorwidget.h>
#include <coreplugin/statusbarmanager.h>
#include <QStatusBar>
#include <QVBoxLayout>
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()

View File

@@ -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<ILocatorFilter>();
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<ILocatorFilter *> filters)
{
if (filters.isEmpty())

View File

@@ -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<ILocatorFilter *> 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

View File

@@ -29,29 +29,45 @@
#include "locator.h"
#include "locatorwidget.h"
#include <aggregation/aggregate.h>
#include <coreplugin/icore.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/qtcassert.h>
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<LocatorPopup> popup;
QWidget *window = ICore::dialogParent()->window();
if (auto *widget = Aggregation::query<LocatorWidget>(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("<type here>");
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

View File

@@ -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);

View File

@@ -49,7 +49,9 @@
#include <utils/stylehelper.h>
#include <utils/utilsicons.h>
#include <QApplication>
#include <QColor>
#include <QDesktopWidget>
#include <QFileInfo>
#include <QTimer>
#include <QEvent>
@@ -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<QKeyEvent *>(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<QFocusEvent *>(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

View File

@@ -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<QWidget> m_window;
private:
void showPopup();
void updateWindow();
CompletionList *m_tree;
QSize m_preferredSize;
QPointer<QWidget> m_window;
void updateWindow();
LocatorWidget *m_inputWidget;
};
LocatorWidget *createStaticLocatorWidget(Locator *locator);
LocatorPopup *createLocatorPopup(Locator *locator, QWidget *parent);
} // namespace Internal
} // namespace Core