mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-12-24 14:59:44 -05:00
Fix multiple issues with entries and keyboard shortcuts (#2431)
* Cleanup entry change notification with entryview focus in/out * Change Open URL shortcut to CTRL+SHIFT+U to conform with an "action" including SHIFT * Change Copy URL shortcut to CTRL+U to conform with "copy" without SHIFT * Entry specific toolbar and menu items are disabled unless the entry row has focus (prevents unintended actions) * Reword security setting for password visibility in entry edit view * Add shortcut to hide/unhide usernames (CTRL+SHIFT+B) * Organize entry menu * Fix #1588 - show keyboard shortcuts in context menu * Fix #2403 - Change auto-type shortcut to CTRL + SHIFT + V * Fix #2096 - Add (CTRL+F) to search bar background * Fix #2031 & Fix #2266 - add shortcut to hide/unhide passwords (CTRL+SHIFT+C) * Fix #2166 - Add reveal password button to entry preview
This commit is contained in:
parent
f06742cf41
commit
ee9c71e11e
@ -175,7 +175,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="passwordCleartextCheckBox">
|
||||
<property name="text">
|
||||
<string>Show passwords in cleartext by default</string>
|
||||
<string>Don't hide passwords when editing them</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -114,7 +114,6 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
|
||||
|
||||
m_previewView = new EntryPreviewWidget(this);
|
||||
m_previewView->hide();
|
||||
connect(this, SIGNAL(pressedEntry(Entry*)), m_previewView, SLOT(setEntry(Entry*)));
|
||||
connect(this, SIGNAL(pressedGroup(Group*)), m_previewView, SLOT(setGroup(Group*)));
|
||||
connect(this, SIGNAL(currentModeChanged(DatabaseWidget::Mode)),
|
||||
m_previewView, SLOT(setDatabaseMode(DatabaseWidget::Mode)));
|
||||
@ -183,7 +182,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
|
||||
connect(m_entryView,
|
||||
SIGNAL(entryActivated(Entry*,EntryModel::ModelColumn)),
|
||||
SLOT(entryActivationSignalReceived(Entry*,EntryModel::ModelColumn)));
|
||||
connect(m_entryView, SIGNAL(entrySelectionChanged()), SIGNAL(entrySelectionChanged()));
|
||||
connect(m_entryView, SIGNAL(entrySelectionChanged()), SLOT(emitEntrySelectionChanged()));
|
||||
connect(m_editEntryWidget, SIGNAL(editFinished(bool)), SLOT(switchToView(bool)));
|
||||
connect(m_editEntryWidget, SIGNAL(historyEntryActivated(Entry*)), SLOT(switchToHistoryView(Entry*)));
|
||||
connect(m_historyEditEntryWidget, SIGNAL(editFinished(bool)), SLOT(switchBackToEntryEdit()));
|
||||
@ -202,9 +201,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
|
||||
|
||||
connect(m_groupView, SIGNAL(groupPressed(Group*)), SLOT(emitPressedGroup(Group*)));
|
||||
connect(m_groupView, SIGNAL(groupChanged(Group*)), SLOT(emitPressedGroup(Group*)));
|
||||
connect(m_entryView, SIGNAL(entryPressed(Entry*)), SLOT(emitPressedEntry(Entry*)));
|
||||
connect(m_entryView, SIGNAL(entrySelectionChanged()), SLOT(emitPressedEntry()));
|
||||
connect(m_editEntryWidget, SIGNAL(editFinished(bool)), SLOT(emitPressedEntry()));
|
||||
connect(m_editEntryWidget, SIGNAL(editFinished(bool)), SLOT(emitEntrySelectionChanged()));
|
||||
|
||||
m_databaseModified = false;
|
||||
|
||||
@ -506,80 +503,60 @@ void DatabaseWidget::setFocus()
|
||||
void DatabaseWidget::copyTitle()
|
||||
{
|
||||
Entry* currentEntry = m_entryView->currentEntry();
|
||||
Q_ASSERT(currentEntry);
|
||||
if (!currentEntry) {
|
||||
return;
|
||||
if (currentEntry) {
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->title()));
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->title()));
|
||||
}
|
||||
|
||||
void DatabaseWidget::copyUsername()
|
||||
{
|
||||
Entry* currentEntry = m_entryView->currentEntry();
|
||||
Q_ASSERT(currentEntry);
|
||||
if (!currentEntry) {
|
||||
return;
|
||||
if (currentEntry) {
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->username()));
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->username()));
|
||||
}
|
||||
|
||||
void DatabaseWidget::copyPassword()
|
||||
{
|
||||
Entry* currentEntry = m_entryView->currentEntry();
|
||||
Q_ASSERT(currentEntry);
|
||||
if (!currentEntry) {
|
||||
return;
|
||||
if (currentEntry) {
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->password()));
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->password()));
|
||||
}
|
||||
|
||||
void DatabaseWidget::copyURL()
|
||||
{
|
||||
Entry* currentEntry = m_entryView->currentEntry();
|
||||
Q_ASSERT(currentEntry);
|
||||
if (!currentEntry) {
|
||||
return;
|
||||
if (currentEntry) {
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->url()));
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->url()));
|
||||
}
|
||||
|
||||
void DatabaseWidget::copyNotes()
|
||||
{
|
||||
Entry* currentEntry = m_entryView->currentEntry();
|
||||
Q_ASSERT(currentEntry);
|
||||
if (!currentEntry) {
|
||||
return;
|
||||
if (currentEntry) {
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->notes()));
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->notes()));
|
||||
}
|
||||
|
||||
void DatabaseWidget::copyAttribute(QAction* action)
|
||||
{
|
||||
Entry* currentEntry = m_entryView->currentEntry();
|
||||
Q_ASSERT(currentEntry);
|
||||
if (!currentEntry) {
|
||||
return;
|
||||
if (currentEntry) {
|
||||
setClipboardTextAndMinimize(
|
||||
currentEntry->resolveMultiplePlaceholders(
|
||||
currentEntry->attributes()->value(action->data().toString())));
|
||||
}
|
||||
|
||||
setClipboardTextAndMinimize(
|
||||
currentEntry->resolveMultiplePlaceholders(currentEntry->attributes()->value(action->data().toString())));
|
||||
}
|
||||
|
||||
void DatabaseWidget::showTotpKeyQrCode()
|
||||
{
|
||||
Entry* currentEntry = m_entryView->currentEntry();
|
||||
Q_ASSERT(currentEntry);
|
||||
if (!currentEntry) {
|
||||
return;
|
||||
if (currentEntry) {
|
||||
auto totpDisplayDialog = new TotpExportSettingsDialog(this, currentEntry);
|
||||
totpDisplayDialog->open();
|
||||
}
|
||||
|
||||
auto totpDisplayDialog = new TotpExportSettingsDialog(this, currentEntry);
|
||||
totpDisplayDialog->open();
|
||||
}
|
||||
|
||||
void DatabaseWidget::setClipboardTextAndMinimize(const QString& text)
|
||||
@ -593,27 +570,22 @@ void DatabaseWidget::setClipboardTextAndMinimize(const QString& text)
|
||||
void DatabaseWidget::performAutoType()
|
||||
{
|
||||
Entry* currentEntry = m_entryView->currentEntry();
|
||||
Q_ASSERT(currentEntry);
|
||||
if (!currentEntry) {
|
||||
return;
|
||||
if (currentEntry) {
|
||||
autoType()->performAutoType(currentEntry, window());
|
||||
}
|
||||
|
||||
autoType()->performAutoType(currentEntry, window());
|
||||
}
|
||||
|
||||
void DatabaseWidget::openUrl()
|
||||
{
|
||||
Entry* currentEntry = m_entryView->currentEntry();
|
||||
Q_ASSERT(currentEntry);
|
||||
if (!currentEntry) {
|
||||
return;
|
||||
if (currentEntry) {
|
||||
openUrlForEntry(currentEntry);
|
||||
}
|
||||
|
||||
openUrlForEntry(currentEntry);
|
||||
}
|
||||
|
||||
void DatabaseWidget::openUrlForEntry(Entry* entry)
|
||||
{
|
||||
Q_ASSERT(entry);
|
||||
QString cmdString = entry->resolveMultiplePlaceholders(entry->url());
|
||||
if (cmdString.startsWith("cmd://")) {
|
||||
// check if decision to execute command was stored
|
||||
@ -1076,10 +1048,11 @@ void DatabaseWidget::setSearchLimitGroup(bool state)
|
||||
void DatabaseWidget::onGroupChanged(Group* group)
|
||||
{
|
||||
// Intercept group changes if in search mode
|
||||
if (isInSearchMode())
|
||||
if (isInSearchMode()) {
|
||||
search(m_lastSearchText);
|
||||
else
|
||||
} else {
|
||||
m_entryView->setGroup(group);
|
||||
}
|
||||
}
|
||||
|
||||
QString DatabaseWidget::getCurrentSearch()
|
||||
@ -1114,20 +1087,14 @@ void DatabaseWidget::emitEntryContextMenuRequested(const QPoint& pos)
|
||||
emit entryContextMenuRequested(m_entryView->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void DatabaseWidget::emitPressedEntry()
|
||||
void DatabaseWidget::emitEntrySelectionChanged()
|
||||
{
|
||||
Entry* currentEntry = m_entryView->currentEntry();
|
||||
emitPressedEntry(currentEntry);
|
||||
}
|
||||
|
||||
void DatabaseWidget::emitPressedEntry(Entry* currentEntry)
|
||||
{
|
||||
if (!currentEntry) {
|
||||
// if no entry is pressed, leave in details the last entry
|
||||
return;
|
||||
if (currentEntry) {
|
||||
m_previewView->setEntry(currentEntry);
|
||||
}
|
||||
|
||||
emit pressedEntry(currentEntry);
|
||||
emit entrySelectionChanged();
|
||||
}
|
||||
|
||||
void DatabaseWidget::emitPressedGroup(Group* currentGroup)
|
||||
@ -1354,7 +1321,12 @@ void DatabaseWidget::restoreGroupEntryFocus(const QUuid& groupUuid, const QUuid&
|
||||
|
||||
bool DatabaseWidget::isGroupSelected() const
|
||||
{
|
||||
return m_groupView->currentGroup() != nullptr;
|
||||
return m_groupView->currentGroup();
|
||||
}
|
||||
|
||||
bool DatabaseWidget::currentEntryHasFocus()
|
||||
{
|
||||
return m_entryView->numberOfSelectedEntries() > 0 && m_entryView->hasFocus();
|
||||
}
|
||||
|
||||
bool DatabaseWidget::currentEntryHasTitle()
|
||||
|
@ -99,6 +99,7 @@ public:
|
||||
QByteArray entryViewState() const;
|
||||
bool setEntryViewState(const QByteArray& state) const;
|
||||
void clearAllWidgets();
|
||||
bool currentEntryHasFocus();
|
||||
bool currentEntryHasTitle();
|
||||
bool currentEntryHasUsername();
|
||||
bool currentEntryHasPassword();
|
||||
@ -198,9 +199,8 @@ private slots:
|
||||
void switchToGroupEdit(Group* entry, bool create);
|
||||
void emitGroupContextMenuRequested(const QPoint& pos);
|
||||
void emitEntryContextMenuRequested(const QPoint& pos);
|
||||
void emitPressedEntry();
|
||||
void emitPressedEntry(Entry* currentEntry);
|
||||
void emitPressedGroup(Group* currentGroup);
|
||||
void emitEntrySelectionChanged();
|
||||
void openDatabase(bool accepted);
|
||||
void mergeDatabase(bool accepted);
|
||||
void unlockDatabase(bool accepted);
|
||||
|
@ -47,12 +47,14 @@ EntryPreviewWidget::EntryPreviewWidget(QWidget* parent)
|
||||
// Entry
|
||||
m_ui->entryTotpButton->setIcon(filePath()->icon("actions", "chronometer"));
|
||||
m_ui->entryCloseButton->setIcon(filePath()->icon("actions", "dialog-close"));
|
||||
m_ui->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show"));
|
||||
|
||||
m_ui->entryAttachmentsWidget->setReadOnly(true);
|
||||
m_ui->entryAttachmentsWidget->setButtonsVisible(false);
|
||||
|
||||
connect(m_ui->entryTotpButton, SIGNAL(toggled(bool)), m_ui->entryTotpWidget, SLOT(setVisible(bool)));
|
||||
connect(m_ui->entryCloseButton, SIGNAL(clicked()), SLOT(hide()));
|
||||
connect(m_ui->togglePasswordButton, SIGNAL(clicked(bool)), SLOT(setPasswordVisible(bool)));
|
||||
connect(m_ui->entryTabWidget, SIGNAL(tabBarClicked(int)), SLOT(updateTabIndexes()), Qt::QueuedConnection);
|
||||
connect(&m_totpTimer, SIGNAL(timeout()), this, SLOT(updateTotpLabel()));
|
||||
|
||||
@ -152,18 +154,40 @@ void EntryPreviewWidget::updateEntryTotp()
|
||||
}
|
||||
}
|
||||
|
||||
void EntryPreviewWidget::setPasswordVisible(bool state)
|
||||
{
|
||||
const QString password = m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->password());
|
||||
auto flags = m_ui->entryPasswordLabel->textInteractionFlags();
|
||||
if (state) {
|
||||
m_ui->entryPasswordLabel->setRawText(password);
|
||||
m_ui->entryPasswordLabel->setToolTip(password);
|
||||
m_ui->entryPasswordLabel->setTextInteractionFlags(flags | Qt::TextSelectableByMouse);
|
||||
} else {
|
||||
m_ui->entryPasswordLabel->setTextInteractionFlags(flags & ~Qt::TextSelectableByMouse);
|
||||
m_ui->entryPasswordLabel->setToolTip({});
|
||||
if (password.isEmpty() && config()->get("security/passwordemptynodots").toBool()) {
|
||||
m_ui->entryPasswordLabel->setRawText("");
|
||||
} else {
|
||||
m_ui->entryPasswordLabel->setRawText(QString("\u25cf").repeated(6));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntryPreviewWidget::updateEntryGeneralTab()
|
||||
{
|
||||
Q_ASSERT(m_currentEntry);
|
||||
m_ui->entryUsernameLabel->setText(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->username()));
|
||||
|
||||
if (!config()->get("security/HidePasswordPreviewPanel").toBool()) {
|
||||
const QString password = m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->password());
|
||||
m_ui->entryPasswordLabel->setRawText(password);
|
||||
m_ui->entryPasswordLabel->setToolTip(password);
|
||||
if (config()->get("security/HidePasswordPreviewPanel").toBool()) {
|
||||
// Hide password
|
||||
setPasswordVisible(false);
|
||||
// Show the password toggle button if there are dots in the label
|
||||
m_ui->togglePasswordButton->setVisible(!m_ui->entryPasswordLabel->rawText().isEmpty());
|
||||
m_ui->togglePasswordButton->setChecked(false);
|
||||
} else {
|
||||
m_ui->entryPasswordLabel->setRawText(QString("\u25cf").repeated(6));
|
||||
m_ui->entryPasswordLabel->setToolTip({});
|
||||
// Show password
|
||||
setPasswordVisible(true);
|
||||
m_ui->togglePasswordButton->setVisible(false);
|
||||
}
|
||||
|
||||
m_ui->entryUrlLabel->setRawText(m_currentEntry->displayUrl());
|
||||
|
@ -51,6 +51,7 @@ private slots:
|
||||
void updateEntryAttributesTab();
|
||||
void updateEntryAttachmentsTab();
|
||||
void updateEntryAutotypeTab();
|
||||
void setPasswordVisible(bool state);
|
||||
|
||||
void updateGroupHeaderLine();
|
||||
void updateGroupGeneralTab();
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>280</width>
|
||||
<height>267</height>
|
||||
<width>573</width>
|
||||
<height>330</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
@ -168,7 +168,7 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QWidget" name="entryGeneralWidget" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0" columnstretch="0,0,0">
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0" columnstretch="0,0,0,0,0,0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -181,65 +181,21 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="2">
|
||||
<widget class="ElidedLabel" name="entryPasswordLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<item row="0" column="0">
|
||||
<spacer name="entryLeftHorizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="ElidedLabel" name="entryUrlLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="entryUsernameLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="entryUsernameTitleLabel">
|
||||
@ -266,6 +222,50 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="entryUsernameLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">username</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="entryPasswordTitleLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" 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>Password</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="entryExpirationTitleLabel">
|
||||
<property name="sizePolicy">
|
||||
@ -288,7 +288,45 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<item row="4" column="4">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="ElidedLabel" name="entryUrlLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">https://example.com</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QLabel" name="entryExpirationLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
@ -296,6 +334,9 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">expired</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
@ -320,8 +361,47 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<spacer name="entryLeftHorizontalSpacer">
|
||||
<item row="1" column="3" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="togglePasswordButton">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ElidedLabel" name="entryPasswordLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">password</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="entryLeftHorizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -336,37 +416,34 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="entryPasswordTitleLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" 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>Password</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<item row="2" column="0">
|
||||
<spacer name="entryLeftHorizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<spacer name="entryLeftHorizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
@ -688,6 +765,12 @@
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -183,7 +183,7 @@ MainWindow::MainWindow()
|
||||
m_ui->actionDatabaseNew->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_N);
|
||||
setShortcut(m_ui->actionDatabaseOpen, QKeySequence::Open, Qt::CTRL + Qt::Key_O);
|
||||
setShortcut(m_ui->actionDatabaseSave, QKeySequence::Save, Qt::CTRL + Qt::Key_S);
|
||||
setShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs);
|
||||
setShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs, Qt::CTRL + Qt::SHIFT + Qt::Key_S);
|
||||
setShortcut(m_ui->actionDatabaseClose, QKeySequence::Close, Qt::CTRL + Qt::Key_W);
|
||||
m_ui->actionLockDatabases->setShortcut(Qt::CTRL + Qt::Key_L);
|
||||
setShortcut(m_ui->actionQuit, QKeySequence::Quit, Qt::CTRL + Qt::Key_Q);
|
||||
@ -196,16 +196,37 @@ MainWindow::MainWindow()
|
||||
m_ui->actionEntryCopyTotp->setShortcut(Qt::CTRL + Qt::Key_T);
|
||||
m_ui->actionEntryCopyUsername->setShortcut(Qt::CTRL + Qt::Key_B);
|
||||
m_ui->actionEntryCopyPassword->setShortcut(Qt::CTRL + Qt::Key_C);
|
||||
setShortcut(m_ui->actionEntryAutoType, QKeySequence::Paste, Qt::CTRL + Qt::Key_V);
|
||||
m_ui->actionEntryOpenUrl->setShortcut(Qt::CTRL + Qt::Key_U);
|
||||
m_ui->actionEntryCopyURL->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_U);
|
||||
m_ui->actionEntryAutoType->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_V);
|
||||
m_ui->actionEntryOpenUrl->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_U);
|
||||
m_ui->actionEntryCopyURL->setShortcut(Qt::CTRL + Qt::Key_U);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
// Qt 5.10 introduced a new "feature" to hide shortcuts in context menus
|
||||
// Unfortunately, Qt::AA_DontShowShortcutsInContextMenus is broken, have to manually enable them
|
||||
m_ui->actionEntryNew->setShortcutVisibleInContextMenu(true);
|
||||
m_ui->actionEntryEdit->setShortcutVisibleInContextMenu(true);
|
||||
m_ui->actionEntryDelete->setShortcutVisibleInContextMenu(true);
|
||||
m_ui->actionEntryClone->setShortcutVisibleInContextMenu(true);
|
||||
m_ui->actionEntryTotp->setShortcutVisibleInContextMenu(true);
|
||||
m_ui->actionEntryCopyTotp->setShortcutVisibleInContextMenu(true);
|
||||
m_ui->actionEntryCopyUsername->setShortcutVisibleInContextMenu(true);
|
||||
m_ui->actionEntryCopyPassword->setShortcutVisibleInContextMenu(true);
|
||||
m_ui->actionEntryAutoType->setShortcutVisibleInContextMenu(true);
|
||||
m_ui->actionEntryOpenUrl->setShortcutVisibleInContextMenu(true);
|
||||
m_ui->actionEntryCopyURL->setShortcutVisibleInContextMenu(true);
|
||||
#endif
|
||||
|
||||
// Control window state
|
||||
new QShortcut(Qt::CTRL + Qt::Key_M, this, SLOT(showMinimized()));
|
||||
new QShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_M, this, SLOT(hideWindow()));
|
||||
// Control database tabs
|
||||
new QShortcut(Qt::CTRL + Qt::Key_Tab, this, SLOT(selectNextDatabaseTab()));
|
||||
new QShortcut(Qt::CTRL + Qt::Key_PageUp, this, SLOT(selectNextDatabaseTab()));
|
||||
new QShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab, this, SLOT(selectPreviousDatabaseTab()));
|
||||
new QShortcut(Qt::CTRL + Qt::Key_PageDown, this, SLOT(selectPreviousDatabaseTab()));
|
||||
// Toggle password and username visibility in entry view
|
||||
new QShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_C, this, SLOT(togglePasswordsHidden()));
|
||||
new QShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_B, this, SLOT(toggleUsernamesHidden()));
|
||||
|
||||
m_ui->actionDatabaseNew->setIcon(filePath()->icon("actions", "document-new"));
|
||||
m_ui->actionDatabaseOpen->setIcon(filePath()->icon("actions", "document-open"));
|
||||
@ -457,8 +478,8 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
|
||||
switch (mode) {
|
||||
case DatabaseWidget::ViewMode: {
|
||||
// bool inSearch = dbWidget->isInSearchMode();
|
||||
bool singleEntrySelected = dbWidget->numberOfSelectedEntries() == 1;
|
||||
bool entriesSelected = dbWidget->numberOfSelectedEntries() > 0;
|
||||
bool singleEntrySelected = dbWidget->numberOfSelectedEntries() == 1 && dbWidget->currentEntryHasFocus();
|
||||
bool entriesSelected = dbWidget->numberOfSelectedEntries() > 0 && dbWidget->currentEntryHasFocus();
|
||||
bool groupSelected = dbWidget->isGroupSelected();
|
||||
bool recycleBinSelected = dbWidget->isRecycleBinSelected();
|
||||
|
||||
@ -472,7 +493,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
|
||||
m_ui->actionEntryCopyURL->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUrl());
|
||||
m_ui->actionEntryCopyNotes->setEnabled(singleEntrySelected && dbWidget->currentEntryHasNotes());
|
||||
m_ui->menuEntryCopyAttribute->setEnabled(singleEntrySelected);
|
||||
m_ui->menuEntryTotp->setEnabled(true);
|
||||
m_ui->menuEntryTotp->setEnabled(singleEntrySelected);
|
||||
m_ui->actionEntryAutoType->setEnabled(singleEntrySelected);
|
||||
m_ui->actionEntryOpenUrl->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUrl());
|
||||
m_ui->actionEntryTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp());
|
||||
@ -507,13 +528,6 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
|
||||
for (QAction* action : groupActions) {
|
||||
action->setEnabled(false);
|
||||
}
|
||||
m_ui->actionEntryCopyTitle->setEnabled(false);
|
||||
m_ui->actionEntryCopyUsername->setEnabled(false);
|
||||
m_ui->actionEntryCopyPassword->setEnabled(false);
|
||||
m_ui->actionEntryCopyURL->setEnabled(false);
|
||||
m_ui->actionEntryCopyNotes->setEnabled(false);
|
||||
m_ui->menuEntryCopyAttribute->setEnabled(false);
|
||||
m_ui->menuEntryTotp->setEnabled(false);
|
||||
|
||||
m_ui->actionChangeMasterKey->setEnabled(false);
|
||||
m_ui->actionChangeDatabaseSettings->setEnabled(false);
|
||||
@ -539,13 +553,6 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
|
||||
for (QAction* action : groupActions) {
|
||||
action->setEnabled(false);
|
||||
}
|
||||
m_ui->actionEntryCopyTitle->setEnabled(false);
|
||||
m_ui->actionEntryCopyUsername->setEnabled(false);
|
||||
m_ui->actionEntryCopyPassword->setEnabled(false);
|
||||
m_ui->actionEntryCopyURL->setEnabled(false);
|
||||
m_ui->actionEntryCopyNotes->setEnabled(false);
|
||||
m_ui->menuEntryCopyAttribute->setEnabled(false);
|
||||
m_ui->menuEntryTotp->setEnabled(false);
|
||||
|
||||
m_ui->actionChangeMasterKey->setEnabled(false);
|
||||
m_ui->actionChangeDatabaseSettings->setEnabled(false);
|
||||
@ -731,6 +738,22 @@ void MainWindow::databaseTabChanged(int tabIndex)
|
||||
m_actionMultiplexer.setCurrentObject(m_ui->tabWidget->currentDatabaseWidget());
|
||||
}
|
||||
|
||||
void MainWindow::togglePasswordsHidden()
|
||||
{
|
||||
auto dbWidget = m_ui->tabWidget->currentDatabaseWidget();
|
||||
if (dbWidget) {
|
||||
dbWidget->setPasswordsHidden(!dbWidget->isPasswordsHidden());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::toggleUsernamesHidden()
|
||||
{
|
||||
auto dbWidget = m_ui->tabWidget->currentDatabaseWidget();
|
||||
if (dbWidget) {
|
||||
dbWidget->setUsernamesHidden(!dbWidget->isUsernamesHidden());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
// ignore double close events (happens on macOS when closing from the dock)
|
||||
|
@ -112,6 +112,8 @@ private slots:
|
||||
void showErrorMessage(const QString& message);
|
||||
void selectNextDatabaseTab();
|
||||
void selectPreviousDatabaseTab();
|
||||
void togglePasswordsHidden();
|
||||
void toggleUsernamesHidden();
|
||||
|
||||
private:
|
||||
static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0);
|
||||
|
@ -180,7 +180,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>30</height>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
@ -197,7 +197,7 @@
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuImport">
|
||||
<property name="title">
|
||||
<string>Import</string>
|
||||
<string>&Import</string>
|
||||
</property>
|
||||
<addaction name="actionImportKeePass1"/>
|
||||
<addaction name="actionImportCsv"/>
|
||||
@ -234,8 +234,11 @@
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Copy att&ribute to clipboard</string>
|
||||
<string>Copy att&ribute...</string>
|
||||
</property>
|
||||
<addaction name="actionEntryCopyTitle"/>
|
||||
<addaction name="actionEntryCopyURL"/>
|
||||
@ -247,23 +250,25 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Time-based one-time password</string>
|
||||
<string>TOTP...</string>
|
||||
</property>
|
||||
<addaction name="actionEntryCopyTotp"/>
|
||||
<addaction name="actionEntryTotp"/>
|
||||
<addaction name="actionEntryTotpQRCode"/>
|
||||
<addaction name="actionEntrySetupTotp"/>
|
||||
</widget>
|
||||
<addaction name="actionEntryCopyUsername"/>
|
||||
<addaction name="actionEntryCopyPassword"/>
|
||||
<addaction name="menuEntryCopyAttribute"/>
|
||||
<addaction name="menuEntryTotp"/>
|
||||
<addaction name="actionEntryAutoType"/>
|
||||
<addaction name="actionEntryOpenUrl"/>
|
||||
<addaction name="actionEntryNew"/>
|
||||
<addaction name="actionEntryEdit"/>
|
||||
<addaction name="actionEntryClone"/>
|
||||
<addaction name="actionEntryDelete"/>
|
||||
<addaction name="actionEntryNew"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionEntryCopyUsername"/>
|
||||
<addaction name="actionEntryCopyPassword"/>
|
||||
<addaction name="menuEntryCopyAttribute"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menuEntryTotp"/>
|
||||
<addaction name="actionEntryOpenUrl"/>
|
||||
<addaction name="actionEntryAutoType"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuGroups">
|
||||
<property name="title">
|
||||
@ -366,12 +371,18 @@
|
||||
</action>
|
||||
<action name="actionDatabaseNew">
|
||||
<property name="text">
|
||||
<string>&New database</string>
|
||||
<string>&New database...</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Create a new database</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDatabaseMerge">
|
||||
<property name="text">
|
||||
<string>Merge from KeePassX database</string>
|
||||
<string>&Merge from database...</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Merge from another KDBX database</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEntryNew">
|
||||
@ -379,7 +390,10 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Add new entry</string>
|
||||
<string>&New entry</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Add a new entry</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEntryEdit">
|
||||
@ -387,7 +401,10 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&View/Edit entry</string>
|
||||
<string>&Edit entry</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>View or edit entry</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEntryDelete">
|
||||
@ -403,7 +420,10 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Add new group</string>
|
||||
<string>&New group</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Add a new group</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGroupEdit">
|
||||
@ -435,7 +455,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Change &master key...</string>
|
||||
<string>Change master &key...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionChangeDatabaseSettings">
|
||||
@ -443,7 +463,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Database settings</string>
|
||||
<string>&Database settings...</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Database settings</string>
|
||||
@ -476,7 +496,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cop&y password</string>
|
||||
<string>Copy &password</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Copy password to clipboard</string>
|
||||
@ -506,7 +526,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Perform Auto-Type</string>
|
||||
<string>Perform &Auto-Type</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEntryOpenUrl">
|
||||
@ -514,7 +534,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Open URL</string>
|
||||
<string>Open &URL</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLockDatabases">
|
||||
@ -568,12 +588,18 @@
|
||||
</action>
|
||||
<action name="actionImportKeePass1">
|
||||
<property name="text">
|
||||
<string>Import KeePass 1 database...</string>
|
||||
<string>KeePass 1 database...</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Import a KeePass 1 database</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImportCsv">
|
||||
<property name="text">
|
||||
<string>Import CSV file...</string>
|
||||
<string>CSV file...</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Import a CSV file</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEntryTotp">
|
||||
|
@ -41,9 +41,11 @@ SearchWidget::SearchWidget(QWidget* parent)
|
||||
connect(m_searchTimer, SIGNAL(timeout()), this, SLOT(startSearch()));
|
||||
connect(this, SIGNAL(escapePressed()), m_ui->searchEdit, SLOT(clear()));
|
||||
|
||||
new QShortcut(Qt::CTRL + Qt::Key_F, this, SLOT(searchFocus()), nullptr, Qt::ApplicationShortcut);
|
||||
new QShortcut(QKeySequence::Find, this, SLOT(searchFocus()), nullptr, Qt::ApplicationShortcut);
|
||||
new QShortcut(Qt::Key_Escape, m_ui->searchEdit, SLOT(clear()), nullptr, Qt::ApplicationShortcut);
|
||||
|
||||
m_ui->searchEdit->setPlaceholderText(tr("Search (%1)...", "Search placeholder text, %1 is the keyboard shortcut")
|
||||
.arg(QKeySequence(QKeySequence::Find).toString(QKeySequence::NativeText)));
|
||||
m_ui->searchEdit->installEventFilter(this);
|
||||
|
||||
QMenu* searchMenu = new QMenu();
|
||||
|
@ -48,7 +48,7 @@
|
||||
<string notr="true">padding:3px</string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Search...</string>
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>false</bool>
|
||||
|
@ -468,9 +468,10 @@ bool EntryModel::isUsernamesHidden() const
|
||||
/**
|
||||
* Set state of 'Hide Usernames' setting and signal change
|
||||
*/
|
||||
void EntryModel::setUsernamesHidden(const bool hide)
|
||||
void EntryModel::setUsernamesHidden(bool hide)
|
||||
{
|
||||
m_hideUsernames = hide;
|
||||
emit dataChanged(index(0, 0), index(rowCount()-1, columnCount() - 1));
|
||||
emit usernamesHiddenChanged();
|
||||
}
|
||||
|
||||
@ -485,28 +486,13 @@ bool EntryModel::isPasswordsHidden() const
|
||||
/**
|
||||
* Set state of 'Hide Passwords' setting and signal change
|
||||
*/
|
||||
void EntryModel::setPasswordsHidden(const bool hide)
|
||||
void EntryModel::setPasswordsHidden(bool hide)
|
||||
{
|
||||
m_hidePasswords = hide;
|
||||
emit dataChanged(index(0, 0), index(rowCount()-1, columnCount() - 1));
|
||||
emit passwordsHiddenChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle state of 'Hide Usernames' setting
|
||||
*/
|
||||
void EntryModel::toggleUsernamesHidden(const bool hide)
|
||||
{
|
||||
setUsernamesHidden(hide);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle state of 'Hide Passwords' setting
|
||||
*/
|
||||
void EntryModel::togglePasswordsHidden(const bool hide)
|
||||
{
|
||||
setPasswordsHidden(hide);
|
||||
}
|
||||
|
||||
void EntryModel::setPaperClipPixmap(const QPixmap& paperclip)
|
||||
{
|
||||
m_paperClipPixmap = paperclip;
|
||||
|
@ -61,13 +61,9 @@ public:
|
||||
QMimeData* mimeData(const QModelIndexList& indexes) const override;
|
||||
|
||||
void setEntryList(const QList<Entry*>& entries);
|
||||
|
||||
bool isUsernamesHidden() const;
|
||||
void setUsernamesHidden(const bool hide);
|
||||
bool isPasswordsHidden() const;
|
||||
void setPasswordsHidden(const bool hide);
|
||||
|
||||
void setPaperClipPixmap(const QPixmap& paperclip);
|
||||
bool isUsernamesHidden() const;
|
||||
bool isPasswordsHidden() const;
|
||||
|
||||
signals:
|
||||
void switchedToListMode();
|
||||
@ -77,8 +73,8 @@ signals:
|
||||
|
||||
public slots:
|
||||
void setGroup(Group* group);
|
||||
void toggleUsernamesHidden(const bool hide);
|
||||
void togglePasswordsHidden(const bool hide);
|
||||
void setUsernamesHidden(bool hide);
|
||||
void setPasswordsHidden(bool hide);
|
||||
|
||||
private slots:
|
||||
void entryAboutToAdd(Entry* entry);
|
||||
|
@ -50,21 +50,21 @@ EntryView::EntryView(QWidget* parent)
|
||||
setDefaultDropAction(Qt::MoveAction);
|
||||
|
||||
connect(this, SIGNAL(doubleClicked(QModelIndex)), SLOT(emitEntryActivated(QModelIndex)));
|
||||
connect(
|
||||
selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SIGNAL(entrySelectionChanged()));
|
||||
connect(selectionModel(),
|
||||
SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SIGNAL(entrySelectionChanged()));
|
||||
|
||||
connect(m_model, SIGNAL(switchedToListMode()), SLOT(switchToListMode()));
|
||||
connect(m_model, SIGNAL(switchedToSearchMode()), SLOT(switchToSearchMode()));
|
||||
connect(m_model, SIGNAL(usernamesHiddenChanged()), SIGNAL(viewStateChanged()));
|
||||
connect(m_model, SIGNAL(passwordsHiddenChanged()), SIGNAL(viewStateChanged()));
|
||||
connect(this, SIGNAL(clicked(QModelIndex)), SLOT(emitEntryPressed(QModelIndex)));
|
||||
|
||||
m_headerMenu = new QMenu(this);
|
||||
m_headerMenu->setTitle(tr("Customize View"));
|
||||
m_headerMenu->addSection(tr("Customize View"));
|
||||
|
||||
m_hideUsernamesAction = m_headerMenu->addAction(tr("Hide Usernames"), m_model, SLOT(toggleUsernamesHidden(bool)));
|
||||
m_hideUsernamesAction = m_headerMenu->addAction(tr("Hide Usernames"), m_model, SLOT(setUsernamesHidden(bool)));
|
||||
m_hideUsernamesAction->setCheckable(true);
|
||||
m_hidePasswordsAction = m_headerMenu->addAction(tr("Hide Passwords"), m_model, SLOT(togglePasswordsHidden(bool)));
|
||||
m_hidePasswordsAction = m_headerMenu->addAction(tr("Hide Passwords"), m_model, SLOT(setPasswordsHidden(bool)));
|
||||
m_hidePasswordsAction->setCheckable(true);
|
||||
m_headerMenu->addSeparator();
|
||||
|
||||
@ -146,6 +146,18 @@ void EntryView::keyPressEvent(QKeyEvent* event)
|
||||
QTreeView::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void EntryView::focusInEvent(QFocusEvent* event)
|
||||
{
|
||||
emit entrySelectionChanged();
|
||||
QTreeView::focusInEvent(event);
|
||||
}
|
||||
|
||||
void EntryView::focusOutEvent(QFocusEvent* event)
|
||||
{
|
||||
emit entrySelectionChanged();
|
||||
QTreeView::focusOutEvent(event);
|
||||
}
|
||||
|
||||
void EntryView::setGroup(Group* group)
|
||||
{
|
||||
m_model->setGroup(group);
|
||||
@ -176,15 +188,9 @@ bool EntryView::inSearchMode()
|
||||
void EntryView::emitEntryActivated(const QModelIndex& index)
|
||||
{
|
||||
Entry* entry = entryFromIndex(index);
|
||||
|
||||
emit entryActivated(entry, static_cast<EntryModel::ModelColumn>(m_sortModel->mapToSource(index).column()));
|
||||
}
|
||||
|
||||
void EntryView::emitEntryPressed(const QModelIndex& index)
|
||||
{
|
||||
emit entryPressed(entryFromIndex(index));
|
||||
}
|
||||
|
||||
void EntryView::setModel(QAbstractItemModel* model)
|
||||
{
|
||||
Q_UNUSED(model);
|
||||
@ -268,6 +274,11 @@ bool EntryView::isUsernamesHidden() const
|
||||
*/
|
||||
void EntryView::setUsernamesHidden(const bool hide)
|
||||
{
|
||||
bool block = m_hideUsernamesAction->signalsBlocked();
|
||||
m_hideUsernamesAction->blockSignals(true);
|
||||
m_hideUsernamesAction->setChecked(hide);
|
||||
m_hideUsernamesAction->blockSignals(block);
|
||||
|
||||
m_model->setUsernamesHidden(hide);
|
||||
}
|
||||
|
||||
@ -285,6 +296,11 @@ bool EntryView::isPasswordsHidden() const
|
||||
*/
|
||||
void EntryView::setPasswordsHidden(const bool hide)
|
||||
{
|
||||
bool block = m_hidePasswordsAction->signalsBlocked();
|
||||
m_hidePasswordsAction->blockSignals(true);
|
||||
m_hidePasswordsAction->setChecked(hide);
|
||||
m_hidePasswordsAction->blockSignals(block);
|
||||
|
||||
m_model->setPasswordsHidden(hide);
|
||||
}
|
||||
|
||||
|
@ -55,16 +55,16 @@ public slots:
|
||||
|
||||
signals:
|
||||
void entryActivated(Entry* entry, EntryModel::ModelColumn column);
|
||||
void entryPressed(Entry* entry);
|
||||
void entrySelectionChanged();
|
||||
void viewStateChanged();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
void focusInEvent(QFocusEvent* event) override;
|
||||
void focusOutEvent(QFocusEvent* event) override;
|
||||
|
||||
private slots:
|
||||
void emitEntryActivated(const QModelIndex& index);
|
||||
void emitEntryPressed(const QModelIndex& index);
|
||||
void switchToListMode();
|
||||
void switchToSearchMode();
|
||||
void showHeaderMenu(const QPoint& position);
|
||||
|
@ -736,11 +736,9 @@ void TestGui::testTotp()
|
||||
auto* entryView = m_dbWidget->findChild<EntryView*>("entryView");
|
||||
|
||||
QCOMPARE(entryView->model()->rowCount(), 1);
|
||||
|
||||
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::ViewMode);
|
||||
QModelIndex item = entryView->model()->index(0, 1);
|
||||
Entry* entry = entryView->entryFromIndex(item);
|
||||
|
||||
clickIndex(item, entryView, Qt::LeftButton);
|
||||
|
||||
triggerAction("actionEntrySetupTotp");
|
||||
@ -749,21 +747,28 @@ void TestGui::testTotp()
|
||||
|
||||
QApplication::processEvents();
|
||||
|
||||
QString exampleSeed = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq";
|
||||
auto* seedEdit = setupTotpDialog->findChild<QLineEdit*>("seedEdit");
|
||||
seedEdit->setText("");
|
||||
|
||||
QString exampleSeed = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq";
|
||||
QTest::keyClicks(seedEdit, exampleSeed);
|
||||
|
||||
auto* setupTotpButtonBox = setupTotpDialog->findChild<QDialogButtonBox*>("buttonBox");
|
||||
QTest::mouseClick(setupTotpButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
|
||||
QTRY_VERIFY(!setupTotpDialog->isVisible());
|
||||
|
||||
// Make sure the entryView is selected and active
|
||||
entryView->activateWindow();
|
||||
QApplication::processEvents();
|
||||
QTRY_VERIFY(entryView->hasFocus());
|
||||
|
||||
auto* entryEditAction = m_mainWindow->findChild<QAction*>("actionEntryEdit");
|
||||
QWidget* entryEditWidget = toolBar->widgetForAction(entryEditAction);
|
||||
QVERIFY(entryEditWidget->isVisible());
|
||||
QVERIFY(entryEditWidget->isEnabled());
|
||||
QTest::mouseClick(entryEditWidget, Qt::LeftButton);
|
||||
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::EditMode);
|
||||
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
|
||||
|
||||
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
|
||||
editEntryWidget->setCurrentPage(1);
|
||||
auto* attrTextEdit = editEntryWidget->findChild<QPlainTextEdit*>("attributesEdit");
|
||||
QTest::mouseClick(editEntryWidget->findChild<QAbstractButton*>("revealAttributeButton"), Qt::LeftButton);
|
||||
@ -836,15 +841,19 @@ void TestGui::testSearch()
|
||||
// Ensure Down focuses on entry view when search text is selected
|
||||
QTest::keyClick(searchTextEdit, Qt::Key_Down);
|
||||
QTRY_VERIFY(entryView->hasFocus());
|
||||
// Refocus back to search edit
|
||||
QTest::mouseClick(searchTextEdit, Qt::LeftButton);
|
||||
QTRY_VERIFY(searchTextEdit->hasFocus());
|
||||
// Test password copy
|
||||
// Test that password copies (entry has focus)
|
||||
QClipboard* clipboard = QApplication::clipboard();
|
||||
QTest::keyClick(searchTextEdit, Qt::Key_C, Qt::ControlModifier);
|
||||
QModelIndex searchedItem = entryView->model()->index(0, 1);
|
||||
Entry* searchedEntry = entryView->entryFromIndex(searchedItem);
|
||||
QTRY_COMPARE(searchedEntry->password(), clipboard->text());
|
||||
// Refocus back to search edit
|
||||
QTest::mouseClick(searchTextEdit, Qt::LeftButton);
|
||||
QTRY_VERIFY(searchTextEdit->hasFocus());
|
||||
// Test that password does not copy
|
||||
searchTextEdit->selectAll();
|
||||
QTest::keyClick(searchTextEdit, Qt::Key_C, Qt::ControlModifier);
|
||||
QTRY_COMPARE(clipboard->text(), QString("someTHING"));
|
||||
|
||||
// Test case sensitive search
|
||||
searchWidget->setCaseSensitive(true);
|
||||
|
Loading…
Reference in New Issue
Block a user