• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IJHack / QtPass / 23715391743

29 Mar 2026 05:57PM UTC coverage: 18.36% (-0.04%) from 18.404%
23715391743

push

github

web-flow
Merge pull request #834 from IJHack/fix/usersdialog-ai-findings

Fix 6 code quality findings in UsersDialog and ConfigDialog

0 of 17 new or added lines in 2 files covered. (0.0%)

2 existing lines in 1 file now uncovered.

925 of 5038 relevant lines covered (18.36%)

7.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/usersdialog.cpp
1
// SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
2
// SPDX-License-Identifier: GPL-3.0-or-later
3
#include "usersdialog.h"
4
#include "qtpasssettings.h"
5
#include "ui_usersdialog.h"
6
#include <QApplication>
7
#include <QCloseEvent>
8
#include <QKeyEvent>
9
#include <QMessageBox>
10
#include <QRegularExpression>
11
#include <QSet>
12
#include <QWidget>
13
#include <utility>
14

15
#ifdef QT_DEBUG
16
#include "debughelper.h"
17
#endif
18
/**
19
 * @brief UsersDialog::UsersDialog basic constructor
20
 * @param parent
21
 */
22
UsersDialog::UsersDialog(QString dir, QWidget *parent)
×
23
    : QDialog(parent), ui(new Ui::UsersDialog), m_dir(std::move(dir)) {
×
24

25
  ui->setupUi(this);
×
26

27
  QList<UserInfo> users = QtPassSettings::getPass()->listKeys();
×
28
  if (users.isEmpty()) {
×
29
    QMessageBox::critical(parent, tr("Keylist missing"),
×
30
                          tr("Could not fetch list of available GPG keys"));
×
31
    reject();
×
32
  }
33

34
  QList<UserInfo> secret_keys = QtPassSettings::getPass()->listKeys("", true);
×
35
  QSet<QString> secretKeyIds;
36
  for (const UserInfo &sec : secret_keys) {
×
37
    secretKeyIds.insert(sec.key_id);
×
38
  }
39
  for (auto &user : users) {
×
40
    if (secretKeyIds.contains(user.key_id)) {
×
41
      user.have_secret = true;
×
42
    }
43
  }
44

45
  QList<UserInfo> selected_users;
×
46
  int count = 0;
×
47

48
  QStringList recipients = QtPassSettings::getPass()->getRecipientString(
×
49
      m_dir.isEmpty() ? "" : m_dir, " ", &count);
×
50
  if (!recipients.isEmpty()) {
×
51
    selected_users = QtPassSettings::getPass()->listKeys(recipients);
×
52
  }
53
  QSet<QString> selectedKeyIds;
54
  for (const UserInfo &sel : selected_users) {
×
55
    selectedKeyIds.insert(sel.key_id);
×
56
  }
57
  for (auto &user : users) {
×
58
    if (selectedKeyIds.contains(user.key_id)) {
×
59
      user.enabled = true;
×
60
    }
61
  }
62

63
  if (count > selected_users.size()) {
×
64
    // Some keys seem missing from keyring, add them separately
65
    QStringList allRecipients = QtPassSettings::getPass()->getRecipientList(
×
66
        m_dir.isEmpty() ? "" : m_dir);
×
67
    for (const QString &recipient : allRecipients) {
×
68
      if (QtPassSettings::getPass()->listKeys(recipient).empty()) {
×
69
        UserInfo i;
×
70
        i.enabled = true;
×
71
        i.key_id = recipient;
×
72
        i.name = " ?? " + tr("Key not found in keyring");
×
73
        users.append(i);
74
      }
×
75
    }
76
  }
77

78
  m_userList = users;
79
  populateList();
×
80

81
  connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
×
82
          &UsersDialog::accept);
×
83
  connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
×
84
  connect(ui->listWidget, &QListWidget::itemChanged, this,
×
85
          &UsersDialog::itemChange);
×
86

87
  ui->lineEdit->setClearButtonEnabled(true);
×
88
}
×
89

90
/**
91
 * @brief UsersDialog::~UsersDialog basic destructor.
92
 */
93
UsersDialog::~UsersDialog() { delete ui; }
×
94

95
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
96
Q_DECLARE_METATYPE(UserInfo *)
97
Q_DECLARE_METATYPE(const UserInfo *)
98
#endif
99

100
/**
101
 * @brief UsersDialog::accept
102
 */
103
void UsersDialog::accept() {
×
104
  QtPassSettings::getPass()->Init(m_dir, m_userList);
×
105

106
  QDialog::accept();
×
107
}
×
108

109
/**
110
 * @brief UsersDialog::closeEvent might have to store size and location if that
111
 * is wanted.
112
 * @param event
113
 */
114
void UsersDialog::closeEvent(QCloseEvent *event) {
×
115
  // TODO(annejan): save window size or something
116
  event->accept();
117
}
×
118

119
/**
120
 * @brief UsersDialog::keyPressEvent clear the lineEdit when escape is pressed.
121
 * No action for Enter currently.
122
 * @param event
123
 */
