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

IJHack / QtPass / 24125716387

08 Apr 2026 08:27AM UTC coverage: 21.044%. Remained the same
24125716387

Pull #930

github

web-flow
Merge 850974b8f into 4828f4ef1
Pull Request #930: chore: remove commented-out debug code

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

9 existing lines in 4 files now uncovered.

1109 of 5270 relevant lines covered (21.04%)

7.8 hits per line

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

0.0
/src/configdialog.cpp
1
// SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
2
// SPDX-License-Identifier: GPL-3.0-or-later
3
#include "configdialog.h"
4
#include "keygendialog.h"
5
#include "mainwindow.h"
6
#include "qtpasssettings.h"
7
#include "ui_configdialog.h"
8
#include "util.h"
9
#include <QClipboard>
10
#include <QDir>
11
#include <QFileDialog>
12
#include <QMessageBox>
13
#include <QPushButton>
14
#include <QSystemTrayIcon>
15
#include <QTableWidgetItem>
16
#include <utility>
17
#ifdef Q_OS_WIN
18
#include <windows.h>
19
#endif
20

21
#ifdef QT_DEBUG
22
#include "debughelper.h"
23
#endif
24

25
/**
26
 * @brief ConfigDialog::ConfigDialog this sets up the configuration screen.
27
 * @param parent
28
 */
29
ConfigDialog::ConfigDialog(MainWindow *parent)
×
30
    : QDialog(parent), ui(new Ui::ConfigDialog) {
×
31
  mainWindow = parent;
×
32
  ui->setupUi(this);
×
33

34
  // Restore dialog state
35
  restoreGeometry(QtPassSettings::getDialogGeometry("configDialog"));
×
36
  if (QtPassSettings::isDialogMaximized("configDialog")) {
×
37
    showMaximized();
×
38
  } else {
39
    move(QtPassSettings::getDialogPos("configDialog"));
×
40
    resize(QtPassSettings::getDialogSize("configDialog"));
×
41
  }
42

43
  ui->passPath->setText(QtPassSettings::getPassExecutable());
×
44
  setGitPath(QtPassSettings::getGitExecutable());
×
45
  ui->gpgPath->setText(QtPassSettings::getGpgExecutable());
×
46
  ui->storePath->setText(QtPassSettings::getPassStore());
×
47

48
  ui->spinBoxAutoclearSeconds->setValue(QtPassSettings::getAutoclearSeconds());
×
49
  ui->spinBoxAutoclearPanelSeconds->setValue(
×
50
      QtPassSettings::getAutoclearPanelSeconds());
×
51
  ui->checkBoxHidePassword->setChecked(QtPassSettings::isHidePassword());
×
52
  ui->checkBoxHideContent->setChecked(QtPassSettings::isHideContent());
×
53
  ui->checkBoxUseMonospace->setChecked(QtPassSettings::isUseMonospace());
×
54
  ui->checkBoxDisplayAsIs->setChecked(QtPassSettings::isDisplayAsIs());
×
55
  ui->checkBoxNoLineWrapping->setChecked(QtPassSettings::isNoLineWrapping());
×
56
  ui->checkBoxAddGPGId->setChecked(QtPassSettings::isAddGPGId(true));
×
57

58
  if (QSystemTrayIcon::isSystemTrayAvailable()) {
×
59
    ui->checkBoxHideOnClose->setChecked(QtPassSettings::isHideOnClose());
×
60
    ui->checkBoxStartMinimized->setChecked(QtPassSettings::isStartMinimized());
×
61
  } else {
62
    ui->checkBoxUseTrayIcon->setEnabled(false);
×
63
    ui->checkBoxUseTrayIcon->setToolTip(tr("System tray is not available"));
×
64
    ui->checkBoxHideOnClose->setEnabled(false);
×
65
    ui->checkBoxStartMinimized->setEnabled(false);
×
66
  }
67

68
  ui->checkBoxAvoidCapitals->setChecked(QtPassSettings::isAvoidCapitals());
×
69
  ui->checkBoxAvoidNumbers->setChecked(QtPassSettings::isAvoidNumbers());
×
70
  ui->checkBoxLessRandom->setChecked(QtPassSettings::isLessRandom());
×
71
  ui->checkBoxUseSymbols->setChecked(QtPassSettings::isUseSymbols());
×
72
  ui->plainTextEditTemplate->setPlainText(QtPassSettings::getPassTemplate());
×
73
  ui->checkBoxTemplateAllFields->setChecked(
×
74
      QtPassSettings::isTemplateAllFields());
×
75
  ui->checkBoxAutoPull->setChecked(QtPassSettings::isAutoPull());
×
76
  ui->checkBoxAutoPush->setChecked(QtPassSettings::isAutoPush());
×
77
  ui->checkBoxAlwaysOnTop->setChecked(QtPassSettings::isAlwaysOnTop());
×
78

79
#if defined(Q_OS_WIN)
80
  ui->checkBoxUseOtp->hide();
81
  ui->checkBoxUseQrencode->hide();
82
  ui->label_10->hide();
83
#endif
84

85
  if (!isPassOtpAvailable()) {
×
86
    ui->checkBoxUseOtp->setEnabled(false);
×
87
    ui->checkBoxUseOtp->setToolTip(
×
88
        tr("Pass OTP extension needs to be installed"));
×
89
  }
90

91
  if (!isQrencodeAvailable()) {
×
92
    ui->checkBoxUseQrencode->setEnabled(false);
93
    ui->checkBoxUseQrencode->setToolTip(tr("qrencode needs to be installed"));
×
94
  }
95

96
  setProfiles(QtPassSettings::getProfiles(), QtPassSettings::getProfile());
×
97
  setPwgenPath(QtPassSettings::getPwgenExecutable());
×
98
  setPasswordConfiguration(QtPassSettings::getPasswordConfiguration());
×
99

100
  usePass(QtPassSettings::isUsePass());
×
101
  useAutoclear(QtPassSettings::isUseAutoclear());
×
102
  useAutoclearPanel(QtPassSettings::isUseAutoclearPanel());
×
103
  useTrayIcon(QtPassSettings::isUseTrayIcon());
×
104
  useGit(QtPassSettings::isUseGit());
×
105

106
  useOtp(QtPassSettings::isUseOtp());
×
107
  useQrencode(QtPassSettings::isUseQrencode());
×
108

109
  usePwgen(QtPassSettings::isUsePwgen());
×
110
  useTemplate(QtPassSettings::isUseTemplate());
×
111

112
  ui->profileTable->verticalHeader()->hide();
×
113
  ui->profileTable->horizontalHeader()->setSectionResizeMode(
×
114
      1, QHeaderView::Stretch);
115
  ui->label->setText(ui->label->text() + VERSION);
×
116
  ui->comboBoxClipboard->clear();
×
117

118
  ui->comboBoxClipboard->addItem(tr("No Clipboard"));
×
119
  ui->comboBoxClipboard->addItem(tr("Always copy to clipboard"));
×
120
  ui->comboBoxClipboard->addItem(tr("On-demand copy to clipboard"));
×
121

122
  int currentIndex = QtPassSettings::getClipBoardTypeRaw();
×
123
  ui->comboBoxClipboard->setCurrentIndex(currentIndex);
×
124
  on_comboBoxClipboard_activated(currentIndex);
×
125

126
  QClipboard *clip = QApplication::clipboard();
×
127
  if (!clip->supportsSelection()) {
×
128
    useSelection(false);
×
129
    ui->checkBoxSelection->setVisible(false);
×
130
  } else {
131
    useSelection(QtPassSettings::isUseSelection());
×
132
  }
133

134
  if (!Util::configIsValid()) {
×
135
    // Show Programs tab, which is likely
136
    // what the user needs to fix now.
137
    ui->tabWidget->setCurrentIndex(1);
×
138
  }
139

140
  connect(ui->profileTable, &QTableWidget::itemChanged, this,
×
141
          &ConfigDialog::onProfileTableItemChanged);
×
142
  connect(this, &ConfigDialog::accepted, this, &ConfigDialog::on_accepted);
×
143
}
×
144

