Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve accessibility #3409

Merged
merged 9 commits into from
Aug 31, 2019
6 changes: 6 additions & 0 deletions src/browser/BrowserAccessControlDialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,19 @@
</item>
<item>
<widget class="QPushButton" name="allowButton">
<property name="accessibleName">
<string>Allow access</string>
</property>
<property name="text">
<string>Allow</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="denyButton">
<property name="accessibleName">
<string>Deny access</string>
</property>
<property name="text">
<string>Deny</string>
</property>
Expand Down
6 changes: 6 additions & 0 deletions src/browser/BrowserOptionDialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,9 @@
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="customProxyLocation">
<property name="accessibleName">
<string>Custom proxy location field</string>
</property>
<property name="maxLength">
<number>999</number>
</property>
Expand All @@ -375,6 +378,9 @@
</item>
<item>
<widget class="QPushButton" name="customProxyLocationBrowseButton">
<property name="accessibleName">
<string>Browser for custom proxy file</string>
</property>
<property name="text">
<string extracomment="Button for opening file dialog">Browse...</string>
</property>
Expand Down
2 changes: 1 addition & 1 deletion src/browser/BrowserService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <QCheckBox>
#include <QInputDialog>
#include <QJsonArray>
#include <QMessageBox>
#include <QProgressDialog>
#include <QUuid>
#include <QCheckBox>

#include "BrowserAccessControlDialog.h"
#include "BrowserEntryConfig.h"
Expand Down
7 changes: 7 additions & 0 deletions src/core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ void Config::sync()
m_settings->sync();
}

void Config::resetToDefaults()
{
for (const auto& setting : m_defaults.keys()) {
droidmonkey marked this conversation as resolved.
Show resolved Hide resolved
m_settings->setValue(setting, m_defaults.value(setting));
}
}

