浏览代码

UnitedEntry: fix the popup hiding input method issue on macOS

Le Tan 3 年之前
父节点
当前提交
e0b07b8aba

+ 5 - 0
.gitignore

@@ -6,3 +6,8 @@ compile_flags.txt
 .cache
 .tasks
 .vimspector.json
+GPATH
+GRTAGS
+GTAGS
+aqtinstall.log
+tags

+ 0 - 33
scripts/coc_update.cmd

@@ -1,33 +0,0 @@
-@echo off
-rem Update .ccls project file for ccls LPS and compile_flags.txt for clangd
-
-if "%~1"=="" (
-    echo missing argument: the location of Qt's include directory
-    EXIT /B 0
-)
-
-set qt_inc=%~1
-set qt_inc=%qt_inc:\=\\%
-
-(
-    echo clang
-    echo -fcxx-exceptions
-    echo -std=c++14
-    echo -Isrc\\core
-    echo -Isrc
-    echo -Ilibs\\vtextedit\\src\\editor\\include
-    echo -Ilibs\\vtitlebar\\src
-    echo -I%qt_inc%
-    echo -I%qt_inc%\\QtCore
-    echo -I%qt_inc%\\QtWebEngineWidgets
-    echo -I%qt_inc%\\QtSvg
-    echo -I%qt_inc%\\QtPrintSupport
-    echo -I%qt_inc%\\QtWidgets
-    echo -I%qt_inc%\\QtWebEngineCore
-    echo -I%qt_inc%\\QtGui
-    echo -I%qt_inc%\\QtWebChannel
-    echo -I%qt_inc%\\QtNetwork
-    echo -I%qt_inc%\\QtTest
-) > ".ccls"
-
-copy /Y .ccls compile_flags.txt

+ 0 - 30
scripts/coc_update.sh

@@ -1,30 +0,0 @@
-#!/bin/sh
-if [ -n "$1" ]; then
-    echo Qt include directory: $1
-else
-    echo Please specify the Qt include directory.
-    exit
-fi
-
-ccls_file=".ccls"
-
-echo clang > $ccls_file
-echo -fcxx-exceptions >> $ccls_file
-echo -std=c++14 >> $ccls_file
-echo -Isrc/core >> $ccls_file
-echo -Isrc >> $ccls_file
-echo -Ilibs/vtextedit/src/editor/include >> $ccls_file
-echo -Ilibs/vtitlebar/src >> $ccls_file
-echo -I$1 >> $ccls_file
-echo -I$1/QtCore >> $ccls_file
-echo -I$1/QtWebEngineWidgets >> $ccls_file
-echo -I$1/QtSvg >> $ccls_file
-echo -I$1/QtPrintSupport >> $ccls_file
-echo -I$1/QtWidgets >> $ccls_file
-echo -I$1/QtWebEngineCore >> $ccls_file
-echo -I$1/QtGui >> $ccls_file
-echo -I$1/QtWebChannel >> $ccls_file
-echo -I$1/QtNetwork >> $ccls_file
-echo -I$1/QtTest >> $ccls_file
-
-cp -f .ccls compile_flags.txt

+ 1 - 0
src/data/core/core.qrc

@@ -10,6 +10,7 @@
         <file>icons/notebook_menu.svg</file>
         <file>icons/task_menu.svg</file>
         <file>icons/united_entry.svg</file>
+        <file>icons/busy.svg</file>
         <file>icons/advanced_settings.svg</file>
         <file>icons/new_notebook_from_folder.svg</file>
         <file>icons/discard_editor.svg</file>

文件差异内容过多而无法显示
+ 1 - 0
src/data/core/icons/busy.svg


+ 4 - 44
src/unitedentry/entrypopup.cpp

@@ -12,9 +12,6 @@ EntryPopup::EntryPopup(QWidget *p_parent)
     Q_ASSERT(p_parent);
     auto layout = new QVBoxLayout(this);
     Q_UNUSED(layout);
-
-    setWindowFlags(Qt::ToolTip);
-    setFocusPolicy(Qt::FocusPolicy::ClickFocus);
 }
 
 EntryPopup::~EntryPopup()