145
/**
146
 * @brief ConfigDialog::~ConfigDialog config destructor, makes sure the
147
 * mainWindow knows about git, gpg and pass executables.
148
 */
149
ConfigDialog::~ConfigDialog() {
×
150
  QtPassSettings::setGitExecutable(ui->gitPath->text());
×
151
  QtPassSettings::setGpgExecutable(ui->gpgPath->text());
×
152
  QtPassSettings::setPassExecutable(ui->passPath->text());
×
153
}
×
154

155
/**
156
 * @brief ConfigDialog::setGitPath set the git executable path.
157
 * Make sure the checkBoxUseGit is updated.
158
 * @param path
159
 */
160
void ConfigDialog::setGitPath(const QString &path) {
×
161
  ui->gitPath->setText(path);
×
162
  ui->checkBoxUseGit->setEnabled(!path.isEmpty());
×
163
  if (path.isEmpty()) {
×
164
    useGit(false);
×
165
  }
166
}
×
167

168
/**
169
 * @brief ConfigDialog::usePass set wether or not we want to use pass.
170
 * Update radio buttons accordingly.
171
 * @param usePass
172
 */
173
void ConfigDialog::usePass(bool usePass) {
×
174
  ui->radioButtonNative->setChecked(!usePass);
×
175
  ui->radioButtonPass->setChecked(usePass);
×
176
  setGroupBoxState();
×
177
}
×
178

179
/**
180
 * @brief Validates the configuration table fields and enables or disables the
181
 * OK button accordingly.
182
 * @example
183
 * ConfigDialog dialog;
184
 * QTableWidgetItem *item = dialog.findChild<QTableWidgetItem*>();
185
 * dialog.validate(item);
186
 *
187
 * @param QTableWidgetItem *item - The table item to validate; if null,
188
 * validates all relevant items in the profile table.
189
 * @return void - This function does not return a value.
190
 */
191
void ConfigDialog::validate(QTableWidgetItem *item) {
×
192
  bool status = true;
193

194
  if (item == nullptr) {
×
195
    for (int i = 0; i < ui->profileTable->rowCount(); i++) {
×
196
      for (int j = 0; j < ui->profileTable->columnCount(); j++) {
×
197
        QTableWidgetItem *_item = ui->profileTable->item(i, j);
×
198

199
        if (_item->text().isEmpty() && j != 2) {
×
200
          _item->setBackground(Qt::red);
×
201
          _item->setToolTip(tr("This field is required"));
×
202
          status = false;
203
          break;
204
        } else {
205
          _item->setToolTip(QString());
×
206
        }
207
      }
208

209
      if (!status) {
210
        break;
211
      }
212
    }
213
  } else {
214
    if (item->text().isEmpty() && item->column() != 2) {
×
215
      item->setBackground(Qt::red);
×
216
      item->setToolTip(tr("This field is required"));
×
217
      status = false;
218
    } else {
219
      item->setToolTip(QString());
×
220
    }
221
  }
222

223
  ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status);
×
224
}
×
225

226
/**
227
 * @brief Saves the configuration dialog settings to persistent application
228
 * settings.
229
 * @example
230
 * ConfigDialog dialog;
231
 * dialog.on_accepted();
232
 * // Expected output: All UI-selected configuration values are stored via
233
 * QtPassSettings.
234
 *
235
 * @return void - This method does not return a value.
236
 */
