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

IJHack / QtPass / 24764840037

22 Apr 2026 06:58AM UTC coverage: 27.36% (-0.04%) from 27.404%
24764840037

push

github

web-flow
Fix: QProgressIndicator memory leak and dark mode support (#1129)

* Apply suggested fix to src/qprogressindicator.cpp from Copilot Autofix

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Fix: QProgressIndicator memory leak and dark mode support

- Fix memory leak in KeygenDialog by tracking and deleting QProgressIndicator
- Use std::unique_ptr for automatic memory management
- Add dark mode support: use palette color when no explicit color set
- Update tst_ui test to match new default color behavior
- Add reset to invalid color test in tst_ui.cpp
- Remove duplicate tests from tst_util.cpp

---------

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Henk <henk@annejan.com>

1 of 10 new or added lines in 2 files covered. (10.0%)

26 existing lines in 3 files now uncovered.

1597 of 5837 relevant lines covered (27.36%)

30.43 hits per line

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

0.0
/src/keygendialog.cpp
1
// SPDX-FileCopyrightText: 2015 Anne Jan Brouwer
2
// SPDX-License-Identifier: GPL-3.0-or-later
3
#include "keygendialog.h"
4
#include "configdialog.h"
5
#include "pass.h"
6
#include "qprogressindicator.h"
7
#include "qtpasssettings.h"
8
#include "ui_keygendialog.h"
9
#include "util.h"
10
#include <QMessageBox>
11
#include <QRegularExpression>
12

13
#ifdef QT_DEBUG
14
#include "debughelper.h"
15
#endif
16

17
/**
18
 * @brief KeygenDialog::KeygenDialog basic constructor.
19
 * @param parent
20
 */
21
KeygenDialog::KeygenDialog(ConfigDialog *parent)
×
NEW
22
    : QDialog(parent), ui(new Ui::KeygenDialog), m_progressIndicator(nullptr) {
×
23
  ui->setupUi(this);
×
24
  dialog = parent;
×
25

26
  // Restore dialog state
27
  QByteArray savedGeometry = QtPassSettings::getDialogGeometry("keygenDialog");
×
28
  bool hasSavedGeometry = !savedGeometry.isEmpty();
29
  if (hasSavedGeometry) {
×
30
    restoreGeometry(savedGeometry);
×
31
  }
32
  if (QtPassSettings::isDialogMaximized("keygenDialog")) {
×
33
    showMaximized();
×
34
  } else if (hasSavedGeometry) {
×
35
    move(QtPassSettings::getDialogPos("keygenDialog"));
×
36
    resize(QtPassSettings::getDialogSize("keygenDialog"));
×
37
  } else {
38
    // Let window manager handle positioning for first launch
39
  }
40

41
  ui->plainTextEdit->setPlainText(Pass::getDefaultKeyTemplate());
×
42
}
×
43

44
/**
45
 * @brief KeygenDialog::~KeygenDialog even more basic destructor.
46
 */
47
KeygenDialog::~KeygenDialog() { delete ui; }
×
48

49
/**
50
 * @brief KeygenDialog::on_passphrase1_textChanged see if we want to have
51
 * protection.
52
 * @param arg1
53
 */
54
void KeygenDialog::on_passphrase1_textChanged(const QString &arg1) {
×
55
  bool state = ui->passphrase1->text() == ui->passphrase2->text();
×
56
  if (state) {
×
57
    replace("Passphrase", arg1);
×
58
    no_protection(arg1.isEmpty());
×
59
  }
60

61
  ui->buttonBox->setEnabled(state);
×
62
}
×
63

64
/**
65
 * @brief KeygenDialog::on_passphrase2_textChanged wrapper for
66
 * KeygenDialog::on_passphrase1_textChanged
67
 * @param arg1
68
 */
69
void KeygenDialog::on_passphrase2_textChanged(const QString &arg1) {
×
70
  on_passphrase1_textChanged(arg1);
×
71
}
×
72

73
/**
74
 * @brief KeygenDialog::on_checkBox_stateChanged expert mode enabled / disabled.
75
 * @param arg1
76
 */
77
void KeygenDialog::on_checkBox_stateChanged(int arg1) {
×
78
  ui->plainTextEdit->setReadOnly(!arg1);
×
79
  ui->plainTextEdit->setEnabled(arg1);
×
80
}
×
81

82
/**
83
 * @brief KeygenDialog::on_email_textChanged update the email in keypair
84
 * generation template.
85
 * @param arg1
86
 */
87
void KeygenDialog::on_email_textChanged(const QString &arg1) {
×
88
  replace("Name-Email", arg1);
×
89
}
×
90

91
/**
92
 * @brief KeygenDialog::on_name_textChanged update the name in keypair
93
 * generation template.
94
 * @param arg1
95
 */
96
void KeygenDialog::on_name_textChanged(const QString &arg1) {
×
97
  replace("Name-Real", arg1);
×
98
}
×
99

100
/**
101
 * @brief KeygenDialog::replace do some regex magic. fore replacing Passphrase
102
 * and protection in keypair generation template.
103
 * @param key
104
 * @param value
105
 */
106
void KeygenDialog::replace(const QString &key, const QString &value) {
×
107
  QStringList clear;
×
108
  QString expert = ui->plainTextEdit->toPlainText();
×
109
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
110
  const QStringList lines =
111
      expert.split(Util::newLinesRegex(), Qt::SkipEmptyParts);
×
112
#else
113
  const QStringList lines =
114
      expert.split(Util::newLinesRegex(), QString::SkipEmptyParts);
115
#endif
116
  for (QString line : lines) {
×
117
    line.replace(QRegularExpression(key + ":.*"), key + ": " + value);
×
118
    if (key == "Passphrase") {
×
119
      line.replace("%no-protection", "Passphrase: " + value);
×
120
    }
121
    clear.append(line);
122
  }
123
  ui->plainTextEdit->setPlainText(clear.join("\n"));
×
124
}
×
125

126
/**
127
 * @brief KeygenDialog::no_protection remove protection in keypair generation
128
 * template.
129
 * @param enable
130
 */
131
void KeygenDialog::no_protection(bool enable) {
×
132
  QStringList clear;
×
133
  QString expert = ui->plainTextEdit->toPlainText();
×
134
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
135
  const QStringList lines =
136
      expert.split(Util::newLinesRegex(), Qt::SkipEmptyParts);
×
137
#else
138
  const QStringList lines =
139
      expert.split(Util::newLinesRegex(), QString::SkipEmptyParts);
140
#endif
141
  for (QString line : lines) {
×
142
    bool remove = false;
143
    if (!enable) {
×
144
      if (line.indexOf("%no-protection") == 0) {
×
145
        remove = true;
146
      }
147
    } else {
148
      if (line.indexOf("Passphrase") == 0) {
×
149
        line = "%no-protection";
×
150
      }
151
    }
152
    if (!remove) {
153
      clear.append(line);
154
    }
155
  }
156
  ui->plainTextEdit->setPlainText(clear.join("\n"));
×
157
}
×
158

159
/**
160
 * @brief KeygenDialog::done we are going to create a key pair and show the
161
 * QProgressIndicator and some text since the generation will take some time.
162
 * @param r
163
 */
164
void KeygenDialog::done(int r) {
×
165
  if (QDialog::Accepted == r) { //  ok was pressed
×
166
                                // check name
167
    if (ui->name->text().length() < 5) {
×
168
      QMessageBox::critical(this, tr("Invalid name"),
×
169
                            tr("Name must be at least 5 characters long."));
×
170
      return;
×
171
    }
172

173
    // check email
174
    static const QRegularExpression mailre(
175
        QRegularExpression::anchoredPattern(
×
176
            R"(\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b)"),
177
        QRegularExpression::CaseInsensitiveOption);
×
178
    if (!mailre.match(ui->email->text()).hasMatch()) {
×
179
      QMessageBox::critical(
×
180
          this, tr("Invalid email"),
×
181
          tr("The email address you typed is not a valid email address."));
×
182
      return;
×
183
    }
184

185
    ui->widget->setEnabled(false);
×
186
    ui->buttonBox->setEnabled(false);
×
187
    ui->checkBox->setEnabled(false);
×
188
    ui->plainTextEdit->setEnabled(false);
×
189

NEW
190
    if (!m_progressIndicator) {
×
NEW
191
      m_progressIndicator = std::make_unique<QProgressIndicator>();
×
NEW
192
      m_progressIndicator->setParent(this);
×
NEW
193
      m_progressIndicator->startAnimation();
×
NEW
194
      m_progressIndicator->setSizePolicy(QSizePolicy::Expanding,
×
195
                                         QSizePolicy::Expanding);
NEW
196
      this->layout()->addWidget(m_progressIndicator.get());
×
197
    }
198

199
    ui->frame->hide();
×
200
    ui->label->setText(
×
201
        tr("This operation can take some minutes.<br />"
×
202
           "We need to generate a lot of random bytes. It is a good idea to "
203
           "perform some other action (type on the keyboard, move the mouse, "
204
           "utilize the disks) during the prime generation; this gives the "
205
           "random number generator a better chance to gain enough entropy."));
206

207
    this->show();
×
UNCOV
208
    dialog->genKey(ui->plainTextEdit->toPlainText(), this);
×
209
  } else { //  cancel, close or exc was pressed
210
    QDialog::done(r);
×
211
    return;
×
212
  }
213
}
214

215
/**
216
 * @brief KeygenDialog::closeEvent we are done here.
217
 * @param event
218
 */
219
void KeygenDialog::closeEvent(QCloseEvent *event) {
×
220
  QtPassSettings::setDialogGeometry("keygenDialog", saveGeometry());
×
221
  if (!isMaximized()) {
×
222
    QtPassSettings::setDialogPos("keygenDialog", pos());
×
223
    QtPassSettings::setDialogSize("keygenDialog", size());
×
224
  }
225
  QtPassSettings::setDialogMaximized("keygenDialog", isMaximized());
×
226
  event->accept();
227
}
×
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