@@ -26,8 +23,6 @@ EntryPopup::~EntryPopup()
 
 void EntryPopup::setWidget(const QSharedPointer<QWidget> &p_widget)
 {
-    Q_ASSERT(p_widget);
-
     if (p_widget == m_widget) {
         return;
     }
@@ -36,11 +31,11 @@ void EntryPopup::setWidget(const QSharedPointer<QWidget> &p_widget)
         takeWidget(m_widget.data());
     }
 
-    layout()->addWidget(p_widget.data());
     m_widget = p_widget;
-    m_widget->show();
-
-    updateGeometryToContents();
+    if (m_widget) {
+        layout()->addWidget(m_widget.data());
+        m_widget->show();
+    }
 }
 
 void EntryPopup::takeWidget(QWidget *p_widget)
@@ -49,38 +44,3 @@ void EntryPopup::takeWidget(QWidget *p_widget)
     p_widget->hide();
     p_widget->setParent(nullptr);
 }
-
-void EntryPopup::showEvent(QShowEvent *p_event)
-{
-    QFrame::showEvent(p_event);
-
-    updateGeometryToContents();
-}
-
-void EntryPopup::updateGeometryToContents()
-{
-    adjustSize();
-
-    auto pa = parentWidget();
-    auto pos = pa->mapToGlobal(QPoint(0, pa->height()));
-    setGeometry(QRect(pos, preferredSize()));
-
-    if (m_widget) {
-        m_widget->updateGeometry();
-    }
-}
-
-QSize EntryPopup::preferredSize() const
-{
-    const int minWidth = 400;
-    const int minHeight = 300;
-
-    auto pa = parentWidget();
-    int w = pa->width();
-    int h = sizeHint().height();
-    if (auto win = pa->window()) {
-        w = qMax(w, qMin(win->width() - 500, 900));
-        h = qMax(h, qMin(win->height() - 500, 800));
-    }
-    return QSize(qMax(minWidth, w), qMax(h, minHeight));
-}

+ 0 - 7
src/unitedentry/entrypopup.h

@@ -16,14 +16,7 @@ namespace vnotex
 
         void setWidget(const QSharedPointer<QWidget> &p_widget);
 
-        void updateGeometryToContents();
-
-    protected:
-        void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
-
     private:
-        QSize preferredSize() const;
-
         void takeWidget(QWidget *p_widget);
 
     private:

+ 3 - 1
src/unitedentry/findunitedentry.cpp

@@ -23,7 +23,7 @@
 using namespace vnotex;
 
 FindUnitedEntry::FindUnitedEntry(const QSharedPointer<ISearchInfoProvider> &p_provider,
-                                 const UnitedEntryMgr *p_mgr,
+                                 UnitedEntryMgr *p_mgr,
                                  QObject *p_parent)
     : IUnitedEntry("find",
                    tr("Search for files in notebooks"),
@@ -343,4 +343,6 @@ void FindUnitedEntry::handleItemActivated(QTreeWidgetItem *p_item, int p_column)
 
     paras->m_searchToken = m_searchTokenOfSession;
     emit VNoteX::getInst().openFileRequested(itemPath, paras);
+
+    emit itemActivated(true, false);
 }

+ 1 - 1
src/unitedentry/findunitedentry.h

@@ -24,7 +24,7 @@ namespace vnotex
         Q_OBJECT
     public:
         FindUnitedEntry(const QSharedPointer<ISearchInfoProvider> &p_provider,
-                        const UnitedEntryMgr *p_mgr,
+                        UnitedEntryMgr *p_mgr,
                         QObject *p_parent = nullptr);
 
         void stop() Q_DECL_OVERRIDE;

+ 1 - 1
src/unitedentry/helpunitedentry.cpp

@@ -6,7 +6,7 @@
 
 using namespace vnotex;
 
-HelpUnitedEntry::HelpUnitedEntry(const UnitedEntryMgr *p_mgr, QObject *p_parent)
+HelpUnitedEntry::HelpUnitedEntry(UnitedEntryMgr *p_mgr, QObject *p_parent)
     : IUnitedEntry("help",
                    tr("Help information about United Entry"),
                    p_mgr,

+ 1 - 1
src/unitedentry/helpunitedentry.h

@@ -13,7 +13,7 @@ namespace vnotex
     {
         Q_OBJECT
     public:
-        HelpUnitedEntry(const UnitedEntryMgr *p_mgr, QObject *p_parent = nullptr);
+        HelpUnitedEntry(UnitedEntryMgr *p_mgr, QObject *p_parent = nullptr);
 
         QSharedPointer<QWidget> currentPopupWidget() const Q_DECL_OVERRIDE;
 

+ 9 - 1
src/unitedentry/iunitedentry.cpp

@@ -6,11 +6,13 @@
 
 #include <widgets/treewidget.h>
 
+#include "unitedentrymgr.h"
+
 using namespace vnotex;
 
 IUnitedEntry::IUnitedEntry(const QString &p_name,
                            const QString &p_description,
-                           const UnitedEntryMgr *p_mgr,
+                           UnitedEntryMgr *p_mgr,
                            QObject *p_parent)
     : QObject(p_parent),
       m_mgr(p_mgr),
@@ -136,3 +138,9 @@ void IUnitedEntry::handleActionCommon(Action p_act, QWidget *p_widget)
         break;
     }
 }
+
+bool IUnitedEntry::isAliasOf(const IUnitedEntry *p_entry) const
+{
+    Q_UNUSED(p_entry);
+    return false;
+}

+ 6 - 2
src/unitedentry/iunitedentry.h

@@ -28,7 +28,7 @@ namespace vnotex
 
         IUnitedEntry(const QString &p_name,
                      const QString &p_description,
-                     const UnitedEntryMgr *p_mgr,
+                     UnitedEntryMgr *p_mgr,
                      QObject *p_parent = nullptr);
 
         const QString &name() const;
@@ -46,11 +46,15 @@ namespace vnotex
 
         virtual QSharedPointer<QWidget> currentPopupWidget() const = 0;
 
+        virtual bool isAliasOf(const IUnitedEntry *p_entry) const;
+
         static void handleActionCommon(Action p_act, QWidget *p_widget);
 
     signals:
         void finished();
 
+        void itemActivated(bool p_quit, bool p_restoreFocus);
+
     protected:
         virtual void initOnFirstProcess() = 0;
 
@@ -61,7 +65,7 @@ namespace vnotex
 
         virtual void setOngoing(bool p_ongoing);
 
-        const UnitedEntryMgr *m_mgr = nullptr;
+        UnitedEntryMgr *m_mgr = nullptr;
 
     private:
         bool m_initialized = false;

+ 129 - 105
src/unitedentry/unitedentry.cpp

@@ -1,6 +1,6 @@
 #include "unitedentry.h"
 
-#include <QHBoxLayout>
+#include <QVBoxLayout>
 #include <QSizePolicy>
 #include <QAction>
 #include <QFocusEvent>
@@ -13,11 +13,11 @@
 #include <QLabel>
 #include <QFont>
 #include <QMenu>
+#include <QMainWindow>
 
 #include <widgets/lineeditwithsnippet.h>
 #include <widgets/widgetsfactory.h>
 #include <widgets/propertydefs.h>
-#include <widgets/mainwindow.h>
 #include <core/configmgr.h>
 #include <core/coreconfig.h>
 #include <core/widgetconfig.h>
@@ -34,8 +34,9 @@
 
 using namespace vnotex;
 
-UnitedEntry::UnitedEntry(QWidget *p_parent)
-    : QWidget(p_parent)
+UnitedEntry::UnitedEntry(QMainWindow *p_mainWindow)
+    : QFrame(p_mainWindow),
+      m_mainWindow(p_mainWindow)
 {
     m_processTimer = new QTimer(this);
     m_processTimer->setSingleShot(true);
@@ -45,11 +46,20 @@ UnitedEntry::UnitedEntry(QWidget *p_parent)
 
     setupUI();
 
+#if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
+    setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint);
+    setWindowModality(Qt::ApplicationModal);
+#else
+    setWindowFlags(Qt::ToolTip);
+#endif
+
     connect(qApp, &QApplication::focusChanged,
             this, &UnitedEntry::handleFocusChanged);
 
     connect(&UnitedEntryMgr::getInst(), &UnitedEntryMgr::entryFinished,
             this, &UnitedEntry::handleEntryFinished);