237
void ConfigDialog::on_accepted() {
×
238
  QtPassSettings::setPassExecutable(ui->passPath->text());
×
239
  QtPassSettings::setGitExecutable(ui->gitPath->text());
×
240
  QtPassSettings::setGpgExecutable(ui->gpgPath->text());
×
241
  QtPassSettings::setPassStore(
×
242
      Util::normalizeFolderPath(ui->storePath->text()));
×
243
  QtPassSettings::setUsePass(ui->radioButtonPass->isChecked());
×
244
  QtPassSettings::setClipBoardType(ui->comboBoxClipboard->currentIndex());
×
245
  QtPassSettings::setUseSelection(ui->checkBoxSelection->isChecked());
×
246
  QtPassSettings::setUseAutoclear(ui->checkBoxAutoclear->isChecked());
×
247
  QtPassSettings::setAutoclearSeconds(ui->spinBoxAutoclearSeconds->value());
×
248
  QtPassSettings::setUseAutoclearPanel(ui->checkBoxAutoclearPanel->isChecked());
×
249
  QtPassSettings::setAutoclearPanelSeconds(
×
250
      ui->spinBoxAutoclearPanelSeconds->value());
×
251
  QtPassSettings::setHidePassword(ui->checkBoxHidePassword->isChecked());
×
252
  QtPassSettings::setHideContent(ui->checkBoxHideContent->isChecked());
×
253
  QtPassSettings::setUseMonospace(ui->checkBoxUseMonospace->isChecked());
×
254
  QtPassSettings::setDisplayAsIs(ui->checkBoxDisplayAsIs->isChecked());
×
255
  QtPassSettings::setNoLineWrapping(ui->checkBoxNoLineWrapping->isChecked());
×
256
  QtPassSettings::setAddGPGId(ui->checkBoxAddGPGId->isChecked());
×
257
  QtPassSettings::setUseTrayIcon(ui->checkBoxUseTrayIcon->isEnabled() &&
×
258
                                 ui->checkBoxUseTrayIcon->isChecked());
×
259
  QtPassSettings::setHideOnClose(ui->checkBoxHideOnClose->isEnabled() &&
×
260
                                 ui->checkBoxHideOnClose->isChecked());
×
261
  QtPassSettings::setStartMinimized(ui->checkBoxStartMinimized->isEnabled() &&
×
262
                                    ui->checkBoxStartMinimized->isChecked());
×
263
  QtPassSettings::setProfiles(getProfiles());
×
264
  QtPassSettings::setUseGit(ui->checkBoxUseGit->isChecked());
×
265
  QtPassSettings::setUseOtp(ui->checkBoxUseOtp->isChecked());
×
266
  QtPassSettings::setUseQrencode(ui->checkBoxUseQrencode->isChecked());
×
267
  QtPassSettings::setPwgenExecutable(ui->pwgenPath->text());
×
268
  QtPassSettings::setUsePwgen(ui->checkBoxUsePwgen->isChecked());
×
269
  QtPassSettings::setAvoidCapitals(ui->checkBoxAvoidCapitals->isChecked());
×
270
  QtPassSettings::setAvoidNumbers(ui->checkBoxAvoidNumbers->isChecked());
×
271
  QtPassSettings::setLessRandom(ui->checkBoxLessRandom->isChecked());
×
272
  QtPassSettings::setUseSymbols(ui->checkBoxUseSymbols->isChecked());
×
273
  QtPassSettings::setPasswordConfiguration(getPasswordConfiguration());
×
274
  QtPassSettings::setUseTemplate(ui->checkBoxUseTemplate->isChecked());
×
275
  QtPassSettings::setPassTemplate(ui->plainTextEditTemplate->toPlainText());
×
276
  QtPassSettings::setTemplateAllFields(
×
277
      ui->checkBoxTemplateAllFields->isChecked());
×
278
  QtPassSettings::setAutoPush(ui->checkBoxAutoPush->isChecked());
×
279
  QtPassSettings::setAutoPull(ui->checkBoxAutoPull->isChecked());
×
280
  QtPassSettings::setAlwaysOnTop(ui->checkBoxAlwaysOnTop->isChecked());
×
281

282
  QtPassSettings::setVersion(VERSION);
×
283
}
×
284

285
/**
286
 * @brief Automatically detects required external binaries in the system PATH
287
 * and updates the dialog fields.
288
 * @example
289
 * ConfigDialog configDialog;
290
 * configDialog.on_autodetectButton_clicked();
291
 *
292
 * @return void - This function does not return a value.
293
 */
294
void ConfigDialog::on_autodetectButton_clicked() {
×
295
  QString pass = Util::findBinaryInPath("pass");
×
296
  if (!pass.isEmpty()) {
×
297
    ui->passPath->setText(pass);
×
298
  }
299
  usePass(!pass.isEmpty());
×
300
  QString gpg = Util::findBinaryInPath("gpg2");
×
301
  if (gpg.isEmpty()) {
×
302
    gpg = Util::findBinaryInPath("gpg");
×
303
  }
304
  if (!gpg.isEmpty()) {
×
305
    ui->gpgPath->setText(gpg);
×
306
  }
307
  QString git = Util::findBinaryInPath("git");
×
308
  if (!git.isEmpty()) {
×
309
    ui->gitPath->setText(git);
×
310
  }
311
  QString pwgen = Util::findBinaryInPath("pwgen");
×
312
  if (!pwgen.isEmpty()) {
×
313
    ui->pwgenPath->setText(pwgen);
×
314
  }
315
}
×
316

317
/**
318
 * @brief ConfigDialog::on_radioButtonNative_clicked wrapper for
319
 * ConfigDialog::setGroupBoxState()
320
 */
321
void ConfigDialog::on_radioButtonNative_clicked() { setGroupBoxState(); }
×
322

323
/**
324
 * @brief ConfigDialog::on_radioButtonPass_clicked wrapper for
325
 * ConfigDialog::setGroupBoxState()
326
 */
