Add search help pop-up

* Support ! modifier (same as '-')
* Create reusable PopupHelpWidget as self-contained popup that can
be positioned around a parent widget and will follow the movement
and sizing of the window
* Eliminated KEEPASSXC_MAIN_WINDOW macro and replaced with
getMainWindow() function
* Add tests to cover search help show/hide
This commit is contained in:
Jonathan White 2018-11-01 21:33:27 -04:00
parent d6ffee5e99
commit 880c3aeb34
No known key found for this signature in database
GPG Key ID: 440FC65F2E0C6E01
20 changed files with 671 additions and 36 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -126,7 +126,6 @@ set(keepassx_SOURCES
gui/UnlockDatabaseWidget.cpp
gui/UnlockDatabaseDialog.cpp
gui/WelcomeWidget.cpp
gui/widgets/ElidedLabel.cpp
gui/csvImport/CsvImportWidget.cpp
gui/csvImport/CsvImportWizard.cpp
gui/csvImport/CsvParserModel.cpp
@ -154,6 +153,8 @@ set(keepassx_SOURCES
gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp
gui/dbsettings/DatabaseSettingsWidgetMasterKey.cpp
gui/settings/SettingsWidget.cpp
gui/widgets/ElidedLabel.cpp
gui/widgets/PopupHelpWidget.cpp
gui/wizard/NewDatabaseWizard.cpp
gui/wizard/NewDatabaseWizardPage.cpp
gui/wizard/NewDatabaseWizardPageMetaData.cpp

View File

@ -88,7 +88,7 @@ bool BrowserService::openDatabase(bool triggerUnlock)
}
if (triggerUnlock) {
KEEPASSXC_MAIN_WINDOW->bringToFront();
getMainWindow()->bringToFront();
m_bringToFrontRequested = true;
}
@ -901,7 +901,7 @@ void BrowserService::databaseUnlocked(DatabaseWidget* dbWidget)
{
if (dbWidget) {
if (m_bringToFrontRequested) {
KEEPASSXC_MAIN_WINDOW->lower();
getMainWindow()->lower();
m_bringToFrontRequested = false;
}
emit databaseUnlocked();

View File

@ -96,6 +96,7 @@ bool EntrySearcher::searchEntryImpl(const QString& searchString, Entry* entry)
found = !attachments.filter(term->regex).empty();
break;
default:
// Terms without a specific field try to match title, username, url, and notes
found = term->regex.match(entry->resolvePlaceholder(entry->title())).hasMatch() ||
term->regex.match(entry->resolvePlaceholder(entry->username())).hasMatch() ||
term->regex.match(entry->resolvePlaceholder(entry->url())).hasMatch() ||
@ -139,7 +140,7 @@ QList<QSharedPointer<EntrySearcher::SearchTerm> > EntrySearcher::parseSearchTerm
term->regex = Tools::convertToRegex(term->word, !mods.contains("*"), mods.contains("+"), m_caseSensitive);
// Exclude modifier
term->exclude = mods.contains("-");
term->exclude = mods.contains("-") || mods.contains("!");
// Determine the field to search
QString field = result.captured(2);

View File

@ -49,7 +49,6 @@ namespace
Application::Application(int& argc, char** argv)
: QApplication(argc, argv)
, m_mainWindow(nullptr)
#ifdef Q_OS_UNIX
, m_unixSignalNotifier(nullptr)
#endif
@ -143,16 +142,6 @@ Application::~Application()
}
}
QWidget* Application::mainWindow() const
{
return m_mainWindow;
}
void Application::setMainWindow(QWidget* mainWindow)
{
m_mainWindow = mainWindow;
}
bool Application::event(QEvent* event)
{
// Handle Apple QFileOpenEvent from finder (double click on .kdbx file)

View File

@ -37,9 +37,7 @@ class Application : public QApplication
public:
Application(int& argc, char** argv);
QWidget* mainWindow() const;
~Application() override;
void setMainWindow(QWidget* mainWindow);
bool event(QEvent* event) override;
bool isAlreadyRunning() const;
@ -60,8 +58,6 @@ private slots:
void socketReadyRead();
private:
QWidget* m_mainWindow;
#if defined(Q_OS_UNIX)
/**
* Register Unix signals such as SIGINT and SIGTERM for clean shutdown.

View File

@ -109,12 +109,17 @@ public:
const QString MainWindow::BaseWindowTitle = "KeePassXC";
MainWindow* g_MainWindow = nullptr;
MainWindow* getMainWindow() { return g_MainWindow; }
MainWindow::MainWindow()
: m_ui(new Ui::MainWindow())
, m_trayIcon(nullptr)
, m_appExitCalled(false)
, m_appExiting(false)
{
g_MainWindow = this;
m_ui->setupUi(this);
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) && !defined(QT_NO_DBUS)

View File

@ -148,8 +148,12 @@ private:
bool m_appExiting;
};
#define KEEPASSXC_MAIN_WINDOW \
(qobject_cast<Application*>(qApp) ? qobject_cast<MainWindow*>(qobject_cast<Application*>(qApp)->mainWindow()) \
: nullptr)
/**
* Return instance of MainWindow created on app load
* non-gui instances will return nullptr
*
* @return MainWindow instance or nullptr
*/
MainWindow* getMainWindow();
#endif // KEEPASSX_MAINWINDOW_H

458
src/gui/SearchHelpWidget.ui Normal file
View File

@ -0,0 +1,458 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SearchHelpWidget</class>
<widget class="QFrame" name="SearchHelpWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>249</height>
</rect>
</property>
<property name="windowTitle">
<string>Search Help</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">#SearchHelpWidget { background-color: #ffffff }</string>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Search terms are as follows: [modifiers][field:][&quot;]term[&quot;]</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_24">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Every search term must match (ie, logical AND)</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="title">
<string>Modifiers</string>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="horizontalSpacing">
<number>8</number>
</property>
<property name="verticalSpacing">
<number>8</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">!</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_7">
<property name="text">
<string>exclude term from results</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_8">
<property name="text">
<string>match term exactly</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_16">
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">*</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_15">
<property name="text">
<string>use regex in term</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">+</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="title">
<string>Fields</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>15</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>15</number>
</property>
<property name="horizontalSpacing">
<number>8</number>
</property>
<property name="verticalSpacing">
<number>5</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string notr="true">username</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string notr="true">password</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string notr="true">title</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string notr="true">url</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_5">
<property name="text">
<string notr="true">notes</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_12">
<property name="text">
<string notr="true">attribute</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_14">
<property name="text">
<string notr="true">attachment</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Term Wildcards</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="horizontalSpacing">
<number>8</number>
</property>
<property name="verticalSpacing">
<number>8</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_18">
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">*</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_19">
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">?</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_20">
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">|</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_21">
<property name="text">
<string>match anything</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_22">
<property name="text">
<string>match one</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_23">
<property name="text">
<string>logical OR</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Examples</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>8</number>
</property>
<item>
<widget class="QLabel" name="label_9">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">user:name1 url:google</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">user:&quot;name1|name2&quot;</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_17">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">+user:name1 *notes:&quot;secret \d&quot;</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -18,6 +18,7 @@
#include "SearchWidget.h"
#include "ui_SearchWidget.h"
#include "ui_SearchHelpWidget.h"
#include <QKeyEvent>
#include <QMenu>
@ -26,6 +27,7 @@
#include "core/Config.h"
#include "core/FilePath.h"
#include "gui/widgets/PopupHelpWidget.h"
SearchWidget::SearchWidget(QWidget* parent)
: QWidget(parent)
@ -35,11 +37,17 @@ SearchWidget::SearchWidget(QWidget* parent)
{
m_ui->setupUi(this);
m_helpWidget = new PopupHelpWidget(m_ui->searchEdit);
m_helpWidget->setOffset(QPoint(0,1));
Ui::SearchHelpWidget helpUi;
helpUi.setupUi(m_helpWidget);
m_searchTimer->setSingleShot(true);
m_clearSearchTimer->setSingleShot(true);
connect(m_ui->searchEdit, SIGNAL(textChanged(QString)), SLOT(startSearchTimer()));
connect(m_ui->clearIcon, SIGNAL(triggered(bool)), m_ui->searchEdit, SLOT(clear()));
connect(m_ui->helpIcon, SIGNAL(triggered()), SLOT(toggleHelp()));
connect(m_searchTimer, SIGNAL(timeout()), this, SLOT(startSearch()));
connect(m_clearSearchTimer, SIGNAL(timeout()), m_ui->searchEdit, SLOT(clear()));
connect(this, SIGNAL(escapePressed()), m_ui->searchEdit, SLOT(clear()));
@ -65,6 +73,9 @@ SearchWidget::SearchWidget(QWidget* parent)
m_ui->searchIcon->setMenu(searchMenu);
m_ui->searchEdit->addAction(m_ui->searchIcon, QLineEdit::LeadingPosition);
m_ui->helpIcon->setIcon(filePath()->icon("actions", "system-help"));
m_ui->searchEdit->addAction(m_ui->helpIcon, QLineEdit::TrailingPosition);
m_ui->clearIcon->setIcon(filePath()->icon("actions", "edit-clear-locationbar-rtl"));
m_ui->clearIcon->setVisible(false);
m_ui->searchEdit->addAction(m_ui->clearIcon, QLineEdit::TrailingPosition);
@ -86,13 +97,6 @@ bool SearchWidget::eventFilter(QObject* obj, QEvent* event)
if (keyEvent->key() == Qt::Key_Escape) {
emit escapePressed();
return true;
} else if (keyEvent->matches(QKeySequence::Copy)) {
// If Control+C is pressed in the search edit when no text
// is selected, copy the password of the current entry
if (!m_ui->searchEdit->hasSelectedText()) {
emit copyPressed();
return true;
}
} else if (keyEvent->matches(QKeySequence::MoveToNextLine)) {
if (m_ui->searchEdit->cursorPosition() == m_ui->searchEdit->text().length()) {
// If down is pressed at EOL, move the focus to the entry view
@ -111,7 +115,7 @@ bool SearchWidget::eventFilter(QObject* obj, QEvent* event)
m_clearSearchTimer->stop();
}
return QObject::eventFilter(obj, event);
return QWidget::eventFilter(obj, event);
}
void SearchWidget::connectSignals(SignalMultiplexer& mx)
@ -188,3 +192,12 @@ void SearchWidget::searchFocus()
m_ui->searchEdit->setFocus();
m_ui->searchEdit->selectAll();
}
void SearchWidget::toggleHelp()
{
if (m_helpWidget->isVisible()) {
m_helpWidget->hide();
} else {
m_helpWidget->show();
}
}

View File

@ -30,6 +30,8 @@ namespace Ui
class SearchWidget;
}
class PopupHelpWidget;
class SearchWidget : public QWidget
{
Q_OBJECT
@ -45,6 +47,7 @@ public:
void setLimitGroup(bool state);
protected:
// Filter key presses in the search field
bool eventFilter(QObject* obj, QEvent* event) override;
signals:
@ -65,9 +68,11 @@ private slots:
void updateCaseSensitive();
void updateLimitGroup();
void searchFocus();
void toggleHelp();
private:
const QScopedPointer<Ui::SearchWidget> m_ui;
PopupHelpWidget* m_helpWidget;
QTimer* m_searchTimer;
QTimer* m_clearSearchTimer;
QAction* m_actionCaseSensitive;

View File

@ -81,6 +81,11 @@
<string>Clear</string>
</property>
</action>
<action name="helpIcon">
<property name="text">
<string>Search Help</string>
</property>
</action>
</widget>
<tabstops>
<tabstop>searchEdit</tabstop>

View File

@ -45,7 +45,7 @@ bool KeyFileEditWidget::addToCompositeKey(QSharedPointer<CompositeKey> key)
}
if (fileKey->type() != FileKey::Hashed) {
QMessageBox::warning(KEEPASSXC_MAIN_WINDOW,
QMessageBox::warning(getMainWindow(),
tr("Legacy key file format"),
tr("You are using a legacy key file format which may become\n"
"unsupported in the future.\n\n"
@ -100,7 +100,7 @@ void KeyFileEditWidget::createKeyFile()
QString errorMsg;
bool created = FileKey::create(fileName, &errorMsg);
if (!created) {
MessageBox::critical(KEEPASSXC_MAIN_WINDOW, tr("Error creating key file"),
MessageBox::critical(getMainWindow(), tr("Error creating key file"),
tr("Unable to create key file: %1").arg(errorMsg), QMessageBox::Button::Ok);
} else {
m_compUi->keyFileCombo->setEditText(fileName);

View File

@ -0,0 +1,99 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PopupHelpWidget.h"
#include <QEvent>
#include "gui/MainWindow.h"
PopupHelpWidget::PopupHelpWidget(QWidget* parent)
: QFrame(parent)
, m_parentWindow(parent->window())
, m_appWindow(getMainWindow())
, m_offset({0, 0})
, m_corner(Qt::BottomLeftCorner)
{
Q_ASSERT(parent);
setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
hide();
m_appWindow->installEventFilter(this);
parent->installEventFilter(this);
}
PopupHelpWidget::~PopupHelpWidget()
{
m_parentWindow->removeEventFilter(this);
parentWidget()->removeEventFilter(this);
}
void PopupHelpWidget::setOffset(const QPoint& offset)
{
m_offset = offset;
if (isVisible()) {
alignWithParent();
}
}
void PopupHelpWidget::setPosition(Qt::Corner corner)
{
m_corner = corner;
if (isVisible()) {
alignWithParent();
}
}
bool PopupHelpWidget::eventFilter(QObject* obj, QEvent* event)
{
if (obj == parentWidget() && event->type() == QEvent::FocusOut) {
hide();
} else if (obj == m_appWindow && (event->type() == QEvent::Move || event->type() == QEvent::Resize)) {
if (isVisible()) {
alignWithParent();
}
}
return QFrame::eventFilter(obj, event);
}
void PopupHelpWidget::showEvent(QShowEvent* event)
{
alignWithParent();
QFrame::showEvent(event);
}
void PopupHelpWidget::alignWithParent()
{
QPoint pos;
switch (m_corner) {
case Qt::TopLeftCorner:
pos = parentWidget()->geometry().topLeft() + m_offset - QPoint(0, height());
break;
case Qt::TopRightCorner:
pos = parentWidget()->geometry().topRight() + m_offset - QPoint(width(), height());
break;
case Qt::BottomRightCorner:
pos = parentWidget()->geometry().bottomRight() + m_offset - QPoint(width(), 0);
break;
default:
pos = parentWidget()->geometry().bottomLeft() + m_offset;
break;
}
move(m_parentWindow->mapToGlobal(pos));
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSXC_POPUPHELPWIDGET_H
#define KEEPASSXC_POPUPHELPWIDGET_H
#include <QPointer>
#include <QFrame>
class PopupHelpWidget : public QFrame
{
Q_OBJECT
public:
explicit PopupHelpWidget(QWidget* parent);
~PopupHelpWidget() override;
void setOffset(const QPoint& offset);
void setPosition(Qt::Corner corner);
protected:
bool eventFilter(QObject* obj, QEvent* event) override;
void showEvent(QShowEvent* event) override;
private:
void alignWithParent();
QPointer<QWidget> m_parentWindow;
QPointer<QWidget> m_appWindow;
QPoint m_offset;
Qt::Corner m_corner;
};
#endif //KEEPASSXC_POPUPHELPWIDGET_H

View File

@ -37,9 +37,9 @@ YkChallengeResponseKey::YkChallengeResponseKey(int slot, bool blocking)
, m_slot(slot)
, m_blocking(blocking)
{
if (KEEPASSXC_MAIN_WINDOW) {
connect(this, SIGNAL(userInteractionRequired()), KEEPASSXC_MAIN_WINDOW, SLOT(showYubiKeyPopup()));
connect(this, SIGNAL(userConfirmed()), KEEPASSXC_MAIN_WINDOW, SLOT(hideYubiKeyPopup()));
if (getMainWindow()) {
connect(this, SIGNAL(userInteractionRequired()), getMainWindow(), SLOT(showYubiKeyPopup()));
connect(this, SIGNAL(userConfirmed()), getMainWindow(), SLOT(hideYubiKeyPopup()));
}
}

View File

@ -111,7 +111,6 @@ int main(int argc, char** argv)
}
MainWindow mainWindow;
app.setMainWindow(&mainWindow);
QObject::connect(&app, SIGNAL(anotherInstanceStarted()), &mainWindow, SLOT(bringToFront()));
QObject::connect(&app, SIGNAL(applicationActivated()), &mainWindow, SLOT(bringToFront()));
QObject::connect(&app, SIGNAL(openFile(QString)), &mainWindow, SLOT(openDatabase(QString)));

View File

@ -802,10 +802,22 @@ void TestGui::testSearch()
auto* clearButton = searchWidget->findChild<QAction*>("clearIcon");
QVERIFY(!clearButton->isVisible());
auto* helpButton = searchWidget->findChild<QAction*>("helpIcon");
auto* helpPanel = searchWidget->findChild<QWidget*>("SearchHelpWidget");
QVERIFY(helpButton->isVisible());
QVERIFY(!helpPanel->isVisible());
// Enter search
QTest::mouseClick(searchTextEdit, Qt::LeftButton);
QTRY_VERIFY(searchTextEdit->hasFocus());
QTRY_VERIFY(!clearButton->isVisible());
// Show/Hide search help
helpButton->trigger();
QTRY_VERIFY(helpPanel->isVisible());
QTest::mouseClick(searchTextEdit, Qt::LeftButton);
QTRY_VERIFY(helpPanel->isVisible());
helpButton->trigger();
QTRY_VERIFY(!helpPanel->isVisible());
// Search for "ZZZ"
QTest::keyClicks(searchTextEdit, "ZZZ");
QTRY_COMPARE(searchTextEdit->text(), QString("ZZZ"));