+    connect(&UnitedEntryMgr::getInst(), &UnitedEntryMgr::entryItemActivated,
+            this, &UnitedEntry::handleEntryItemActivated);
 }
 
 UnitedEntry::~UnitedEntry()
@@ -58,79 +68,62 @@ UnitedEntry::~UnitedEntry()
 
 void UnitedEntry::setupUI()
 {
-    auto mainLayout = new QHBoxLayout(this);
-    mainLayout->setContentsMargins(0, 0, 0, 0);
-
-    setSizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Fixed);
-
-    // Shortcut.
-    const auto shortcut = ConfigMgr::getInst().getCoreConfig().getShortcut(CoreConfig::Shortcut::UnitedEntry);
-    const QKeySequence kseq(shortcut);
-    const auto shortcutText = kseq.isEmpty() ? QString() : kseq.toString(QKeySequence::NativeText);
-    if (!kseq.isEmpty()) {
-        auto sc = WidgetUtils::createShortcut(shortcut, this, Qt::ShortcutContext::ApplicationShortcut);
-        if (sc) {
-            connect(sc, &QShortcut::activated,
-                    this, [this]() {
-                        if (m_lineEdit->hasFocus()) {
-                            return;
-                        }
-
-                        bool popupVisible = m_popup->isVisible();
-                        if (popupVisible) {
-                            // Make m_lineEdit->setFocus() work.
-                            m_popup->hide();
-                        }
-                        m_lineEdit->setFocus();
-                        if (popupVisible) {
-                            m_popup->show();
-                        }
-                    });
-        }
-    }
-    setToolTip(shortcutText.isEmpty() ? tr("United Entry") : tr("United Entry (%1)").arg(shortcutText));
+    auto mainLayout = new QVBoxLayout(this);
 
     // Line edit.
     m_lineEdit = WidgetsFactory::createLineEditWithSnippet(this);
     mainLayout->addWidget(m_lineEdit);
-    m_lineEdit->setToolTip(QString());
-    m_lineEdit->setPlaceholderText(shortcutText.isEmpty() ? tr("Type to command") : tr("Type to command (%1)").arg(shortcutText));
+    m_lineEdit->setPlaceholderText(tr("Type to command"));
     m_lineEdit->setClearButtonEnabled(true);
-    m_lineEdit->setSizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Fixed);
+    m_lineEdit->installEventFilter(this);
     connect(m_lineEdit, &QLineEdit::textChanged,
             m_processTimer, QOverload<>::of(&QTimer::start));
     setFocusProxy(m_lineEdit);
 
+    setupActions();
+
     // Popup.
     m_popup = new EntryPopup(this);
+    mainLayout->addWidget(m_popup);
     m_popup->installEventFilter(this);
-    m_popup->hide();
 
-    setupIcons();
+    hide();
 }
 