327
void ConfigDialog::on_radioButtonPass_clicked() { setGroupBoxState(); }
×
328

329
/**
330
 * @brief ConfigDialog::getSecretKeys get list of secret/private keys
331
 * @return QStringList keys
332
 */
333
auto ConfigDialog::getSecretKeys() -> QStringList {
×
334
  QList<UserInfo> keys = QtPassSettings::getPass()->listKeys("", true);
×
335
  QStringList names;
×
336

337
  if (keys.empty()) {
×
338
    return names;
339
  }
340

341
  foreach (const UserInfo &sec, keys)
×
342
    names << sec.name;
×
343

344
  return names;
×
345
}
346

347
/**
348
 * @brief ConfigDialog::setGroupBoxState update checkboxes.
349
 */
350
void ConfigDialog::setGroupBoxState() {
×
351
  bool state = ui->radioButtonPass->isChecked();
×
352
  ui->groupBoxNative->setEnabled(!state);
×
353
  ui->groupBoxPass->setEnabled(state);
×
354
}
×
355

356
/**
357
 * @brief ConfigDialog::selectExecutable pop-up to choose an executable.
358
 * @return
359
 */
360
auto ConfigDialog::selectExecutable() -> QString {
×
361
  QFileDialog dialog(this);
×
362
  dialog.setFileMode(QFileDialog::ExistingFile);
×
363
  dialog.setOption(QFileDialog::ReadOnly);
×
364
  if (dialog.exec()) {
×
365
    return dialog.selectedFiles().constFirst();
×
366
  }
367

368
  return {};
369
}
×
370

371
/**
372
 * @brief ConfigDialog::selectFolder pop-up to choose a folder.
373
 * @return
374
 */
375
auto ConfigDialog::selectFolder() -> QString {
×
376
  QFileDialog dialog(this);
×
377
  dialog.setFileMode(QFileDialog::Directory);
×
378
  dialog.setFilter(QDir::NoFilter);
×
379
  dialog.setOption(QFileDialog::ShowDirsOnly);
×
380
  if (dialog.exec()) {
×
381
    return dialog.selectedFiles().constFirst();
×
382
  }
383

384
  return {};
385
}
×
386

387
/**
388
 * @brief ConfigDialog::on_toolButtonGit_clicked get git application.
389
 * Enable checkboxes if found.
390
 */
391
void ConfigDialog::on_toolButtonGit_clicked() {
×
392
  QString git = selectExecutable();
×
393
  bool state = !git.isEmpty();
×
394
  if (state) {
×
395
    ui->gitPath->setText(git);
×
396
  } else {
397
    useGit(false);
×
398
  }
399

400
  ui->checkBoxUseGit->setEnabled(state);
×
401
}
×
402

403
/**
404
 * @brief ConfigDialog::on_toolButtonGpg_clicked get gpg application.
405
 */
406
void ConfigDialog::on_toolButtonGpg_clicked() {
×
407
  QString gpg = selectExecutable();
×
408
  if (!gpg.isEmpty()) {
×
409
    ui->gpgPath->setText(gpg);
×
410
  }
411
}
×
412

413
/**
414
 * @brief ConfigDialog::on_pushButtonGenerateKey_clicked open keygen dialog.
415
 */
416
void ConfigDialog::on_pushButtonGenerateKey_clicked() {
×
417
  KeygenDialog d(this);
×
418
  d.exec();
×
419
}
×
420

421
/**
422
 * @brief ConfigDialog::on_toolButtonPass_clicked get pass application.
423
 */
424
void ConfigDialog::on_toolButtonPass_clicked() {
×
425
  QString pass = selectExecutable();
×
426
  if (!pass.isEmpty()) {
×
427
    ui->passPath->setText(pass);
×
428
  }
429
}
×
430

431
/**
432
 * @brief ConfigDialog::on_toolButtonStore_clicked get .password-store
433
 * location.s
434
 */
435
void ConfigDialog::on_toolButtonStore_clicked() {
×
436
  QString store = selectFolder();
×
437
  if (!store.isEmpty()) {
×
438
    ui->storePath->setText(store);
×
439
  }
440
}
×
441

442
/**
443
 * @brief ConfigDialog::on_comboBoxClipboard_activated show and hide options.
444
 * @param index of selectbox (0 = no clipboard).
445
 */
446
void ConfigDialog::on_comboBoxClipboard_activated(int index) {
×
447
  bool state = index > 0;
×
448

449
  ui->checkBoxSelection->setEnabled(state);
×
450
  ui->checkBoxAutoclear->setEnabled(state);
×
451
  ui->checkBoxHidePassword->setEnabled(state);
×
452
  ui->checkBoxHideContent->setEnabled(state);
×
453
  if (state) {
×
454
    ui->spinBoxAutoclearSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
×
455
    ui->labelSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
×
456
  } else {
457
    ui->spinBoxAutoclearSeconds->setEnabled(false);
×
458
    ui->labelSeconds->setEnabled(false);
×
459
  }
460
}
×
461

462
/**
463
 * @brief ConfigDialog::on_checkBoxAutoclearPanel_clicked enable and disable
464
 * options based on autoclear use.
465
 */
466
void ConfigDialog::on_checkBoxAutoclearPanel_clicked() {
×
467
  bool state = ui->checkBoxAutoclearPanel->isChecked();
×
468
  ui->spinBoxAutoclearPanelSeconds->setEnabled(state);
×
469
  ui->labelPanelSeconds->setEnabled(state);
×
470
}
×
471

472
/**
473
 * @brief ConfigDialog::useSelection set the clipboard type use from
474
 * MainWindow.
475
 * @param useSelection
476
 */
477
void ConfigDialog::useSelection(bool useSelection) {
×
478
  ui->checkBoxSelection->setChecked(useSelection);
×
479
  on_checkBoxSelection_clicked();
×
480
}
×
481