124
void UsersDialog::keyPressEvent(QKeyEvent *event) {
×
125
  switch (event->key()) {
×
126
  case Qt::Key_Escape:
×
127
    ui->lineEdit->clear();
×
128
    break;
×
129
  default:
130
    break;
131
  }
132
}
×
133

134
/**
135
 * @brief UsersDialog::itemChange update the item information.
136
 * @param item
137
 */
138
void UsersDialog::itemChange(QListWidgetItem *item) {
×
139
  if (!item) {
×
UNCOV
140
    return;
×
141
  }
NEW
142
  bool ok = false;
×
NEW
143
  const int index = item->data(Qt::UserRole).toInt(&ok);
×
NEW
144
  if (!ok || index < 0 || index >= m_userList.size()) {
×
145
    return;
146
  }
NEW
147
  m_userList[index].enabled = item->checkState() == Qt::Checked;
×
148
}
149

150
/**
151
 * @brief UsersDialog::populateList update the view based on filter options
152
 * (such as searching).
153
 * @param filter
154
 */
155
void UsersDialog::populateList(const QString &filter) {
×
156
  QRegularExpression nameFilter(
157
      QRegularExpression::wildcardToRegularExpression("*" + filter + "*"),
×
158
      QRegularExpression::CaseInsensitiveOption);
×
159
  ui->listWidget->clear();
×
160

NEW
161
  for (int i = 0; i < m_userList.size(); ++i) {
×
162
    const auto &user = m_userList.at(i);
163
    if (!passesFilter(user, filter, nameFilter)) {
×
164
      continue;
×
165
    }
166

167
    auto *item = new QListWidgetItem(buildUserText(user), ui->listWidget);
×
168
    applyUserStyling(item, user);
×
169
    item->setCheckState(user.enabled ? Qt::Checked : Qt::Unchecked);
×
NEW
170
    item->setData(Qt::UserRole, QVariant::fromValue(i));
×
171
    ui->listWidget->addItem(item);
×
172
  }
173
}
×
174

175
bool UsersDialog::passesFilter(const UserInfo &user, const QString &filter,
×
176
                               const QRegularExpression &nameFilter) const {
177
  if (!filter.isEmpty() && !nameFilter.match(user.name).hasMatch()) {
×
178
    return false;
179
  }
180
  if (!user.isValid() && !ui->checkBox->isChecked()) {
×
181
    return false;
182
  }
183
  const bool expired = isUserExpired(user);
×
184
  return !(expired && !ui->checkBox->isChecked());
×
185
}
186

187
bool UsersDialog::isUserExpired(const UserInfo &user) const {
×
188
  return user.expiry.toSecsSinceEpoch() > 0 &&
×
189
         QDateTime::currentDateTime() > user.expiry;
×
190
}
191

192
QString UsersDialog::buildUserText(const UserInfo &user) const {
×
193
  QString text = user.name + "\n" + user.key_id;
×
194
  if (user.created.toSecsSinceEpoch() > 0) {
×
195
    text += " " + tr("created") + " " +
×
196
            QLocale::system().toString(user.created, QLocale::ShortFormat);
×
197
  }
198
  if (user.expiry.toSecsSinceEpoch() > 0) {
×
199
    text += " " + tr("expires") + " " +
×
200
            QLocale::system().toString(user.expiry, QLocale::ShortFormat);
×
201
  }
202
  return text;
×
203
}
204

205
void UsersDialog::applyUserStyling(QListWidgetItem *item,
×
206
                                   const UserInfo &user) const {
NEW
207
  const QString originalText = item->text();
×
208
  if (user.have_secret) {
×
NEW
209
    const QPalette palette = QApplication::palette();
×
NEW
210
    item->setForeground(palette.color(QPalette::Link));
×
UNCOV
211
    QFont font = item->font();
×
212
    font.setBold(true);
213
    item->setFont(font);
×
214
  } else if (!user.isValid()) {
×
215
    item->setBackground(Qt::darkRed);
×
216
    item->setForeground(Qt::white);
×
NEW
217
    item->setText(tr("[INVALID] ") + originalText);
×
218
  } else if (isUserExpired(user)) {
×
219
    item->setForeground(Qt::darkRed);
×
NEW
220
    item->setText(tr("[EXPIRED] ") + originalText);
×
221
  } else if (!user.fullyValid()) {
×
222
    item->setBackground(Qt::darkYellow);
×
223
    item->setForeground(Qt::white);
×
NEW
224
    item->setText(tr("[PARTIAL] ") + originalText);
×
225
  } else {
NEW
226
    item->setText(originalText);
×
227
  }
228
}
×
229

230
/**
231
 * @brief UsersDialog::on_lineEdit_textChanged typing in the searchbox.
232
 * @param filter
233
 */
234
void UsersDialog::on_lineEdit_textChanged(const QString &filter) {
×
235
  populateList(filter);
×
236
}
×
237

238
/**
239
 * @brief UsersDialog::on_checkBox_clicked filtering.
240
 */
241
void UsersDialog::on_checkBox_clicked() { populateList(ui->lineEdit->text()); }
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc