diff --git a/src/utils/gui-helper.cpp b/src/utils/gui-helper.cpp index 13e24c7fc..9aead7add 100644 --- a/src/utils/gui-helper.cpp +++ b/src/utils/gui-helper.cpp @@ -1,157 +1,178 @@ /* crypto/gui/signencryptemailconflictdialog.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2017 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include "gui-helper.h" #include #include +#include #include #include #ifdef Q_OS_WIN #include #endif +using namespace Kleo; + /* This is a Hack to workaround the fact that Foregrounding a Window is so restricted that it AllowSetForegroundWindow does not always work e.g. when the ForegroundWindow timeout has not expired. This Hack is semi official but may stop working in future windows versions. This is similar to what pinentry-qt does on Windows. */ #ifdef Q_OS_WIN WINBOOL SetForegroundWindowEx(HWND hWnd) { // Attach foreground window thread to our thread const DWORD ForeGroundID = GetWindowThreadProcessId(::GetForegroundWindow(), NULL); const DWORD CurrentID = GetCurrentThreadId(); WINBOOL retval; AttachThreadInput(ForeGroundID, CurrentID, TRUE); // Do our stuff here HWND hLastActivePopupWnd = GetLastActivePopup(hWnd); retval = SetForegroundWindow(hLastActivePopupWnd); // Detach the attached thread AttachThreadInput(ForeGroundID, CurrentID, FALSE); return retval; } // End SetForegroundWindowEx #endif void Kleo::aggressive_raise(QWidget *w, bool stayOnTop) { /* Maybe Qt will become aggressive enough one day that * this is enough on windows too*/ w->raise(); w->setWindowState(Qt::WindowActive); w->activateWindow(); #ifdef Q_OS_WIN HWND wid = (HWND)w->effectiveWinId(); /* In the meantime we do our own attention grabbing */ if (!SetForegroundWindow(wid) && !SetForegroundWindowEx(wid)) { OutputDebugStringA("SetForegroundWindow (ex) failed"); /* Yet another fallback which will not work on some * versions and is not recommended by msdn */ if (!ShowWindow(wid, SW_SHOWNORMAL)) { OutputDebugStringA("ShowWindow failed."); } } /* Even if SetForgeoundWindow / SetForegroundWinowEx don't fail * we sometimes are still not in the foreground. So we try yet * another hack by using SetWindowPos */ if (!SetWindowPos(wid, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW)) { OutputDebugStringA("SetWindowPos failed."); } /* sometimes we want to stay on top even if the user * changes focus because we are _aggressive_ and otherwise * Outlook might show the "Help I'm unresponsive so I must have * crashed" Popup if the user clicks into Outlook while a dialog * from us is active. */ else if (!stayOnTop) { // Without moving back to NOTOPMOST we just stay on top. // Even if the user changes focus. SetWindowPos(wid, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } #else Q_UNUSED(stayOnTop) #endif } void Kleo::forceSetTabOrder(QWidget *first, QWidget *second) { if (!first || !second || first == second) { return; } // temporarily change the focus policy of the two widgets to something // other than Qt::NoFocus because QWidget::setTabOrder() does nothing // if either widget has focus policy Qt::NoFocus const auto firstFocusPolicy = first->focusPolicy(); const auto secondFocusPolicy = second->focusPolicy(); if (firstFocusPolicy == Qt::NoFocus) { first->setFocusPolicy(Qt::StrongFocus); } if (secondFocusPolicy == Qt::NoFocus) { second->setFocusPolicy(Qt::StrongFocus); } QWidget::setTabOrder(first, second); if (first->focusPolicy() != firstFocusPolicy) { first->setFocusPolicy(firstFocusPolicy); } if (second->focusPolicy() != secondFocusPolicy) { second->setFocusPolicy(secondFocusPolicy); } } template bool focusFirstButtonIf(const std::vector &buttons, UnaryPredicate p) { auto it = std::find_if(std::begin(buttons), std::end(buttons), p); if (it != std::end(buttons)) { (*it)->setFocus(); return true; } return false; } bool Kleo::focusFirstCheckedButton(const std::vector &buttons) { return focusFirstButtonIf(buttons, [](auto btn) { return btn && btn->isEnabled() && btn->isChecked(); }); } bool Kleo::focusFirstEnabledButton(const std::vector &buttons) { return focusFirstButtonIf(buttons, [](auto btn) { return btn && btn->isEnabled(); }); } void Kleo::unsetDefaultButtons(const QDialogButtonBox *buttonBox) { if (!buttonBox) { return; } const auto buttons = buttonBox->buttons(); for (auto button : buttons) { if (auto pushButton = qobject_cast(button)) { pushButton->setDefault(false); } } } void Kleo::unsetAutoDefaultButtons(const QDialog *dialog) { if (!dialog) { return; } const auto pushButtons = dialog->findChildren(); for (auto pushButton : pushButtons) { pushButton->setAutoDefault(false); } } + +BulkStateChanger::BulkStateChanger() = default; + +void BulkStateChanger::addWidget(QWidget *widget) +{ + if (widget) { + mWidgets.push_back(widget); + } +} + +void BulkStateChanger::setVisible(bool visible) +{ + for (auto &w : mWidgets) { + if (w) { + w->setVisible(visible); + } + } +} diff --git a/src/utils/gui-helper.h b/src/utils/gui-helper.h index 22882264c..6c9959b6b 100644 --- a/src/utils/gui-helper.h +++ b/src/utils/gui-helper.h @@ -1,89 +1,101 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/gui-helper.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include class QDialog; class QDialogButtonBox; class QWidget; namespace Kleo { static inline void really_check(QAbstractButton &b, bool on) { const bool excl = b.autoExclusive(); b.setAutoExclusive(false); b.setChecked(on); b.setAutoExclusive(excl); } static inline bool xconnect(const QObject *a, const char *signal, const QObject *b, const char *slot) { return QObject::connect(a, signal, b, slot) && QObject::connect(b, signal, a, slot); } /** Aggressively raise a window to foreground. May be platform * specific. */ void aggressive_raise(QWidget *w, bool stayOnTop); /** * Puts the second widget after the first widget in the focus order. * * In contrast to QWidget::setTabOrder(), this function also changes the * focus order if the first widget or the second widget has focus policy * Qt::NoFocus. * * Note: After calling this function all widgets in the focus proxy chain * of the first widget have focus policy Qt::NoFocus if the first widget * has this focus policy. Correspondingly, for the second widget. */ void forceSetTabOrder(QWidget *first, QWidget *second); /** * Gives the keyboard input focus to the first of the \p buttons, that is * enabled and checked. * * Returns true, if a button was given focus. Returns false, if no button was * found that is enabled and checked. */ bool focusFirstCheckedButton(const std::vector &buttons); /** * Gives the keyboard input focus to the first of the \p buttons, that is * enabled. * * Returns true, if a button was given focus. Returns false, if no button was * found that is enabled. */ bool focusFirstEnabledButton(const std::vector &buttons); /** * Unsets the default property of all push buttons in the button box. * * This function needs to be called after the button box received the show event * because QDialogButtonBox automatically sets a default button when it is shown. * * \sa unsetAutoDefaultButtons */ void unsetDefaultButtons(const QDialogButtonBox *buttonBox); /** * Unsets the auto-default property of all push buttons in the dialog. * * This can be useful if you want to prevent the accidental closing of the dialog * when the user presses Enter while another UI element, e.g. a text input field * has focus. * * \sa unsetDefaultButtons */ void unsetAutoDefaultButtons(const QDialog *dialog); +class BulkStateChanger +{ +public: + BulkStateChanger(); + + void addWidget(QWidget *widget); + + void setVisible(bool visible); + +private: + std::vector> mWidgets; +}; }