482
/**
483
 * @brief ConfigDialog::useAutoclear set the clipboard autoclear use from
484
 * MainWindow.
485
 * @param useAutoclear
486
 */
487
void ConfigDialog::useAutoclear(bool useAutoclear) {
×
488
  ui->checkBoxAutoclear->setChecked(useAutoclear);
×
489
  on_checkBoxAutoclear_clicked();
×
490
}
×
491

492
/**
493
 * @brief ConfigDialog::useAutoclearPanel set the panel autoclear use from
494
 * MainWindow.
495
 * @param useAutoclearPanel
496
 */
497
void ConfigDialog::useAutoclearPanel(bool useAutoclearPanel) {
×
498
  ui->checkBoxAutoclearPanel->setChecked(useAutoclearPanel);
×
499
  on_checkBoxAutoclearPanel_clicked();
×
500
}
×
501

502
/**
503
 * @brief ConfigDialog::on_checkBoxSelection_clicked checkbox clicked, update
504
 * state via ConfigDialog::on_comboBoxClipboard_activated
505
 */
506
void ConfigDialog::on_checkBoxSelection_clicked() {
×
507
  on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
×
508
}
×
509

510
/**
511
 * @brief ConfigDialog::on_checkBoxAutoclear_clicked checkbox clicked, update
512
 * state via ConfigDialog::on_comboBoxClipboard_activated
513
 */
514
void ConfigDialog::on_checkBoxAutoclear_clicked() {
×
515
  on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
×
516
}
×
517

518
/**
519
 * @brief ConfigDialog::genKey tunnel function to make MainWindow generate a
520
 * gpg key pair.
521
 * @todo refactor the process to not be entangled so much.
522
 * @param batch
523
 * @param dialog
524
 */
525
void ConfigDialog::genKey(const QString &batch, QDialog *dialog) {
×
526
  mainWindow->generateKeyPair(batch, dialog);
×
527
}
×
528

529
/**
530
 * @brief ConfigDialog::setProfiles set the profiles and chosen profile from
531
 * MainWindow.
532
 * @param profiles
533
 * @param profile
534
 */
535
void ConfigDialog::setProfiles(QHash<QString, QHash<QString, QString>> profiles,
×
536
                               const QString &currentProfile) {
UNCOV
537
  if (profiles.contains("")) {
×
538
    profiles.remove("");
×
539
    // remove weird "" key value pairs
540
  }
541

542
  ui->profileTable->setRowCount(profiles.count());
×
543
  QHashIterator<QString, QHash<QString, QString>> i(profiles);
×
544
  int n = 0;
545
  while (i.hasNext()) {
×
546
    i.next();
547
    if (!i.value().isEmpty() && !i.key().isEmpty()) {
×
548
      ui->profileTable->setItem(n, 0, new QTableWidgetItem(i.key()));
×
549
      ui->profileTable->setItem(n, 1,
×
550
                                new QTableWidgetItem(i.value().value("path")));
×
551
      ui->profileTable->setItem(
×
552
          n, 2, new QTableWidgetItem(i.value().value("signingKey")));
×
UNCOV
553
      if (i.key() == currentProfile) {
×
554
        ui->profileTable->selectRow(n);
×
555
      }
556
    }
557
    ++n;
×
558
  }
559
}
×
560

561
/**
562
 * @brief ConfigDialog::getProfiles return profile list.
563
 * @return
564
 */
565
auto ConfigDialog::getProfiles() -> QHash<QString, QHash<QString, QString>> {
×
566
  QHash<QString, QHash<QString, QString>> profiles;
×
567
  // Check?
568
  for (int i = 0; i < ui->profileTable->rowCount(); ++i) {
×
569
    QHash<QString, QString> profile;
×
570
    QTableWidgetItem *pathItem = ui->profileTable->item(i, 1);
×
571
    if (nullptr != pathItem) {
×
572
      QTableWidgetItem *item = ui->profileTable->item(i, 0);
×
573
      if (item == nullptr) {
×
574
        continue;
575
      }
576
      profile["path"] = pathItem->text();
×
577
      QTableWidgetItem *signingKeyItem = ui->profileTable->item(i, 2);
×
578
      if (nullptr != signingKeyItem) {
×
579
        profile["signingKey"] = signingKeyItem->text();
×
580
      }
581
      profiles.insert(item->text(), profile);
×
582
    }
583
  }
×
584
  return profiles;
×
585
}
×
586

587
/**
588
 * @brief ConfigDialog::on_addButton_clicked add a profile row.
589
 */
590
void ConfigDialog::on_addButton_clicked() {
×
591
  int n = ui->profileTable->rowCount();
×
592
  ui->profileTable->insertRow(n);
×
593
  ui->profileTable->setItem(n, 0, new QTableWidgetItem());
×
594
  ui->profileTable->setItem(n, 1, new QTableWidgetItem(ui->storePath->text()));
×
595
  ui->profileTable->setItem(n, 2, new QTableWidgetItem());
×
596
  ui->profileTable->selectRow(n);
×
597
  ui->deleteButton->setEnabled(true);
×
598

599
  validate();
×
600
}
×
601

602
/**
603
 * @brief ConfigDialog::on_deleteButton_clicked remove a profile row.
604
 */