void Config::upgrade()
{
const auto keys = deprecationMap.keys();
Expand Down
1 change: 1 addition & 0 deletions src/core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class Config : public QObject
void set(const QString& key, const QVariant& value);
bool hasAccessError();
void sync();
void resetToDefaults();

static Config* instance();
static void createConfigFromFile(const QString& file);
Expand Down
105 changes: 59 additions & 46 deletions src/core/Translator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,21 @@
*/
void Translator::installTranslators()
{
QLocale locale;
QString language = config()->get("GUI/Language").toString();
if (!language.isEmpty() && language != "system") {
// use actual English translation instead of the English locale source language
if (language == "en") {
language = "en_US";
}
locale = QLocale(language);
QStringList languages;
QString languageSetting = config()->get("GUI/Language").toString();
if (languageSetting.isEmpty() || languageSetting == "system") {
// NOTE: this is a workaround for the terrible way Qt loads languages
// using the QLocale::uiLanguages() approach. Instead, we search each
// language and all country variants in order before moving to the next.
QLocale locale;
languages = locale.uiLanguages();
} else {
languages << languageSetting;
}

// Always try to load english last
languages << "en_US";

const QStringList paths = {
#ifdef QT_DEBUG
QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR),
Expand All @@ -52,9 +57,10 @@ void Translator::installTranslators()

bool translationsLoaded = false;
for (const QString& path : paths) {
translationsLoaded |= installTranslator(locale, path) || installTranslator(QLocale("en_US"), path);
if (!installQtTranslator(language, path)) {
installQtTranslator(QLocale("en"), path);
installQtTranslator(languages, path);
if (installTranslator(languages, path)) {
translationsLoaded = true;
break;
}
}

Expand All @@ -64,6 +70,48 @@ void Translator::installTranslators()
}
}

/**
* Install KeePassXC translator.
*
* @param languages priority-ordered list of languages
* @param path absolute search path
* @return true on success
*/
bool Translator::installTranslator(const QStringList& languages, const QString& path)
{
for (const auto& language : languages) {
QLocale locale(language);
QScopedPointer<QTranslator> translator(new QTranslator(qApp));
if (translator->load(locale, "keepassx_", "", path)) {
droidmonkey marked this conversation as resolved.
Show resolved Hide resolved
return QCoreApplication::installTranslator(translator.take());
}
}

return false;
}

/**
* Install Qt5 base translator from the specified local search path or the default system path
* if no qtbase_* translations were found at the local path.
*
* @param languages priority-ordered list of languages
* @param path absolute search path
* @return true on success
*/
bool Translator::installQtTranslator(const QStringList& languages, const QString& path)
{
for (const auto& language : languages) {
QLocale locale(language);
QScopedPointer<QTranslator> qtTranslator(new QTranslator(qApp));
if (qtTranslator->load(locale, "qtbase_", "", path)) {
return QCoreApplication::installTranslator(qtTranslator.take());
} else if (qtTranslator->load(locale, "qtbase_", "", QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
return QCoreApplication::installTranslator(qtTranslator.take());
}
}
return false;
}

/**
* @return list of pairs of available language codes and names
*/
Expand Down Expand Up @@ -108,38 +156,3 @@ QList<QPair<QString, QString>> Translator::availableLanguages()

return languages;
}

/**
* Install KeePassXC translator.
*
* @param language translator language
* @param path local search path
* @return true on success
*/
bool Translator::installTranslator(const QLocale& locale, const QString& path)
{
QScopedPointer<QTranslator> translator(new QTranslator(qApp));
if (translator->load(locale, "keepassx_", "", path)) {
return QCoreApplication::installTranslator(translator.take());
}
return false;
}

/**
* Install Qt5 base translator from the specified local search path or the default system path
* if no qtbase_* translations were found at the local path.
*
* @param language translator language
* @param path local search path
* @return true on success
*/
bool Translator::installQtTranslator(const QLocale& locale, const QString& path)
{
QScopedPointer<QTranslator> qtTranslator(new QTranslator(qApp));
if (qtTranslator->load(locale, "qtbase_", "", path)) {
return QCoreApplication::installTranslator(qtTranslator.take());
} else if (qtTranslator->load(locale, "qtbase_", "", QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
return QCoreApplication::installTranslator(qtTranslator.take());
}
return false;
}
4 changes: 2 additions & 2 deletions src/core/Translator.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class Translator
static QList<QPair<QString, QString>> availableLanguages();

private:
static bool installTranslator(const QLocale& locale, const QString& path);
static bool installQtTranslator(const QLocale& locale, const QString& path);
static bool installTranslator(const QStringList& languages, const QString& path);
static bool installQtTranslator(const QStringList& languages, const QString& path);
};

#endif // KEEPASSX_TRANSLATOR_H
75 changes: 74 additions & 1 deletion src/gui/ApplicationSettingsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "core/Global.h"
#include "core/Translator.h"

#include "MessageBox.h"
#include "touchid/TouchID.h"

class ApplicationSettingsWidget::ExtraPage
Expand All @@ -54,6 +55,28 @@ class ApplicationSettingsWidget::ExtraPage
QWidget* widget;
};

/**
* Helper class to ignore mouse wheel events on non-focused widgets
* NOTE: The widget must NOT have a focus policy of "WHEEL"
*/
class MouseWheelEventFilter : public QObject
{
public:
explicit MouseWheelEventFilter(QObject* parent)
: QObject(parent){};

protected:
bool eventFilter(QObject* obj, QEvent* event) override
{
const auto* widget = qobject_cast<QWidget*>(obj);
if (event->type() == QEvent::Wheel && widget && !widget->hasFocus()) {
event->ignore();
return true;
}
return QObject::eventFilter(obj, event);
}
};

ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent)
: EditWidget(parent)
, m_secWidget(new QWidget())
Expand Down Expand Up @@ -84,6 +107,7 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent)
connect(m_generalUi->systrayShowCheckBox, SIGNAL(toggled(bool)), SLOT(systrayToggled(bool)));
connect(m_generalUi->toolbarHideCheckBox, SIGNAL(toggled(bool)), SLOT(toolbarSettingsToggled(bool)));
connect(m_generalUi->rememberLastDatabasesCheckBox, SIGNAL(toggled(bool)), SLOT(rememberDatabasesToggled(bool)));
connect(m_generalUi->resetSettingsButton, SIGNAL(clicked()), SLOT(resetSettings()));