-void UnitedEntry::setupIcons()
+QAction *UnitedEntry::getTriggerAction()
 {
     const auto &themeMgr = VNoteX::getInst().getThemeMgr();
     const auto fg = themeMgr.paletteColor("widgets#unitedentry#icon#fg");
-    // Use QIcon::Disabled as the busy state.
-    const auto busyFg = themeMgr.paletteColor("widgets#unitedentry#icon#busy#fg");
-    QVector<IconUtils::OverriddenColor> colors;
-    colors.push_back(IconUtils::OverriddenColor(fg, QIcon::Normal));
-    colors.push_back(IconUtils::OverriddenColor(busyFg, QIcon::Disabled));
 
-    const auto icon = IconUtils::fetchIcon(themeMgr.getIconFile("united_entry.svg"), colors);
-    m_iconAction = m_lineEdit->addAction(icon, QLineEdit::ActionPosition::LeadingPosition);
-    m_iconAction->setText(tr("Options"));
+    const auto icon = IconUtils::fetchIcon(themeMgr.getIconFile("united_entry.svg"), fg);
+    auto act = new QAction(icon, tr("United Entry"), this);
+    connect(act, &QAction::triggered,
+            this, &UnitedEntry::activateUnitedEntry);
+
+    const auto shortcut = ConfigMgr::getInst().getCoreConfig().getShortcut(CoreConfig::Shortcut::UnitedEntry);
+    WidgetUtils::addActionShortcut(act, shortcut, Qt::ApplicationShortcut);
+
+    return act;
+}
+
+void UnitedEntry::setupActions()
+{
+    const auto &themeMgr = VNoteX::getInst().getThemeMgr();
+    const auto fg = themeMgr.paletteColor("widgets#unitedentry#icon#fg");
+    const auto busyFg = themeMgr.paletteColor("widgets#unitedentry#icon#busy#fg");
 
     // Menu.
+    const auto menuIcon = IconUtils::fetchIcon(themeMgr.getIconFile("menu.svg"), fg);
+    m_menuIconAction = m_lineEdit->addAction(menuIcon, QLineEdit::ActionPosition::TrailingPosition);
+    m_menuIconAction->setText(tr("Options"));
+
     auto menu = WidgetsFactory::createMenu(this);
-    m_iconAction->setMenu(menu);
+    m_menuIconAction->setMenu(menu);
 
     {
         auto expandAct = menu->addAction(tr("Expand All"),
                                          this,
-                                         [this](bool checked) {
+                                         [](bool checked) {
                                             ConfigMgr::getInst().getWidgetConfig().setUnitedEntryExpandAllEnabled(checked);
                                             UnitedEntryMgr::getInst().setExpandAllEnabled(checked);
                                          });
@@ -139,12 +132,18 @@ void UnitedEntry::setupIcons()
         UnitedEntryMgr::getInst().setExpandAllEnabled(expandAct->isChecked());
     }
 
-    connect(m_iconAction, &QAction::triggered,
+    connect(m_menuIconAction, &QAction::triggered,
             this, [this]() {
-                auto pos = mapToGlobal(QPoint(0, height()));
-                auto menu = m_iconAction->menu();
+                const auto pos = QCursor::pos();
+                auto menu = m_menuIconAction->menu();
                 menu->exec(pos);
             });
+
+    // Busy.
+    const auto busyIcon = IconUtils::fetchIcon(themeMgr.getIconFile("busy.svg"), busyFg);
+    m_busyIconAction = m_lineEdit->addAction(busyIcon, QLineEdit::ActionPosition::TrailingPosition);
+    m_busyIconAction->setText(tr("Busy"));
+    m_busyIconAction->setVisible(false);
 }
 
 void UnitedEntry::activateUnitedEntry()
@@ -159,12 +158,15 @@ void UnitedEntry::activateUnitedEntry()
 
     m_activated = true;
 
-    setSizePolicy(QSizePolicy::Policy::MinimumExpanding, QSizePolicy::Policy::Fixed);
+    m_previousFocusWidget = QApplication::focusWidget();
+
+    show();
+
+    m_processTimer->stop();
+    processInput();
 
     m_lineEdit->selectAll();
     m_lineEdit->setFocus();
-
-    m_processTimer->start();
 }
 
 void UnitedEntry::deactivateUnitedEntry()
@@ -176,28 +178,7 @@ void UnitedEntry::deactivateUnitedEntry()
     m_activated = false;
     m_previousFocusWidget = nullptr;
 
-    setSizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Fixed);
-
-    m_popup->hide();
-}
-
-void UnitedEntry::handleFocusChanged(QWidget *p_old, QWidget *p_now)
-{
-    if (p_now == m_lineEdit) {
-        activateUnitedEntry();
-        if (!m_previousFocusWidget && p_old != this && !WidgetUtils::isOrAncestorOf(this, p_old)) {
-            m_previousFocusWidget = p_old;
-        }
-        return;
-    }
-
-    if (!m_activated) {
-        return;
-    }
-
-    if (!p_now || (p_now != this && !WidgetUtils::isOrAncestorOf(this, p_now))) {
-        deactivateUnitedEntry();
-    }
+    hide();
 }
 
 void UnitedEntry::keyPressEvent(QKeyEvent *p_event)
@@ -310,13 +291,13 @@ void UnitedEntry::keyPressEvent(QKeyEvent *p_event)
         break;
     }
 