605
void ConfigDialog::on_deleteButton_clicked() {
×
606
  QSet<int> selectedRows; //  we use a set to prevent doubles
607
  QList<QTableWidgetItem *> itemList = ui->profileTable->selectedItems();
×
608
  if (itemList.count() == 0) {
×
609
    QMessageBox::warning(this, tr("No profile selected"),
×
610
                         tr("No profile selected to delete"));
×
611
    return;
612
  }
613
  QTableWidgetItem *item;
614
  foreach (item, itemList)
×
615
    selectedRows.insert(item->row());
×
616
  // get a list, and sort it big to small
617
  QList<int> rows = selectedRows.values();
×
618
  std::sort(rows.begin(), rows.end());
×
619
  // now actually do the removing:
620
  foreach (int row, rows)
×
621
    ui->profileTable->removeRow(row);
×
622
  if (ui->profileTable->rowCount() < 1) {
×
623
    ui->deleteButton->setEnabled(false);
×
624
  }
625

626
  validate();
×
627
}
628

629
/**
630
 * @brief ConfigDialog::criticalMessage weapper for showing critical messages
631
 * in a popup.
632
 * @param title
633
 * @param text
634
 */
635
void ConfigDialog::criticalMessage(const QString &title, const QString &text) {
×
636
  QMessageBox::critical(this, title, text, QMessageBox::Ok, QMessageBox::Ok);
×
637
}
×
638

639
/**
640
 * @brief Checks whether the qrencode executable is available on the system.
641
 * @example
642
 * bool result = ConfigDialog::isQrencodeAvailable();
643
 * std::cout << result << std::endl; // Expected output: true if qrencode is
644
 * found, otherwise false
645
 *
646
 * @return bool - True if qrencode is available; otherwise false. On Windows,
647
 * always returns false.
648
 */
649
auto ConfigDialog::isQrencodeAvailable() -> bool {
×
650
#ifdef Q_OS_WIN
651
  return false;
652
#else
653
  QProcess which;
×
654
  which.start("which", QStringList() << "qrencode");
×
655
  which.waitForFinished();
×
656
  QtPassSettings::setQrencodeExecutable(
×
657
      which.readAllStandardOutput().trimmed());
×
658
  return which.exitCode() == 0;
×
659
#endif
660
}
×
661

662
auto ConfigDialog::isPassOtpAvailable() -> bool {
×
663
#ifdef Q_OS_WIN
664
  return false;
665
#else
666
  QProcess pass;
×
667
  pass.start(QtPassSettings::getPassExecutable(), QStringList() << "otp"
×
668
                                                                << "--help");
×
669
  pass.waitForFinished(2000);
×
670
  return pass.exitCode() == 0;
×
671
#endif
672
}
×
673

674
/**
675
 * @brief ConfigDialog::wizard first-time use wizard.
676
 * @todo make this thing more reliable.
677
 */
678
void ConfigDialog::wizard() {
×
679
  (void)Util::configIsValid();
×
680
  on_autodetectButton_clicked();
×
681

682
  if (!checkGpgExistence()) {
×
683
    return;
684
  }
685
  if (!checkSecretKeys()) {
×
686
    return;
687
  }
688
  if (!checkPasswordStore()) {
×
689
    return;
690
  }
691
  handleGpgIdFile();
×
692

693
  ui->checkBoxHidePassword->setCheckState(Qt::Checked);
×
694
}
695

696
/**
697
 * @brief Checks whether the configured GnuPG executable exists.
698
 * @example
699
 * bool result = ConfigDialog::checkGpgExistence();
700
 * std::cout << result << std::endl; // Expected output: true if GnuPG is found,
701
 * false otherwise
702
 *
703
 * @return bool - True if the GnuPG path is valid or uses a WSL command prefix;
704
 * false if the executable cannot be found and an error message is shown.
705
 */
706
auto ConfigDialog::checkGpgExistence() -> bool {
×
707
  QString gpg = ui->gpgPath->text();
×
708
  if (!gpg.startsWith("wsl ") && !QFile(gpg).exists()) {
×
709
    criticalMessage(
×
710
        tr("GnuPG not found"),
×
711
#ifdef Q_OS_WIN
712
#ifdef WINSTORE
713
        tr("Please install GnuPG on your system.<br>Install "
714
           "<strong>Ubuntu</strong> from the Microsoft Store to get it.<br>"
715
           "If you already did so, make sure you started it once and<br>"
716
           "click \"Autodetect\" in the next dialog.")
717
#else
718
        tr("Please install GnuPG on your system.<br>Install "
719
           "<strong>Ubuntu</strong> from the Microsoft Store<br>or <a "
720
           "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
721
           "from GnuPG.org")
722
#endif
723
#else
724
        tr("Please install GnuPG on your system.<br>Install "
×
725
           "<strong>gpg</strong> using your favorite package manager<br>or "
726
           "<a "
727
           "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
728
           "from GnuPG.org")
729
#endif
730
    );
731
    return false;
×
732
  }
733
  return true;
734
}
735

736
/**
737
 * @brief Checks whether secret keys are available and, if needed, prompts the
738
 * user to generate them.
739
 * @example
740
 * bool result = ConfigDialog.checkSecretKeys();
741
 * std::cout << result << std::endl; // Expected output: true if keys are
742
 * present or key generation dialog is accepted, false otherwise
743
 *
744
 * @return bool - Returns true when secret keys are already available or the key
745
 * generation dialog is accepted; false if the dialog is rejected.
746
 */
747
auto ConfigDialog::checkSecretKeys() -> bool {
×
748
  QString gpg = ui->gpgPath->text();
×
749
  QStringList names = getSecretKeys();
×
750

751
#ifdef QT_DEBUG
752
  dbg() << names;
753
#endif
754

755
  if ((gpg.startsWith("wsl ") || QFile(gpg).exists()) && names.empty()) {
×
756
    KeygenDialog d(this);
×
757
    return d.exec();
×
758
  }
×
759
  return true;
760
}
761

762
/**
763
 * @brief Checks whether the password-store path exists and prompts the user to
764
 * create it if it does not.
765
 * @example
766
 * bool result = ConfigDialog::checkPasswordStore();
767
 * std::cout << std::boolalpha << result << std::endl; // Expected output: true
768
 * if the store exists or is created successfully, false if creation fails
769
 *
770
 * @return bool - True if the password-store exists or is successfully created,
771
 * false if creation fails.
772
 */