connect(m_secUi->clearClipboardCheckBox, SIGNAL(toggled(bool)),
m_secUi->clearClipboardSpinBox, SLOT(setEnabled(bool)));
Expand All @@ -95,6 +119,13 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent)
m_secUi->touchIDResetSpinBox, SLOT(setEnabled(bool)));
// clang-format on

// Disable mouse wheel grab when scrolling
// This prevents combo box and spinner values from changing without explicit focus
auto mouseWheelFilter = new MouseWheelEventFilter(this);
droidmonkey marked this conversation as resolved.
Show resolved Hide resolved
m_generalUi->faviconTimeoutSpinBox->installEventFilter(mouseWheelFilter);
m_generalUi->toolButtonStyleComboBox->installEventFilter(mouseWheelFilter);
m_generalUi->languageComboBox->installEventFilter(mouseWheelFilter);

#ifdef WITH_XC_UPDATECHECK
connect(m_generalUi->checkForUpdatesOnStartupCheckBox, SIGNAL(toggled(bool)), SLOT(checkUpdatesToggled(bool)));
#else
Expand Down Expand Up @@ -246,7 +277,6 @@ void ApplicationSettingsWidget::loadSettings()

void ApplicationSettingsWidget::saveSettings()
{

if (config()->hasAccessError()) {
showMessage(tr("Access error for config file %1").arg(config()->getFileName()), MessageWidget::Error);
// We prevent closing the settings page if we could not write to
Expand Down Expand Up @@ -330,6 +360,7 @@ void ApplicationSettingsWidget::saveSettings()
config()->set("LastDatabases", {});
config()->set("OpenPreviousDatabasesOnStartup", {});
config()->set("LastActiveDatabase", {});
config()->set("LastAttachmentDir", {});
}

if (!config()->get("RememberLastKeyFiles").toBool()) {
Expand All @@ -342,6 +373,48 @@ void ApplicationSettingsWidget::saveSettings()
}
}

void ApplicationSettingsWidget::resetSettings()
{
// Confirm reset
auto ans = MessageBox::question(this,
tr("Reset Settings?"),
tr("Are you sure you want to reset all general and security settings to default?"),
MessageBox::Reset | MessageBox::Cancel,
MessageBox::Cancel);
if (ans == MessageBox::Cancel) {
return;
}

if (config()->hasAccessError()) {
showMessage(tr("Access error for config file %1").arg(config()->getFileName()), MessageWidget::Error);
// We prevent closing the settings page if we could not write to
// the config file.
return;
}

// Reset general and security settings to default
config()->resetToDefaults();

// Clear recently used data
config()->set("LastDatabases", {});
config()->set("OpenPreviousDatabasesOnStartup", {});
config()->set("LastActiveDatabase", {});
config()->set("LastAttachmentDir", {});
config()->set("LastKeyFiles", {});
config()->set("LastDir", "");

// Save the Extra Pages (these are NOT reset)
for (const ExtraPage& page : asConst(m_extraPages)) {
page.saveSettings();
}

config()->sync();

// Refresh the settings widget and notify listeners
loadSettings();
emit settingsReset();
}

void ApplicationSettingsWidget::reject()
{
// register the old key again as it might have changed
Expand Down
4 changes: 4 additions & 0 deletions src/gui/ApplicationSettingsWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ class ApplicationSettingsWidget : public EditWidget
void addSettingsPage(ISettingsPage* page);
void loadSettings();

signals:
void settingsReset();

private slots:
void saveSettings();
void resetSettings();
void reject();
void autoSaveToggled(bool checked);
void hideWindowOnCopyCheckBoxToggled(bool checked);
Expand Down
Loading