-    QWidget::keyPressEvent(p_event);
+    QFrame::keyPressEvent(p_event);
 }
 
 void UnitedEntry::clear()
 {
-    m_lineEdit->setFocus();
     m_lineEdit->clear();
+    m_lineEdit->setFocus();
 }
 
 void UnitedEntry::processInput()
@@ -327,11 +308,6 @@ void UnitedEntry::processInput()
         return;
     }
 
-    if (m_iconAction->menu()->isVisible()) {
-        // Do not display the popup which will hide the menu.
-        return;
-    }
-
     if (m_lastEntry && m_lastEntry->isOngoing()) {
         m_hasPending = true;
         m_lastEntry->stop();
@@ -375,7 +351,8 @@ void UnitedEntry::processInput()
 void UnitedEntry::popupWidget(const QSharedPointer<QWidget> &p_widget)
 {
     m_popup->setWidget(p_widget);
-    m_popup->show();
+
+    m_lineEdit->setFocus();
 }
 
 const QSharedPointer<QTreeWidget> &UnitedEntry::getEntryListWidget()
@@ -399,18 +376,6 @@ QSharedPointer<QLabel> UnitedEntry::getInfoWidget(const QString &p_info)
     return EntryWidgetFactory::createLabel(p_info);
 }
 
-void UnitedEntry::resizeEvent(QResizeEvent *p_event)
-{
-    QWidget::resizeEvent(p_event);
-
-    updatePopupGeometry();
-}
-
-void UnitedEntry::updatePopupGeometry()
-{
-    m_popup->updateGeometryToContents();
-}
-
 bool UnitedEntry::filterEntryListWidgetEntries(const QString &p_name)
 {
     const auto &entryListWidget = getEntryListWidget();
@@ -445,14 +410,29 @@ void UnitedEntry::handleEntryFinished(IUnitedEntry *p_entry)
     }
 }
 
+void UnitedEntry::handleEntryItemActivated(IUnitedEntry *p_entry, bool p_quit, bool p_restoreFocus)
+{
+    if (p_entry != m_lastEntry.data()) {
+        return;
+    }
+
+    if (p_quit) {
+        if (p_restoreFocus) {
+            exitUnitedEntry();
+        } else {
+            deactivateUnitedEntry();
+        }
+    }
+}
+
 void UnitedEntry::setBusy(bool p_busy)
 {
-    m_iconAction->setEnabled(!p_busy);
+    m_busyIconAction->setVisible(p_busy);
 }
 
 bool UnitedEntry::eventFilter(QObject *p_watched, QEvent *p_event)
 {
-    if (p_watched == m_popup) {
+    if (p_watched == m_popup || p_watched == m_lineEdit) {
         if (p_event->type() == QEvent::KeyPress) {
             auto eve = static_cast<QKeyEvent *>(p_event);
             switch (eve->key()) {
@@ -463,8 +443,6 @@ bool UnitedEntry::eventFilter(QObject *p_watched, QEvent *p_event)
                 Q_FALLTHROUGH();
             case Qt::Key_Escape:
                 exitUnitedEntry();
-                // Need to call deactivateUnitedEntry() again since focusChanged is not triggered.
-                deactivateUnitedEntry();
                 return true;
 
             default:
@@ -473,7 +451,7 @@ bool UnitedEntry::eventFilter(QObject *p_watched, QEvent *p_event)
         }
     }
 
-    return QWidget::eventFilter(p_watched, p_event);
+    return QFrame::eventFilter(p_watched, p_event);
 }
 
 void UnitedEntry::exitUnitedEntry()
@@ -482,6 +460,52 @@ void UnitedEntry::exitUnitedEntry()
         // Deactivate and focus previous widget.
         m_previousFocusWidget->setFocus();
     } else {
-        VNoteX::getInst().getMainWindow()->setFocus();
+        m_mainWindow->setFocus();
+    }
+    deactivateUnitedEntry();
+}
+
+void UnitedEntry::showEvent(QShowEvent *p_event)
+{
+    QFrame::showEvent(p_event);
+
+    // Fix input method issue.
+    activateWindow();
+
+    m_lineEdit->setFocus();
+
+    updateGeometryToContents();
+}
+
+void UnitedEntry::updateGeometryToContents()
+{
+    adjustSize();
+
+    const auto winSize = m_mainWindow->size();
+    const auto sz = preferredSize();
+    auto pos = parentWidget()->mapToGlobal(QPoint((winSize.width() - sz.width()) / 2,
+                                                  (winSize.height() - sz.height()) / 2));
+    setGeometry(QRect(pos, preferredSize()));
+}
+
+QSize UnitedEntry::preferredSize() const
+{
+    const int minWidth = 400;
+    const int minHeight = 300;
+
+    const auto winSize = m_mainWindow->size();
+    int w = minWidth;
+    int h = sizeHint().height();
+    w = qMax(w, qMin(winSize.width() / 2, 900));
+    h = qMax(h, qMin(winSize.height() - 300, 800));
+    return QSize(qMax(minWidth, w), qMax(h, minHeight));
+}
+
+void UnitedEntry::handleFocusChanged(QWidget *p_old, QWidget *p_now)
+{
+    Q_UNUSED(p_old);
+    if (m_activated &&
+        (!p_now || (p_now != this && !WidgetUtils::isOrAncestorOf(this, p_now)))) {
+        deactivateUnitedEntry();
     }
 }