773
auto ConfigDialog::checkPasswordStore() -> bool {
×
774
  QString passStore = ui->storePath->text();
×
775

776
  if (!QFile(passStore).exists()) {
×
777
    if (QMessageBox::question(
×
778
            this, tr("Create password-store?"),
×
779
            tr("Would you like to create a password-store at %1?")
×
780
                .arg(passStore),
×
781
            QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
782
      if (!QDir().mkdir(passStore)) {
×
783
        QMessageBox::warning(
×
784
            this, tr("Error"),
×
785
            tr("Failed to create password-store at: %1").arg(passStore));
×
786
        return false;
×
787
      }
788
#ifdef Q_OS_WIN
789
      SetFileAttributes(passStore.toStdWString().c_str(),
790
                        FILE_ATTRIBUTE_HIDDEN);
791
#endif
792
      if (ui->checkBoxUseGit->isChecked()) {
×
793
        emit mainWindow->passGitInitNeeded();
×
794
      }
795
      mainWindow->userDialog(passStore);
×
796
    }
797
  }
798
  return true;
799
}
800

801
/**
802
 * @brief Handles selection and validation of the password store's .gpg-id file.
803
 * @example
804
 * ConfigDialog dialog;
805
 * dialog.handleGpgIdFile();
806
 *
807
 * @return void - This method does not return a value; it updates the UI flow
808
 * and may prompt the user to choose a valid password store.
809
 */
810
void ConfigDialog::handleGpgIdFile() {
×
811
  QString passStore = ui->storePath->text();
×
812
  if (!QFile(QDir(passStore).filePath(".gpg-id")).exists()) {
×
813
#ifdef QT_DEBUG
814
    dbg() << ".gpg-id file does not exist";
815
#endif
816
    criticalMessage(tr("Password store not initialised"),
×
817
                    tr("The folder %1 doesn't seem to be a password store or "
×
818
                       "is not yet initialised.")
819
                        .arg(passStore));
×
820

821
    while (!QFile(passStore).exists()) {
×
822
      on_toolButtonStore_clicked();
×
823
      if (passStore == ui->storePath->text()) {
×
824
        return;
825
      }
826
      passStore = ui->storePath->text();
×
827
    }
828
    if (!QFile(passStore + ".gpg-id").exists()) {
×
829
#ifdef QT_DEBUG
830
      dbg() << ".gpg-id file still does not exist :/";
831
#endif
832
      mainWindow->userDialog(passStore);
×
833
    }
834
  }
835
}
836

837
/**
838
 * @brief ConfigDialog::useTrayIcon set preference for using trayicon.
839
 * Enable or disable related checkboxes accordingly.
840
 * @param useSystray
841
 */
842
void ConfigDialog::useTrayIcon(bool useSystray) {
×
843
  if (QSystemTrayIcon::isSystemTrayAvailable()) {
×
844
    ui->checkBoxUseTrayIcon->setChecked(useSystray);
×
845
    ui->checkBoxHideOnClose->setEnabled(useSystray);
×
846
    ui->checkBoxStartMinimized->setEnabled(useSystray);
×
847

848
    if (!useSystray) {
×
849
      ui->checkBoxHideOnClose->setChecked(false);
×
850
      ui->checkBoxStartMinimized->setChecked(false);
×
851
    }
852
  }
853
}
×
854

855
/**
856
 * @brief ConfigDialog::on_checkBoxUseTrayIcon_clicked enable and disable
857
 * related checkboxes.
858
 */
859
void ConfigDialog::on_checkBoxUseTrayIcon_clicked() {
×
860
  bool state = ui->checkBoxUseTrayIcon->isChecked();
×
861
  ui->checkBoxHideOnClose->setEnabled(state);
×
862
  ui->checkBoxStartMinimized->setEnabled(state);
×
863
}
×
864

865
/**
866
 * @brief ConfigDialog::closeEvent close this window.
867
 * @param event
868
 */
869
void ConfigDialog::closeEvent(QCloseEvent *event) {
×
870
  QtPassSettings::setDialogGeometry("configDialog", saveGeometry());
×
871
  QtPassSettings::setDialogPos("configDialog", pos());
×
872
  QtPassSettings::setDialogSize("configDialog", size());
×
873
  QtPassSettings::setDialogMaximized("configDialog", isMaximized());
×
874
  event->accept();
875
}
×
876

877
/**
878
 * @brief ConfigDialog::useGit set preference for using git.
879
 * @param useGit
880
 */
881
void ConfigDialog::useGit(bool useGit) {
×
882
  ui->checkBoxUseGit->setChecked(useGit);
×
883
  on_checkBoxUseGit_clicked();
×
884
}
×
885

886
/**
887
 * @brief ConfigDialog::useOtp set preference for using otp plugin.
888
 * @param useOtp
889
 */
890
void ConfigDialog::useOtp(bool useOtp) {
×
891
  ui->checkBoxUseOtp->setChecked(useOtp);
×
892
}
×
893

894
/**
895
 * @brief ConfigDialog::useOtp set preference for using otp plugin.
896
 * @param useOtp
897
 */
898
void ConfigDialog::useQrencode(bool useQrencode) {
×
899
  ui->checkBoxUseQrencode->setChecked(useQrencode);
×
900
}
×
901

902
/**
903
 * @brief ConfigDialog::on_checkBoxUseGit_clicked enable or disable related
904
 * checkboxes.
905
 */
906
void ConfigDialog::on_checkBoxUseGit_clicked() {
×
907
  ui->checkBoxAddGPGId->setEnabled(ui->checkBoxUseGit->isChecked());
×
908
  ui->checkBoxAutoPull->setEnabled(ui->checkBoxUseGit->isChecked());
×
909
  ui->checkBoxAutoPush->setEnabled(ui->checkBoxUseGit->isChecked());
×
910
}
×
911

912
/**
913
 * @brief ConfigDialog::on_toolButtonPwgen_clicked enable or disable related
914
 * options in the interface.
915
 */
916
void ConfigDialog::on_toolButtonPwgen_clicked() {
×
917
  QString pwgen = selectExecutable();
×
918
  if (!pwgen.isEmpty()) {
×
919
    ui->pwgenPath->setText(pwgen);
×
920
    ui->checkBoxUsePwgen->setEnabled(true);
×
921
  } else {
922
    ui->checkBoxUsePwgen->setEnabled(false);
×
923
    ui->checkBoxUsePwgen->setChecked(false);
×
924
  }
925
}
×
926

927
/**
928
 * @brief ConfigDialog::setPwgenPath set pwgen executable path.
929
 * Enable or disable related options in the interface.
930
 * @param pwgen
931
 */
932
void ConfigDialog::setPwgenPath(const QString &pwgen) {
×
933
  ui->pwgenPath->setText(pwgen);
×
934
  if (pwgen.isEmpty()) {
×
935
    ui->checkBoxUsePwgen->setChecked(false);
×
936
    ui->checkBoxUsePwgen->setEnabled(false);
×
937
  }
938
  on_checkBoxUsePwgen_clicked();
×
939
}
×
940

941
/**
942
 * @brief ConfigDialog::on_checkBoxUsPwgen_clicked enable or disable related
943
 * options in the interface.
944
 */
945
void ConfigDialog::on_checkBoxUsePwgen_clicked() {
×
946
  bool usePwgen = ui->checkBoxUsePwgen->isChecked();
×
947
  ui->checkBoxAvoidCapitals->setEnabled(usePwgen);
×
948
  ui->checkBoxAvoidNumbers->setEnabled(usePwgen);
×
949
  ui->checkBoxLessRandom->setEnabled(usePwgen);
×
950
  ui->checkBoxUseSymbols->setEnabled(usePwgen);
×
951
  ui->lineEditPasswordChars->setEnabled(!usePwgen);
×
952
  ui->labelPasswordChars->setEnabled(!usePwgen);
×
953
  ui->passwordCharTemplateSelector->setEnabled(!usePwgen);
×
954
}
×
955

956
/**
957
 * @brief ConfigDialog::usePwgen set preference for using pwgen (can be
958
 * overruled buy empty pwgenPath).
959
 * enable or disable related options in the interface via
960
 * ConfigDialog::on_checkBoxUsePwgen_clicked
961
 * @param usePwgen
962
 */
963
void ConfigDialog::usePwgen(bool usePwgen) {
×
964
  if (ui->pwgenPath->text().isEmpty()) {
×
965
    usePwgen = false;
966
  }
967
  ui->checkBoxUsePwgen->setChecked(usePwgen);
×
968
  on_checkBoxUsePwgen_clicked();
×
969
}
×
970

971
void ConfigDialog::setPasswordConfiguration(
×
972
    const PasswordConfiguration &config) {
973
  ui->spinBoxPasswordLength->setValue(config.length);
×
974
  ui->passwordCharTemplateSelector->setCurrentIndex(config.selected);
×
975
  if (config.selected != PasswordConfiguration::CUSTOM) {
×
976
    ui->lineEditPasswordChars->setEnabled(false);
×
977
  }
978
  ui->lineEditPasswordChars->setText(config.Characters[config.selected]);
×
979
}
×
980

981
auto ConfigDialog::getPasswordConfiguration() -> PasswordConfiguration {
×
982
  PasswordConfiguration config;
×
983
  config.length = ui->spinBoxPasswordLength->value();
×
984
  config.selected = static_cast<PasswordConfiguration::characterSet>(
×
985
      ui->passwordCharTemplateSelector->currentIndex());
×
986
  config.Characters[PasswordConfiguration::CUSTOM] =
987
      ui->lineEditPasswordChars->text();
×
988
  return config;
×
989
}
×
990

991
/**
992
 * @brief ConfigDialog::on_passwordCharTemplateSelector_activated sets the
993
 * passwordChar Template
994
 * combo box to the desired entry
995
 * @param entry of
996
 */
997
void ConfigDialog::on_passwordCharTemplateSelector_activated(int index) {
×
998
  ui->lineEditPasswordChars->setText(
×
999
      QtPassSettings::getPasswordConfiguration().Characters[index]);
×
1000
  if (index == 3) {
×
1001
    ui->lineEditPasswordChars->setEnabled(true);
×
1002
  } else {
1003
    ui->lineEditPasswordChars->setEnabled(false);
×
1004
  }
1005
}
×
1006

1007
/**
1008
 * @brief ConfigDialog::on_checkBoxUseTemplate_clicked enable or disable the
1009
 * template field and options.
1010
 */
1011
void ConfigDialog::on_checkBoxUseTemplate_clicked() {
×
1012
  ui->plainTextEditTemplate->setEnabled(ui->checkBoxUseTemplate->isChecked());
×
1013
  ui->checkBoxTemplateAllFields->setEnabled(
×
1014
      ui->checkBoxUseTemplate->isChecked());
×
1015
}
×
1016

1017
void ConfigDialog::onProfileTableItemChanged(QTableWidgetItem *item) {
×
1018
  validate(item);
×
1019
}
×
1020

1021
/**
1022
 * @brief ConfigDialog::useTemplate set preference for using templates.
1023
 * @param useTemplate
1024
 */
1025
void ConfigDialog::useTemplate(bool useTemplate) {
×
1026
  ui->checkBoxUseTemplate->setChecked(useTemplate);
×
1027
  on_checkBoxUseTemplate_clicked();
×
NEW
1028
}
×
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