+ 21 - 10
src/unitedentry/unitedentry.h

@@ -1,13 +1,14 @@
 #ifndef UNITEDENTRY_H
 #define UNITEDENTRY_H
 
-#include <QWidget>
+#include <QFrame>
 #include <QSharedPointer>
 
 class QAction;
 class QTimer;
 class QTreeWidget;
 class QLabel;
+class QMainWindow;
 
 namespace vnotex
 {
@@ -15,42 +16,42 @@ namespace vnotex
     class EntryPopup;
     class IUnitedEntry;
 
-    class UnitedEntry : public QWidget
+    class UnitedEntry : public QFrame
     {
         Q_OBJECT
     public:
-        explicit UnitedEntry(QWidget *p_parent = nullptr);
+        explicit UnitedEntry(QMainWindow *p_mainWindow);
 
         ~UnitedEntry();
 
         bool eventFilter(QObject *p_watched, QEvent *p_event) Q_DECL_OVERRIDE;
 
+        QAction *getTriggerAction();
+
     protected:
         void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE;
 
-        void resizeEvent(QResizeEvent *p_event) Q_DECL_OVERRIDE;
+        void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
 
     private:
         void setupUI();
 
-        void setupIcons();
+        void setupActions();
 
         void activateUnitedEntry();
 
         void deactivateUnitedEntry();
 
-        void handleFocusChanged(QWidget *p_old, QWidget *p_now);
-
         void clear();
 
         void processInput();
 
+        void handleFocusChanged(QWidget *p_old, QWidget *p_now);
+
         const QSharedPointer<QTreeWidget> &getEntryListWidget();
 
         QSharedPointer<QLabel> getInfoWidget(const QString &p_info);
 
-        void updatePopupGeometry();
-
         void popupWidget(const QSharedPointer<QWidget> &p_widget);
 
         // Return true if there is any entry visible.
@@ -58,15 +59,25 @@ namespace vnotex
 
         void handleEntryFinished(IUnitedEntry *p_entry);
 
+        void handleEntryItemActivated(IUnitedEntry *p_entry, bool p_quit, bool p_restoreFocus);
+
         void setBusy(bool p_busy);
 
         void exitUnitedEntry();
 
+        void updateGeometryToContents();
+
+        QSize preferredSize() const;
+
+        QMainWindow *m_mainWindow = nullptr;
+
         LineEditWithSnippet *m_lineEdit = nullptr;
 
         EntryPopup *m_popup = nullptr;
 
-        QAction *m_iconAction = nullptr;
+        QAction *m_menuIconAction = nullptr;
+
+        QAction *m_busyIconAction = nullptr;
 
         bool m_activated = false;
 

+ 9 - 2
src/unitedentry/unitedentryalias.cpp

@@ -11,7 +11,7 @@ using namespace vnotex;
 UnitedEntryAlias::UnitedEntryAlias(const QString &p_name,
                                    const QString &p_description,
                                    const QString &p_value,
-                                   const UnitedEntryMgr *p_mgr,
+                                   UnitedEntryMgr *p_mgr,
                                    QObject *p_parent)
     : IUnitedEntry(p_name, p_description, p_mgr, p_parent),
       m_value(p_value)
@@ -20,7 +20,7 @@ UnitedEntryAlias::UnitedEntryAlias(const QString &p_name,
 }
 
 UnitedEntryAlias::UnitedEntryAlias(const QJsonObject &p_obj,
-                                   const UnitedEntryMgr *p_mgr,
+                                   UnitedEntryMgr *p_mgr,
                                    QObject *p_parent)
     : UnitedEntryAlias(p_obj[QStringLiteral("name")].toString(),
                        p_obj[QStringLiteral("description")].toString(),
@@ -52,6 +52,8 @@ void UnitedEntryAlias::initOnFirstProcess()
     } else {
         connect(m_realEntry, &IUnitedEntry::finished,
                 this, &IUnitedEntry::finished);
+        connect(m_realEntry, &IUnitedEntry::itemActivated,
+                this, &IUnitedEntry::itemActivated);
     }
 }
 
@@ -97,3 +99,8 @@ QSharedPointer<QWidget> UnitedEntryAlias::currentPopupWidget() const
 
     return nullptr;
 }
+
+bool UnitedEntryAlias::isAliasOf(const IUnitedEntry *p_entry) const
+{
+    return p_entry == m_realEntry;
+}

+ 4 - 2
src/unitedentry/unitedentryalias.h

@@ -19,11 +19,11 @@ namespace vnotex
         UnitedEntryAlias(const QString &p_name,
                          const QString &p_description,
                          const QString &p_value,
-                         const UnitedEntryMgr *p_mgr,
+                         UnitedEntryMgr *p_mgr,
                          QObject *p_parent = nullptr);
 
         UnitedEntryAlias(const QJsonObject &p_obj,
-                         const UnitedEntryMgr *p_mgr,
+                         UnitedEntryMgr *p_mgr,
                          QObject *p_parent = nullptr);
 
         QJsonObject toJson() const;
@@ -36,6 +36,8 @@ namespace vnotex
 
         QSharedPointer<QWidget> currentPopupWidget() const Q_DECL_OVERRIDE;
 
+        bool isAliasOf(const IUnitedEntry *p_entry) const Q_DECL_OVERRIDE;
+
     protected:
         void initOnFirstProcess() Q_DECL_OVERRIDE;
 

+ 4 - 0
src/unitedentry/unitedentrymgr.cpp

@@ -47,6 +47,10 @@ void UnitedEntryMgr::addEntry(const QSharedPointer<IUnitedEntry> &p_entry)
             this, [this]() {
                 emit entryFinished(reinterpret_cast<IUnitedEntry *>(sender()));
             });
+    connect(p_entry.data(), &IUnitedEntry::itemActivated,
+            this, [this](bool quit, bool restoreFocus) {
+                emit entryItemActivated(reinterpret_cast<IUnitedEntry *>(sender()), quit, restoreFocus);
+            });
 }
 
 QList<QSharedPointer<IUnitedEntry>> UnitedEntryMgr::getEntries() const

+ 2 - 0
src/unitedentry/unitedentrymgr.h

@@ -36,6 +36,8 @@ namespace vnotex
     signals:
         void entryFinished(IUnitedEntry *p_entry);
 
+        void entryItemActivated(IUnitedEntry *p_entry, bool p_quit, bool p_restoreFocus);
+
     private:
         explicit UnitedEntryMgr(QObject *p_parent = nullptr);
 

+ 3 - 2
src/widgets/toolbarhelper.cpp

@@ -307,8 +307,9 @@ QToolBar *ToolBarHelper::setupQuickAccessToolBar(MainWindow *p_win, QToolBar *p_
 
     // United Entry.
     {
-        auto ueEdit = new UnitedEntry(tb);
-        tb->addWidget(ueEdit);
+        // Managed by QObject.
+        auto ue = new UnitedEntry(p_win);
+        tb->addAction(ue->getTriggerAction());
     }
 
     return tb;

部分文件因为文件数量过多而无法显示